diff --git a/Jenkinsfile b/Jenkinsfile index 797871e69d0bf22a4e404ba46eff9ca3f8307a50..3298e8c38b7aaa8035e6f0540e21d8df572f33ab 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -97,7 +97,7 @@ pipeline { steps { script { FAILED_STAGE=env.STAGE_NAME - IMAGE_TAG = "${env.BRANCH_NAME}-${VERSION}" + IMAGE_TAG = generateImageTag() container("maven-17"){ configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) { @@ -162,7 +162,7 @@ pipeline { } } } - stage('Deploy Goofy') { + stage('Tag and Push Docker Image') { when { anyOf { branch 'master' @@ -173,49 +173,29 @@ pipeline { steps { script { FAILED_STAGE = env.STAGE_NAME - } - container("docker") { - script { - withCredentials([usernamePassword(credentialsId: 'jenkins-docker-login', usernameVariable: 'USER', passwordVariable: 'PASSWORD')]) { - sh 'docker login docker.ozg-sh.de -u ${USER} -p ${PASSWORD}' - - if (env.BRANCH_NAME == 'release') { - sh "docker tag docker.ozg-sh.de/goofy:${IMAGE_TAG} docker.ozg-sh.de/goofy:latest" - sh 'docker push docker.ozg-sh.de/goofy:latest' - } - - if (env.BRANCH_NAME == 'master') { - sh "docker tag docker.ozg-sh.de/goofy:${IMAGE_TAG} docker.ozg-sh.de/goofy:snapshot-latest" - sh 'docker push docker.ozg-sh.de/goofy:snapshot-latest' - } - } + + if (env.BRANCH_NAME == 'master') { + tagAndPushDockerImage('snapshot-latest') + } + else if (env.BRANCH_NAME == 'release') { + tagAndPushDockerImage('latest') } } } } - stage('Rollout (kiel-dev & ea-dev) | (kiel-test $ sl-test) Goofy') { + stage('Trigger Dev rollout') { when { - anyOf { - branch 'master' - branch 'release' - } + branch 'master' } - steps { script { FAILED_STAGE = env.STAGE_NAME - } - container("k8s"){ - script { - if (env.BRANCH_NAME == 'master') { - sh 'kubectl rollout restart deployment/goofy -n sh-kiel-dev' - sh 'kubectl rollout status deployment/goofy -n sh-kiel-dev' + checkoutProvisioningRepo() - sh 'kubectl rollout restart deployment/goofy -n sh-ea-dev' - sh 'kubectl rollout status deployment/goofy -n sh-ea-dev' - } - } + setNewGoofyProvisioningVersion('dev') + + pushNewProvisioningVersion('dev') } } } @@ -287,6 +267,24 @@ pipeline { } } } + stage('Trigger Test | Stage rollout') { + when { + branch 'release' + } + + steps { + script { + FAILED_STAGE = env.STAGE_NAME + + checkoutProvisioningRepo() + + setNewGoofyProvisioningVersion('test') + setNewGoofyProvisioningVersion('stage') + + pushNewProvisioningVersion('test stage') + } + } + } } post { failure { @@ -299,6 +297,27 @@ pipeline { } } +Void tagAndPushDockerImage(String newTag){ + container("docker") { + withCredentials([usernamePassword(credentialsId: 'jenkins-docker-login', usernameVariable: 'USER', passwordVariable: 'PASSWORD')]) { + sh 'docker login docker.ozg-sh.de -u ${USER} -p ${PASSWORD}' + + sh "docker tag docker.ozg-sh.de/goofy:${IMAGE_TAG} docker.ozg-sh.de/goofy:${newTag}" + sh "docker push docker.ozg-sh.de/goofy:${newTag}" + } + } +} + +String generateImageTag() { + def imageTag = "${env.BRANCH_NAME}-${VERSION}" + + if (env.BRANCH_NAME == 'master') { + imageTag += "-${env.GIT_COMMIT.take(7)}" + } + + return imageTag +} + Void startEnvironment(String bezeichner, String stage, String imageTag, Boolean isEa) { setupAnsible(imageTag, stage, isEa) @@ -338,7 +357,7 @@ Void setAnsibleKubeConfig() { } } -Void checkoutProvisioningRepo(String stage) { +Void checkoutProvisioningRepo(String stage="") { withCredentials([usernamePassword(credentialsId: 'jenkins-gitea-access-token', passwordVariable: 'TOKEN', usernameVariable: 'USER')]) { dir(stage) { sh 'git clone https://${USER}:${TOKEN}@git.ozg-sh.de/mgm/provisioning.git' @@ -443,9 +462,15 @@ Void rolloutKopStack(String bezeichner, String stage) { "kop_postfach_api_key":"", \ "install_afm_adapter":false, \ "install_fs_adapter":false, \ - "external_db_enabled":false}""" + "external_db_enabled":false, \ + "disable_update":true}""" - sh "ansible-playbook playbooks/rollout.yml --extra-vars '${ansibleVars}'" + if (env.BRANCH_NAME == 'release') { + sh "ansible-playbook playbook/rollout.yml --extra-vars '${ansibleVars}'" + } + else { + sh "ansible-playbook playbooks/rollout.yml --extra-vars '${ansibleVars}'" + } } } } @@ -464,7 +489,12 @@ Void addKeycloakGroups(String bezeichner, String stage) { }""" dir("${stage}/provisioning") { - sh "ansible-playbook playbooks/add-keycloak-group.yml --extra-vars '${ansibleVars}'" + if (env.BRANCH_NAME == 'release') { + sh "ansible-playbook playbook/add-keycloak-group.yml --extra-vars '${ansibleVars}'" + } + else { + sh "ansible-playbook playbooks/add-keycloak-group.yml --extra-vars '${ansibleVars}'" + } } } } @@ -484,7 +514,12 @@ Void addKeycloakUser(String bezeichner, String stage) { }""" dir("${stage}/provisioning") { - sh "ansible-playbook playbooks/add-keycloak-user.yml --extra-vars '${ansibleVars}'" + if (env.BRANCH_NAME == 'release') { + sh "ansible-playbook playbook/add-keycloak-user.yml --extra-vars '${ansibleVars}'" + } + else { + sh "ansible-playbook playbooks/add-keycloak-user.yml --extra-vars '${ansibleVars}'" + } } } } @@ -497,7 +532,12 @@ Void deleteKopStack(String bezeichner, String stage) { "kop_env":"dev", \ "kop_bezeichner":${bezeichner}}""" - sh "ansible-playbook playbooks/delete-commune.yml --extra-vars '${ansibleVars}'" + if (env.BRANCH_NAME == 'release') { + sh "ansible-playbook playbook/delete-commune.yml --extra-vars '${ansibleVars}'" + } + else { + sh "ansible-playbook playbooks/delete-commune.yml --extra-vars '${ansibleVars}'" + } } } } @@ -534,7 +574,6 @@ String runTests(String stageName, String bezeichner, String reportFolder) { } } - String makeUrlConform(String input) { return input.replaceAll(/[^a-zA-Z0-9]+/, "").toLowerCase() } @@ -558,7 +597,6 @@ String cutBranchNameForKeycloakRealm(String branchName, String stageName) { return branchName } - String generateCypressConfig(String stage, String bezeichner, String testFolder) { def namespace = "sh-${bezeichner}-dev" def configName = "cypress-ci-"+testFolder+".json" @@ -641,6 +679,38 @@ Void initHelmRepo() { } } +Void setNewGoofyProvisioningVersion(String environment) { + dir("provisioning") { + def envFile = "inventories/group_vars/${environment}/versions" + + if (env.BRANCH_NAME == 'release') { + envFile = "playbook/inventory/versions/${environment}.yml" + } + def envVersions = readYaml file: envFile + + envVersions.versions.goofy.image.tag = IMAGE_TAG + + writeYaml file: envFile, data: envVersions, overwrite: true + } +} + +Void pushNewProvisioningVersion(String environment) { + withCredentials([usernamePassword(credentialsId: 'jenkins-gitea-access-token', passwordVariable: 'TOKEN', usernameVariable: 'USER')]) { + dir('provisioning') { + if (env.BRANCH_NAME == 'release') { + sh 'git add playbook/inventory/versions/.' + } + else { + sh 'git add inventories/group_vars/*/versions' + } + sh 'git config user.email "jenkins@ozg.de"' + sh 'git config user.name "jenkins"' + sh "git commit -m 'jenkins rollout ${environment} goofy version ${IMAGE_TAG}'" + sh 'git push https://${USER}:${TOKEN}@git.ozg-sh.de/mgm/provisioning.git' + } + } +} + def getElasticsearchSecret(namespace) { container("k8s"){ script { diff --git a/goofy-client/libs/navigation/src/lib/header-container/header-container.component.ts b/goofy-client/libs/navigation/src/lib/header-container/header-container.component.ts index 1ac12eadeda9850e6c1a9ac4f24b74114a2b91ac..7a884f0c64b6e6edaf5217ecdde397855f65f69b 100644 --- a/goofy-client/libs/navigation/src/lib/header-container/header-container.component.ts +++ b/goofy-client/libs/navigation/src/lib/header-container/header-container.component.ts @@ -9,7 +9,6 @@ import { Observable } from 'rxjs'; styleUrls: ['./header-container.component.scss'] }) export class HeaderContainerComponent { - navigationCollapse$: Observable<boolean>; constructor( diff --git a/goofy-client/libs/tech-shared/src/lib/pipe/has-link.pipe.spec.ts b/goofy-client/libs/tech-shared/src/lib/pipe/has-link.pipe.spec.ts index a79e88cff27da627162cacb7341f64404e01b1ac..f04ba918de0d428e2c266757650bd2dbc92875ed 100644 --- a/goofy-client/libs/tech-shared/src/lib/pipe/has-link.pipe.spec.ts +++ b/goofy-client/libs/tech-shared/src/lib/pipe/has-link.pipe.spec.ts @@ -18,4 +18,10 @@ describe('HasLinkPipe', () => { expect(result).toBe(false); }) + + it('should return false on null resource', () => { + const result: boolean = pipe.transform(null, dummyLink); + + expect(result).toBe(false); + }) }) diff --git a/goofy-client/libs/tech-shared/src/lib/tech-shared.module.ts b/goofy-client/libs/tech-shared/src/lib/tech-shared.module.ts index 67328c81f7d110f528ba7d4282651a251f6ddf24..71a35c3ed94c563e7fea7be87c8299ccf9160802 100644 --- a/goofy-client/libs/tech-shared/src/lib/tech-shared.module.ts +++ b/goofy-client/libs/tech-shared/src/lib/tech-shared.module.ts @@ -27,7 +27,7 @@ import { ToTrafficLightPipe } from './pipe/to-traffic-light.pipe'; ToTrafficLightTooltipPipe, ToEmbeddedResourcesPipe, ConvertForDataTestPipe, - FileSizePipe, + FileSizePipe ], exports: [ FormatToPrettyDatePipe, diff --git a/goofy-client/libs/test-utils/src/lib/helper.ts b/goofy-client/libs/test-utils/src/lib/helper.ts index 7c775584cf72b5bd3546ab540fdc24deb7661f68..0071199dcd46eaa0186b7976c45a57bc01964d88 100644 --- a/goofy-client/libs/test-utils/src/lib/helper.ts +++ b/goofy-client/libs/test-utils/src/lib/helper.ts @@ -25,4 +25,8 @@ export function dispatchEventFromFixture(fixture: ComponentFixture<any>, element export function getDebugElementFromFixtureByCss(fixture: ComponentFixture<any>, query: string): DebugElement { return fixture.debugElement.query(By.css(query)); -} \ No newline at end of file +} + +export function getElementFromDomRoot(fixture: ComponentFixture<any>, htmlElement: string): any { + return fixture.nativeElement.parentNode.querySelector(htmlElement); +} diff --git a/goofy-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.html b/goofy-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.html new file mode 100644 index 0000000000000000000000000000000000000000..7235740b584452e2b564af2c26a2bda33f575a81 --- /dev/null +++ b/goofy-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.html @@ -0,0 +1,6 @@ +<mat-slide-toggle color="primary" + [disabled]="disabled" + [matTooltip]="toolTip" + [checked]="checked" + (change)="valueChanged.emit($event.checked)">{{label}} +</mat-slide-toggle> \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-darkmode/user-settings-darkmode.component.scss b/goofy-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.scss similarity index 100% rename from goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-darkmode/user-settings-darkmode.component.scss rename to goofy-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.scss diff --git a/goofy-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.spec.ts b/goofy-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd765783a48db51221dd014d4a269938cb84a698 --- /dev/null +++ b/goofy-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.spec.ts @@ -0,0 +1,31 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatRippleModule } from '@angular/material/core'; +import { MatSlideToggle } from '@angular/material/slide-toggle'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { SlideToggleComponent } from './slide-toggle.component'; + +describe('SlideToggleComponent', () => { + let component: SlideToggleComponent; + let fixture: ComponentFixture<SlideToggleComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + MatTooltipModule, + MatRippleModule + ], + declarations: [ + SlideToggleComponent, + MatSlideToggle + ], + }).compileComponents(); + + fixture = TestBed.createComponent(SlideToggleComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); \ No newline at end of file diff --git a/goofy-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.ts b/goofy-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..3fe18601f2128057e3046662b3cfe7f6badbf34b --- /dev/null +++ b/goofy-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.ts @@ -0,0 +1,17 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { EMPTY_STRING } from '@goofy-client/tech-shared'; + +@Component({ + selector: 'goofy-client-slide-toggle', + templateUrl: './slide-toggle.component.html', + styleUrls: ['./slide-toggle.component.scss'], +}) +export class SlideToggleComponent { + + @Input() checked: boolean = false; + @Input() label: string = EMPTY_STRING; + @Input() toolTip: string = EMPTY_STRING; + @Input() disabled: boolean = false; + + @Output() valueChanged: EventEmitter<boolean> = new EventEmitter(); +} \ No newline at end of file diff --git a/goofy-client/libs/ui/src/lib/ui/ui.module.ts b/goofy-client/libs/ui/src/lib/ui/ui.module.ts index 22a7a0090517c78fe341797187ed68d2dc767a32..017ea2d8687bd81935dde6f5d948a277efbe13d8 100644 --- a/goofy-client/libs/ui/src/lib/ui/ui.module.ts +++ b/goofy-client/libs/ui/src/lib/ui/ui.module.ts @@ -58,6 +58,7 @@ import { } from './mattooltip/mattooltip.directive'; import { InternalServerErrorDialogComponent } from './notification/internal-server-error-dialog/internal-server-error-dialog.component'; import { ProgressBarComponent } from './progress-bar/progress-bar.component'; +import { SlideToggleComponent } from './slide-toggle/slide-toggle.component'; import { SpinnerComponent } from './spinner/spinner.component'; import { SubnavigationComponent } from './subnavigation/subnavigation.component'; import { ValidationErrorComponent } from './validation-error/validation-error.component'; @@ -87,7 +88,8 @@ const components = [ MattooltipClassDirective, PostfachIconComponent, AccordionComponent, - AppIconComponent + AppIconComponent, + SlideToggleComponent ]; const modules = [ diff --git a/goofy-client/libs/user-settings/src/index.ts b/goofy-client/libs/user-settings/src/index.ts index ba9f3be48abca118db96c0fabea35ac298590866..0aa6dc8d1f8bf46f46e05ffcb3e83dd0e549dd78 100644 --- a/goofy-client/libs/user-settings/src/index.ts +++ b/goofy-client/libs/user-settings/src/index.ts @@ -1,4 +1,3 @@ export * from './lib/user-settings-container/user-settings-container.component'; -export * from './lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component'; export * from './lib/user-settings.module'; diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.html b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.html index 7cff27785933adb77a43e9155b796fd3efb9d9d8..9569f67d6ee739e66de75549bb80e57920697782 100644 --- a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.html +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.html @@ -1,16 +1 @@ -<goofy-client-icon-button-with-spinner icon="settings" toolTip="Einstellungen" - [matMenuTriggerFor]="settingsMenu"> -</goofy-client-icon-button-with-spinner> - -<mat-menu #settingsMenu="matMenu"> - <div class="menu-container" (click)="$event.stopPropagation()"> - <goofy-client-user-settings-email-benachrichtigung - [userSettings$]="userSettings$" - (valueChanged)="changeNotificationsSendFor($event)" - ></goofy-client-user-settings-email-benachrichtigung> - <goofy-client-user-settings-darkmode - [darkMode$]="darkMode$" - (darkModeEmitter)="changeColorMode($event)" - ></goofy-client-user-settings-darkmode> - </div> -</mat-menu> +<goofy-client-user-settings [apiRoot]="apiRoot$ | async"></goofy-client-user-settings> \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.scss b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.scss index e15dab43b6e1199516db6bca6fe3c9ad2574d47e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.scss +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.scss @@ -1,8 +0,0 @@ -.menu-container { - margin: 12px 16px; -} - -goofy-client-icon-button-with-spinner, -mat-slide-toggle { - display: block; -} diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.spec.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.spec.ts index d11f9673e482b3b32a9c60b9f203382028210041..103e05eebbe727bcd20b280ce1ec282501e6df2b 100644 --- a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.spec.ts +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.spec.ts @@ -1,41 +1,26 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatMenuModule } from '@angular/material/menu'; -import { AppService } from '@goofy-client/app-shared'; -import { mock } from '@goofy-client/test-utils'; -import { IconButtonWithSpinnerComponent } from '@goofy-client/ui'; -import { UserSettingsService } from '@goofy-client/user-settings-shared'; -import { NotificationsSendFor } from 'libs/user-settings-shared/src/lib/user-settings.model'; +import { ApiRootFacade } from '@goofy-client/api-root-shared'; +import { Mock, mock } from '@goofy-client/test-utils'; import { MockComponent } from 'ng-mocks'; -import { BehaviorSubject } from 'rxjs'; import { UserSettingsContainerComponent } from './user-settings-container.component'; -import { UserSettingsDarkmodeComponent } from './user-settings-darkmode/user-settings-darkmode.component'; -import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component'; +import { UserSettingsComponent } from './user-settings/user-settings.component'; describe('UserSettingsContainerComponent', () => { let component: UserSettingsContainerComponent; let fixture: ComponentFixture<UserSettingsContainerComponent>; - const darkModeSubj: BehaviorSubject<boolean> = new BehaviorSubject(false); - const appService = { ...mock(AppService), getDarkMode: () => darkModeSubj }; - const userSettingsService = { ...mock(UserSettingsService), setUserSettings: jest.fn() }; + const apiRootFacade: Mock<ApiRootFacade> = { ...mock(ApiRootFacade), getApiRoot: jest.fn() }; beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [MatMenuModule], declarations: [ UserSettingsContainerComponent, - MockComponent(UserSettingsDarkmodeComponent), - MockComponent(UserSettingsEmailBenachrichtigungComponent), - MockComponent(IconButtonWithSpinnerComponent) + MockComponent(UserSettingsComponent) ], providers: [ { - provide: AppService, - useValue: appService, - }, - { - provide: UserSettingsService, - useValue: userSettingsService + provide: ApiRootFacade, + useValue: apiRootFacade } ], }); @@ -44,34 +29,19 @@ describe('UserSettingsContainerComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(UserSettingsContainerComponent); component = fixture.componentInstance; - fixture.detectChanges(); + fixture.autoDetectChanges(true); }); it('should create', () => { expect(component).toBeTruthy(); }); - describe('change color mode', () => { - - it('should call app service', () => { - component.changeColorMode(true); - - expect(appService.setDarkMode).toHaveBeenCalledWith(true); - }) - }) - - describe('change notifications send for', () => { - - it('should call service with ALL', () => { - component.changeNotificationsSendFor(true); - - expect(userSettingsService.setUserSettings).toHaveBeenCalledWith({ notificationsSendFor: NotificationsSendFor.ALL }); - }) + describe('ngOnInit', () => { - it('should call service with NONE', () => { - component.changeNotificationsSendFor(false); + it('should call apiRoot facade', () => { + component.ngOnInit(); - expect(userSettingsService.setUserSettings).toHaveBeenCalledWith({ notificationsSendFor: NotificationsSendFor.NONE }); + expect(apiRootFacade.getApiRoot).toHaveBeenCalled(); }) }) }); diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.ts index 3ebe11daa5b45cdd973c475cd500f065bc3581d2..fece5a34c85f38306d70528c2eb864337b9caa21 100644 --- a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.ts +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.ts @@ -1,9 +1,6 @@ -import { DOCUMENT } from '@angular/common'; -import { Component, Inject, OnInit, Renderer2 } from '@angular/core'; -import { AppService, localStorageDark } from '@goofy-client/app-shared'; -import { StateResource } from '@goofy-client/tech-shared'; -import { UserSettingsService } from '@goofy-client/user-settings-shared'; -import { NotificationsSendFor, UserSettings, UserSettingsResource } from 'libs/user-settings-shared/src/lib/user-settings.model'; +import { Component, OnInit } from '@angular/core'; +import { ApiRootFacade, ApiRootResource } from '@goofy-client/api-root-shared'; +import { createEmptyStateResource, StateResource } from '@goofy-client/tech-shared'; import { Observable, of } from 'rxjs'; @Component({ @@ -12,50 +9,12 @@ import { Observable, of } from 'rxjs'; styleUrls: ['./user-settings-container.component.scss'], }) export class UserSettingsContainerComponent implements OnInit { - darkMode$: Observable<boolean> = of(true); - userSettings$: Observable<StateResource<UserSettingsResource>>; - constructor( - private renderer: Renderer2, - private appService: AppService, - private userSettingsService: UserSettingsService, - @Inject(DOCUMENT) private document: Document - ) { - this.darkMode$ = this.appService.getDarkMode(); + apiRoot$: Observable<StateResource<ApiRootResource>> = of(createEmptyStateResource<ApiRootResource>()); - this.subscribeToDarkMode(); - } + constructor(private apiRootFacade: ApiRootFacade) { } ngOnInit(): void { - this.userSettings$ = this.userSettingsService.getUserSettings(); - } - - private subscribeToDarkMode(): void { - this.darkMode$.subscribe((darkMode) => - darkMode - ? this.addClass(localStorageDark) - : this.removeClass(localStorageDark) - ); - } - - private addClass(styleClass: string): void { - this.renderer.addClass(this.document.body, styleClass); - } - - private removeClass(styleClass: string): void { - this.renderer.removeClass(this.document.body, styleClass); - } - - changeColorMode(darkMode: boolean): void { - this.appService.setDarkMode(darkMode); - } - - changeNotificationsSendFor(toggleValue: boolean): void { - this.userSettingsService.setUserSettings(this.createUserSettings(toggleValue)); - } - - private createUserSettings(toggleValue: boolean): UserSettings { - const notificationsSendFor: NotificationsSendFor = toggleValue ? NotificationsSendFor.ALL : NotificationsSendFor.NONE; - return { notificationsSendFor }; + this.apiRoot$ = this.apiRootFacade.getApiRoot(); } } \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-darkmode/user-settings-darkmode.component.html b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-darkmode/user-settings-darkmode.component.html deleted file mode 100644 index 07a006c57442bef409a85437b10a68fde2f5c680..0000000000000000000000000000000000000000 --- a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-darkmode/user-settings-darkmode.component.html +++ /dev/null @@ -1,6 +0,0 @@ -<mat-slide-toggle - color="primary" - [checked]="darkMode$ | async" - (change)="darkModeEmitter.emit($event.checked)" - >Dark Mode -</mat-slide-toggle> diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.html b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.html deleted file mode 100644 index 90823c5225e8680fc0f3c4e8f2d59ada0db9366e..0000000000000000000000000000000000000000 --- a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.html +++ /dev/null @@ -1,8 +0,0 @@ -<ng-container *ngIf="(userSettings$ | async)?.resource as userSettings"> - <mat-slide-toggle data-test-id="toggle-notifications-send-for" - color="primary" - matTooltip="Benachrichtigung per E-Mail bei Eingang eines Antrags" - [checked]="getToggleStatus(userSettings)" - (change)="valueChanged.emit($event.checked)">Benachrichtigung per E-Mail - </mat-slide-toggle> -</ng-container> \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.scss b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.scss deleted file mode 100644 index 92276dfe14738302abcf74e348103b1dfb94c9fe..0000000000000000000000000000000000000000 --- a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -mat-slide-toggle { - margin-bottom: 0.5rem; -} diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.spec.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.spec.ts deleted file mode 100644 index 84969ed2659f95fb7dd76e3fd5eb56be1719b2f2..0000000000000000000000000000000000000000 --- a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatRippleModule } from '@angular/material/core'; -import { MatMenuModule } from '@angular/material/menu'; -import { MatSlideToggle } from '@angular/material/slide-toggle'; -import { createStateResource } from '@goofy-client/tech-shared'; - -import { dispatchEventFromFixture, mock } from '@goofy-client/test-utils'; -import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; -import { NotificationsSendFor } from 'libs/user-settings-shared/src/lib/user-settings.model'; -import { createUserSettings, createUserSettingsResource } from 'libs/user-settings-shared/test/user-settings'; -import { of } from 'rxjs'; -import { EventEmitter } from 'stream'; -import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-email-benachrichtigung.component'; - -describe('UserSettingsEmailBenachrichtigungComponent', () => { - let component: UserSettingsEmailBenachrichtigungComponent; - let fixture: ComponentFixture<UserSettingsEmailBenachrichtigungComponent>; - - const toggle: string = getDataTestIdOf('toggle-notifications-send-for'); - const userSettings = createUserSettings(); - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [MatMenuModule, MatRippleModule], - declarations: [UserSettingsEmailBenachrichtigungComponent, MatSlideToggle], - }).compileComponents(); - - fixture = TestBed.createComponent( - UserSettingsEmailBenachrichtigungComponent - ); - component = fixture.componentInstance; - component.userSettings$ = of(createStateResource(createUserSettingsResource())); - component.valueChanged = { ...<any>mock(EventEmitter), emit: jest.fn() }; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should show toggle', () => { - const element = fixture.nativeElement.querySelector(toggle); - - expect(element).toBeInstanceOf(HTMLElement); - }) - - describe('toggle status', () => { - it('should be set if userSettings.notificationsSendFor is ALL', () => { - userSettings.notificationsSendFor = NotificationsSendFor.ALL; - - const result: boolean = component.getToggleStatus(userSettings); - - expect(result).toBeTruthy(); - }) - - it('should not be set if userSettings.notificationsSendFor is NONE', () => { - userSettings.notificationsSendFor = NotificationsSendFor.NONE; - - const result: boolean = component.getToggleStatus(userSettings); - - expect(result).toBeFalsy(); - }) - - it('should emit value if toggled', () => { - dispatchEventFromFixture(fixture, toggle, 'change'); - - expect(component.valueChanged.emit).toHaveBeenCalled(); - }) - }) -}); diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.html b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..a560d5d9197ec12d62d5bf507d8416d4b2d6f48a --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.html @@ -0,0 +1,4 @@ +<goofy-client-user-settings-darkmode + [darkMode]="darkMode$ | async" + (valueChanged)="changeColorMode($event)"> +</goofy-client-user-settings-darkmode> \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.scss b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.spec.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..d643d606c471f1eb9e23ad2af9d550bdbf0da4e6 --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.spec.ts @@ -0,0 +1,47 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { AppService } from '@goofy-client/app-shared'; +import { mock } from '@goofy-client/test-utils'; +import { MockComponent } from 'ng-mocks'; +import { BehaviorSubject } from 'rxjs'; +import { UserSettingsDarkmodeContainerComponent } from './user-settings-darkmode-container.component'; +import { UserSettingsDarkmodeComponent } from './user-settings-darkmode/user-settings-darkmode.component'; + +describe('UserSettingsDarkmodeContainerComponent', () => { + let component: UserSettingsDarkmodeContainerComponent; + let fixture: ComponentFixture<UserSettingsDarkmodeContainerComponent>; + + const darkModeSubj: BehaviorSubject<boolean> = new BehaviorSubject(false); + const appService = { ...mock(AppService), getDarkMode: () => darkModeSubj }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + UserSettingsDarkmodeContainerComponent, + MockComponent(UserSettingsDarkmodeComponent) + ], + providers: [ + { + provide: AppService, + useValue: appService, + } + ] + }).compileComponents(); + + fixture = TestBed.createComponent(UserSettingsDarkmodeContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('change color mode', () => { + + it('should call app service', () => { + component.changeColorMode(true); + + expect(appService.setDarkMode).toHaveBeenCalledWith(true); + }) + }) +}); \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..07d0a9d53dcb43474a42c3bedbeabd7b0f999953 --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.ts @@ -0,0 +1,46 @@ +import { DOCUMENT } from '@angular/common'; +import { Component, Inject, OnInit, Renderer2 } from '@angular/core'; +import { AppService, localStorageDark } from '@goofy-client/app-shared'; +import { Observable } from 'rxjs'; + +@Component({ + selector: 'goofy-client-user-settings-darkmode-container', + templateUrl: './user-settings-darkmode-container.component.html', + styleUrls: ['./user-settings-darkmode-container.component.scss'], +}) +export class UserSettingsDarkmodeContainerComponent implements OnInit { + + darkMode$: Observable<boolean>; + + constructor( + private renderer: Renderer2, + private appService: AppService, + @Inject(DOCUMENT) private document: Document + ) { } + + ngOnInit(): void { + this.darkMode$ = this.appService.getDarkMode(); + + this.subscribeToDarkMode(); + } + + private subscribeToDarkMode(): void { + this.darkMode$.subscribe((darkMode) => + darkMode + ? this.addClass(localStorageDark) + : this.removeClass(localStorageDark) + ); + } + + private addClass(styleClass: string): void { + this.renderer.addClass(this.document.body, styleClass); + } + + private removeClass(styleClass: string): void { + this.renderer.removeClass(this.document.body, styleClass); + } + + public changeColorMode(darkMode: boolean): void { + this.appService.setDarkMode(darkMode); + } +} \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.html b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.html new file mode 100644 index 0000000000000000000000000000000000000000..0eb6e7c227193cd7124a3b6b710014715b9c9a63 --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.html @@ -0,0 +1,6 @@ +<goofy-client-slide-toggle data-test-id="toggle-dark-mode" + label="Dark Mode" + [checked]="darkMode" + (valueChanged)="valueChanged.emit($event)"> +</goofy-client-slide-toggle> + diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.scss b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..da1cfd3eb891a5f6857e27dadc340527de7e240a --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.scss @@ -0,0 +1,3 @@ +goofy-client-slide-toggle { + display: block; +} \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-darkmode/user-settings-darkmode.component.spec.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.spec.ts similarity index 72% rename from goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-darkmode/user-settings-darkmode.component.spec.ts rename to goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.spec.ts index f333224d4ba89c44239501605915654454dcfa27..90d17346a372e6650387e5c36fc6e3eef2d4554b 100644 --- a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-darkmode/user-settings-darkmode.component.spec.ts +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.spec.ts @@ -1,5 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { UiModule } from '@goofy-client/ui'; +import { SlideToggleComponent } from 'libs/ui/src/lib/ui/slide-toggle/slide-toggle.component'; +import { MockComponent } from 'ng-mocks'; import { UserSettingsDarkmodeComponent } from './user-settings-darkmode.component'; describe('UserSettingsDarkmodeComponent', () => { @@ -8,8 +9,10 @@ describe('UserSettingsDarkmodeComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [UiModule], - declarations: [UserSettingsDarkmodeComponent], + declarations: [ + UserSettingsDarkmodeComponent, + MockComponent(SlideToggleComponent) + ], }).compileComponents(); fixture = TestBed.createComponent(UserSettingsDarkmodeComponent); diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-darkmode/user-settings-darkmode.component.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.ts similarity index 63% rename from goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-darkmode/user-settings-darkmode.component.ts rename to goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.ts index 651132cf8620c19aa5b6375164247bf99ddb0384..d8b0ae504705e2ebf05031c768239a5d5c7b6f57 100644 --- a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-darkmode/user-settings-darkmode.component.ts +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.ts @@ -1,5 +1,4 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Observable, of } from 'rxjs'; @Component({ selector: 'goofy-client-user-settings-darkmode', @@ -7,8 +6,8 @@ import { Observable, of } from 'rxjs'; styleUrls: ['./user-settings-darkmode.component.scss'], }) export class UserSettingsDarkmodeComponent { - @Input() darkMode$: Observable<boolean> = of(true); - @Output() public darkModeEmitter: EventEmitter<boolean> = - new EventEmitter(); + @Input() darkMode: boolean; + + @Output() valueChanged: EventEmitter<boolean> = new EventEmitter(); } diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.html b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..cb8e4eef3b53e78862c66ab5d3dec7d2a2dbbb11 --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.html @@ -0,0 +1,4 @@ +<goofy-client-user-settings-email-benachrichtigung + [userSettings]="userSettings$ | async" + (valueChanged)="changeNotificationsSendFor($event)"> +</goofy-client-user-settings-email-benachrichtigung> \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.scss b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.spec.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..9cf1529d435cf71e45b497795ce2d747a556a9b1 --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.spec.ts @@ -0,0 +1,60 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { mock } from '@goofy-client/test-utils'; +import { NotificationsSendFor, UserSettingsService } from '@goofy-client/user-settings-shared'; +import { MockComponent } from 'ng-mocks'; +import { UserSettingsEmailBenachrichtigungContainerComponent } from './user-settings-email-benachrichtigung-container.component'; +import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component'; + +describe('UserSettingsEmailBenachrichtigungContainerComponent', () => { + let component: UserSettingsEmailBenachrichtigungContainerComponent; + let fixture: ComponentFixture<UserSettingsEmailBenachrichtigungContainerComponent>; + + const userSettingsService = { ...mock(UserSettingsService), setUserSettings: jest.fn() }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + UserSettingsEmailBenachrichtigungContainerComponent, + MockComponent(UserSettingsEmailBenachrichtigungComponent) + ], + providers: [ + { + provide: UserSettingsService, + useValue: userSettingsService + } + ], + }).compileComponents(); + + fixture = TestBed.createComponent(UserSettingsEmailBenachrichtigungContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('ngOnInit', () => { + + it('should call userSettings service', () => { + component.ngOnInit(); + + expect(userSettingsService.getUserSettings).toHaveBeenCalled(); + }) + }) + + describe('change notifications send for', () => { + + it('should call service with ALL', () => { + component.changeNotificationsSendFor(true); + + expect(userSettingsService.setUserSettings).toHaveBeenCalledWith({ notificationsSendFor: NotificationsSendFor.ALL }); + }) + + it('should call service with NONE', () => { + component.changeNotificationsSendFor(false); + + expect(userSettingsService.setUserSettings).toHaveBeenCalledWith({ notificationsSendFor: NotificationsSendFor.NONE }); + }) + }) +}); diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..ba354ea97e4c3ae887f9a2aa7aaeb962ef0f4752 --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.ts @@ -0,0 +1,29 @@ +import { Component } from '@angular/core'; +import { StateResource } from '@goofy-client/tech-shared'; +import { NotificationsSendFor, UserSettings, UserSettingsResource, UserSettingsService } from '@goofy-client/user-settings-shared'; +import { Observable } from 'rxjs'; + +@Component({ + selector: 'goofy-client-user-settings-email-benachrichtigung-container', + templateUrl: './user-settings-email-benachrichtigung-container.component.html', + styleUrls: ['./user-settings-email-benachrichtigung-container.component.scss'] +}) +export class UserSettingsEmailBenachrichtigungContainerComponent { + + userSettings$: Observable<StateResource<UserSettingsResource>>; + + constructor(private userSettingsService: UserSettingsService) { } + + ngOnInit(): void { + this.userSettings$ = this.userSettingsService.getUserSettings(); + } + + changeNotificationsSendFor(toggleValue: boolean): void { + this.userSettingsService.setUserSettings(this.createUserSettings(toggleValue)); + } + + private createUserSettings(toggleValue: boolean): UserSettings { + const notificationsSendFor: NotificationsSendFor = toggleValue ? NotificationsSendFor.ALL : NotificationsSendFor.NONE; + return { notificationsSendFor }; + } +} diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.html b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.html new file mode 100644 index 0000000000000000000000000000000000000000..7aa4001e220985f47b3951f4674a2f41fadb2e3e --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.html @@ -0,0 +1,11 @@ +<ng-container *ngIf="userSettings.resource"> + + <goofy-client-slide-toggle data-test-id="toggle-notifications-send-for" + label="Benachrichtigung per E-Mail" + toolTip="Benachrichtigung per E-Mail bei Eingang eines Antrags" + [disabled]="userSettings.resource | notHasLink: userSettingsLinkRel.EDIT" + [checked]="isChecked(userSettings.resource)" + (valueChanged)="valueChanged.emit($event)"> + </goofy-client-slide-toggle> + +</ng-container> \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.scss b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..541defa5587fd7dd46a8ae3e55bf955e3a5dbd90 --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.scss @@ -0,0 +1,4 @@ +goofy-client-slide-toggle { + margin-bottom: 0.5rem; + display: block; +} \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.spec.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ccdbfa447d14e6a3833f6099571badc0369fef5 --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.spec.ts @@ -0,0 +1,86 @@ +import { EventEmitter } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { createEmptyStateResource, createStateResource, NotHasLinkPipe } from '@goofy-client/tech-shared'; +import { dispatchEventFromFixture, getElementFromFixture, Mock, mock, useFromMock } from '@goofy-client/test-utils'; +import { UserSettingsLinkRel } from '@goofy-client/user-settings-shared'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { SlideToggleComponent } from 'libs/ui/src/lib/ui/slide-toggle/slide-toggle.component'; +import { NotificationsSendFor, UserSettings } from 'libs/user-settings-shared/src/lib/user-settings.model'; +import { createUserSettings, createUserSettingsResource } from 'libs/user-settings-shared/test/user-settings'; +import { MockComponent } from 'ng-mocks'; +import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-email-benachrichtigung.component'; + +describe('UserSettingsEmailBenachrichtigungComponent', () => { + let component: UserSettingsEmailBenachrichtigungComponent; + let fixture: ComponentFixture<UserSettingsEmailBenachrichtigungComponent>; + + const notificationSensForToggle: string = getDataTestIdOf('toggle-notifications-send-for'); + + const valueChangedEmitter: Mock<EventEmitter<boolean>> = { ...mock(EventEmitter), emit: jest.fn() }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + NotHasLinkPipe, + UserSettingsEmailBenachrichtigungComponent, + MockComponent(SlideToggleComponent) + ], + }).compileComponents(); + + fixture = TestBed.createComponent(UserSettingsEmailBenachrichtigungComponent); + component = fixture.componentInstance; + component.userSettings = createEmptyStateResource(); + component.valueChanged = useFromMock(valueChangedEmitter); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('toggle', () => { + + it('should be active if notificationsSendFor is ALL', () => { + const userSettings: UserSettings = { ...createUserSettings(), notificationsSendFor: NotificationsSendFor.ALL }; + + const result: boolean = component.isChecked(userSettings); + + expect(result).toBeTruthy(); + }) + + it('should be not active if notificationsSendFor is NONE', () => { + const userSettings: UserSettings = { ...createUserSettings(), notificationsSendFor: NotificationsSendFor.NONE }; + + const result: boolean = component.isChecked(userSettings); + + expect(result).toBeFalsy(); + }) + + it('should emit value if toggled', () => { + component.userSettings = createStateResource(createUserSettingsResource()); + fixture.detectChanges(); + + dispatchEventFromFixture(fixture, notificationSensForToggle, 'valueChanged'); + + expect(component.valueChanged.emit).toHaveBeenCalled(); + }) + + it('should be deactivated if edit link is missing', () => { + component.userSettings = createStateResource(createUserSettingsResource()); + fixture.detectChanges(); + + const element = getElementFromFixture(fixture, notificationSensForToggle); + + expect(element).toHaveAttribute('ng-reflect-disabled', 'true'); + }) + + it('should be activated if edit link exist', () => { + component.userSettings = createStateResource(createUserSettingsResource([UserSettingsLinkRel.EDIT])); + fixture.detectChanges(); + + const element = getElementFromFixture(fixture, notificationSensForToggle); + + expect(element).toHaveAttribute('ng-reflect-disabled', 'false'); + }) + }) +}); diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.ts similarity index 52% rename from goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.ts rename to goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.ts index adb1df1f939759d85464ac9503323a94759f55c2..c75d06adc451eaf4454e35e6c216cceb315ed1c3 100644 --- a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.ts +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.ts @@ -1,7 +1,6 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { StateResource } from '@goofy-client/tech-shared'; -import { NotificationsSendFor, UserSettings, UserSettingsResource } from '@goofy-client/user-settings-shared'; -import { Observable } from 'rxjs'; +import { createEmptyStateResource, StateResource } from '@goofy-client/tech-shared'; +import { NotificationsSendFor, UserSettings, UserSettingsLinkRel, UserSettingsResource } from '@goofy-client/user-settings-shared'; @Component({ selector: 'goofy-client-user-settings-email-benachrichtigung', @@ -9,10 +8,14 @@ import { Observable } from 'rxjs'; styleUrls: ['./user-settings-email-benachrichtigung.component.scss'], }) export class UserSettingsEmailBenachrichtigungComponent { - @Input() userSettings$: Observable<StateResource<UserSettingsResource>>; + + @Input() userSettings: StateResource<UserSettingsResource> = createEmptyStateResource<UserSettingsResource>(); + @Output() valueChanged: EventEmitter<boolean> = new EventEmitter(); - public getToggleStatus(userSettings: UserSettings): boolean { + readonly userSettingsLinkRel = UserSettingsLinkRel; + + public isChecked(userSettings: UserSettings): boolean { return userSettings.notificationsSendFor === NotificationsSendFor.ALL; } -} +} \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.html b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.html new file mode 100644 index 0000000000000000000000000000000000000000..818deb74c0fac712245a6fb44c24f354b756a976 --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.html @@ -0,0 +1 @@ +<goofy-client-icon-button-with-spinner icon="settings" toolTip="Einstellungen" data-test-id="menu-button"></goofy-client-icon-button-with-spinner> \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.scss b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..d7da62a838b151a216dcea229531f0e7d813574f --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.scss @@ -0,0 +1,3 @@ +goofy-client-icon-button-with-spinner { + display: block; +} \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.spec.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..e1579bbb6e91664e24033528cd334c88983f337a --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.spec.ts @@ -0,0 +1,26 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { IconButtonWithSpinnerComponent } from '@goofy-client/ui'; +import { MockComponent } from 'ng-mocks'; +import { UserSettingsMenuButtonComponent } from './user-settings-menu-button.component'; + +describe('UserSettingsMenuButtonComponent', () => { + let component: UserSettingsMenuButtonComponent; + let fixture: ComponentFixture<UserSettingsMenuButtonComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + UserSettingsMenuButtonComponent, + MockComponent(IconButtonWithSpinnerComponent) + ] + }).compileComponents(); + + fixture = TestBed.createComponent(UserSettingsMenuButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..95409cf3727a4aeb4192b75f92c1efa83f2a11ef --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'goofy-client-user-settings-menu-button', + templateUrl: './user-settings-menu-button.component.html', + styleUrls: ['./user-settings-menu-button.component.scss'], +}) +export class UserSettingsMenuButtonComponent { + +} diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.html b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.html new file mode 100644 index 0000000000000000000000000000000000000000..d46c460c866ab0a08822427b9cc1a5c56a211fa6 --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.html @@ -0,0 +1,9 @@ +<goofy-client-user-settings-menu-button [matMenuTriggerFor]="settingsMenu" data-test-id="menu-button"></goofy-client-user-settings-menu-button> + +<!-- TODO Das Menu in eine eigene Componente auslagern um die Technik zu kapseln --> +<mat-menu #settingsMenu="matMenu"> + <div class="menu-container" (click)="$event.stopPropagation()"> + <goofy-client-user-settings-email-benachrichtigung-container *ngIf="apiRoot.resource | hasLink: apiRootLinkRel.CURRENT_USER" data-test-id="email-benachrichtigung-toggle"></goofy-client-user-settings-email-benachrichtigung-container> + <goofy-client-user-settings-darkmode-container></goofy-client-user-settings-darkmode-container> + </div> +</mat-menu> \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.scss b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..038d35c13b62e3a68f60feaf4623f8a76d2cbd29 --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.scss @@ -0,0 +1,3 @@ +.menu-container { + margin: 12px 16px; +} \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.spec.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a5a034792606583324e4a40fdac2e6c52e8360c --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.spec.ts @@ -0,0 +1,70 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatButtonModule } from '@angular/material/button'; +import { MatMenuModule } from '@angular/material/menu'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { ApiRootLinkRel } from '@goofy-client/api-root-shared'; +import { createEmptyStateResource, createStateResource, HasLinkPipe } from '@goofy-client/tech-shared'; +import { getElementFromDomRoot, getElementFromFixture } from '@goofy-client/test-utils'; +import { createApiRootResource } from 'libs/api-root-shared/test/api-root'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { MockComponent } from 'ng-mocks'; +import { UserSettingsDarkmodeContainerComponent } from './user-settings-darkmode-container/user-settings-darkmode-container.component'; +import { UserSettingsEmailBenachrichtigungContainerComponent } from './user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component'; +import { UserSettingsMenuButtonComponent } from './user-settings-menu-button/user-settings-menu-button.component'; +import { UserSettingsComponent } from './user-settings.component'; + +describe('UserSettingsComponent', () => { + let component: UserSettingsComponent; + let fixture: ComponentFixture<UserSettingsComponent>; + + const menuButton: string = getDataTestIdOf('menu-button'); + const emailBenachrichtigung: string = getDataTestIdOf('email-benachrichtigung-toggle'); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + NoopAnimationsModule, + MatButtonModule, + MatMenuModule + ], + declarations: [ + HasLinkPipe, + UserSettingsComponent, + MockComponent(UserSettingsMenuButtonComponent), + MockComponent(UserSettingsEmailBenachrichtigungContainerComponent), + MockComponent(UserSettingsDarkmodeContainerComponent), + ], + }).compileComponents(); + + fixture = TestBed.createComponent(UserSettingsComponent); + component = fixture.componentInstance; + component.apiRoot = createEmptyStateResource() + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('Toggle for "email benachrichtigung"', () => { + + it('should show if link exists', () => { + component.apiRoot = createStateResource(createApiRootResource([ApiRootLinkRel.CURRENT_USER])); + fixture.detectChanges(); + + getElementFromFixture(fixture, menuButton).click(); + const element = getElementFromDomRoot(fixture, emailBenachrichtigung); + + expect(element).toBeInTheDocument(); + }) + + it('should hide if link not exists', () => { + component.apiRoot = createStateResource(createApiRootResource()); + + getElementFromFixture(fixture, menuButton).click(); + const element = getElementFromDomRoot(fixture, emailBenachrichtigung); + + expect(element).not.toBeInTheDocument(); + }) + }) +}); \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..fae9dc99d8e8cb242aa21bd03b3a9770aa46d173 --- /dev/null +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.ts @@ -0,0 +1,15 @@ +import { Component, Input } from '@angular/core'; +import { ApiRootLinkRel, ApiRootResource } from '@goofy-client/api-root-shared'; +import { StateResource } from '@goofy-client/tech-shared'; + +@Component({ + selector: 'goofy-client-user-settings', + templateUrl: './user-settings.component.html', + styleUrls: ['./user-settings.component.scss'], +}) +export class UserSettingsComponent { + + @Input() apiRoot: StateResource<ApiRootResource>; + + readonly apiRootLinkRel = ApiRootLinkRel; +} \ No newline at end of file diff --git a/goofy-client/libs/user-settings/src/lib/user-settings.module.ts b/goofy-client/libs/user-settings/src/lib/user-settings.module.ts index 79c603fe449e56a1414bd9eec6ae65bc3aa9672e..4127c4f4c1857f280b14c2b05b90edbcef13d7da 100644 --- a/goofy-client/libs/user-settings/src/lib/user-settings.module.ts +++ b/goofy-client/libs/user-settings/src/lib/user-settings.module.ts @@ -3,8 +3,12 @@ import { NgModule } from '@angular/core'; import { UiModule } from '@goofy-client/ui'; import { UserSettingsSharedModule } from '@goofy-client/user-settings-shared'; import { UserSettingsContainerComponent } from './user-settings-container/user-settings-container.component'; -import { UserSettingsDarkmodeComponent } from './user-settings-container/user-settings-darkmode/user-settings-darkmode.component'; -import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component'; +import { UserSettingsDarkmodeContainerComponent } from './user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component'; +import { UserSettingsDarkmodeComponent } from './user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component'; +import { UserSettingsEmailBenachrichtigungContainerComponent } from './user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component'; +import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component'; +import { UserSettingsMenuButtonComponent } from './user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component'; +import { UserSettingsComponent } from './user-settings-container/user-settings/user-settings.component'; @NgModule({ imports: [ @@ -16,10 +20,14 @@ import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-cont UserSettingsContainerComponent, UserSettingsEmailBenachrichtigungComponent, UserSettingsDarkmodeComponent, + UserSettingsComponent, + UserSettingsDarkmodeContainerComponent, + UserSettingsEmailBenachrichtigungContainerComponent, + UserSettingsMenuButtonComponent, ], exports: [ UserSettingsContainerComponent, UserSettingsEmailBenachrichtigungComponent, ], }) -export class UserSettingsModule {} +export class UserSettingsModule { } diff --git a/goofy-client/libs/user-settings/src/test-setup.ts b/goofy-client/libs/user-settings/src/test-setup.ts index 08ef82b5d5efa87cb27257314075f6a16eb7a63e..82178098b34faeb3a94a8268bd072d4db95371a3 100644 --- a/goofy-client/libs/user-settings/src/test-setup.ts +++ b/goofy-client/libs/user-settings/src/test-setup.ts @@ -1,9 +1,10 @@ +import '@testing-library/jest-dom'; import 'jest-preset-angular/setup-jest'; import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, - platformBrowserDynamicTesting, + platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; getTestBed().resetTestEnvironment();