From b8a57aa103a5744ca10161ecbea6e7a70437e4fd Mon Sep 17 00:00:00 2001 From: Marcel Haag Date: Wed, 23 Feb 2022 17:13:39 +0100 Subject: [PATCH] feat: added update project option and refactored project-dialog --- .../project-overview.component.html | 4 +- .../project-overview.component.scss | 8 +- .../project-overview.component.spec.ts | 3 + .../project-overview.component.ts | 37 +++++-- .../src/assets/i18n/de-DE.json | 29 +++-- .../src/assets/i18n/en-US.json | 51 +++++---- security-c4po-angular/src/index.html | 4 +- .../src/shared/config/global-variables.ts | 2 +- .../src/shared/models/project-dialog-data.ts | 26 +++++ .../src/shared/models/project.model.ts | 2 +- .../project-dialog.component.html | 71 ++++++------ .../project-dialog.component.scss | 13 ++- .../project-dialog.component.spec.ts | 90 +++++++++++++++- .../project-dialog.component.ts | 87 ++++++++------- .../project-dialog/project-dialog.module.ts | 2 + .../service/project-dialog.service.mock.ts | 17 +++ .../service/project-dialog.service.spec.ts | 30 ++++++ .../service/project-dialog.service.ts | 102 ++++++++++++++++++ .../services/dialog-service/dialog.service.ts | 4 +- .../shared/services/project.service.mock.ts | 8 +- .../shared/services/project.service.spec.ts | 4 +- .../src/shared/services/project.service.ts | 14 ++- security-c4po-angular/tsconfig.json | 1 + security-c4po-angular/tsconfig.spec.json | 1 + .../kc/docker-compose.keycloak.yml | 2 +- 25 files changed, 475 insertions(+), 137 deletions(-) create mode 100644 security-c4po-angular/src/shared/models/project-dialog-data.ts create mode 100644 security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.mock.ts create mode 100644 security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.spec.ts create mode 100644 security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.ts diff --git a/security-c4po-angular/src/app/project-overview/project-overview.component.html b/security-c4po-angular/src/app/project-overview/project-overview.component.html index 2582c21..ccae143 100644 --- a/security-c4po-angular/src/app/project-overview/project-overview.component.html +++ b/security-c4po-angular/src/app/project-overview/project-overview.component.html @@ -45,7 +45,7 @@ status="primary" size="small" class="project-button" - (click)="onClickEditProject()"> + (click)="onClickEditProject(project)"> - diff --git a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.scss b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.scss index a8fa406..7fc74d7 100644 --- a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.scss +++ b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.scss @@ -1,8 +1,9 @@ @import "../../../assets/@theme/styles/_dialog.scss"; +@import '../../../assets/@theme/styles/themes'; .project-dialog { - width: 24rem; - height: 31rem; + width: 25.25rem; + height: 35rem; .project-dialog-header { height: 8vh; @@ -20,6 +21,12 @@ } .input { - width: 15rem; + width: 18rem; + margin-bottom: 0.5rem; + } + + .error-text { + float: left; + color: nb-theme(color-danger-default);; } } diff --git a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.spec.ts b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.spec.ts index 4f0802e..d099b3b 100644 --- a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.spec.ts +++ b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.spec.ts @@ -1,8 +1,15 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; - import {ProjectDialogComponent} from './project-dialog.component'; import {CommonModule} from '@angular/common'; -import {NbButtonModule, NbCardModule, NbDialogRef, NbFormFieldModule, NbInputModule, NbLayoutModule} from '@nebular/theme'; +import { + NB_DIALOG_CONFIG, + NbButtonModule, + NbCardModule, + NbDialogRef, + NbFormFieldModule, + NbInputModule, + NbLayoutModule +} from '@nebular/theme'; import {FlexLayoutModule} from '@angular/flex-layout'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {ThemeModule} from '@assets/@theme/theme.module'; @@ -14,13 +21,18 @@ import {NotificationService} from '@shared/services/notification.service'; import {NotificationServiceMock} from '@shared/services/notification.service.mock'; import {DialogService} from '@shared/services/dialog-service/dialog.service'; import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock'; -import {ReactiveFormsModule} from '@angular/forms'; +import {ReactiveFormsModule, Validators} from '@angular/forms'; +import {Project} from '@shared/models/project.model'; +import Mock = jest.Mock; +import deepEqual from 'deep-equal'; describe('ProjectDialogComponent', () => { let component: ProjectDialogComponent; let fixture: ComponentFixture; beforeEach(async () => { + const dialogSpy = createSpyObj('NbDialogRef', ['close']); + await TestBed.configureTestingModule({ declarations: [ ProjectDialogComponent @@ -49,12 +61,14 @@ describe('ProjectDialogComponent', () => { providers: [ {provide: NotificationService, useValue: new NotificationServiceMock()}, {provide: DialogService, useClass: DialogServiceMock}, - {provide: NbDialogRef, useValue: {}} + {provide: NbDialogRef, useValue: dialogSpy}, + {provide: NB_DIALOG_CONFIG, useValue: mockedDialogData} ] }).compileComponents(); }); beforeEach(() => { + TestBed.overrideProvider(NB_DIALOG_CONFIG, {useValue: mockedDialogData}); fixture = TestBed.createComponent(ProjectDialogComponent); component = fixture.componentInstance; fixture.detectChanges(); @@ -64,3 +78,71 @@ describe('ProjectDialogComponent', () => { expect(component).toBeTruthy(); }); }); + +export const createSpyObj = (baseName, methodNames): { [key: string]: Mock } => { + const obj: any = {}; + for (const i of methodNames) { + obj[i] = jest.fn(); + } + return obj; +}; + +export const mockProject: Project = { + id: '11-22-33', + title: 'Test Project', + client: 'Testclient', + tester: 'Testpentester', + createdAt: new Date(), + createdBy: 'UID-11-12-13' +}; + +export const mockedDialogData = { + form: { + projectTitle: { + fieldName: 'projectTitle', + type: 'text', + labelKey: 'project.title.label', + placeholder: 'project.title', + controlsConfig: [ + {value: mockProject ? mockProject.title : '', disabled: false}, + [Validators.required] + ], + errors: [ + {errorCode: 'required', translationKey: 'project.validationMessage.titleRequired'} + ] + }, + projectClient: { + fieldName: 'projectClient', + type: 'text', + labelKey: 'project.client.label', + placeholder: 'project.client', + controlsConfig: [ + {value: mockProject ? mockProject.client : '', disabled: false}, + [Validators.required] + ], + errors: [ + {errorCode: 'required', translationKey: 'project.validationMessage.clientRequired'} + ] + }, + projectTester: { + fieldName: 'projectTester', + type: 'text', + labelKey: 'project.tester.label', + placeholder: 'project.tester', + controlsConfig: [ + {value: mockProject ? mockProject.tester : '', disabled: false}, + [Validators.required] + ], + errors: [ + {errorCode: 'required', translationKey: 'project.validationMessage.testerRequired'} + ] + } + }, + options: [ + { + headerLabelKey: 'project.edit.header', + buttonKey: 'global.action.update', + accentColor: 'warning' + }, + ] +}; diff --git a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.ts b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.ts index 2d7a718..1e9ebd3 100644 --- a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.ts +++ b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.ts @@ -1,8 +1,8 @@ -import {Component, OnDestroy, OnInit} from '@angular/core'; -import {NbDialogRef} from '@nebular/theme'; -import {AbstractControl, FormBuilder, FormGroup, Validators} from '@angular/forms'; -import {FieldStatus} from '@shared/models/form-field-status.model'; -import {untilDestroyed} from 'ngx-take-until-destroy'; +import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; +import {NB_DIALOG_CONFIG, NbDialogRef} from '@nebular/theme'; +import {FormBuilder, FormGroup} from '@angular/forms'; +import {GenericFormFieldConfig, ProjectDialogData} from '@shared/models/project-dialog-data'; +import deepEqual from 'deep-equal'; @Component({ selector: 'app-project-dialog', @@ -12,40 +12,29 @@ import {untilDestroyed} from 'ngx-take-until-destroy'; export class ProjectDialogComponent implements OnInit, OnDestroy { // form control elements projectFormGroup: FormGroup; - projectTitleCtrl: AbstractControl; - projectClientCtrl: AbstractControl; - projectTesterCtrl: AbstractControl; + formArray: GenericFormFieldConfig[]; - formCtrlStatus = FieldStatus.BASIC; - - invalidProjectTitle: string; - invalidProjectClient: string; - invalidProjectTester: string; - - readonly MIN_LENGTH: number = 2; + dialogData: ProjectDialogData; constructor( + @Inject(NB_DIALOG_CONFIG) private data: ProjectDialogData, private fb: FormBuilder, protected dialogRef: NbDialogRef ) { } ngOnInit(): void { - this.projectFormGroup = this.fb.group({ - projectTitle: ['', [Validators.required, Validators.minLength(this.MIN_LENGTH)]], - projectClient: ['', [Validators.required, Validators.minLength(this.MIN_LENGTH)]], - projectTester: ['', [Validators.required, Validators.minLength(this.MIN_LENGTH)]] - }); + this.projectFormGroup = this.generateFormCreationFieldArray(); + this.dialogData = this.data; + } - this.projectTitleCtrl = this.projectFormGroup.get('projectTitle'); - this.projectClientCtrl = this.projectFormGroup.get('projectClient'); - this.projectTesterCtrl = this.projectFormGroup.get('projectTester'); - - this.projectFormGroup.valueChanges - .pipe(untilDestroyed(this)) - .subscribe(() => { - this.formCtrlStatus = FieldStatus.BASIC; - }); + generateFormCreationFieldArray(): FormGroup { + this.formArray = Object.values(this.data.form); + const config = this.formArray?.reduce((accumulator: {}, currentValue: GenericFormFieldConfig) => ({ + ...accumulator, + [currentValue?.fieldName]: currentValue?.controlsConfig + }), {}); + return this.fb.group(config); } onClickSave(value): void { @@ -60,23 +49,41 @@ export class ProjectDialogComponent implements OnInit, OnDestroy { this.dialogRef.close(); } - formIsEmptyOrInvalid(): boolean { - return this.isEmpty(this.projectTitleCtrl.value) - || this.isEmpty(this.projectClientCtrl.value) - || this.isEmpty(this.projectTesterCtrl.value) - || this.projectTitleCtrl.invalid - || this.projectClientCtrl.invalid - || this.projectTesterCtrl.invalid; + allowSave(): boolean { + return this.projectFormGroup.valid && this.projectDataChanged(); } /** - * @param ctrlValue of type string - * @return if ctrlValue is empty or not + * @return true if project data is different from initial value */ - isEmpty(ctrlValue: string): boolean { - return ctrlValue === ''; + private projectDataChanged(): boolean { + const oldProjectData = this.parseInitializedProjectDialogData(this.dialogData); + const newProjectData = this.projectFormGroup.getRawValue(); + Object.entries(newProjectData).forEach(entry => { + const [key, value] = entry; + if (value === null) { + newProjectData[key] = ''; + } + }); + const didChange = !deepEqual(oldProjectData, newProjectData); + return didChange; + } + + /** + * @param dialogData of type ProjectDialogData + * @return parsed projectData + */ + private parseInitializedProjectDialogData(dialogData: ProjectDialogData): any { + const projectData = {}; + Object.entries(dialogData.form).forEach(entry => { + const [key, value] = entry; + projectData[key] = value.controlsConfig[0] ? + (value.controlsConfig[0].value ? value.controlsConfig[0].value : value.controlsConfig[0]) : ''; + }); + return projectData; } ngOnDestroy(): void { + // ToDo: Remove this after Angular upgrade and use @UnitDestroy() instead } } diff --git a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.module.ts b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.module.ts index 6e46c61..0b06202 100644 --- a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.module.ts +++ b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.module.ts @@ -7,6 +7,7 @@ import {FontAwesomeModule} from '@fortawesome/angular-fontawesome'; import {TranslateModule} from '@ngx-translate/core'; import {DialogService} from '@shared/services/dialog-service/dialog.service'; import {ReactiveFormsModule} from '@angular/forms'; +import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service'; @NgModule({ declarations: [ @@ -25,6 +26,7 @@ import {ReactiveFormsModule} from '@angular/forms'; ], providers: [ DialogService, + ProjectDialogService, NbDialogService ], entryComponents: [ diff --git a/security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.mock.ts b/security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.mock.ts new file mode 100644 index 0000000..685e209 --- /dev/null +++ b/security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.mock.ts @@ -0,0 +1,17 @@ +import {ComponentType} from '@angular/cdk/overlay'; +import {NbDialogConfig} from '@nebular/theme'; +import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service'; +import {Project} from '@shared/models/project.model'; +import {Observable, of} from 'rxjs'; + +export class ProjectDialogServiceMock implements Required { + + dialog: any; + + openProjectDialog( + componentOrTemplateRef: ComponentType, + project: Project | undefined, + config: Partial | string>> | undefined): Observable { + return of(undefined); + } +} diff --git a/security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.spec.ts b/security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.spec.ts new file mode 100644 index 0000000..bfbc628 --- /dev/null +++ b/security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.spec.ts @@ -0,0 +1,30 @@ +import { TestBed } from '@angular/core/testing'; + +import { ProjectDialogService } from './project-dialog.service'; +import {HttpClientTestingModule} from '@angular/common/http/testing'; +import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import {NbDialogModule, NbDialogRef} from '@nebular/theme'; +import {ProjectDialogServiceMock} from '@shared/modules/project-dialog/service/project-dialog.service.mock'; + +describe('ProjectDialogService', () => { + let service: ProjectDialogService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule, + BrowserAnimationsModule, + NbDialogModule.forRoot() + ], + providers: [ + {provide: ProjectDialogService, useClass: ProjectDialogServiceMock}, + {provide: NbDialogRef, useValue: {}}, + ] + }); + service = TestBed.inject(ProjectDialogService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.ts b/security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.ts new file mode 100644 index 0000000..1e89fba --- /dev/null +++ b/security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.ts @@ -0,0 +1,102 @@ +import {Injectable} from '@angular/core'; +import {NbDialogConfig, NbDialogService} from '@nebular/theme'; +import {ComponentType} from '@angular/cdk/overlay'; +import {Observable} from 'rxjs'; +import {Project} from '@shared/models/project.model'; +import {ProjectDialogComponent} from '@shared/modules/project-dialog/project-dialog.component'; +import {Validators} from '@angular/forms'; +import {ProjectDialogData} from '@shared/models/project-dialog-data'; + +@Injectable() +export class ProjectDialogService { + + constructor(private readonly dialog: NbDialogService) { + } + + private readonly MIN_LENGTH: number = 4; + + static addDataToDialogConfig( + dialogOptions?: Partial | string>>, + projectData?: ProjectDialogData + ): Partial | string>> { + return { + context: {data: projectData}, + closeOnEsc: dialogOptions?.closeOnEsc || false, + hasScroll: dialogOptions?.hasScroll || false, + autoFocus: dialogOptions?.autoFocus || false, + closeOnBackdropClick: dialogOptions?.closeOnBackdropClick || false + }; + } + + public openProjectDialog(componentOrTemplateRef: ComponentType, + project?: Project, + config?: Partial | string>>): Observable { + let dialogOptions: Partial | string>>; + let dialogData: ProjectDialogData; + // Setup ProjectDialogData + dialogData = { + form: { + projectTitle: { + fieldName: 'projectTitle', + type: 'text', + labelKey: 'project.title.label', + placeholder: 'project.title', + controlsConfig: [ + {value: project ? project.title : '', disabled: false}, + [Validators.required] + ], + errors: [ + {errorCode: 'required', translationKey: 'project.validationMessage.titleRequired'} + ] + }, + projectClient: { + fieldName: 'projectClient', + type: 'text', + labelKey: 'project.client.label', + placeholder: 'project.client', + controlsConfig: [ + {value: project ? project.client : '', disabled: false}, + [Validators.required] + ], + errors: [ + {errorCode: 'required', translationKey: 'project.validationMessage.clientRequired'} + ] + }, + projectTester: { + fieldName: 'projectTester', + type: 'text', + labelKey: 'project.tester.label', + placeholder: 'project.tester', + controlsConfig: [ + {value: project ? project.tester : '', disabled: false}, + [Validators.required] + ], + errors: [ + {errorCode: 'required', translationKey: 'project.validationMessage.testerRequired'} + ] + } + }, + options: [] + }; + if (project) { + dialogData.options = [ + { + headerLabelKey: 'project.edit.header', + buttonKey: 'global.action.update', + accentColor: 'warning' + }, + ]; + } else { + dialogData.options = [ + { + headerLabelKey: 'project.create.header', + buttonKey: 'global.action.save', + accentColor: 'primary' + }, + ]; + } + // Merge dialog config with project data + dialogOptions = ProjectDialogService.addDataToDialogConfig(config, dialogData); + return this.dialog.open(ProjectDialogComponent, dialogOptions).onClose; + } +} diff --git a/security-c4po-angular/src/shared/services/dialog-service/dialog.service.ts b/security-c4po-angular/src/shared/services/dialog-service/dialog.service.ts index 1aa701c..1a52226 100644 --- a/security-c4po-angular/src/shared/services/dialog-service/dialog.service.ts +++ b/security-c4po-angular/src/shared/services/dialog-service/dialog.service.ts @@ -24,7 +24,7 @@ export class DialogService { closeOnEsc: config?.closeOnEsc || false, hasScroll: config?.hasScroll || false, autoFocus: config?.autoFocus || false, - closeOnBackdropClick: config?.closeOnBackdropClick || false, + closeOnBackdropClick: config?.closeOnBackdropClick || false }); } @@ -35,7 +35,7 @@ export class DialogService { */ openConfirmDialog(message: DialogMessage): NbDialogRef { return this.dialog.open(ConfirmDialogComponent, { - closeOnEsc: false, + closeOnEsc: true, hasScroll: false, autoFocus: false, closeOnBackdropClick: false, diff --git a/security-c4po-angular/src/shared/services/project.service.mock.ts b/security-c4po-angular/src/shared/services/project.service.mock.ts index c4e198e..4ce3c1f 100644 --- a/security-c4po-angular/src/shared/services/project.service.mock.ts +++ b/security-c4po-angular/src/shared/services/project.service.mock.ts @@ -1,7 +1,7 @@ import {ProjectService} from '@shared/services/project.service'; import {HttpClient} from '@angular/common/http'; import {Observable, of} from 'rxjs'; -import {Project, SaveProjectDialogBody} from '@shared/models/project.model'; +import {Project, ProjectDialogBody} from '@shared/models/project.model'; export class ProjectServiceMock implements Required { @@ -12,7 +12,11 @@ export class ProjectServiceMock implements Required { return of([]); } - saveProject(saveProject: SaveProjectDialogBody): Observable { + saveProject(saveProject: ProjectDialogBody): Observable { + return of(); + } + + updateProject(projectId: string, project: ProjectDialogBody): Observable { return of(); } diff --git a/security-c4po-angular/src/shared/services/project.service.spec.ts b/security-c4po-angular/src/shared/services/project.service.spec.ts index ca8e4c6..e655285 100644 --- a/security-c4po-angular/src/shared/services/project.service.spec.ts +++ b/security-c4po-angular/src/shared/services/project.service.spec.ts @@ -4,7 +4,7 @@ import {ProjectService} from './project.service'; import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {KeycloakService} from 'keycloak-angular'; -import {Project, SaveProjectDialogBody} from '@shared/models/project.model'; +import {Project, ProjectDialogBody} from '@shared/models/project.model'; import {environment} from '../../environments/environment'; describe('ProjectService', () => { @@ -76,7 +76,7 @@ describe('ProjectService', () => { describe('saveProject', () => { // arrange - const mockSaveProjectDialogBody: SaveProjectDialogBody = { + const mockSaveProjectDialogBody: ProjectDialogBody = { client: 'E Corp', title: 'Some Mock API (v1.0) Scanning', tester: 'Novatester', diff --git a/security-c4po-angular/src/shared/services/project.service.ts b/security-c4po-angular/src/shared/services/project.service.ts index beb0678..11a9826 100644 --- a/security-c4po-angular/src/shared/services/project.service.ts +++ b/security-c4po-angular/src/shared/services/project.service.ts @@ -1,7 +1,7 @@ import {Injectable} from '@angular/core'; import {environment} from '../../environments/environment'; import {HttpClient} from '@angular/common/http'; -import {Project, SaveProjectDialogBody} from '../models/project.model'; +import {Project, ProjectDialogBody} from '../models/project.model'; import {Observable} from 'rxjs'; @Injectable({ @@ -25,10 +25,20 @@ export class ProjectService { * Save Project * @param project the information of the project */ - public saveProject(project: SaveProjectDialogBody): Observable { + public saveProject(project: ProjectDialogBody): Observable { return this.http.post(`${this.apiBaseURL}`, project); } + /** + * Update Project + * @param projectId the id of the project + * @param project the information of the project + */ + public updateProject(projectId: string, project: ProjectDialogBody): Observable { + console.log('update Project'); + return this.http.patch(`${this.apiBaseURL}/${projectId}`, project); + } + /** * Delete Project * @param projectId the id of the project diff --git a/security-c4po-angular/tsconfig.json b/security-c4po-angular/tsconfig.json index bf60e0f..d9d85c4 100644 --- a/security-c4po-angular/tsconfig.json +++ b/security-c4po-angular/tsconfig.json @@ -7,6 +7,7 @@ "sourceMap": true, "declaration": false, "downlevelIteration": true, + "esModuleInterop": true, "experimentalDecorators": true, "allowSyntheticDefaultImports": true, "moduleResolution": "node", diff --git a/security-c4po-angular/tsconfig.spec.json b/security-c4po-angular/tsconfig.spec.json index 2b6775c..d18c4fa 100644 --- a/security-c4po-angular/tsconfig.spec.json +++ b/security-c4po-angular/tsconfig.spec.json @@ -6,6 +6,7 @@ "jest" ], "module": "commonjs", + "esModuleInterop": true, "emitDecoratorMetadata": true, "allowJs": true, }, diff --git a/security-c4po-cfg/kc/docker-compose.keycloak.yml b/security-c4po-cfg/kc/docker-compose.keycloak.yml index 050428c..51204a1 100644 --- a/security-c4po-cfg/kc/docker-compose.keycloak.yml +++ b/security-c4po-cfg/kc/docker-compose.keycloak.yml @@ -12,7 +12,7 @@ services: - ../cfg/keycloak.env c4po-keycloak-postgress: container_name: c4po-keycloak-postgres - image: postgres:latest + image: postgres:10.16-alpine env_file: - ../cfg/keycloakdb.env ports: