diff --git a/alfa-client/.prettierignore b/alfa-client/.prettierignore index ee7824bd9c6d18d685c77479a451c9554c111e9d..0eb1899d00dd4018fa9605a6b746a08a07174333 100644 --- a/alfa-client/.prettierignore +++ b/alfa-client/.prettierignore @@ -6,4 +6,5 @@ packages/workspace/src/generators/**/files/**/*.json /.nx/cache .angular -/.nx/workspace-data \ No newline at end of file +/.nx/workspace-data +*.md \ No newline at end of file diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-zu-oe-hinzufuegen.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-zu-oe-hinzufuegen.cy.ts index 3735e511e5eb33b45987bbf61fb4aa757d02025c..9095c63279a17ffe2cbada1f4de9f956593c0638 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-zu-oe-hinzufuegen.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-zu-oe-hinzufuegen.cy.ts @@ -13,7 +13,7 @@ describe('Organisationseinheit zu Benutzer hinzufügen', () => { const zustaendigeStelleSearchComponent: ZustaendigeStelleDialogE2EComponent = new ZustaendigeStelleDialogE2EComponent(); const organistationsEinheitOrdnungsamt: string = 'Ordnungsamt'; const organisationsEinheitDenkmalpflege: string = 'Denkmalpflege'; - const organisationsEinheitWentorf: string = 'grundschule wentorf'; + const organisationsEinheitLiegenschaften: string = 'Liegenschaften'; const organisationsEinheitNone: string = 'keine zuständige Stelle zugewiesen'; const vorname: string = 'Theo'; const nachname: string = 'Testuser'; @@ -91,7 +91,7 @@ describe('Organisationseinheit zu Benutzer hinzufügen', () => { it('should enable new Organisationseinheit for users after adding it', () => { mainPage.clickOrganisationsEinheitenNavigationItem(); organisationsEinheitenComponent.clickHinzufuegen(); - zustaendigeStelleSearchComponent.enterSearchTerm(organisationsEinheitWentorf); + zustaendigeStelleSearchComponent.enterSearchTerm(organisationsEinheitLiegenschaften); zustaendigeStelleSearchComponent.getZustaendigeStelleTitle(0).then((title: string) => { zustaendigeStelleSearchComponent.clickFoundItem(0); }); @@ -99,12 +99,12 @@ describe('Organisationseinheit zu Benutzer hinzufügen', () => { mainPage.clickBenutzerNavigationItem(); benutzerPage.clickUserEntry(benutzername2); - exist(benutzerPage.getOrganisationsEinheitCheckbox(organisationsEinheitWentorf)); + exist(benutzerPage.getOrganisationsEinheitCheckbox(organisationsEinheitLiegenschaften)); }); it('should add new Organisationseinheit to existing user', () => { - benutzerPage.clickOrganisationsEinheitCheckbox(organistationsEinheitOrdnungsamt); + benutzerPage.clickOrganisationsEinheitCheckbox(organisationsEinheitLiegenschaften); benutzerPage.saveUser(); - benutzerPage.stringExistsInUserEntry(organisationsEinheitWentorf, benutzername2); + benutzerPage.stringExistsInUserEntry(organisationsEinheitLiegenschaften, benutzername2); }); }); diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-laden.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-laden.cy.ts index ed230c60ca0575070181bc4c680f2876b231f808..91a1673e96e41b8dbdae4e4338e864a0527f816e 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-laden.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-laden.cy.ts @@ -48,7 +48,7 @@ describe.skip('TODO: activate after fix for OZG-7391: show Organisationsheiten', it('should show table of Organisationseinheiten', () => { waitForSpinnerToDisappear(); - mainPage.openOrganisationsEinheiten(); + mainPage.clickOrganisationsEinheitenNavigationItem(); exist(organisationsEinheitenTab.getOrganisationsEinheitList()); }); diff --git a/alfa-client/apps/admin/src/app/app.component.ts b/alfa-client/apps/admin/src/app/app.component.ts index fe6c276c6df933b4df3e29605271a7cf31380042..6de5c0ab4da5fed7ffc763b86cdb18e253c44528 100644 --- a/alfa-client/apps/admin/src/app/app.component.ts +++ b/alfa-client/apps/admin/src/app/app.component.ts @@ -27,13 +27,19 @@ import { ROUTES } from '@admin-client/shared'; import { KeycloakTokenService } from '@admin/keycloak-shared'; import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared'; import { BuildInfoComponent } from '@alfa-client/common'; -import { isLoaded, isNotUndefined, mapToResource, StateResource, TechSharedModule } from '@alfa-client/tech-shared'; +import { HasLinkPipe, isLoaded, isNotUndefined, mapToResource, StateResource } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { Component, inject, OnInit } from '@angular/core'; import { Router, RouterLink, RouterOutlet } from '@angular/router'; import { AuthenticationService } from '@authentication'; import { hasLink } from '@ngxp/rest'; -import { AdminLogoIconComponent, NavbarComponent, NavItemComponent, OrgaUnitIconComponent, UsersIconComponent, } from '@ods/system'; +import { + AdminLogoIconComponent, + NavbarComponent, + NavItemComponent, + OrgaUnitIconComponent, + UsersIconComponent, +} from '@ods/system'; import { filter, Observable, Subscription } from 'rxjs'; import { UserProfileButtonContainerComponent } from '../common/user-profile-button-container/user-profile.button-container.component'; import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/unavailable-page.component'; @@ -54,9 +60,9 @@ import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/ RouterOutlet, UnavailablePageComponent, BuildInfoComponent, - TechSharedModule, MenuContainerComponent, RouterLink, + HasLinkPipe, ], }) export class AppComponent implements OnInit { diff --git a/alfa-client/apps/admin/src/main.ts b/alfa-client/apps/admin/src/main.ts index 517ab0538bea573be67b1b8184ec7bb50695c242..de7bed8ea66ac6e222311d9d8c185b4cad477b85 100644 --- a/alfa-client/apps/admin/src/main.ts +++ b/alfa-client/apps/admin/src/main.ts @@ -21,18 +21,23 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { EnvironmentModule, loadEnvironment } from '@alfa-client/environment-shared'; -import { enableProdMode, importProvidersFrom, Injectable } from '@angular/core'; -import { isNil } from 'lodash-es'; - +import { AggregationMappingProvider } from '@admin-client/reporting-shared'; import { ApiRootModule } from '@alfa-client/api-root-shared'; +import { EnvironmentModule, loadEnvironment } from '@alfa-client/environment-shared'; import { NavigationSharedModule } from '@alfa-client/navigation-shared'; import { registerLocaleData } from '@angular/common'; import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import localeDe from '@angular/common/locales/de'; +import { enableProdMode, importProvidersFrom, Injectable } from '@angular/core'; import { bootstrapApplication, BrowserModule } from '@angular/platform-browser'; import { provideAnimations } from '@angular/platform-browser/animations'; -import { ActivatedRouteSnapshot, BaseRouteReuseStrategy, provideRouter, RouteReuseStrategy, withRouterConfig, } from '@angular/router'; +import { + ActivatedRouteSnapshot, + BaseRouteReuseStrategy, + provideRouter, + RouteReuseStrategy, + withRouterConfig, +} from '@angular/router'; import { HttpUnauthorizedInterceptor } from '@authentication'; import { EffectsModule } from '@ngrx/effects'; import { StoreRouterConnectingModule } from '@ngrx/router-store'; @@ -43,6 +48,10 @@ import { ConfigurationsProviders } from 'libs/admin/configuration-shared/src/lib import { PostfachProviders } from 'libs/admin/postfach-shared/src/lib/postfach.providers'; import { SettingsProviders } from 'libs/admin/settings-shared/src/lib/settings.providers'; import { UserProviders } from 'libs/admin/user/src/lib/user.providers'; +import { isNil } from 'lodash-es'; +import { HttpBinaryFileInterceptor } from '../../../libs/tech-shared/src/lib/interceptor/http-binary-file.interceptor'; +import { HttpXsrfInterceptor } from '../../../libs/tech-shared/src/lib/interceptor/http-xsrf.interceptor'; +import { XhrInterceptor } from '../../../libs/tech-shared/src/lib/interceptor/xhr.interceptor'; import { AppComponent } from './app/app.component'; import { appRoutes } from './app/app.routes'; import { environment } from './environments/environment'; @@ -69,10 +78,26 @@ loadEnvironment(environment.environmentUrl).then((env) => { bootstrapApplication(AppComponent, { providers: [ { provide: RouteReuseStrategy, useClass: NoRouteReuseStrategy }, + { + provide: HTTP_INTERCEPTORS, + useClass: XhrInterceptor, + multi: true, + }, + { + provide: HTTP_INTERCEPTORS, + useClass: HttpXsrfInterceptor, + multi: true, + }, + { + provide: HTTP_INTERCEPTORS, + useClass: HttpBinaryFileInterceptor, + multi: true, + }, ConfigurationsProviders, PostfachProviders, SettingsProviders, UserProviders, + AggregationMappingProvider, importProvidersFrom( NavigationSharedModule, BrowserModule, diff --git a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.ts b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.ts index d2d9e1334032279c2fd0aa5b32ffc76a89944534..431f26bb8d2aa1913a5a8b67563aa75466d13ce3 100644 --- a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.ts +++ b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.ts @@ -22,12 +22,13 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { OrganisationsEinheitContainerComponent } from '@admin-client/organisations-einheit'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; import { Component } from '@angular/core'; @Component({ selector: 'organisationseinheit-page', templateUrl: './organisationseinheit-page.component.html', standalone: true, - imports: [OrganisationsEinheitContainerComponent], + imports: [ OrganisationsEinheitContainerComponent, HasLinkPipe], }) export class OrganisationsEinheitPageComponent {} diff --git a/alfa-client/apps/admin/src/pages/statistik/statistik-fields-form-page/statistik-fields-form-page.component.spec.ts b/alfa-client/apps/admin/src/pages/statistik/statistik-fields-form-page/statistik-fields-form-page.component.spec.ts index a861afd0728827a45330d8d5d2d78f63e6dfc5d1..938cc1b0061d2194105629ca70c1e5f8619d881c 100644 --- a/alfa-client/apps/admin/src/pages/statistik/statistik-fields-form-page/statistik-fields-form-page.component.spec.ts +++ b/alfa-client/apps/admin/src/pages/statistik/statistik-fields-form-page/statistik-fields-form-page.component.spec.ts @@ -1,7 +1,7 @@ +import { AdminStatistikFieldsFormComponent } from '@admin-client/statistik'; import { existsAsHtmlElement } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockComponent } from 'ng-mocks'; -import { AdminStatistikFieldsFormComponent } from '../../../../../../libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component'; import { getDataTestIdOf } from '../../../../../../libs/tech-shared/test/data-test'; import { StatistikFieldsFormPageComponent } from './statistik-fields-form-page.component'; diff --git a/alfa-client/apps/admin/src/pages/statistik/statistik-fields-form-page/statistik-fields-form-page.component.ts b/alfa-client/apps/admin/src/pages/statistik/statistik-fields-form-page/statistik-fields-form-page.component.ts index e249c034417fc7133d8cc2c5db690ddcb94ea50f..c4122b72d148865b4219d5446a3c2060574b23e7 100644 --- a/alfa-client/apps/admin/src/pages/statistik/statistik-fields-form-page/statistik-fields-form-page.component.ts +++ b/alfa-client/apps/admin/src/pages/statistik/statistik-fields-form-page/statistik-fields-form-page.component.ts @@ -1,6 +1,6 @@ +import { AdminStatistikFieldsFormComponent } from '@admin-client/statistik'; import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; -import { AdminStatistikFieldsFormComponent } from '../../../../../../libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component'; @Component({ selector: 'statistik-fields-form-page', diff --git a/alfa-client/apps/alfa-e2e/docker-compose.yml b/alfa-client/apps/alfa-e2e/docker-compose.yml index efbb27de9070db53e35dc0e0c7c3d41ed9015966..cb3cff0ebb701a6600ea2204ea18b3928a0ddbbd 100644 --- a/alfa-client/apps/alfa-e2e/docker-compose.yml +++ b/alfa-client/apps/alfa-e2e/docker-compose.yml @@ -154,7 +154,7 @@ services: soft: 65536 hard: 65536 healthcheck: - test: [ 'CMD-SHELL', "curl -s 'http://localhost:9200/_cat/health?h=status' | egrep -q '(green|yellow)'" ] + test: ['CMD-SHELL', "curl -s 'http://localhost:9200/_cat/health?h=status' | egrep -q '(green|yellow)'"] interval: 10s timeout: 10s retries: 5 @@ -195,7 +195,7 @@ services: - 7080:8080 - 7081:8081 healthcheck: - test: [ 'CMD-SHELL', 'wget --spider localhost:8081/version' ] + test: ['CMD-SHELL', 'wget --spider localhost:8081/version'] interval: 5s timeout: 5s retries: 5 diff --git a/alfa-client/apps/alfa-e2e/src/components/ui/button-with-spinner.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/ui/button-with-spinner.e2e.component.ts deleted file mode 100644 index 4ac9816e675cd64b552f97c41b05a685dd8307d1..0000000000000000000000000000000000000000 --- a/alfa-client/apps/alfa-e2e/src/components/ui/button-with-spinner.e2e.component.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -export class ButtonWithSpinnerE2EComponent { - private readonly locatorButton: string = 'icon-button'; - - public findButton(root) { - return root.findTestElementWithClass(this.locatorButton); - } - - //TODO Methode aus der MeinPage verwenden - public waitToDisappear(root) { - root.should('not.have.descendants', '[data-test-class=spinner]'); - } -} diff --git a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-bescheid-wizard.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-bescheid-wizard.e2e.component.ts index f2ee0ef04a1a37219a85db48a5b894dd0229123b..057b39b29c7de8819c69e745af44cda24e300859 100644 --- a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-bescheid-wizard.e2e.component.ts +++ b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-bescheid-wizard.e2e.component.ts @@ -24,6 +24,7 @@ import { contains, enterWith } from '../../support/cypress.util'; import { uploadFile } from '../../support/file-upload'; import { getAdjustedDateGerman } from '../../support/tech.util'; +import Chainable = Cypress.Chainable; export class VorgangBescheidWizardE2EComponent { private readonly bewilligtButton: string = 'button-bewilligt'; @@ -43,10 +44,8 @@ export class VorgangBescheidWizardE2EComponent { private readonly closeButton: string = 'close-bescheid'; private readonly closeDialog: string = 'bescheid-close-dialog'; private readonly bescheidResultBox: string = 'bescheiden-result'; - private readonly bescheidVerwerfenButton: string = - 'bescheiderstellung-abbrechen-entwurf-verwerfen'; - private readonly bescheidSpeichernButton: string = - 'bescheiderstellung-abbrechen-entwurf-speichern'; + private readonly bescheidVerwerfenButton: string = 'bescheiderstellung-abbrechen-entwurf-verwerfen'; + private readonly bescheidSpeichernButton: string = 'bescheiderstellung-abbrechen-entwurf-speichern'; private readonly uploadBescheidFileButton: string = '-single-file-upload-button'; private readonly uploadAttachmentButton: string = 'Anhang_hochladen-file-upload-button'; private readonly uploadAutomaticBescheid: string = 'create-bescheid-document-button'; @@ -60,18 +59,15 @@ export class VorgangBescheidWizardE2EComponent { private readonly fileBescheidValid: string = 'Bescheid_validpdf-file-item'; private readonly fileAnhangValid: string = 'Anhang_validpdf-file-item'; - private readonly fileAutomaticBescheid: string = - 'KFAS_LIVE_KI_10_Haltverbot_befristetpdf-file-item'; + private readonly fileAutomaticBescheid: string = 'KFAS_LIVE_KI_10_Haltverbot_befristetpdf-file-item'; private readonly bescheidDocument: string = 'bescheid-document'; private readonly attachmentDocument: string = 'bescheid-attachments'; - private readonly bescheidUploadSpinner: string = - '[data-test-id="bescheid-document"] ods-spinner-icon'; - private readonly attachmentUploadSpinner: string = - '[data-test-id="bescheid-attachments"] ods-spinner-icon'; - private readonly bescheidSaveSpinner: string = - '[data-test-id="confirm-and-save-button"] ods-spinner-icon'; + private readonly bescheidUploadSpinner: string = '[data-test-id="bescheid-document"] ods-spinner-icon'; + private readonly attachmentUploadSpinner: string = '[data-test-id="bescheid-attachments"] ods-spinner-icon'; + private readonly bescheidSaveSpinner: string = '[data-test-id="confirm-and-save-button"] ods-spinner-icon'; private readonly sendenSpinner: string = '[data-test-id="send-button"] ods-spinner-icon'; + private readonly missingBescheidDocumentMessage: string = 'missing-bescheid-document-error-message'; private locatorRoot: string = 'bescheid-wizard'; @@ -93,6 +89,7 @@ export class VorgangBescheidWizardE2EComponent { public getUeberspringenButton(): Cypress.Chainable<JQuery<HTMLElement>> { return cy.getTestElement(this.ueberspringenButton); } + public getStatusText(): Cypress.Chainable<JQuery<HTMLElement>> { return cy.getTestElement(this.statusText); } @@ -112,6 +109,7 @@ export class VorgangBescheidWizardE2EComponent { public getDateInput(): Cypress.Chainable<JQuery<HTMLElement>> { return cy.getTestElement(this.dateInput); } + public getDateError(): Cypress.Chainable<JQuery<HTMLElement>> { return cy.getTestElement(this.dateError); } @@ -292,4 +290,8 @@ export class VorgangBescheidWizardE2EComponent { public closeDialogIsShown(): void { this.getCloseDialog().should('exist'); } + + public getMissingBescheidDocumentMessage(): Chainable<Element> { + return cy.getTestElement(this.missingBescheidDocumentMessage); + } } diff --git a/alfa-client/apps/alfa-e2e/src/components/wiedervorlage/wiedervorlage-page.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/wiedervorlage/wiedervorlage-page.e2e.component.ts index 4be7b6532108923566044183f5591b1a175ee2d8..e17043afdfaa7c7de564ec7b244ff85b1761985a 100644 --- a/alfa-client/apps/alfa-e2e/src/components/wiedervorlage/wiedervorlage-page.e2e.component.ts +++ b/alfa-client/apps/alfa-e2e/src/components/wiedervorlage/wiedervorlage-page.e2e.component.ts @@ -22,7 +22,6 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { AttachmentContainerE2EComponent } from '../attachment/attachment.e2e.component'; -import { ButtonWithSpinnerE2EComponent } from '../ui/button-with-spinner.e2e.component'; export class WiedervorlageE2EComponent { private readonly locatorBetreffInput: string = 'Betreff-text-input'; @@ -33,10 +32,7 @@ export class WiedervorlageE2EComponent { private readonly locatorStatusDot: string = 'dot'; private readonly locatorSpeichernButton: string = 'speichern-button'; - private readonly buttonWithSpinnerComponent: ButtonWithSpinnerE2EComponent = - new ButtonWithSpinnerE2EComponent(); - private readonly attachmentContainer: AttachmentContainerE2EComponent = - new AttachmentContainerE2EComponent(); + private readonly attachmentContainer: AttachmentContainerE2EComponent = new AttachmentContainerE2EComponent(); public getBetreff() { return cy.getTestElement(this.locatorBetreffInput); @@ -63,9 +59,7 @@ export class WiedervorlageE2EComponent { } public getSpeichernButton() { - return this.buttonWithSpinnerComponent.findButton( - cy.getTestElement(this.locatorSpeichernButton), - ); + return cy.getTestElement(this.locatorSpeichernButton); } public getAttachmentContainer(): AttachmentContainerE2EComponent { diff --git a/alfa-client/apps/alfa-e2e/src/components/wiedervorlage/wiedervorlagen-in-vorgang.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/wiedervorlage/wiedervorlagen-in-vorgang.e2e.component.ts index 93801c671d44ca75f7473867689c7941d6efa611..91718623842de6e64bb8c0a863ba2146606d68c4 100644 --- a/alfa-client/apps/alfa-e2e/src/components/wiedervorlage/wiedervorlagen-in-vorgang.e2e.component.ts +++ b/alfa-client/apps/alfa-e2e/src/components/wiedervorlage/wiedervorlagen-in-vorgang.e2e.component.ts @@ -21,15 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { ButtonWithSpinnerE2EComponent } from '../ui/button-with-spinner.e2e.component'; import { WiedervorlageInVorgangE2EComponent } from './wiedervorlage-in-vorgang.e2e.component'; export class WiedervorlagenInVorgangE2EComponent { private readonly locatorCreateWiedervorlageButton: string = 'create-wiedervorlage'; - - private readonly buttonWithSpinnerComponent: ButtonWithSpinnerE2EComponent = - new ButtonWithSpinnerE2EComponent(); - private readonly locatorRoot: string = 'wiedervorlagen-in-vorgang'; public getRoot() { diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-abbrechen.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-abbrechen.cy.ts index 85aceeb252469b106e0ff87864712d178b2b5797..7292aa333e4233b18c846485f02d316a080b6dc4 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-abbrechen.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-abbrechen.cy.ts @@ -26,11 +26,7 @@ import localeDe from '@angular/common/locales/de'; import localeDeExtra from '@angular/common/locales/extra/de'; import { VorgangBescheidWizardE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-bescheid-wizard.e2e.component'; import { VorgangFormularButtonsE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-formular-buttons.e2e.components'; -import { - VorgangE2E, - VorgangStatusE2E, - vorgangStatusLabelE2E, -} from 'apps/alfa-e2e/src/model/vorgang'; +import { VorgangE2E, VorgangStatusE2E, vorgangStatusLabelE2E } from 'apps/alfa-e2e/src/model/vorgang'; import { uploadFile } from 'apps/alfa-e2e/src/support/file-upload'; import { getAdjustedDateGerman } from 'apps/alfa-e2e/src/support/tech.util'; import 'cypress-real-events/support'; @@ -39,10 +35,7 @@ import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main. import { VorgangPage } from '../../../page-objects/vorgang.po'; import { dropCollections } from '../../../support/cypress-helper'; import { contains, exist, haveText, notExist } from '../../../support/cypress.util'; -import { - TEST_FILE_BESCHEID_ANHANG_VALID, - TEST_FILE_BESCHEID_VALID, -} from '../../../support/data.util'; +import { TEST_FILE_BESCHEID_ANHANG_VALID, TEST_FILE_BESCHEID_VALID } from '../../../support/data.util'; import { initUsermanagerUsers, loginAsSabine } from '../../../support/user-util'; import { buildVorgang, initVorgaenge, objectIds } from '../../../support/vorgang-util'; @@ -64,8 +57,7 @@ describe('Vorgang - Bescheid abbrechen', () => { status: VorgangStatusE2E.IN_BEARBEITUNG, }; - const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = - vorgangPage.getFormularButtons(); + const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = vorgangPage.getFormularButtons(); before(() => { initVorgaenge([bescheidVorgang]); @@ -81,7 +73,7 @@ describe('Vorgang - Bescheid abbrechen', () => { dropCollections(); }); - describe.skip('Sollte gefixt sein nach OZG-6185 - Discard changes after click on Verwerfen', () => { + describe('Discard changes after click on Verwerfen', () => { it('should click abgelehnt, enter date, and continue to step 2', () => { vorgangList.getListItem(bescheidVorgang.name).getRoot().click(); waitForSpinnerToDisappear(); @@ -118,14 +110,18 @@ describe('Vorgang - Bescheid abbrechen', () => { }); it('should show status In Bearbeitung', () => { - haveText( - vorgangPage.getVorgangDetailHeader().getStatus(), - vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG], - ); + haveText(vorgangPage.getVorgangDetailHeader().getStatus(), vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG]); }); }); describe('Keep changes after click on Entwurf speichern', () => { + it('should navigate to vorgang list page', () => { + vorgangPage.getSubnavigation().getBackButton().click(); + waitForSpinnerToDisappear(); + + exist(vorgangList.getRoot()); + }); + it('click Vorgang', () => { vorgangList.getListItem(bescheidVorgang.name).getRoot().click(); waitForSpinnerToDisappear(); @@ -160,10 +156,7 @@ describe('Vorgang - Bescheid abbrechen', () => { }); it('should show status In Bearbeitung', () => { - haveText( - vorgangPage.getVorgangDetailHeader().getStatus(), - vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG], - ); + haveText(vorgangPage.getVorgangDetailHeader().getStatus(), vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG]); }); it('should keep date and status from current Bescheid in progress', () => { diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-dokumente-hochladen.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-dokumente-hochladen.cy.ts index 5fa34c5a3e560c4f2a343c38e071550be99856a2..2f0235885f20f005854b6a72df819534cbd15c6c 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-dokumente-hochladen.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-dokumente-hochladen.cy.ts @@ -33,16 +33,8 @@ import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-lis import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; import { VorgangPage } from '../../../page-objects/vorgang.po'; import { dropCollections, getTestElement } from '../../../support/cypress-helper'; -import { contains, exist, haveValue, notContains, notExist } from '../../../support/cypress.util'; -import { - TEST_FILE_BESCHEID_ANHANG_BIG, - TEST_FILE_BESCHEID_ANHANG_VALID, - TEST_FILE_BESCHEID_VALID, - TEST_FILE_JPEG, - TEST_FILE_JPG, - TEST_FILE_PNG, - TEST_FILE_WITH_CONTENT, -} from '../../../support/data.util'; +import { contains, exist, haveText, haveValue, notContains, notExist } from '../../../support/cypress.util'; +import { TEST_FILE_BESCHEID_ANHANG_BIG, TEST_FILE_BESCHEID_ANHANG_VALID, TEST_FILE_BESCHEID_VALID, TEST_FILE_JPEG, TEST_FILE_JPG, TEST_FILE_PNG, TEST_FILE_WITH_CONTENT, } from '../../../support/data.util'; import { initUsermanagerUsers, loginAsSabine } from '../../../support/user-util'; import { buildVorgang, initVorgaenge, objectIds } from '../../../support/vorgang-util'; @@ -60,12 +52,11 @@ describe('Bescheid Dokumente hochladen', () => { status: VorgangStatusE2E.IN_BEARBEITUNG, }; - const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = - vorgangPage.getFormularButtons(); + const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = vorgangPage.getFormularButtons(); const documentError: string = 'Erlaubte Dateiendungen'; const sizeError: string = 'Anhänge größer'; - const missingBescheidError: string = 'Bitte fügen Sie'; + const missingBescheidError: string = 'Bitte fügen Sie ein Bescheiddokument hinzu.'; const nachrichtHeader: string = 'Neue Nachricht'; const antragstellerName: string = 'An: Max Testermann'; const betreffText: string = 'Ihr Bescheid zum Antrag'; @@ -127,17 +118,11 @@ describe('Bescheid Dokumente hochladen', () => { }); it('should delete files on clicking X button', () => { - bescheidWizard - .getDeleteButtonOfElement( - bescheidWizard.getElementFromFileName(TEST_FILE_BESCHEID_ANHANG_VALID), - ) - .click(); + bescheidWizard.getDeleteButtonOfElement(bescheidWizard.getElementFromFileName(TEST_FILE_BESCHEID_ANHANG_VALID)).click(); notExist(bescheidWizard.getFileAnhangValidInWizard()); exist(bescheidWizard.getFileBescheidValidInWizard()); - bescheidWizard - .getDeleteButtonOfElement(bescheidWizard.getElementFromFileName(TEST_FILE_BESCHEID_VALID)) - .click(); + bescheidWizard.getDeleteButtonOfElement(bescheidWizard.getElementFromFileName(TEST_FILE_BESCHEID_VALID)).click(); notExist(bescheidWizard.getFileBescheidValidInWizard()); }); @@ -169,7 +154,8 @@ describe('Bescheid Dokumente hochladen', () => { describe('do not continue without attached Bescheid', () => { it('should show error if no Bescheid is attached and step 3 is clicked', () => { bescheidWizard.getWeiterButton().click(); - contains(bescheidWizard.getBescheidDocument(), missingBescheidError); + exist(bescheidWizard.getMissingBescheidDocumentMessage()); + haveText(bescheidWizard.getMissingBescheidDocumentMessage(), missingBescheidError); }); }); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-historie.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-historie.cy.ts index 30031db94e06f4edfbd0d265a38d3d04bdd78069..0507e30112e6638ca225665737c64002a6ec99f0 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-historie.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-historie.cy.ts @@ -29,16 +29,10 @@ import { VorgangBescheideE2EComponent } from 'apps/alfa-e2e/src/components/vorga import { VorgangFormularButtonsE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-formular-buttons.e2e.components'; import { VorgangFormularDatenE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-formular.e2e.component'; import { VorgangSubnavigationE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-subnavigation'; -import { - BescheidHistorieItemE2EComponent, - VorgangFormularDatenHistorieItemE2EComponent, -} from 'apps/alfa-e2e/src/components/vorgang/vorgang.formular-daten.historie.e2e.component'; +import { BescheidHistorieItemE2EComponent, VorgangFormularDatenHistorieItemE2EComponent, } from 'apps/alfa-e2e/src/components/vorgang/vorgang.formular-daten.historie.e2e.component'; import { HistorieHeadlineE2E } from 'apps/alfa-e2e/src/model/historie'; import { VorgangE2E, VorgangStatusE2E } from 'apps/alfa-e2e/src/model/vorgang'; -import { - TEST_FILE_BESCHEID_ANHANG_VALID, - TEST_FILE_BESCHEID_VALID, -} from 'apps/alfa-e2e/src/support/data.util'; +import { TEST_FILE_BESCHEID_ANHANG_VALID, TEST_FILE_BESCHEID_VALID } from 'apps/alfa-e2e/src/support/data.util'; import { uploadFile } from 'apps/alfa-e2e/src/support/file-upload'; import { getAdjustedDateGerman } from 'apps/alfa-e2e/src/support/tech.util'; import 'cypress-real-events/support'; @@ -79,14 +73,11 @@ describe('Bescheid History', () => { status: VorgangStatusE2E.IN_BEARBEITUNG, }; - const vorgangDatenFormular: VorgangFormularDatenE2EComponent = - vorgangPage.getFormularDatenContainer(); + const vorgangDatenFormular: VorgangFormularDatenE2EComponent = vorgangPage.getFormularDatenContainer(); - const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = - vorgangPage.getFormularButtons(); + const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = vorgangPage.getFormularButtons(); - const vorgangSubnavigationButtons: VorgangSubnavigationE2EComponent = - vorgangPage.getSubnavigation(); + const vorgangSubnavigationButtons: VorgangSubnavigationE2EComponent = vorgangPage.getSubnavigation(); const bescheide: VorgangBescheideE2EComponent = vorgangPage.getBescheide(); @@ -125,16 +116,14 @@ describe('Bescheid History', () => { waitForSpinnerToDisappear(); vorgangDatenFormular.getHistorieTab().click(); - const historieItem: VorgangFormularDatenHistorieItemE2EComponent = - vorgangDatenFormular.getHistorieItemByIndex(0); + const historieItem: VorgangFormularDatenHistorieItemE2EComponent = vorgangDatenFormular.getHistorieItemByIndex(0); contains(historieItem.getHeadline(), HistorieHeadlineE2E.BESCHEID_ERSTELLT); contains(historieItem.getUser(), userName); }); it('should show detailed info after click on arrow', () => { - const historieItem: VorgangFormularDatenHistorieItemE2EComponent = - vorgangDatenFormular.getHistorieItemByIndex(0); + const historieItem: VorgangFormularDatenHistorieItemE2EComponent = vorgangDatenFormular.getHistorieItemByIndex(0); const bescheidItem: BescheidHistorieItemE2EComponent = historieItem.getBescheid(); historieItem.getExpandButton().click(); @@ -160,8 +149,7 @@ describe('Bescheid History', () => { waitForSpinnerToDisappear(); vorgangDatenFormular.getHistorieTab().click(); - const historieItem: VorgangFormularDatenHistorieItemE2EComponent = - vorgangDatenFormular.getHistorieItemByIndex(0); + const historieItem: VorgangFormularDatenHistorieItemE2EComponent = vorgangDatenFormular.getHistorieItemByIndex(0); const bescheidItem: BescheidHistorieItemE2EComponent = historieItem.getBescheid(); historieItem.getExpandButton().click(); @@ -172,7 +160,7 @@ describe('Bescheid History', () => { }); }); - describe.skip('Show history entry after sending Bescheid', () => { + describe('Show history entry after sending Bescheid', () => { it('should show Bescheid entry on history tab after sending message', () => { vorgangSubnavigationButtons.getBackButton().click(); vorgangList.getListItem(bescheidSendenVorgang.name).getRoot().click(); @@ -194,8 +182,7 @@ describe('Bescheid History', () => { notExist(bescheidWizard.getSendenSpinner()); vorgangDatenFormular.getHistorieTab().click(); - const historieItemExpand: VorgangFormularDatenHistorieItemE2EComponent = - vorgangDatenFormular.getHistorieItemByIndex(0); + const historieItemExpand: VorgangFormularDatenHistorieItemE2EComponent = vorgangDatenFormular.getHistorieItemByIndex(0); const bescheidItem: BescheidHistorieItemE2EComponent = historieItemExpand.getBescheid(); historieItemExpand.getExpandButton().click(); @@ -206,13 +193,11 @@ describe('Bescheid History', () => { }); it('should show history entries for sent Bescheid and message', () => { - const historieItemSent: VorgangFormularDatenHistorieItemE2EComponent = - vorgangDatenFormular.getHistorieItemByIndex(1); + const historieItemSent: VorgangFormularDatenHistorieItemE2EComponent = vorgangDatenFormular.getHistorieItemByIndex(1); contains(historieItemSent.getHeadline(), HistorieHeadlineE2E.BESCHEID_VERSCHICKT); contains(historieItemSent.getUser(), userName); - const historieItemMessage: VorgangFormularDatenHistorieItemE2EComponent = - vorgangDatenFormular.getHistorieItemByIndex(3); + const historieItemMessage: VorgangFormularDatenHistorieItemE2EComponent = vorgangDatenFormular.getHistorieItemByIndex(3); contains(historieItemMessage.getHeadline(), HistorieHeadlineE2E.SEND_POSTFACH_NACHRICHT); contains(historieItemMessage.getUser(), userName); }); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-nur-speichern.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-nur-speichern.cy.ts index b75f8c43401365ded80a0f22ae2571b78f9dd6d5..d2e2df9695234a26ff907b7cdde54563df9ca977 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-nur-speichern.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-nur-speichern.cy.ts @@ -26,11 +26,7 @@ import localeDe from '@angular/common/locales/de'; import localeDeExtra from '@angular/common/locales/extra/de'; import { VorgangBescheidWizardE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-bescheid-wizard.e2e.component'; import { VorgangFormularButtonsE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-formular-buttons.e2e.components'; -import { - VorgangE2E, - VorgangStatusE2E, - vorgangStatusLabelE2E, -} from 'apps/alfa-e2e/src/model/vorgang'; +import { VorgangE2E, VorgangStatusE2E, vorgangStatusLabelE2E } from 'apps/alfa-e2e/src/model/vorgang'; import { uploadFile } from 'apps/alfa-e2e/src/support/file-upload'; import { getAdjustedDateGerman } from 'apps/alfa-e2e/src/support/tech.util'; import 'cypress-real-events/support'; @@ -39,10 +35,7 @@ import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main. import { VorgangPage } from '../../../page-objects/vorgang.po'; import { dropCollections } from '../../../support/cypress-helper'; import { contains, enterWith, exist, haveText, notExist } from '../../../support/cypress.util'; -import { - TEST_FILE_BESCHEID_ANHANG_VALID, - TEST_FILE_BESCHEID_VALID, -} from '../../../support/data.util'; +import { TEST_FILE_BESCHEID_ANHANG_VALID, TEST_FILE_BESCHEID_VALID } from '../../../support/data.util'; import { initUsermanagerUsers, loginAsSabine } from '../../../support/user-util'; import { buildVorgang, initVorgaenge, objectIds } from '../../../support/vorgang-util'; @@ -53,7 +46,7 @@ describe('Bescheid speichern', () => { const vorgangList: VorgangListE2EComponent = mainPage.getVorgangList(); const abgelehntText: string = 'Abgelehnt am'; - const manuellText: string = 'Bescheid muss manuell'; + const manuellText: string = 'Der Bescheid muss manuell versendet werden.'; const vorgangPage: VorgangPage = new VorgangPage(); const bescheidWizard: VorgangBescheidWizardE2EComponent = vorgangPage.getBescheidWizard(); @@ -63,8 +56,7 @@ describe('Bescheid speichern', () => { status: VorgangStatusE2E.IN_BEARBEITUNG, }; - const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = - vorgangPage.getFormularButtons(); + const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = vorgangPage.getFormularButtons(); before(() => { initVorgaenge([bescheidVorgang]); @@ -108,10 +100,7 @@ describe('Bescheid speichern', () => { notExist(bescheidWizard.getRoot()); waitForSpinnerToDisappear(); - haveText( - vorgangPage.getVorgangDetailHeader().getStatus(), - vorgangStatusLabelE2E[VorgangStatusE2E.BESCHIEDEN], - ); + haveText(vorgangPage.getVorgangDetailHeader().getStatus(), vorgangStatusLabelE2E[VorgangStatusE2E.BESCHIEDEN]); }); }); }); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-abschliessen.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-abschliessen.cy.ts index 81bbd0cdfbe44f1480fcd852caa3f0ae3657e701..e7cbc9d44df2099c5443729d0bb2b1187dd4e5f9 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-abschliessen.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-abschliessen.cy.ts @@ -27,7 +27,7 @@ import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-lis import { VorgangE2E, VorgangMessagesE2E, VorgangStatusE2E, vorgangStatusLabelE2E } from '../../../model/vorgang'; import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; import { VorgangPage } from '../../../page-objects/vorgang.po'; -import { dropCollections, wait } from '../../../support/cypress-helper'; +import { dropCollections } from '../../../support/cypress-helper'; import { contains, exist, haveText, notExist } from '../../../support/cypress.util'; import { loginAsSabine } from '../../../support/user-util'; import { buildVorgang, initVorgaenge, objectIds } from '../../../support/vorgang-util'; @@ -132,15 +132,12 @@ describe('Vorgang abschliessen', () => { it('should close snackbar on revoke', () => { snackBar.getRevokeButton().click(); - wait(500); waitForSpinnerToDisappear(); - notExist(snackBar.getMessage()); }); - it.skip('UNSTABLE: should show status Beschieden', () => { + it('should show status Beschieden', () => { notExist(vorgangPage.getProgressBar()); - haveText(vorgangPage.getVorgangDetailHeader().getStatus(), vorgangStatusLabelE2E[VorgangStatusE2E.BESCHIEDEN]); }); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-detailansicht-formdata.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-detailansicht-formdata.cy.ts index 893f7d2d803a5ba3b368af963a296f6dc494620c..a7912650d925a0159a8ec3793d6cca2449715311 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-detailansicht-formdata.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-detailansicht-formdata.cy.ts @@ -39,6 +39,7 @@ import { initVorgaenge, objectIds, } from '../../../support/vorgang-util'; +import { VorgangSubnavigationE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-subnavigation'; registerLocaleData(localeDe, 'de', localeDeExtra); @@ -51,6 +52,7 @@ describe('Vorgang Detailansicht with formData', () => { vorgangPage.getFormularDatenContainer(); const vorgangHeader: VorgangDetailHeaderE2EComponent = vorgangPage.getVorgangDetailHeader(); + const vorgangSubnavigation: VorgangSubnavigationE2EComponent = new VorgangSubnavigationE2EComponent(); const ort: string = 'Ort'; const sh_strasse: string = 'Strasse'; @@ -135,33 +137,12 @@ describe('Vorgang Detailansicht with formData', () => { contains(vorgangDatenFormular.getRoot(), 'sh_strasse'); }); }); - - // SKIP: Metadaten sind aktuell aus - describe('click on "Metadaten" tab', () => { - it.skip('should show on click on tab', () => { - vorgangDatenFormular.getMetadatenTab().click(); - - exist(vorgangDatenFormular.getMetadaten()); - }); - - it.skip('should show "emailadresse"', () => { - contains(vorgangDatenFormular.getRoot(), 'emailadresse'); - }); - - it.skip('should show "postleitzahl"', () => { - contains(vorgangDatenFormular.getRoot(), 'postleitzahl'); - }); - - it('should navigate back to Vorgang List', () => { - vorgangPage.getSubnavigation().getBackButton().click(); - waitForSpinnerToDisappear(); - }); - }); }); describe('navigate to vorgang detail (with labels)', () => { describe('click on vorgang in list', () => { it('should show header', () => { + vorgangSubnavigation.back(); vorgangList.getListItem(vorgangWithLabels.name).getRoot().click(); waitForSpinnerToDisappear(); @@ -193,20 +174,5 @@ describe('Vorgang Detailansicht with formData', () => { }); }); - describe.skip('click on "Metadaten" tab', () => { - it('should show on click on tab', () => { - vorgangDatenFormular.getMetadatenTab().click(); - - exist(vorgangDatenFormular.getMetadaten()); - }); - - it('should show "E-Mail Adresse"', () => { - contains(vorgangDatenFormular.getRoot(), emailadresse); - }); - - it('should show "PLZ"', () => { - contains(vorgangDatenFormular.getRoot(), postleitzahl); - }); - }); }); }); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-detailansicht.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-detailansicht.cy.ts index 7fa1b271ad7f923a8757a96e1e73854837fe101c..435e7106eda6a88a896ac03e25fe1cc75f1132e7 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-detailansicht.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-detailansicht.cy.ts @@ -107,19 +107,6 @@ describe('Vorgang Detailansicht', () => { }); }); - // SKIP: Metada sind aktuell disabled - describe.skip('metadaten in tab', () => { - it('should show on click on tab', () => { - vorgangDatenFormular.getMetadatenTab().click(); - - exist(vorgangDatenFormular.getMetadaten()); - }); - - it('should show "empfangendestelle"', () => { - contains(vorgangDatenFormular.getRoot(), vorgang.eingangs[0].formData.empfangendestelle.emailadresse); - }); - }); - describe('antragdaten in tab', () => { it('should show on click on tab', () => { vorgangDatenFormular.getAntragdatenTab().click(); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-vorpruefen.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-vorpruefen.cy.ts index 2b9956e17ae93200b66f44edd95bca083813ea1f..ca02f561b4be2aa40d3a8dc9c65feeff9dfe6269 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-vorpruefen.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-vorpruefen.cy.ts @@ -115,40 +115,23 @@ describe.skip('Vorgang vorprüfen', () => { }); it('should open "more menu"', () => { - //nur testweise - //kommentarContainer.getHinzufuegenButton().click(); - //kommentarContainer.getTextInput().clear().type(kommentarText); - //kommentarContainer.getFormularSpeichernButton().click(); waitForSpinnerToDisappear(); - // - vorgangMoreMenu.getButton().click(); exist(vorgangMoreMenu.getRoot()); }); - it('should show Prüfung item', () => { - //exist(menuItem.getRoot());? - }); - it('should show "Vorgang vorpüfen" button', () => { exist(menuItem.getButton()); }); - it('should have a positive comment after Prüfung', () => { + it.skip('AKTUELL FEHLER: should have a positive comment after Prüfung', () => { menuItem.getButton().click(); - //waitForSpinnerToDisappear(); - exist(kommentarContainer.getKommentar(kommentarText).getRoot()); - //check for positive comment }); it('should close menu after Prüfung', () => { - //am Ende entfernen vorgangMoreMenu.getButton().click(); - - //notExist(menuItem.getRoot()); - vorgangPage.getSubnavigation().getBackButton().click(); }); }); @@ -165,22 +148,10 @@ describe.skip('Vorgang vorprüfen', () => { exist(vorgangPage.getVorgangDetailHeader().getRoot()); }); - it('should have a negative comment after Prüfung', () => { + it.skip('AKTUELL FEHLER: should have a negative comment after Prüfung', () => { vorgangMoreMenu.getButton().click(); - menuItem.getButton().click(); - - //nur testweise - //kommentarContainer.getHinzufuegenButton().click(); - //kommentarContainer.getTextInput().clear().type(kommentarText); - //kommentarContainer.getFormularSpeichernButton().click(); - waitForSpinnerToDisappear(); - // - - waitForSpinnerToDisappear(); - exist(kommentarContainer.getKommentar(kommentarText).getRoot()); - //check for negative comment }); it('should close menu after Prüfung', () => { @@ -190,20 +161,12 @@ describe.skip('Vorgang vorprüfen', () => { }); }); - describe('button not available on other Vorgänge', () => { - const menuItem: VorgangMoreMenuVorpruefenItemE2EComponent = - vorgangMoreMenu.getVorpruefenItem(); - - it('should open Vorgang-Detail-Page', () => { + describe('menu not available on other Vorgänge', () => { + it('should not show more menu on other Vorgänge', () => { vorgangList.getListItem(vorgangOhnePruefung.name).getRoot().click(); waitForSpinnerToDisappear(); - exist(vorgangPage.getVorgangDetailHeader().getRoot()); - }); - - it('more menu should not contain Vorprüfen button', () => { - vorgangMoreMenu.getButton().click(); - notExist(menuItem.getRoot()); + notExist(vorgangMoreMenu.getRoot()); }); }); }); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-wiedereroeffnen.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-wiedereroeffnen.cy.ts index c86efc5d90992c7d5eb14b126554bc3b1872cac1..a589537f1b6c1ebc75b77173ca51aa829824bc8a 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-wiedereroeffnen.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-wiedereroeffnen.cy.ts @@ -27,7 +27,7 @@ import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-lis import { VorgangE2E, VorgangMessagesE2E, VorgangStatusE2E, vorgangStatusLabelE2E } from '../../../model/vorgang'; import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; import { VorgangPage } from '../../../page-objects/vorgang.po'; -import { dropCollections, wait } from '../../../support/cypress-helper'; +import { dropCollections } from '../../../support/cypress-helper'; import { contains, exist, haveText, notExist } from '../../../support/cypress.util'; import { loginAsSabine } from '../../../support/user-util'; import { buildVorgang, createVorgang, initVorgaenge, objectIds } from '../../../support/vorgang-util'; @@ -137,8 +137,6 @@ describe('Vorgang wiedereroeffnen', () => { describe('by icon-button', () => { it('should have status Beschieden', () => { - wait(500); - haveText( vorgangPage.getVorgangDetailHeader().getStatus(), vorgangStatusLabelE2E[vorgangBeschiedenWiedereroeffnenRevoke.status], @@ -153,7 +151,7 @@ describe('Vorgang wiedereroeffnen', () => { contains(snackbar.getMessage(), VorgangMessagesE2E.WIEDEREROEFFNET); }); - it('should close snackbar on revoke', () => { + it('should click on snackbar revoke', () => { snackbar.getRevokeButton().click(); waitForSpinnerToDisappear(); @@ -258,9 +256,8 @@ describe('Vorgang wiedereroeffnen', () => { contains(snackbar.getMessage(), VorgangMessagesE2E.WIEDEREROEFFNET); }); - it('should close snackbar on revoke', () => { + it('should click snackbar revoke', () => { snackbar.getRevokeButton().click(); - wait(500); waitForSpinnerToDisappear(); notExist(snackbar.getMessage()); diff --git a/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts b/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts index 69e7bccdfc44a17993598e6c49a8e81bd066db33..3dbd6155939b778a411f9b2fd18822286feaf958 100644 --- a/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts +++ b/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts @@ -46,10 +46,9 @@ export function notExist(element: any): void { } export function haveText(element: any, text: string): void { - element - .invoke('text') - .then((elementText) => elementText.trim()) - .should('equal', text); + element.invoke('text').should(($text) => { + expect($text.trim()).to.equal(text); + }); } export function haveTextWithoutChildren(element: any, text: string): void { diff --git a/alfa-client/apps/alfa/src/app/app.component.ts b/alfa-client/apps/alfa/src/app/app.component.ts index 559dcfd6e2a53319d2a3710cddbf06c168e8a112..6a4820c7036735d0a1fd127463805e28aacad058 100644 --- a/alfa-client/apps/alfa/src/app/app.component.ts +++ b/alfa-client/apps/alfa/src/app/app.component.ts @@ -24,7 +24,7 @@ import { ApiRootFacade, ApiRootResource } from '@alfa-client/api-root-shared'; import { ENVIRONMENT_CONFIG } from '@alfa-client/environment-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { StateResource, isNotNull } from '@alfa-client/tech-shared'; +import { InjectorService, StateResource, isNotNull } from '@alfa-client/tech-shared'; import { IconService } from '@alfa-client/ui'; import { buildPathSegmentsFromLocalStorage } from '@alfa-client/vorgang-shared'; import { Component, Inject, OnInit } from '@angular/core'; @@ -49,6 +49,7 @@ export class AppComponent implements OnInit { private iconService: IconService, private oAuthService: OAuthService, private navigationService: NavigationService, + private injectorService: InjectorService, ) { this.iconService.registerIcons(); } diff --git a/alfa-client/apps/alfa/src/app/app.module.ts b/alfa-client/apps/alfa/src/app/app.module.ts index d8e90a9d20917ac50f4056a53fe9d18825cde65d..566ebc0b3fd03aa04506016be0d3c16aa1bf1fd9 100644 --- a/alfa-client/apps/alfa/src/app/app.module.ts +++ b/alfa-client/apps/alfa/src/app/app.module.ts @@ -29,11 +29,14 @@ import { HintSharedModule } from '@alfa-client/hint-shared'; import { NavigationModule } from '@alfa-client/navigation'; import { OzgCloudUrlSerializer } from '@alfa-client/navigation-shared'; import { ResourceRedirectComponent } from '@alfa-client/resource-redirect'; -import { UiModule } from '@alfa-client/ui'; +import { SpinnerComponent } from '@alfa-client/ui'; import { registerLocaleData } from '@angular/common'; -import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import localeDe from '@angular/common/locales/de'; import { LOCALE_ID, NgModule } from '@angular/core'; +import { DateFnsAdapter } from '@angular/material-date-fns-adapter'; +import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core'; +import { MatIconModule } from '@angular/material/icon'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { RouterModule, Routes, UrlSerializer } from '@angular/router'; @@ -42,11 +45,29 @@ import { StoreRouterConnectingModule } from '@ngrx/router-store'; import { StoreModule } from '@ngrx/store'; import { StoreDevtoolsModule } from '@ngrx/store-devtools'; import { OAuthModule } from 'angular-oauth2-oidc'; +import { de } from 'date-fns/locale'; +import { HttpBinaryFileInterceptor } from '../../../../libs/tech-shared/src/lib/interceptor/http-binary-file.interceptor'; +import { HttpXsrfInterceptor } from '../../../../libs/tech-shared/src/lib/interceptor/http-xsrf.interceptor'; +import { XhrInterceptor } from '../../../../libs/tech-shared/src/lib/interceptor/xhr.interceptor'; +import { HttpConnectionTimeoutInterceptor } from '../../../../libs/ui/src/lib/interceptor/http-connection-timeout.interceptor'; +import { HttpErrorInterceptor } from '../../../../libs/ui/src/lib/interceptor/http-error.interceptor'; import { environment } from '../environments/environment'; import { AppComponent } from './app.component'; registerLocaleData(localeDe); +export const CUSTOM_DATE_FORMATS = { + parse: { + dateInput: 'dd.MM.yyyy', + }, + display: { + dateInput: 'dd.MM.yyyy', + monthYearLabel: 'MMM yyyy', + dateA11yLabel: 'dd.MM.yyyy', + monthYearA11yLabel: 'MM yyyy', + }, +}; + const routes: Routes = [ { path: '', @@ -61,13 +82,13 @@ const routes: Routes = [ @NgModule({ declarations: [AppComponent], imports: [ + MatIconModule, BrowserModule, BrowserAnimationsModule, RouterModule.forRoot(routes, { initialNavigation: 'disabled', onSameUrlNavigation: 'reload', }), - UiModule, EnvironmentModule, OAuthModule.forRoot({ resourceServer: { @@ -94,10 +115,49 @@ const routes: Routes = [ // Workaround: load any module depending on ApiRootActions.loadApiRootSuccess // TODO Check if a future NgRx version will solve Lazy Loading + Effects.forFeature() HintSharedModule, + SpinnerComponent, ], providers: [ { provide: LOCALE_ID, useValue: 'de' }, { provide: UrlSerializer, useClass: OzgCloudUrlSerializer }, + { + provide: HTTP_INTERCEPTORS, + useClass: HttpErrorInterceptor, + multi: true, + }, + { + provide: HTTP_INTERCEPTORS, + useClass: HttpConnectionTimeoutInterceptor, + multi: true, + }, + { + provide: HTTP_INTERCEPTORS, + useClass: XhrInterceptor, + multi: true, + }, + { + provide: HTTP_INTERCEPTORS, + useClass: HttpXsrfInterceptor, + multi: true, + }, + { + provide: HTTP_INTERCEPTORS, + useClass: HttpBinaryFileInterceptor, + multi: true, + }, + { + provide: MAT_DATE_LOCALE, + useValue: de, + }, + { + provide: MAT_DATE_FORMATS, + useValue: CUSTOM_DATE_FORMATS, + }, + { + provide: DateAdapter, + useClass: DateFnsAdapter, + deps: [MAT_DATE_LOCALE], + }, provideHttpClient(withInterceptorsFromDi()), ], bootstrap: [AppComponent], diff --git a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.spec.ts b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.spec.ts index 1f417e5febf09fcf523cd7c2d01a273d65630e79..6fe7f6ec6a78e51ef53b8f5b3e8c5f4fc7d129b1 100644 --- a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.spec.ts +++ b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.spec.ts @@ -17,8 +17,8 @@ describe('MenuComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [MenuComponent], - declarations: [HasLinkPipe, MockComponent(NavItemComponent), MockComponent(MailboxIconComponent)], + imports: [MenuComponent, HasLinkPipe], + declarations: [MockComponent(NavItemComponent), MockComponent(MailboxIconComponent)], }).compileComponents(); fixture = TestBed.createComponent(MenuComponent); diff --git a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.ts b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.ts index 19cc60bab45d9e098ace89450e3c7efa50e96c30..0c9cddefff0b13b58d8dd915f44352b78bd60f2b 100644 --- a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.ts +++ b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.ts @@ -1,5 +1,5 @@ import { ConfigurationLinkRel, ConfigurationResource } from '@admin-client/configuration-shared'; -import { StateResource, TechSharedModule } from '@alfa-client/tech-shared'; +import { HasLinkPipe, StateResource } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; import { MailboxIconComponent, NavItemComponent, StatisticIconComponent } from '@ods/system'; @@ -7,7 +7,7 @@ import { MailboxIconComponent, NavItemComponent, StatisticIconComponent } from ' @Component({ selector: 'admin-menu', standalone: true, - imports: [CommonModule, NavItemComponent, MailboxIconComponent, TechSharedModule, StatisticIconComponent], + imports: [CommonModule, NavItemComponent, MailboxIconComponent, StatisticIconComponent, HasLinkPipe], templateUrl: './menu.component.html', }) export class MenuComponent { diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/organisations-einheit.repository.spec.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/organisations-einheit.repository.spec.ts index 043e5c2e056bb11eb29983c5eef09ce0fa17a74e..43bc3d38565e870585b2ba846b8c2d681d977014 100644 --- a/alfa-client/libs/admin/keycloak-shared/src/lib/organisations-einheit.repository.spec.ts +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/organisations-einheit.repository.spec.ts @@ -39,6 +39,7 @@ describe('AdminOrganisationsEinheitRepository', () => { (group: GroupRepresentation): AdminOrganisationsEinheit => ({ name: group.name, id: group.id, + attributes: group.attributes, }), ); @@ -63,6 +64,7 @@ describe('AdminOrganisationsEinheitRepository', () => { const organisationsEinheit: AdminOrganisationsEinheit = { name: groupRep.name, id: groupRep.id, + attributes: groupRep.attributes, }; beforeEach(() => { diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/organisations-einheit.repository.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/organisations-einheit.repository.ts index 5dc1b0ee3bf1ea39b1668edf2fa7379a6836f81f..c2d454434e07562492f0c929bc710d7793a70403 100644 --- a/alfa-client/libs/admin/keycloak-shared/src/lib/organisations-einheit.repository.ts +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/organisations-einheit.repository.ts @@ -40,6 +40,7 @@ export class AdminOrganisationsEinheitRepository { return { id: group.id, name: group.name, + attributes: group.attributes, }; } } diff --git a/alfa-client/libs/admin/organisations-einheit-shared/src/lib/organisations-einheit.model.ts b/alfa-client/libs/admin/organisations-einheit-shared/src/lib/organisations-einheit.model.ts index 8a4b105a948caf4f288a8639468d888d2fb3c255..3a93c42e6b0042f02dd9f509969444431ce6c374 100644 --- a/alfa-client/libs/admin/organisations-einheit-shared/src/lib/organisations-einheit.model.ts +++ b/alfa-client/libs/admin/organisations-einheit-shared/src/lib/organisations-einheit.model.ts @@ -24,4 +24,5 @@ export interface AdminOrganisationsEinheit { id?: string; name: string; + attributes: { [key: string]: string[] }; } diff --git a/alfa-client/libs/admin/organisations-einheit-shared/src/test/organisations-einheit.ts b/alfa-client/libs/admin/organisations-einheit-shared/src/test/organisations-einheit.ts index 6bb1baad301e83997665d96347628cf092f1d5ea..aac833df1f46a18a007d4c780e5673dbe5a7ec19 100644 --- a/alfa-client/libs/admin/organisations-einheit-shared/src/test/organisations-einheit.ts +++ b/alfa-client/libs/admin/organisations-einheit-shared/src/test/organisations-einheit.ts @@ -29,6 +29,9 @@ export function createAdminOrganisationsEinheit(): AdminOrganisationsEinheit { return { id: faker.string.uuid(), name: faker.lorem.word(), + attributes: { + organisationseinheitId: [faker.string.uuid()], + }, }; } diff --git a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-container.component.spec.ts b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-container.component.spec.ts index 5fd68cc789206b701f2adad2c2d0f5280917b55d..2f207e5573f8398234d5d01e201430a4c4e34303 100644 --- a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-container.component.spec.ts +++ b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-container.component.spec.ts @@ -25,7 +25,7 @@ import { OrganisationsEinheitContainerComponent } from '@admin-client/organisati import { AdminOrganisationsEinheit, AdminOrganisationsEinheitService } from '@admin-client/organisations-einheit-shared'; import { createStateResource, StateResource, ToEmbeddedResourcesPipe } from '@alfa-client/tech-shared'; import { existsAsHtmlElement, getMockComponent, Mock, mock } from '@alfa-client/test-utils'; -import { OzgcloudDialogService, UiModule } from '@alfa-client/ui'; +import { OzgcloudDialogService } from '@alfa-client/ui'; import { OrganisationsEinheitResource } from '@alfa-client/zustaendige-stelle-shared'; import { CommonModule } from '@angular/common'; import { ViewContainerRef } from '@angular/core'; @@ -66,7 +66,7 @@ describe('OrganisationsEinheitContainerComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ToEmbeddedResourcesPipe], - imports: [CommonModule, UiModule, OrganisationsEinheitContainerComponent, MockComponent(OrganisationsEinheitListComponent)], + imports: [CommonModule, OrganisationsEinheitContainerComponent, MockComponent(OrganisationsEinheitListComponent)], providers: [ { provide: AdminOrganisationsEinheitService, useValue: organisationsEinheitService }, { provide: OzgcloudDialogService, useValue: dialogService }, @@ -85,7 +85,16 @@ describe('OrganisationsEinheitContainerComponent', () => { describe('component', () => { describe('ngOnInit', () => { - it('should call organisationsEinheitService getAll', (done) => { + it('should call organisationsEinheitService getList', (done) => { + component.ngOnInit(); + + component.organisationsEinheitenStateResource$.subscribe(() => { + expect(organisationsEinheitService.getAll).toHaveBeenCalled(); + done(); + }); + }); + + it('should set organisationsEinheitListStateResource$', (done) => { component.ngOnInit(); component.organisationsEinheitenStateResource$.subscribe(() => { @@ -143,7 +152,10 @@ describe('OrganisationsEinheitContainerComponent', () => { it('should call organisationsEinheitService create', () => { component.handleDialogResponse(organisationsEinheitResource); - expect(organisationsEinheitService.create).toHaveBeenCalledWith({ name: organisationsEinheitResource.name }); + expect(organisationsEinheitService.create).toHaveBeenCalledWith({ + name: organisationsEinheitResource.name, + attributes: { organisationseinheitId: [organisationsEinheitResource.organisationEinheitId] }, + }); }); it('should set createOrganisationsEinheitProgress$', () => { diff --git a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-container.component.ts b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-container.component.ts index a1b124b07e83e6496d5409cef4cdd271e826b842..31e3a25fa7f482c8b85cf9de2a97e8623596d555 100644 --- a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-container.component.ts +++ b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-container.component.ts @@ -7,9 +7,8 @@ import { ResourceSearchService, SearchResourceServiceConfig, StateResource, - TechSharedModule, } from '@alfa-client/tech-shared'; -import { OzgcloudDialogService, UiModule } from '@alfa-client/ui'; +import { OzgcloudDialogService, SpinnerComponent } from '@alfa-client/ui'; import { ZustaendigeStelleModule } from '@alfa-client/zustaendige-stelle'; import { OrganisationsEinheitListResource, @@ -31,12 +30,11 @@ import { OrganisationsEinheitListComponent } from './organisations-einheit-list/ standalone: true, imports: [ CommonModule, - UiModule, ZustaendigeStelleModule, ZustaendigeStelleSharedModule, OrganisationsEinheitListComponent, - TechSharedModule, ButtonComponent, + SpinnerComponent, ], providers: [ { @@ -82,6 +80,9 @@ export class OrganisationsEinheitContainerComponent implements OnInit, OnDestroy mapToAdminOrganisationsEinheit(organisationsEinheitResource: OrganisationsEinheitResource): AdminOrganisationsEinheit { return { name: organisationsEinheitResource.name, + attributes: { + organisationseinheitId: [organisationsEinheitResource.organisationEinheitId], + }, }; } } diff --git a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.spec.ts b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.spec.ts index 6fd9e1d7f938b76081a00e071efe41067de9273b..dd2fba6125d358ef26de554cdf79d2afdc40cf9b 100644 --- a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.spec.ts +++ b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.spec.ts @@ -22,14 +22,14 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { AdminOrganisationsEinheit } from '@admin-client/organisations-einheit-shared'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { existsAsHtmlElement, getElementFromFixture, mock } from '@alfa-client/test-utils'; import { CommonModule } from '@angular/common'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatTooltipModule } from '@angular/material/tooltip'; import { ActivatedRoute } from '@angular/router'; import { ExclamationIconComponent, ListComponent, ListItemComponent } from '@ods/system'; import { getConvertedDataTestIdOf, getDataTestIdOf } from 'libs/tech-shared/test/data-test'; -import { MockComponent, MockModule } from 'ng-mocks'; +import { MockComponent } from 'ng-mocks'; import { createAdminOrganisationsEinheit } from '../../../../../organisations-einheit-shared/src/test/organisations-einheit'; import { OrganisationsEinheitListComponent } from './organisations-einheit-list.component'; @@ -48,13 +48,12 @@ describe('OrganisationsEinheitListComponent', () => { useValue: mock(ActivatedRoute), }, ], - imports: [ - CommonModule, + imports: [CommonModule, ConvertForDataTestPipe], + declarations: [ OrganisationsEinheitListComponent, MockComponent(ListComponent), MockComponent(ListItemComponent), MockComponent(ExclamationIconComponent), - MockModule(MatTooltipModule), ], }).compileComponents(); diff --git a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.ts b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.ts index 349085056be2fdeda545dda9849cac09822254c0..7efc0bbbe6727d1d558c63bad8ffe6a2d08b9d35 100644 --- a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.ts +++ b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.ts @@ -22,7 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { AdminOrganisationsEinheit } from '@admin-client/organisations-einheit-shared'; -import { TechSharedModule } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe, ToResourceUriPipe } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; import { ExclamationIconComponent, ListComponent, ListItemComponent, TooltipDirective } from '@ods/system'; @@ -31,7 +31,15 @@ import { ExclamationIconComponent, ListComponent, ListItemComponent, TooltipDire selector: 'admin-organisations-einheit-list', templateUrl: './organisations-einheit-list.component.html', standalone: true, - imports: [CommonModule, ListComponent, ListItemComponent, ExclamationIconComponent, TooltipDirective, TechSharedModule], + imports: [ + CommonModule, + ListComponent, + ListItemComponent, + ExclamationIconComponent, + TooltipDirective, + ToResourceUriPipe, + ConvertForDataTestPipe, + ], }) export class OrganisationsEinheitListComponent { @Input() public organisationsEinheitList: AdminOrganisationsEinheit[] = []; diff --git a/alfa-client/libs/admin/postfach-shared/project.json b/alfa-client/libs/admin/postfach-shared/project.json index 6489dc23d02f10a0660d03ccd39ccebae8dadc5d..e02554623fc02a4f2929efea43c8669d24ecdf3a 100644 --- a/alfa-client/libs/admin/postfach-shared/project.json +++ b/alfa-client/libs/admin/postfach-shared/project.json @@ -10,7 +10,7 @@ "executor": "@nx/jest:jest", "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], "options": { - "tsConfig": "libs/admin//postfach-shared/tsconfig.spec.json", + "tsConfig": "libs/admin/postfach-shared/tsconfig.spec.json", "jestConfig": "libs/admin/postfach-shared/jest.config.ts" } }, diff --git a/alfa-client/libs/admin/postfach-shared/src/lib/postfach-resource.service.ts b/alfa-client/libs/admin/postfach-shared/src/lib/postfach-resource.service.ts index 48043163dea114eba85fa881d9047ec90f8ef24a..a617ed3abf3f31d102889877f0d10a8117bb23b2 100644 --- a/alfa-client/libs/admin/postfach-shared/src/lib/postfach-resource.service.ts +++ b/alfa-client/libs/admin/postfach-shared/src/lib/postfach-resource.service.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { SettingsService } from '@admin-client/settings-shared'; +import { SettingName, SettingsService } from '@admin-client/settings-shared'; import { ApiResourceService, ResourceRepository, ResourceServiceConfig } from '@alfa-client/tech-shared'; import { PostfachLinkRel } from './postfach.linkrel'; import { PostfachResource } from './postfach.model'; @@ -34,7 +34,7 @@ export function createPostfachResourceService(repository: ResourceRepository, se function buildConfig(settingService: SettingsService): ResourceServiceConfig<PostfachResource> { return { - resource: settingService.getPostfach(), + resource: settingService.get(SettingName.POSTFACH), getLinkRel: PostfachLinkRel.SELF, edit: { linkRel: PostfachLinkRel.SELF }, }; diff --git a/alfa-client/libs/admin/postfach-shared/src/lib/postfach.model.ts b/alfa-client/libs/admin/postfach-shared/src/lib/postfach.model.ts index c592dec3e6621543ca69e9ee23abdeea1ec6f4ec..e3ce2fb8bd6153796bea9bf82422718d2324721e 100644 --- a/alfa-client/libs/admin/postfach-shared/src/lib/postfach.model.ts +++ b/alfa-client/libs/admin/postfach-shared/src/lib/postfach.model.ts @@ -21,8 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Resource } from '@ngxp/rest'; -import { SettingName } from 'libs/admin/settings-shared/src/lib/settings.model'; +import { SettingItemResource } from 'libs/admin/settings-shared/src/lib/settings.model'; export interface Absender { name: string; @@ -37,9 +36,4 @@ export interface Postfach { signatur: string; } -export declare type PostfachSettingsItem = { - name: SettingName.POSTFACH; - settingBody: Postfach; -}; - -export declare type PostfachResource = Resource & PostfachSettingsItem; +export declare type PostfachResource = SettingItemResource<Postfach>; diff --git a/alfa-client/libs/admin/postfach-shared/src/lib/postfach.service.spec.ts b/alfa-client/libs/admin/postfach-shared/src/lib/postfach.service.spec.ts index d779cb50dc2173e7dee4dc929a7e11f5d259724d..2441dc06db2b787fe3f33389d1fb2daae412e3bf 100644 --- a/alfa-client/libs/admin/postfach-shared/src/lib/postfach.service.spec.ts +++ b/alfa-client/libs/admin/postfach-shared/src/lib/postfach.service.spec.ts @@ -21,6 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { SettingItem } from '@admin-client/settings-shared'; import { createEmptyStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared'; import { Mock, mock } from '@alfa-client/test-utils'; import { SnackBarService } from '@alfa-client/ui'; @@ -31,7 +32,7 @@ import { singleCold, singleHot } from 'libs/tech-shared/test/marbles'; import { Observable, of } from 'rxjs'; import { createPostfachResource, createPostfachSettingItem } from '../test/postfach'; import { PostfachResourceService } from './postfach-resource.service'; -import { PostfachResource, PostfachSettingsItem } from './postfach.model'; +import { Postfach, PostfachResource } from './postfach.model'; import { PostfachService } from './postfach.service'; describe('PostfachService', () => { @@ -78,7 +79,7 @@ describe('PostfachService', () => { }); describe('save', () => { - const postfachSettingsItem: PostfachSettingsItem = createPostfachSettingItem(); + const postfachSettingsItem: SettingItem<Postfach> = createPostfachSettingItem(); const postfachResource: PostfachResource = createPostfachResource(); const postfachStateResource: StateResource<PostfachResource> = createStateResource(postfachResource); diff --git a/alfa-client/libs/admin/postfach-shared/src/lib/postfach.service.ts b/alfa-client/libs/admin/postfach-shared/src/lib/postfach.service.ts index 19cf4ef6cf561586b44f3afee70e4c716ec54052..3321cfc1690bd504a1e0f94ac6eda627170a29c9 100644 --- a/alfa-client/libs/admin/postfach-shared/src/lib/postfach.service.ts +++ b/alfa-client/libs/admin/postfach-shared/src/lib/postfach.service.ts @@ -21,13 +21,13 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { SettingName } from '@admin-client/settings-shared'; +import { SettingItem, SettingName } from '@admin-client/settings-shared'; import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; import { SnackBarService } from '@alfa-client/ui'; import { inject, Injectable } from '@angular/core'; import { Observable, startWith, tap } from 'rxjs'; import { PostfachResourceService } from './postfach-resource.service'; -import { Postfach, PostfachResource, PostfachSettingsItem } from './postfach.model'; +import { Postfach, PostfachResource } from './postfach.model'; @Injectable() export class PostfachService { @@ -51,7 +51,7 @@ export class PostfachService { } } - private buildPostfachSettingItem(postfach: Postfach): PostfachSettingsItem { + private buildPostfachSettingItem(postfach: Postfach): SettingItem<Postfach> { return { name: SettingName.POSTFACH, settingBody: postfach, diff --git a/alfa-client/libs/admin/postfach-shared/src/test/postfach.ts b/alfa-client/libs/admin/postfach-shared/src/test/postfach.ts index 93d7492c32b0e0b595a447757952ee358b0e1345..88132bc3d88c73d130f50caed0da9aa15ae68d5b 100644 --- a/alfa-client/libs/admin/postfach-shared/src/test/postfach.ts +++ b/alfa-client/libs/admin/postfach-shared/src/test/postfach.ts @@ -22,9 +22,9 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { faker } from '@faker-js/faker'; -import { SettingItemResource, SettingName } from 'libs/admin/settings-shared/src/lib/settings.model'; +import { SettingItem, SettingName } from 'libs/admin/settings-shared/src/lib/settings.model'; import { toResource } from 'libs/tech-shared/test/resource'; -import { Postfach, PostfachResource, PostfachSettingsItem } from '../lib/postfach.model'; +import { Postfach, PostfachResource } from '../lib/postfach.model'; export function createPostfach(): Postfach { return { @@ -39,7 +39,7 @@ export function createPostfach(): Postfach { }; } -export function createPostfachSettingItem(): PostfachSettingsItem { +export function createPostfachSettingItem(): SettingItem<Postfach> { return { name: SettingName.POSTFACH, settingBody: createPostfach(), @@ -49,10 +49,3 @@ export function createPostfachSettingItem(): PostfachSettingsItem { export function createPostfachResource(): PostfachResource { return toResource(createPostfachSettingItem()); } - -export function createSettingItemResource(): SettingItemResource { - return toResource({ - name: faker.word.sample(), - settingBody: {}, - }); -} diff --git a/alfa-client/libs/admin/reporting-shared/.eslintrc.json b/alfa-client/libs/admin/reporting-shared/.eslintrc.json new file mode 100644 index 0000000000000000000000000000000000000000..7474579d583c598ae092a906b3e6cf1ad3c08a50 --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "admin", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "admin", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/alfa-client/libs/admin/reporting-shared/README.md b/alfa-client/libs/admin/reporting-shared/README.md new file mode 100644 index 0000000000000000000000000000000000000000..be5bb22469ec116a5b8b3d498db669555c92da4e --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/README.md @@ -0,0 +1,7 @@ +# admin-reporting-shared + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test admin-reporting-shared` to execute the unit tests. diff --git a/alfa-client/libs/admin/reporting-shared/jest.config.ts b/alfa-client/libs/admin/reporting-shared/jest.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..b4f392a061baff74cb98d86a02f0100960384315 --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/jest.config.ts @@ -0,0 +1,21 @@ +export default { + displayName: 'admin-reporting-shared', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'], + coverageDirectory: '../../../coverage/libs/admin/reporting-shared', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '<rootDir>/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/alfa-client/libs/admin/reporting-shared/project.json b/alfa-client/libs/admin/reporting-shared/project.json new file mode 100644 index 0000000000000000000000000000000000000000..f7a760900530aff273dc117494292f1e2b028824 --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/project.json @@ -0,0 +1,22 @@ +{ + "name": "admin-reporting-shared", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/admin/reporting-shared/src", + "prefix": "admin", + "projectType": "library", + "tags": [], + "targets": { + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "tsConfig": "libs/admin/reporting-shared/tsconfig.spec.json", + "jestConfig": "libs/admin/reporting-shared/jest.config.ts" + } + }, + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"] + } + } +} diff --git a/alfa-client/libs/admin/reporting-shared/src/index.ts b/alfa-client/libs/admin/reporting-shared/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..44ab78233d97deaf497e327e28f71c431ae6960e --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/index.ts @@ -0,0 +1,4 @@ +export * from './lib/aggregation-mapping-resource.service'; +export * from './lib/aggregation-mapping.model'; +export * from './lib/aggregation-mapping.provider'; +export * from './lib/aggregation-mapping.service'; diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..65eb7a8e1680b97f12cdba2556ae8d9d9041883c --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.ts @@ -0,0 +1,26 @@ +import { ConfigurationLinkRel, ConfigurationResource, ConfigurationService } from '@admin-client/configuration-shared'; +import { ListResourceServiceConfig, ResourceListService, ResourceRepository } from '@alfa-client/tech-shared'; +import { AggregationMappingListLinkRel } from './aggregation-mapping.linkrel'; +import { AggregationMappingListResource, AggregationMappingResource } from './aggregation-mapping.model'; + +export class AggregationMappingListResourceService extends ResourceListService< + ConfigurationResource, + AggregationMappingListResource, + AggregationMappingResource +> {} + +export function createAggregationMappingResourceService( + repository: ResourceRepository, + configurationService: ConfigurationService, +) { + return new ResourceListService(buildConfig(configurationService), repository); +} + +function buildConfig(configurationService: ConfigurationService): ListResourceServiceConfig<ConfigurationResource> { + return { + baseResource: configurationService.get(), + listLinkRel: ConfigurationLinkRel.AGGREGATION_MAPPINGS, + listResourceListLinkRel: AggregationMappingListLinkRel.LIST, + createLinkRel: AggregationMappingListLinkRel.SELF, + }; +} diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.linkrel.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.linkrel.ts new file mode 100644 index 0000000000000000000000000000000000000000..a4a02bfd7087b105a9d0d2dd816aa2b180a4db9c --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.linkrel.ts @@ -0,0 +1,4 @@ +export enum AggregationMappingListLinkRel { + LIST = 'aggregationMappings', + SELF = 'self', +} diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.model.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..0db6cb4e397768b10781b3c34c9379fc866cec2b --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.model.ts @@ -0,0 +1,20 @@ +import { ListResource } from '@alfa-client/tech-shared'; +import { Resource } from '@ngxp/rest'; + +export interface AggregationMapping { + formIdentifier: FormIdentifier; + mappings: FieldMapping[]; +} + +export interface FormIdentifier { + formEngineName: string; + formId: string; +} + +export interface FieldMapping { + sourcePath: string; + targetPath: string; +} + +export interface AggregationMappingResource extends AggregationMapping, Resource {} +export interface AggregationMappingListResource extends ListResource {} diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.provider.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.provider.ts new file mode 100644 index 0000000000000000000000000000000000000000..888d7154e81dbfe53fb7476e4de8835463de6d25 --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.provider.ts @@ -0,0 +1,17 @@ +import { ResourceRepository } from '@alfa-client/tech-shared'; +import { Provider } from '@angular/core'; +import { ConfigurationService } from 'libs/admin/configuration-shared/src/lib/configuration.service'; +import { + AggregationMappingListResourceService, + createAggregationMappingResourceService, +} from './aggregation-mapping-resource.service'; +import { AggregationMappingService } from './aggregation-mapping.service'; + +export const AggregationMappingProvider: Provider[] = [ + { + provide: AggregationMappingListResourceService, + useFactory: createAggregationMappingResourceService, + deps: [ResourceRepository, ConfigurationService], + }, + AggregationMappingService, +]; diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.service.spec.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..ecf4387ceee6a3dbdd6775f8ef4fa3a306144002 --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.service.spec.ts @@ -0,0 +1,79 @@ +import { StateResource, createStateResource } from '@alfa-client/tech-shared'; +import { Mock, mock } from '@alfa-client/test-utils'; +import { TestBed } from '@angular/core/testing'; +import { singleCold } from 'libs/tech-shared/test/marbles'; +import { Observable } from 'rxjs'; +import { + createAggregationMapping, + createAggregationMappingListResource, + createAggregationMappingResource, +} from '../../test/aggregation-mapping'; +import { AggregationMappingListResourceService } from './aggregation-mapping-resource.service'; +import { AggregationMapping, AggregationMappingListResource, AggregationMappingResource } from './aggregation-mapping.model'; +import { AggregationMappingService } from './aggregation-mapping.service'; + +describe('AggregationMappingService', () => { + let service: AggregationMappingService; + let listResourceService: Mock<AggregationMappingListResourceService>; + + beforeEach(() => { + listResourceService = mock(AggregationMappingListResourceService); + + TestBed.configureTestingModule({ + providers: [AggregationMappingService, { provide: AggregationMappingListResourceService, useValue: listResourceService }], + }); + + service = TestBed.inject(AggregationMappingService); + }); + + it('should create', () => { + expect(service).toBeTruthy(); + }); + + describe('get list', () => { + const aggregationMappingListResource: AggregationMappingListResource = createAggregationMappingListResource(); + const aggregationMappingListStateResource: StateResource<AggregationMappingListResource> = + createStateResource(aggregationMappingListResource); + + beforeEach(() => { + listResourceService.getList = jest.fn().mockReturnValue(singleCold(aggregationMappingListStateResource)); + }); + + it('should call listResourceService', () => { + service.getList(); + + expect(listResourceService.getList).toHaveBeenCalled(); + }); + + it('should return value', () => { + const loadedAggregationMappingListResource: Observable<StateResource<AggregationMappingListResource>> = service.getList(); + + expect(loadedAggregationMappingListResource).toBeObservable(singleCold(aggregationMappingListStateResource)); + }); + }); + + describe('create', () => { + const aggregationMappingResource: AggregationMappingResource = createAggregationMappingResource(); + const aggregationMappingStateResource: StateResource<AggregationMappingResource> = + createStateResource(aggregationMappingResource); + + const aggregationMapping: AggregationMapping = createAggregationMapping(); + + beforeEach(() => { + listResourceService.create = jest.fn().mockReturnValue(singleCold(aggregationMappingStateResource)); + }); + + it('should call resourceService', () => { + service.create(aggregationMapping); + + expect(listResourceService.create).toHaveBeenCalledWith(aggregationMapping); + }); + + it('should return value', () => { + const loadedAggregationMappingResource: Observable<StateResource<AggregationMappingResource>> = + service.create(aggregationMapping); + + expect(loadedAggregationMappingResource).toBeObservable(singleCold(aggregationMappingStateResource)); + }); + }); +}); diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.service.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..20a8ce6c1ccda133323bac99a671d887e77afb8e --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.service.ts @@ -0,0 +1,18 @@ +import { StateResource } from '@alfa-client/tech-shared'; +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { AggregationMappingListResourceService } from './aggregation-mapping-resource.service'; +import { AggregationMapping, AggregationMappingListResource, AggregationMappingResource } from './aggregation-mapping.model'; + +@Injectable() +export class AggregationMappingService { + readonly listService = inject(AggregationMappingListResourceService); + + public getList(): Observable<StateResource<AggregationMappingListResource>> { + return this.listService.getList(); + } + + public create(toCreate: AggregationMapping): Observable<StateResource<AggregationMappingResource>> { + return this.listService.create(toCreate); + } +} diff --git a/alfa-client/libs/admin/reporting-shared/src/test-setup.ts b/alfa-client/libs/admin/reporting-shared/src/test-setup.ts new file mode 100644 index 0000000000000000000000000000000000000000..c408668266d2fec3a9803c0ec044bc163fb987fe --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/test-setup.ts @@ -0,0 +1,12 @@ +import '@testing-library/jest-dom'; +import 'jest-preset-angular/setup-jest'; + +import { getTestBed } from '@angular/core/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; + +getTestBed().resetTestEnvironment(); +getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { + teardown: { destroyAfterEach: false }, + errorOnUnknownProperties: true, + errorOnUnknownElements: true, +}); diff --git a/alfa-client/libs/admin/reporting-shared/test/aggregation-mapping.ts b/alfa-client/libs/admin/reporting-shared/test/aggregation-mapping.ts new file mode 100644 index 0000000000000000000000000000000000000000..acbcc9fa75722396e4a410ea77e9157a2a8ce8fc --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/test/aggregation-mapping.ts @@ -0,0 +1,35 @@ +import { faker } from '@faker-js/faker'; +import { times } from 'lodash-es'; +import { LinkRelationName } from '../../../tech-shared/src'; +import { toResource } from '../../../tech-shared/test/resource'; +import { AggregationMapping, AggregationMappingListResource, AggregationMappingResource } from '../src'; +import { AggregationMappingListLinkRel } from '../src/lib/aggregation-mapping.linkrel'; + +export function createAggregationMapping(): AggregationMapping { + return { + formIdentifier: { + formEngineName: faker.lorem.word(), + formId: faker.string.uuid(), + }, + mappings: [ + { + sourcePath: faker.lorem.word(), + targetPath: faker.lorem.word(), + }, + ], + }; +} + +export function createAggregationMappingResource(linkRelations: LinkRelationName[] = []): AggregationMappingResource { + return toResource(createAggregationMapping(), linkRelations); +} + +export function createAggregationMappingResources(linkRelations: LinkRelationName[] = []): AggregationMappingResource[] { + return times(10, () => createAggregationMappingResource(linkRelations)); +} + +export function createAggregationMappingListResource(linkRelations: LinkRelationName[] = []): AggregationMappingListResource { + return toResource({}, linkRelations, { + [AggregationMappingListLinkRel.LIST]: createAggregationMappingResources(), + }); +} diff --git a/alfa-client/libs/admin/reporting-shared/tsconfig.json b/alfa-client/libs/admin/reporting-shared/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..8ca9ad312c2bd4dc364383853ddd91a2ed8f86fd --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "compilerOptions": { + "target": "es2022" + } +} diff --git a/alfa-client/libs/admin/reporting-shared/tsconfig.lib.json b/alfa-client/libs/admin/reporting-shared/tsconfig.lib.json new file mode 100644 index 0000000000000000000000000000000000000000..8441346f6e5858b2ef4235cb3c3160eda256f94a --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": ["src/**/*.spec.ts", "src/test-setup.ts", "jest.config.ts", "src/**/*.test.ts"], + "include": ["src/**/*.ts"] +} diff --git a/alfa-client/libs/admin/reporting-shared/tsconfig.spec.json b/alfa-client/libs/admin/reporting-shared/tsconfig.spec.json new file mode 100644 index 0000000000000000000000000000000000000000..723782fbd367969806c5992aea882773ab65af8b --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/tsconfig.spec.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"], + "target": "ES2022", + "useDefineForClassFields": false + }, + "files": ["src/test-setup.ts"], + "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts", "jest.config.ts"] +} diff --git a/alfa-client/libs/admin/settings-shared/jest.config.ts b/alfa-client/libs/admin/settings-shared/jest.config.ts index e9e4c0e81848959b2203b3551b8a0e999c127500..9c940034939a689a0f138e47d5c3a5c34d2bb92e 100644 --- a/alfa-client/libs/admin/settings-shared/jest.config.ts +++ b/alfa-client/libs/admin/settings-shared/jest.config.ts @@ -1,9 +1,8 @@ export default { - displayName: 'admin-settings', + displayName: 'admin-settings-shared', preset: '../../../jest.preset.js', setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'], - globals: {}, - coverageDirectory: '../../coverage/libs/admin/settings-shared', + coverageDirectory: '../../../coverage/libs/admin/settings-shared', transform: { '^.+\\.(ts|mjs|js|html)$': [ 'jest-preset-angular', @@ -13,7 +12,7 @@ export default { }, ], }, - transformIgnorePatterns: ['node_modules/(?!.pnpm|.*\\.mjs$)'], + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], snapshotSerializers: [ 'jest-preset-angular/build/serializers/no-ng-attributes', 'jest-preset-angular/build/serializers/ng-snapshot', diff --git a/alfa-client/libs/admin/settings-shared/project.json b/alfa-client/libs/admin/settings-shared/project.json index 702a27446f83db42dc97ec9409c8f3d323dcbb65..02e461c6816868190ac3b45dea543a934a1d6d1d 100644 --- a/alfa-client/libs/admin/settings-shared/project.json +++ b/alfa-client/libs/admin/settings-shared/project.json @@ -1,15 +1,11 @@ { - "name": "admin-settings", + "name": "admin-settings-shared", "$schema": "../../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "libs/admin/settings-shared/src", - "projectType": "library", "prefix": "admin", + "projectType": "library", "tags": [], "targets": { - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"] - }, "test": { "executor": "@nx/jest:jest", "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], @@ -17,6 +13,10 @@ "tsConfig": "libs/admin/settings-shared/tsconfig.spec.json", "jestConfig": "libs/admin/settings-shared/jest.config.ts" } + }, + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"] } } } diff --git a/alfa-client/libs/admin/settings-shared/src/lib/settings-resource.service.ts b/alfa-client/libs/admin/settings-shared/src/lib/settings-resource.service.ts index a75f91afec901a8c969c00ede9a8631766421f1f..7e9df14e6ec13929f720978ada7ebcb3e74c5ef9 100644 --- a/alfa-client/libs/admin/settings-shared/src/lib/settings-resource.service.ts +++ b/alfa-client/libs/admin/settings-shared/src/lib/settings-resource.service.ts @@ -4,7 +4,11 @@ import { Resource } from '@ngxp/rest'; import { SettingListLinkRel } from './settings.linkrel'; import { SettingItemResource, SettingListResource } from './settings.model'; -export class SettingListResourceService extends ResourceListService<Resource, SettingListResource, SettingItemResource> {} +export class SettingListResourceService extends ResourceListService< + Resource, + SettingListResource, + SettingItemResource<unknown> +> {} export function createSettingListResourceService(repository: ResourceRepository, configurationService: ConfigurationService) { return new ResourceListService(buildConfig(configurationService), repository); diff --git a/alfa-client/libs/admin/settings-shared/src/lib/settings.model.ts b/alfa-client/libs/admin/settings-shared/src/lib/settings.model.ts index 263fca126d53eb889e1701e931a8b32a38899145..2e97584b7934ea105c828cbb2523c0d16ce431a1 100644 --- a/alfa-client/libs/admin/settings-shared/src/lib/settings.model.ts +++ b/alfa-client/libs/admin/settings-shared/src/lib/settings.model.ts @@ -25,16 +25,16 @@ import { ListResource } from '@alfa-client/tech-shared'; import { Resource } from '@ngxp/rest'; export interface SettingListResource extends ListResource { - _embedded: { settings: SettingItemResource[] }; + _embedded: { settings: SettingItemResource<unknown>[] }; } export enum SettingName { POSTFACH = 'Postfach', } -export interface SettingItem { +export interface SettingItem<T> { name: SettingName; - settingBody: unknown; + settingBody: T; } -export declare type SettingItemResource = Resource & SettingItem; +export interface SettingItemResource<T> extends SettingItem<T>, Resource {} diff --git a/alfa-client/libs/admin/settings-shared/src/lib/settings.service.spec.ts b/alfa-client/libs/admin/settings-shared/src/lib/settings.service.spec.ts index 9b24d56767a9f5de93f738638d976333cfa93af7..1cf23c357186c0480ce12a349497c2c1f66139e5 100644 --- a/alfa-client/libs/admin/settings-shared/src/lib/settings.service.spec.ts +++ b/alfa-client/libs/admin/settings-shared/src/lib/settings.service.spec.ts @@ -21,16 +21,14 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { PostfachResource } from '@admin-client/postfach-shared'; import { StateResource, createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared'; import { Mock, mock } from '@alfa-client/test-utils'; import { TestBed } from '@angular/core/testing'; import { singleCold } from 'libs/tech-shared/test/marbles'; import { Observable, of } from 'rxjs'; -import { createPostfachResource, createSettingItemResource } from '../../../postfach-shared/src/test/postfach'; -import { createSettingsListResource } from '../../test/settings'; +import { createSettingItemResource, createSettingsListResource } from '../../test/settings'; import { SettingListResourceService } from './settings-resource.service'; -import { SettingListResource } from './settings.model'; +import { SettingItemResource, SettingListResource, SettingName } from './settings.model'; import { SettingsService } from './settings.service'; describe('SettingsService', () => { @@ -51,11 +49,12 @@ describe('SettingsService', () => { expect(service).toBeTruthy(); }); - describe('get Postfach', () => { - const postfachResource = createPostfachResource(); - const postfachStateResource: StateResource<PostfachResource> = createStateResource(postfachResource); + describe('get by setting name', () => { + const settingItemName: SettingName = <SettingName>'DUMMY'; + const settingItemResource: SettingItemResource<unknown> = { ...createSettingItemResource(), name: settingItemName }; + const settingItemStateResource: StateResource<SettingItemResource<unknown>> = createStateResource(settingItemResource); const settingsListResource: StateResource<SettingListResource> = createStateResource( - createSettingsListResource([postfachResource]), + createSettingsListResource([settingItemResource]), ); beforeEach(() => { @@ -63,28 +62,28 @@ describe('SettingsService', () => { }); it('should call resource service', () => { - service.getPostfach(); + service.get(settingItemName); expect(settingListResourceService.getList).toHaveBeenCalled(); }); - it('should return null for non postfach resource', () => { + it('should return null for non existing setting item resource', () => { const emptySettingsListResource: StateResource<SettingListResource> = createStateResource( createSettingsListResource([createSettingItemResource()]), ); - settingListResourceService.getList = jest.fn().mockReturnValue(singleCold(emptySettingsListResource)); - const postfach: Observable<StateResource<PostfachResource>> = service.getPostfach(); - expect(postfach).toBeObservable(singleCold(createEmptyStateResource())); + const settingItemStateResource$: Observable<StateResource<SettingItemResource<unknown>>> = service.get(settingItemName); + + expect(settingItemStateResource$).toBeObservable(singleCold(createEmptyStateResource())); }); - it('should return item resource as postfach resource', () => { + it('should return item resource as setting item resource', () => { settingListResourceService.getList = jest.fn().mockReturnValue(singleCold(settingsListResource)); - const postfach: Observable<StateResource<PostfachResource>> = service.getPostfach(); + const settingItemStateResource$: Observable<StateResource<SettingItemResource<unknown>>> = service.get(settingItemName); - expect(postfach).toBeObservable(singleCold(postfachStateResource)); + expect(settingItemStateResource$).toBeObservable(singleCold(settingItemStateResource)); }); }); }); diff --git a/alfa-client/libs/admin/settings-shared/src/lib/settings.service.ts b/alfa-client/libs/admin/settings-shared/src/lib/settings.service.ts index 51faa2be7ea9aa2a9f878de233ad56d32ec0f81c..770c9d7da6230f67e7d92c553e97e062277b5994 100644 --- a/alfa-client/libs/admin/settings-shared/src/lib/settings.service.ts +++ b/alfa-client/libs/admin/settings-shared/src/lib/settings.service.ts @@ -1,15 +1,17 @@ -import { PostfachResource } from '@admin-client/postfach-shared'; import { StateResource } from '@alfa-client/tech-shared'; import { inject, Injectable } from '@angular/core'; import { map, Observable } from 'rxjs'; import { SettingListResourceService } from './settings-resource.service'; -import { getPostfachResource } from './settings.util'; +import { SettingItemResource, SettingListResource, SettingName } from './settings.model'; +import { getSettingItemResource } from './settings.util'; @Injectable() export class SettingsService { private settingListResourceService = inject(SettingListResourceService); - public getPostfach(): Observable<StateResource<PostfachResource>> { - return this.settingListResourceService.getList().pipe(map(getPostfachResource)); + public get<T>(name: SettingName): Observable<StateResource<SettingItemResource<T>>> { + return this.settingListResourceService + .getList() + .pipe(map((list: StateResource<SettingListResource>) => getSettingItemResource<T>(list, name))); } } diff --git a/alfa-client/libs/admin/settings-shared/src/lib/settings.util.spec.ts b/alfa-client/libs/admin/settings-shared/src/lib/settings.util.spec.ts index 5b78df34aa506c8180878416054cd11bb4164d14..fe8480f147ba265070096e70d6fe54f817324397 100644 --- a/alfa-client/libs/admin/settings-shared/src/lib/settings.util.spec.ts +++ b/alfa-client/libs/admin/settings-shared/src/lib/settings.util.spec.ts @@ -21,30 +21,31 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { PostfachResource } from '@admin-client/postfach-shared'; -import { SettingListResource } from '@admin-client/settings-shared'; import { createEmptyStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared'; -import { createPostfachResource } from 'libs/admin/postfach-shared/src/test/postfach'; -import { createFilledSettingsListResource } from '../../test/settings'; -import { getPostfachResource } from './settings.util'; +import { Resource } from '@ngxp/rest'; +import { createFilledSettingsListResource, createSettingItemResource } from '../../test/settings'; +import { SettingItemResource, SettingListResource, SettingName } from './settings.model'; +import { getSettingItemResource } from './settings.util'; -describe('get postfach resource', () => { - it('should return state resource with postfach resource if exists', () => { - const postfachResource: PostfachResource = createPostfachResource(); +describe('get setting item resource', () => { + const settingName: SettingName = <SettingName>'DUMMY'; + + it('should return matching setting resource as state resource if exists', () => { + const settingItemResource: SettingItemResource<unknown> = { ...createSettingItemResource(), name: settingName }; const settingsListResource: StateResource<SettingListResource> = createStateResource( - createFilledSettingsListResource([postfachResource]), + createFilledSettingsListResource([settingItemResource]), ); - const postfachStateResource: StateResource<PostfachResource> = getPostfachResource(settingsListResource); + const stateResource: StateResource<Resource> = getSettingItemResource(settingsListResource, settingName); - expect(postfachStateResource.resource).toEqual(postfachResource); + expect(stateResource.resource).toEqual(settingItemResource); }); - it('should return empty state resource if postfach resource NOT exists', () => { + it('should return empty state resource if no matching resource exists', () => { const settingsListResource: StateResource<SettingListResource> = createStateResource(createFilledSettingsListResource([])); - const postfachStateResource: StateResource<PostfachResource> = getPostfachResource(settingsListResource); + const stateResource: StateResource<Resource> = getSettingItemResource(settingsListResource, settingName); - expect(postfachStateResource).toEqual(createEmptyStateResource()); + expect(stateResource).toEqual(createEmptyStateResource()); }); }); diff --git a/alfa-client/libs/admin/settings-shared/src/lib/settings.util.ts b/alfa-client/libs/admin/settings-shared/src/lib/settings.util.ts index d5cf7605cada028e253a26d1e3641eee5856e2c7..2a00f86b2a84fef05b45ccfde06c3ff8a6321745 100644 --- a/alfa-client/libs/admin/settings-shared/src/lib/settings.util.ts +++ b/alfa-client/libs/admin/settings-shared/src/lib/settings.util.ts @@ -21,7 +21,6 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { PostfachResource } from '@admin-client/postfach-shared'; import { createEmptyStateResource, createStateResource, @@ -32,14 +31,11 @@ import { import { SettingListLinkRel } from './settings.linkrel'; import { SettingItemResource, SettingListResource, SettingName } from './settings.model'; -export function getPostfachResource(settingsListResource: StateResource<SettingListResource>): StateResource<PostfachResource> { - const entries: SettingItemResource[] = getEmbeddedResources(settingsListResource, SettingListLinkRel.LIST); - const postfachSettingItemResource: SettingItemResource = entries.find(isPostfachSettingItem); - return isNotNil(postfachSettingItemResource) ? - createStateResource(postfachSettingItemResource as PostfachResource) - : createEmptyStateResource(); -} - -function isPostfachSettingItem(item: SettingItemResource): boolean { - return item.name === SettingName.POSTFACH; +export function getSettingItemResource<T>( + settingsListResource: StateResource<SettingListResource>, + itemName: SettingName, +): StateResource<SettingItemResource<T>> { + const entries: SettingItemResource<T>[] = getEmbeddedResources(settingsListResource, SettingListLinkRel.LIST); + const entry: SettingItemResource<T> = entries.find((item: SettingItemResource<T>) => item.name === itemName); + return isNotNil(entry) ? createStateResource(entry) : createEmptyStateResource<SettingItemResource<T>>(); } diff --git a/alfa-client/libs/admin/settings-shared/test/settings.ts b/alfa-client/libs/admin/settings-shared/test/settings.ts index c3b9478ea57d373b18ad6315c0e5161fd7d9b008..a7bf1ded5bac477efcce579bd74f1646d8664a2d 100644 --- a/alfa-client/libs/admin/settings-shared/test/settings.ts +++ b/alfa-client/libs/admin/settings-shared/test/settings.ts @@ -1,9 +1,10 @@ +import { faker } from '@faker-js/faker/.'; import { Resource } from '@ngxp/rest'; import { toResource } from 'libs/tech-shared/test/resource'; import { SettingListLinkRel } from '../src/lib/settings.linkrel'; import { SettingItemResource, SettingListResource } from '../src/lib/settings.model'; -export function createSettingsListResource(settingsItems: SettingItemResource[]): SettingListResource { +export function createSettingsListResource(settingsItems: SettingItemResource<unknown>[]): SettingListResource { return toResource({}, [], { settings: settingsItems, }); @@ -14,3 +15,10 @@ export function createFilledSettingsListResource(resources: Resource[], linkRela [SettingListLinkRel.LIST]: resources, }); } + +export function createSettingItemResource(): SettingItemResource<unknown> { + return toResource({ + name: faker.word.sample(), + settingBody: {}, + }); +} diff --git a/alfa-client/libs/admin/shared/src/index.ts b/alfa-client/libs/admin/shared/src/index.ts index ece2c025dc3e05d4b26ad131fc7e419331e301d2..8f0992f8376dfb02cbd0096e33f516ac819f3d97 100644 --- a/alfa-client/libs/admin/shared/src/index.ts +++ b/alfa-client/libs/admin/shared/src/index.ts @@ -1 +1,4 @@ +export * from './lib/admin-cancel-button/admin-cancel-button.component'; +export * from './lib/admin-save-button/admin-save-button.component'; export * from './lib/routes'; +export * from './lib/token'; diff --git a/alfa-client/libs/admin/shared/src/lib/admin-cancel-button/admin-cancel-button.component.html b/alfa-client/libs/admin/shared/src/lib/admin-cancel-button/admin-cancel-button.component.html new file mode 100644 index 0000000000000000000000000000000000000000..3125fbdfd9242e48e3a30a5891e445bb6d8b8498 --- /dev/null +++ b/alfa-client/libs/admin/shared/src/lib/admin-cancel-button/admin-cancel-button.component.html @@ -0,0 +1,3 @@ +<ods-routing-button [linkPath]="linkPath" text="Abbrechen" variant="outline" dataTestId="cancel-button"> + <ods-close-icon icon class="fill-primary" /> +</ods-routing-button> diff --git a/alfa-client/libs/admin/shared/src/lib/admin-cancel-button/admin-cancel-button.component.spec.ts b/alfa-client/libs/admin/shared/src/lib/admin-cancel-button/admin-cancel-button.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..253650b230fb8be30ddb854fe3ad62351b058e5b --- /dev/null +++ b/alfa-client/libs/admin/shared/src/lib/admin-cancel-button/admin-cancel-button.component.spec.ts @@ -0,0 +1,36 @@ +import { AdminCancelButtonComponent } from '@admin-client/shared'; +import { getMockComponent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { RoutingButtonComponent } from '@ods/component'; +import { CloseIconComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; + +describe('AdminCancelButtonComponent', () => { + let component: AdminCancelButtonComponent; + let fixture: ComponentFixture<AdminCancelButtonComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AdminCancelButtonComponent], + declarations: [MockComponent(RoutingButtonComponent), MockComponent(CloseIconComponent)], + }).compileComponents(); + + fixture = TestBed.createComponent(AdminCancelButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('button', () => { + it('should be called with linkPath', () => { + component.linkPath = 'dummyLinkPath'; + + fixture.detectChanges(); + + expect(getMockComponent(fixture, RoutingButtonComponent).linkPath).toBe('dummyLinkPath'); + }); + }); +}); diff --git a/alfa-client/libs/admin/shared/src/lib/admin-cancel-button/admin-cancel-button.component.ts b/alfa-client/libs/admin/shared/src/lib/admin-cancel-button/admin-cancel-button.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..8c284f05c61e3d545025c8447d4d302a0fc3db85 --- /dev/null +++ b/alfa-client/libs/admin/shared/src/lib/admin-cancel-button/admin-cancel-button.component.ts @@ -0,0 +1,14 @@ +import { CommonModule } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { RoutingButtonComponent } from '@ods/component'; +import { CloseIconComponent } from '@ods/system'; + +@Component({ + selector: 'admin-cancel-button', + templateUrl: './admin-cancel-button.component.html', + standalone: true, + imports: [CommonModule, RoutingButtonComponent, CloseIconComponent], +}) +export class AdminCancelButtonComponent { + @Input() linkPath: string; +} diff --git a/alfa-client/libs/admin/shared/src/lib/admin-save-button/admin-save-button.component.html b/alfa-client/libs/admin/shared/src/lib/admin-save-button/admin-save-button.component.html new file mode 100644 index 0000000000000000000000000000000000000000..8bd6a5f92932e22006b3b8e2cb353a9c3fa93eb1 --- /dev/null +++ b/alfa-client/libs/admin/shared/src/lib/admin-save-button/admin-save-button.component.html @@ -0,0 +1,6 @@ +<ods-button-with-spinner + (clickEmitter)="submit()" + text="Speichern" + dataTestId="save-button" + [stateResource]="stateResource$ | async" +/> diff --git a/alfa-client/libs/admin/shared/src/lib/admin-save-button/admin-save-button.component.spec.ts b/alfa-client/libs/admin/shared/src/lib/admin-save-button/admin-save-button.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..52a303f378e824677dd6518126ae838ebd416e3a --- /dev/null +++ b/alfa-client/libs/admin/shared/src/lib/admin-save-button/admin-save-button.component.spec.ts @@ -0,0 +1,71 @@ +import { ADMIN_FORMSERVICE } from '@admin-client/shared'; +import { AbstractFormService, createStateResource, StateResource } from '@alfa-client/tech-shared'; +import { dispatchEventFromFixture, getMockComponent, Mock, MockEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { Resource } from '@ngxp/rest'; +import { ButtonWithSpinnerComponent } from '@ods/component'; +import { getDataTestIdAttributeOf } from 'libs/tech-shared/test/data-test'; +import { singleCold } from 'libs/tech-shared/test/marbles'; +import { createDummyResource } from 'libs/tech-shared/test/resource'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { AdminSaveButtonComponent } from './admin-save-button.component'; + +describe('AdminSaveButtonComponent', () => { + let component: AdminSaveButtonComponent; + let fixture: ComponentFixture<AdminSaveButtonComponent>; + + let formService: Mock<AbstractFormService<Resource>>; + + const saveButton: string = getDataTestIdAttributeOf('save-button'); + + const stateResource: StateResource<Resource> = createStateResource(createDummyResource()); + + beforeEach(async () => { + formService = <any>{ submit: jest.fn().mockReturnValue(singleCold(stateResource)) }; + + await TestBed.configureTestingModule({ + imports: [AdminSaveButtonComponent], + declarations: [MockComponent(ButtonWithSpinnerComponent)], + providers: [ + { + provide: ADMIN_FORMSERVICE, + useValue: formService, + }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(AdminSaveButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('on submit', () => { + it('should call formService', () => { + dispatchEventFromFixture(fixture, saveButton, MockEvent.CLICK); + + expect(formService.submit).toHaveBeenCalled(); + }); + + it('should assign state resource', () => { + dispatchEventFromFixture(fixture, saveButton, MockEvent.CLICK); + + expect(component.stateResource$).toBeObservable(singleCold(stateResource)); + }); + }); + + describe('button', () => { + it('should call with stateResource', () => { + component.stateResource$ = of(stateResource); + + fixture.detectChanges(); + + const comp: ButtonWithSpinnerComponent = getMockComponent(fixture, ButtonWithSpinnerComponent); + expect(comp.stateResource).toBe(stateResource); + }); + }); +}); diff --git a/alfa-client/libs/admin/shared/src/lib/admin-save-button/admin-save-button.component.ts b/alfa-client/libs/admin/shared/src/lib/admin-save-button/admin-save-button.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..60abd08c7f311ecabe6d56ecc47fbfcd16412877 --- /dev/null +++ b/alfa-client/libs/admin/shared/src/lib/admin-save-button/admin-save-button.component.ts @@ -0,0 +1,23 @@ +import { ADMIN_FORMSERVICE } from '@admin-client/shared'; +import { AbstractFormService, createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; +import { CommonModule } from '@angular/common'; +import { Component, inject } from '@angular/core'; +import { Resource } from '@ngxp/rest'; +import { ButtonWithSpinnerComponent } from '@ods/component'; +import { Observable, of } from 'rxjs'; + +@Component({ + selector: 'admin-save-button', + standalone: true, + imports: [CommonModule, ButtonWithSpinnerComponent], + templateUrl: './admin-save-button.component.html', +}) +export class AdminSaveButtonComponent { + private formService: AbstractFormService<Resource> = inject(ADMIN_FORMSERVICE); + + public stateResource$: Observable<StateResource<Resource>> = of(createEmptyStateResource<Resource>()); + + public submit(): void { + this.stateResource$ = this.formService.submit(); + } +} diff --git a/alfa-client/libs/admin/shared/src/lib/token.ts b/alfa-client/libs/admin/shared/src/lib/token.ts new file mode 100644 index 0000000000000000000000000000000000000000..f19e2c875946591ba08470c654f91c80664176aa --- /dev/null +++ b/alfa-client/libs/admin/shared/src/lib/token.ts @@ -0,0 +1,5 @@ +import { AbstractFormService } from '@alfa-client/tech-shared'; +import { InjectionToken } from '@angular/core'; +import { Resource } from '@ngxp/rest'; + +export const ADMIN_FORMSERVICE = new InjectionToken<AbstractFormService<Resource>>('adminFormService'); diff --git a/alfa-client/libs/admin/statistik/src/index.ts b/alfa-client/libs/admin/statistik/src/index.ts index cdc5d7b64f24d50920b721f3ab01c5b69cb41b99..157271feb3bf8625864f12faec9623307c3b7690 100644 --- a/alfa-client/libs/admin/statistik/src/index.ts +++ b/alfa-client/libs/admin/statistik/src/index.ts @@ -1 +1,2 @@ export * from './lib/statistik-container/statistik-container.component'; +export * from './lib/statistik-fields-form/admin-statistik-fields-form.component'; diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html index 77c10ae229f5d8c6430d82349d6f2d213fa72054..1fd0441a39d71372d0c65fd84d0ce5386ac52fd2 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html @@ -24,10 +24,12 @@ --> <h1 class="heading-1" data-test-id="statistik-header-text">Statistik</h1> -<div class="mt-4"> - <ods-button +<div class="mt-4 w-fit"> + <ods-routing-button + [linkPath]="ROUTES.STATISTIK_NEU" text="Weitere Felder auswerten" - (clickEmitter)="navigateToStatistikFieldsForm()" dataTestId="weitere-felder-auswerten-button" - ></ods-button> + ></ods-routing-button> </div> + +<ng-container *ngIf="listStateResource$ | async"></ng-container> diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts index b4390c03face2557262e05f6964e02dc40e4cd7a..a2bc7e4bfe5efdec1af21b9ad1da7deaccf1a21f 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts @@ -21,11 +21,15 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { ROUTES } from '@admin-client/shared'; -import { NavigationService } from '@alfa-client/navigation-shared'; -import { existsAsHtmlElement, mock, Mock, triggerEvent } from '@alfa-client/test-utils'; +import { AggregationMappingListResource, AggregationMappingService } from '@admin-client/reporting-shared'; +import { createStateResource, StateResource } from '@alfa-client/tech-shared'; +import { existsAsHtmlElement, mock, Mock } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { RoutingButtonComponent } from '@ods/component'; +import { singleCold } from 'libs/tech-shared/test/marbles'; +import { MockComponent } from 'ng-mocks'; import { getDataTestIdAttributeOf } from '../../../../../tech-shared/test/data-test'; +import { createAggregationMappingListResource } from '../../../../reporting-shared/test/aggregation-mapping'; import { StatistikContainerComponent } from './statistik-container.component'; describe('StatistikContainerComponent', () => { @@ -34,43 +38,34 @@ describe('StatistikContainerComponent', () => { const evaluateAdditionalFieldsTestId: string = getDataTestIdAttributeOf('weitere-felder-auswerten-button'); - let navigationService: Mock<NavigationService>; - - beforeEach(() => { - navigationService = mock(NavigationService); - }); + let aggregationMappingService: Mock<AggregationMappingService>; beforeEach(async () => { + aggregationMappingService = mock(AggregationMappingService); + await TestBed.configureTestingModule({ imports: [StatistikContainerComponent], - providers: [ - { - provide: NavigationService, - useValue: navigationService, + declarations: [MockComponent(RoutingButtonComponent)], + }) + .overrideComponent(StatistikContainerComponent, { + set: { + providers: [ + { + provide: AggregationMappingService, + useValue: aggregationMappingService, + }, + ], }, - ], - }); - }); + }) + .compileComponents(); - beforeEach(() => { fixture = TestBed.createComponent(StatistikContainerComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); - describe('component', () => { - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('navigateToStatistikFieldsForm', () => { - it('should call navigation service', () => { - component.navigateToStatistikFieldsForm(); - - expect(navigationService.navigate).toHaveBeenCalledWith(ROUTES.STATISTIK_NEU); - }); - }); + it('should create', () => { + expect(component).toBeTruthy(); }); describe('template', () => { @@ -80,23 +75,28 @@ describe('StatistikContainerComponent', () => { existsAsHtmlElement(fixture, evaluateAdditionalFieldsTestId); }); + }); + }); - describe('output', () => { - describe('clickEmitter', () => { - it('should call handler', () => { - component.navigateToStatistikFieldsForm = jest.fn(); - fixture.detectChanges(); + describe('on init', () => { + const stateResource: StateResource<AggregationMappingListResource> = createStateResource( + createAggregationMappingListResource(), + ); - triggerEvent({ - fixture, - elementSelector: evaluateAdditionalFieldsTestId, - name: 'clickEmitter', - }); + beforeEach(() => { + aggregationMappingService.getList.mockReturnValue(singleCold(stateResource)); + }); - expect(component.navigateToStatistikFieldsForm).toHaveBeenCalled(); - }); - }); - }); + it('should call service to get list', () => { + component.ngOnInit(); + + expect(aggregationMappingService.getList).toHaveBeenCalled(); + }); + + it('should assign stateResource', () => { + component.ngOnInit(); + + expect(component.listStateResource$).toBeObservable(singleCold(stateResource)); }); }); }); diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts index a00051de29e86232f267891b6f6c8324a726993a..90c3515896348b1c1d6ee77ba4f247428e79c4bf 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts @@ -21,22 +21,29 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { AggregationMappingListResource, AggregationMappingService } from '@admin-client/reporting-shared'; import { ROUTES } from '@admin-client/shared'; -import { NavigationService } from '@alfa-client/navigation-shared'; +import { StateResource } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; -import { Component, inject } from '@angular/core'; -import { ButtonComponent } from '@ods/system'; +import { Component, inject, OnInit } from '@angular/core'; +import { RoutingButtonComponent } from '@ods/component'; +import { Observable } from 'rxjs'; @Component({ selector: 'admin-statistik-container', templateUrl: './statistik-container.component.html', standalone: true, - imports: [CommonModule, ButtonComponent], + imports: [CommonModule, RoutingButtonComponent], + providers: [AggregationMappingService], }) -export class StatistikContainerComponent { - private readonly navigationService = inject(NavigationService); +export class StatistikContainerComponent implements OnInit { + private service = inject(AggregationMappingService); - public navigateToStatistikFieldsForm(): void { - this.navigationService.navigate(ROUTES.STATISTIK_NEU); + public listStateResource$: Observable<StateResource<AggregationMappingListResource>>; + + public readonly ROUTES = ROUTES; + + ngOnInit(): void { + this.listStateResource$ = this.service.getList(); } } diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component.html b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component.html index cef302fc15f148000041c0c968f1ccbefc446e83..27805c87fe074bae41311083bc1aed20d5aaeaef 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component.html +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component.html @@ -1,37 +1,29 @@ <h2 class="heading-2" data-test-id="statistik-fields-form-header-text">Felder zur Auswertung hinzufügen</h2> <div class="flex max-w-4xl flex-col gap-4"> - <ods-text-input - [fieldControl]="formEngineFormControl" - label="Formengine" - placeholder="Tragen Sie hier die Formengine des Formulars ein." - data-test-id="form-engine-input" - ></ods-text-input> - - <ods-text-input - [fieldControl]="formIdFormControl" - label="FormID" - placeholder="Tragen Sie hier die FormID des Formulars ein." - data-test-id="form-id-input" - ></ods-text-input> - - @for (dataFieldControl of dataFieldsFormControls; track $index) { - <ods-text-input - [fieldControl]="dataFieldControl" - label="Pfad des Datenfeldes" - placeholder="Tragen Sie hier den gesamten Pfad des Datenfeldes ein, das Sie auswerten möchten." - [attr.data-test-id]="'data-statistik-field-' + $index" - ></ods-text-input> - } - - <ods-button text="Datenfeld hinzufügen" (clickEmitter)="addDataField()" dataTestId="add-data-field-button"> - <ods-plus-icon icon class="fill-whitetext"/> + <form class="form flex-col" [formGroup]="formService.form" class="flex flex-col gap-4"> + <div [formGroupName]="StatistikFieldsFormService.FIELD_FORM_IDENTIFIER" class="flex flex-col gap-4"> + <ods-text-editor + [formControlName]="StatistikFieldsFormService.FIELD_FORM_ENGINE_NAME" + label="Formengine" + placeholder="Tragen Sie hier die Formengine des Formulars ein." + data-test-id="form-engine-name-input" + ></ods-text-editor> + <ods-text-editor + [formControlName]="StatistikFieldsFormService.FIELD_FORM_ID" + label="FormID" + placeholder="Tragen Sie hier die FormID des Formulars ein." + data-test-id="form-id-input" + ></ods-text-editor> + </div> + <statistik-fields-form-mapping /> + </form> + <ods-button text="Datenfeld hinzufügen" dataTestId="add-mapping-button" (clickEmitter)="formService.addMapping()"> + <ods-plus-icon icon class="fill-whitetext" /> </ods-button> <div class="mt-4 flex gap-4"> - <ods-button text="Speichern" dataTestId="save-statistik-fields-button"></ods-button> - <ods-button text="Abbrechen" variant="outline" (clickEmitter)="onCancel()" dataTestId="cancel-statistik-fields-button"> - <ods-close-icon icon class="fill-primary"/> - </ods-button> + <admin-save-button /> + <admin-cancel-button [linkPath]="Routes.STATISTIK" /> </div> </div> diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component.spec.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component.spec.ts index 54502497cd68edcdec0876e2aad378126c2c28e3..a0154fd3137315cfbfd12187d70f0ffb43635df5 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component.spec.ts +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component.spec.ts @@ -1,86 +1,75 @@ -import { ROUTES } from '@admin-client/shared'; -import { NavigationService } from '@alfa-client/navigation-shared'; -import { existsAsHtmlElement, getElementComponentFromFixtureByCss, mock, Mock, triggerEvent } from '@alfa-client/test-utils'; +import { ADMIN_FORMSERVICE } from '@admin-client/shared'; +import { EMPTY_STRING } from '@alfa-client/tech-shared'; +import { dispatchEventFromFixture, existsAsHtmlElement, mock, Mock, MockEvent } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormBuilder } from '@angular/forms'; -import { TextInputComponent } from '@ods/system'; +import { FormBuilder, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { TextEditorComponent } from '@ods/component'; +import { ButtonComponent, PlusIconComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; import { getDataTestIdAttributeOf, getDataTestIdOf } from '../../../../../tech-shared/test/data-test'; +import { AdminCancelButtonComponent } from '../../../../shared/src/lib/admin-cancel-button/admin-cancel-button.component'; +import { AdminSaveButtonComponent } from '../../../../shared/src/lib/admin-save-button/admin-save-button.component'; import { AdminStatistikFieldsFormComponent } from './admin-statistik-fields-form.component'; +import { AdminStatistikFieldsFormMappingComponent } from './statistik-fields-form-mapping/statistik-fields-form-mapping.component'; import { StatistikFieldsFormService } from './statistik-fields.formservice'; describe('AdminStatistikFieldsFormComponent', () => { let component: AdminStatistikFieldsFormComponent; let fixture: ComponentFixture<AdminStatistikFieldsFormComponent>; - const formEngineInputTestId: string = getDataTestIdOf('form-engine-input'); + const formEngineNameInputTestId: string = getDataTestIdOf('form-engine-name-input'); const formIdInputTestId: string = getDataTestIdOf('form-id-input'); - const addDataFieldButtonTestId: string = getDataTestIdAttributeOf('add-data-field-button'); - const saveButtonTestId: string = getDataTestIdAttributeOf('save-statistik-fields-button'); - const cancelButtonTestId: string = getDataTestIdAttributeOf('cancel-statistik-fields-button'); - const dataField1TestId: string = getDataTestIdOf('data-statistik-field-0'); + const addMappingButton: string = getDataTestIdAttributeOf('add-mapping-button'); - let formService: StatistikFieldsFormService; - let navigationService: Mock<NavigationService>; + const formBuilder: FormBuilder = new FormBuilder(); - beforeEach(() => { - formService = new StatistikFieldsFormService(new FormBuilder()); - navigationService = mock(NavigationService); - }); + let formService: Mock<StatistikFieldsFormService>; beforeEach(async () => { - TestBed.overrideComponent(AdminStatistikFieldsFormComponent, { - set: { - providers: [ - { - provide: StatistikFieldsFormService, - useValue: formService, - }, - { - provide: NavigationService, - useValue: navigationService, - }, - ], - }, + const form: FormGroup = formBuilder.group({ + [StatistikFieldsFormService.FIELD_FORM_IDENTIFIER]: formBuilder.group({ + [StatistikFieldsFormService.FIELD_FORM_ENGINE_NAME]: new FormControl(EMPTY_STRING), + [StatistikFieldsFormService.FIELD_FORM_ID]: new FormControl(EMPTY_STRING), + }), }); + formService = <any>{ ...mock(StatistikFieldsFormService), form }; + await TestBed.configureTestingModule({ - imports: [AdminStatistikFieldsFormComponent], - providers: [{ provide: StatistikFieldsFormService, useValue: formService }], - }).compileComponents(); + declarations: [ + AdminStatistikFieldsFormComponent, + MockComponent(TextEditorComponent), + MockComponent(ButtonComponent), + MockComponent(PlusIconComponent), + MockComponent(AdminSaveButtonComponent), + MockComponent(AdminCancelButtonComponent), + MockComponent(AdminStatistikFieldsFormMappingComponent), + ], + imports: [ReactiveFormsModule], + }) + .overrideComponent(AdminStatistikFieldsFormComponent, { + set: { + providers: [ + { + provide: StatistikFieldsFormService, + useValue: formService, + }, + { + provide: ADMIN_FORMSERVICE, + useValue: formService, + }, + ], + }, + }) + .compileComponents(); fixture = TestBed.createComponent(AdminStatistikFieldsFormComponent); component = fixture.componentInstance; fixture.detectChanges(); }); - describe('component', () => { - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should set form controls', () => { - expect(component.formEngineFormControl).toBeDefined(); - expect(component.formIdFormControl).toBeDefined(); - expect(component.dataFieldsFormControls).toBeDefined(); - }); - - describe('addDataField', () => { - it('should call form service', () => { - formService.addDataField = jest.fn(); - - component.addDataField(); - - expect(formService.addDataField).toHaveBeenCalled(); - }); - }); - - describe('onCancel', () => { - it('should call navigation service', () => { - component.onCancel(); - - expect(navigationService.navigate).toHaveBeenCalledWith(ROUTES.STATISTIK); - }); - }); + it('should create', () => { + expect(component).toBeTruthy(); }); describe('template', () => { @@ -88,18 +77,7 @@ describe('AdminStatistikFieldsFormComponent', () => { it('should exists', () => { fixture.detectChanges(); - existsAsHtmlElement(fixture, formEngineInputTestId); - }); - - it('should have been called with inputs', () => { - fixture.detectChanges(); - - const formEngineInput: TextInputComponent = getElementComponentFromFixtureByCss<TextInputComponent>( - fixture, - formEngineInputTestId, - ); - - expect(formEngineInput.fieldControl).toEqual(component.formEngineFormControl); + existsAsHtmlElement(fixture, formEngineNameInputTestId); }); }); @@ -109,91 +87,23 @@ describe('AdminStatistikFieldsFormComponent', () => { existsAsHtmlElement(fixture, formIdInputTestId); }); - - it('should have been called with inputs', () => { - fixture.detectChanges(); - - const formIdInput: TextInputComponent = getElementComponentFromFixtureByCss<TextInputComponent>( - fixture, - formIdInputTestId, - ); - - expect(formIdInput.fieldControl).toEqual(component.formIdFormControl); - }); - }); - - describe('data field input', () => { - it('should exists', () => { - fixture.detectChanges(); - - existsAsHtmlElement(fixture, dataField1TestId); - }); - - it('should have been called with inputs', () => { - fixture.detectChanges(); - - const dataFieldInput: TextInputComponent = getElementComponentFromFixtureByCss<TextInputComponent>( - fixture, - dataField1TestId, - ); - - expect(dataFieldInput.fieldControl).toEqual(component.dataFieldsFormControls[0]); - }); - }); - - describe('add data field button', () => { - it('should exists', () => { - fixture.detectChanges(); - - existsAsHtmlElement(fixture, addDataFieldButtonTestId); - }); - - describe('output', () => { - describe('clickEmitter', () => { - it('should call handler', () => { - fixture.detectChanges(); - component.addDataField = jest.fn(); - - triggerEvent({ - fixture, - elementSelector: addDataFieldButtonTestId, - name: 'clickEmitter', - }); - - expect(component.addDataField).toHaveBeenCalled(); - }); - }); - }); - }); - - describe('save button', () => { - it('should exists', () => { - fixture.detectChanges(); - - existsAsHtmlElement(fixture, saveButtonTestId); - }); }); - describe('cancel button', () => { + describe('add mapping button', () => { it('should exists', () => { fixture.detectChanges(); - existsAsHtmlElement(fixture, cancelButtonTestId); + existsAsHtmlElement(fixture, addMappingButton); }); describe('output', () => { describe('clickEmitter', () => { - it('should call handler', () => { - component.onCancel = jest.fn(); + it('should call formService', () => { fixture.detectChanges(); - triggerEvent({ - fixture, - elementSelector: cancelButtonTestId, - name: 'clickEmitter', - }); + dispatchEventFromFixture(fixture, addMappingButton, MockEvent.CLICK); - expect(component.onCancel).toHaveBeenCalled(); + expect(formService.addMapping).toHaveBeenCalled(); }); }); }); diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component.ts index 59d083f34a2f5f727734c29c02f6b8de13c7d2d6..0298196202e623a3d080468c792f3c1c800a8750 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component.ts +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/admin-statistik-fields-form.component.ts @@ -1,37 +1,30 @@ -import { ROUTES } from '@admin-client/shared'; -import { NavigationService } from '@alfa-client/navigation-shared'; -import { CommonModule } from '@angular/common'; +import { ADMIN_FORMSERVICE, AdminCancelButtonComponent, AdminSaveButtonComponent, ROUTES } from '@admin-client/shared'; import { Component, inject } from '@angular/core'; -import { FormArray, FormControl, ReactiveFormsModule } from '@angular/forms'; -import { ButtonComponent, CloseIconComponent, PlusIconComponent, TextInputComponent } from '@ods/system'; +import { ReactiveFormsModule } from '@angular/forms'; +import { TextEditorComponent } from '@ods/component'; +import { ButtonComponent, DeleteIconComponent, PlusIconComponent } from '@ods/system'; +import { AdminStatistikFieldsFormMappingComponent } from './statistik-fields-form-mapping/statistik-fields-form-mapping.component'; import { StatistikFieldsFormService } from './statistik-fields.formservice'; @Component({ selector: 'admin-statistik-fields-form', - standalone: true, - imports: [CommonModule, TextInputComponent, ButtonComponent, CloseIconComponent, ReactiveFormsModule, PlusIconComponent], - providers: [StatistikFieldsFormService], templateUrl: './admin-statistik-fields-form.component.html', + standalone: true, + imports: [ + ButtonComponent, + PlusIconComponent, + ReactiveFormsModule, + TextEditorComponent, + DeleteIconComponent, + AdminSaveButtonComponent, + AdminCancelButtonComponent, + AdminStatistikFieldsFormMappingComponent, + ], + providers: [{ provide: ADMIN_FORMSERVICE, useClass: StatistikFieldsFormService }], }) export class AdminStatistikFieldsFormComponent { - private readonly formService = inject(StatistikFieldsFormService); - private readonly navigationService = inject(NavigationService); - - public readonly formEngineFormControl: FormControl = this.formService.form.controls[ - StatistikFieldsFormService.FIELD_FORM_ENGINE - ] as FormControl; - public readonly formIdFormControl: FormControl = this.formService.form.controls[ - StatistikFieldsFormService.FIELD_FORM_ID - ] as FormControl; - public readonly dataFieldsFormControls: FormControl[] = ( - this.formService.form.controls[StatistikFieldsFormService.FIELD_DATA_FIELDS] as FormArray - ).controls as FormControl[]; - - public addDataField(): void { - this.formService.addDataField(); - } + public readonly formService = <StatistikFieldsFormService>inject(ADMIN_FORMSERVICE); - public onCancel(): void { - this.navigationService.navigate(ROUTES.STATISTIK); - } + public readonly StatistikFieldsFormService = StatistikFieldsFormService; + public readonly Routes = ROUTES; } diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form-mapping/statistik-fields-form-mapping.component.html b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form-mapping/statistik-fields-form-mapping.component.html new file mode 100644 index 0000000000000000000000000000000000000000..2ce86b545b1039b795911cf172f154b9e2b97871 --- /dev/null +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form-mapping/statistik-fields-form-mapping.component.html @@ -0,0 +1,27 @@ +<form [formGroup]="formService.form"> + <div class="flex flex-col gap-4" [formArrayName]="StatistikFieldsFormService.FIELD_MAPPINGS"> + <div + *ngFor="let mappingControl of formService.mappings.controls; let i = index" + [formGroupName]="i" + class="flex w-full gap-2" + > + <ods-text-editor + class="flex-1" + formControlName="sourcePath" + label="Pfad des Datenfeldes" + placeholder="Tragen Sie hier den gesamten Pfad des Datenfeldes ein, das Sie auswerten möchten." + [attr.data-test-id]="'mapping-field-' + i" + ></ods-text-editor> + <ods-button + class="self-end" + variant="ghost" + size="fit" + destructive="true" + (clickEmitter)="formService.removeMapping(i)" + [dataTestId]="'remove-mapping-button-' + i" + > + <ods-delete-icon icon /> + </ods-button> + </div> + </div> +</form> diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form-mapping/statistik-fields-form-mapping.component.spec.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form-mapping/statistik-fields-form-mapping.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..61cd006e429951cde3657be7688b30063cc2e6eb --- /dev/null +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form-mapping/statistik-fields-form-mapping.component.spec.ts @@ -0,0 +1,90 @@ +import { ADMIN_FORMSERVICE } from '@admin-client/shared'; +import { EMPTY_STRING } from '@alfa-client/tech-shared'; +import { dispatchEventFromFixture, existsAsHtmlElement, mock, Mock, MockEvent, mockGetValue } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormBuilder, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { TextEditorComponent } from '@ods/component'; +import { ButtonComponent, DeleteIconComponent } from '@ods/system'; +import { getDataTestIdOf, getDynamicDataTestIdAttributOf } from 'libs/tech-shared/test/data-test'; +import { MockComponent } from 'ng-mocks'; +import { StatistikFieldsFormService } from '../statistik-fields.formservice'; +import { AdminStatistikFieldsFormMappingComponent } from './statistik-fields-form-mapping.component'; + +describe('AdminStatistikFieldsFormMappingComponent', () => { + let component: AdminStatistikFieldsFormMappingComponent; + let fixture: ComponentFixture<AdminStatistikFieldsFormMappingComponent>; + + const mappingField: string = getDataTestIdOf('mapping-field-0'); + const removeMappingButton: string = getDynamicDataTestIdAttributOf('remove-mapping-button-0'); + + const formBuilder: FormBuilder = new FormBuilder(); + + let formService: Mock<StatistikFieldsFormService>; + + beforeEach(async () => { + const form: FormGroup = formBuilder.group({ + [StatistikFieldsFormService.FIELD_MAPPINGS]: formBuilder.array([ + new FormGroup({ sourcePath: new FormControl(EMPTY_STRING) }), + ]), + }); + + formService = <any>{ + ...mock(StatistikFieldsFormService), + form, + addMapping: jest.fn(), + removeMapping: jest.fn(), + }; + + mockGetValue( + formService, + StatistikFieldsFormService.FIELD_MAPPINGS, + form.controls[StatistikFieldsFormService.FIELD_MAPPINGS], + ); + + await TestBed.configureTestingModule({ + declarations: [ + AdminStatistikFieldsFormMappingComponent, + MockComponent(TextEditorComponent), + MockComponent(ButtonComponent), + MockComponent(DeleteIconComponent), + ], + imports: [ReactiveFormsModule], + providers: [ + { + provide: StatistikFieldsFormService, + useValue: formService, + }, + { + provide: ADMIN_FORMSERVICE, + useValue: formService, + }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(AdminStatistikFieldsFormMappingComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('template', () => { + describe('mapping input', () => { + it('should exists', () => { + fixture.detectChanges(); + + existsAsHtmlElement(fixture, mappingField); + }); + }); + + describe('remove mapping button', () => { + it('should call formservice', () => { + dispatchEventFromFixture(fixture, removeMappingButton, MockEvent.CLICK); + + expect(formService.removeMapping).toHaveBeenCalledWith(0); + }); + }); + }); +}); diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form-mapping/statistik-fields-form-mapping.component.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form-mapping/statistik-fields-form-mapping.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..48bc3eaddd2a2fe51b983939dd8920b02e7f8dae --- /dev/null +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form-mapping/statistik-fields-form-mapping.component.ts @@ -0,0 +1,29 @@ +import { ADMIN_FORMSERVICE, AdminCancelButtonComponent, AdminSaveButtonComponent, ROUTES } from '@admin-client/shared'; +import { CommonModule } from '@angular/common'; +import { Component, inject } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { TextEditorComponent } from '@ods/component'; +import { ButtonComponent, DeleteIconComponent, PlusIconComponent } from '@ods/system'; +import { StatistikFieldsFormService } from '../statistik-fields.formservice'; + +@Component({ + selector: 'statistik-fields-form-mapping', + templateUrl: './statistik-fields-form-mapping.component.html', + standalone: true, + imports: [ + CommonModule, + ButtonComponent, + PlusIconComponent, + ReactiveFormsModule, + TextEditorComponent, + DeleteIconComponent, + AdminSaveButtonComponent, + AdminCancelButtonComponent, + ], +}) +export class AdminStatistikFieldsFormMappingComponent { + public readonly formService = <StatistikFieldsFormService>inject(ADMIN_FORMSERVICE); + + public readonly StatistikFieldsFormService = StatistikFieldsFormService; + public readonly Routes = ROUTES; +} diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.spec.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..58a2273cb692762c4f930e583c8c49f210099517 --- /dev/null +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.spec.ts @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { AggregationMappingResource, AggregationMappingService } from '@admin-client/reporting-shared'; +import { EMPTY_STRING, StateResource, createStateResource } from '@alfa-client/tech-shared'; +import { Mock, mock } from '@alfa-client/test-utils'; +import { TestBed } from '@angular/core/testing'; +import { FormArray, FormControl, FormGroup } from '@angular/forms'; +import { createAggregationMapping, createAggregationMappingResource } from 'libs/admin/reporting-shared/test/aggregation-mapping'; +import { of } from 'rxjs'; +import { StatistikFieldsFormService } from './statistik-fields.formservice'; + +describe('StatistikFieldsFormService', () => { + let formService: StatistikFieldsFormService; + + let service: Mock<AggregationMappingService>; + + beforeEach(() => { + service = mock(AggregationMappingService); + + TestBed.configureTestingModule({ + providers: [StatistikFieldsFormService, { provide: AggregationMappingService, useValue: service }], + }); + + formService = TestBed.inject(StatistikFieldsFormService); + }); + + it('should create', () => { + expect(formService).toBeTruthy(); + }); + + describe('on do submit', () => { + const stateResource: StateResource<AggregationMappingResource> = createStateResource(createAggregationMappingResource()); + + beforeEach(() => { + service.create.mockReturnValue(of(stateResource)); + }); + + it('should call service', () => { + formService.form = <any>createAggregationMapping(); + + formService.submit(); + + expect(service.create).toHaveBeenCalledWith(formService.form.value); + }); + }); + + describe('add mapping', () => { + it('should add mapping control', () => { + formService.addMapping(); + + const mappingFormArray: FormArray = <FormArray>formService.form.controls[StatistikFieldsFormService.FIELD_MAPPINGS]; + expect(mappingFormArray).toHaveLength(2); + expect(mappingFormArray.controls[0].value).toEqual({ sourcePath: EMPTY_STRING }); + }); + }); + + describe('remove mapping', () => { + it('should remove mapping control', () => { + (<FormArray>formService.form.controls[StatistikFieldsFormService.FIELD_MAPPINGS]).push( + new FormGroup({ sourcePath: new FormControl('controlToRemove') }), + ); + + formService.removeMapping(1); + + const mappingFormArray: FormArray = <FormArray>formService.form.controls[StatistikFieldsFormService.FIELD_MAPPINGS]; + expect(mappingFormArray).toHaveLength(1); + expect(mappingFormArray.controls[0].value).toEqual({ sourcePath: EMPTY_STRING }); + }); + }); + + describe('get mappings', () => { + it('should return mappings as array', () => { + const mappings: FormArray = formService.mappings; + + expect(mappings).toHaveLength(1); + expect(mappings.controls[0].value).toEqual({ sourcePath: EMPTY_STRING }); + }); + }); +}); diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.ts index 229a7147d1b785c937d46c45c3ae65070a8b2608..1b746e12f42b44cc1261ce6de543380ea61d9ec4 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.ts +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.ts @@ -1,32 +1,50 @@ +import { AggregationMappingResource, AggregationMappingService } from '@admin-client/reporting-shared'; import { AbstractFormService, EMPTY_STRING, StateResource } from '@alfa-client/tech-shared'; -import { Injectable } from '@angular/core'; -import { FormArray, FormControl, UntypedFormGroup } from '@angular/forms'; -import { Resource } from '@ngxp/rest'; -import { EMPTY, Observable } from 'rxjs'; +import { inject, Injectable } from '@angular/core'; +import { FormArray, FormControl, FormGroup, UntypedFormGroup } from '@angular/forms'; +import { Observable } from 'rxjs'; @Injectable() -export class StatistikFieldsFormService extends AbstractFormService<Resource> { - public static readonly FIELD_FORM_ENGINE: string = 'formEngine'; +export class StatistikFieldsFormService extends AbstractFormService<AggregationMappingResource> { + private service = inject(AggregationMappingService); + + public static readonly FIELD_FORM_IDENTIFIER: string = 'formIdentifier'; + public static readonly FIELD_FORM_ENGINE_NAME: string = 'formEngineName'; public static readonly FIELD_FORM_ID: string = 'formId'; - public static readonly FIELD_DATA_FIELDS: string = 'dataFields'; + + public static readonly FIELD_MAPPINGS: string = 'mappings'; protected initForm(): UntypedFormGroup { return this.formBuilder.group({ - [StatistikFieldsFormService.FIELD_FORM_ENGINE]: new FormControl(EMPTY_STRING), - [StatistikFieldsFormService.FIELD_FORM_ID]: new FormControl(EMPTY_STRING), - [StatistikFieldsFormService.FIELD_DATA_FIELDS]: new FormArray([new FormControl(EMPTY_STRING)]), + [StatistikFieldsFormService.FIELD_FORM_IDENTIFIER]: this.formBuilder.group({ + [StatistikFieldsFormService.FIELD_FORM_ENGINE_NAME]: new FormControl(EMPTY_STRING), + [StatistikFieldsFormService.FIELD_FORM_ID]: new FormControl(EMPTY_STRING), + }), + [StatistikFieldsFormService.FIELD_MAPPINGS]: new FormArray([this.createArrayControl()]), }); } - protected doSubmit(): Observable<StateResource<Resource>> { - return EMPTY; + protected doSubmit(): Observable<StateResource<AggregationMappingResource>> { + return this.service.create(this.getFormValue()); } protected getPathPrefix(): string { return 'settingBody'; } - public addDataField(): void { - (this.form.controls[StatistikFieldsFormService.FIELD_DATA_FIELDS] as FormArray).push(new FormControl(EMPTY_STRING)); + public addMapping(): void { + this.mappings.push(this.createArrayControl()); + } + + private createArrayControl(): FormGroup { + return new FormGroup({ sourcePath: new FormControl(EMPTY_STRING) }); + } + + public removeMapping(index: number): void { + this.mappings.removeAt(index); + } + + public get mappings(): FormArray { + return this.form.controls[StatistikFieldsFormService.FIELD_MAPPINGS] as FormArray; } } diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts index 92031a721d4ebb9e879f75308b003848c82d6cc0..8e823be03c1f064fe2cd152da724bb3e0fcdc001 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts @@ -438,7 +438,7 @@ describe('UserFormService', () => { }); it('should return bauamt group when active', () => { - const organisationsEinheit: AdminOrganisationsEinheit = { name: 'bauamt' }; + const organisationsEinheit: AdminOrganisationsEinheit = createAdminOrganisationsEinheit(); organisationsEinheitenGroup.addControl(organisationsEinheit.name, new FormControl(true)); const result: string[] = formService._getActiveOrganisationsEinheiten(); diff --git a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user-list.component.html b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user-list.component.html index bffb14da6bda5e9ae083f25f445a12b3d6854ae5..153e3e19deecd0653b83ae9fc7e516f85b6a8716 100644 --- a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user-list.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user-list.component.html @@ -24,9 +24,9 @@ --> <h1 class="heading-1 mb-4">Benutzer & Rollen</h1> -<ods-routing-button [linkPath]="ROUTES.BENUTZER_NEU" text="Benutzer hinzufügen" class="mb-4" dataTestId="add-user-button" /> +<ods-routing-button [linkPath]="ROUTES.BENUTZER_NEU" text="Benutzer hinzufügen" class="mb-4 w-fit" dataTestId="add-user-button" /> <ods-list> @for (user of usersStateResource.resource; track $index) { <admin-user [user]="user" class="block w-full" /> } -</ods-list> \ No newline at end of file +</ods-list> diff --git a/alfa-client/libs/authentication/src/lib/http-unauthorized.interceptor.spec.ts b/alfa-client/libs/authentication/src/lib/http-unauthorized.interceptor.spec.ts index bf426ac9299c13c5440929e9b54d276e35f6be8e..8e32931929aab5f151b00cc4b14b3aaacc5c9142 100644 --- a/alfa-client/libs/authentication/src/lib/http-unauthorized.interceptor.spec.ts +++ b/alfa-client/libs/authentication/src/lib/http-unauthorized.interceptor.spec.ts @@ -22,12 +22,12 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Mock, mock } from '@alfa-client/test-utils'; +import { HttpErrorResponse, HttpHandler, HttpRequest } from '@angular/common/http'; import { TestBed } from '@angular/core/testing'; import { MatDialogModule } from '@angular/material/dialog'; -import { HttpUnauthorizedInterceptor } from './http-unauthorized.interceptor'; -import { HttpErrorResponse, HttpHandler, HttpRequest } from '@angular/common/http'; import { Subject, isEmpty } from 'rxjs'; import { AuthenticationService } from './authentication.service'; +import { HttpUnauthorizedInterceptor } from './http-unauthorized.interceptor'; describe('HttpUnauthorizedInterceptor', () => { let interceptor: HttpUnauthorizedInterceptor; @@ -96,7 +96,7 @@ describe('HttpUnauthorizedInterceptor', () => { it('should rethrow error if not unauthorized status', () => { const anyError: any = new HttpErrorResponse({ status: 500 }); - expect(() => interceptor.handleError(anyError)).toThrowError(); + expect(() => interceptor.handleError(anyError)).toThrow(); }); }); }); diff --git a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.spec.ts index 5a6c54ccfacecba703c2c89e30cc7fac777ec114..35a608b28271ff395579092f156f23ad0fc1f445 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.spec.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.spec.ts @@ -22,10 +22,10 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { CommandOrder, CommandResource } from '@alfa-client/command-shared'; -import { ApiError } from '@alfa-client/tech-shared'; +import { ApiError, createEmptyStateResource } from '@alfa-client/tech-shared'; import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { Action } from '@ngrx/store'; -import { createCommandResource } from 'libs/command-shared/test/command'; +import { createCommandResource, createSuccessfullyDoneCommandStateResource } from 'libs/command-shared/test/command'; import { createApiError } from 'libs/tech-shared/test/error'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; import { BescheidState, initialState, reducer } from './bescheid.reducer'; @@ -55,7 +55,21 @@ describe('Bescheid Reducer', () => { const state: BescheidState = reducer(initialState, action); - expect(state.bescheidCommand.loading).toBeTruthy(); + expect(state.bescheidCommand).toEqual(createEmptyStateResource(true)); + }); + + it('should replace state resource with loading', () => { + const initialState: BescheidState = { bescheidCommand: createSuccessfullyDoneCommandStateResource() }; + const resource: VorgangWithEingangResource = createVorgangWithEingangResource(); + const action: Action = CommandActions.createCommand({ + resource, + linkRel: VorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT, + command: { ...createCommandResource(), order: CommandOrder.CREATE_BESCHEID }, + }); + + const state: BescheidState = reducer(initialState, action); + + expect(state.bescheidCommand).toEqual(createEmptyStateResource(true)); }); }); diff --git a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.ts b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.ts index 0e804a1d07360070a1b3eaab5411a9c841c0e473..870d54c9df087e333cb44249f93ab9f133562396 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.ts @@ -21,19 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - CommandProps, - CommandResource, - CreateCommandFailureProps, - CreateCommandProps, -} from '@alfa-client/command-shared'; -import { - ApiError, - StateResource, - createEmptyStateResource, - createErrorStateResource, - createStateResource, -} from '@alfa-client/tech-shared'; +import { CommandProps, CommandResource, CreateCommandFailureProps, CreateCommandProps } from '@alfa-client/command-shared'; +import { ApiError, createEmptyStateResource, createErrorStateResource, createStateResource, StateResource, } from '@alfa-client/tech-shared'; import { HttpErrorResponse } from '@angular/common/http'; import { Action, ActionReducer, createReducer, on } from '@ngrx/store'; import { isCreateBescheidCommand } from '../bescheid.util'; @@ -56,35 +45,22 @@ export const initialState: BescheidState = { const bescheidReducer: ActionReducer<BescheidState, Action> = createReducer( initialState, - on( - CommandActions.createCommand, - (state: BescheidState, props: CreateCommandProps): BescheidState => { - return isCreateBescheidCommand(props.command.order) ? - { ...state, bescheidCommand: { ...state.bescheidCommand, loading: true } } - : state; - }, - ), - on( - CommandActions.createCommandSuccess, - (state: BescheidState, props: CommandProps): BescheidState => { - return isCreateBescheidCommand(props.command.order) ? - { ...state, bescheidCommand: createStateResource(props.command) } - : state; - }, - ), - on( - CommandActions.createCommandFailure, - (state: BescheidState, props: CreateCommandFailureProps): BescheidState => { - return isCreateBescheidCommand(props.command.order) ? - { - ...state, - bescheidCommand: createErrorStateResource( - <ApiError>(<HttpErrorResponse>props.error).error, - ), - } - : state; - }, - ), + on(CommandActions.createCommand, (state: BescheidState, props: CreateCommandProps): BescheidState => { + return isCreateBescheidCommand(props.command.order) ? { ...state, bescheidCommand: createEmptyStateResource(true) } : state; + }), + on(CommandActions.createCommandSuccess, (state: BescheidState, props: CommandProps): BescheidState => { + return isCreateBescheidCommand(props.command.order) ? + { ...state, bescheidCommand: createStateResource(props.command) } + : state; + }), + on(CommandActions.createCommandFailure, (state: BescheidState, props: CreateCommandFailureProps): BescheidState => { + return isCreateBescheidCommand(props.command.order) ? + { + ...state, + bescheidCommand: createErrorStateResource(<ApiError>(<HttpErrorResponse>props.error).error), + } + : state; + }), ); export function reducer(state: BescheidState, action: Action): BescheidState { diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid-resource-service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid-resource-service.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab266d7734797b1e6fdf8b845ba8793696893a8e --- /dev/null +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid-resource-service.ts @@ -0,0 +1,25 @@ +import { CommandOrder, CommandResourceService, CommandService } from '@alfa-client/command-shared'; +import { ResourceRepository, ResourceServiceConfig } from '@alfa-client/tech-shared'; +import { VorgangService, VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { BescheidLinkRel } from './bescheid.linkrel'; +import { BescheidResource } from './bescheid.model'; + +export class BescheidResourceService extends CommandResourceService<VorgangWithEingangResource, BescheidResource> {} + +export function createBescheidResourceService( + repository: ResourceRepository, + commandService: CommandService, + vorgangService: VorgangService, +): CommandResourceService<VorgangWithEingangResource, BescheidResource> { + console.info('Create Bescheid Resource Service'); + return new CommandResourceService(buildConfig(vorgangService), repository, commandService); +} + +function buildConfig(vorgangService: VorgangService): ResourceServiceConfig<VorgangWithEingangResource> { + return { + resource: vorgangService.getVorgangWithEingang(), + getLinkRel: VorgangWithEingangLinkRel.BESCHEID_DRAFT, + delete: { linkRel: BescheidLinkRel.DELETE, order: CommandOrder.DELETE_BESCHEID }, + edit: { linkRel: BescheidLinkRel.UPDATE, order: CommandOrder.UPDATE_BESCHEID }, + }; +} diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.model.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.model.ts index b661c130f51fb8e2e2239a68a525b6f25d24c598..6fee5ec006a52da9172c6491cc0bf38c4a0ba0df 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.model.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.model.ts @@ -21,8 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { HttpError, ListResource } from '@alfa-client/tech-shared'; -import { Resource } from '@ngxp/rest'; +import { BinaryFileResource } from '@alfa-client/binary-file-shared'; +import { CommandResource } from '@alfa-client/command-shared'; +import { createEmptyStateResource, HttpError, ListResource, StateResource } from '@alfa-client/tech-shared'; +import { Resource, ResourceUri } from '@ngxp/rest'; export enum BescheidStatus { DRAFT = 'DRAFT', @@ -64,3 +66,55 @@ export enum BescheidWizardStep { export interface BescheidWizardDialogResult { reloadVorgang: boolean; } + +export interface BescheidDocument { + upload: UploadFileInProgress; + create: StateResource<CommandResource>; + documentUri?: ResourceUri; + resource?: BinaryFileResource; +} + +export function createEmptyBescheidDocument(): BescheidDocument { + return { + upload: createEmptyUploadInProgress(), + create: createEmptyStateResource(), + }; +} + +export interface BescheidAttachments { + upload: UploadFileInProgress; + uploadStateResource: StateResource<BinaryFileResource>; + items: BinaryFileResource[]; +} + +export function createEmptyBescheidAttachments(): BescheidAttachments { + return { + upload: createEmptyUploadInProgress(), + uploadStateResource: createEmptyStateResource(), + items: [], + }; +} + +export function createEmptyUploadInProgress(): UploadFileInProgress { + return { + loading: false, + fileName: null, + }; +} + +export interface Wizard { + activeStep: BescheidWizardStep; + sendBy: BescheidSendBy; + canBeSend: boolean; + bescheidCreated: boolean; + empfaenger?: string; +} + +export function createInitialWizard(): Wizard { + return { + activeStep: BescheidWizardStep.AntragBescheiden, + sendBy: BescheidSendBy.NACHRICHT, + canBeSend: true, + bescheidCreated: false, + }; +} diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts index d799453d615d41bd0e21b7940461d59c7131adf0..ab845cf6b4f7e3156ebb7a940e418780e9a410d2 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts @@ -23,6 +23,7 @@ */ import { BinaryFileListResource, BinaryFileResource, BinaryFileService } from '@alfa-client/binary-file-shared'; import { CommandOrder, CommandResource, CommandService, CreateCommandProps } from '@alfa-client/command-shared'; +import { PostfachService } from '@alfa-client/postfach-shared'; import { ApiError, EMPTY_ARRAY, @@ -80,7 +81,6 @@ import { BescheidService } from './bescheid.service'; import { DocumentLinkRel } from './document.linkrel'; import { DocumentResource } from './document.model'; -import { PostfachService } from '@alfa-client/postfach-shared'; import * as DateUtil from '../../../tech-shared/src/lib/date.util'; import * as BescheidUtil from './bescheid.util'; @@ -89,7 +89,7 @@ describe('BescheidService', () => { let facade: Mock<BescheidFacade>; let vorgangService: Mock<VorgangService>; - let resourceRepository: Mock<ResourceRepository>; + let resourceRepository: Mock<ResourceRepository<BescheidResource>>; let commandService: Mock<CommandService>; let vorgangCommandService: Mock<VorgangCommandService>; let binaryFileService: Mock<BinaryFileService>; diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts index 3426c36b0868b332b4324580b8eadf6fcbab37f0..7b8a2f737d688302a3a9f30e218b126a9fad285e 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts @@ -124,7 +124,7 @@ export class BescheidService { private readonly commandService: CommandService, private readonly vorgangCommandService: VorgangCommandService, private readonly binaryFileService: BinaryFileService, - private readonly repository: ResourceRepository, + private readonly repository: ResourceRepository<BescheidResource>, private readonly postfachService: PostfachService, ) { this.bescheidResourceService = new CommandResourceService( @@ -132,7 +132,11 @@ export class BescheidService { repository, this.commandService, ); - this.bescheidListResourceService = new ResourceListService(this.buildBescheidListServiceConfig(), repository); + this.bescheidListResourceService = new ResourceListService< + VorgangWithEingangResource, + BescheidListResource, + BescheidResource + >(this.buildBescheidListServiceConfig(), repository); } public getActiveStep(): Observable<BescheidWizardStep> { diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..977ca30abc3c3200416749391b488b397e75731c --- /dev/null +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.spec.ts @@ -0,0 +1,975 @@ +/* + * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { BinaryFileListLinkRel, BinaryFileListResource, BinaryFileResource, BinaryFileService, } from '@alfa-client/binary-file-shared'; +import { CommandOrder, CommandResource, CommandResourceService, CommandService, CreateCommandProps, getEffectedResourceUrl, } from '@alfa-client/command-shared'; +import { PostfachService } from '@alfa-client/postfach-shared'; +import { createEmptyStateResource, createErrorStateResource, createLoadingStateResource, createStateResource, EMPTY_STRING, getEmbeddedResources, StateResource, } from '@alfa-client/tech-shared'; +import { Mock, mock } from '@alfa-client/test-utils'; +import { VorgangCommandService, VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { TestBed } from '@angular/core/testing'; +import { faker } from '@faker-js/faker'; +import { getUrl, LinkRel, ResourceUri } from '@ngxp/rest'; +import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel'; +import { createProblemDetail } from 'libs/tech-shared/test/error'; +import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; +import { EMPTY, Observable, of } from 'rxjs'; +import { createBinaryFileListResource, createBinaryFileResource } from '../../../binary-file-shared/test/binary-file'; +import { createCommandErrorStateResource, createCommandResource, createCommandStateResource, createCreateCommandProps, createSuccessfullyDoneCommandStateResource, } from '../../../command-shared/test/command'; +import { ResourceRepository } from '../../../tech-shared/src/lib/resource/resource.repository'; +import { createFile } from '../../../tech-shared/test/file'; +import { singleCold, singleColdCompleted } from '../../../tech-shared/test/marbles'; +import { createBescheid, createBescheidAttachments, createBescheidDocument, createBescheidResource } from '../test/bescheid'; +import { createDocumentResource } from '../test/document'; +import { BescheidFacade } from './+state/bescheid.facade'; +import { BescheidResourceService } from './bescheid-resource-service'; +import { BescheidLinkRel } from './bescheid.linkrel'; +import { Bescheid, BescheidAttachments, BescheidDocument, BescheidResource, BescheidWizardStep, createEmptyBescheidAttachments, createEmptyBescheidDocument, createEmptyUploadInProgress, createInitialWizard, } from './bescheid.model'; +import { BescheidService2 } from './bescheid2.service'; +import { DocumentLinkRel } from './document.linkrel'; +import { DocumentResource } from './document.model'; + +import { expect } from '@jest/globals'; +import * as BescheidUtil from './bescheid.util'; + +describe('BescheidService', () => { + let service: BescheidService2; + + let facade: Mock<BescheidFacade>; + let vorgangService: Mock<VorgangService>; + let resourceRepository: Mock<ResourceRepository>; + let commandService: Mock<CommandService>; + let vorgangCommandService: Mock<VorgangCommandService>; + let binaryFileService: Mock<BinaryFileService>; + let postfachService: Mock<PostfachService>; + let bescheidResourceService: Mock<BescheidResourceService>; + + const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource(); + const vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource> = + createStateResource(vorgangWithEingangResource); + const bescheidResource: BescheidResource = createBescheidResource(); + const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); + + beforeEach(() => { + facade = mock(BescheidFacade); + resourceRepository = mock(ResourceRepository); + commandService = mock(CommandService); + vorgangCommandService = mock(VorgangCommandService); + vorgangService = mock(VorgangService); + vorgangService.getVorgangWithEingang.mockReturnValue(of(vorgangWithEingangStateResource)); + binaryFileService = mock(BinaryFileService); + postfachService = mock(PostfachService); + bescheidResourceService = mock(CommandResourceService); + + TestBed.configureTestingModule({ + providers: [ + { provide: BescheidFacade, useValue: facade }, + { provide: VorgangService, useValue: vorgangService }, + { provide: ResourceRepository, useValue: resourceRepository }, + { provide: CommandService, useValue: commandService }, + { provide: VorgangCommandService, useValue: vorgangCommandService }, + { provide: BinaryFileService, useValue: binaryFileService }, + { + provide: PostfachService, + useValue: postfachService, + }, + { provide: BescheidResourceService, useValue: bescheidResourceService }, + BescheidService2, + ], + }); + + service = TestBed.inject(BescheidService2); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + describe('init', () => { + it('should init state', () => { + service.setActiveStep(2); + + service.init(); + + expect(service.getWizard()).toBeObservable(singleCold(createInitialWizard())); + expect(service.getActiveStep()).toBeObservable(singleCold(BescheidWizardStep.AntragBescheiden)); + expect(service.getBescheidCreated()).toBeObservable(singleCold(false)); + expect(service.getBescheidDocument()).toBeObservable(singleCold(createEmptyBescheidDocument())); + expect(service.getAttachments()).toBeObservable(singleCold(createEmptyBescheidAttachments())); + }); + }); + + describe('exit', () => { + it('should reload postfach list', () => { + service.exit(); + + expect(postfachService.setPostfachMailOnReload).toHaveBeenCalled(); + }); + }); + + describe('skipBescheidCreation', () => { + beforeEach(() => { + service.deleteBescheidAndCompleteVorgang = jest.fn().mockReturnValue(of(commandStateResource)); + }); + + it('should complete vorgang', () => { + service.skipBescheidCreation(vorgangWithEingangResource, null); + + expect(vorgangCommandService.abschliessen).toHaveBeenCalledWith(vorgangWithEingangResource); + }); + + it('should NOT complete vorgang', () => { + service.skipBescheidCreation(vorgangWithEingangResource, bescheidResource); + + expect(vorgangCommandService.abschliessen).not.toHaveBeenCalled(); + }); + + it('should delete bescheid and complete vorgang', () => { + service.skipBescheidCreation(vorgangWithEingangResource, bescheidResource).subscribe(); + + expect(service.deleteBescheidAndCompleteVorgang).toHaveBeenCalledWith(vorgangWithEingangResource); + }); + + it('should return command', () => { + const command$: Observable<StateResource<CommandResource>> = service.skipBescheidCreation( + vorgangWithEingangResource, + bescheidResource, + ); + + expect(command$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + }); + + describe('deleteBescheidAndCompleteVorgang', () => { + beforeEach(() => { + service.deleteBescheid = jest.fn().mockReturnValue(of(createCommandStateResource)); + vorgangCommandService.abschliessen.mockReturnValue(EMPTY); + }); + + it('should complete vorgang', () => { + service.deleteBescheidAndCompleteVorgang(vorgangWithEingangResource).subscribe(); + + expect(vorgangCommandService.abschliessen).toHaveBeenCalledWith(vorgangWithEingangResource); + }); + + it('should delete bescheid', () => { + vorgangCommandService.abschliessen.mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + service.deleteBescheidAndCompleteVorgang(vorgangWithEingangResource).subscribe(); + + expect(service.deleteBescheid).toHaveBeenCalled(); + }); + + it('should NOT delete bescheid on loading', () => { + vorgangCommandService.abschliessen.mockReturnValue(of(createEmptyStateResource(true))); + + service.deleteBescheidAndCompleteVorgang(vorgangWithEingangResource).subscribe(); + + expect(service.deleteBescheid).not.toHaveBeenCalled(); + }); + + it('should NOT delete bescheid on error', () => { + vorgangCommandService.abschliessen.mockReturnValue(of(createErrorStateResource(createProblemDetail()))); + + service.deleteBescheidAndCompleteVorgang(vorgangWithEingangResource).subscribe(); + + expect(service.deleteBescheid).not.toHaveBeenCalled(); + }); + + it('should return vorgang abschliessen command', () => { + const command: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + vorgangCommandService.abschliessen.mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = + service.deleteBescheidAndCompleteVorgang(vorgangWithEingangResource); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + }); + + describe('delete bescheid', () => { + it('should create command', () => { + service.deleteBescheid(); + + expect(bescheidResourceService.delete).toHaveBeenCalled(); + }); + + it('should return command', () => { + const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + bescheidResourceService.delete.mockReturnValue(of(commandStateResource)); + + const createdCommand$: Observable<StateResource<CommandResource>> = service.deleteBescheid(); + + expect(createdCommand$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + }); + + describe('loadFiles', () => { + beforeEach(() => { + service.loadBescheidDocument = jest.fn(); + service.loadAttachments = jest.fn(); + }); + + it('should bescheid document', () => { + service.loadFiles(bescheidResource); + + expect(service.loadBescheidDocument).toHaveBeenCalledWith(bescheidResource); + }); + + it('should load attachments', () => { + service.loadFiles(bescheidResource); + + expect(service.loadAttachments).toHaveBeenCalledWith(bescheidResource); + }); + }); + + describe('create bescheid document', () => { + beforeEach(() => { + service.doCreateBescheidDocument = jest.fn().mockReturnValue(EMPTY); + service.handleCreateBescheidDocumentResponse = jest.fn(); + }); + + it('should emit bescheid document', () => { + service.createBescheidDocument(bescheidResource); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ ...createEmptyBescheidDocument(), create: createEmptyStateResource(true) }), + ); + }); + + it('should do create bescheid document', () => { + service.createBescheidDocument(bescheidResource); + + expect(service.doCreateBescheidDocument).toHaveBeenCalledWith(bescheidResource); + }); + + it('should handle create response on loaded', () => { + service.doCreateBescheidDocument = jest.fn().mockReturnValue(of(commandStateResource)); + + service.createBescheidDocument(bescheidResource); + + expect(service.handleCreateBescheidDocumentResponse).toHaveBeenCalledWith(commandStateResource); + }); + + it('should handle create response on error', () => { + const commandError: StateResource<CommandResource> = createCommandErrorStateResource(); + service.doCreateBescheidDocument = jest.fn().mockReturnValue(of(commandError)); + + service.createBescheidDocument(bescheidResource); + + expect(service.handleCreateBescheidDocumentResponse).toHaveBeenCalledWith(commandError); + }); + }); + + describe('doCreateBescheidDocument', () => { + it('should create command by props', () => { + service.doCreateBescheidDocument(bescheidResource); + + expect(commandService.createCommandByProps).toHaveBeenCalledWith({ + resource: bescheidResource, + linkRel: BescheidLinkRel.CREATE_DOCUMENT, + command: { + order: CommandOrder.CREATE_BESCHEID_DOCUMENT, + body: null, + }, + snackBarMessage: EMPTY_STRING, + }); + }); + }); + + describe('handleCreateBescheidDocumentResponse', () => { + const commandStateResource: StateResource<CommandResource> = createStateResource( + createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]), + ); + + beforeEach(() => { + service.loadBescheidDocumentByUri = jest.fn(); + service.emitBescheidDocumentError = jest.fn(); + }); + + it('should emit error', () => { + const commandErrorStateResource: StateResource<CommandResource> = createCommandErrorStateResource(); + + service.handleCreateBescheidDocumentResponse(commandErrorStateResource); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ ...createEmptyBescheidDocument(), create: commandErrorStateResource } as BescheidDocument), + ); + }); + + it('should emit bescheid document state', () => { + service.handleCreateBescheidDocumentResponse(commandStateResource); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ + ...createEmptyBescheidDocument(), + documentUri: getEffectedResourceUrl(commandStateResource.resource), + }), + ); + }); + + it('should load document by uri', () => { + service.handleCreateBescheidDocumentResponse(commandStateResource); + + expect(service.loadBescheidDocumentByUri).toHaveBeenCalledWith(getEffectedResourceUrl(commandStateResource.resource)); + }); + }); + + describe('emitBescheidDocumentError', () => { + it('should emit', () => { + const commandError: StateResource<CommandResource> = createCommandErrorStateResource(); + + service.emitBescheidDocumentError(commandError); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ + ...createEmptyBescheidDocument(), + upload: { ...createEmptyUploadInProgress(), loading: false, error: commandError.error }, + }), + ); + }); + }); + + describe('loadBescheidDocument', () => { + beforeEach(() => { + service.loadBescheidDocumentByUri = jest.fn(); + }); + + it('should load by uri', () => { + const bescheidResource: BescheidResource = createBescheidResource([BescheidLinkRel.BESCHEID_DOCUMENT]); + + service.loadBescheidDocument(bescheidResource); + + expect(service.loadBescheidDocumentByUri).toHaveBeenCalledWith(getUrl(bescheidResource, BescheidLinkRel.BESCHEID_DOCUMENT)); + }); + + it('should NOT load by uri', () => { + service.loadBescheidDocument(bescheidResource); + + expect(service.loadBescheidDocumentByUri).not.toHaveBeenCalled(); + }); + }); + + describe('loadBescheidDocumentByUri', () => { + const resourceUri: ResourceUri = faker.internet.url(); + + beforeEach(() => { + resourceRepository.getResource.mockReturnValue(EMPTY); + service.loadBescheidDocumentFile = jest.fn(); + }); + + it('should get resource', () => { + service.loadBescheidDocumentByUri(resourceUri); + + expect(resourceRepository.getResource).toHaveBeenCalledWith(resourceUri); + }); + + it('should load bescheid document file', () => { + const documentResource: DocumentResource = createDocumentResource(); + resourceRepository.getResource.mockReturnValue(of(documentResource)); + + service.loadBescheidDocumentByUri(resourceUri); + + expect(service.loadBescheidDocumentFile).toHaveBeenCalledWith(documentResource); + }); + }); + + describe('load bescheid document file', () => { + const document: DocumentResource = createDocumentResource([DocumentLinkRel.FILE]); + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource()); + + beforeEach(() => { + binaryFileService.getFile.mockReturnValue(of(binaryFileStateResource)); + }); + + it('should call binary file service', () => { + service.loadBescheidDocumentFile(document); + + expect(binaryFileService.getFile).toHaveBeenCalledWith(getUrl(document, DocumentLinkRel.FILE)); + }); + + it('should emit bescheid document state', () => { + service.loadBescheidDocumentFile(document); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ + upload: createEmptyUploadInProgress(), + create: createEmptyStateResource(), + resource: binaryFileStateResource.resource, + documentUri: getUrl(document, LinkRel.Self), + }), + ); + }); + }); + + describe('loadAttachments', () => { + const bescheidResourceWithAttachments: BescheidResource = createBescheidResource([BescheidLinkRel.ATTACHMENTS]); + + beforeEach(() => { + binaryFileService.getFiles.mockReturnValue(EMPTY); + }); + + it('should call binary file service', () => { + service.loadAttachments(bescheidResourceWithAttachments); + + expect(binaryFileService.getFiles).toHaveBeenCalledWith(bescheidResourceWithAttachments, BescheidLinkRel.ATTACHMENTS); + }); + + it('should NOT call binary file service', () => { + service.loadAttachments(bescheidResource); + + expect(binaryFileService.getFiles).not.toHaveBeenCalled(); + }); + + it('should emit attachments state', () => { + const binaryFileListStateResource: StateResource<BinaryFileListResource> = + createStateResource(createBinaryFileListResource()); + binaryFileService.getFiles.mockReturnValue(of(binaryFileListStateResource)); + service.loadAttachments(bescheidResourceWithAttachments); + + expect(binaryFileService.getFiles).toHaveBeenCalledWith(bescheidResourceWithAttachments, BescheidLinkRel.ATTACHMENTS); + + expect(service.getAttachments()).toBeObservable( + singleCold({ + ...createEmptyBescheidAttachments(), + items: getEmbeddedResources(binaryFileListStateResource, BinaryFileListLinkRel.FILE_LIST), + }), + ); + }); + }); + + describe('uploadAttachment', () => { + const attachment: File = createFile(); + + beforeEach(() => { + binaryFileService.uploadFile.mockReturnValue(EMPTY); + service.handleAttachmentUpload = jest.fn(); + }); + + it('should emit upload loading', () => { + service.uploadAttachment(attachment, bescheidResource); + + expect(service.getAttachments()).toBeObservable( + singleCold({ + ...createEmptyBescheidAttachments(), + upload: { fileName: attachment.name, loading: true }, + uploadStateResource: createLoadingStateResource(), + } as BescheidAttachments), + ); + }); + + it('should call binary file service', () => { + service.uploadAttachment(attachment, bescheidResource); + + expect(binaryFileService.uploadFile).toHaveBeenCalledWith( + bescheidResource, + BescheidLinkRel.UPLOAD_ATTACHMENT, + attachment, + false, + ); + }); + + it('should handle attachment upload', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource()); + binaryFileService.uploadFile.mockReturnValue(of(binaryFileStateResource)); + + service.uploadAttachment(attachment, bescheidResource); + + expect(service.handleAttachmentUpload).toHaveBeenCalledWith(binaryFileStateResource); + }); + }); + + describe('handleAttachmentUpload', () => { + it('should emit state on success', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource()); + + service.handleAttachmentUpload(binaryFileStateResource); + + expect(service.getAttachments()).toBeObservable( + singleCold({ + ...createEmptyBescheidAttachments(), + items: [binaryFileStateResource.resource], + uploadStateResource: binaryFileStateResource, + upload: { + ...createEmptyUploadInProgress(), + error: binaryFileStateResource.error, + loading: binaryFileStateResource.loading, + }, + } as BescheidAttachments), + ); + }); + + it('should emit state on error', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = createErrorStateResource(createProblemDetail()); + + service.handleAttachmentUpload(binaryFileStateResource); + + expect(service.getAttachments()).toBeObservable( + singleCold({ + ...createEmptyBescheidAttachments(), + items: [], + uploadStateResource: binaryFileStateResource, + upload: { + ...createEmptyUploadInProgress(), + error: binaryFileStateResource.error, + loading: binaryFileStateResource.loading, + }, + }), + ); + }); + }); + + describe('deleteAttachment', () => { + it('should delete', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource()); + service.handleAttachmentUpload(binaryFileStateResource); + + service.deleteAttachment(binaryFileStateResource.resource); + + expect(service.getAttachments()).toBeObservable( + singleCold({ ...createEmptyBescheidAttachments(), uploadStateResource: binaryFileStateResource } as BescheidAttachments), + ); + }); + }); + + describe('upload bescheid document', () => { + const documentFile: File = createFile(); + + beforeEach(() => { + binaryFileService.uploadFile.mockReturnValue(EMPTY); + service.handleUploadBescheidDocumentResponse = jest.fn(); + }); + + it('should emit bescheid document state', () => { + service.uploadBescheidDocument(documentFile, bescheidResource); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ ...createEmptyBescheidDocument(), upload: { fileName: documentFile.name, loading: true } }), + ); + }); + + it('should call binary file service', () => { + service.uploadBescheidDocument(documentFile, bescheidResource); + + expect(binaryFileService.uploadFile).toHaveBeenCalledWith( + bescheidResource, + BescheidLinkRel.UPLOAD_BESCHEID_FILE, + documentFile, + false, + ); + }); + + it('should handle upload response', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource()); + binaryFileService.uploadFile.mockReturnValue(of(binaryFileStateResource)); + + service.uploadBescheidDocument(documentFile, bescheidResource); + + expect(service.handleUploadBescheidDocumentResponse).toHaveBeenCalledWith(bescheidResource, binaryFileStateResource); + }); + }); + + describe('handleUploadBescheidDocumentResponse', () => { + beforeEach(() => { + service.emitBescheidDocumentError = jest.fn(); + service.createBescheidDocumentFromFile = jest.fn(); + }); + + it('should emit error', () => { + const errorStateResource: StateResource<BinaryFileResource> = createErrorStateResource(createProblemDetail()); + + service.handleUploadBescheidDocumentResponse(bescheidResource, errorStateResource); + + expect(service.emitBescheidDocumentError).toHaveBeenCalledWith(errorStateResource); + }); + + it('should create bescheid document from file', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource()); + + service.handleUploadBescheidDocumentResponse(bescheidResource, binaryFileStateResource); + + expect(service.createBescheidDocumentFromFile).toHaveBeenCalledWith(bescheidResource, binaryFileStateResource.resource); + }); + }); + + describe('create bescheid document from file', () => { + const bescheid: BescheidResource = createBescheidResource(); + const binaryFile: BinaryFileResource = createBinaryFileResource(); + + const createCommandProps: CreateCommandProps = createCreateCommandProps(); + let buildCreateBescheidDocumentFromFilePropsSpy; + + const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); + + beforeEach(() => { + buildCreateBescheidDocumentFromFilePropsSpy = jest + .spyOn(BescheidUtil, 'buildCreateBescheidDocumentFromFileProps') + .mockReturnValue(createCommandProps); + commandService.createCommandByProps.mockReturnValue(of(commandStateResource)); + }); + + it('should call command sevice', () => { + service.createBescheidDocumentFromFile(bescheid, binaryFile); + + expect(commandService.createCommandByProps).toHaveBeenCalledWith(createCommandProps); + }); + + it('should build create command document from file props', () => { + service.createBescheidDocumentFromFile(bescheid, binaryFile); + + expect(buildCreateBescheidDocumentFromFilePropsSpy).toHaveBeenCalledWith(bescheid, binaryFile); + }); + + it('should call handle create bescheid document from file response', () => { + service.handleCreateBescheidDocumentFromFileResponse = jest.fn(); + + service.createBescheidDocumentFromFile(bescheid, binaryFile); + + expect(service.handleCreateBescheidDocumentFromFileResponse).toHaveBeenCalledWith(commandStateResource, binaryFile); + }); + }); + + describe('handleCreateBescheidDocumentFromFileResponse', () => { + const commandStateResource: StateResource<CommandResource> = createStateResource( + createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]), + ); + + beforeEach(() => { + service.emitBescheidDocumentError = jest.fn(); + }); + + it('should emit error', () => { + const errorStateResource: StateResource<CommandResource> = createErrorStateResource(createProblemDetail()); + + service.handleCreateBescheidDocumentFromFileResponse(errorStateResource, createBinaryFileResource()); + + expect(service.emitBescheidDocumentError).toHaveBeenCalledWith(errorStateResource); + }); + + it('should NOT emit error', () => { + const binaryFileResource: BinaryFileResource = createBinaryFileResource(); + + service.handleCreateBescheidDocumentFromFileResponse(commandStateResource, binaryFileResource); + + expect(service.emitBescheidDocumentError).not.toHaveBeenCalled(); + }); + + it('should emit bescheid document state', () => { + const binaryFileResource: BinaryFileResource = createBinaryFileResource(); + + service.handleCreateBescheidDocumentFromFileResponse(commandStateResource, binaryFileResource); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ + ...createEmptyBescheidDocument(), + documentUri: getEffectedResourceUrl(commandStateResource.resource), + upload: createEmptyUploadInProgress(), + resource: binaryFileResource, + }), + ); + }); + + it('should NOT emit bescheid document state', () => { + const errorStateResource: StateResource<CommandResource> = createErrorStateResource(createProblemDetail()); + + service.handleCreateBescheidDocumentFromFileResponse(errorStateResource, createBinaryFileResource()); + + expect(service.getBescheidDocument()).toBeObservable(singleCold(createEmptyBescheidDocument())); + }); + }); + + describe('createBescheid', () => { + const vorgangWithEingang: VorgangWithEingangResource = createVorgangWithEingangResource(); + const command: CommandResource = createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]); + const commandStateResource: StateResource<CommandResource> = createStateResource(command); + + beforeEach(() => { + service.updateBescheidDraft = jest.fn(); + }); + + beforeEach(() => { + facade.getBescheidCommand.mockReturnValue(of(commandStateResource)); + (service as any).bescheidResourceService.loadByResourceUri = jest.fn(); + }); + + it('should call facade', () => { + service.createBescheid(vorgangWithEingang).subscribe(); + + expect(facade.createBescheidDraft).toHaveBeenCalledWith(vorgangWithEingang, { + order: CommandOrder.CREATE_BESCHEID, + body: null, + }); + }); + + it('should update bescheid draft', () => { + service.createBescheid(vorgangWithEingang).subscribe(); + + expect(service.updateBescheidDraft).toHaveBeenCalledWith(commandStateResource.resource); + }); + }); + + describe('updateBescheidDraft', () => { + const command: CommandResource = createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]); + + beforeEach(() => { + (service as any).bescheidResourceService.loadByResourceUri = jest.fn(); + }); + + it('should load resource by uri', () => { + service.updateBescheidDraft(command); + + expect((service as any).bescheidResourceService.loadByResourceUri).toHaveBeenCalledWith( + getUrl(command, CommandLinkRel.EFFECTED_RESOURCE), + ); + }); + + it('should emit bescheid created', () => { + service.updateBescheidDraft({ ...command, order: CommandOrder.CREATE_BESCHEID }); + + expect(service.getBescheidCreated()).toBeObservable(singleCold(true)); + }); + }); + + describe('updateBescheid', () => { + const bescheid: Bescheid = createBescheid(); + const commandResource: CommandResource = createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]); + const commandStateResource: StateResource<CommandResource> = createStateResource(commandResource); + + beforeEach(() => { + service.doUpdateBescheid = jest.fn().mockReturnValue(EMPTY); + service.updateBescheidDraft = jest.fn().mockReturnValue(EMPTY); + }); + + it('should do update bescheid', () => { + service.updateBescheid(bescheidResource, bescheid); + + expect(service.doUpdateBescheid).toHaveBeenCalledWith(bescheidResource, bescheid); + }); + + it('should update bescheid draft', () => { + service.doUpdateBescheid = jest.fn().mockReturnValue(of(commandStateResource)); + + service.updateBescheid(bescheidResource, bescheid).subscribe(); + + expect(service.updateBescheidDraft).toHaveBeenCalledWith(commandResource); + }); + }); + + describe('do update bescheid', () => { + const bescheid: Bescheid = createBescheid(); + const bescheidResource: BescheidResource = createBescheidResource(); + + const createCommandProps: CreateCommandProps = createCreateCommandProps(); + let buildUpdateBescheidCommandPropsSpy: jest.SpyInstance; + + beforeEach(() => { + buildUpdateBescheidCommandPropsSpy = jest + .spyOn(BescheidUtil, 'buildUpdateBescheidCommandProps') + .mockReturnValue(createCommandProps); + commandService.createCommandByProps.mockClear(); + commandService.createCommandByProps.mockReturnValue(of(createCommandStateResource())); + }); + + it('should build update bescheid command props', () => { + service.doUpdateBescheid(bescheidResource, bescheid); + + expect(buildUpdateBescheidCommandPropsSpy).toHaveBeenCalledWith(bescheidResource, bescheid); + }); + + it('should call command service', () => { + service.doUpdateBescheid(bescheidResource, bescheid).subscribe(); + + expect(commandService.createCommandByProps).toHaveBeenCalledWith(createCommandProps); + }); + }); + + describe('sendBescheidManually', () => { + beforeEach(() => { + service.sendBescheid = jest.fn().mockReturnValue(EMPTY); + }); + + it('should send bescheid', () => { + service.sendBescheidManually().subscribe(); + + expect(service.sendBescheid).toHaveBeenCalledWith(BescheidLinkRel.BESCHEIDEN); + }); + + it('should return send bescheid command', () => { + const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + service.sendBescheid = jest.fn().mockReturnValue(of(commandStateResource)); + + const sendCommandStateResource$: Observable<StateResource<CommandResource>> = service.sendBescheidManually(); + + expect(sendCommandStateResource$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + }); + + describe('sendBescheid', () => { + beforeEach(() => { + service.getBescheidDraft = jest.fn().mockReturnValue(of(createStateResource(bescheidResource))); + commandService.createCommandByProps.mockReturnValue(EMPTY); + }); + + it('should get bescheid draft', () => { + service.sendBescheidManually().subscribe(); + + expect(service.getBescheidDraft).toHaveBeenCalled(); + }); + + it('should create command', () => { + service.sendBescheid(BescheidLinkRel.BESCHEIDEN).subscribe(); + + expect(commandService.createCommandByProps).toHaveBeenCalledWith({ + resource: bescheidResource, + linkRel: BescheidLinkRel.BESCHEIDEN, + command: { + order: CommandOrder.SEND_BESCHEID, + body: null, + }, + snackBarMessage: EMPTY_STRING, + } as CreateCommandProps); + }); + + it('should return send bescheid command', () => { + const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + commandService.createCommandByProps = jest.fn().mockReturnValue(of(commandStateResource)); + + const sendCommandStateResource$: Observable<StateResource<CommandResource>> = service.sendBescheid( + BescheidLinkRel.BESCHEIDEN, + ); + + expect(sendCommandStateResource$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + }); + + describe('sendBescheidMessage', () => { + beforeEach(() => { + service.getBescheidDraft = jest.fn().mockReturnValue(createStateResource(bescheidResource)); + service.sendBescheid = jest.fn().mockReturnValue(EMPTY); + }); + + it('should send bescheid', () => { + service.sendBescheidMessage().subscribe(); + + expect(service.sendBescheid).toHaveBeenCalledWith(BescheidLinkRel.BESCHEIDEN_UND_SENDEN); + }); + + it('should return send bescheid command', () => { + const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + service.sendBescheid = jest.fn().mockReturnValue(of(commandStateResource)); + + const sendCommandStateResource$: Observable<StateResource<CommandResource>> = service.sendBescheidMessage(); + + expect(sendCommandStateResource$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + }); + + describe('setActiveStep', () => { + it('should emit changed active step', () => { + service.setActiveStep(BescheidWizardStep.DokumenteHochladen); + + expect(service.getActiveStep()).toBeObservable(singleCold(BescheidWizardStep.DokumenteHochladen)); + }); + }); + + describe('getBescheidDraft', () => { + const bescheidDraft: BescheidResource = createBescheidResource(); + const bescheidDraftStateResource: StateResource<BescheidResource> = createStateResource(bescheidDraft); + + it('should call resource service', () => { + bescheidResourceService.get = jest.fn(); + + service.getBescheidDraft(); + + expect(bescheidResourceService.get).toHaveBeenCalled(); + }); + + it('should return value', () => { + bescheidResourceService.get = jest.fn().mockReturnValue(singleCold(bescheidDraftStateResource)); + + const bescheidStateResource$: Observable<StateResource<BescheidResource>> = service.getBescheidDraft(); + + expect(bescheidStateResource$).toBeObservable(singleCold(bescheidDraftStateResource)); + }); + }); + + describe('setNachrichtEmpfaenger', () => { + it('should change wizard state', () => { + const empfaenger: string = faker.person.fullName(); + + service.setNachrichtEmpfaenger(empfaenger); + + expect(service.getWizard()).toBeObservable(singleCold({ ...createInitialWizard(), empfaenger })); + }); + }); + + describe('lockBescheidSending', () => { + it('should change wizard state', () => { + service.lockBescheidSending(); + + expect(service.getWizard()).toBeObservable(singleCold({ ...createInitialWizard(), canBeSend: false })); + }); + }); + + describe('unlockBescheidSending', () => { + it('should change wizard state', () => { + service.unlockBescheidSending(); + + expect(service.getWizard()).toBeObservable(singleCold({ ...createInitialWizard(), canBeSend: true })); + }); + }); + + describe('finishAddingAttachments', () => { + it('should update state', () => { + const attachments: BescheidAttachments = createBescheidAttachments(); + service._attachments$.next(attachments); + + service.finishAddingAttachments(); + + expect(service.getAttachments()).toBeObservable( + singleCold({ + ...attachments, + upload: createEmptyUploadInProgress(), + uploadStateResource: createEmptyStateResource(), + } as BescheidAttachments), + ); + }); + }); + + describe('finishAddingBescheidDocument', () => { + it('should update state', () => { + const bescheidDocument: BescheidDocument = createBescheidDocument(); + service._bescheidDocument$.next(bescheidDocument); + + service.finishAddingBescheidDocument(); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ + ...bescheidDocument, + create: createEmptyStateResource(), + upload: createEmptyUploadInProgress(), + } as BescheidDocument), + ); + }); + }); +}); diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..3c5d8191390993f76b6456a8577d895b57dd6f55 --- /dev/null +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.ts @@ -0,0 +1,387 @@ +import { + Bescheid, + BescheidAttachments, + BescheidDocument, + BescheidLinkRel, + BescheidResource, + BescheidSendBy, + BescheidWizardStep, + buildCreateBescheidCommand, + buildCreateBescheidDocumentCommandProps, + buildCreateBescheidDocumentFromFileProps, + buildSendBescheidCommandProps, + buildUpdateBescheidCommandProps, + createEmptyBescheidAttachments, + createEmptyBescheidDocument, + createEmptyUploadInProgress, + createInitialWizard, + DocumentResource, + Wizard, +} from '@alfa-client/bescheid-shared'; +import { + BinaryFileListLinkRel, + BinaryFileListResource, + BinaryFileResource, + BinaryFileService, +} from '@alfa-client/binary-file-shared'; +import { + CommandOrder, + CommandResource, + CommandService, + getEffectedResourceUrl, + notHasCommandError, + tapOnCommandSuccessfullyDone, +} from '@alfa-client/command-shared'; +import { PostfachService } from '@alfa-client/postfach-shared'; +import { + createEmptyStateResource, + createLoadingStateResource, + filterIsLoadedOrHasError, + getEmbeddedResources, + hasStateResourceError, + isLoaded, + ResourceRepository, + StateResource, +} from '@alfa-client/tech-shared'; +import { VorgangCommandService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { inject, Injectable } from '@angular/core'; +import { getUrl, hasLink, LinkRel, Resource, ResourceUri } from '@ngxp/rest'; +import { isNil } from 'lodash-es'; +import { BehaviorSubject, filter, first, map, Observable, switchMap } from 'rxjs'; +import { BescheidFacade } from './+state/bescheid.facade'; +import { BescheidResourceService } from './bescheid-resource-service'; +import { DocumentLinkRel } from './document.linkrel'; + +@Injectable() +export class BescheidService2 { + private readonly bescheidFacade = inject(BescheidFacade); + private readonly commandService = inject(CommandService); + private readonly vorgangCommandService = inject(VorgangCommandService); + private readonly binaryFileService = inject(BinaryFileService); + private readonly resourceRepository = inject(ResourceRepository); + private readonly postfachService = inject(PostfachService); + private readonly bescheidResourceService = inject(BescheidResourceService); + + readonly _bescheidDocument$: BehaviorSubject<BescheidDocument> = new BehaviorSubject(createEmptyBescheidDocument()); + readonly _attachments$: BehaviorSubject<BescheidAttachments> = new BehaviorSubject(createEmptyBescheidAttachments()); + readonly _wizard$: BehaviorSubject<Wizard> = new BehaviorSubject(createInitialWizard()); + + public init(): void { + this._wizard$.next(createInitialWizard()); + this._bescheidDocument$.next(createEmptyBescheidDocument()); + this._attachments$.next(createEmptyBescheidAttachments()); + } + + public exit(): void { + this.postfachService.setPostfachMailOnReload(); + } + + public skipBescheidCreation( + vorgangWithEingangResource: VorgangWithEingangResource, + bescheidResource: BescheidResource, + ): Observable<StateResource<CommandResource>> { + if (isNil(bescheidResource)) { + return this.vorgangCommandService.abschliessen(vorgangWithEingangResource); + } + return this.deleteBescheidAndCompleteVorgang(vorgangWithEingangResource); + } + + deleteBescheidAndCompleteVorgang( + vorgangWithEingangResource: VorgangWithEingangResource, + ): Observable<StateResource<CommandResource>> { + return this.vorgangCommandService + .abschliessen(vorgangWithEingangResource) + .pipe(tapOnCommandSuccessfullyDone(() => this.deleteBescheid())); + } + + public deleteBescheid(): Observable<StateResource<CommandResource>> { + return this.bescheidResourceService.delete(); + } + + public loadFiles(bescheidResource: BescheidResource): void { + this.loadBescheidDocument(bescheidResource); + this.loadAttachments(bescheidResource); + } + + public createBescheidDocument(bescheidResource: BescheidResource): void { + this._bescheidDocument$.next({ ...createEmptyBescheidDocument(), create: createEmptyStateResource(true) }); + this.doCreateBescheidDocument(bescheidResource) + .pipe(filterIsLoadedOrHasError(), first()) + .subscribe((commandStateResource: StateResource<CommandResource>) => + this.handleCreateBescheidDocumentResponse(commandStateResource), + ); + } + + doCreateBescheidDocument(bescheidResource: BescheidResource): Observable<StateResource<CommandResource>> { + return this.commandService.createCommandByProps(buildCreateBescheidDocumentCommandProps(bescheidResource)); + } + + handleCreateBescheidDocumentResponse(commandStateResource: StateResource<CommandResource>): void { + if (notHasCommandError(commandStateResource.resource)) { + const documentUri: ResourceUri = getEffectedResourceUrl(commandStateResource.resource); + this._bescheidDocument$.next({ ...this._bescheidDocument$.value, documentUri }); + this.loadBescheidDocumentByUri(documentUri); + } else { + this._bescheidDocument$.next({ ...this._bescheidDocument$.value, create: commandStateResource }); + } + } + + emitBescheidDocumentError(stateResource: StateResource<Resource>): void { + const value: BescheidDocument = this._bescheidDocument$.value; + this._bescheidDocument$.next({ + ...value, + upload: { ...value.upload, loading: false, error: stateResource.error }, + }); + } + + loadBescheidDocument(bescheidResource: BescheidResource): void { + if (hasLink(bescheidResource, BescheidLinkRel.BESCHEID_DOCUMENT)) { + this.loadBescheidDocumentByUri(getUrl(bescheidResource, BescheidLinkRel.BESCHEID_DOCUMENT)); + } + } + + public loadBescheidDocumentByUri(resourceUri: ResourceUri): void { + this.resourceRepository + .getResource(resourceUri) + .pipe(first()) + .subscribe((document: DocumentResource) => this.loadBescheidDocumentFile(document)); + } + + loadBescheidDocumentFile(document: DocumentResource): void { + this.binaryFileService + .getFile(getUrl(document, DocumentLinkRel.FILE)) + .pipe(filterIsLoadedOrHasError(), first()) + .subscribe((binaryFile: StateResource<BinaryFileResource>) => { + this._bescheidDocument$.next({ + ...this._bescheidDocument$.value, + upload: createEmptyUploadInProgress(), + create: createEmptyStateResource(), + resource: binaryFile.resource, + documentUri: getUrl(document, LinkRel.Self), + }); + }); + } + + loadAttachments(bescheidResource: BescheidResource): void { + if (hasLink(bescheidResource, BescheidLinkRel.ATTACHMENTS)) { + this.binaryFileService + .getFiles(bescheidResource, BescheidLinkRel.ATTACHMENTS) + .pipe( + filterIsLoadedOrHasError(), + first(), + map((stateResource: StateResource<BinaryFileListResource>) => + getEmbeddedResources<BinaryFileResource>(stateResource, BinaryFileListLinkRel.FILE_LIST), + ), + ) + .subscribe((files: BinaryFileResource[]) => this._attachments$.next({ ...this._attachments$.value, items: files })); + } + } + + public uploadAttachment(attachment: File, bescheidResource: BescheidResource): void { + this._attachments$.next({ + ...this._attachments$.value, + upload: { fileName: attachment.name, loading: true }, + uploadStateResource: createLoadingStateResource(), + }); + this.binaryFileService + .uploadFile(bescheidResource, BescheidLinkRel.UPLOAD_ATTACHMENT, attachment, false) + .pipe(filterIsLoadedOrHasError(), first()) + .subscribe((binaryFileStateResource: StateResource<BinaryFileResource>) => + this.handleAttachmentUpload(binaryFileStateResource), + ); + } + + handleAttachmentUpload(binaryFileStateResource: StateResource<BinaryFileResource>) { + const value: BescheidAttachments = this._attachments$.value; + if (hasStateResourceError(binaryFileStateResource)) { + this._attachments$.next({ + ...value, + uploadStateResource: binaryFileStateResource, + upload: { ...value.upload, error: binaryFileStateResource.error, loading: binaryFileStateResource.loading }, + }); + } else { + this._attachments$.next({ + ...value, + uploadStateResource: binaryFileStateResource, + items: [...value.items, binaryFileStateResource.resource], + upload: { ...value.upload, error: binaryFileStateResource.error, loading: binaryFileStateResource.loading }, + }); + } + } + + public deleteAttachment(attachment: BinaryFileResource): void { + const value: BescheidAttachments = this._attachments$.value; + this._attachments$.next({ + ...value, + items: value.items.filter((each: BinaryFileResource) => getUrl(each) !== getUrl(attachment)), + }); + } + + public uploadBescheidDocument(document: File, bescheid: BescheidResource): void { + this._bescheidDocument$.next({ ...this._bescheidDocument$.value, upload: { fileName: document.name, loading: true } }); + this.binaryFileService + .uploadFile(bescheid, BescheidLinkRel.UPLOAD_BESCHEID_FILE, document, false) + .pipe(filterIsLoadedOrHasError(), first()) + .subscribe((binaryFileStateResource: StateResource<BinaryFileResource>) => + this.handleUploadBescheidDocumentResponse(bescheid, binaryFileStateResource), + ); + } + + handleUploadBescheidDocumentResponse( + bescheid: BescheidResource, + binaryFileStateResource: StateResource<BinaryFileResource>, + ): void { + if (hasStateResourceError(binaryFileStateResource)) { + this.emitBescheidDocumentError(binaryFileStateResource); + } else { + this.createBescheidDocumentFromFile(bescheid, binaryFileStateResource.resource); + } + } + + createBescheidDocumentFromFile(bescheid: BescheidResource, binaryFile: BinaryFileResource): void { + this.commandService + .createCommandByProps(buildCreateBescheidDocumentFromFileProps(bescheid, binaryFile)) + .pipe(filterIsLoadedOrHasError(), first()) + .subscribe((commandStateResource: StateResource<CommandResource>) => + this.handleCreateBescheidDocumentFromFileResponse(commandStateResource, binaryFile), + ); + } + + handleCreateBescheidDocumentFromFileResponse( + commandStateResource: StateResource<CommandResource>, + binaryFile: BinaryFileResource, + ): void { + if (hasStateResourceError(commandStateResource)) { + this.emitBescheidDocumentError(commandStateResource); + } else { + this._bescheidDocument$.next({ + ...this._bescheidDocument$.value, + documentUri: getEffectedResourceUrl(commandStateResource.resource), + upload: createEmptyUploadInProgress(), + resource: binaryFile, + }); + } + } + + public createBescheid( + vorgangWithEingang: VorgangWithEingangResource, + bescheid?: Bescheid, + ): Observable<StateResource<CommandResource>> { + this.bescheidFacade.createBescheidDraft(vorgangWithEingang, buildCreateBescheidCommand(bescheid)); + return this.bescheidFacade + .getBescheidCommand() + .pipe( + tapOnCommandSuccessfullyDone((commandStateResource: StateResource<CommandResource>) => + this.updateBescheidDraft(commandStateResource.resource), + ), + ); + } + + updateBescheidDraft(command: CommandResource): void { + this.bescheidResourceService.loadByResourceUri(getEffectedResourceUrl(command)); + if (command.order === CommandOrder.CREATE_BESCHEID) { + this._wizard$.next({ ...this._wizard$.value, bescheidCreated: true }); + } + } + + public updateBescheid( + bescheidResource: BescheidResource, + updatedBescheid: Bescheid, + ): Observable<StateResource<CommandResource>> { + return this.doUpdateBescheid(bescheidResource, updatedBescheid).pipe( + tapOnCommandSuccessfullyDone((commandStateResource: StateResource<CommandResource>) => { + this.updateBescheidDraft(commandStateResource.resource); + }), + ); + } + + doUpdateBescheid(bescheidResource: BescheidResource, bescheid: Bescheid): Observable<StateResource<CommandResource>> { + return this.commandService.createCommandByProps(buildUpdateBescheidCommandProps(bescheidResource, bescheid)); + } + + public sendBescheidManually(): Observable<StateResource<CommandResource>> { + return this.sendBescheid(BescheidLinkRel.BESCHEIDEN); + } + + public sendBescheidMessage(): Observable<StateResource<CommandResource>> { + return this.sendBescheid(BescheidLinkRel.BESCHEIDEN_UND_SENDEN); + } + + sendBescheid(linkRel: BescheidLinkRel): Observable<StateResource<CommandResource>> { + return this.getBescheidDraft().pipe( + filter(isLoaded), + map((stateResource: StateResource<BescheidResource>) => stateResource.resource), + switchMap((bescheidResource: BescheidResource) => + this.commandService.createCommandByProps(buildSendBescheidCommandProps(bescheidResource, linkRel)), + ), + ); + } + + public getBescheidDraft(): Observable<StateResource<BescheidResource>> { + return this.bescheidResourceService.get(); + } + + public getAttachments(): Observable<BescheidAttachments> { + return this._attachments$.asObservable(); + } + + public getBescheidDocument(): Observable<BescheidDocument> { + return this._bescheidDocument$.asObservable(); + } + + public deleteBescheidDocument(): void { + this._bescheidDocument$.next(createEmptyBescheidDocument()); + } + + public getActiveStep(): Observable<BescheidWizardStep> { + return this._wizard$.asObservable().pipe(map((wizard: Wizard) => wizard.activeStep)); + } + + public setActiveStep(step: BescheidWizardStep): void { + this._wizard$.next({ ...this._wizard$.value, activeStep: step }); + } + + public getBescheidCreated(): Observable<boolean> { + return this._wizard$.asObservable().pipe(map((wizard: Wizard) => wizard.bescheidCreated)); + } + + public selectBescheidResource(): Observable<StateResource<BescheidResource>> { + return this.bescheidResourceService.selectResource(); + } + + public getWizard(): Observable<Wizard> { + return this._wizard$.asObservable(); + } + + public setSendBy(sendBy: BescheidSendBy): void { + this._wizard$.next({ ...this._wizard$.value, sendBy: sendBy }); + } + + public setNachrichtEmpfaenger(empfaenger: string): void { + this._wizard$.next({ ...this._wizard$.value, empfaenger: empfaenger }); + } + + public lockBescheidSending(): void { + this._wizard$.next({ ...this._wizard$.value, canBeSend: false }); + } + + public unlockBescheidSending(): void { + this._wizard$.next({ ...this._wizard$.value, canBeSend: true }); + } + + public finishAddingAttachments(): void { + this._attachments$.next({ + ...this._attachments$.value, + upload: createEmptyUploadInProgress(), + uploadStateResource: createEmptyStateResource(), + }); + } + + public finishAddingBescheidDocument(): void { + this._bescheidDocument$.next({ + ...this._bescheidDocument$.value, + upload: createEmptyUploadInProgress(), + create: createEmptyStateResource(), + }); + } +} diff --git a/alfa-client/libs/bescheid-shared/src/test/bescheid.ts b/alfa-client/libs/bescheid-shared/src/test/bescheid.ts index d9140137173742b27c72af02134df8c57475f2e1..b8f118a56164cfd5fd06c7b6e2db02c9bac57471 100644 --- a/alfa-client/libs/bescheid-shared/src/test/bescheid.ts +++ b/alfa-client/libs/bescheid-shared/src/test/bescheid.ts @@ -25,16 +25,11 @@ import { createStateResource, StateResource } from '@alfa-client/tech-shared'; import { faker } from '@faker-js/faker'; import { toResource } from 'libs/tech-shared/test/resource'; import { times } from 'lodash-es'; -import { createApiError } from '../../../tech-shared/test/error'; +import { createBinaryFileResource } from '../../../binary-file-shared/test/binary-file'; +import { createSuccessfullyDoneCommandStateResource } from '../../../command-shared/test/command'; +import { createProblemDetail } from '../../../tech-shared/test/error'; import { BescheidListLinkRel } from '../lib/bescheid.linkrel'; -import { - Bescheid, - BescheidListResource, - BescheidResource, - BescheidSendBy, - BescheidStatus, - UploadFileInProgress, -} from '../lib/bescheid.model'; +import { Bescheid, BescheidAttachments, BescheidDocument, BescheidListResource, BescheidResource, BescheidSendBy, BescheidStatus, BescheidWizardStep, UploadFileInProgress, Wizard, } from '../lib/bescheid.model'; export function createBescheid(): Bescheid { return { @@ -53,14 +48,12 @@ export function createBescheidResource(linkRel: string[] = []): BescheidResource return toResource(createBescheid(), linkRel); } -export function createBescheidStateResource( - linkRel: string[] = [], -): StateResource<BescheidResource> { +export function createBescheidStateResource(linkRel: string[] = []): StateResource<BescheidResource> { return createStateResource(createBescheidResource(linkRel)); } export function createUploadFileInProgress(): UploadFileInProgress { - return { loading: true, fileName: faker.person.firstName(), error: createApiError() }; + return { loading: true, fileName: faker.person.firstName(), error: createProblemDetail() }; } export function createBescheidResources(linkRelations: string[] = []): BescheidResource[] { @@ -75,3 +68,54 @@ export function createBescheidListResource( [BescheidListLinkRel.BESCHEID_LIST]: bescheide, }); } + +export function createBescheidAttachments(): BescheidAttachments { + return { + upload: createUploadFileInProgress(), + items: [createBinaryFileResource()], + uploadStateResource: createStateResource(createBinaryFileResource()), + }; +} + +export function createBescheidDocument(): BescheidDocument { + return { + upload: createUploadFileInProgress(), + create: createSuccessfullyDoneCommandStateResource(), + documentUri: faker.internet.url(), + resource: createBinaryFileResource(), + }; +} + +export function createSuccessfulUpload(): UploadFileInProgress { + return { + loading: false, + error: null, + fileName: faker.system.fileName(), + }; +} + +export function createPendingUpload(): UploadFileInProgress { + return { + loading: true, + fileName: faker.system.fileName(), + error: null, + }; +} + +export function createErrorUpload(): UploadFileInProgress { + return { + loading: false, + error: createProblemDetail(), + fileName: faker.system.fileName(), + }; +} + +export function createWizard(): Wizard { + return { + empfaenger: faker.person.fullName(), + sendBy: BescheidSendBy.MANUAL, + bescheidCreated: false, + canBeSend: true, + activeStep: BescheidWizardStep.BescheidVersenden, + }; +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.html index dd3c548c5ab8b1d8b0811314cc637153af596aab..d63d7046e6e03287fae28cd1e019ff1fe55ce0f6 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.html @@ -27,28 +27,25 @@ <div class="fixed inset-0 z-10 w-screen overflow-y-auto"> <div class="flex h-full items-center justify-center p-8"> <div - class="relative h-full w-full max-w-7xl transform overflow-hidden rounded-lg bg-background-200 px-6 py-10 text-left shadow-xl transition-all" + class="relative h-full w-full max-w-7xl transform overflow-hidden rounded-lg bg-background-200 py-9 pl-6 pr-9 text-left shadow-xl transition-all" > - <ng-container *ngIf="bescheidDraftStateResource$ | async as bescheidStateResource"> - <ods-button - variant="ghost" - size="fit" - class="absolute right-0 top-0 text-text" - (clickEmitter)="cancelWizard(bescheidStateResource.resource)" - data-test-id="close-bescheid" - > - <ods-close-icon icon /> - </ods-button> - <alfa-bescheid-wizard - [vorgangWithEingangResource]="vorgangWithEingangResource" - [activeStep]="bescheidService.getActiveStep() | async" - [bescheidStateResource]="bescheidStateResource" - [submitStateResource]="submitStateResource$ | async" - (weiterClickEmitter)="onWeiter($event)" - (vorgangAbgeschlossen)="onVorgangAbgeschlossen()" - data-test-id="bescheid-wizard" - ></alfa-bescheid-wizard> - </ng-container> + @let bescheidStateResource = bescheidDraftStateResource$ | async; + <ods-button + variant="ghost" + size="fit" + class="absolute right-0 top-0 text-text" + (clickEmitter)="cancelWizard(bescheidStateResource.resource)" + dataTestId="close-bescheid" + > + <ods-close-icon icon /> + </ods-button> + <alfa-bescheid-wizard + [vorgangWithEingangResource]="vorgangWithEingangResource" + [activeStep]="activeStep$ | async" + [bescheidStateResource]="bescheidStateResource" + (vorgangAbgeschlossen)="onVorgangAbgeschlossen()" + data-test-id="bescheid-wizard" + ></alfa-bescheid-wizard> </div> </div> </div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.spec.ts index 55cca698c53bc342a4a2546ce9bde17a57b5e889..1fe204ade444f7609bea459484de54ed0ab5a829 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.spec.ts @@ -21,21 +21,15 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidResource, BescheidService, BescheidWizardDialogResult, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { BescheidResource, BescheidWizardDialogResult, BescheidWizardStep } from '@alfa-client/bescheid-shared'; import { CommandOrder, CommandResource } from '@alfa-client/command-shared'; +import { createEmptyStateResource, createStateResource, ESCAPE_KEY, StateResource } from '@alfa-client/tech-shared'; import { - ESCAPE_KEY, - StateResource, - createEmptyStateResource, - createErrorStateResource, - createStateResource, -} from '@alfa-client/tech-shared'; -import { - DialogRefMock, - Mock, createDialogRefMock, + DialogRefMock, existsAsHtmlElement, getElementFromFixtureByType, + Mock, mock, triggerEvent, useFromMock, @@ -47,15 +41,10 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ButtonComponent, CloseIconComponent } from '@ods/system'; import { MockComponent } from 'ng-mocks'; import { EMPTY, of } from 'rxjs'; +import { BescheidService2 } from '../../../../bescheid-shared/src/lib/bescheid2.service'; import { createBescheidResource, createBescheidStateResource } from '../../../../bescheid-shared/src/test/bescheid'; -import { - createCommandErrorResource, - createCommandResource, - createSuccessfullyDoneCommandResource, - createSuccessfullyDoneCommandStateResource, -} from '../../../../command-shared/test/command'; -import { getDataTestIdOf } from '../../../../tech-shared/test/data-test'; -import { createApiError } from '../../../../tech-shared/test/error'; +import { createCommandErrorResource, createSuccessfullyDoneCommandResource } from '../../../../command-shared/test/command'; +import { getDataTestIdAttributeOf, getDataTestIdOf } from '../../../../tech-shared/test/data-test'; import { singleColdCompleted } from '../../../../tech-shared/test/marbles'; import { createKeydownKeyboardEvent } from '../../../../test-utils/src/lib/keyboard'; import { createVorgangWithEingangResource } from '../../../../vorgang-shared/test/vorgang'; @@ -73,9 +62,9 @@ describe('BescheidWizardContainerComponent', () => { let fixture: ComponentFixture<BescheidWizardContainerComponent>; const bescheidWizard: string = getDataTestIdOf('bescheid-wizard'); - const closeButton: string = getDataTestIdOf('close-bescheid'); + const closeButton: string = getDataTestIdAttributeOf('close-bescheid'); - let bescheidService: Mock<BescheidService>; + let bescheidService: Mock<BescheidService2>; let ozgcloudDialogService: Mock<OzgcloudDialogService>; let formService: Mock<BescheidFormService>; let wizardDialogRef: DialogRefMock<BescheidWizardDialogResult>; @@ -83,7 +72,8 @@ describe('BescheidWizardContainerComponent', () => { const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource(); beforeEach(() => { - bescheidService = mock(BescheidService); + bescheidService = mock(BescheidService2); + bescheidService.getBescheidCreated.mockReturnValue(EMPTY); ozgcloudDialogService = mock(OzgcloudDialogService); formService = mock(BescheidFormService); wizardDialogRef = createDialogRefMock(); @@ -115,7 +105,7 @@ describe('BescheidWizardContainerComponent', () => { useValue: { vorgangWithEingangResource }, }, { - provide: BescheidService, + provide: BescheidService2, useValue: bescheidService, }, { @@ -160,6 +150,14 @@ describe('BescheidWizardContainerComponent', () => { expect(formService.setVorgangWithEingangResource).toHaveBeenCalledWith(vorgangWithEingangResource); }); + it('should set active step', () => { + bescheidService.getActiveStep.mockReturnValue(of(BescheidWizardStep.BescheidVersenden)); + + component.ngOnInit(); + + expect(component.activeStep$).toBeObservable(singleColdCompleted(BescheidWizardStep.BescheidVersenden)); + }); + it('should subscribe to bescheid resource', () => { component.subscribeToBescheidResourceIfExists = jest.fn(); @@ -231,74 +229,6 @@ describe('BescheidWizardContainerComponent', () => { }); }); - describe('onWeiter', () => { - beforeEach(() => { - formService.submit = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); - component.isBescheidSuccessfullyCreated = jest.fn().mockReturnValue(true); - bescheidService.getBescheidDraft.mockReturnValue(of(createBescheidStateResource())); - }); - - it('should submit form', () => { - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - expect(formService.submit).toHaveBeenCalled(); - }); - - it('should increment step on created bescheid', () => { - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - component.submitStateResource$.subscribe(); - expect(bescheidService.setActiveStep).toHaveBeenCalledWith(BescheidWizardStep.DokumenteHochladen); - }); - - it('should increment step on updated bescheid', () => { - component.isBescheidSuccessfullyCreated = jest.fn().mockReturnValue(false); - - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - component.submitStateResource$.subscribe(); - expect(bescheidService.setActiveStep).toHaveBeenCalledWith(BescheidWizardStep.DokumenteHochladen); - }); - - it('should not increment step on command resource error', () => { - component.isBescheidSuccessfullyCreated = jest.fn().mockReturnValue(false); - formService.submit = jest.fn().mockReturnValue(of(createErrorStateResource(createApiError()))); - - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - component.submitStateResource$.subscribe(); - expect(bescheidService.setActiveStep).not.toHaveBeenCalled(); - }); - - it('should not increment step on command resource loading', () => { - component.isBescheidSuccessfullyCreated = jest.fn().mockReturnValue(false); - formService.submit = jest.fn().mockReturnValue(of(createStateResource(createCommandResource(), true))); - - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - component.submitStateResource$.subscribe(); - expect(bescheidService.setActiveStep).not.toHaveBeenCalled(); - }); - - it('should not increment step on bescheid resource error', () => { - bescheidService.getBescheidDraft.mockReturnValue(of(createErrorStateResource(createApiError()))); - - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - component.submitStateResource$.subscribe(); - expect(bescheidService.setActiveStep).not.toHaveBeenCalled(); - }); - - it('should not increment step on bescheid loading', () => { - bescheidService.getBescheidDraft.mockReturnValue(of(createStateResource(null, true))); - - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - component.submitStateResource$.subscribe(); - expect(bescheidService.setActiveStep).not.toHaveBeenCalled(); - }); - }); - describe('isBescheidSuccessfullyCreated', () => { it('should return true', () => { const createBescheidCommandResource: CommandResource = { @@ -498,81 +428,60 @@ describe('BescheidWizardContainerComponent', () => { }); describe('template', () => { - describe('alfa-bescheid-wizard', () => { + describe('wizard', () => { function getElementComponent(): BescheidWizardComponent { return getElementFromFixtureByType(fixture, BescheidWizardComponent); } - describe('input', () => { - it('should set vorgangWithEingangResource', () => { - component.vorgangWithEingangResource = createVorgangWithEingangResource(); - - fixture.detectChanges(); - - expect(getElementComponent().vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); - }); - - it('should set activeStep', () => { - bescheidService.getActiveStep.mockReturnValue(of(2)); - - fixture.detectChanges(); - - expect(getElementComponent().activeStep).toBe(2); - }); - - it('should set bescheidStateResource', () => { - const bescheidStateResource: StateResource<BescheidResource> = createBescheidStateResource(); - component.bescheidDraftStateResource$ = of(bescheidStateResource); + it('should have been called with inputs', () => { + component.vorgangWithEingangResource = createVorgangWithEingangResource(); + bescheidService.getActiveStep.mockReturnValue(of(BescheidWizardStep.DokumenteHochladen)); + const bescheidStateResource: StateResource<BescheidResource> = createBescheidStateResource(); + component.bescheidDraftStateResource$ = of(bescheidStateResource); + component.ngOnInit(); - fixture.detectChanges(); + fixture.detectChanges(); - expect(getElementComponent().bescheidStateResource).toBe(bescheidStateResource); - }); + expect(getElementComponent().vorgangWithEingangResource).toEqual(component.vorgangWithEingangResource); + expect(getElementComponent().activeStep).toEqual(2); + expect(getElementComponent().bescheidStateResource).toEqual(bescheidStateResource); }); describe('output', () => { - it('should call onWeiter', () => { - component.onWeiter = jest.fn(); + describe('vorgangAbgeschlossen', () => { + it('should call onVorgangAbgeschlossen', () => { + component.onVorgangAbgeschlossen = jest.fn(); - triggerEvent({ - fixture, - name: 'weiterClickEmitter', - elementSelector: bescheidWizard, - }); - - expect(component.onWeiter).toHaveBeenCalled(); - }); - - it('should call onVorgangAbgeschlossen', () => { - component.onVorgangAbgeschlossen = jest.fn(); + triggerEvent({ + fixture, + name: 'vorgangAbgeschlossen', + elementSelector: bescheidWizard, + }); - triggerEvent({ - fixture, - name: 'vorgangAbgeschlossen', - elementSelector: bescheidWizard, + expect(component.onVorgangAbgeschlossen).toHaveBeenCalled(); }); - - expect(component.onVorgangAbgeschlossen).toHaveBeenCalled(); }); }); }); - describe('ods-button close', () => { - it('should show', () => { + describe('close button', () => { + it('should exists', () => { existsAsHtmlElement(fixture, closeButton); }); describe('output', () => { - it('should call cancelWizard', () => { - component.cancelWizard = jest.fn(); + describe('clickEmitter', () => { + it('should call cancelWizard', () => { + component.cancelWizard = jest.fn(); - triggerEvent({ - fixture, - name: 'clickEmitter', - elementSelector: closeButton, - }); + triggerEvent({ + fixture, + name: 'clickEmitter', + elementSelector: closeButton, + }); - expect(component.cancelWizard).toHaveBeenCalled(); + expect(component.cancelWizard).toHaveBeenCalled(); + }); }); }); }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.ts index d3be996f4a86c3236bbc64cfb9ec74baa5f9b761..cba4185d1a3d6805f5291ad6972c11965ed40fc5 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.ts @@ -21,28 +21,19 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidResource, BescheidService, BescheidWizardDialogResult, BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { CommandOrder, CommandResource, isSuccessfulDone } from '@alfa-client/command-shared'; -import { - StateResource, - createEmptyStateResource, - hasStateResourceError, - isEscapeKey, - isLoaded, - isNotLoading, - isNotNil, -} from '@alfa-client/tech-shared'; +import { BescheidResource, BescheidWizardDialogResult, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { CommandOrder, CommandResource, CommandService, isSuccessfulDone } from '@alfa-client/command-shared'; +import { createEmptyStateResource, isEscapeKey, isNotLoading, isNotNil, ResourceRepository, StateResource, } from '@alfa-client/tech-shared'; import { OzgcloudDialogService } from '@alfa-client/ui'; -import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { VorgangService, VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { getEmpfaenger } from '@alfa-client/vorgang-shared-ui'; import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog'; -import { Component, Inject, OnDestroy, OnInit, ViewContainerRef } from '@angular/core'; -import { Resource, hasLink } from '@ngxp/rest'; -import { Observable, Subscription, filter, first, of, switchMap, tap } from 'rxjs'; -import { - BescheidWizardCancelDialogContainerComponent, - CancelWizardDialogData, - CancelWizardDialogResult, -} from './bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component'; +import { Component, inject, OnDestroy, OnInit, ViewContainerRef } from '@angular/core'; +import { hasLink } from '@ngxp/rest'; +import { BescheidResourceService, createBescheidResourceService } from 'libs/bescheid-shared/src/lib/bescheid-resource-service'; +import { filter, first, Observable, of, Subscription, switchMap } from 'rxjs'; +import { BescheidService2 } from '../../../../bescheid-shared/src/lib/bescheid2.service'; +import { BescheidWizardCancelDialogContainerComponent, CancelWizardDialogData, CancelWizardDialogResult, } from './bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component'; import { BescheidFormService } from './bescheid.formservice'; export interface BescheidWizardDialogData { @@ -52,42 +43,63 @@ export interface BescheidWizardDialogData { @Component({ selector: 'alfa-bescheid-wizard-container', templateUrl: './bescheid-wizard-container.component.html', - providers: [BescheidFormService], + providers: [ + BescheidFormService, + BescheidService2, + { + provide: BescheidResourceService, + useFactory: createBescheidResourceService, + deps: [ResourceRepository, CommandService, VorgangService], + }, + ], }) export class BescheidWizardContainerComponent implements OnInit, OnDestroy { + private readonly bescheidService = inject(BescheidService2); + private readonly ozgcloudDialogService = inject(OzgcloudDialogService); + private readonly dialogData: BescheidWizardDialogData = inject(DIALOG_DATA); + private readonly dialogRef = inject(DialogRef<BescheidWizardDialogResult>); + private readonly formService = inject(BescheidFormService); + readonly viewContainerRef = inject(ViewContainerRef); + public bescheidDraftStateResource$: Observable<StateResource<BescheidResource>> = of(createEmptyStateResource<BescheidResource>()); - public submitStateResource$: Observable<StateResource<Resource>> = of(createEmptyStateResource<Resource>()); + public activeStep$: Observable<BescheidWizardStep>; cancelDialogRef: DialogRef<CancelWizardDialogResult>; vorgangWithEingangResource: VorgangWithEingangResource; keydownEventsSubscription: Subscription; - constructor( - @Inject(DIALOG_DATA) private readonly dialogData: BescheidWizardDialogData, - private readonly dialogRef: DialogRef<BescheidWizardDialogResult>, - readonly viewContainerRef: ViewContainerRef, - public readonly formService: BescheidFormService, - readonly bescheidService: BescheidService, - private readonly ozgcloudDialogService: OzgcloudDialogService, - ) { - this.vorgangWithEingangResource = dialogData.vorgangWithEingangResource; + constructor() { + this.vorgangWithEingangResource = this.dialogData.vorgangWithEingangResource; } ngOnInit(): void { this.bescheidService.init(); + this.bescheidService.setNachrichtEmpfaenger(getEmpfaenger(this.vorgangWithEingangResource)); this.formService.setVorgangWithEingangResource(this.vorgangWithEingangResource); + this.activeStep$ = this.bescheidService.getActiveStep(); this.subscribeToBescheidResourceIfExists(); this.handleEscapeKey(); } ngOnDestroy(): void { this.keydownEventsSubscription.unsubscribe(); + this.bescheidService.exit(); } subscribeToBescheidResourceIfExists(): void { if (hasLink(this.vorgangWithEingangResource, VorgangWithEingangLinkRel.BESCHEID_DRAFT)) { this.bescheidDraftStateResource$ = this.bescheidService.getBescheidDraft(); + } else { + this.bescheidService + .getBescheidCreated() + .pipe( + filter((created: boolean) => created), + first(), + ) + .subscribe(() => { + this.bescheidDraftStateResource$ = this.bescheidService.selectBescheidResource(); + }); } } @@ -103,23 +115,6 @@ export class BescheidWizardContainerComponent implements OnInit, OnDestroy { }); } - public onWeiter(nextStep: BescheidWizardStep): void { - this.submitStateResource$ = this.formService.submit().pipe( - switchMap((commandStateResource: StateResource<CommandResource>) => { - if (this.isBescheidSuccessfullyCreated(commandStateResource.resource)) { - this.bescheidDraftStateResource$ = this.bescheidService.getBescheidDraft(); - return this.bescheidDraftStateResource$; - } - return of(commandStateResource); - }), - tap((stateResource: StateResource<Resource>) => { - if (isLoaded(stateResource) && !hasStateResourceError(stateResource)) { - this.bescheidService.setActiveStep(nextStep); - } - }), - ); - } - isBescheidSuccessfullyCreated(commandResource: CommandResource): boolean { return isSuccessfulDone(commandResource) && commandResource.order === CommandOrder.CREATE_BESCHEID; } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.html similarity index 100% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.html rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.html diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.spec.ts similarity index 82% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.spec.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.spec.ts index 82b7402b1b2792d8ddd554934d8b9a5fb8071811..52f9b2e3270123a2dbf0204ef563ba4a38ab5e9c 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.spec.ts @@ -21,31 +21,18 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - createDialogRefMock, - DialogRefMock, - existsAsHtmlElement, - mock, - Mock, - triggerEvent, - useFromMock, -} from '@alfa-client/test-utils'; -import { OzgcloudDialogService } from '@alfa-client/ui'; +import { BescheidResource } from '@alfa-client/bescheid-shared'; +import { createDialogRefMock, DialogRefMock, existsAsHtmlElement, mock, Mock, triggerEvent, useFromMock, } from '@alfa-client/test-utils'; +import { createDialogResult, OzgcloudDialogCommandResult, OzgcloudDialogService } from '@alfa-client/ui'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { EventEmitter } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { of } from 'rxjs'; -import { createSuccessfullyDoneCommandStateResource } from '../../../../../../command-shared/test/command'; -import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; -import { - createDialogResult, - OzgcloudDialogCommandResult, -} from '../../../../../../ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.result'; -import { createVorgangWithEingangResource } from '../../../../../../vorgang-shared/test/vorgang'; -import { - AbschliessenDialogData, - BescheidWizardAbschliessenDialogContainerComponent, -} from '../abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component'; +import { createBescheidResource } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../command-shared/test/command'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { createVorgangWithEingangResource } from '../../../../../../../vorgang-shared/test/vorgang'; +import { AbschliessenDialogData, BescheidWizardAbschliessenDialogContainerComponent, } from '../abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component'; import { BescheidWizardAbschliessenButtonComponent } from './bescheid-wizard-abschliessen-button.component'; describe('BescheidWizardAbschliessenButtonComponent', () => { @@ -89,14 +76,16 @@ describe('BescheidWizardAbschliessenButtonComponent', () => { it('should open dialog', () => { const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource(); + const bescheidResource: BescheidResource = createBescheidResource(); component.vorgangWithEingangResource = vorgangWithEingangResource; + component.bescheidResource = bescheidResource; component.onClick(); expect(ozgcloudDialogService.openInCallingComponentContext).toHaveBeenCalledWith( BescheidWizardAbschliessenDialogContainerComponent, component.viewContainerRef, - { vorgangWithEingangResource } as AbschliessenDialogData, + { vorgangWithEingangResource, bescheidResource } as AbschliessenDialogData, ); }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.ts similarity index 70% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.ts index 506fee1b6090c5bfcaf238d866b95b8cf284c711..c6622e64f1f3ee3dce37cef72ed5371892a7893c 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.ts @@ -21,15 +21,16 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { BescheidResource } from '@alfa-client/bescheid-shared'; import { OzgcloudDialogService } from '@alfa-client/ui'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { DialogRef } from '@angular/cdk/dialog'; -import { Component, EventEmitter, Input, Output, ViewContainerRef } from '@angular/core'; +import { Component, EventEmitter, inject, Input, Output, ViewContainerRef } from '@angular/core'; import { filter } from 'rxjs'; import { - OzgcloudDialogCommandResult, isDialogSuccessfullyCompleted, -} from '../../../../../../ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.result'; + OzgcloudDialogCommandResult, +} from '../../../../../../../ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.result'; import { AbschliessenDialogData, BescheidWizardAbschliessenDialogContainerComponent, @@ -38,35 +39,33 @@ import { @Component({ selector: 'alfa-bescheid-wizard-abschliessen-button', templateUrl: './bescheid-wizard-abschliessen-button.component.html', + styles: [':host {@apply flex-1 flex items-end}'], }) export class BescheidWizardAbschliessenButtonComponent { @Input() vorgangWithEingangResource: VorgangWithEingangResource; + @Input() bescheidResource: BescheidResource; @Output() vorgangAbgeschlossen: EventEmitter<void> = new EventEmitter<void>(); - constructor( - private readonly ozgclouDialogService: OzgcloudDialogService, - readonly viewContainerRef: ViewContainerRef, - ) {} + private readonly ozgcloudDialogService = inject(OzgcloudDialogService); + readonly viewContainerRef = inject(ViewContainerRef); public onClick(): void { const dialogData: AbschliessenDialogData = { vorgangWithEingangResource: this.vorgangWithEingangResource, + bescheidResource: this.bescheidResource, }; - const dialogRef: DialogRef<OzgcloudDialogCommandResult> = - this.ozgclouDialogService.openInCallingComponentContext( - BescheidWizardAbschliessenDialogContainerComponent, - this.viewContainerRef, - dialogData, - ); + const dialogRef: DialogRef<OzgcloudDialogCommandResult> = this.ozgcloudDialogService.openInCallingComponentContext( + BescheidWizardAbschliessenDialogContainerComponent, + this.viewContainerRef, + dialogData, + ); this.handleDialogClosed(dialogRef); } handleDialogClosed(dialogRef: DialogRef<OzgcloudDialogCommandResult>): void { - dialogRef.closed - .pipe(filter(isDialogSuccessfullyCompleted)) - .subscribe(() => this.vorgangAbgeschlossen.emit()); + dialogRef.closed.pipe(filter(isDialogSuccessfullyCompleted)).subscribe(() => this.vorgangAbgeschlossen.emit()); } } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.html similarity index 100% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.html rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.html diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.spec.ts similarity index 75% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.spec.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.spec.ts index 01d76234027235a6d5417fd1ec6758d5d6c4f24b..df6b0e09d088b27f5601ba9b12abf43363b8a0a7 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.spec.ts @@ -21,33 +21,24 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidService } from '@alfa-client/bescheid-shared'; +import { BescheidResource } from '@alfa-client/bescheid-shared'; import { CommandResource } from '@alfa-client/command-shared'; import { StateResource } from '@alfa-client/tech-shared'; -import { - createDialogRefMock, - DialogRefMock, - getElementComponentFromFixtureByCss, - mock, - Mock, - triggerEvent, -} from '@alfa-client/test-utils'; -import { OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; +import { createDialogRefMock, DialogRefMock, getElementComponentFromFixtureByCss, mock, Mock, triggerEvent, } from '@alfa-client/test-utils'; +import { createDialogResult, OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatIcon } from '@angular/material/icon'; import { MockComponent } from 'ng-mocks'; import { of } from 'rxjs'; -import { createSuccessfullyDoneCommandStateResource } from '../../../../../../command-shared/test/command'; -import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; -import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; -import { createDialogResult } from '../../../../../../ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.result'; -import { createVorgangWithEingangResource } from '../../../../../../vorgang-shared/test/vorgang'; -import { - AbschliessenDialogData, - BescheidWizardAbschliessenDialogContainerComponent, -} from './bescheid-wizard-abschliessen-dialog-container.component'; +import { BescheidService2 } from '../../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidResource } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../command-shared/test/command'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../../tech-shared/test/marbles'; +import { createVorgangWithEingangResource } from '../../../../../../../vorgang-shared/test/vorgang'; +import { AbschliessenDialogData, BescheidWizardAbschliessenDialogContainerComponent, } from './bescheid-wizard-abschliessen-dialog-container.component'; describe('BescheidWizardAbschliessenDialogContainerComponent', () => { let component: BescheidWizardAbschliessenDialogContainerComponent; @@ -57,13 +48,14 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { const confirmButtonDataTestId: string = getDataTestIdOf('ueberspringen-abschliessen-button'); const cancelButtonDataTestId: string = getDataTestIdOf('ueberspringen-abbrechen-button'); const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource(); - const dialogData: AbschliessenDialogData = { vorgangWithEingangResource }; + const bescheidResource: BescheidResource = createBescheidResource(); + const dialogData: AbschliessenDialogData = { vorgangWithEingangResource, bescheidResource }; let dialogRef: DialogRefMock; - let bescheidService: Mock<BescheidService>; + let bescheidService: Mock<BescheidService2>; beforeEach(() => { - bescheidService = mock(BescheidService); + bescheidService = mock(BescheidService2); dialogRef = createDialogRefMock(); }); @@ -84,7 +76,7 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { useValue: dialogRef, }, { - provide: BescheidService, + provide: BescheidService2, useValue: bescheidService, }, ], @@ -111,16 +103,16 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { describe('onConfirm', () => { it('should call bescheid service', () => { const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); - bescheidService.bescheidErstellungUeberspringen.mockReturnValue(of(commandStateResource)); + bescheidService.skipBescheidCreation.mockReturnValue(of(commandStateResource)); component.onConfirm(); - expect(bescheidService.bescheidErstellungUeberspringen).toHaveBeenCalledWith(vorgangWithEingangResource); + expect(bescheidService.skipBescheidCreation).toHaveBeenCalledWith(vorgangWithEingangResource, bescheidResource); }); it('should set abschliessen$', () => { const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); - bescheidService.bescheidErstellungUeberspringen.mockReturnValue(of(commandStateResource)); + bescheidService.skipBescheidCreation.mockReturnValue(of(commandStateResource)); component.onConfirm(); @@ -129,7 +121,7 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { it('should close dialog', () => { const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); - bescheidService.bescheidErstellungUeberspringen.mockReturnValue(of(commandStateResource)); + bescheidService.skipBescheidCreation.mockReturnValue(of(commandStateResource)); component.onConfirm(); component.abschliessen$.subscribe(); @@ -140,7 +132,7 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { }); describe('template', () => { - describe('button close', () => { + describe('close button', () => { describe('output', () => { it('should call onClose', () => { component.onClose = jest.fn(); @@ -152,7 +144,7 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { }); }); - describe('ozgcloud-stroked-button-with-spinner Überspringen und abschließen', () => { + describe('überspringen und abschließen button', () => { function getElementComponent(): OzgcloudStrokedButtonWithSpinnerComponent { return getElementComponentFromFixtureByCss(fixture, confirmButtonDataTestId); } @@ -172,18 +164,14 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { it('should call onConfirm', () => { component.onConfirm = jest.fn(); - triggerEvent({ - fixture, - name: 'click', - elementSelector: confirmButtonDataTestId, - }); + triggerEvent({ fixture, name: 'click', elementSelector: confirmButtonDataTestId }); expect(component.onConfirm).toHaveBeenCalled(); }); }); }); - describe('ozgcloud-stroked-button-with-spinner Abbrechen', () => { + describe('abbrechen button', () => { it('should call onClose', () => { component.onClose = jest.fn(); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.ts similarity index 78% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.ts index f147cfea08b03a214884c2d4d5d5c8414df4b4be..5a8ace4040ce03c2e7cff5f2efc3f24877d0f201 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.ts @@ -21,17 +21,19 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidService } from '@alfa-client/bescheid-shared'; +import { BescheidResource } from '@alfa-client/bescheid-shared'; import { CommandResource, tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared'; import { StateResource } from '@alfa-client/tech-shared'; import { createDialogResult } from '@alfa-client/ui'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog'; -import { Component, Inject } from '@angular/core'; +import { Component, inject } from '@angular/core'; import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../../bescheid-shared/src/lib/bescheid2.service'; export interface AbschliessenDialogData { vorgangWithEingangResource: VorgangWithEingangResource; + bescheidResource: BescheidResource; } @Component({ @@ -39,21 +41,20 @@ export interface AbschliessenDialogData { templateUrl: './bescheid-wizard-abschliessen-dialog-container.component.html', }) export class BescheidWizardAbschliessenDialogContainerComponent { - public abschliessen$: Observable<StateResource<CommandResource>>; + private readonly dialogData: AbschliessenDialogData = inject(DIALOG_DATA); + private readonly dialogRef = inject(DialogRef); + private readonly bescheidService = inject(BescheidService2); - constructor( - @Inject(DIALOG_DATA) private readonly dialogData: AbschliessenDialogData, - private readonly dialogRef: DialogRef, - private readonly bescheidService: BescheidService, - ) {} + public abschliessen$: Observable<StateResource<CommandResource>>; public onClose(): void { this.dialogRef.close(); } public onConfirm(): void { + // @ts-ignore this.abschliessen$ = this.bescheidService - .bescheidErstellungUeberspringen(this.dialogData.vorgangWithEingangResource) + .skipBescheidCreation(this.dialogData.vorgangWithEingangResource, this.dialogData.bescheidResource) .pipe( tapOnCommandSuccessfullyDone((commandStateResource: StateResource<CommandResource>) => this.dialogRef.close(createDialogResult(commandStateResource)), diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.html similarity index 75% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.html rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.html index 6d9e44922fc835eaffab2615c9a54659f928a195..025f01d04b1065869baaffd5dc7814c956f6850f 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.html @@ -23,29 +23,25 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<div class="mt-2 grid h-full grid-cols-[min-content_1fr_1fr] gap-7"> - <alfa-bescheid-wizard-stepper - [activeStep]="bescheidWizardStep.AntragBescheiden" - data-test-id="wizard-stepper" - ></alfa-bescheid-wizard-stepper> - <div> - <alfa-bescheid-wizard-step-title label="Antrag bescheiden" data-test-id="wizard-step-title"></alfa-bescheid-wizard-step-title> +<alfa-step-content-layout [activeStep]="BescheidWizardStep.AntragBescheiden"> + <ng-container stepPanel> + <alfa-bescheid-wizard-step-title label="Antrag bescheiden" data-test-id="wizard-step-title" /> <alfa-bescheid-wizard-antrag-bescheiden-form [vorgangWithEingangResource]="vorgangWithEingangResource" [bescheidResource]="bescheidResource" - [submitStateResource]="submitStateResource" - (weiterClickEmitter)="weiterClickEmitter.emit(bescheidWizardStep.DokumenteHochladen)" + (weiterClickEmitter)="onWeiterClick()" data-test-id="antrag-bescheiden-form" ></alfa-bescheid-wizard-antrag-bescheiden-form> <alfa-bescheid-wizard-abschliessen-button [vorgangWithEingangResource]="vorgangWithEingangResource" + [bescheidResource]="bescheidResource" (vorgangAbgeschlossen)="vorgangAbgeschlossen.emit()" data-test-id="wizard-abschliessen-button" ></alfa-bescheid-wizard-abschliessen-button> - </div> - <alfa-bescheid-wizard-summary data-test-id="wizard-summary"> + </ng-container> + <ng-container summary> <alfa-bescheid-wizard-antrag-bescheiden-summary data-test-id="antrag-bescheiden-summary" ></alfa-bescheid-wizard-antrag-bescheiden-summary> - </alfa-bescheid-wizard-summary> -</div> + </ng-container> +</alfa-step-content-layout> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.spec.ts similarity index 54% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.spec.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.spec.ts index a2a12395ea886598dae1607d5836a41dc2602097..d3452acaabaa91d8cced04afc925138dd1d2d546 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.spec.ts @@ -21,44 +21,43 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidService, BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { Mock, existsAsHtmlElement, getElementFromFixtureByType, mock, triggerEvent, useFromMock } from '@alfa-client/test-utils'; +import { existsAsHtmlElement, getElementFromFixtureByType, Mock, mock, triggerEvent, useFromMock } from '@alfa-client/test-utils'; import { EventEmitter } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockComponent } from 'ng-mocks'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; import { createBescheidResource } from '../../../../../../bescheid-shared/src/test/bescheid'; -import { createCommandStateResource } from '../../../../../../command-shared/test/command'; import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; import { createVorgangWithEingangResource } from '../../../../../../vorgang-shared/test/vorgang'; -import { BescheidWizardAbschliessenButtonComponent } from '../abschliessen-button/bescheid-wizard-abschliessen-button.component'; +import { StepContentLayoutComponent } from '../step-content-layout/step-content-layout.component'; import { BescheidWizardStepTitleComponent } from '../step-title/bescheid-wizard-step-title.component'; import { BescheidWizardStepperComponent } from '../stepper/bescheid-wizard-stepper.component'; import { BescheidWizardSummaryComponent } from '../summary/bescheid-wizard-summary.component'; -import { BescheidWizardAntragBescheidenComponent } from './bescheid-wizard-antrag-bescheiden.component'; +import { BescheidWizardAbschliessenButtonComponent } from './abschliessen-button/bescheid-wizard-abschliessen-button.component'; +import { BescheidWizardAntragBescheidenContainerComponent } from './bescheid-wizard-antrag-bescheiden-container.component'; import { BescheidWizardAntragBescheidenFormComponent } from './form/bescheid-wizard-antrag-bescheiden-form.component'; import { BescheidWizardAntragBescheidenSummaryComponent } from './summary/bescheid-wizard-antrag-bescheiden-summary.component'; describe('BescheidWizardAntragBescheidenComponent', () => { - let component: BescheidWizardAntragBescheidenComponent; - let fixture: ComponentFixture<BescheidWizardAntragBescheidenComponent>; + let component: BescheidWizardAntragBescheidenContainerComponent; + let fixture: ComponentFixture<BescheidWizardAntragBescheidenContainerComponent>; - const wizardStepper: string = getDataTestIdOf('wizard-stepper'); const wizardStepTitle: string = getDataTestIdOf('wizard-step-title'); const antragBescheidenForm: string = getDataTestIdOf('antrag-bescheiden-form'); const abschliessenButton: string = getDataTestIdOf('wizard-abschliessen-button'); - const wizardSummary: string = getDataTestIdOf('wizard-summary'); const antragBescheidenSummary: string = getDataTestIdOf('antrag-bescheiden-summary'); - let bescheidService: Mock<BescheidService>; + let bescheidService: Mock<BescheidService2>; beforeEach(() => { - bescheidService = mock(BescheidService); + bescheidService = mock(BescheidService2); }); beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ - BescheidWizardAntragBescheidenComponent, + BescheidWizardAntragBescheidenContainerComponent, + MockComponent(StepContentLayoutComponent), MockComponent(BescheidWizardStepTitleComponent), MockComponent(BescheidWizardAntragBescheidenFormComponent), MockComponent(BescheidWizardSummaryComponent), @@ -68,15 +67,14 @@ describe('BescheidWizardAntragBescheidenComponent', () => { ], providers: [ { - provide: BescheidService, + provide: BescheidService2, useValue: bescheidService, }, ], }).compileComponents(); - fixture = TestBed.createComponent(BescheidWizardAntragBescheidenComponent); + fixture = TestBed.createComponent(BescheidWizardAntragBescheidenContainerComponent); component = fixture.componentInstance; - component.weiterClickEmitter = useFromMock(mock(EventEmitter<BescheidWizardStep>)); component.vorgangAbgeschlossen = useFromMock(mock(EventEmitter<void>)); fixture.detectChanges(); }); @@ -86,121 +84,75 @@ describe('BescheidWizardAntragBescheidenComponent', () => { }); describe('template', () => { - describe('alfa-bescheid-wizard-stepper', () => { - function getElementComponent(): BescheidWizardStepperComponent { - return getElementFromFixtureByType(fixture, BescheidWizardStepperComponent); + describe('wizard step title', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, wizardStepTitle); + }); + }); + + describe('antrag bescheiden form', () => { + function getElementComponent(): BescheidWizardAntragBescheidenFormComponent { + return getElementFromFixtureByType(fixture, BescheidWizardAntragBescheidenFormComponent); } it('should exists', () => { - fixture.detectChanges(); - - existsAsHtmlElement(fixture, wizardStepper); + existsAsHtmlElement(fixture, antragBescheidenForm); }); - describe('input', () => { - it('should set activeStep', () => { - fixture.detectChanges(); + it('should have been called with inputs', () => { + component.vorgangWithEingangResource = createVorgangWithEingangResource(); + component.bescheidResource = createBescheidResource(); - expect(getElementComponent().activeStep).toBe(BescheidWizardStep.AntragBescheiden); - }); - }); - }); + fixture.detectChanges(); - describe('alfa-bescheid-wizard-step-title', () => { - it('should show', () => { - existsAsHtmlElement(fixture, wizardStepTitle); + expect(getElementComponent().vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); + expect(getElementComponent().bescheidResource).toBe(component.bescheidResource); }); - }); - describe('alfa-bescheid-wizard-summary', () => { - it('should show', () => { - existsAsHtmlElement(fixture, wizardSummary); - }); - }); + describe('output', () => { + describe('weiterClickEmitter', () => { + it('should call handler', () => { + component.onWeiterClick = jest.fn(); - describe('alfa-bescheid-wizard-antrag-bescheiden-summary', () => { - it('should show', () => { - existsAsHtmlElement(fixture, antragBescheidenSummary); + triggerEvent({ fixture, name: 'weiterClickEmitter', elementSelector: antragBescheidenForm }); + + expect(component.onWeiterClick).toHaveBeenCalled(); + }); + }); }); }); - describe('alfa-bescheid-wizard-abschliessen-button', () => { + describe('abschliessen button', () => { function getElementComponent(): BescheidWizardAbschliessenButtonComponent { return getElementFromFixtureByType(fixture, BescheidWizardAbschliessenButtonComponent); } - it('should show', () => { + it('should exists', () => { existsAsHtmlElement(fixture, abschliessenButton); }); - describe('input', () => { - it('should set vorgangWithEingangResource', () => { - component.vorgangWithEingangResource = createVorgangWithEingangResource(); + it('should have been called with inputs', () => { + component.vorgangWithEingangResource = createVorgangWithEingangResource(); + component.bescheidResource = createBescheidResource(); - fixture.detectChanges(); + fixture.detectChanges(); - expect(getElementComponent().vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); - }); + expect(getElementComponent().vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); + expect(getElementComponent().bescheidResource).toBe(component.bescheidResource); }); describe('output', () => { - it('should call onVorgangAbgeschlossen', () => { - triggerEvent({ - fixture, - name: 'vorgangAbgeschlossen', - elementSelector: abschliessenButton, - }); + it('should call handler', () => { + triggerEvent({ fixture, name: 'vorgangAbgeschlossen', elementSelector: abschliessenButton }); expect(component.vorgangAbgeschlossen.emit).toHaveBeenCalled(); }); }); }); - describe('alfa-bescheid-wizard-antrag-bescheiden-form', () => { - function getElementComponent(): BescheidWizardAntragBescheidenFormComponent { - return getElementFromFixtureByType(fixture, BescheidWizardAntragBescheidenFormComponent); - } - - it('should show', () => { - existsAsHtmlElement(fixture, antragBescheidenForm); - }); - - describe('input', () => { - it('should set vorgangWithEingangResource', () => { - component.vorgangWithEingangResource = createVorgangWithEingangResource(); - - fixture.detectChanges(); - - expect(getElementComponent().vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); - }); - - it('should set bescheidResource', () => { - component.bescheidResource = createBescheidResource(); - - fixture.detectChanges(); - - expect(getElementComponent().bescheidResource).toBe(component.bescheidResource); - }); - - it('should set submitStateResource', () => { - component.submitStateResource = createCommandStateResource(); - - fixture.detectChanges(); - - expect(getElementComponent().submitStateResource).toBe(component.submitStateResource); - }); - }); - - describe('output', () => { - it('should emit weiterClickEmitter', () => { - triggerEvent({ - fixture, - name: 'weiterClickEmitter', - elementSelector: antragBescheidenForm, - }); - - expect(component.weiterClickEmitter.emit).toHaveBeenCalledWith(BescheidWizardStep.DokumenteHochladen); - }); + describe('antrag bescheiden summary', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, antragBescheidenSummary); }); }); }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.ts similarity index 68% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.ts index 2dcbf71a91305c14e8c10cd4b8c4130f1609f715..9837cbe2bca5ed1e8ff4f9674d10895c476d7faf 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.ts @@ -22,22 +22,25 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { BescheidResource, BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { StateResource } from '@alfa-client/tech-shared'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Resource } from '@ngxp/rest'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; @Component({ - selector: 'alfa-bescheid-wizard-antrag-bescheiden', - templateUrl: './bescheid-wizard-antrag-bescheiden.component.html', + selector: 'alfa-bescheid-wizard-antrag-bescheiden-container', + templateUrl: './bescheid-wizard-antrag-bescheiden-container.component.html', }) -export class BescheidWizardAntragBescheidenComponent { +export class BescheidWizardAntragBescheidenContainerComponent { @Input() vorgangWithEingangResource: VorgangWithEingangResource; @Input() bescheidResource: BescheidResource; - @Input() submitStateResource: StateResource<Resource>; - @Output() weiterClickEmitter: EventEmitter<BescheidWizardStep> = new EventEmitter<BescheidWizardStep>(); @Output() vorgangAbgeschlossen: EventEmitter<void> = new EventEmitter<void>(); - public readonly bescheidWizardStep = BescheidWizardStep; + private readonly bescheidService = inject(BescheidService2); + + public readonly BescheidWizardStep = BescheidWizardStep; + + public onWeiterClick(): void { + this.bescheidService.setActiveStep(BescheidWizardStep.DokumenteHochladen); + } } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.html index 5d3a471c46056ef89c8d3995ce0591519fd97bbc..8861db5df5fd7745a5061fecd7fead4301583384 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.html @@ -24,7 +24,7 @@ --> <div [formGroup]="formService.form" role="radiogroup" aria-label="Bescheidstatus"> - <div class="my-10 flex max-w-2xl gap-8"> + <div class="my-10 flex flex-wrap gap-8"> <ods-radio-button-card label="bewilligt" [name]="formServiceClass.FIELD_BEWILLIGT" @@ -52,12 +52,13 @@ </ozgcloud-date-editor> </div> </div> -<alfa-bescheid-wizard-weiter-button - *ngIf=" - (vorgangWithEingangResource | hasLink: vorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT) || - (bescheidResource | hasLink: bescheidLinkRel.UPDATE) - " - [submitStateResource]="submitStateResource" - (clickEmitter)="weiterClickEmitter.emit()" - data-test-id="weiter-button" -></alfa-bescheid-wizard-weiter-button> +@if ( + (vorgangWithEingangResource | hasLink: vorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT) || + (bescheidResource | hasLink: bescheidLinkRel.UPDATE) +) { + <alfa-bescheid-wizard-weiter-button + [submitStateResource]="submitStateResource$ | async" + (clickEmitter)="submit()" + data-test-id="weiter-button" + ></alfa-bescheid-wizard-weiter-button> +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.spec.ts index fb9b631931e637501aefed12255c8b44284b0167..fc15a7f9282febbd25179f0b255a5781234bfb86 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.spec.ts @@ -21,9 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidLinkRel, BescheidService } from '@alfa-client/bescheid-shared'; -import { HasLinkPipe } from '@alfa-client/tech-shared'; -import { existsAsHtmlElement, mock, notExistsAsHtmlElement, triggerEvent, useFromMock } from '@alfa-client/test-utils'; +import { BescheidLinkRel } from '@alfa-client/bescheid-shared'; +import { CommandResource } from '@alfa-client/command-shared'; +import { createEmptyStateResource, HasLinkPipe, StateResource } from '@alfa-client/tech-shared'; +import { existsAsHtmlElement, getElementFromFixtureByType, mock, notExistsAsHtmlElement, triggerEvent, useFromMock, } from '@alfa-client/test-utils'; import { DateEditorComponent } from '@alfa-client/ui'; import { VorgangWithEingangLinkRel } from '@alfa-client/vorgang-shared'; import { EventEmitter } from '@angular/core'; @@ -31,8 +32,12 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; import { CloseIconComponent, RadioButtonCardComponent, StampIconComponent } from '@ods/system'; import { MockComponent } from 'ng-mocks'; +import { EMPTY, of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../../bescheid-shared/src/lib/bescheid2.service'; import { createBescheidResource } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../command-shared/test/command'; import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../../tech-shared/test/marbles'; import { createVorgangWithEingangResource } from '../../../../../../../vorgang-shared/test/vorgang'; import { BescheidFormService } from '../../../bescheid.formservice'; import { BescheidWizardWeiterButtonComponent } from '../../weiter-button/bescheid-wizard-weiter-button.component'; @@ -47,7 +52,8 @@ describe('BescheidWizardAntragBescheidenFormComponent', () => { let formService: BescheidFormService; beforeEach(async () => { - formService = new BescheidFormService(new UntypedFormBuilder(), useFromMock(mock(BescheidService))); + formService = new BescheidFormService(new UntypedFormBuilder(), useFromMock(mock(BescheidService2))); + formService.submit = jest.fn().mockReturnValue(EMPTY); await TestBed.configureTestingModule({ declarations: [ @@ -74,12 +80,35 @@ describe('BescheidWizardAntragBescheidenFormComponent', () => { fixture.detectChanges(); }); - it('should create', () => { - expect(component).toBeTruthy(); + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.submitStateResource$).toBeObservable(singleColdCompleted(createEmptyStateResource())); + }); + + describe('submit', () => { + it('should call form service', () => { + component.submit(); + + expect(formService.submit).toHaveBeenCalled(); + }); + + it('should emit weiter click', () => { + formService.submit = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(component.weiterClickEmitter.emit).toHaveBeenCalled(); + }); + }); }); describe('template', () => { - describe('alfa-bescheid-wizard-weiter-button', () => { + describe('weiter button', () => { it('should exists if bescheid update link exists', () => { component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); @@ -98,7 +127,7 @@ describe('BescheidWizardAntragBescheidenFormComponent', () => { existsAsHtmlElement(fixture, weiterButton); }); - it('should not exists if update and create links missing', () => { + it('should NOT exists if update and create links missing', () => { component.vorgangWithEingangResource = createVorgangWithEingangResource(); component.bescheidResource = createBescheidResource(); @@ -107,7 +136,7 @@ describe('BescheidWizardAntragBescheidenFormComponent', () => { notExistsAsHtmlElement(fixture, weiterButton); }); - it('should not exists if update link missing', () => { + it('should NOT exists if update link missing', () => { component.bescheidResource = createBescheidResource(); fixture.detectChanges(); @@ -115,19 +144,36 @@ describe('BescheidWizardAntragBescheidenFormComponent', () => { notExistsAsHtmlElement(fixture, weiterButton); }); + it('should have been called with inputs', (done) => { + component.vorgangWithEingangResource = createVorgangWithEingangResource([ + VorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT, + ]); + + fixture.detectChanges(); + + const weiterButtonComponent: BescheidWizardWeiterButtonComponent = getElementFromFixtureByType( + fixture, + BescheidWizardWeiterButtonComponent, + ); + + component.submitStateResource$.subscribe((submitStateResource: StateResource<CommandResource>) => { + expect(weiterButtonComponent.submitStateResource).toEqual(submitStateResource); + done(); + }); + }); + describe('output', () => { - it('should emit weiterClickEmitter', () => { - component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); + describe('clickEmitter', () => { + it('should submit', () => { + component.submit = jest.fn(); + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); - fixture.detectChanges(); + fixture.detectChanges(); - triggerEvent({ - fixture, - name: 'clickEmitter', - elementSelector: weiterButton, - }); + triggerEvent({ fixture, name: 'clickEmitter', elementSelector: weiterButton }); - expect(component.weiterClickEmitter.emit).toHaveBeenCalled(); + expect(component.submit).toHaveBeenCalled(); + }); }); }); }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.ts index 5806f5dcf9a2ecb1cf45d737419fe19da8f546ec..5c9c0ab6365f39586a6b9809fbd41ecba860a869 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.ts @@ -22,10 +22,11 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { BescheidLinkRel, BescheidResource } from '@alfa-client/bescheid-shared'; -import { StateResource } from '@alfa-client/tech-shared'; +import { CommandResource, tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared'; +import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Resource } from '@ngxp/rest'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { Observable, of } from 'rxjs'; import { BescheidFormService } from '../../../bescheid.formservice'; @Component({ @@ -35,13 +36,20 @@ import { BescheidFormService } from '../../../bescheid.formservice'; export class BescheidWizardAntragBescheidenFormComponent { @Input() vorgangWithEingangResource: VorgangWithEingangResource; @Input() bescheidResource: BescheidResource; - @Input() submitStateResource: StateResource<Resource>; @Output() weiterClickEmitter = new EventEmitter<void>(); + public readonly formService = inject(BescheidFormService); + + public submitStateResource$: Observable<StateResource<CommandResource>> = of(createEmptyStateResource<CommandResource>()); + public readonly vorgangWithEingangLinkRel = VorgangWithEingangLinkRel; public readonly bescheidLinkRel = BescheidLinkRel; public readonly formServiceClass = BescheidFormService; - constructor(public readonly formService: BescheidFormService) {} + public submit(): void { + this.submitStateResource$ = this.formService + .submit() + .pipe(tapOnCommandSuccessfullyDone(() => this.weiterClickEmitter.emit())); + } } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component.spec.ts index e4d89586aec9b233d612f87877efdd1298a8c318..571478e90cb9e5e00e8f79f7d695c475416cf95e 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component.spec.ts @@ -60,18 +60,20 @@ describe('BescheidWizardAntragBescheidenSummaryComponent', () => { }); describe('template', () => { - describe('ods-bescheid-status-text', () => { + describe('status text', () => { function getElementComponent(): BescheidStatusTextComponent { return getElementFromFixtureByType(fixture, BescheidStatusTextComponent); } - it('should subscribe to bescheid value form changes', () => { + it('should exists', () => { + formService.getBescheidFormValueChanges.mockReturnValue(of(createBescheid())); + fixture.detectChanges(); - expect(formService.getBescheidFormValueChanges).toHaveBeenCalled(); + existsAsHtmlElement(fixture, bescheidStatusText); }); - it('should NOT show', () => { + it('should NOT exists', () => { formService.getBescheidFormValueChanges.mockReturnValue(EMPTY); fixture.detectChanges(); @@ -79,41 +81,21 @@ describe('BescheidWizardAntragBescheidenSummaryComponent', () => { notExistsAsHtmlElement(fixture, bescheidStatusText); }); - it('should show', () => { - formService.getBescheidFormValueChanges.mockReturnValue(of(createBescheid())); - + it('should subscribe to bescheid value form changes', () => { fixture.detectChanges(); - existsAsHtmlElement(fixture, bescheidStatusText); + expect(formService.getBescheidFormValueChanges).toHaveBeenCalled(); }); - describe('input', () => { - it('should set bewilligt', () => { - const bescheid: Bescheid = createBescheid(); - formService.getBescheidFormValueChanges.mockReturnValue(of(bescheid)); - - fixture.detectChanges(); - - expect(getElementComponent().bewilligt).toBe(bescheid.bewilligt); - }); - - it('should set dateText', () => { - const bescheid: Bescheid = { ...createBescheid(), beschiedenAm: '2024-01-01' }; - formService.getBescheidFormValueChanges.mockReturnValue(of(bescheid)); + it('should have been called with inputs', () => { + const bescheid: Bescheid = createBescheid(); + formService.getBescheidFormValueChanges.mockReturnValue(of(bescheid)); - fixture.detectChanges(); - - expect(getElementComponent().dateText).toBe('01.01.2024'); - }); - - it('should set hasBescheidDraft', () => { - const bescheid: Bescheid = createBescheid(); - formService.getBescheidFormValueChanges.mockReturnValue(of(bescheid)); - - fixture.detectChanges(); + fixture.detectChanges(); - expect(getElementComponent().hasBescheidDraft).toBeFalsy(); - }); + expect(getElementComponent().bewilligt).toBe(bescheid.bewilligt); + expect(getElementComponent().dateText).toBe('01.01.2024'); + expect(getElementComponent().hasBescheidDraft).toBeFalsy(); }); }); }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.html new file mode 100644 index 0000000000000000000000000000000000000000..622107cd6a88a6410e8c7bcdc7e08fd262f1635b --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.html @@ -0,0 +1,21 @@ +<ods-attachment-wrapper> + @for (attachment of attachments; track $index) { + <alfa-binary-file2-container + [file]="attachment" + [deletable]="deletable" + (startDelete)="delete.emit($event)" + [attr.data-test-id]="(attachment.name | convertForDataTest) + '-file2-container'" + > + </alfa-binary-file2-container> + } + @if (upload.loading || upload.error) { + <ods-attachment + [loadingCaption]="upload.fileName" + errorCaption="Fehler beim Hochladen" + [errorMessages]="upload.error | convertProblemDetailToErrorMessages" + description="Anhang wird hochgeladen" + [isLoading]="upload.loading" + data-test-id="attachment-upload-in-progress" + ></ods-attachment> + } +</ods-attachment-wrapper> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..92f027903e7ddb01410294bcced6f60759882b68 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.spec.ts @@ -0,0 +1,165 @@ +import { BescheidAttachments, createEmptyBescheidAttachments, createEmptyUploadInProgress } from '@alfa-client/bescheid-shared'; +import { BinaryFile2ContainerComponent } from '@alfa-client/binary-file'; +import { ConvertForDataTestPipe, ConvertProblemDetailToErrorMessagesPipe, ProblemDetail } from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + notExistsAsHtmlElement, + triggerEvent, +} from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { AttachmentComponent, AttachmentWrapperComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { createBescheidAttachments } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { createProblemDetail } from '../../../../../../../tech-shared/test/error'; +import { BescheidWizardAttachmentFilesComponent } from './bescheid-wizard-attachment-files.component'; + +describe('BescheidWizardAttachmentFileComponent', () => { + let component: BescheidWizardAttachmentFilesComponent; + let fixture: ComponentFixture<BescheidWizardAttachmentFilesComponent>; + + const convertForDataTest: ConvertForDataTestPipe = new ConvertForDataTestPipe(); + const convertProblemDetailsToErrorMessage: ConvertProblemDetailToErrorMessagesPipe = + new ConvertProblemDetailToErrorMessagesPipe(); + + const attachments: BescheidAttachments = createBescheidAttachments(); + + const binaryFileContainerTestId: string = getDataTestIdOf( + convertForDataTest.transform(attachments.items[0].name) + '-file2-container', + ); + const attachmentUploadTestId: string = getDataTestIdOf('attachment-upload-in-progress'); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardAttachmentFilesComponent, + MockComponent(BinaryFile2ContainerComponent), + MockComponent(AttachmentComponent), + MockComponent(AttachmentWrapperComponent), + ConvertForDataTestPipe, + ConvertProblemDetailToErrorMessagesPipe, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardAttachmentFilesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.upload).toEqual(createEmptyUploadInProgress()); + expect(component.attachments).toEqual(createEmptyBescheidAttachments().items); + }); + + describe('set attachments', () => { + it('should set attachments', () => { + component.attachments = attachments; + + expect(component.attachments).toEqual(attachments.items); + }); + + it('should set upload', () => { + component.attachments = attachments; + + expect(component.upload).toEqual(attachments.upload); + }); + }); + }); + + describe('template', () => { + describe('attachment binary file container', () => { + it('should exists', () => { + component.attachments = attachments; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, binaryFileContainerTestId); + }); + + it('should have been called with inputs', () => { + component.attachments = attachments; + + fixture.detectChanges(); + const binaryFileComponent: BinaryFile2ContainerComponent = + getElementComponentFromFixtureByCss<BinaryFile2ContainerComponent>(fixture, binaryFileContainerTestId); + + expect(binaryFileComponent.file).toEqual(attachments.items[0]); + expect(binaryFileComponent.deletable).toEqual(component.deletable); + }); + + describe('output', () => { + describe('startDelete', () => { + it('should emit', () => { + component.attachments = attachments; + component.delete.emit = jest.fn(); + + fixture.detectChanges(); + + triggerEvent({ + fixture, + elementSelector: binaryFileContainerTestId, + name: 'startDelete', + data: attachments.items[0], + }); + + expect(component.delete.emit).toHaveBeenCalledWith(attachments.items[0]); + }); + }); + }); + }); + + describe('upload attachment', () => { + it('should exists on loading', () => { + component.attachments = { ...attachments, upload: { ...attachments.upload, loading: true, error: null } }; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, attachmentUploadTestId); + }); + + it('should exists on error', () => { + component.attachments = { + ...attachments, + upload: { ...attachments.upload, loading: false, error: createProblemDetail() }, + }; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, attachmentUploadTestId); + }); + + it('should NOT exists', () => { + component.attachments = { + ...attachments, + upload: { ...attachments.upload, loading: false, error: null }, + }; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, attachmentUploadTestId); + }); + + it('should have been called with inputs', () => { + component.attachments = attachments; + + fixture.detectChanges(); + const attachmentComponent: AttachmentComponent = getElementComponentFromFixtureByCss<AttachmentComponent>( + fixture, + attachmentUploadTestId, + ); + + expect(attachmentComponent.loadingCaption).toEqual(attachments.upload.fileName); + expect(attachmentComponent.errorMessages).toEqual( + convertProblemDetailsToErrorMessage.transform(attachments.upload.error as ProblemDetail), + ); + expect(attachmentComponent.isLoading).toEqual(attachments.upload.loading); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..b5a60cd795a7f6b7b918ce39a5fd5b45c1b3cb63 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.ts @@ -0,0 +1,30 @@ +import { + BescheidAttachments, + createEmptyBescheidAttachments, + createEmptyUploadInProgress, + UploadFileInProgress, +} from '@alfa-client/bescheid-shared'; +import { BinaryFileResource } from '@alfa-client/binary-file-shared'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +@Component({ + selector: 'alfa-bescheid-wizard-attachment-files', + templateUrl: './bescheid-wizard-attachment-files.component.html', +}) +export class BescheidWizardAttachmentFilesComponent { + @Input() set attachments(value: BescheidAttachments) { + this._attachments = value; + this.upload = value.upload; + } + + get attachments(): BinaryFileResource[] { + return this._attachments.items; + } + + @Input() deletable: boolean; + + @Output() delete: EventEmitter<BinaryFileResource> = new EventEmitter(); + + public upload: UploadFileInProgress = createEmptyUploadInProgress(); + private _attachments: BescheidAttachments = createEmptyBescheidAttachments(); +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..c34bfce43f0959f56aa16e8a993f31b61bec0839 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.html @@ -0,0 +1,6 @@ +<alfa-bescheid-wizard-attachment-files + [attachments]="attachments$ | async" + [deletable]="(activeStep$ | async) === bescheidWizardStep.DokumenteHochladen" + (delete)="deleteAttachment($event)" + data-test-id="bescheid-attachments" +></alfa-bescheid-wizard-attachment-files> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..9c2cdd8df598bfddfb8b6fc3512066f44d58cc65 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.spec.ts @@ -0,0 +1,123 @@ +import { BescheidAttachments, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { BinaryFileResource } from '@alfa-client/binary-file-shared'; +import { existsAsHtmlElement, getElementComponentFromFixtureByCss, mock, Mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidAttachments } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { createBinaryFileResource } from '../../../../../../binary-file-shared/test/binary-file'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { BescheidWizardAttachmentFilesComponent } from './attachment-files/bescheid-wizard-attachment-files.component'; +import { BescheidWizardAttachmentFilesContainerComponent } from './bescheid-wizard-attachment-files-container.component'; + +describe('BescheidWizardAttachmentFileContainerComponent', () => { + let component: BescheidWizardAttachmentFilesContainerComponent; + let fixture: ComponentFixture<BescheidWizardAttachmentFilesContainerComponent>; + + const attachmentsFilesTestId: string = getDataTestIdOf('bescheid-attachments'); + + const attachments: BescheidAttachments = createBescheidAttachments(); + + let bescheidService: Mock<BescheidService2>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BescheidWizardAttachmentFilesContainerComponent, MockComponent(BescheidWizardAttachmentFilesComponent)], + providers: [{ provide: BescheidService2, useValue: bescheidService }], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardAttachmentFilesContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('ngOnInit', () => { + it('should set attachments', () => { + bescheidService.getAttachments.mockReturnValue(of(attachments)); + + component.ngOnInit(); + + expect(component.attachments$).toBeObservable(singleColdCompleted(attachments)); + }); + + it('should set active step', () => { + bescheidService.getActiveStep.mockReturnValue(of(BescheidWizardStep.BescheidVersenden)); + + component.ngOnInit(); + + expect(component.activeStep$).toBeObservable(singleColdCompleted(BescheidWizardStep.BescheidVersenden)); + }); + }); + + describe('deleteAttachment', () => { + it('should call service', () => { + component.deleteAttachment = jest.fn(); + const binaryFileResource: BinaryFileResource = createBinaryFileResource(); + + component.deleteAttachment(binaryFileResource); + + expect(component.deleteAttachment).toHaveBeenCalledWith(binaryFileResource); + }); + }); + }); + + describe('template', () => { + describe('attachment files', () => { + function getComponent(): BescheidWizardAttachmentFilesComponent { + return getElementComponentFromFixtureByCss<BescheidWizardAttachmentFilesComponent>(fixture, attachmentsFilesTestId); + } + + it('should exists', () => { + existsAsHtmlElement(fixture, attachmentsFilesTestId); + }); + + it('should have been called with attachments', () => { + component.attachments$ = of(attachments); + + fixture.detectChanges(); + + expect(getComponent().attachments).toEqual(attachments); + }); + + it('should have been called with deletable true', () => { + component.activeStep$ = of(BescheidWizardStep.DokumenteHochladen); + + fixture.detectChanges(); + + expect(getComponent().deletable).toEqual(true); + }); + + it('should have been called with deletable false', () => { + component.activeStep$ = of(BescheidWizardStep.BescheidVersenden); + + fixture.detectChanges(); + + expect(getComponent().deletable).toEqual(false); + }); + + describe('output', () => { + describe('delete', () => { + it('should call handler', () => { + const binaryFileResource: BinaryFileResource = createBinaryFileResource(); + component.deleteAttachment = jest.fn(); + + triggerEvent({ fixture, elementSelector: attachmentsFilesTestId, name: 'delete', data: binaryFileResource }); + + expect(component.deleteAttachment).toHaveBeenCalledWith(binaryFileResource); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..50d2dea88ea12ba5fec926d895ff47044f017409 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.ts @@ -0,0 +1,27 @@ +import { BescheidAttachments, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { BinaryFileResource } from '@alfa-client/binary-file-shared'; +import { Component, inject, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; + +@Component({ + selector: 'alfa-bescheid-wizard-attachment-files-container', + templateUrl: './bescheid-wizard-attachment-files-container.component.html', +}) +export class BescheidWizardAttachmentFilesContainerComponent implements OnInit { + public readonly bescheidService = inject(BescheidService2); + + public attachments$: Observable<BescheidAttachments>; + public activeStep$: Observable<BescheidWizardStep>; + + public readonly bescheidWizardStep = BescheidWizardStep; + + ngOnInit(): void { + this.attachments$ = this.bescheidService.getAttachments(); + this.activeStep$ = this.bescheidService.getActiveStep(); + } + + public deleteAttachment(binaryFileResource: BinaryFileResource): void { + this.bescheidService.deleteAttachment(binaryFileResource); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..ebb663b568ce2cddf824bba0988d46ed38c3c6e8 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.html @@ -0,0 +1,30 @@ +<alfa-step-content-layout + [activeStep]="bescheidWizardStep.BescheidVersenden" + (stepChange)="onStepChange($event)" + data-test-id="step-content-layout" +> + <ng-container stepPanel> + <alfa-bescheid-wizard-step-title + label="Antrag bescheiden" + [inactiveStep]="true" + data-test-id="antrag-bescheiden-step-title" + /> + <alfa-bescheid-wizard-step-title + label="Dokumente hinzufügen" + [inactiveStep]="true" + data-test-id="dokumente-hochladen-step-title" + /> + <alfa-bescheid-wizard-step-title label="Bescheid versenden" /> + <alfa-bescheid-wizard-bescheid-versenden-form + [bescheidResource]="bescheidResource" + (sendBy)="onSendBy($event)" + data-test-id="bescheid-wizard-bescheid-versenden-form" + /> + </ng-container> + <ng-container summary> + <alfa-bescheid-wizard-bescheid-versenden-summary + [bescheidResource]="bescheidResource" + [wizard]="wizard$ | async" + data-test-id="bescheiden-result" + /> </ng-container +></alfa-step-content-layout> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..abdb3be7cef699e775c5bbc324911d1ef71b7127 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.spec.ts @@ -0,0 +1,184 @@ +import { BescheidResource, BescheidSendBy, BescheidWizardStep, Wizard } from '@alfa-client/bescheid-shared'; +import { existsAsHtmlElement, getElementComponentFromFixtureByCss, mock, Mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidResource, createWizard } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { StepContentLayoutComponent } from '../step-content-layout/step-content-layout.component'; +import { BescheidWizardStepTitleComponent } from '../step-title/bescheid-wizard-step-title.component'; +import { BescheidWizardSummaryComponent } from '../summary/bescheid-wizard-summary.component'; +import { BescheidWizardBescheidVersendenContainerComponent } from './bescheid-wizard-bescheid-versenden-container.component'; +import { BescheidWizardBescheidVersendenFormComponent } from './form/bescheid-wizard-bescheid-versenden-form.component'; +import { BescheidWizardBescheidVersendenSummaryComponent } from './summary/bescheid-wizard-bescheid-versenden-summary.component'; + +describe('BescheidWizardBescheidVersendenComponent', () => { + let component: BescheidWizardBescheidVersendenContainerComponent; + let fixture: ComponentFixture<BescheidWizardBescheidVersendenContainerComponent>; + + const stepContentLayout: string = getDataTestIdOf('step-content-layout'); + const antragBescheidenStepTitleTestId: string = getDataTestIdOf('antrag-bescheiden-step-title'); + const dokumenteHochladenStepTitleTestId: string = getDataTestIdOf('dokumente-hochladen-step-title'); + const formTestId: string = getDataTestIdOf('bescheid-wizard-bescheid-versenden-form'); + const versendenSummaryTestId: string = getDataTestIdOf('bescheiden-result'); + + const bescheidResource: BescheidResource = createBescheidResource(); + + let bescheidService: Mock<BescheidService2>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardBescheidVersendenContainerComponent, + MockComponent(StepContentLayoutComponent), + MockComponent(BescheidWizardStepTitleComponent), + MockComponent(BescheidWizardBescheidVersendenFormComponent), + MockComponent(BescheidWizardSummaryComponent), + MockComponent(BescheidWizardBescheidVersendenSummaryComponent), + ], + providers: [{ provide: BescheidService2, useValue: bescheidService }], + }).compileComponents(); + + createComponent(); + }); + + function createComponent() { + fixture = TestBed.createComponent(BescheidWizardBescheidVersendenContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + } + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + const wizard: Wizard = createWizard(); + bescheidService.getWizard.mockReturnValue(of(wizard)); + + createComponent(); + + expect(component.wizard$).toBeObservable(singleColdCompleted(wizard)); + }); + + it('should set bescheid resource', () => { + component.bescheidResource = bescheidResource; + + expect(component.bescheidResource).toEqual(bescheidResource); + }); + + it('should set send by', () => { + component.bescheidResource = bescheidResource; + + expect(bescheidService.setSendBy).toHaveBeenCalledWith(bescheidResource.sendBy); + }); + + describe('onSendBy', () => { + it('should call service', () => { + component.onSendBy(BescheidSendBy.MANUAL); + + expect(bescheidService.setSendBy).toHaveBeenCalledWith(BescheidSendBy.MANUAL); + }); + }); + + describe('onStepChange', () => { + it('should call service', () => { + component.onStepChange(BescheidWizardStep.DokumenteHochladen); + + expect(bescheidService.setActiveStep).toHaveBeenCalledWith(BescheidWizardStep.DokumenteHochladen); + }); + }); + }); + + describe('template', () => { + describe('step content layout', () => { + describe('output', () => { + describe('stepChange', () => { + it('should call handler', () => { + component.onStepChange = jest.fn(); + + triggerEvent({ + fixture, + elementSelector: stepContentLayout, + name: 'stepChange', + data: BescheidWizardStep.DokumenteHochladen, + }); + + expect(component.onStepChange).toHaveBeenCalledWith(BescheidWizardStep.DokumenteHochladen); + }); + }); + }); + }); + + describe('antrag bescheid step title', () => { + it('should have inputs', () => { + const stepTitleComponent: BescheidWizardStepTitleComponent = + getElementComponentFromFixtureByCss<BescheidWizardStepTitleComponent>(fixture, antragBescheidenStepTitleTestId); + + expect(stepTitleComponent.inactiveStep).toEqual(true); + }); + }); + + describe('dokumente hochladen step title', () => { + it('should have inputs', () => { + const stepTitleComponent: BescheidWizardStepTitleComponent = + getElementComponentFromFixtureByCss<BescheidWizardStepTitleComponent>(fixture, dokumenteHochladenStepTitleTestId); + + expect(stepTitleComponent.inactiveStep).toEqual(true); + }); + }); + + describe('bescheid versenden form', () => { + it('should have inputs', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + const formComponent: BescheidWizardBescheidVersendenFormComponent = + getElementComponentFromFixtureByCss<BescheidWizardBescheidVersendenFormComponent>(fixture, formTestId); + + expect(formComponent.bescheidResource).toEqual(component.bescheidResource); + }); + + describe('output', () => { + describe('sendBy', () => { + it('should call handler', () => { + component.onSendBy = jest.fn(); + + triggerEvent({ fixture, elementSelector: formTestId, name: 'sendBy', data: BescheidSendBy.MANUAL }); + + expect(component.onSendBy).toHaveBeenCalledWith(BescheidSendBy.MANUAL); + }); + }); + }); + }); + + describe('bescheid versenden summary', () => { + it('should exists', () => { + fixture.detectChanges(); + + existsAsHtmlElement(fixture, versendenSummaryTestId); + }); + + it('should have inputs', () => { + const wizard: Wizard = createWizard(); + bescheidService.getWizard.mockReturnValue(of(wizard)); + createComponent(); + component.bescheidResource = bescheidResource; + + fixture.detectChanges(); + const summaryComponent: BescheidWizardBescheidVersendenSummaryComponent = + getElementComponentFromFixtureByCss<BescheidWizardBescheidVersendenSummaryComponent>(fixture, versendenSummaryTestId); + + expect(summaryComponent.bescheidResource).toEqual(bescheidResource); + expect(summaryComponent.wizard).toEqual(wizard); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..70408d0b23afb74630248f0a140e07f8f0ccf60a --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.ts @@ -0,0 +1,35 @@ +import { BescheidResource, BescheidSendBy, BescheidWizardStep, Wizard } from '@alfa-client/bescheid-shared'; +import { Component, inject, Input } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; + +@Component({ + selector: 'alfa-bescheid-wizard-bescheid-versenden-container', + templateUrl: './bescheid-wizard-bescheid-versenden-container.component.html', +}) +export class BescheidWizardBescheidVersendenContainerComponent { + @Input() set bescheidResource(value: BescheidResource) { + this._bescheidResource = value; + this.bescheidService.setSendBy(value.sendBy); + } + + get bescheidResource(): BescheidResource { + return this._bescheidResource; + } + + private readonly bescheidService: BescheidService2 = inject(BescheidService2); + + public readonly wizard$: Observable<Wizard> = this.bescheidService.getWizard(); + + private _bescheidResource: BescheidResource; + + public readonly bescheidWizardStep = BescheidWizardStep; + + public onSendBy(sendBy: BescheidSendBy): void { + this.bescheidService.setSendBy(sendBy); + } + + public onStepChange(step: BescheidWizardStep): void { + this.bescheidService.setActiveStep(step); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.html new file mode 100644 index 0000000000000000000000000000000000000000..b9ebc81cb5beee11821a7ecdba7e340bc1883fbe --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.html @@ -0,0 +1,33 @@ +<div + [formGroup]="formService.form" + class="mt-5 flex w-full max-w-72 flex-col gap-4" + role="radiogroup" + aria-level="Bescheid versenden" +> + @if (bescheidResource | hasLink: bescheidLinkRel.BESCHEIDEN_UND_SENDEN) { + <ods-radio-button-card + label="Als neue Nachricht an den Antragsteller senden" + [value]="bescheidSendBy.NACHRICHT" + [name]="formServiceClass.FIELD_SEND_BY" + variant="bescheid_save" + [fullWidthText]="true" + (change)="changeSendBy(bescheidSendBy.NACHRICHT)" + data-test-id="send-to-antragsteller-button" + > + <ods-send-icon size="large"></ods-send-icon> + </ods-radio-button-card> + @if (bescheidResource | hasLink: bescheidLinkRel.BESCHEIDEN) { + <ods-radio-button-card + label="Nur speichern" + [value]="bescheidSendBy.MANUAL" + [name]="formServiceClass.FIELD_SEND_BY" + variant="bescheid_save" + [fullWidthText]="true" + (change)="changeSendBy(bescheidSendBy.MANUAL)" + data-test-id="save-button" + > + <ods-save-icon size="large"></ods-save-icon> + </ods-radio-button-card> + } + } +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..fc058c004dce9f0e1c8e22efc3960498c03e0d90 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.spec.ts @@ -0,0 +1,177 @@ +import { BescheidLinkRel, BescheidSendBy } from '@alfa-client/bescheid-shared'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + notExistsAsHtmlElement, + triggerEvent, +} from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; +import { RadioButtonCardComponent, SaveIconComponent, SendIconComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { createBescheidResource } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { BescheidFormService } from '../../../bescheid.formservice'; +import { BescheidWizardBescheidVersendenFormComponent } from './bescheid-wizard-bescheid-versenden-form.component'; + +describe('BescheidWizardBescheidVersendenFormComponent', () => { + let component: BescheidWizardBescheidVersendenFormComponent; + let fixture: ComponentFixture<BescheidWizardBescheidVersendenFormComponent>; + + const sendBescheidMessageTestId: string = getDataTestIdOf('send-to-antragsteller-button'); + const saveBeschedTestId: string = getDataTestIdOf('save-button'); + + let formService: BescheidFormService; + + beforeEach(() => { + formService = new BescheidFormService(new FormBuilder(), null); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardBescheidVersendenFormComponent, + MockComponent(RadioButtonCardComponent), + MockComponent(SendIconComponent), + MockComponent(SaveIconComponent), + HasLinkPipe, + ReactiveFormsModule, + ], + providers: [{ provide: BescheidFormService, useValue: formService }], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardBescheidVersendenFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('changeSendBy', () => { + it('should emit', () => { + component.sendBy.emit = jest.fn(); + + component.changeSendBy(BescheidSendBy.NACHRICHT); + + expect(component.sendBy.emit).toHaveBeenCalledWith(BescheidSendBy.NACHRICHT); + }); + }); + }); + + describe('template', () => { + describe('als neue nachricht radio button', () => { + it('should exists', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, sendBescheidMessageTestId); + }); + + it('should NOT exists', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, sendBescheidMessageTestId); + }); + + it('should have inputs', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + + fixture.detectChanges(); + const radioButton: RadioButtonCardComponent = getElementComponentFromFixtureByCss<RadioButtonCardComponent>( + fixture, + sendBescheidMessageTestId, + ); + + expect(radioButton.value).toEqual(BescheidSendBy.NACHRICHT); + expect(radioButton.name).toEqual(BescheidFormService.FIELD_SEND_BY); + expect(radioButton.fullWidthText).toEqual(true); + }); + + describe('output', () => { + describe('change', () => { + it('should call handler', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + component.changeSendBy = jest.fn(); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: sendBescheidMessageTestId, name: 'change', data: BescheidSendBy.NACHRICHT }); + + expect(component.changeSendBy).toHaveBeenCalledWith(BescheidSendBy.NACHRICHT); + }); + }); + }); + }); + + describe('nur speichern radio button', () => { + it('should exists', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN, BescheidLinkRel.BESCHEIDEN]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, saveBeschedTestId); + }); + + it('should NOT exists if on missing bescheiden und send link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN]); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, saveBeschedTestId); + }); + + it('should NOT exists if on missing bescheiden link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, saveBeschedTestId); + }); + + it('should NOT exists if on missinglinks', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, saveBeschedTestId); + }); + + it('should have inputs', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN, BescheidLinkRel.BESCHEIDEN]); + + fixture.detectChanges(); + const radioButton: RadioButtonCardComponent = getElementComponentFromFixtureByCss<RadioButtonCardComponent>( + fixture, + saveBeschedTestId, + ); + + expect(radioButton.value).toEqual(BescheidSendBy.MANUAL); + expect(radioButton.name).toEqual(BescheidFormService.FIELD_SEND_BY); + expect(radioButton.fullWidthText).toEqual(true); + }); + + describe('output', () => { + describe('change', () => { + it('should call handler', () => { + component.bescheidResource = createBescheidResource([ + BescheidLinkRel.BESCHEIDEN_UND_SENDEN, + BescheidLinkRel.BESCHEIDEN, + ]); + component.changeSendBy = jest.fn(); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: saveBeschedTestId, name: 'change', data: BescheidSendBy.MANUAL }); + + expect(component.changeSendBy).toHaveBeenCalledWith(BescheidSendBy.MANUAL); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..de149b55c7e9e215a9d3284fe4a441a5bbf19c30 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.ts @@ -0,0 +1,23 @@ +import { BescheidLinkRel, BescheidResource, BescheidSendBy } from '@alfa-client/bescheid-shared'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { BescheidFormService } from '../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-bescheid-versenden-form', + templateUrl: './bescheid-wizard-bescheid-versenden-form.component.html', +}) +export class BescheidWizardBescheidVersendenFormComponent { + @Input() bescheidResource: BescheidResource; + + @Output() sendBy: EventEmitter<BescheidSendBy> = new EventEmitter<BescheidSendBy>(); + + public readonly formService: BescheidFormService = inject(BescheidFormService); + + public readonly bescheidLinkRel = BescheidLinkRel; + public readonly formServiceClass = BescheidFormService; + public readonly bescheidSendBy = BescheidSendBy; + + public changeSendBy(sendBy: BescheidSendBy): void { + this.sendBy.emit(sendBy); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.html new file mode 100644 index 0000000000000000000000000000000000000000..be23ec4fce623714a97ce620605b74fd7b09a9ae --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.html @@ -0,0 +1,15 @@ +<section tabindex="0" class="h-full"> + @if (wizard.sendBy === bescheidSendBy.MANUAL) { + <alfa-bescheid-wizard-bescheid-versenden-speichern + [bescheidResource]="bescheidResource" + data-test-id="bescheid-versenden-speichern" + ></alfa-bescheid-wizard-bescheid-versenden-speichern> + } + @if (wizard.sendBy === bescheidSendBy.NACHRICHT) { + <alfa-bescheid-wizard-bescheid-versenden-senden + [bescheidResource]="bescheidResource" + [wizard]="wizard" + data-test-id="bescheid-versenden-senden" + ></alfa-bescheid-wizard-bescheid-versenden-senden> + } +</section> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..83b9df452df3cde3a70ef32cc1cc032123f43cd5 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.spec.ts @@ -0,0 +1,105 @@ +import { BescheidResource, BescheidSendBy } from '@alfa-client/bescheid-shared'; +import { existsAsHtmlElement, getElementComponentFromFixtureByCss, notExistsAsHtmlElement } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { createBescheidResource, createWizard } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { BescheidWizardBescheidVersendenSummaryComponent } from './bescheid-wizard-bescheid-versenden-summary.component'; +import { BescheidWizardBescheidVersendenSendenComponent } from './senden/bescheid-wizard-bescheid-versenden-senden.component'; +import { BescheidWizardBescheidVersendenSpeichernComponent } from './speichern/bescheid-wizard-bescheid-versenden-speichern.component'; + +describe('BescheidWizardBescheidVersendenSummaryComponent', () => { + let component: BescheidWizardBescheidVersendenSummaryComponent; + let fixture: ComponentFixture<BescheidWizardBescheidVersendenSummaryComponent>; + + const bescheidVersendenSpeichernTestId: string = getDataTestIdOf('bescheid-versenden-speichern'); + const bescheidVersendenSendenTestId: string = getDataTestIdOf('bescheid-versenden-senden'); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardBescheidVersendenSummaryComponent, + MockComponent(BescheidWizardBescheidVersendenSpeichernComponent), + MockComponent(BescheidWizardBescheidVersendenSendenComponent), + ], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardBescheidVersendenSummaryComponent); + component = fixture.componentInstance; + component.wizard = createWizard(); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('template', () => { + const bescheidResource: BescheidResource = createBescheidResource(); + + describe('bescheid versenden speichern', () => { + it('should exists', () => { + component.wizard = { ...createWizard(), sendBy: BescheidSendBy.MANUAL }; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, bescheidVersendenSpeichernTestId); + }); + + it('should NOT exists', () => { + component.wizard = { ...createWizard(), sendBy: BescheidSendBy.NACHRICHT }; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, bescheidVersendenSpeichernTestId); + }); + + it('should have inputs', () => { + component.wizard = { ...createWizard(), sendBy: BescheidSendBy.MANUAL }; + component.bescheidResource = bescheidResource; + + fixture.detectChanges(); + const speichernComponent: BescheidWizardBescheidVersendenSpeichernComponent = + getElementComponentFromFixtureByCss<BescheidWizardBescheidVersendenSpeichernComponent>( + fixture, + bescheidVersendenSpeichernTestId, + ); + + expect(speichernComponent.bescheidResource).toEqual(bescheidResource); + }); + }); + + describe('bescheid versenden senden', () => { + it('should exists', () => { + component.wizard = { ...createWizard(), sendBy: BescheidSendBy.NACHRICHT }; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, bescheidVersendenSendenTestId); + }); + + it('should NOT exists', () => { + component.wizard = { ...createWizard(), sendBy: BescheidSendBy.MANUAL }; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, bescheidVersendenSendenTestId); + }); + + it('should have inputs', () => { + component.wizard = { ...createWizard(), sendBy: BescheidSendBy.NACHRICHT }; + component.bescheidResource = bescheidResource; + + fixture.detectChanges(); + const sendenComponent: BescheidWizardBescheidVersendenSendenComponent = + getElementComponentFromFixtureByCss<BescheidWizardBescheidVersendenSendenComponent>( + fixture, + bescheidVersendenSendenTestId, + ); + + expect(sendenComponent.bescheidResource).toEqual(bescheidResource); + expect(sendenComponent.wizard).toEqual(component.wizard); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..da53ce4b8adedd2adeb59a8829653b85d983c3fa --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.ts @@ -0,0 +1,14 @@ +import { BescheidLinkRel, BescheidResource, BescheidSendBy, Wizard } from '@alfa-client/bescheid-shared'; +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'alfa-bescheid-wizard-bescheid-versenden-summary', + templateUrl: './bescheid-wizard-bescheid-versenden-summary.component.html', +}) +export class BescheidWizardBescheidVersendenSummaryComponent { + @Input() bescheidResource: BescheidResource; + @Input() wizard: Wizard; + + public readonly bescheidLinkRel = BescheidLinkRel; + public readonly bescheidSendBy = BescheidSendBy; +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.html new file mode 100644 index 0000000000000000000000000000000000000000..0631bc2d3607a669dc82fd6185fce16cc3593113 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.html @@ -0,0 +1,45 @@ +<div class="flex h-full flex-col justify-between"> + <div> + <div data-test-id="bescheid-nachricht-an-antragsteller"> + <h3 class="mb-3 font-medium text-primary">Neue Nachricht</h3> + @if (wizard?.empfaenger) { + <p data-test-id="bescheid-nachricht-empfaenger" class="mb-2 text-sm font-medium">An: {{ wizard.empfaenger }}</p> + } + </div> + <div [formGroup]="formService.form"> + <ods-text-editor + [formControlName]="formServiceClass.FIELD_NACHRICHT_SUBJECT" + label="Betreff" + placeholder="Betreff hier eingeben" + [focus]="focusBetreff" + [isRequired]="true" + > + </ods-text-editor> + + <ods-textarea-editor + [formControlName]="formServiceClass.FIELD_NACHRICHT_TEXT" + label="Text" + placeholder="Nachrichtentext hier eingeben" + [focus]="focusNachricht" + [isRequired]="true" + > + </ods-textarea-editor> + </div> + + <alfa-bescheid-wizard-dokumente-hochladen-summary + [isBescheidDocumentMissing]="false" + data-test-id="bescheid-versenden-dokumente" + ></alfa-bescheid-wizard-dokumente-hochladen-summary> + </div> + @if ( + (bescheidResource | hasLink: bescheidLinkRel.UPDATE) || (bescheidResource | hasLink: bescheidLinkRel.BESCHEIDEN_UND_SENDEN) + ) { + <ods-button-with-spinner + class="self-end" + [stateResource]="submitStateResource$ | async" + text="Bescheid senden" + (clickEmitter)="submit()" + data-test-id="send-button" + ></ods-button-with-spinner> + } +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..9f90d5f49aead888a0b1eff751476d748859fe07 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.spec.ts @@ -0,0 +1,314 @@ +import { BescheidLinkRel, BescheidWizardDialogResult } from '@alfa-client/bescheid-shared'; +import { CommandResource } from '@alfa-client/command-shared'; +import { + createEmptyStateResource, + createErrorStateResource, + createLoadingStateResource, + HasLinkPipe, + StateResource, +} from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + mock, + Mock, + notExistsAsHtmlElement, + triggerEvent, + useFromMock, +} from '@alfa-client/test-utils'; +import { DialogRef } from '@angular/cdk/dialog'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; +import { expect } from '@jest/globals'; +import { ButtonWithSpinnerComponent, TextareaEditorComponent, TextEditorComponent } from '@ods/component'; +import { MockComponent } from 'ng-mocks'; +import { EMPTY, of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidResource, createWizard } from '../../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../../command-shared/test/command'; +import { getDataTestIdOf } from '../../../../../../../../tech-shared/test/data-test'; +import { createProblemDetail } from '../../../../../../../../tech-shared/test/error'; +import { singleColdCompleted } from '../../../../../../../../tech-shared/test/marbles'; +import { BescheidFormService } from '../../../../bescheid.formservice'; +import { BescheidWizardDokumenteHochladenSummaryComponent } from '../../../dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component'; +import { BescheidWizardBescheidVersendenSendenComponent } from './bescheid-wizard-bescheid-versenden-senden.component'; + +describe('BescheidWizardBescheidVersendenSendenComponent', () => { + let component: BescheidWizardBescheidVersendenSendenComponent; + let fixture: ComponentFixture<BescheidWizardBescheidVersendenSendenComponent>; + + const dokumenteTestsId: string = getDataTestIdOf('bescheid-versenden-dokumente'); + const submitButtonTestId: string = getDataTestIdOf('send-button'); + const empfaengerTestId: string = getDataTestIdOf('bescheid-nachricht-empfaenger'); + + let bescheidService: Mock<BescheidService2>; + let formService: BescheidFormService; + let dialogRef: Mock<DialogRef<BescheidWizardDialogResult>>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + formService = new BescheidFormService(new FormBuilder(), useFromMock(bescheidService)); + formService.submit = jest.fn(); + dialogRef = mock(DialogRef<BescheidWizardDialogResult>); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardBescheidVersendenSendenComponent, + MockComponent(BescheidWizardDokumenteHochladenSummaryComponent), + MockComponent(ButtonWithSpinnerComponent), + MockComponent(TextareaEditorComponent), + MockComponent(TextEditorComponent), + HasLinkPipe, + ReactiveFormsModule, + ], + providers: [ + { provide: BescheidFormService, useValue: formService }, + { provide: DialogRef<BescheidWizardDialogResult>, useValue: dialogRef }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardBescheidVersendenSendenComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.submitStateResource$).toBeObservable(singleColdCompleted(createEmptyStateResource())); + }); + + describe('submit', () => { + beforeEach(() => { + formService.submit = jest.fn().mockReturnValue(EMPTY); + component._resetFocus = jest.fn(); + }); + + it('should reset focus', () => { + component.submit(); + component.submitStateResource$.subscribe(); + + expect(component._resetFocus).toHaveBeenCalled(); + }); + + it('should call form service', () => { + component.submit(); + component.submitStateResource$.subscribe(); + + expect(formService.submit).toHaveBeenCalled(); + }); + + it('should close dialog', () => { + formService.submit = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(dialogRef.close).toHaveBeenCalledWith({ reloadVorgang: true } as BescheidWizardDialogResult); + }); + + it('should NOT close dialog on pending send', () => { + formService.submit = jest.fn().mockReturnValue(of(createLoadingStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(dialogRef.close).not.toHaveBeenCalled(); + }); + + it('should NOT close dialog on failed send', () => { + formService.submit = jest.fn().mockReturnValue(of(createErrorStateResource(createProblemDetail()))); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(dialogRef.close).not.toHaveBeenCalled(); + }); + + it('should focus to first invalid control', () => { + component._focusToFirstInvalidControl = jest.fn(); + formService.submit = jest.fn().mockReturnValue(of(createErrorStateResource(createProblemDetail()))); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(component._focusToFirstInvalidControl).toHaveBeenCalled(); + }); + + it('should NOT focus to first invalid control on pending submit', () => { + component._focusToFirstInvalidControl = jest.fn(); + formService.submit = jest.fn().mockReturnValue(of(createLoadingStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(component._focusToFirstInvalidControl).not.toHaveBeenCalled(); + }); + + it('should NOT focus to first invalid control on successful submit', () => { + component._focusToFirstInvalidControl = jest.fn(); + formService.submit = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(component._focusToFirstInvalidControl).not.toHaveBeenCalled(); + }); + }); + + describe('_focusToFirstInvalidControl', () => { + beforeEach(() => { + component._resetFocus = jest.fn(); + + formService.isBetreffInvalid = jest.fn(); + formService.isNachrichtInvalid = jest.fn(); + }); + + it('should check betreff', () => { + component._focusToFirstInvalidControl(); + + expect(formService.isBetreffInvalid).toHaveBeenCalled(); + }); + + it('should check nachricht', () => { + formService.isBetreffInvalid = jest.fn().mockReturnValue(false); + + component._focusToFirstInvalidControl(); + + expect(formService.isNachrichtInvalid).toHaveBeenCalled(); + }); + + it('should NOT check nachricht', () => { + formService.isBetreffInvalid = jest.fn().mockReturnValue(true); + + component._focusToFirstInvalidControl(); + + expect(formService.isNachrichtInvalid).not.toHaveBeenCalled(); + }); + + it('should focus betreff', () => { + formService.isBetreffInvalid = jest.fn().mockReturnValue(true); + + component._focusToFirstInvalidControl(); + + expect(component.focusBetreff).toBe(true); + }); + + it('should NOT focus betreff', () => { + formService.isBetreffInvalid = jest.fn().mockReturnValue(false); + + component._focusToFirstInvalidControl(); + + expect(component.focusBetreff).toBe(false); + }); + + it('should focus nachricht', () => { + formService.isBetreffInvalid = jest.fn().mockReturnValue(false); + formService.isNachrichtInvalid = jest.fn().mockReturnValue(true); + + component._focusToFirstInvalidControl(); + + expect(component.focusNachricht).toBe(true); + }); + + it('should NOT focus nachricht', () => { + formService.isBetreffInvalid = jest.fn().mockReturnValue(true); + formService.isNachrichtInvalid = jest.fn().mockReturnValue(false); + + component._focusToFirstInvalidControl(); + + expect(component.focusNachricht).toBe(false); + }); + }); + }); + + describe('template', () => { + describe('empfaenger', () => { + it('should exists', () => { + component.wizard = createWizard(); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, empfaengerTestId); + }); + + it('should NOT exits', () => { + component.wizard = { ...createWizard(), empfaenger: null }; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, empfaengerTestId); + }); + }); + + describe('dokumente hochladen summary', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, dokumenteTestsId); + }); + + it('should have inputs', () => { + const dokumentComponent: BescheidWizardDokumenteHochladenSummaryComponent = + getElementComponentFromFixtureByCss<BescheidWizardDokumenteHochladenSummaryComponent>(fixture, dokumenteTestsId); + + expect(dokumentComponent.isBescheidDocumentMissing).toBe(false); + }); + + describe('submit button', () => { + it('should exists with update link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, dokumenteTestsId); + }); + + it('should exists with bescheiden link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, dokumenteTestsId); + }); + + it('should NOT exists on missing links', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, submitButtonTestId); + }); + + it('should have inputs', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + const submitCommandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + component.submitStateResource$ = of(submitCommandStateResource); + + fixture.detectChanges(); + const submitButtonComponent: ButtonWithSpinnerComponent = + getElementComponentFromFixtureByCss<ButtonWithSpinnerComponent>(fixture, submitButtonTestId); + + expect(submitButtonComponent.stateResource).toEqual(submitCommandStateResource); + }); + + describe('output', () => { + describe('clickEmitter', () => { + it('should call handler', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + component.submit = jest.fn(); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: submitButtonTestId, name: 'clickEmitter' }); + + expect(component.submit).toHaveBeenCalled(); + }); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..5d03f994ed85918c979d7101e8d6b4ec14a59ee3 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.ts @@ -0,0 +1,48 @@ +import { BescheidLinkRel, BescheidResource, BescheidWizardDialogResult, Wizard } from '@alfa-client/bescheid-shared'; +import { CommandResource, tapOnCommandSuccessfullyDone, tapOnFailedCommand } from '@alfa-client/command-shared'; +import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; +import { DialogRef } from '@angular/cdk/dialog'; +import { Component, inject, Input } from '@angular/core'; +import { Observable, of } from 'rxjs'; +import { BescheidFormService } from '../../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-bescheid-versenden-senden', + templateUrl: './bescheid-wizard-bescheid-versenden-senden.component.html', +}) +export class BescheidWizardBescheidVersendenSendenComponent { + @Input() bescheidResource: BescheidResource; + @Input() wizard: Wizard; + + public readonly formService: BescheidFormService = inject(BescheidFormService); + private readonly dialogRef = inject(DialogRef<BescheidWizardDialogResult>); + + public submitStateResource$: Observable<StateResource<CommandResource>> = of(createEmptyStateResource<CommandResource>()); + + public focusBetreff: boolean = false; + public focusNachricht: boolean = false; + + public readonly bescheidLinkRel = BescheidLinkRel; + public readonly formServiceClass = BescheidFormService; + + public submit(): void { + this._resetFocus(); + this.submitStateResource$ = this.formService.submit().pipe( + tapOnFailedCommand(() => this._focusToFirstInvalidControl()), + tapOnCommandSuccessfullyDone(() => this.dialogRef.close({ reloadVorgang: true })), + ); + } + + _focusToFirstInvalidControl(): void { + if (this.formService.isBetreffInvalid()) { + this.focusBetreff = true; + } else if (this.formService.isNachrichtInvalid()) { + this.focusNachricht = true; + } + } + + _resetFocus(): void { + this.focusBetreff = false; + this.focusNachricht = false; + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.html new file mode 100644 index 0000000000000000000000000000000000000000..a19c2b53db33741056c2cc6844e7b83536512f5d --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.html @@ -0,0 +1,20 @@ +<div class="flex h-full flex-col justify-between"> + <div> + <alfa-bescheid-wizard-antrag-bescheiden-summary></alfa-bescheid-wizard-antrag-bescheiden-summary> + <alfa-bescheid-wizard-dokumente-hochladen-summary + [isBescheidDocumentMissing]="false" + data-test-id="bescheid-versenden-dokumente" + ></alfa-bescheid-wizard-dokumente-hochladen-summary> + <p class="mb-8 text-base font-normal text-text">Der Bescheid muss manuell versendet werden.</p> + </div> + + @if ((bescheidResource | hasLink: bescheidLinkRel.UPDATE) || (bescheidResource | hasLink: bescheidLinkRel.BESCHEIDEN)) { + <ods-button-with-spinner + class="self-end" + [stateResource]="submitStateResource$ | async" + text="Antrag bescheiden und speichern" + (clickEmitter)="submit()" + data-test-id="confirm-and-save-button" + ></ods-button-with-spinner> + } +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..4382985e2f96fcff9aee1b1604a7622641202420 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.spec.ts @@ -0,0 +1,186 @@ +import { BescheidLinkRel, BescheidWizardDialogResult } from '@alfa-client/bescheid-shared'; +import { CommandResource } from '@alfa-client/command-shared'; +import { + createEmptyStateResource, + createErrorStateResource, + createLoadingStateResource, + HasLinkPipe, + StateResource, +} from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + Mock, + mock, + notExistsAsHtmlElement, + triggerEvent, +} from '@alfa-client/test-utils'; +import { DialogRef } from '@angular/cdk/dialog'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { expect } from '@jest/globals'; +import { ButtonWithSpinnerComponent } from '@ods/component'; +import { MockComponent } from 'ng-mocks'; +import { EMPTY, of } from 'rxjs'; +import { createBescheidResource } from '../../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../../command-shared/test/command'; +import { getDataTestIdOf } from '../../../../../../../../tech-shared/test/data-test'; +import { createProblemDetail } from '../../../../../../../../tech-shared/test/error'; +import { singleColdCompleted } from '../../../../../../../../tech-shared/test/marbles'; +import { BescheidFormService } from '../../../../bescheid.formservice'; +import { BescheidWizardAntragBescheidenSummaryComponent } from '../../../antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component'; +import { BescheidWizardDokumenteHochladenSummaryComponent } from '../../../dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component'; +import { BescheidWizardBescheidVersendenSpeichernComponent } from './bescheid-wizard-bescheid-versenden-speichern.component'; + +describe('BescheidWizardBescheidVersendenSpeichernComponent', () => { + let component: BescheidWizardBescheidVersendenSpeichernComponent; + let fixture: ComponentFixture<BescheidWizardBescheidVersendenSpeichernComponent>; + + const dokumenteTestsId: string = getDataTestIdOf('bescheid-versenden-dokumente'); + const submitButtonTestId: string = getDataTestIdOf('confirm-and-save-button'); + + let formService: Mock<BescheidFormService>; + let dialogRef: Mock<DialogRef<BescheidWizardDialogResult>>; + + beforeEach(() => { + formService = mock(BescheidFormService); + formService.submit = jest.fn(); + dialogRef = mock(DialogRef<BescheidWizardDialogResult>); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardBescheidVersendenSpeichernComponent, + MockComponent(BescheidWizardAntragBescheidenSummaryComponent), + MockComponent(BescheidWizardDokumenteHochladenSummaryComponent), + MockComponent(ButtonWithSpinnerComponent), + HasLinkPipe, + ], + providers: [ + { provide: BescheidFormService, useValue: formService }, + { provide: DialogRef<BescheidWizardDialogResult>, useValue: dialogRef }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardBescheidVersendenSpeichernComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.submitStateResource$).toBeObservable(singleColdCompleted(createEmptyStateResource())); + }); + + describe('submit', () => { + beforeEach(() => { + formService.submit.mockReturnValue(EMPTY); + }); + + it('should call form service', () => { + component.submit(); + component.submitStateResource$.subscribe(); + + expect(formService.submit).toHaveBeenCalled(); + }); + + it('should close dialog', () => { + formService.submit.mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(dialogRef.close).toHaveBeenCalled(); + }); + + it('should NOT close dialog on pending send', () => { + formService.submit.mockReturnValue(of(createLoadingStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(dialogRef.close).not.toHaveBeenCalled(); + }); + + it('should NOT close dialog on failed send', () => { + formService.submit.mockReturnValue(of(createErrorStateResource(createProblemDetail()))); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(dialogRef.close).not.toHaveBeenCalled(); + }); + }); + }); + + describe('template', () => { + describe('dokumente hochladen summary', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, dokumenteTestsId); + }); + + it('should have inputs', () => { + const dokumentComponent: BescheidWizardDokumenteHochladenSummaryComponent = + getElementComponentFromFixtureByCss<BescheidWizardDokumenteHochladenSummaryComponent>(fixture, dokumenteTestsId); + + expect(dokumentComponent.isBescheidDocumentMissing).toBe(false); + }); + + describe('submit button', () => { + it('should exists with update link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, dokumenteTestsId); + }); + + it('should exists with bescheiden link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, dokumenteTestsId); + }); + + it('should NOT exists on missing links', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, submitButtonTestId); + }); + + it('should have inputs', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN]); + const submitCommandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + component.submitStateResource$ = of(submitCommandStateResource); + + fixture.detectChanges(); + const submitButtonComponent: ButtonWithSpinnerComponent = + getElementComponentFromFixtureByCss<ButtonWithSpinnerComponent>(fixture, submitButtonTestId); + + expect(submitButtonComponent.stateResource).toEqual(submitCommandStateResource); + }); + + describe('output', () => { + describe('clickEmitter', () => { + it('should call handler', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN]); + component.submit = jest.fn(); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: submitButtonTestId, name: 'clickEmitter' }); + + expect(component.submit).toHaveBeenCalled(); + }); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..f7ee9b36506b3b783c70df4e5238eb690a7bb0c2 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.ts @@ -0,0 +1,28 @@ +import { BescheidLinkRel, BescheidResource, BescheidWizardDialogResult } from '@alfa-client/bescheid-shared'; +import { CommandResource, tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared'; +import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; +import { DialogRef } from '@angular/cdk/dialog'; +import { Component, inject, Input } from '@angular/core'; +import { Observable, of } from 'rxjs'; +import { BescheidFormService } from '../../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-bescheid-versenden-speichern', + templateUrl: './bescheid-wizard-bescheid-versenden-speichern.component.html', +}) +export class BescheidWizardBescheidVersendenSpeichernComponent { + @Input() bescheidResource: BescheidResource; + + private readonly formService: BescheidFormService = inject(BescheidFormService); + private readonly dialogRef = inject(DialogRef<BescheidWizardDialogResult>); + + public submitStateResource$: Observable<StateResource<CommandResource>> = of(createEmptyStateResource<CommandResource>()); + + public readonly bescheidLinkRel = BescheidLinkRel; + + public submit(): void { + this.submitStateResource$ = this.formService + .submit() + .pipe(tapOnCommandSuccessfullyDone(() => this.dialogRef.close({ reloadVorgang: true }))); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.html index c7041e1f2afb7f84f09f5f6591815279ae82a87f..178a0f574555303c350994f4696c6e9e42f1fc52 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.html @@ -32,18 +32,27 @@ <form [formGroup]="formService.form" class="h-full"> <div class="grid h-full"> - <alfa-bescheid-wizard-antrag-bescheiden - *ngIf="activeStep === bescheidWizardStep.AntragBescheiden" - [vorgangWithEingangResource]="vorgangWithEingangResource" - [bescheidResource]="bescheidStateResource.resource" - [submitStateResource]="submitStateResource" - (weiterClickEmitter)="weiterClickEmitter.emit($event)" - (vorgangAbgeschlossen)="vorgangAbgeschlossen.emit()" - data-test-id="antrag-bescheiden-step" - ></alfa-bescheid-wizard-antrag-bescheiden> - <alfa-bescheid-wizard-dokumente-hochladen - *ngIf="activeStep === bescheidWizardStep.DokumenteHochladen" - data-test-id="dokumente-hochladen-step" - ></alfa-bescheid-wizard-dokumente-hochladen> + @switch (activeStep) { + @case (bescheidWizardStep.AntragBescheiden) { + <alfa-bescheid-wizard-antrag-bescheiden-container + [vorgangWithEingangResource]="vorgangWithEingangResource" + [bescheidResource]="bescheidResource" + (vorgangAbgeschlossen)="vorgangAbgeschlossen.emit()" + data-test-id="antrag-bescheiden-step" + ></alfa-bescheid-wizard-antrag-bescheiden-container> + } + @case (bescheidWizardStep.DokumenteHochladen) { + <alfa-bescheid-wizard-dokumente-hochladen-container + [bescheidResource]="bescheidResource" + data-test-id="dokumente-hochladen-step" + ></alfa-bescheid-wizard-dokumente-hochladen-container> + } + @case (bescheidWizardStep.BescheidVersenden) { + <alfa-bescheid-wizard-bescheid-versenden-container + [bescheidResource]="bescheidResource" + data-test-id="bescheid-versenden-step" + ></alfa-bescheid-wizard-bescheid-versenden-container> + } + } </div> </form> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.spec.ts index 0f84df6c0fb722b9b4c8cded349b71edf8b039a9..c818a3613876e7b6533d508d5714fbbfa5881330 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.spec.ts @@ -21,12 +21,18 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidResource, BescheidService, BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { HasLinkPipe, StateResource, createEmptyStateResource } from '@alfa-client/tech-shared'; +import { BescheidResource, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { + createEmptyStateResource, + createErrorStateResource, + createLoadingStateResource, + HasLinkPipe, + StateResource, +} from '@alfa-client/tech-shared'; import { - Mock, existsAsHtmlElement, - getElementFromFixtureByType, + getElementComponentFromFixtureByCss, + Mock, mock, notExistsAsHtmlElement, triggerEvent, @@ -37,15 +43,18 @@ import { VorgangWithEingangLinkRel } from '@alfa-client/vorgang-shared'; import { EventEmitter } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; +import { expect } from '@jest/globals'; import { MockComponent } from 'ng-mocks'; -import { createBescheidStateResource } from '../../../../../bescheid-shared/src/test/bescheid'; -import { createSuccessfullyDoneCommandStateResource } from '../../../../../command-shared/test/command'; +import { BescheidService2 } from '../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidResource, createBescheidStateResource } from '../../../../../bescheid-shared/src/test/bescheid'; import { getDataTestIdOf } from '../../../../../tech-shared/test/data-test'; +import { createProblemDetail } from '../../../../../tech-shared/test/error'; import { createVorgangWithEingangResource } from '../../../../../vorgang-shared/test/vorgang'; import { BescheidFormService } from '../bescheid.formservice'; -import { BescheidWizardAntragBescheidenComponent } from './antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component'; +import { BescheidWizardAntragBescheidenContainerComponent } from './antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component'; +import { BescheidWizardBescheidVersendenContainerComponent } from './bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component'; import { BescheidWizardComponent } from './bescheid-wizard.component'; -import { BescheidWizardDokumenteHochladenComponent } from './dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component'; +import { BescheidWizardDokumenteHochladenContainerComponent } from './dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component'; import { BescheidWizardStepperComponent } from './stepper/bescheid-wizard-stepper.component'; describe('BescheidWizardComponent', () => { @@ -55,12 +64,13 @@ describe('BescheidWizardComponent', () => { const bescheidLoadingSpinner: string = getDataTestIdOf('bescheid-loading-spinner'); const antragBescheidenStep: string = getDataTestIdOf('antrag-bescheiden-step'); const dokumenteHochladenStep: string = getDataTestIdOf('dokumente-hochladen-step'); + const bescheidVersendenStepTestId: string = getDataTestIdOf('bescheid-versenden-step'); - let bescheidService: Mock<BescheidService>; + let bescheidService: Mock<BescheidService2>; let formService: BescheidFormService; beforeEach(() => { - bescheidService = mock(BescheidService); + bescheidService = mock(BescheidService2); formService = new BescheidFormService(new UntypedFormBuilder(), useFromMock(bescheidService)); }); @@ -69,8 +79,9 @@ describe('BescheidWizardComponent', () => { declarations: [ BescheidWizardComponent, MockComponent(BescheidWizardStepperComponent), - MockComponent(BescheidWizardAntragBescheidenComponent), - MockComponent(BescheidWizardDokumenteHochladenComponent), + MockComponent(BescheidWizardAntragBescheidenContainerComponent), + MockComponent(BescheidWizardDokumenteHochladenContainerComponent), + MockComponent(BescheidWizardBescheidVersendenContainerComponent), MockComponent(SpinnerComponent), HasLinkPipe, ], @@ -85,7 +96,6 @@ describe('BescheidWizardComponent', () => { fixture = TestBed.createComponent(BescheidWizardComponent); component = fixture.componentInstance; - component.weiterClickEmitter = useFromMock(mock(EventEmitter<BescheidWizardStep>)); component.vorgangAbgeschlossen = useFromMock(mock(EventEmitter<void>)); fixture.detectChanges(); }); @@ -117,6 +127,30 @@ describe('BescheidWizardComponent', () => { expect(component.bescheidStateResource).toEqual(component.bescheidStateResource); }); + + it('should set bescheid resource if loaded', () => { + component.bescheidStateResource = createBescheidStateResource(); + + expect(component.bescheidResource).toEqual(component.bescheidStateResource.resource); + }); + + it('should NOT set bescheid resource on pending load', () => { + const bescheidResource: BescheidResource = createBescheidResource(); + component.bescheidResource = bescheidResource; + + component.bescheidStateResource = createLoadingStateResource(); + + expect(component.bescheidResource).toEqual(bescheidResource); + }); + + it('should NOT set bescheid resource on failed load', () => { + const bescheidResource: BescheidResource = createBescheidResource(); + component.bescheidResource = bescheidResource; + + component.bescheidStateResource = createErrorStateResource(createProblemDetail()); + + expect(component.bescheidResource).toEqual(bescheidResource); + }); }); }); @@ -125,7 +159,7 @@ describe('BescheidWizardComponent', () => { component.bescheidStateResource = createBescheidStateResource(); }); - describe('ozgcloud-spinner', () => { + describe('spinner', () => { it('should exists', () => { component.vorgangWithEingangResource = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEID_DRAFT]); component.bescheidStateResource = createEmptyStateResource(); @@ -153,110 +187,126 @@ describe('BescheidWizardComponent', () => { notExistsAsHtmlElement(fixture, bescheidLoadingSpinner); }); - describe('input', () => { - it('should set stateResource', () => { - component.vorgangWithEingangResource = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEID_DRAFT]); - component.bescheidStateResource = createEmptyStateResource(); + it('should have been called with inputs', () => { + component.vorgangWithEingangResource = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEID_DRAFT]); + component.bescheidStateResource = createEmptyStateResource(); - fixture.detectChanges(); + fixture.detectChanges(); + const spinnerComponent: SpinnerComponent = getElementComponentFromFixtureByCss<SpinnerComponent>( + fixture, + bescheidLoadingSpinner, + ); - expect(getElementFromFixtureByType(fixture, SpinnerComponent).stateResource).toEqual(component.bescheidStateResource); - }); + expect(spinnerComponent.stateResource).toEqual(component.bescheidStateResource); }); }); - describe('alfa-bescheid-wizard-antrag-bescheiden', () => { - function getElementComponent(): BescheidWizardAntragBescheidenComponent { - return getElementFromFixtureByType(fixture, BescheidWizardAntragBescheidenComponent); - } - - it('should show', () => { - givenActiveStep(1); - givenLoadedBescheidStateResrouce(); + describe('antrag bescheiden', () => { + it('should exists', () => { + givenActiveStep(BescheidWizardStep.AntragBescheiden); existsAsHtmlElement(fixture, antragBescheidenStep); }); - it.each([2, 3])('should NOT show in step %d', (step: number) => { + it.each([2, 3])('should NOT exists in step %d', (step: number) => { givenActiveStep(step); - givenLoadedBescheidStateResrouce(); notExistsAsHtmlElement(fixture, antragBescheidenStep); }); - describe('input', () => { - it('should set vorgangWithEingangResource', () => { - givenActiveStep(1); - givenLoadedBescheidStateResrouce(); - component.vorgangWithEingangResource = createVorgangWithEingangResource(); - - fixture.detectChanges(); + it('should have been called with inputs', () => { + givenActiveStep(BescheidWizardStep.AntragBescheiden); + givenLoadedBescheidStateResource(); + givenLoadedBescheidStateResource(); + component.vorgangWithEingangResource = createVorgangWithEingangResource(); - expect(getElementComponent().vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); - }); + fixture.detectChanges(); - it('should set bescheidResource', () => { - givenActiveStep(1); - givenLoadedBescheidStateResrouce(); + const antragBescheidenComponent: BescheidWizardAntragBescheidenContainerComponent = + getElementComponentFromFixtureByCss<BescheidWizardAntragBescheidenContainerComponent>(fixture, antragBescheidenStep); - fixture.detectChanges(); + expect(antragBescheidenComponent.vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); + expect(antragBescheidenComponent.bescheidResource).toEqual(component.bescheidResource); + }); - expect(getElementComponent().bescheidResource).toEqual(component.bescheidStateResource.resource); + describe('output', () => { + beforeEach(() => { + givenActiveStep(BescheidWizardStep.AntragBescheiden); + givenLoadedBescheidStateResource(); }); - it('should set submitStateResource', () => { - givenActiveStep(1); - givenLoadedBescheidStateResrouce(); - component.submitStateResource = createSuccessfullyDoneCommandStateResource(); + describe('vorgangAbgeschlossen', () => { + it('should emit', () => { + triggerEvent({ + fixture, + name: 'vorgangAbgeschlossen', + elementSelector: antragBescheidenStep, + }); - fixture.detectChanges(); - - expect(getElementComponent().submitStateResource).toEqual(component.submitStateResource); + expect(component.vorgangAbgeschlossen.emit).toHaveBeenCalled(); + }); }); }); + }); - describe('output', () => { - beforeEach(() => { - givenActiveStep(1); - givenLoadedBescheidStateResrouce(); - }); + describe('dokumente hochladen', () => { + beforeEach(() => { + givenActiveStep(BescheidWizardStep.DokumenteHochladen); + fixture.detectChanges(); + }); - it('should emit weiterClickEmitter', () => { - triggerEvent({ - fixture, - name: 'weiterClickEmitter', - elementSelector: antragBescheidenStep, - data: BescheidWizardStep.DokumenteHochladen, - }); + it('should exists', () => { + existsAsHtmlElement(fixture, dokumenteHochladenStep); + }); - expect(component.weiterClickEmitter.emit).toHaveBeenCalledWith(BescheidWizardStep.DokumenteHochladen); - }); + it.each([1, 3])('should NOT exists in step %d', (step: number) => { + givenActiveStep(step); + + notExistsAsHtmlElement(fixture, dokumenteHochladenStep); + }); - it('should emit vorgangAbgeschlossen', () => { - triggerEvent({ + it('should have been called with inputs', () => { + givenActiveStep(BescheidWizardStep.DokumenteHochladen); + + fixture.detectChanges(); + + const dokumenteHochladenComponent: BescheidWizardDokumenteHochladenContainerComponent = + getElementComponentFromFixtureByCss<BescheidWizardDokumenteHochladenContainerComponent>( fixture, - name: 'vorgangAbgeschlossen', - elementSelector: antragBescheidenStep, - }); + dokumenteHochladenStep, + ); - expect(component.vorgangAbgeschlossen.emit).toHaveBeenCalled(); - }); + expect(dokumenteHochladenComponent.bescheidResource).toEqual(component.bescheidResource); }); }); - describe('alfa-bescheid-wizard-dokumente-hochladen', () => { - it('should show', () => { - givenActiveStep(2); - givenLoadedBescheidStateResrouce(); + describe('bescheid versenden', () => { + beforeEach(() => { + component.activeStep = BescheidWizardStep.BescheidVersenden; + fixture.detectChanges(); + }); - existsAsHtmlElement(fixture, dokumenteHochladenStep); + it('should exists', () => { + existsAsHtmlElement(fixture, bescheidVersendenStepTestId); }); - it.each([1, 3])('should NOT show in step %d', (step: number) => { + it.each([1, 2])('should NOT exists in step %d', (step: number) => { givenActiveStep(step); - givenLoadedBescheidStateResrouce(); - notExistsAsHtmlElement(fixture, dokumenteHochladenStep); + notExistsAsHtmlElement(fixture, bescheidVersendenStepTestId); + }); + + it('should have been called with inputs', () => { + component.bescheidStateResource = createBescheidStateResource(); + + fixture.detectChanges(); + const bescheidVersendenComponent: BescheidWizardBescheidVersendenContainerComponent = + getElementComponentFromFixtureByCss<BescheidWizardBescheidVersendenContainerComponent>( + fixture, + bescheidVersendenStepTestId, + ); + + expect(bescheidVersendenComponent.bescheidResource).toEqual(component.bescheidResource); }); }); }); @@ -266,10 +316,11 @@ describe('BescheidWizardComponent', () => { fixture.detectChanges(); } - function givenLoadedBescheidStateResrouce(): StateResource<BescheidResource> { - const resource: StateResource<BescheidResource> = createBescheidStateResource(); - component.bescheidStateResource = resource; + function givenLoadedBescheidStateResource(): StateResource<BescheidResource> { + const stateResource: StateResource<BescheidResource> = createBescheidStateResource(); + component.bescheidStateResource = stateResource; + component.bescheidResource = stateResource.resource; fixture.detectChanges(); - return resource; + return stateResource; } }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.ts index bbeb757952ace3785c2fafbd24e0e80f862b9959..d601c79c77cbfe839e4563419004d503810b012e 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.ts @@ -22,10 +22,9 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { BescheidResource, BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { StateResource, isLoaded } from '@alfa-client/tech-shared'; +import { isLoaded, StateResource } from '@alfa-client/tech-shared'; import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Resource } from '@ngxp/rest'; import { BescheidFormService } from '../bescheid.formservice'; @Component({ @@ -38,6 +37,7 @@ export class BescheidWizardComponent { @Input() set bescheidStateResource(value: StateResource<BescheidResource>) { if (isLoaded(value)) { this.formService.patchValues(value.resource); + this.bescheidResource = value.resource; } this._bescheidStateResource = value; } @@ -46,12 +46,11 @@ export class BescheidWizardComponent { return this._bescheidStateResource; } - @Input() activeStep: number; - @Input() submitStateResource: StateResource<Resource>; + @Input() activeStep: BescheidWizardStep; - @Output() weiterClickEmitter: EventEmitter<BescheidWizardStep> = new EventEmitter<BescheidWizardStep>(); @Output() vorgangAbgeschlossen: EventEmitter<void> = new EventEmitter<void>(); + public bescheidResource: BescheidResource; private _bescheidStateResource: StateResource<BescheidResource>; public readonly vorgangWithEingangLinkRel = VorgangWithEingangLinkRel; diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.spec.ts index 2e4c13bcb369d85dba5df9be85adff92e41bb760..5dfde26e4da2a928be6046e7c14d50b60790900a 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.spec.ts @@ -21,36 +21,23 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidService } from '@alfa-client/bescheid-shared'; import { CommandResource } from '@alfa-client/command-shared'; -import { StateResource, createErrorStateResource } from '@alfa-client/tech-shared'; -import { - DialogRefMock, - Mock, - createDialogRefMock, - existsAsHtmlElement, - getElementComponentFromFixtureByCss, - mock, - triggerEvent, -} from '@alfa-client/test-utils'; +import { createErrorStateResource, StateResource } from '@alfa-client/tech-shared'; +import { createDialogRefMock, DialogRefMock, existsAsHtmlElement, getElementComponentFromFixtureByCss, Mock, mock, triggerEvent, } from '@alfa-client/test-utils'; import { OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { expect } from '@jest/globals'; import { MockComponent } from 'ng-mocks'; import { EMPTY, of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; import { createBescheidResource } from '../../../../../../bescheid-shared/src/test/bescheid'; -import { - createCommandStateResource, - createSuccessfullyDoneCommandStateResource, -} from '../../../../../../command-shared/test/command'; +import { createCommandStateResource, createSuccessfullyDoneCommandStateResource, } from '../../../../../../command-shared/test/command'; import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; import { createApiError } from '../../../../../../tech-shared/test/error'; import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; import { BescheidFormService } from '../../bescheid.formservice'; -import { - BescheidWizardCancelDialogContainerComponent, - CancelWizardDialogData, -} from './bescheid-wizard-cancel-dialog-container.component'; +import { BescheidWizardCancelDialogContainerComponent, CancelWizardDialogData, } from './bescheid-wizard-cancel-dialog-container.component'; describe('BescheidWizardCancelDialogContainerComponent', () => { let component: BescheidWizardCancelDialogContainerComponent; @@ -64,21 +51,23 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { }; let formService: Mock<BescheidFormService>; - let bescheidService: Mock<BescheidService>; + let bescheidService: Mock<BescheidService2>; let dialogRef: DialogRefMock; beforeEach(() => { - formService = { ...mock(BescheidFormService), submit: jest.fn().mockReturnValue(EMPTY) }; - bescheidService = { ...mock(BescheidService), bescheidVerwerfen: jest.fn().mockReturnValue(EMPTY) }; + formService = mock(BescheidFormService); + formService.submit = jest.fn().mockReturnValue(EMPTY); + bescheidService = mock(BescheidService2); + bescheidService.deleteBescheid.mockReturnValue(EMPTY); dialogRef = createDialogRefMock(); }); - beforeEach(async () => { + async function configureTestingModule(dialogData: CancelWizardDialogData) { await TestBed.configureTestingModule({ declarations: [BescheidWizardCancelDialogContainerComponent, MockComponent(OzgcloudStrokedButtonWithSpinnerComponent)], providers: [ { - provide: BescheidService, + provide: BescheidService2, useValue: bescheidService, }, { @@ -99,13 +88,33 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { fixture = TestBed.createComponent(BescheidWizardCancelDialogContainerComponent); component = fixture.componentInstance; fixture.detectChanges(); - }); + } - it('should create', () => { - expect(component).toBeTruthy(); + beforeEach(async () => { + await configureTestingModule(dialogData); }); describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('ngOnInit', () => { + it('should lock bescheid sending', () => { + component.ngOnInit(); + + expect(bescheidService.lockBescheidSending).toHaveBeenCalled(); + }); + }); + + describe('ngOnDestroy', () => { + it('should unlock bescheid sending', () => { + component.ngOnDestroy(); + + expect(bescheidService.unlockBescheidSending).toHaveBeenCalled(); + }); + }); + describe('save', () => { beforeEach(() => { component.closeDialogWithWizard = jest.fn(); @@ -117,7 +126,7 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { expect(formService.submit).toHaveBeenCalled(); }); - it('should emit save command state resource', () => { + it('should set save state resource', () => { const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); formService.submit = jest.fn().mockReturnValue(of(commandStateResource)); @@ -126,7 +135,7 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { expect(component.saveStateResource$).toBeObservable(singleColdCompleted(commandStateResource)); }); - it('should handle successfully saved bescheid', () => { + it('should close dialog with wizard', () => { const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); formService.submit = jest.fn().mockReturnValue(of(commandStateResource)); @@ -136,7 +145,7 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { expect(component.closeDialogWithWizard).toHaveBeenCalled(); }); - it('should NOT handle successfully saved bescheid', () => { + it('should NOT close dialog with wizard', () => { const commandStateResource: StateResource<CommandResource> = createErrorStateResource(createApiError()); formService.submit = jest.fn().mockReturnValue(of(commandStateResource)); @@ -155,20 +164,20 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { it('should delete bescheid', () => { component.cancel(); - expect(bescheidService.bescheidVerwerfen).toHaveBeenCalled(); + expect(bescheidService.deleteBescheid).toHaveBeenCalled(); }); - it('should NOT delete bescheid', () => { - component.bescheidResource = null; + it('should NOT delete bescheid', async () => { + await configureTestingModule({} as CancelWizardDialogData); component.cancel(); - expect(bescheidService.bescheidVerwerfen).not.toHaveBeenCalled(); + expect(bescheidService.deleteBescheid).not.toHaveBeenCalled(); }); - it('should emit delete command state resource', () => { + it('should set delete command state resource', () => { const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); - bescheidService.bescheidVerwerfen = jest.fn().mockReturnValue(of(commandStateResource)); + bescheidService.deleteBescheid = jest.fn().mockReturnValue(of(commandStateResource)); component.cancel(); @@ -177,7 +186,7 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { it('should close dialog on success', () => { const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); - bescheidService.bescheidVerwerfen = jest.fn().mockReturnValue(of(commandStateResource)); + bescheidService.deleteBescheid = jest.fn().mockReturnValue(of(commandStateResource)); component.cancel(); component.deleteStateResource$.subscribe(); @@ -187,7 +196,7 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { it('should NOT close dialog on error', () => { const commandStateResource: StateResource<CommandResource> = createErrorStateResource(createApiError()); - bescheidService.bescheidVerwerfen = jest.fn().mockReturnValue(of(commandStateResource)); + bescheidService.deleteBescheid = jest.fn().mockReturnValue(of(commandStateResource)); component.cancel(); component.deleteStateResource$.subscribe(); @@ -195,8 +204,9 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { expect(component.closeDialogWithWizard).not.toHaveBeenCalled(); }); - it('should close dialog with cancel result on non existing bescheid', () => { - component.bescheidResource = null; + it('should close dialog with cancel result on non existing bescheid', async () => { + await configureTestingModule({} as CancelWizardDialogData); + component.closeDialogWithWizard = jest.fn(); component.cancel(); @@ -214,25 +224,23 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { }); describe('template', () => { - describe('ozgcloud-stroked-button-with-spinner Entwurf speichern', () => { - it('should show', () => { + describe('save button', () => { + it('should exists', () => { existsAsHtmlElement(fixture, speichernButton); }); - describe('input', () => { - it('should set stateResource', () => { - const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); - component.saveStateResource$ = of(commandStateResource); + it('should have been called with inputs', () => { + const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); + component.saveStateResource$ = of(commandStateResource); - const elementComponent: OzgcloudStrokedButtonWithSpinnerComponent = getElementComponentFromFixtureByCss( - fixture, - speichernButton, - ); + const elementComponent: OzgcloudStrokedButtonWithSpinnerComponent = getElementComponentFromFixtureByCss( + fixture, + speichernButton, + ); - fixture.detectChanges(); + fixture.detectChanges(); - expect(elementComponent.stateResource).toBe(commandStateResource); - }); + expect(elementComponent.stateResource).toBe(commandStateResource); }); describe('output', () => { @@ -246,25 +254,23 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { }); }); - describe('ozgcloud-stroked-button-with-spinner Verwerfen', () => { - it('should show', () => { + describe('delete button', () => { + it('should exists', () => { existsAsHtmlElement(fixture, verwerfenButton); }); - describe('input', () => { - it('should set stateResource', () => { - const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); - component.deleteStateResource$ = of(commandStateResource); + it('should have been called with inputs', () => { + const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); + component.deleteStateResource$ = of(commandStateResource); - const elementComponent: OzgcloudStrokedButtonWithSpinnerComponent = getElementComponentFromFixtureByCss( - fixture, - verwerfenButton, - ); + const elementComponent: OzgcloudStrokedButtonWithSpinnerComponent = getElementComponentFromFixtureByCss( + fixture, + verwerfenButton, + ); - fixture.detectChanges(); + fixture.detectChanges(); - expect(elementComponent.stateResource).toBe(commandStateResource); - }); + expect(elementComponent.stateResource).toBe(commandStateResource); }); describe('output', () => { diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.ts index ae452113e7c35d55c6341ba1c79aa0fadb2005d3..2b2ee2327c607f41cc889b00a62c84ff3b9560b2 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.ts @@ -21,13 +21,14 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidResource, BescheidService } from '@alfa-client/bescheid-shared'; +import { BescheidResource } from '@alfa-client/bescheid-shared'; import { tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared'; -import { StateResource, isNotNil } from '@alfa-client/tech-shared'; +import { isNotNil, StateResource } from '@alfa-client/tech-shared'; import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog'; -import { Component, Inject } from '@angular/core'; +import { Component, inject, OnDestroy, OnInit } from '@angular/core'; import { Resource } from '@ngxp/rest'; import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; import { BescheidFormService } from '../../bescheid.formservice'; export interface CancelWizardDialogData { @@ -41,19 +42,23 @@ export interface CancelWizardDialogResult { @Component({ templateUrl: './bescheid-wizard-cancel-dialog-container.component.html', }) -export class BescheidWizardCancelDialogContainerComponent { +export class BescheidWizardCancelDialogContainerComponent implements OnInit, OnDestroy { + private readonly dialogData: CancelWizardDialogData = inject(DIALOG_DATA); + private readonly dialogRef = inject(DialogRef); + private readonly bescheidService = inject(BescheidService2); + private readonly formService = inject(BescheidFormService); + public saveStateResource$: Observable<StateResource<Resource>>; public deleteStateResource$: Observable<StateResource<Resource>>; - bescheidResource: BescheidResource; + private readonly bescheidResource: BescheidResource = this.dialogData.bescheidResource; + + ngOnInit(): void { + this.bescheidService.lockBescheidSending(); + } - constructor( - @Inject(DIALOG_DATA) readonly dialogData: CancelWizardDialogData, - public dialogRef: DialogRef<CancelWizardDialogResult>, - private readonly bescheidService: BescheidService, - private readonly formService: BescheidFormService, - ) { - this.bescheidResource = dialogData.bescheidResource; + ngOnDestroy(): void { + this.bescheidService.unlockBescheidSending(); } public save(): void { @@ -63,7 +68,7 @@ export class BescheidWizardCancelDialogContainerComponent { public cancel(): void { if (isNotNil(this.bescheidResource)) { this.deleteStateResource$ = this.bescheidService - .bescheidVerwerfen() + .deleteBescheid() .pipe(tapOnCommandSuccessfullyDone(() => this.closeDialogWithWizard())); } else { this.closeDialogWithWizard(); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..e1c9cb9a825ec71879a005c00d792e406280dfc3 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.html @@ -0,0 +1,6 @@ +<alfa-bescheid-wizard-create-document-button + [bescheidResource]="bescheidResource" + [bescheidDocument]="bescheidDocument$ | async" + (clickEmitter)="createBescheidDocument()" + data-test-id="bescheid-wizard-create-button" +></alfa-bescheid-wizard-create-document-button> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..578b614b16d24e6b9d40ed36e1a0608b04781e24 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.spec.ts @@ -0,0 +1,100 @@ +import { BescheidDocument, BescheidResource } from '@alfa-client/bescheid-shared'; +import { existsAsHtmlElement, getElementComponentFromFixtureByCss, mock, Mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidDocument, createBescheidResource } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { BescheidWizardCreateDocumentButtonContainerComponent } from './bescheid-wizard-create-document-button-container.component'; +import { BescheidWizardCreateDocumentButtonComponent } from './create-document-button/bescheid-wizard-create-document-button.component'; + +describe('BescheidWizardCreateDocumentButtonContainerComponent', () => { + let component: BescheidWizardCreateDocumentButtonContainerComponent; + let fixture: ComponentFixture<BescheidWizardCreateDocumentButtonContainerComponent>; + + const buttonTestId: string = getDataTestIdOf('bescheid-wizard-create-button'); + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + const bescheidResource: BescheidResource = createBescheidResource(); + + let bescheidService: Mock<BescheidService2>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardCreateDocumentButtonContainerComponent, + MockComponent(BescheidWizardCreateDocumentButtonComponent), + ], + providers: [{ provide: BescheidService2, useValue: bescheidService }], + }).compileComponents(); + + createComponent(); + }); + + function createComponent() { + fixture = TestBed.createComponent(BescheidWizardCreateDocumentButtonContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + } + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + createComponent(); + + expect(component.bescheidDocument$).toBeObservable(singleColdCompleted(bescheidDocument)); + }); + + describe('createBescheidDocument', () => { + it('should call service', () => { + component.createBescheidDocument(); + + expect(bescheidService.createBescheidDocument).toHaveBeenCalledWith(component.bescheidResource); + }); + }); + }); + + describe('template', () => { + describe('create button', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, buttonTestId); + }); + + it('should have been called with inputs', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + createComponent(); + component.bescheidResource = bescheidResource; + + fixture.detectChanges(); + + const buttonComponent: BescheidWizardCreateDocumentButtonComponent = + getElementComponentFromFixtureByCss<BescheidWizardCreateDocumentButtonComponent>(fixture, buttonTestId); + + expect(buttonComponent.bescheidResource).toEqual(bescheidResource); + expect(buttonComponent.bescheidDocument).toEqual(bescheidDocument); + }); + + describe('output', () => { + describe('clickEmitter', () => { + it('should call handler', () => { + component.createBescheidDocument = jest.fn(); + + triggerEvent({ fixture, elementSelector: buttonTestId, name: 'clickEmitter' }); + + expect(component.createBescheidDocument).toHaveBeenCalled(); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..63c525d76932091bdf971c5789c843568afd8112 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.ts @@ -0,0 +1,20 @@ +import { BescheidDocument, BescheidResource } from '@alfa-client/bescheid-shared'; +import { Component, inject, Input } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; + +@Component({ + selector: 'alfa-bescheid-wizard-create-document-button-container', + templateUrl: './bescheid-wizard-create-document-button-container.component.html', +}) +export class BescheidWizardCreateDocumentButtonContainerComponent { + @Input() bescheidResource: BescheidResource; + + private readonly bescheidService = inject(BescheidService2); + + public readonly bescheidDocument$: Observable<BescheidDocument> = this.bescheidService.getBescheidDocument(); + + public createBescheidDocument(): void { + this.bescheidService.createBescheidDocument(this.bescheidResource); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.html new file mode 100644 index 0000000000000000000000000000000000000000..db9307187ec8c100d91ff2c2ffc7b99dd22fc5e2 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.html @@ -0,0 +1,12 @@ +@if (bescheidResource | hasLink: BescheidLinkRel.CREATE_DOCUMENT) { + <ods-button-card + class="w-full max-w-72" + [isLoading]="bescheidDocument.create.loading" + (click)="clickEmitter.emit()" + text="Bescheiddokument" + subText="automatisch erstellen" + data-test-id="create-bescheid-document-button" + > + <ods-bescheid-generate-icon icon /> + </ods-button-card> +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..0870d4c34bd3f5dab6ae510dfe171877bc700590 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.spec.ts @@ -0,0 +1,119 @@ +import { BescheidDocument, BescheidLinkRel, createEmptyBescheidDocument } from '@alfa-client/bescheid-shared'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + mock, + Mock, + notExistsAsHtmlElement, + triggerEvent, +} from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { BescheidGenerateIconComponent, ButtonCardComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { createBescheidDocument, createBescheidResource } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { BescheidFormService } from '../../../bescheid.formservice'; +import { BescheidWizardCreateDocumentButtonComponent } from './bescheid-wizard-create-document-button.component'; + +describe('BescheidWizardAutomatischErstellenButtonComponent', () => { + let component: BescheidWizardCreateDocumentButtonComponent; + let fixture: ComponentFixture<BescheidWizardCreateDocumentButtonComponent>; + + const createButtonTestId: string = getDataTestIdOf('create-bescheid-document-button'); + + let formService: Mock<BescheidFormService>; + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + beforeEach(() => { + formService = mock(BescheidFormService); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardCreateDocumentButtonComponent, + MockComponent(ButtonCardComponent), + MockComponent(BescheidGenerateIconComponent), + HasLinkPipe, + ], + providers: [{ provide: BescheidFormService, useValue: formService }], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardCreateDocumentButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.bescheidDocument).toEqual(createEmptyBescheidDocument()); + }); + + describe('set bescheid document', () => { + it('should set value', () => { + component.bescheidDocument = bescheidDocument; + + expect(component.bescheidDocument).toEqual(bescheidDocument); + }); + + it('should call form service', () => { + component.bescheidDocument = bescheidDocument; + + expect(formService.updateBescheidDocumentFile).toHaveBeenCalledWith(bescheidDocument.documentUri); + }); + }); + }); + + describe('template', () => { + describe('create button', () => { + it('should exists', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.CREATE_DOCUMENT]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, createButtonTestId); + }); + + it('should NOT exists', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, createButtonTestId); + }); + + it('should have been called with inputs', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.CREATE_DOCUMENT]); + component.bescheidDocument = bescheidDocument; + + fixture.detectChanges(); + const buttonComponent: ButtonCardComponent = getElementComponentFromFixtureByCss<ButtonCardComponent>( + fixture, + createButtonTestId, + ); + + expect(buttonComponent.isLoading).toEqual(bescheidDocument.create.loading); + }); + + describe('output', () => { + describe('clickEmitter', () => { + it('should emit', () => { + component.clickEmitter.emit = jest.fn(); + component.bescheidResource = createBescheidResource([BescheidLinkRel.CREATE_DOCUMENT]); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: createButtonTestId, name: 'click' }); + + expect(component.clickEmitter.emit).toHaveBeenCalled(); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..083aec95ac2ddd1d4b030e8ab57a3baf6b55f72e --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.ts @@ -0,0 +1,28 @@ +import { BescheidDocument, BescheidLinkRel, BescheidResource, createEmptyBescheidDocument } from '@alfa-client/bescheid-shared'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { BescheidFormService } from '../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-create-document-button', + templateUrl: './bescheid-wizard-create-document-button.component.html', +}) +export class BescheidWizardCreateDocumentButtonComponent { + @Input() bescheidResource: BescheidResource; + + @Input() set bescheidDocument(value: BescheidDocument) { + this._bescheidDocument = value; + this.formService.updateBescheidDocumentFile(value.documentUri); + } + + get bescheidDocument(): BescheidDocument { + return this._bescheidDocument; + } + + @Output() clickEmitter: EventEmitter<void> = new EventEmitter<void>(); + + private readonly formService = inject(BescheidFormService); + + private _bescheidDocument: BescheidDocument = createEmptyBescheidDocument(); + + public readonly BescheidLinkRel = BescheidLinkRel; +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..dcf2a2ac6fc332f13bd56c900007dd25d16a2375 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.html @@ -0,0 +1,7 @@ +<alfa-bescheid-wizard-document-file + [bescheidDocument]="bescheidDocument$ | async" + [deletable]="(activeStep$ | async) === bescheidWizardStep.DokumenteHochladen" + (deleteFile)="deleteBescheidDocument()" + data-test-id="bescheid-document" +> +</alfa-bescheid-wizard-document-file> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..9171b0143e8af45416b48d4a779d6e277ad0a5ef --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.spec.ts @@ -0,0 +1,123 @@ +import { BescheidDocument, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { existsAsHtmlElement, getElementComponentFromFixtureByCss, Mock, mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidDocument } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { BescheidFormService } from '../../bescheid.formservice'; +import { BescheidWizardDocumentFileContainerComponent } from './bescheid-wizard-document-file-container.component'; +import { BescheidWizardDocumentFileComponent } from './document-file/bescheid-wizard-document-file.component'; + +describe('BescheidWizardDocumentFileContainerComponent', () => { + let component: BescheidWizardDocumentFileContainerComponent; + let fixture: ComponentFixture<BescheidWizardDocumentFileContainerComponent>; + + const documentFileTestId: string = getDataTestIdOf('bescheid-document'); + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + let bescheidService: Mock<BescheidService2>; + let formService: Mock<BescheidFormService>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + formService = mock(BescheidFormService); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BescheidWizardDocumentFileContainerComponent, MockComponent(BescheidWizardDocumentFileComponent)], + providers: [ + { provide: BescheidService2, useValue: bescheidService }, + { provide: BescheidFormService, useValue: formService }, + ], + }).compileComponents(); + + createComponent(); + }); + + function createComponent() { + fixture = TestBed.createComponent(BescheidWizardDocumentFileContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + } + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + bescheidService.getActiveStep.mockReturnValue(of(BescheidWizardStep.BescheidVersenden)); + + createComponent(); + + expect(component.bescheidDocument$).toBeObservable(singleColdCompleted(bescheidDocument)); + expect(component.activeStep$).toBeObservable(singleColdCompleted(BescheidWizardStep.BescheidVersenden)); + }); + + describe('deleteBescheidDocument', () => { + it('should call form service', () => { + component.deleteBescheidDocument(); + + expect(formService.clearBescheidDocumentFile).toHaveBeenCalled(); + expect(bescheidService.deleteBescheidDocument).toHaveBeenCalled(); + }); + }); + }); + + describe('template', () => { + describe('document file', () => { + function getComponent(): BescheidWizardDocumentFileComponent { + return getElementComponentFromFixtureByCss<BescheidWizardDocumentFileComponent>(fixture, documentFileTestId); + } + + it('should exists', () => { + existsAsHtmlElement(fixture, documentFileTestId); + }); + + it('should have been called with bescheid document', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + + createComponent(); + fixture.detectChanges(); + + expect(getComponent().bescheidDocument).toEqual(bescheidDocument); + }); + + it('should have been called with deletable true', () => { + bescheidService.getActiveStep.mockReturnValue(of(BescheidWizardStep.DokumenteHochladen)); + + createComponent(); + fixture.detectChanges(); + + expect(getComponent().deletable).toEqual(true); + }); + + it('should have been called with deletable false', () => { + bescheidService.getActiveStep.mockReturnValue(of(BescheidWizardStep.BescheidVersenden)); + + createComponent(); + fixture.detectChanges(); + + expect(getComponent().deletable).toEqual(false); + }); + + describe('output', () => { + describe('deleteFile', () => { + it('should call handler', () => { + component.deleteBescheidDocument = jest.fn(); + + triggerEvent({ fixture, elementSelector: documentFileTestId, name: 'deleteFile' }); + + expect(component.deleteBescheidDocument).toHaveBeenCalled(); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..f50758a6f2914eacb0f1f0a3711e6d0eec3f5d13 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.ts @@ -0,0 +1,24 @@ +import { BescheidDocument, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { Component, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { BescheidFormService } from '../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-document-file-container', + templateUrl: './bescheid-wizard-document-file-container.component.html', +}) +export class BescheidWizardDocumentFileContainerComponent { + private readonly bescheidService = inject(BescheidService2); + private readonly formService = inject(BescheidFormService); + + public readonly bescheidDocument$: Observable<BescheidDocument> = this.bescheidService.getBescheidDocument(); + public readonly activeStep$: Observable<BescheidWizardStep> = this.bescheidService.getActiveStep(); + + public readonly bescheidWizardStep = BescheidWizardStep; + + public deleteBescheidDocument(): void { + this.formService.clearBescheidDocumentFile(); + this.bescheidService.deleteBescheidDocument(); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.html new file mode 100644 index 0000000000000000000000000000000000000000..c77ff1d88a92fcc3b6141fb911ac50580ffa9b95 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.html @@ -0,0 +1,28 @@ +<ods-attachment-wrapper> + @if (showAutomaticCreation) { + <ods-attachment + errorCaption="Fehler beim automatischen Erstellen" + loadingCaption="Bescheiddokument" + description="Bescheiddokument wird erstellt" + [isLoading]="bescheidDocument.create.loading" + [errorMessages]="createDocumentErrorMessages" + data-test-id="create-bescheid-document-attachment" + ></ods-attachment> + } + + @if (showUpload) { + <ods-attachment + errorCaption="Fehler beim Hochladen" + [loadingCaption]="bescheidDocument.upload.fileName" + [attr.data-test-id]="'upload-bescheid-document'" + [isLoading]="bescheidDocument.upload.loading" + [errorMessages]="bescheidDocument.upload.error | convertProblemDetailToErrorMessages" + description="Bescheiddokument wird hochgeladen" + ></ods-attachment> + } + + @if (showDocument) { + <alfa-binary-file2-container [file]="bescheidDocument.resource" [deletable]="deletable" (startDelete)="deleteFile.emit()" data-test-id="bescheid-document-binary-file"> + </alfa-binary-file2-container> + } +</ods-attachment-wrapper> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..412b4eb3ff92220473ee167ef709f8fbf3baf77d --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.spec.ts @@ -0,0 +1,301 @@ +import { BescheidDocument, createEmptyBescheidDocument, createEmptyUploadInProgress } from '@alfa-client/bescheid-shared'; +import { BinaryFile2ContainerComponent } from '@alfa-client/binary-file'; +import { + ConvertProblemDetailToErrorMessagesPipe, + createEmptyStateResource, + createErrorStateResource, + createLoadingStateResource, + ProblemDetail, +} from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + notExistsAsHtmlElement, + triggerEvent, +} from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { AttachmentComponent, AttachmentWrapperComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { + createBescheidDocument, + createErrorUpload, + createPendingUpload, + createSuccessfulUpload, +} from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../command-shared/test/command'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { createProblemDetail } from '../../../../../../../tech-shared/test/error'; +import { BescheidWizardDocumentFileComponent } from './bescheid-wizard-document-file.component'; + +describe('BescheidWizardDocumentFileComponent', () => { + let component: BescheidWizardDocumentFileComponent; + let fixture: ComponentFixture<BescheidWizardDocumentFileComponent>; + + const convertProblemDetailsToErrorMessages: ConvertProblemDetailToErrorMessagesPipe = + new ConvertProblemDetailToErrorMessagesPipe(); + + const createBescheidTestId: string = getDataTestIdOf('create-bescheid-document-attachment'); + const uploadBescheidTestId: string = getDataTestIdOf('upload-bescheid-document'); + const bescheidDocumentTestId: string = getDataTestIdOf('bescheid-document-binary-file'); + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardDocumentFileComponent, + MockComponent(AttachmentWrapperComponent), + MockComponent(AttachmentComponent), + MockComponent(BinaryFile2ContainerComponent), + ConvertProblemDetailToErrorMessagesPipe, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardDocumentFileComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.showAutomaticCreation).toEqual(false); + expect(component.showUpload).toEqual(false); + expect(component.showDocument).toEqual(false); + expect(component.createDocumentErrorMessages).toEqual([]); + expect(component.bescheidDocument).toEqual(createEmptyBescheidDocument()); + }); + + describe('set bescheid document', () => { + it('should update component state', () => { + component.update = jest.fn(); + + component.bescheidDocument = bescheidDocument; + + expect(component.update).toHaveBeenCalled(); + }); + }); + + describe('update', () => { + it('should set bescheid document', () => { + component.update(bescheidDocument); + + expect(component.bescheidDocument).toEqual(bescheidDocument); + }); + + it('should show automatic creation on loading', () => { + component.update({ ...bescheidDocument, create: createLoadingStateResource() }); + + expect(component.showAutomaticCreation).toEqual(true); + }); + + it('should show automatic creation on error', () => { + component.update({ + ...bescheidDocument, + create: createErrorStateResource(createProblemDetail()), + }); + + expect(component.showAutomaticCreation).toEqual(true); + }); + + it('should show upload on loading', () => { + component.update({ ...bescheidDocument, upload: createPendingUpload() }); + + expect(component.showUpload).toEqual(true); + }); + + it('should show upload on error', () => { + component.update({ + ...bescheidDocument, + upload: createErrorUpload(), + }); + + expect(component.showUpload).toEqual(true); + }); + + it('should show created document', () => { + component.update({ + ...bescheidDocument, + create: createSuccessfullyDoneCommandStateResource(), + upload: createEmptyUploadInProgress(), + }); + + expect(component.showDocument).toEqual(true); + }); + + it('should show uploaded document', () => { + component.update({ + ...bescheidDocument, + create: createEmptyStateResource(), + upload: createSuccessfulUpload(), + }); + + expect(component.showDocument).toEqual(true); + }); + + it('should NOT show document on pending creation', () => { + component.update({ + ...bescheidDocument, + create: createLoadingStateResource(), + upload: createEmptyUploadInProgress(), + }); + + expect(component.showDocument).toEqual(false); + }); + + it('should NOT show document on pending upload', () => { + component.update({ + ...bescheidDocument, + create: createEmptyStateResource(), + upload: createPendingUpload(), + }); + + expect(component.showDocument).toEqual(false); + }); + + it('should NOT show document if not exists', () => { + component.update({ + ...bescheidDocument, + resource: null, + create: createEmptyStateResource(), + upload: createPendingUpload(), + }); + + expect(component.showDocument).toEqual(false); + }); + + it('should have error messages', () => { + component.update({ + ...bescheidDocument, + create: createErrorStateResource(createProblemDetail()), + upload: createEmptyUploadInProgress(), + }); + + expect(component.createDocumentErrorMessages).toEqual([BescheidWizardDocumentFileComponent.CREATE_ERROR_MESSAGE]); + }); + + it('should NOT have error messages', () => { + component.update({ + ...bescheidDocument, + create: createSuccessfullyDoneCommandStateResource(), + upload: createEmptyUploadInProgress(), + }); + + expect(component.createDocumentErrorMessages).toEqual([]); + }); + }); + }); + + describe('template', () => { + describe('automatic creation attachment', () => { + it('should exists', () => { + component.showAutomaticCreation = true; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, createBescheidTestId); + }); + + it('should NOT exists', () => { + component.showAutomaticCreation = false; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, createBescheidTestId); + }); + + it('should have been called with inputs', () => { + component.showAutomaticCreation = true; + + fixture.detectChanges(); + const attachmentComponent: AttachmentComponent = getElementComponentFromFixtureByCss<AttachmentComponent>( + fixture, + createBescheidTestId, + ); + + expect(attachmentComponent.isLoading).toEqual(component.bescheidDocument.create.loading); + expect(attachmentComponent.errorMessages).toEqual(component.createDocumentErrorMessages); + }); + }); + + describe('upload file', () => { + it('should exists', () => { + component.showUpload = true; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, uploadBescheidTestId); + }); + + it('should NOT exists', () => { + component.showUpload = false; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, uploadBescheidTestId); + }); + + it('should have been called with inputs', () => { + component.showUpload = true; + + fixture.detectChanges(); + const attachmentComponent: AttachmentComponent = getElementComponentFromFixtureByCss<AttachmentComponent>( + fixture, + uploadBescheidTestId, + ); + + expect(attachmentComponent.loadingCaption).toEqual(component.bescheidDocument.upload.fileName); + expect(attachmentComponent.isLoading).toEqual(component.bescheidDocument.upload.loading); + expect(attachmentComponent.errorMessages).toEqual( + convertProblemDetailsToErrorMessages.transform(component.bescheidDocument.upload.error as ProblemDetail), + ); + }); + }); + + describe('document binary file', () => { + it('should exists', () => { + component.showDocument = true; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, bescheidDocumentTestId); + }); + + it('should NOT exists', () => { + component.showDocument = false; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, bescheidDocumentTestId); + }); + + it('should have been called with inputs', () => { + component.showDocument = true; + + fixture.detectChanges(); + const attachmentComponent: BinaryFile2ContainerComponent = + getElementComponentFromFixtureByCss<BinaryFile2ContainerComponent>(fixture, bescheidDocumentTestId); + + expect(attachmentComponent.file).toEqual(component.bescheidDocument.resource); + expect(attachmentComponent.deletable).toEqual(component.deletable); + }); + + describe('output', () => { + describe('startDelete', () => { + it('should emit', () => { + component.showDocument = true; + fixture.detectChanges(); + component.deleteFile.emit = jest.fn(); + + triggerEvent({ fixture, elementSelector: bescheidDocumentTestId, name: 'startDelete' }); + + expect(component.deleteFile.emit).toHaveBeenCalled(); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..231c486fde2bcae1b49a21eca2319751b76865c4 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.ts @@ -0,0 +1,39 @@ +import { BescheidDocument, createEmptyBescheidDocument } from '@alfa-client/bescheid-shared'; +import { hasStateResourceError, isNotNil } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +@Component({ + selector: 'alfa-bescheid-wizard-document-file', + templateUrl: './bescheid-wizard-document-file.component.html', +}) +export class BescheidWizardDocumentFileComponent { + static readonly CREATE_ERROR_MESSAGE = 'Bescheiddokument konnte nicht erzeugt werden.'; + + @Input() set bescheidDocument(value: BescheidDocument) { + this.update(value); + } + + get bescheidDocument(): BescheidDocument { + return this._bescheidDocument; + } + + @Input() public deletable: boolean; + + @Output() deleteFile: EventEmitter<void> = new EventEmitter<void>(); + + public showAutomaticCreation: boolean = false; + public showUpload: boolean = false; + public showDocument: boolean = false; + public createDocumentErrorMessages: string[] = []; + + private _bescheidDocument: BescheidDocument = createEmptyBescheidDocument(); + + update(value: BescheidDocument) { + this._bescheidDocument = value; + this.showAutomaticCreation = value.create.loading || hasStateResourceError(value.create); + this.showUpload = value.upload.loading || isNotNil(value.upload.error); + this.showDocument = isNotNil(value.resource) && !value.upload.loading && !value.create.loading; + this.createDocumentErrorMessages = + hasStateResourceError(value.create) ? [BescheidWizardDocumentFileComponent.CREATE_ERROR_MESSAGE] : []; + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..c039d147b1d8c2f8be9d3fe0f63ef42ccd1a0972 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.html @@ -0,0 +1,53 @@ +<!-- + + Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + Ministerpräsidenten des Landes Schleswig-Holstein + Staatskanzlei + Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + + Lizenziert unter der EUPL, Version 1.2 oder - sobald + diese von der Europäischen Kommission genehmigt wurden - + Folgeversionen der EUPL ("Lizenz"); + Sie dürfen dieses Werk ausschließlich gemäß + dieser Lizenz nutzen. + Eine Kopie der Lizenz finden Sie hier: + + https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + + Sofern nicht durch anwendbare Rechtsvorschriften + gefordert oder in schriftlicher Form vereinbart, wird + die unter der Lizenz verbreitete Software "so wie sie + ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + ausdrücklich oder stillschweigend - verbreitet. + Die sprachspezifischen Genehmigungen und Beschränkungen + unter der Lizenz sind dem Lizenztext zu entnehmen. + +--> +<alfa-step-content-layout + [activeStep]="BescheidWizardStep.DokumenteHochladen" + (stepChange)="onStepChange($event)" + data-test-id="step-content-layout" +> + <ng-container stepPanel> + <alfa-bescheid-wizard-step-title + label="Antrag bescheiden" + [inactiveStep]="true" + data-test-id="antrag-bescheiden-step-title" + /> + <alfa-bescheid-wizard-step-title label="Dokumente hinzufügen" /> + <alfa-bescheid-wizard-dokumente-hochladen-form + [bescheidResource]="bescheidResource" + [bescheidDocument]="bescheidDocument$ | async" + (weiterClickEmitter)="onWeiterClick()" + (bescheidDocumentMissing)="onBescheidDocumentMissing($event)" + data-test-id="bescheid-wizard-dokumente-hochladen-form" + /> + </ng-container> + <ng-container summary> + <alfa-bescheid-wizard-antrag-bescheiden-summary /> + <alfa-bescheid-wizard-dokumente-hochladen-summary + [isBescheidDocumentMissing]="isBescheidDocumentMissing" + data-test-id="bescheid-wizard-dokumente-hochladen-summary" + /> + </ng-container> +</alfa-step-content-layout> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..749ab02b1417d171af7d7549c1c2994d4116fc04 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.spec.ts @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { BescheidDocument, BescheidResource, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { getElementComponentFromFixtureByCss, Mock, mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { expect } from '@jest/globals'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidDocument, createBescheidResource } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { BescheidWizardAntragBescheidenSummaryComponent } from '../antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component'; +import { StepContentLayoutComponent } from '../step-content-layout/step-content-layout.component'; +import { BescheidWizardStepTitleComponent } from '../step-title/bescheid-wizard-step-title.component'; +import { BescheidWizardStepperComponent } from '../stepper/bescheid-wizard-stepper.component'; +import { BescheidWizardSummaryComponent } from '../summary/bescheid-wizard-summary.component'; +import { BescheidWizardDokumenteHochladenContainerComponent } from './bescheid-wizard-dokumente-hochladen-container.component'; +import { BescheidWizardDokumenteHochladenFormComponent } from './form/bescheid-wizard-dokumente-hochladen-form.component'; +import { BescheidWizardDokumenteHochladenSummaryComponent } from './summary/bescheid-wizard-dokumente-hochladen-summary.component'; + +describe('BescheidWizardDokumenteHochladenComponent', () => { + let component: BescheidWizardDokumenteHochladenContainerComponent; + let fixture: ComponentFixture<BescheidWizardDokumenteHochladenContainerComponent>; + + const stepContentLayout: string = getDataTestIdOf('step-content-layout'); + const antragBescheidenStepTitleTestId: string = getDataTestIdOf('antrag-bescheiden-step-title'); + const dokumenteHochladenFormTestId: string = getDataTestIdOf('bescheid-wizard-dokumente-hochladen-form'); + const dokumenteHochladenSummaryTestId: string = getDataTestIdOf('bescheid-wizard-dokumente-hochladen-summary'); + + const bescheidResource: BescheidResource = createBescheidResource(); + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + let bescheidService: Mock<BescheidService2>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardDokumenteHochladenContainerComponent, + MockComponent(StepContentLayoutComponent), + MockComponent(BescheidWizardSummaryComponent), + MockComponent(BescheidWizardAntragBescheidenSummaryComponent), + MockComponent(BescheidWizardDokumenteHochladenSummaryComponent), + MockComponent(BescheidWizardStepTitleComponent), + MockComponent(BescheidWizardDokumenteHochladenFormComponent), + MockComponent(BescheidWizardStepperComponent), + ], + providers: [{ provide: BescheidService2, useValue: bescheidService }], + }).compileComponents(); + + createComponent(); + }); + + function createComponent() { + fixture = TestBed.createComponent(BescheidWizardDokumenteHochladenContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + } + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + + createComponent(); + + expect(component.bescheidDocument$).toBeObservable(singleColdCompleted(bescheidDocument)); + }); + + describe('ngOnInit', () => { + it('should load files', () => { + component.ngOnInit(); + + expect(bescheidService.loadFiles).toHaveBeenCalled(); + }); + }); + + describe('set bescheid resource', () => { + it('should set value', () => { + component.bescheidResource = bescheidResource; + + expect(component.bescheidResource).toEqual(bescheidResource); + }); + }); + + describe('onWeiterClick', () => { + it('should finish adding attachments', () => { + component.onWeiterClick(); + + expect(bescheidService.finishAddingAttachments).toHaveBeenCalled(); + }); + + it('should finish adding bescheid document', () => { + component.onWeiterClick(); + + expect(bescheidService.finishAddingBescheidDocument).toHaveBeenCalled(); + }); + + it('should change active step', () => { + component.onWeiterClick(); + + expect(bescheidService.setActiveStep).toHaveBeenCalledWith(BescheidWizardStep.BescheidVersenden); + }); + }); + + describe('onBescheidDocumentMissing', () => { + it('should set value', () => { + component.isBescheidDocumentMissing = false; + + component.onBescheidDocumentMissing(true); + + expect(component.isBescheidDocumentMissing).toEqual(true); + }); + }); + + describe('onStepChange', () => { + it('should change step', () => { + component.onStepChange(BescheidWizardStep.AntragBescheiden); + + expect(bescheidService.setActiveStep).toHaveBeenCalledWith(BescheidWizardStep.AntragBescheiden); + }); + }); + }); + + describe('template', () => { + describe('step content layout', () => { + describe('output', () => { + it('should call handler', () => { + component.onStepChange = jest.fn(); + + triggerEvent({ + fixture, + name: 'stepChange', + elementSelector: stepContentLayout, + data: BescheidWizardStep.AntragBescheiden, + }); + + expect(component.onStepChange).toHaveBeenCalledWith(BescheidWizardStep.AntragBescheiden); + }); + }); + }); + + describe('antrag bescheiden step title', () => { + it('should have been called with inputs', () => { + const stepTitle: BescheidWizardStepTitleComponent = getElementComponentFromFixtureByCss<BescheidWizardStepTitleComponent>( + fixture, + antragBescheidenStepTitleTestId, + ); + + expect(stepTitle.inactiveStep).toBeTruthy(); + }); + }); + + describe('hochladen form', () => { + it('should have been called with inputs', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + createComponent(); + component.bescheidResource = bescheidResource; + + fixture.detectChanges(); + const hochladenForm: BescheidWizardDokumenteHochladenFormComponent = + getElementComponentFromFixtureByCss<BescheidWizardDokumenteHochladenFormComponent>( + fixture, + dokumenteHochladenFormTestId, + ); + + expect(hochladenForm.bescheidResource).toEqual(bescheidResource); + expect(hochladenForm.bescheidDocument).toEqual(bescheidDocument); + }); + + describe('output', () => { + describe('weiterClickEmitter', () => { + it('should call handler', () => { + component.onWeiterClick = jest.fn(); + + triggerEvent({ fixture, elementSelector: dokumenteHochladenFormTestId, name: 'weiterClickEmitter' }); + + expect(component.onWeiterClick).toHaveBeenCalled(); + }); + }); + + describe('bescheidDocumentMissing', () => { + it('should call handler', () => { + component.onBescheidDocumentMissing = jest.fn(); + + triggerEvent({ fixture, elementSelector: dokumenteHochladenFormTestId, name: 'bescheidDocumentMissing' }); + + expect(component.onBescheidDocumentMissing).toHaveBeenCalled(); + }); + }); + }); + }); + + describe('hochladen summary', () => { + it('should have been called with inputs', () => { + component.isBescheidDocumentMissing = true; + + fixture.detectChanges(); + const hochladenSummary: BescheidWizardDokumenteHochladenSummaryComponent = + getElementComponentFromFixtureByCss<BescheidWizardDokumenteHochladenSummaryComponent>( + fixture, + dokumenteHochladenSummaryTestId, + ); + + expect(hochladenSummary).toBeTruthy(); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..eb90a6109b54253184476b5b3542bd31f0851d94 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.ts @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { BescheidDocument, BescheidResource, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { Component, inject, Input, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; + +@Component({ + selector: 'alfa-bescheid-wizard-dokumente-hochladen-container', + templateUrl: './bescheid-wizard-dokumente-hochladen-container.component.html', +}) +export class BescheidWizardDokumenteHochladenContainerComponent implements OnInit { + @Input() bescheidResource: BescheidResource; + + private readonly bescheidService = inject(BescheidService2); + + public readonly bescheidDocument$: Observable<BescheidDocument> = this.bescheidService.getBescheidDocument(); + public isBescheidDocumentMissing: boolean = false; + + public readonly BescheidWizardStep = BescheidWizardStep; + + ngOnInit(): void { + this.bescheidService.loadFiles(this.bescheidResource); + } + + public onWeiterClick(): void { + this.bescheidService.finishAddingAttachments(); + this.bescheidService.finishAddingBescheidDocument(); + this.bescheidService.setActiveStep(BescheidWizardStep.BescheidVersenden); + } + + public onBescheidDocumentMissing(value: boolean): void { + this.isBescheidDocumentMissing = value; + } + + public onStepChange(step: BescheidWizardStep): void { + this.bescheidService.setActiveStep(step); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.html similarity index 51% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.html rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.html index 95c0c3895cacf7701e2b189c74964fa72072056f..fd2a2ab6c43b6e00ba06a0347278e2ab53b0c5aa 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.html @@ -23,15 +23,24 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<div class="mt-2 grid h-full grid-cols-[min-content_1fr_1fr] gap-7"> - <alfa-bescheid-wizard-stepper [activeStep]="bescheidWizardStep.DokumenteHochladen"></alfa-bescheid-wizard-stepper> - <div> - <alfa-bescheid-wizard-step-title label="Antrag bescheiden" [inactiveStep]="true"></alfa-bescheid-wizard-step-title> - <alfa-bescheid-wizard-step-title label="Dokumente hochladen"></alfa-bescheid-wizard-step-title> - <alfa-bescheid-wizard-dokumente-hochladen-form></alfa-bescheid-wizard-dokumente-hochladen-form> - </div> - <alfa-bescheid-wizard-summary> - <alfa-bescheid-wizard-antrag-bescheiden-summary></alfa-bescheid-wizard-antrag-bescheiden-summary> - <alfa-bescheid-wizard-dokumente-hochladen-summary></alfa-bescheid-wizard-dokumente-hochladen-summary> - </alfa-bescheid-wizard-summary> +<div class="mt-4 flex flex-col gap-4"> + <alfa-bescheid-wizard-create-document-button-container + [bescheidResource]="bescheidResource" + data-test-id="create-document-button" + ></alfa-bescheid-wizard-create-document-button-container> + <alfa-bescheid-wizard-upload-document-button-container + [bescheidResource]="bescheidResource" + data-test-id="upload-document-button" + ></alfa-bescheid-wizard-upload-document-button-container> + <alfa-bescheid-wizard-upload-attachment-button-container + [bescheidResource]="bescheidResource" + data-test-id="upload-attachment-button" + ></alfa-bescheid-wizard-upload-attachment-button-container> + @if (bescheidResource | hasLink: bescheidLinkRel.UPDATE) { + <alfa-bescheid-wizard-weiter-button + [submitStateResource]="submitStateResource$ | async" + (clickEmitter)="gotoNextStep()" + data-test-id="weiter-button" + ></alfa-bescheid-wizard-weiter-button> + } </div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..02452fe302b69a044cef2cf621ea5a1e5734d6c2 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.spec.ts @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierun + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { BescheidDocument, BescheidLinkRel, createEmptyBescheidDocument } from '@alfa-client/bescheid-shared'; +import { CommandResource } from '@alfa-client/command-shared'; +import { HasLinkPipe, StateResource } from '@alfa-client/tech-shared'; +import { existsAsHtmlElement, getElementComponentFromFixtureByCss, mock, Mock, notExistsAsHtmlElement, triggerEvent, } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { EMPTY, of } from 'rxjs'; +import { createBescheidDocument, createBescheidResource } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../command-shared/test/command'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { BescheidFormService } from '../../../bescheid.formservice'; +import { BescheidWizardCreateDocumentButtonContainerComponent } from '../../create-document-button-container/bescheid-wizard-create-document-button-container.component'; +import { BescheidWizardUploadAttachmentButtonContainerComponent } from '../../upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component'; +import { BescheidWizardUploadDocumentButtonContainerComponent } from '../../upload-document-button-container/bescheid-wizard-upload-document-button-container.component'; +import { BescheidWizardWeiterButtonComponent } from '../../weiter-button/bescheid-wizard-weiter-button.component'; +import { BescheidWizardDokumenteHochladenFormComponent } from './bescheid-wizard-dokumente-hochladen-form.component'; + +describe('BescheidWizardDokumenteHochladenFormComponent', () => { + let component: BescheidWizardDokumenteHochladenFormComponent; + let fixture: ComponentFixture<BescheidWizardDokumenteHochladenFormComponent>; + + const createDocumentButtonTestId: string = getDataTestIdOf('create-document-button'); + const uploadDocumentButtonTestId: string = getDataTestIdOf('upload-document-button'); + const uploadAttachmentButtonTestId: string = getDataTestIdOf('upload-attachment-button'); + const weiterButtonTestId: string = getDataTestIdOf('weiter-button'); + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + let formService: Mock<BescheidFormService>; + + beforeEach(() => { + formService = mock(BescheidFormService); + formService.submit = jest.fn().mockReturnValue(EMPTY); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardDokumenteHochladenFormComponent, + MockComponent(BescheidWizardCreateDocumentButtonContainerComponent), + MockComponent(BescheidWizardUploadDocumentButtonContainerComponent), + MockComponent(BescheidWizardUploadAttachmentButtonContainerComponent), + MockComponent(BescheidWizardWeiterButtonComponent), + HasLinkPipe, + ], + providers: [{ provide: BescheidFormService, useValue: formService }], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardDokumenteHochladenFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('set bescheid document', () => { + it('should emit missing bescheid document false', () => { + component.bescheidDocumentMissing.emit = jest.fn(); + component.bescheidDocument = bescheidDocument; + + expect(component.bescheidDocumentMissing.emit).toHaveBeenCalledWith(false); + }); + + it('should NOT emit missing bescheid document', () => { + component.bescheidDocumentMissing.emit = jest.fn(); + component.bescheidDocument = createEmptyBescheidDocument(); + + expect(component.bescheidDocumentMissing.emit).not.toHaveBeenCalled(); + }); + }); + + describe('gotoNextStep', () => { + it('should emit missing bescheid document true', () => { + component.bescheidDocumentMissing.emit = jest.fn(); + component.bescheidDocument = createEmptyBescheidDocument(); + + component.gotoNextStep(); + + expect(component.bescheidDocumentMissing.emit).toHaveBeenCalledWith(true); + }); + + it('should submit form', () => { + component.bescheidDocumentMissing.emit = jest.fn(); + component.bescheidDocument = bescheidDocument; + + component.gotoNextStep(); + + expect(formService.submit).toHaveBeenCalled(); + }); + + it('should emit weiter click', () => { + component.weiterClickEmitter.emit = jest.fn(); + component.bescheidDocument = bescheidDocument; + formService.submit = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + component.gotoNextStep(); + component.submitStateResource$.subscribe(); + + expect(component.weiterClickEmitter.emit).toHaveBeenCalled(); + }); + }); + }); + + describe('template', () => { + describe('create document button', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, createDocumentButtonTestId); + }); + + it('should have been called with inputs', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + const createDocumentButton: BescheidWizardCreateDocumentButtonContainerComponent = + getElementComponentFromFixtureByCss<BescheidWizardCreateDocumentButtonContainerComponent>( + fixture, + createDocumentButtonTestId, + ); + + expect(createDocumentButton.bescheidResource).toEqual(component.bescheidResource); + }); + }); + + describe('upload document button', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, uploadDocumentButtonTestId); + }); + + it('should have been called with inputs', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + const uploadDocumentButton: BescheidWizardUploadDocumentButtonContainerComponent = + getElementComponentFromFixtureByCss<BescheidWizardUploadDocumentButtonContainerComponent>( + fixture, + uploadDocumentButtonTestId, + ); + + expect(uploadDocumentButton.bescheidResource).toEqual(component.bescheidResource); + }); + }); + + describe('upload attachment button', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, uploadAttachmentButtonTestId); + }); + + it('should have been called with inputs', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + const uploadAttachmentButton: BescheidWizardUploadAttachmentButtonContainerComponent = + getElementComponentFromFixtureByCss<BescheidWizardUploadAttachmentButtonContainerComponent>( + fixture, + uploadDocumentButtonTestId, + ); + + expect(uploadAttachmentButton.bescheidResource).toEqual(component.bescheidResource); + }); + }); + + describe('weiter button', () => { + it('should exists', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, weiterButtonTestId); + }); + + it('should NOT exists', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, weiterButtonTestId); + }); + + it('should have been called with inputs', () => { + const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + component.submitStateResource$ = of(commandStateResource); + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); + + fixture.detectChanges(); + const weiterButton: BescheidWizardWeiterButtonComponent = + getElementComponentFromFixtureByCss<BescheidWizardWeiterButtonComponent>(fixture, weiterButtonTestId); + component.submitStateResource$.subscribe(); + + expect(weiterButton.submitStateResource).toEqual(commandStateResource); + }); + + describe('output', () => { + describe('clickEmitter', () => { + it('should call handler', () => { + component.gotoNextStep = jest.fn(); + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: weiterButtonTestId, name: 'clickEmitter' }); + + expect(component.gotoNextStep).toHaveBeenCalled(); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..d09a24bce3dfd8a65dac3470147f42fff00aeda9 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.ts @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { BescheidDocument, BescheidLinkRel, BescheidResource } from '@alfa-client/bescheid-shared'; +import { tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared'; +import { isNotNil, StateResource } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { Resource } from '@ngxp/rest'; +import { isNil } from 'lodash-es'; +import { Observable } from 'rxjs'; +import { BescheidFormService } from '../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-dokumente-hochladen-form', + templateUrl: './bescheid-wizard-dokumente-hochladen-form.component.html', +}) +export class BescheidWizardDokumenteHochladenFormComponent { + @Input() set bescheidDocument(value: BescheidDocument) { + this._bescheidDocument = value; + if (isNotNil(value.resource)) { + this.bescheidDocumentMissing.emit(false); + } + } + + @Input() bescheidResource: BescheidResource; + + @Output() weiterClickEmitter: EventEmitter<void> = new EventEmitter<void>(); + @Output() bescheidDocumentMissing: EventEmitter<boolean> = new EventEmitter<boolean>(); + + private readonly formService = inject(BescheidFormService); + + public submitStateResource$: Observable<StateResource<Resource>>; + + private _bescheidDocument: BescheidDocument; + + protected readonly bescheidLinkRel = BescheidLinkRel; + + public gotoNextStep(): void { + if (isNil(this._bescheidDocument.resource)) { + this.bescheidDocumentMissing.emit(true); + } else { + this.submitStateResource$ = this.formService + .submit() + .pipe(tapOnCommandSuccessfullyDone(() => this.weiterClickEmitter.emit())); + } + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.html similarity index 65% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.html rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.html index 1ce18413c69e7b7399288ffa987dfdeb0b2d4ee5..b8c80fafbcec28185f7ff568c8b5357c197b1503 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.html @@ -23,4 +23,17 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<p>bescheid-wizard-dokumente-hochladen-summary works!</p> + +@if (isBescheidDocumentMissing) { + <p data-test-id="missing-bescheid-document-error-message" class="my-4 text-base text-error"> + Bitte fügen Sie ein Bescheiddokument hinzu. + </p> +} +<div class="my-4"> + <alfa-bescheid-wizard-document-file-container data-test-id="bescheid-document-file"> + </alfa-bescheid-wizard-document-file-container> +</div> +<div class="my-4"> + <alfa-bescheid-wizard-attachment-files-container data-test-id="bescheid-attachment-files"> + </alfa-bescheid-wizard-attachment-files-container> +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ed6c9e5d11f1e5ebbe9fda0b395d70bc856c323 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.spec.ts @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { existsAsHtmlElement, notExistsAsHtmlElement } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { BescheidWizardAttachmentFilesContainerComponent } from '../../attachment-files-container/bescheid-wizard-attachment-files-container.component'; +import { BescheidWizardDocumentFileContainerComponent } from '../../document-file-container/bescheid-wizard-document-file-container.component'; +import { BescheidWizardDokumenteHochladenSummaryComponent } from './bescheid-wizard-dokumente-hochladen-summary.component'; + +describe('BescheidWizardDokumenteHochladenSummaryComponent', () => { + let component: BescheidWizardDokumenteHochladenSummaryComponent; + let fixture: ComponentFixture<BescheidWizardDokumenteHochladenSummaryComponent>; + + const missingBescheidErrorMessageTestId: string = getDataTestIdOf('missing-bescheid-document-error-message'); + const documentFileTestId: string = getDataTestIdOf('bescheid-document-file'); + const attachmentFilesTestId: string = getDataTestIdOf('bescheid-attachment-files'); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardDokumenteHochladenSummaryComponent, + MockComponent(BescheidWizardDocumentFileContainerComponent), + MockComponent(BescheidWizardAttachmentFilesContainerComponent), + ], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardDokumenteHochladenSummaryComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('template', () => { + describe('missing bescheid error message', () => { + it('should exists', () => { + component.isBescheidDocumentMissing = true; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, missingBescheidErrorMessageTestId); + }); + + it('should NOT exists', () => { + component.isBescheidDocumentMissing = false; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, missingBescheidErrorMessageTestId); + }); + }); + + describe('document file', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, documentFileTestId); + }); + }); + + describe('attachment files', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, attachmentFilesTestId); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.ts similarity index 87% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.ts index 9ef966f315ee77c10a08a177d0eddc0ce2d86c61..6bf136b2492c45205aa1fe115c3a033d92c1d174 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.ts @@ -21,10 +21,12 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component } from '@angular/core'; +import { Component, Input } from '@angular/core'; @Component({ selector: 'alfa-bescheid-wizard-dokumente-hochladen-summary', templateUrl: './bescheid-wizard-dokumente-hochladen-summary.component.html', }) -export class BescheidWizardDokumenteHochladenSummaryComponent {} +export class BescheidWizardDokumenteHochladenSummaryComponent { + @Input() isBescheidDocumentMissing: boolean; +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.spec.ts deleted file mode 100644 index 3776924bd38321a3ae2e369805d408f7e0961582..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.spec.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { getElementFromFixtureByType } from '@alfa-client/test-utils'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MockComponent } from 'ng-mocks'; -import { BescheidWizardAntragBescheidenSummaryComponent } from '../antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component'; -import { BescheidWizardStepTitleComponent } from '../step-title/bescheid-wizard-step-title.component'; -import { BescheidWizardStepperComponent } from '../stepper/bescheid-wizard-stepper.component'; -import { BescheidWizardSummaryComponent } from '../summary/bescheid-wizard-summary.component'; -import { BescheidWizardDokumenteHochladenComponent } from './bescheid-wizard-dokumente-hochladen.component'; -import { BescheidWizardDokumenteHochladenFormComponent } from './form/bescheid-wizard-dokumente-hochladen-form.component'; -import { BescheidWizardDokumenteHochladenSummaryComponent } from './summary/bescheid-wizard-dokumente-hochladen-summary.component'; - -describe('BescheidWizardDokumenteHochladenComponent', () => { - let component: BescheidWizardDokumenteHochladenComponent; - let fixture: ComponentFixture<BescheidWizardDokumenteHochladenComponent>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - BescheidWizardDokumenteHochladenComponent, - MockComponent(BescheidWizardSummaryComponent), - MockComponent(BescheidWizardAntragBescheidenSummaryComponent), - MockComponent(BescheidWizardDokumenteHochladenSummaryComponent), - MockComponent(BescheidWizardStepTitleComponent), - MockComponent(BescheidWizardDokumenteHochladenFormComponent), - MockComponent(BescheidWizardStepperComponent), - ], - }).compileComponents(); - - fixture = TestBed.createComponent(BescheidWizardDokumenteHochladenComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('template', () => { - describe('alfa-bescheid-wizard-stepper', () => { - function getElementComponent(): BescheidWizardStepperComponent { - return getElementFromFixtureByType(fixture, BescheidWizardStepperComponent); - } - - describe('input', () => { - it('should set activeStep', () => { - fixture.detectChanges(); - - expect(getElementComponent().activeStep).toBe(BescheidWizardStep.DokumenteHochladen); - }); - }); - }); - - describe('alfa-bescheid-wizard-step-title', () => { - function getElementComponent(): BescheidWizardStepTitleComponent { - return getElementFromFixtureByType(fixture, BescheidWizardStepTitleComponent); - } - - describe('input', () => { - it('should set inactiveStep', () => { - fixture.detectChanges(); - - expect(getElementComponent().inactiveStep).toBeTruthy(); - }); - }); - }); - }); -}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.spec.ts deleted file mode 100644 index bcf7a846b3cca932af5613b3af7baec9a57d43d6..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { BescheidWizardDokumenteHochladenFormComponent } from './bescheid-wizard-dokumente-hochladen-form.component'; - -describe('BescheidWizardDokumenteHochladenFormComponent', () => { - let component: BescheidWizardDokumenteHochladenFormComponent; - let fixture: ComponentFixture<BescheidWizardDokumenteHochladenFormComponent>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BescheidWizardDokumenteHochladenFormComponent], - }).compileComponents(); - - fixture = TestBed.createComponent(BescheidWizardDokumenteHochladenFormComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.ts deleted file mode 100644 index 3f4923a9b4a0b40edc3b6392aae2d52f2b3b4d8d..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { Component } from '@angular/core'; - -@Component({ - selector: 'alfa-bescheid-wizard-dokumente-hochladen-form', - templateUrl: './bescheid-wizard-dokumente-hochladen-form.component.html', -}) -export class BescheidWizardDokumenteHochladenFormComponent {} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.spec.ts deleted file mode 100644 index 0b30871de20941b223787ab12b0e40d233dd8f9f..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { BescheidWizardDokumenteHochladenSummaryComponent } from './bescheid-wizard-dokumente-hochladen-summary.component'; - -describe('BescheidWizardDokumenteHochladenSummaryComponent', () => { - let component: BescheidWizardDokumenteHochladenSummaryComponent; - let fixture: ComponentFixture<BescheidWizardDokumenteHochladenSummaryComponent>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BescheidWizardDokumenteHochladenSummaryComponent], - }).compileComponents(); - - fixture = TestBed.createComponent(BescheidWizardDokumenteHochladenSummaryComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.html similarity index 60% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.html rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.html index d147a2c6bdf7308ae737b78a7814e447702120fa..43b8946ab2d59886a58ed927028c68158785dedc 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.html @@ -1,6 +1,6 @@ <!-- - Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung @@ -23,4 +23,20 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<p>bescheid-wizard-dokumente-hochladen-form works!</p> +<div class="flex h-full gap-11"> + <div class="flex w-1/2 flex-row gap-7"> + <alfa-bescheid-wizard-stepper + [activeStep]="activeStep" + (stepChange)="stepChange.emit($event)" + data-test-id="wizard-stepper" + /> + <div class="mt-2 flex flex-1 flex-col"> + <ng-content select="[stepPanel]" /> + </div> + </div> + <div class="flex w-1/2"> + <alfa-bescheid-wizard-summary headline="Bescheid" data-test-id="wizard-summary"> + <ng-content select="[summary]" /> + </alfa-bescheid-wizard-summary> + </div> +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..9a3c8cc809e97eb6b89cf7b3dc7ed15b6f6d81f9 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.spec.ts @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { MockComponent } from 'ng-mocks'; +import { BescheidWizardStepperComponent } from '../stepper/bescheid-wizard-stepper.component'; +import { BescheidWizardSummaryComponent } from '../summary/bescheid-wizard-summary.component'; +import { StepContentLayoutComponent } from './step-content-layout.component'; + +describe('StepContentLayoutComponent', () => { + let component: StepContentLayoutComponent; + let fixture: ComponentFixture<StepContentLayoutComponent>; + + const wizardStepper: string = getDataTestIdOf('wizard-stepper'); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + StepContentLayoutComponent, + MockComponent(BescheidWizardStepperComponent), + MockComponent(BescheidWizardSummaryComponent), + ], + }).compileComponents(); + + fixture = TestBed.createComponent(StepContentLayoutComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('on stepper step change', () => { + it('should emit', () => { + component.stepChange.emit = jest.fn(); + + triggerEvent({ + fixture, + name: 'stepChange', + elementSelector: wizardStepper, + data: BescheidWizardStep.AntragBescheiden, + }); + + expect(component.stepChange.emit).toHaveBeenCalledWith(BescheidWizardStep.AntragBescheiden); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.ts similarity index 70% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.ts index c145f7b4995e9ac1193ce9dd148dc78a50e682da..8fd8d880d084fdcb16f9f121becfdbd1dc850e41 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.ts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den * Ministerpräsidenten des Landes Schleswig-Holstein * Staatskanzlei * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung @@ -22,12 +22,14 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { Component } from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; @Component({ - selector: 'alfa-bescheid-wizard-dokumente-hochladen', - templateUrl: './bescheid-wizard-dokumente-hochladen.component.html', + selector: 'alfa-step-content-layout', + templateUrl: './step-content-layout.component.html', }) -export class BescheidWizardDokumenteHochladenComponent { - public readonly bescheidWizardStep = BescheidWizardStep; +export class StepContentLayoutComponent { + @Input() public activeStep: BescheidWizardStep; + + @Output() public stepChange: EventEmitter<BescheidWizardStep> = new EventEmitter(); } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.html index b8fa88049ce906de0d08d137018d21d725c3ded3..cda7188f9d38f435d1c3f582ed9980061bb98c08 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.html @@ -23,7 +23,9 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<section class="flex h-full w-full flex-col overflow-auto rounded-xl bg-background-100 px-4 py-5"> - <h3 class="mb-4 text-base font-bold text-primary-600">Bescheid</h3> - <ng-content></ng-content> +<section class="absolute flex size-full flex-col gap-4 overflow-auto rounded-xl bg-background-100 px-4 py-5"> + <h3 class="text-base font-bold text-primary">{{ headline }}</h3> + <div class="flex-1"> + <ng-content /> + </div> </section> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.ts index f6ca78a11b86260c57e235229ec2333e80ff6d85..2a6b34b223a8dd367abc352356c67799274d1323 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.ts @@ -21,10 +21,13 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component } from '@angular/core'; +import { Component, Input } from '@angular/core'; @Component({ selector: 'alfa-bescheid-wizard-summary', templateUrl: './bescheid-wizard-summary.component.html', + styles: [':host {@apply relative w-full}'], }) -export class BescheidWizardSummaryComponent {} +export class BescheidWizardSummaryComponent { + @Input() public headline: string; +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..0442de58d2afd83f13f0adb7f928829302ffcea2 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.html @@ -0,0 +1,5 @@ +<alfa-bescheid-wizard-upload-attachment-button + [attachments]="attachments$ | async" + (uploadFile)="uploadFile($event)" + data-test-id="upload-attachment-button" +></alfa-bescheid-wizard-upload-attachment-button> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..6035095eb818710798ad643934245f0ad1cf503f --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.spec.ts @@ -0,0 +1,101 @@ +import { BescheidAttachments, BescheidResource } from '@alfa-client/bescheid-shared'; +import { getElementComponentFromFixtureByCss, Mock, mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidAttachments, createBescheidResource } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { createFile } from '../../../../../../tech-shared/test/file'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { BescheidWizardUploadAttachmentButtonContainerComponent } from './bescheid-wizard-upload-attachment-button-container.component'; +import { BescheidWizardUploadAttachmentButtonComponent } from './upload-attachment-button/bescheid-wizard-upload-attachment-button.component'; + +describe('BescheidWizardUploadAttachmentButtonContainerComponent', () => { + let component: BescheidWizardUploadAttachmentButtonContainerComponent; + let fixture: ComponentFixture<BescheidWizardUploadAttachmentButtonContainerComponent>; + + const uploadAttachmentButtonTestId: string = getDataTestIdOf('upload-attachment-button'); + + const bescheidAttachments: BescheidAttachments = createBescheidAttachments(); + + let bescheidService: Mock<BescheidService2>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardUploadAttachmentButtonContainerComponent, + MockComponent(BescheidWizardUploadAttachmentButtonComponent), + ], + providers: [{ provide: BescheidService2, useValue: bescheidService }], + }).compileComponents(); + + createComponent(); + }); + + function createComponent() { + fixture = TestBed.createComponent(BescheidWizardUploadAttachmentButtonContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + } + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + bescheidService.getAttachments.mockReturnValue(of(bescheidAttachments)); + + createComponent(); + + expect(component.attachments$).toBeObservable(singleColdCompleted(bescheidAttachments)); + }); + + describe('uploadFile', () => { + it('should call bescheid service', () => { + const bescheidResource: BescheidResource = createBescheidResource(); + const file: File = createFile(); + component.bescheidResource = bescheidResource; + + component.uploadFile(file); + + expect(bescheidService.uploadAttachment).toHaveBeenCalledWith(file, bescheidResource); + }); + }); + }); + + describe('template', () => { + describe('upload attachment button', () => { + it('should have been called with inputs', () => { + bescheidService.getAttachments.mockReturnValue(of(bescheidAttachments)); + createComponent(); + + const uploadAttachmentButtonComponent: BescheidWizardUploadAttachmentButtonComponent = + getElementComponentFromFixtureByCss<BescheidWizardUploadAttachmentButtonComponent>( + fixture, + uploadAttachmentButtonTestId, + ); + + expect(uploadAttachmentButtonComponent.attachments).toEqual(bescheidAttachments); + }); + + describe('output', () => { + describe('uploadFile', () => { + it('should call handler', () => { + component.uploadFile = jest.fn(); + const file: File = createFile(); + + triggerEvent({ fixture, elementSelector: uploadAttachmentButtonTestId, name: 'uploadFile', data: file }); + + expect(component.uploadFile).toHaveBeenCalledWith(file); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..620adb8db26f04e7dc6b810c37c6acdef0c12d4e --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.ts @@ -0,0 +1,20 @@ +import { BescheidAttachments, BescheidResource } from '@alfa-client/bescheid-shared'; +import { Component, inject, Input } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; + +@Component({ + selector: 'alfa-bescheid-wizard-upload-attachment-button-container', + templateUrl: './bescheid-wizard-upload-attachment-button-container.component.html', +}) +export class BescheidWizardUploadAttachmentButtonContainerComponent { + @Input() bescheidResource: BescheidResource; + + private readonly bescheidService = inject(BescheidService2); + + public readonly attachments$: Observable<BescheidAttachments> = this.bescheidService.getAttachments(); + + public uploadFile(file: File): void { + this.bescheidService.uploadAttachment(file, this.bescheidResource); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.html new file mode 100644 index 0000000000000000000000000000000000000000..daa2be54c067aee56f12918fc97895d4a9cfd87f --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.html @@ -0,0 +1,11 @@ +<div [formGroup]="formService.form"> + <ods-file-upload-editor + [parentFormArrayName]="formServiceClass.FIELD_ATTACHMENTS" + [uploadInProgress]="upload" + [fileLinkList]="fileUrls" + (newFile)="uploadFile.emit($event)" + label="Anhang hochladen" + data-test-id="bescheid-wizard-upload-editor" + > + </ods-file-upload-editor> +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..7aff85b5a346f756fae78c33398f875236e24390 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.spec.ts @@ -0,0 +1,84 @@ +import { BescheidAttachments } from '@alfa-client/bescheid-shared'; +import { createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared'; +import { getElementComponentFromFixtureByCss, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; +import { faker } from '@faker-js/faker'; +import { FileUploadEditorComponent } from '@ods/component'; +import { MockComponent } from 'ng-mocks'; +import { createBescheidAttachments } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { createBinaryFileResource } from '../../../../../../../binary-file-shared/test/binary-file'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { createFile } from '../../../../../../../tech-shared/test/file'; +import { BescheidFormService } from '../../../bescheid.formservice'; +import { BescheidWizardUploadAttachmentButtonComponent } from './bescheid-wizard-upload-attachment-button.component'; + +describe('BescheidWizardUploadAttachmentButtonComponent', () => { + let component: BescheidWizardUploadAttachmentButtonComponent; + let fixture: ComponentFixture<BescheidWizardUploadAttachmentButtonComponent>; + + const uploadEditorTestId: string = getDataTestIdOf('bescheid-wizard-upload-editor'); + + const bescheidAttachments: BescheidAttachments = createBescheidAttachments(); + + let formService: BescheidFormService; + + beforeEach(() => { + formService = new BescheidFormService(new FormBuilder(), null); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BescheidWizardUploadAttachmentButtonComponent, MockComponent(FileUploadEditorComponent)], + providers: [{ provide: BescheidFormService, useValue: formService }], + imports: [ReactiveFormsModule], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardUploadAttachmentButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.upload).toEqual(createEmptyStateResource()); + expect(component.fileUrls).toEqual([]); + }); + }); + + describe('template', () => { + describe('upload editor', () => { + it('should have been called with inputs', () => { + component.upload = createStateResource(createBinaryFileResource()); + component.fileUrls = [faker.internet.url()]; + + fixture.detectChanges(); + const uploadEditorComponent: FileUploadEditorComponent = getElementComponentFromFixtureByCss<FileUploadEditorComponent>( + fixture, + uploadEditorTestId, + ); + + expect(uploadEditorComponent.parentFormArrayName).toEqual(BescheidFormService.FIELD_ATTACHMENTS); + expect(uploadEditorComponent.uploadInProgress).toEqual(component.upload); + expect(uploadEditorComponent.fileLinkList).toEqual(component.fileUrls); + }); + + describe('output', () => { + describe('newFile', () => { + it('should emit', () => { + component.uploadFile.emit = jest.fn(); + const file: File = createFile(); + + triggerEvent({ fixture, elementSelector: uploadEditorTestId, name: 'newFile', data: file }); + + expect(component.uploadFile.emit).toHaveBeenCalledWith(file); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..0ec17648a4f94e19a0b6184e4a2cbb68f1b6edcd --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.ts @@ -0,0 +1,32 @@ +import { BescheidAttachments, createEmptyBescheidAttachments } from '@alfa-client/bescheid-shared'; +import { BinaryFileResource } from '@alfa-client/binary-file-shared'; +import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { getUrl } from '@ngxp/rest'; +import { BescheidFormService } from '../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-upload-attachment-button', + templateUrl: './bescheid-wizard-upload-attachment-button.component.html', +}) +export class BescheidWizardUploadAttachmentButtonComponent { + @Input() set attachments(value: BescheidAttachments) { + this.updateAttachments(value); + } + + @Output() uploadFile: EventEmitter<File> = new EventEmitter<File>(); + + public readonly formService: BescheidFormService = inject(BescheidFormService); + + public fileUrls: string[] = []; + public upload: StateResource<BinaryFileResource> = createEmptyStateResource(); + private _attachments: BescheidAttachments = createEmptyBescheidAttachments(); + + public readonly formServiceClass = BescheidFormService; + + updateAttachments(value: BescheidAttachments) { + this._attachments = value; + this.upload = value.uploadStateResource; + this.fileUrls = this._attachments.items.map((binaryFileResource: BinaryFileResource) => getUrl(binaryFileResource)); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..99efc09710ff3289b34e59461294c0a3e39596a7 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.html @@ -0,0 +1,6 @@ +<alfa-bescheid-wizard-upload-document-button + [bescheidResource]="bescheidResource" + [bescheidDocument]="bescheidDocument$ | async" + (file)="uploadBescheidDocumentFile($event)" + data-test-id="bescheid-wizard-upload-document-button" +></alfa-bescheid-wizard-upload-document-button> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..aad7d40ccedf3a798acadb6be1b76e9560b43912 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.spec.ts @@ -0,0 +1,102 @@ +import { BescheidDocument, BescheidResource } from '@alfa-client/bescheid-shared'; +import { getElementComponentFromFixtureByCss, mock, Mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidDocument, createBescheidResource } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { createFile } from '../../../../../../tech-shared/test/file'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { BescheidWizardUploadDocumentButtonContainerComponent } from './bescheid-wizard-upload-document-button-container.component'; +import { BescheidWizardUploadDocumentButtonComponent } from './upload-document-button/bescheid-wizard-upload-document-button.component'; + +describe('BescheidWizardDokumentHochladenContainerButtonComponent', () => { + let component: BescheidWizardUploadDocumentButtonContainerComponent; + let fixture: ComponentFixture<BescheidWizardUploadDocumentButtonContainerComponent>; + + const uploadDocumentButtonTestId: string = getDataTestIdOf('bescheid-wizard-upload-document-button'); + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + let bescheidService: Mock<BescheidService2>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardUploadDocumentButtonContainerComponent, + MockComponent(BescheidWizardUploadDocumentButtonComponent), + ], + providers: [{ provide: BescheidService2, useValue: bescheidService }], + }).compileComponents(); + + createComponent(); + }); + + function createComponent() { + fixture = TestBed.createComponent(BescheidWizardUploadDocumentButtonContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + } + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + + createComponent(); + + expect(component.bescheidDocument$).toBeObservable(singleColdCompleted(bescheidDocument)); + }); + + describe('uploadBescheidDocumentFile', () => { + it('should call bescheid service', () => { + const file: File = createFile(); + const bescheidResource: BescheidResource = createBescheidResource(); + component.bescheidResource = bescheidResource; + + component.uploadBescheidDocumentFile(file); + + expect(bescheidService.uploadBescheidDocument).toHaveBeenCalledWith(file, bescheidResource); + }); + }); + }); + + describe('template', () => { + describe('upload document button', () => { + it('should have been called with inputs', () => { + const bescheidResource: BescheidResource = createBescheidResource(); + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + createComponent(); + component.bescheidResource = bescheidResource; + + fixture.detectChanges(); + const uploadDocumentButtonComponent: BescheidWizardUploadDocumentButtonComponent = + getElementComponentFromFixtureByCss<BescheidWizardUploadDocumentButtonComponent>(fixture, uploadDocumentButtonTestId); + + expect(uploadDocumentButtonComponent.bescheidResource).toEqual(bescheidResource); + expect(uploadDocumentButtonComponent.bescheidDocument).toEqual(bescheidDocument); + }); + + describe('output', () => { + describe('file', () => { + it('should call handler', () => { + component.uploadBescheidDocumentFile = jest.fn(); + const file: File = createFile(); + + triggerEvent({ fixture, elementSelector: uploadDocumentButtonTestId, name: 'file', data: file }); + + expect(component.uploadBescheidDocumentFile).toHaveBeenCalledWith(file); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..a874617f496f42ccb8492a8fd116ae29d2384d36 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.ts @@ -0,0 +1,20 @@ +import { BescheidDocument, BescheidResource } from '@alfa-client/bescheid-shared'; +import { Component, inject, Input } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; + +@Component({ + selector: 'alfa-bescheid-wizard-upload-document-button-container', + templateUrl: './bescheid-wizard-upload-document-button-container.component.html', +}) +export class BescheidWizardUploadDocumentButtonContainerComponent { + @Input() bescheidResource: BescheidResource; + + private readonly bescheidService = inject(BescheidService2); + + public readonly bescheidDocument$: Observable<BescheidDocument> = this.bescheidService.getBescheidDocument(); + + public uploadBescheidDocumentFile(file: File): void { + this.bescheidService.uploadBescheidDocument(file, this.bescheidResource); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.html new file mode 100644 index 0000000000000000000000000000000000000000..0b04ceb6fc50d6d98b70f95f7f252c6a62a11252 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.html @@ -0,0 +1,14 @@ +<div [formGroup]="formService.form" class="w-full"> + <ods-single-file-upload-editor + *ngIf="bescheidResource | hasLink: bescheidLinkRel.UPLOAD_BESCHEID_FILE" + [uploadInProgress]="upload.loading" + [formControlName]="formServiceClass.FIELD_BESCHEID_DOCUMENT" + (newFile)="uploadFile($event)" + class="w-72" + data-test-id="bescheid-wizard-upload-document-upload-editor" + > + <ods-bescheid-upload-icon icon></ods-bescheid-upload-icon> + <ods-spinner-icon spinner size="extra-large"></ods-spinner-icon> + <div text class="text-center">Bescheiddokument hochladen</div> + </ods-single-file-upload-editor> +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..d6616d37317a467e6a8c1976cfb1f2f5fc937ffc --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.spec.ts @@ -0,0 +1,148 @@ +import { BescheidDocument, BescheidLinkRel, createEmptyUploadInProgress } from '@alfa-client/bescheid-shared'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + mock, + notExistsAsHtmlElement, + triggerEvent, + useFromMock, +} from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; +import { SingleFileUploadEditorComponent } from '@ods/component'; +import { BescheidUploadIconComponent, SpinnerIconComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { BescheidService2 } from '../../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { + createBescheidDocument, + createBescheidResource, + createPendingUpload, +} from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { createFile } from '../../../../../../../tech-shared/test/file'; +import { BescheidFormService } from '../../../bescheid.formservice'; +import { BescheidWizardUploadDocumentButtonComponent } from './bescheid-wizard-upload-document-button.component'; + +describe('BescheidWizardDokumentHochladenButtonComponent', () => { + let component: BescheidWizardUploadDocumentButtonComponent; + let fixture: ComponentFixture<BescheidWizardUploadDocumentButtonComponent>; + + const fileUploadEditorTestId: string = getDataTestIdOf('bescheid-wizard-upload-document-upload-editor'); + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + let formService: BescheidFormService; + + beforeEach(() => { + formService = new BescheidFormService(new UntypedFormBuilder(), useFromMock(mock(BescheidService2))); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardUploadDocumentButtonComponent, + MockComponent(SingleFileUploadEditorComponent), + MockComponent(BescheidUploadIconComponent), + MockComponent(SpinnerIconComponent), + HasLinkPipe, + ], + providers: [ + { + provide: BescheidFormService, + useValue: formService, + }, + ], + imports: [ReactiveFormsModule], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardUploadDocumentButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.upload).toEqual(createEmptyUploadInProgress()); + }); + + describe('set bescheid document', () => { + it('should call form service', () => { + formService.updateBescheidDocumentFile = jest.fn(); + + component.bescheidDocument = bescheidDocument; + + expect(formService.updateBescheidDocumentFile).toHaveBeenCalledWith(bescheidDocument.documentUri); + }); + + it('should set upload', () => { + formService.updateBescheidDocumentFile = jest.fn(); + + component.bescheidDocument = bescheidDocument; + + expect(component.upload).toEqual(bescheidDocument.upload); + }); + }); + + describe('uploadFile', () => { + it('should emit', () => { + component.file.emit = jest.fn(); + const file: File = createFile(); + + component.uploadFile(file); + + expect(component.file.emit).toHaveBeenCalledWith(file); + }); + }); + }); + + describe('template', () => { + describe('file upload editor', () => { + it('should exists', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPLOAD_BESCHEID_FILE]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, fileUploadEditorTestId); + }); + + it('should NOT exists', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, fileUploadEditorTestId); + }); + + it('should have been called with inputs', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPLOAD_BESCHEID_FILE]); + component.upload = createPendingUpload(); + + fixture.detectChanges(); + const fileUploadEditorComponent: SingleFileUploadEditorComponent = + getElementComponentFromFixtureByCss<SingleFileUploadEditorComponent>(fixture, fileUploadEditorTestId); + + expect(fileUploadEditorComponent.uploadInProgress).toEqual(component.upload.loading); + }); + + describe('output', () => { + describe('newFile', () => { + it('should call handler', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPLOAD_BESCHEID_FILE]); + const file: File = createFile(); + component.uploadFile = jest.fn(); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: fileUploadEditorTestId, name: 'newFile', data: file }); + + expect(component.uploadFile).toHaveBeenCalledWith(file); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..d48f7dbde8774df3bf2599415e84da79a123d49d --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.ts @@ -0,0 +1,36 @@ +import { + BescheidDocument, + BescheidLinkRel, + BescheidResource, + createEmptyUploadInProgress, + UploadFileInProgress, +} from '@alfa-client/bescheid-shared'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { BescheidFormService } from '../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-upload-document-button', + templateUrl: './bescheid-wizard-upload-document-button.component.html', + styles: [':host {@apply flex grow}'], +}) +export class BescheidWizardUploadDocumentButtonComponent { + @Input() bescheidResource: BescheidResource; + + @Input() set bescheidDocument(value: BescheidDocument) { + this.formService.updateBescheidDocumentFile(value.documentUri); + this.upload = value.upload; + } + + @Output() file: EventEmitter<File> = new EventEmitter<File>(); + + public readonly formService = inject(BescheidFormService); + + public upload: UploadFileInProgress = createEmptyUploadInProgress(); + + public readonly formServiceClass = BescheidFormService; + public readonly bescheidLinkRel = BescheidLinkRel; + + public uploadFile(file: File): void { + this.file.emit(file); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.html index e02e0583599c0f9efd985994734571c1e19de055..491749c3c65e2134761b1588f930f5a29bde5561 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.html @@ -28,8 +28,8 @@ (clickEmitter)="clickEmitter.emit()" variant="primary" size="medium" - class="mt-8 flex" - data-test-id="bescheid-weiter-button" + class="mt-4 flex" text="Weiter" + dataTestId="bescheid-weiter-button" > </ods-button-with-spinner> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.spec.ts index 5f970240cbfc56e5c7bb123b1c93060e1360b195..d5f5cded5a3a08e16a482c4674febf9a5c66fd21 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.spec.ts @@ -29,14 +29,14 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ButtonWithSpinnerComponent } from '@ods/component'; import { MockComponent } from 'ng-mocks'; import { createCommandResource } from '../../../../../../command-shared/test/command'; -import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { getDataTestIdAttributeOf } from '../../../../../../tech-shared/test/data-test'; import { BescheidWizardWeiterButtonComponent } from './bescheid-wizard-weiter-button.component'; describe('BescheidWizardWeiterButtonComponent', () => { let component: BescheidWizardWeiterButtonComponent; let fixture: ComponentFixture<BescheidWizardWeiterButtonComponent>; - const button: string = getDataTestIdOf('bescheid-weiter-button'); + const button: string = getDataTestIdAttributeOf('bescheid-weiter-button'); let clickEmitter: Mock<EventEmitter<MouseEvent>>; diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.spec.ts index 68c46faa40d9354dfcb976a2726e533f76b96cb3..2125d0b8e171796f264901d4b22e40c269d0cc7d 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.spec.ts @@ -21,18 +21,23 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Bescheid, BescheidLinkRel, BescheidResource, BescheidSendBy, BescheidService } from '@alfa-client/bescheid-shared'; -import { formatForDatabase } from '@alfa-client/tech-shared'; +import { Bescheid, BescheidLinkRel, BescheidResource, BescheidSendBy, BescheidWizardStep, Wizard, } from '@alfa-client/bescheid-shared'; +import { CommandResource } from '@alfa-client/command-shared'; +import { createErrorStateResource, createLoadingStateResource, formatForDatabase, StateResource } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { registerLocaleData } from '@angular/common'; import localeDe from '@angular/common/locales/de'; import { UntypedFormBuilder } from '@angular/forms'; import { faker } from '@faker-js/faker'; +import { expect } from '@jest/globals'; import { ResourceUri } from '@ngxp/rest'; import { EMPTY, Observable, of } from 'rxjs'; -import { createBescheid, createBescheidResource } from '../../../../bescheid-shared/src/test/bescheid'; -import { singleCold } from '../../../../tech-shared/test/marbles'; +import { BescheidService2 } from '../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheid, createBescheidResource, createWizard } from '../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../command-shared/test/command'; +import { createProblemDetail } from '../../../../tech-shared/test/error'; +import { singleCold, singleColdCompleted } from '../../../../tech-shared/test/marbles'; import { createVorgangWithEingangResource } from '../../../../vorgang-shared/test/vorgang'; import { BescheidFormService } from './bescheid.formservice'; @@ -40,27 +45,373 @@ registerLocaleData(localeDe); describe('BescheidFormService', () => { let service: BescheidFormService; - let bescheidService: Mock<BescheidService>; + let bescheidService: Mock<BescheidService2>; const now: Date = new Date(); Date.now = jest.fn().mockReturnValue(now); const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource(); beforeEach(() => { - bescheidService = mock(BescheidService); - bescheidService.createBescheid.mockReturnValue(of(EMPTY)); + bescheidService = mock(BescheidService2); service = new BescheidFormService(new UntypedFormBuilder(), useFromMock(bescheidService)); service.setVorgangWithEingangResource(vorgangWithEingangResource); }); describe('doSubmit', () => { + const wizard: Wizard = createWizard(); + + beforeEach(() => { + service._submitBescheid = jest.fn().mockReturnValue(EMPTY); + bescheidService.getWizard.mockReturnValue(of(wizard)); + }); + + it('should get wizard', () => { + service.submit().subscribe(); + + expect(bescheidService.getWizard).toHaveBeenCalled(); + }); + + it('should submit bescheid', () => { + service.submit().subscribe(); + + expect(service._submitBescheid).toHaveBeenCalledWith(wizard); + }); + + it('should return command', () => { + const command: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + service._submitBescheid = jest.fn().mockReturnValue(of(command)); + + const submit$: Observable<StateResource<CommandResource>> = service.submit(); + + expect(submit$).toBeObservable(singleColdCompleted(command)); + }); + }); + + describe('_submitBescheid', () => { + const command: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + + beforeEach(() => { + service._updateAndSendBescheid = jest.fn().mockReturnValue(EMPTY); + service._createBescheid = jest.fn().mockReturnValue(EMPTY); + service._updateBescheid = jest.fn().mockReturnValue(EMPTY); + service.isPatch = jest.fn(); + }); + + describe('create', () => { + beforeEach(() => { + service.isPatch = jest.fn().mockReturnValue(false); + }); + + it('should create', () => { + service._submitBescheid(createWizard()).subscribe(); + + expect(service._createBescheid).toHaveBeenCalled(); + }); + + it('should return command', () => { + service._createBescheid = jest.fn().mockReturnValue(of(command)); + + const submit$: Observable<StateResource<CommandResource>> = service._submitBescheid(createWizard()); + + expect(submit$).toBeObservable(singleColdCompleted(command)); + }); + }); + + describe('update', () => { + beforeEach(() => { + service._canSendBescheid = jest.fn().mockReturnValue(false); + }); + + it('should update on change bescheid', () => { + service.isPatch = jest.fn().mockReturnValue(true); + + service._submitBescheid(createWizard()).subscribe(); + + expect(service._updateBescheid).toHaveBeenCalled(); + }); + + it('should update on existing bescheid', () => { + service.isPatch = jest.fn().mockReturnValue(false); + service.patchValues(createBescheidResource()); + + service._submitBescheid(createWizard()).subscribe(); + + expect(service._updateBescheid).toHaveBeenCalled(); + }); + + it('should return command', () => { + service.isPatch = jest.fn().mockReturnValue(true); + service._updateBescheid = jest.fn().mockReturnValue(of(command)); + + const submit$: Observable<StateResource<CommandResource>> = service._submitBescheid(createWizard()); + + expect(submit$).toBeObservable(singleColdCompleted(command)); + }); + }); + + describe('update and send', () => { + const wizard: Wizard = createWizard(); + + beforeEach(() => { + service.isPatch = jest.fn().mockReturnValue(true); + }); + + it('should update and send', () => { + service._canSendBescheid = jest.fn().mockReturnValue(true); + + service._submitBescheid(wizard).subscribe(); + + expect(service._updateAndSendBescheid).toHaveBeenCalledWith(wizard.sendBy); + }); + + it('should NOT update and send', () => { + service._canSendBescheid = jest.fn().mockReturnValue(false); + + service._submitBescheid(wizard).subscribe(); + + expect(service._updateAndSendBescheid).not.toHaveBeenCalled(); + }); + + it('should return command', () => { + service._updateAndSendBescheid = jest.fn().mockReturnValue(of(command)); + + const submit$: Observable<StateResource<CommandResource>> = service._submitBescheid(wizard); + + expect(submit$).toBeObservable(singleColdCompleted(command)); + }); + }); + }); + + describe('_canSendBescheid', () => { + it('should return true', () => { + const canSendBescheid: boolean = service._canSendBescheid({ + ...createWizard(), + activeStep: BescheidWizardStep.BescheidVersenden, + canBeSend: true, + }); + + expect(canSendBescheid).toBeTruthy(); + }); + + it.each([BescheidWizardStep.AntragBescheiden, BescheidWizardStep.DokumenteHochladen])( + 'should return false on step %s', + (step: BescheidWizardStep) => { + const canSendBescheid: boolean = service._canSendBescheid({ + ...createWizard(), + activeStep: step, + canBeSend: true, + }); + + expect(canSendBescheid).toBeFalsy(); + }, + ); + + it('should return false if bescheid sending locked', () => { + const canSendBescheid: boolean = service._canSendBescheid({ + ...createWizard(), + activeStep: BescheidWizardStep.BescheidVersenden, + canBeSend: false, + }); + + expect(canSendBescheid).toBeFalsy(); + }); + }); + + describe('_createBescheid', () => { + beforeEach(() => { + bescheidService.createBescheid.mockReturnValue(of(EMPTY)); + }); + it('should create bescheid', () => { const formValue: Bescheid = createBescheid(); service.getBescheidFormValue = jest.fn().mockReturnValue(formValue); - service.submit(); + service._createBescheid(); expect(bescheidService.createBescheid).toHaveBeenCalledWith(vorgangWithEingangResource, formValue); }); + + it('should return create command', () => { + const formValue: Bescheid = createBescheid(); + service.getBescheidFormValue = jest.fn().mockReturnValue(formValue); + const createCommand: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + bescheidService.createBescheid.mockReturnValue(of(createCommand)); + + const command$: Observable<StateResource<CommandResource>> = service._createBescheid(); + + expect(command$).toBeObservable(singleColdCompleted(createCommand)); + }); + }); + + describe('_updateBescheid', () => { + beforeEach(() => { + bescheidService.updateBescheid.mockReturnValue(of(EMPTY)); + }); + + it('should update bescheid', () => { + const formValue: Bescheid = createBescheid(); + service.getBescheidFormValue = jest.fn().mockReturnValue(formValue); + const bescheidResource: BescheidResource = createBescheidResource(); + service.patchValues(bescheidResource); + + service._updateBescheid(); + + expect(bescheidService.updateBescheid).toHaveBeenCalledWith(bescheidResource, formValue); + }); + + it('should return create command', () => { + const formValue: Bescheid = createBescheid(); + service.getBescheidFormValue = jest.fn().mockReturnValue(formValue); + const bescheidResource: BescheidResource = createBescheidResource(); + service.patchValues(bescheidResource); + const createCommand: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + bescheidService.updateBescheid.mockReturnValue(of(createCommand)); + + const command$: Observable<StateResource<CommandResource>> = service._updateBescheid(); + + expect(command$).toBeObservable(singleColdCompleted(createCommand)); + }); + }); + + describe('_updateAndSendBescheid', () => { + beforeEach(() => { + service._updateBescheid = jest.fn().mockReturnValue(EMPTY); + }); + + describe('send manually', () => { + it('should update bescheid', () => { + service._updateAndSendBescheid(BescheidSendBy.MANUAL).subscribe(); + + expect(service._updateBescheid).toHaveBeenCalled(); + }); + + it('should send bescheid manually', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + service._updateAndSendBescheid(BescheidSendBy.MANUAL).subscribe(); + + expect(bescheidService.sendBescheidManually).toHaveBeenCalled(); + }); + + it('should not send on pending update', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createLoadingStateResource())); + + service._updateAndSendBescheid(BescheidSendBy.MANUAL).subscribe(); + + expect(bescheidService.sendBescheidManually).not.toHaveBeenCalled(); + }); + + it('should not send on failed update', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createErrorStateResource(createProblemDetail()))); + + service._updateAndSendBescheid(BescheidSendBy.MANUAL).subscribe(); + + expect(bescheidService.sendBescheidManually).not.toHaveBeenCalled(); + }); + + it('should return update command on pending update', () => { + const command: StateResource<CommandResource> = createLoadingStateResource(); + service._updateBescheid = jest.fn().mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = service._updateAndSendBescheid(BescheidSendBy.MANUAL); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + + it('should return update command on failed update', () => { + const command: StateResource<CommandResource> = createErrorStateResource(createProblemDetail()); + service._updateBescheid = jest.fn().mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = service._updateAndSendBescheid(BescheidSendBy.MANUAL); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + + it('should return send bescheid command on successful update', () => { + const command: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + service._updateBescheid = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + bescheidService.sendBescheidManually.mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = service._updateAndSendBescheid(BescheidSendBy.MANUAL); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + + it('should not send message', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + service._updateAndSendBescheid(BescheidSendBy.MANUAL).subscribe(); + + expect(bescheidService.sendBescheidMessage).not.toHaveBeenCalled(); + }); + }); + + describe('send by nachricht', () => { + it('should update bescheid', () => { + service._updateAndSendBescheid(BescheidSendBy.NACHRICHT); + + expect(service._updateBescheid).toHaveBeenCalled(); + }); + + it('should send bescheid message', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + service._updateAndSendBescheid(BescheidSendBy.NACHRICHT).subscribe(); + + expect(bescheidService.sendBescheidMessage).toHaveBeenCalled(); + }); + + it('should not send on pending update', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createLoadingStateResource())); + + service._updateAndSendBescheid(BescheidSendBy.NACHRICHT).subscribe(); + + expect(bescheidService.sendBescheidMessage).not.toHaveBeenCalled(); + }); + + it('should not send on failed update', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createErrorStateResource(createProblemDetail()))); + + service._updateAndSendBescheid(BescheidSendBy.NACHRICHT).subscribe(); + + expect(bescheidService.sendBescheidMessage).not.toHaveBeenCalled(); + }); + + it('should return update command on pending update', () => { + const command: StateResource<CommandResource> = createLoadingStateResource(); + service._updateBescheid = jest.fn().mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = service._updateAndSendBescheid(BescheidSendBy.NACHRICHT); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + + it('should return update command on failed update', () => { + const command: StateResource<CommandResource> = createErrorStateResource(createProblemDetail()); + service._updateBescheid = jest.fn().mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = service._updateAndSendBescheid(BescheidSendBy.NACHRICHT); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + + it('should return send bescheid command on successful update', () => { + const command: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + service._updateBescheid = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + bescheidService.sendBescheidMessage.mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = service._updateAndSendBescheid(BescheidSendBy.NACHRICHT); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + + it('should not send manually', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + service._updateAndSendBescheid(BescheidSendBy.NACHRICHT).subscribe(); + + expect(bescheidService.sendBescheidManually).not.toHaveBeenCalled(); + }); + }); }); describe('patchValues', () => { @@ -162,4 +513,30 @@ describe('BescheidFormService', () => { } as Bescheid); }); }); + + describe('clearBescheidDocumentFile', () => { + it('should update bescheid document file', () => { + service.updateBescheidDocumentFile = jest.fn(); + + service.clearBescheidDocumentFile(); + + expect(service.updateBescheidDocumentFile).toHaveBeenCalledWith(null); + }); + }); + + describe('updateBescheidDocumentFile', () => { + it('should patch form control value to null', () => { + service.updateBescheidDocumentFile(); + + expect(service.getBescheidFormValue().bescheidDocument).toBeNull(); + }); + + it('should patch form control value', () => { + const bescheidResource: BescheidResource = createBescheidResource(); + + service.updateBescheidDocumentFile(bescheidResource.bescheidDocument); + + expect(service.getBescheidFormValue().bescheidDocument).toEqual(bescheidResource.bescheidDocument); + }); + }); }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.ts index 4f9036dadf2779eff368da4ceeef7709f53df4e7..4e650ff9f6660e2e987ee53979858474096cafe2 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.ts @@ -21,15 +21,23 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Bescheid, BescheidLinkRel, BescheidResource, BescheidSendBy, BescheidService } from '@alfa-client/bescheid-shared'; -import { CommandResource } from '@alfa-client/command-shared'; -import { AbstractFormService, StateResource, convertToBoolean, formatForDatabase } from '@alfa-client/tech-shared'; +import { + Bescheid, + BescheidLinkRel, + BescheidResource, + BescheidSendBy, + BescheidWizardStep, + Wizard, +} from '@alfa-client/bescheid-shared'; +import { CommandResource, switchMapCommandSuccessfullyDone } from '@alfa-client/command-shared'; +import { AbstractFormService, convertToBoolean, formatForDatabase, isNotNil, StateResource } from '@alfa-client/tech-shared'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { Injectable } from '@angular/core'; -import { UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; -import { ResourceUri, getUrl, hasLink } from '@ngxp/rest'; -import { isUndefined } from 'lodash-es'; -import { Observable, startWith } from 'rxjs'; +import { FormControl, UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { getUrl, hasLink, ResourceUri } from '@ngxp/rest'; +import { isNil, isUndefined } from 'lodash-es'; +import { first, Observable, startWith, switchMap } from 'rxjs'; +import { BescheidService2 } from '../../../../bescheid-shared/src/lib/bescheid2.service'; @Injectable() export class BescheidFormService extends AbstractFormService<CommandResource> { @@ -44,10 +52,11 @@ export class BescheidFormService extends AbstractFormService<CommandResource> { static readonly FIELD_PATH_PREFIX = 'command.body'; private vorgangWithEingangResource: VorgangWithEingangResource; + private bescheidResource: BescheidResource; constructor( formBuilder: UntypedFormBuilder, - private readonly bescheidService: BescheidService, + private readonly bescheidService: BescheidService2, ) { super(formBuilder); } @@ -65,25 +74,61 @@ export class BescheidFormService extends AbstractFormService<CommandResource> { } protected doSubmit(): Observable<StateResource<CommandResource>> { + return this.bescheidService.getWizard().pipe( + first(), + switchMap((wizard: Wizard) => this._submitBescheid(wizard)), + ); + } + + _submitBescheid(wizard: Wizard): Observable<StateResource<CommandResource>> { + if (this.isPatch() || isNotNil(this.bescheidResource)) { + if (this._canSendBescheid(wizard)) { + return this._updateAndSendBescheid(wizard.sendBy); + } + return this._updateBescheid(); + } + return this._createBescheid(); + } + + _canSendBescheid(wizard: Wizard): boolean { + return wizard.activeStep === BescheidWizardStep.BescheidVersenden && wizard.canBeSend; + } + + _createBescheid(): Observable<StateResource<CommandResource>> { return this.bescheidService.createBescheid(this.vorgangWithEingangResource, this.getBescheidFormValue()); } + _updateBescheid(): Observable<StateResource<CommandResource>> { + return this.bescheidService.updateBescheid(this.bescheidResource, this.getBescheidFormValue()); + } + + _updateAndSendBescheid(sendBy: BescheidSendBy): Observable<StateResource<CommandResource>> { + if (sendBy === BescheidSendBy.MANUAL) { + return this._updateBescheid().pipe(switchMapCommandSuccessfullyDone(() => this.bescheidService.sendBescheidManually())); + } + if (sendBy === BescheidSendBy.NACHRICHT) { + return this._updateBescheid().pipe(switchMapCommandSuccessfullyDone(() => this.bescheidService.sendBescheidMessage())); + } + } + protected getPathPrefix(): string { return BescheidFormService.FIELD_PATH_PREFIX; } - public patchValues(bescheid: BescheidResource): void { - const bescheidDocumentUri: ResourceUri = this.getBescheidDocumentUri(bescheid); - this.bescheidService.setDocumentUri(bescheidDocumentUri); + public patchValues(bescheidResource: BescheidResource): void { + this.bescheidResource = bescheidResource; + const bescheidDocumentUri: ResourceUri = this.getBescheidDocumentUri(bescheidResource); this.patch({ - [BescheidFormService.FIELD_BESCHIEDEN_AM]: bescheid.beschiedenAm, - [BescheidFormService.FIELD_BEWILLIGT]: String(bescheid.bewilligt), + [BescheidFormService.FIELD_BESCHIEDEN_AM]: bescheidResource.beschiedenAm, + [BescheidFormService.FIELD_BEWILLIGT]: String(bescheidResource.bewilligt), [BescheidFormService.FIELD_BESCHEID_DOCUMENT]: bescheidDocumentUri, - [BescheidFormService.FIELD_SEND_BY]: isUndefined(bescheid.sendBy) ? BescheidSendBy.NACHRICHT : bescheid.sendBy, - [BescheidFormService.FIELD_NACHRICHT_SUBJECT]: bescheid.nachrichtSubject, - [BescheidFormService.FIELD_NACHRICHT_TEXT]: bescheid.nachrichtText, + [BescheidFormService.FIELD_SEND_BY]: + isUndefined(bescheidResource.sendBy) ? BescheidSendBy.NACHRICHT : bescheidResource.sendBy, + [BescheidFormService.FIELD_NACHRICHT_SUBJECT]: bescheidResource.nachrichtSubject, + [BescheidFormService.FIELD_NACHRICHT_TEXT]: bescheidResource.nachrichtText, }); - bescheid.attachments.forEach((attachmentLink) => + (this.form.controls[BescheidFormService.FIELD_ATTACHMENTS] as UntypedFormArray).clear(); + bescheidResource.attachments.forEach((attachmentLink) => (this.form.controls[BescheidFormService.FIELD_ATTACHMENTS] as UntypedFormArray).push( new UntypedFormControl(attachmentLink), ), @@ -114,4 +159,28 @@ export class BescheidFormService extends AbstractFormService<CommandResource> { public setVorgangWithEingangResource(vorgangWithEingangResource: VorgangWithEingangResource): void { this.vorgangWithEingangResource = vorgangWithEingangResource; } + + public clearBescheidDocumentFile(): void { + this.updateBescheidDocumentFile(null); + } + + public updateBescheidDocumentFile(uri?: ResourceUri): void { + if (isNil(uri)) { + this.getBescheidDocumentControl().patchValue(null); + } else { + this.getBescheidDocumentControl().patchValue(uri); + } + } + + private getBescheidDocumentControl(): FormControl { + return <FormControl>this.form.controls[BescheidFormService.FIELD_BESCHEID_DOCUMENT]; + } + + public isBetreffInvalid(): boolean { + return this.form.controls[BescheidFormService.FIELD_NACHRICHT_SUBJECT].invalid; + } + + public isNachrichtInvalid(): boolean { + return this.form.controls[BescheidFormService.FIELD_NACHRICHT_TEXT].invalid; + } } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid.module.ts b/alfa-client/libs/bescheid/src/lib/bescheid.module.ts index 1771b5fc23ff9ce35d049fe26904470bd8e6ffd4..b8f0eb5dafcd5b84ec2d13457ae195d2f4589ef9 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid.module.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid.module.ts @@ -24,10 +24,22 @@ import { BescheidSharedModule } from '@alfa-client/bescheid-shared'; import { BinaryFileModule } from '@alfa-client/binary-file'; import { CommandSharedModule } from '@alfa-client/command-shared'; -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { + ConvertForDataTestPipe, + ConvertProblemDetailToErrorMessagesPipe, + GetUrlPipe, + HasLinkPipe, + ToEmbeddedResourcesPipe, +} from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { + ButtonWithSpinnerComponent, + FileUploadEditorComponent, + SingleFileUploadEditorComponent, + TextareaEditorComponent, + TextEditorComponent, +} from '@ods/component'; import { BescheidInVorgangContainerComponent } from './bescheid-in-vorgang-container/bescheid-in-vorgang-container.component'; import { BescheidInVorgangComponent } from './bescheid-in-vorgang-container/bescheid-in-vorgang/bescheid-in-vorgang.component'; import { BescheidListInVorgangContainerComponent } from './bescheid-list-in-vorgang-container/bescheid-list-in-vorgang-container.component'; @@ -36,30 +48,62 @@ import { DocumentInBescheidContainerComponent } from './bescheid-list-in-vorgang import { BeschiedenDateContainerComponent } from './beschieden-date-in-vorgang-container/beschieden-date-container/beschieden-date-container.component'; import { BeschiedenDateInVorgangContainerComponent } from './beschieden-date-in-vorgang-container/beschieden-date-in-vorgang-container.component'; -import { ButtonWithSpinnerComponent } from '@ods/component'; import { + DateEditorComponent, + ExpansionPanelComponent, + OzgcloudStrokedButtonWithSpinnerComponent, + SpinnerComponent, +} from '@alfa-client/ui'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatIcon } from '@angular/material/icon'; +import { + AttachmentComponent, + AttachmentWrapperComponent, + BescheidGenerateIconComponent, BescheidStatusTextComponent, + BescheidUploadIconComponent, BescheidWrapperComponent, + ButtonCardComponent, ButtonComponent, CloseIconComponent, RadioButtonCardComponent, + SaveIconComponent, + SendIconComponent, + SpinnerIconComponent, StampIconComponent, } from '@ods/system'; +import { FormatFullDatePipe } from '../../../tech-shared/src/lib/pipe/format-full-date.pipe'; import { BescheidWizardContainerComponent } from './bescheid-wizard-container/bescheid-wizard-container.component'; -import { BescheidWizardAbschliessenButtonComponent } from './bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component'; -import { BescheidWizardAbschliessenDialogContainerComponent } from './bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component'; -import { BescheidWizardAntragBescheidenComponent } from './bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component'; +import { BescheidWizardAbschliessenButtonComponent } from './bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component'; +import { BescheidWizardAbschliessenDialogContainerComponent } from './bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component'; +import { BescheidWizardAntragBescheidenContainerComponent } from './bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component'; import { BescheidWizardAntragBescheidenFormComponent } from './bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component'; import { BescheidWizardAntragBescheidenSummaryComponent } from './bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component'; +import { BescheidWizardAttachmentFilesComponent } from './bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component'; +import { BescheidWizardAttachmentFilesContainerComponent } from './bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component'; +import { BescheidWizardBescheidVersendenContainerComponent } from './bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component'; +import { BescheidWizardBescheidVersendenFormComponent } from './bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component'; +import { BescheidWizardBescheidVersendenSummaryComponent } from './bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component'; +import { BescheidWizardBescheidVersendenSendenComponent } from './bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component'; +import { BescheidWizardBescheidVersendenSpeichernComponent } from './bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component'; import { BescheidWizardComponent } from './bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component'; import { BescheidWizardCancelDialogContainerComponent } from './bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component'; -import { BescheidWizardDokumenteHochladenComponent } from './bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component'; -import { BescheidWizardDokumenteHochladenFormComponent } from './bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component'; -import { BescheidWizardDokumenteHochladenSummaryComponent } from './bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component'; +import { BescheidWizardCreateDocumentButtonContainerComponent } from './bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component'; +import { BescheidWizardCreateDocumentButtonComponent } from './bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component'; +import { BescheidWizardDocumentFileContainerComponent } from './bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component'; +import { BescheidWizardDocumentFileComponent } from './bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component'; +import { BescheidWizardDokumenteHochladenContainerComponent } from './bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component'; +import { BescheidWizardDokumenteHochladenFormComponent } from './bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component'; +import { BescheidWizardDokumenteHochladenSummaryComponent } from './bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component'; +import { StepContentLayoutComponent } from './bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component'; import { BescheidWizardStepTitleComponent } from './bescheid-wizard-container/bescheid-wizard/step-title/bescheid-wizard-step-title.component'; import { BescheidWizardStepperComponent } from './bescheid-wizard-container/bescheid-wizard/stepper/bescheid-wizard-stepper.component'; import { BescheidWizardStepComponent } from './bescheid-wizard-container/bescheid-wizard/stepper/step/bescheid-wizard-step.component'; import { BescheidWizardSummaryComponent } from './bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component'; +import { BescheidWizardUploadAttachmentButtonContainerComponent } from './bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component'; +import { BescheidWizardUploadAttachmentButtonComponent } from './bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component'; +import { BescheidWizardUploadDocumentButtonContainerComponent } from './bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component'; +import { BescheidWizardUploadDocumentButtonComponent } from './bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component'; import { BescheidWizardWeiterButtonComponent } from './bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component'; @NgModule({ @@ -67,8 +111,6 @@ import { BescheidWizardWeiterButtonComponent } from './bescheid-wizard-container CommonModule, BescheidSharedModule, BinaryFileModule, - TechSharedModule, - UiModule, CommandSharedModule, BescheidStatusTextComponent, BescheidWrapperComponent, @@ -77,6 +119,31 @@ import { BescheidWizardWeiterButtonComponent } from './bescheid-wizard-container ButtonWithSpinnerComponent, RadioButtonCardComponent, ButtonComponent, + FormatFullDatePipe, + HasLinkPipe, + GetUrlPipe, + ToEmbeddedResourcesPipe, + SpinnerComponent, + ExpansionPanelComponent, + AttachmentWrapperComponent, + MatIcon, + DateEditorComponent, + OzgcloudStrokedButtonWithSpinnerComponent, + ReactiveFormsModule, + ButtonCardComponent, + BescheidGenerateIconComponent, + SingleFileUploadEditorComponent, + BescheidUploadIconComponent, + SpinnerIconComponent, + AttachmentComponent, + AttachmentWrapperComponent, + FileUploadEditorComponent, + SendIconComponent, + SaveIconComponent, + TextEditorComponent, + TextareaEditorComponent, + ConvertForDataTestPipe, + ConvertProblemDetailToErrorMessagesPipe, ], declarations: [ BescheidInVorgangContainerComponent, @@ -94,14 +161,31 @@ import { BescheidWizardWeiterButtonComponent } from './bescheid-wizard-container BescheidWizardSummaryComponent, BescheidWizardWeiterButtonComponent, BescheidWizardCancelDialogContainerComponent, - BescheidWizardAntragBescheidenComponent, + BescheidWizardAntragBescheidenContainerComponent, BescheidWizardAntragBescheidenFormComponent, BescheidWizardAntragBescheidenSummaryComponent, - BescheidWizardDokumenteHochladenComponent, + BescheidWizardDokumenteHochladenContainerComponent, BescheidWizardDokumenteHochladenFormComponent, BescheidWizardDokumenteHochladenSummaryComponent, BescheidWizardAbschliessenButtonComponent, BescheidWizardAbschliessenDialogContainerComponent, + BescheidWizardCreateDocumentButtonContainerComponent, + BescheidWizardCreateDocumentButtonComponent, + BescheidWizardUploadDocumentButtonComponent, + BescheidWizardUploadDocumentButtonContainerComponent, + BescheidWizardDocumentFileComponent, + BescheidWizardDocumentFileContainerComponent, + BescheidWizardDocumentFileComponent, + BescheidWizardUploadAttachmentButtonContainerComponent, + BescheidWizardUploadAttachmentButtonComponent, + BescheidWizardAttachmentFilesContainerComponent, + BescheidWizardAttachmentFilesComponent, + BescheidWizardBescheidVersendenContainerComponent, + BescheidWizardBescheidVersendenFormComponent, + BescheidWizardBescheidVersendenSummaryComponent, + BescheidWizardBescheidVersendenSendenComponent, + BescheidWizardBescheidVersendenSpeichernComponent, + StepContentLayoutComponent, ], exports: [ BescheidInVorgangContainerComponent, diff --git a/alfa-client/libs/binary-file-shared/src/lib/binary-file.repository.spec.ts b/alfa-client/libs/binary-file-shared/src/lib/binary-file.repository.spec.ts index 98650f90ed0824bf3764373e3e07e9e8951b0599..27377b3854e4b1e87900b83f4d957a7751641b1b 100644 --- a/alfa-client/libs/binary-file-shared/src/lib/binary-file.repository.spec.ts +++ b/alfa-client/libs/binary-file-shared/src/lib/binary-file.repository.spec.ts @@ -28,26 +28,22 @@ import { HttpErrorHandler, HttpHeader, ListResource, - TechSharedModule, } from '@alfa-client/tech-shared'; import { mock, mockClass, useFromMock } from '@alfa-client/test-utils'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { faker } from '@faker-js/faker'; import { Resource, ResourceFactory, ResourceUri, getUrl } from '@ngxp/rest'; import { cold, hot } from 'jest-marbles'; +import { InjectorService } from 'libs/tech-shared/src/lib/injector/injector.service'; import { DummyLinkRel } from 'libs/tech-shared/test/dummy'; import { createDummyListResource, createDummyResource } from 'libs/tech-shared/test/resource'; import { Observable, of } from 'rxjs'; -import { - createBinaryFileResource, - createBlob, - createGetRequestOptions, -} from '../../test/binary-file'; +import { createBinaryFileResource, createBlob, createGetRequestOptions } from '../../test/binary-file'; import { BinaryFileLinkRel } from './binary-file.linkrel'; import { BinaryFileResource } from './binary-file.model'; import { BinaryFileRepository } from './binary-file.repository'; -import * as HttpUtil from '../../../tech-shared/src/lib/http.util'; +import * as HttpUtil from 'libs/tech-shared/src/lib/http.util'; describe('BinaryFileRepository', () => { let repository: BinaryFileRepository; @@ -66,7 +62,7 @@ describe('BinaryFileRepository', () => { }); function mockInterceptor(): void { - mockClass(TechSharedModule).injector = <any>{ get: () => useFromMock(mock(HttpErrorHandler)) }; + mockClass(InjectorService).injector = <any>{ get: () => useFromMock(mock(HttpErrorHandler)) }; } it('should be created', () => { @@ -102,9 +98,7 @@ describe('BinaryFileRepository', () => { describe('download', () => { const blob = {}; - const binaryFileResource: BinaryFileResource = createBinaryFileResource([ - BinaryFileLinkRel.DOWNLOAD, - ]); + const binaryFileResource: BinaryFileResource = createBinaryFileResource([BinaryFileLinkRel.DOWNLOAD]); beforeEach(() => { httpClient.get.mockReturnValue(hot('a', { a: blob })); @@ -117,10 +111,7 @@ describe('BinaryFileRepository', () => { repository.download(binaryFileResource); - expect(httpClient.get).toHaveBeenCalledWith( - getUrl(binaryFileResource, BinaryFileLinkRel.DOWNLOAD), - requestOptions, - ); + expect(httpClient.get).toHaveBeenCalledWith(getUrl(binaryFileResource, BinaryFileLinkRel.DOWNLOAD), requestOptions); }); it('should return value', () => { @@ -189,10 +180,7 @@ describe('BinaryFileRepository', () => { }); function getExpectedRequestOptions(): HttpHeaders { - return new HttpHeaders().set(HttpHeader.ACCEPT, [ - ContentType.APPLICATION_PDF, - ContentType.APPLICATION_JSON, - ]); + return new HttpHeaders().set(HttpHeader.ACCEPT, [ContentType.APPLICATION_PDF, ContentType.APPLICATION_JSON]); } }); diff --git a/alfa-client/libs/binary-file/src/lib/binary-file.module.ts b/alfa-client/libs/binary-file/src/lib/binary-file.module.ts index ee4cacdb5f276222620c9a4297808dc6e836c007..9327cbb0be7ef4527eff2aaf36b8f4ffac6e0cb3 100644 --- a/alfa-client/libs/binary-file/src/lib/binary-file.module.ts +++ b/alfa-client/libs/binary-file/src/lib/binary-file.module.ts @@ -21,10 +21,12 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { ConvertForDataTestPipe, FileSizePipe, HasLinkPipe, ToEmbeddedResourcesPipe } from '@alfa-client/tech-shared'; +import { IconButtonWithSpinnerComponent, SpinnerComponent } from '@alfa-client/ui'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; import { DownloadButtonComponent } from '@ods/component'; import { AttachmentComponent, @@ -34,6 +36,8 @@ import { SpinnerIconComponent, TooltipDirective, } from '@ods/system'; +import { FileSizePlainPipe } from '../../../tech-shared/src/lib/pipe/file-size-plain.pipe'; +import { FileUploadEditorComponent } from '../../../ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component'; import { BinaryFileAttachmentContainerComponent } from './binary-file-attachment-container/binary-file-attachment-container.component'; import { BinaryFileContainerComponent } from './binary-file-container/binary-file-container.component'; import { BinaryFileComponent } from './binary-file-container/binary-file/binary-file.component'; @@ -49,14 +53,22 @@ import { VerticalBinaryFileListComponent } from './vertical-binary-file-list/ver @NgModule({ imports: [ CommonModule, - UiModule, - TechSharedModule, AttachmentComponent, AttachmentHeaderComponent, AttachmentWrapperComponent, SpinnerIconComponent, CloseIconComponent, DownloadButtonComponent, + FileUploadEditorComponent, + HasLinkPipe, + MatTooltip, + MatIcon, + SpinnerComponent, + IconButtonWithSpinnerComponent, + FileSizePipe, + ConvertForDataTestPipe, + ToEmbeddedResourcesPipe, + FileSizePlainPipe, TooltipDirective, ], declarations: [ diff --git a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.html b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.html index 83e0a83f944e796fb61fda44e53b40d6637dda78..96927c6b043705cd333e9783282e98ceeca9bc79 100644 --- a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.html +++ b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.html @@ -37,7 +37,7 @@ <button *ngIf="deletable" class="flex size-10 items-center justify-center rounded-md hover:border hover:border-grayborder hover:bg-background-50" - (click)="deleteFile()" + (click)="deleteFile($event)" title="Anhang löschen" aria-label="Anhang löschen Button" > diff --git a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.spec.ts b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.spec.ts index 148cf03abfaa5832df7eed67cdb819b925793c33..7f114ea64baf234b8c76d4a549464d87c21b3801 100644 --- a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.spec.ts +++ b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.spec.ts @@ -89,10 +89,11 @@ describe('BinaryFile2Component', () => { describe('click on delete button', () => { it('should emit delete', () => { + const clickEvent = new Event(''); jest.spyOn(component.startDelete, 'emit'); component.file = createBinaryFileResource(); - component.deleteFile(); + component.deleteFile(clickEvent); expect(component.startDelete.emit).toHaveBeenCalledWith(component.file); }); diff --git a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.ts b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.ts index bcf41375a0ef242662a7261d1f7d6cea78bfddb6..6b0e9946b551196a9968ec0d3f590a876e5c1fb5 100644 --- a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.ts +++ b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.ts @@ -22,11 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { ApiDownloadToken } from '@alfa-client/api-root-shared'; -import { - BinaryFileIcon, - BinaryFileLinkRel, - BinaryFileResource, -} from '@alfa-client/binary-file-shared'; +import { BinaryFileIcon, BinaryFileLinkRel, BinaryFileResource } from '@alfa-client/binary-file-shared'; import { StateResource, createEmptyStateResource } from '@alfa-client/tech-shared'; import { HttpParams } from '@angular/common/http'; import { Component, EventEmitter, Input, Output } from '@angular/core'; @@ -45,10 +41,8 @@ export class BinaryFile2Component { readonly fileLinkRel = BinaryFileLinkRel; - @Output() public startDownload: EventEmitter<BinaryFileResource> = - new EventEmitter<BinaryFileResource>(); - @Output() public startDelete: EventEmitter<BinaryFileResource> = - new EventEmitter<BinaryFileResource>(); + @Output() public startDownload: EventEmitter<BinaryFileResource> = new EventEmitter<BinaryFileResource>(); + @Output() public startDelete: EventEmitter<BinaryFileResource> = new EventEmitter<BinaryFileResource>(); @Output() public getDownloadToken: EventEmitter<void> = new EventEmitter<void>(); get isDisabled(): boolean { @@ -71,7 +65,8 @@ export class BinaryFile2Component { this.startDownload.emit(this.file); } - deleteFile(): void { + deleteFile(e: Event): void { + e.stopPropagation(); this.startDelete.emit(this.file); } diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts index 9af26540fdf4031d434bcb3d4000e2a3f56d3c96..d5726c77529ec251188d2323565ad95742986a58 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts @@ -22,11 +22,11 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { CollaborationListResource } from '@alfa-client/collaboration-shared'; -import { SnackBarService } from '@alfa-client/ui'; -import { TestBed } from '@angular/core/testing'; import { CommandLinkRel, CommandResource } from '@alfa-client/command-shared'; import { StateResource, createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared'; -import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; +import { Mock, mock } from '@alfa-client/test-utils'; +import { SnackBarService } from '@alfa-client/ui'; +import { TestBed } from '@angular/core/testing'; import { UntypedFormBuilder } from '@angular/forms'; import { CollaborationService } from 'libs/collaboration-shared/src/lib/collaboration.service'; import { createCollaborationListResource } from 'libs/collaboration-shared/test/collaboration'; @@ -57,7 +57,6 @@ describe('CollaborationRequestFormService', () => { }); formService = TestBed.inject(CollaborationRequestFormService); - TestBed.inject(CollaborationRequestFormService); }); it('should create', () => { diff --git a/alfa-client/libs/collaboration/src/lib/collaboration.module.ts b/alfa-client/libs/collaboration/src/lib/collaboration.module.ts index a99b23f737e31e8e6024ac8aa471ea53024d61b2..62308b9704c1157391003ae56408374b6ca23cb7 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration.module.ts +++ b/alfa-client/libs/collaboration/src/lib/collaboration.module.ts @@ -22,8 +22,8 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { CollaborationSharedModule } from '@alfa-client/collaboration-shared'; -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; +import { SpinnerComponent } from '@alfa-client/ui'; import { ZustaendigeStelleModule } from '@alfa-client/zustaendige-stelle'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; @@ -63,7 +63,6 @@ import { CollaborationRequestFormComponent } from './collaboration-in-vorgang-co TextareaEditorComponent, FormsModule, ReactiveFormsModule, - TechSharedModule, ButtonWithSpinnerComponent, ZustaendigeStelleModule, OfficeIconComponent, @@ -71,7 +70,8 @@ import { CollaborationRequestFormComponent } from './collaboration-in-vorgang-co PublicAdministrationIconComponent, OrganisationsEinheitListItemContainerComponent, ExterneFachstelleListItemContainerComponent, - UiModule, + HasLinkPipe, + SpinnerComponent, ], declarations: [ CollaborationInVorgangContainerComponent, diff --git a/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts b/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts index 200b8572a2ed3faccb5d14a2346e085ca8262024..c7640cb221008d78f73dd470ae9d3f10287d4bcb 100644 --- a/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts +++ b/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts @@ -74,13 +74,13 @@ describe('CommandResourceService', () => { describe('doSave', () => { it('should throw error', () => { - expect(() => service.doSave(configResource, {})).toThrowError('Method not implemented.'); + expect(() => service.doSave(configResource, {})).toThrow('Method not implemented.'); }); }); describe('doPatch', () => { it('should throw error', () => { - expect(() => service.doPatch(configResource, {})).toThrowError('Method not implemented.'); + expect(() => service.doPatch(configResource, {})).toThrow('Method not implemented.'); }); }); diff --git a/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.spec.ts b/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.spec.ts index 33396fafe3df1fc0f053eb653f7884bf0e5d8788..f4ae75529acf2ebe89875ff3a99f1cc73bc6046e 100644 --- a/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.spec.ts +++ b/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.spec.ts @@ -21,12 +21,13 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { StateResource, createStateResource } from '@alfa-client/tech-shared'; -import { createCommandResource } from 'libs/command-shared/test/command'; +import { createErrorStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared'; +import { createCommandResource, createSuccessfullyDoneCommandStateResource } from 'libs/command-shared/test/command'; import { Observable, of } from 'rxjs'; import { CommandResource } from './command.model'; -import { tapOnCommandSuccessfullyDone } from './command.rxjs.operator'; +import { tapOnCommandSuccessfullyDone, tapOnFailedCommand } from './command.rxjs.operator'; +import { createProblemDetail } from '../../../tech-shared/test/error'; import * as CommandUtil from './command.util'; describe('Command rxjs operator', () => { @@ -54,4 +55,28 @@ describe('Command rxjs operator', () => { }); }); }); + + describe('tapOnFailedCommand', () => { + it('should call the execute the runnable if command has failed', (done) => { + const command = createErrorStateResource(createProblemDetail()); + const commandStateResource$: Observable<StateResource<CommandResource>> = of(command); + const runnable = jest.fn(); + + commandStateResource$.pipe(tapOnFailedCommand(runnable)).subscribe(() => { + expect(runnable).toHaveBeenCalledWith(command); + done(); + }); + }); + + it('should NOT execute the runnable if command was successful', (done) => { + const command = createSuccessfullyDoneCommandStateResource(); + const commandStateResource$: Observable<StateResource<CommandResource>> = of(command); + const runnable = jest.fn(); + + commandStateResource$.pipe(tapOnFailedCommand(runnable)).subscribe(() => { + expect(runnable).not.toHaveBeenCalled(); + done(); + }); + }); + }); }); diff --git a/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.ts b/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.ts index 3acbebff9699ea2dbc5695212070f63e9b07a96b..9e0fddd601cc937185b27a525fab2d710bebe16f 100644 --- a/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.ts +++ b/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.ts @@ -21,19 +21,15 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { StateResource } from '@alfa-client/tech-shared'; +import { hasStateResourceError, StateResource } from '@alfa-client/tech-shared'; import { Observable, of, switchMap, tap } from 'rxjs'; import { CommandResource } from './command.model'; import { isSuccessfulDone } from './command.util'; export function tapOnCommandSuccessfullyDone( runnable: (commandStateResource: StateResource<CommandResource>) => void, -): ( - source: Observable<StateResource<CommandResource>>, -) => Observable<StateResource<CommandResource>> { - return ( - source: Observable<StateResource<CommandResource>>, - ): Observable<StateResource<CommandResource>> => { +): (source: Observable<StateResource<CommandResource>>) => Observable<StateResource<CommandResource>> { + return (source: Observable<StateResource<CommandResource>>): Observable<StateResource<CommandResource>> => { return source.pipe( tap((commandStateResource: StateResource<CommandResource>) => { if (isSuccessfulDone(commandStateResource.resource)) runnable(commandStateResource); @@ -42,14 +38,22 @@ export function tapOnCommandSuccessfullyDone( }; } +export function tapOnFailedCommand( + runnable: (commandStateResource: StateResource<CommandResource>) => void, +): (source: Observable<StateResource<CommandResource>>) => Observable<StateResource<CommandResource>> { + return (source: Observable<StateResource<CommandResource>>): Observable<StateResource<CommandResource>> => { + return source.pipe( + tap((commandStateResource: StateResource<CommandResource>) => { + if (hasStateResourceError(commandStateResource)) runnable(commandStateResource); + }), + ); + }; +} + export function switchMapCommandSuccessfullyDone( runnable: (command: StateResource<CommandResource>) => Observable<StateResource<CommandResource>>, -): ( - source: Observable<StateResource<CommandResource>>, -) => Observable<StateResource<CommandResource>> { - return ( - source: Observable<StateResource<CommandResource>>, - ): Observable<StateResource<CommandResource>> => { +): (source: Observable<StateResource<CommandResource>>) => Observable<StateResource<CommandResource>> { + return (source: Observable<StateResource<CommandResource>>): Observable<StateResource<CommandResource>> => { return source.pipe( switchMap((commandStateResource: StateResource<CommandResource>) => { if (isSuccessfulDone(commandStateResource.resource)) { diff --git a/alfa-client/libs/common/src/lib/build-info/build-info.component.spec.ts b/alfa-client/libs/common/src/lib/build-info/build-info.component.spec.ts index 0f8d5ff01398c359e4eefc7c4b635e454e1ec694..a47f70b4bf63016ac31f407352ff3973d64bca1a 100644 --- a/alfa-client/libs/common/src/lib/build-info/build-info.component.spec.ts +++ b/alfa-client/libs/common/src/lib/build-info/build-info.component.spec.ts @@ -47,8 +47,7 @@ describe('BuildInfoComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [BuildInfoComponent], - declarations: [FormatDateWithTimePipe], + imports: [BuildInfoComponent, FormatDateWithTimePipe], }).compileComponents(); }); diff --git a/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.spec.ts b/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.spec.ts index de1242c608e560f453c76ee160ddaf89dc3b9b0c..7643fbc6e08d29e0aadf7792f87d1f40348b709b 100644 --- a/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.spec.ts +++ b/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.spec.ts @@ -21,13 +21,13 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { createStateResource, StateResource } from '@alfa-client/tech-shared'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { createCommandErrorStateResource, createCommandResource } from 'libs/command-shared/test/command'; +import { createCommandErrorStateResource } from 'libs/command-shared/test/command'; import { createApiError } from 'libs/tech-shared/test/error'; +import { createDummyResource } from '../../../../tech-shared/test/resource'; import { ButtonWithSpinnerComponent } from './button-with-spinner.component'; -import * as ResourceUtils from 'libs/tech-shared/src/lib/resource/resource.util'; - describe('ButtonWithSpinnerComponent', () => { let component: ButtonWithSpinnerComponent; let fixture: ComponentFixture<ButtonWithSpinnerComponent>; @@ -46,39 +46,25 @@ describe('ButtonWithSpinnerComponent', () => { expect(component).toBeTruthy(); }); - describe('onInit', () => { - it('should call getStateResource', () => { - component.getStateResource = jest.fn(); + describe('set stateResource', () => { + it('should set stateResource', () => { + const stateResource: StateResource<unknown> = createStateResource(createDummyResource()); - component.ngOnInit(); + component.stateResource = stateResource; - expect(component.getStateResource).toHaveBeenCalled(); + expect(component._stateResource).toBe(stateResource); }); - }); - - describe('getStateResource', () => { - it('should return stateResource', () => { - component.stateResource = ResourceUtils.createStateResource(createCommandResource()); - - component.getStateResource(); - const valid: boolean = ResourceUtils.isValidStateResource(component.stateResource); - expect(valid).toBeTruthy(); - }); - - it('should return empty stateResource', () => { - const spy = jest.spyOn(ResourceUtils, 'createEmptyStateResource'); + it('should not set stateResource', () => { component.stateResource = null; - component.getStateResource(); - - expect(spy).toHaveBeenCalled(); + expect(component._stateResource).not.toBe(null); }); }); describe('isLoading', () => { it('should return false', () => { - component.stateResource.loading = component.stateResource.reload = false; + component._stateResource.loading = component._stateResource.reload = false; const isLoading: boolean = component.isLoading; @@ -86,8 +72,8 @@ describe('ButtonWithSpinnerComponent', () => { }); it('should return true if stateResource is loading', () => { - component.stateResource.loading = true; - component.stateResource.reload = false; + component._stateResource.loading = true; + component._stateResource.reload = false; const isLoading: boolean = component.isLoading; @@ -95,8 +81,8 @@ describe('ButtonWithSpinnerComponent', () => { }); it('should return true if stateResource is reloading', () => { - component.stateResource.loading = false; - component.stateResource.reload = true; + component._stateResource.loading = false; + component._stateResource.reload = true; const isLoading: boolean = component.isLoading; @@ -106,7 +92,7 @@ describe('ButtonWithSpinnerComponent', () => { describe('isError', () => { it('should return false if error is not set', () => { - component.stateResource.error = null; + component._stateResource.error = null; const isError: boolean = component.isError; @@ -114,7 +100,7 @@ describe('ButtonWithSpinnerComponent', () => { }); it('should return false if error is set and error is ApiError', () => { - component.stateResource.error = createApiError(); + component._stateResource.error = createApiError(); const isError: boolean = component.isError; @@ -122,7 +108,7 @@ describe('ButtonWithSpinnerComponent', () => { }); it('should return true if error is set and error is not ApiError', () => { - component.stateResource = createCommandErrorStateResource(); + component._stateResource = createCommandErrorStateResource(); const isError: boolean = component.isError; diff --git a/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.ts b/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.ts index f76f1f907cecaa625c3e1c6dc950458e3f4aa640..a12b0a8ad74b49d34ec172ae36682d7d0ce01104 100644 --- a/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.ts +++ b/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.ts @@ -24,7 +24,7 @@ import { CommandResource, hasCommandError } from '@alfa-client/command-shared'; import { StateResource, createEmptyStateResource, isLoaded } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; import { ButtonComponent, ErrorMessageComponent, buttonVariants } from '@ods/system'; import { VariantProps } from 'class-variance-authority'; import { isNil } from 'lodash-es'; @@ -49,28 +49,24 @@ type ButtonVariants = VariantProps<typeof buttonVariants>; <ng-content icon select="[icon]" /> </ods-button>`, }) -export class ButtonWithSpinnerComponent implements OnInit { +export class ButtonWithSpinnerComponent { + @Input() set stateResource(value: StateResource<unknown>) { + if (!isNil(value)) this._stateResource = value; + } @Input() text: string = ''; @Input() dataTestId: string = ''; - @Input() stateResource: StateResource<unknown>; @Input() variant: ButtonVariants['variant'] = 'primary'; @Input() size: ButtonVariants['size'] = 'medium'; @Output() public clickEmitter: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>(); - ngOnInit(): void { - this.stateResource = this.getStateResource(); - } - - getStateResource(): StateResource<unknown> { - return isNil(this.stateResource) ? createEmptyStateResource() : this.stateResource; - } + _stateResource: StateResource<unknown> = createEmptyStateResource(); get isLoading(): boolean { - return this.stateResource.loading || this.stateResource.reload; + return this._stateResource.loading || this._stateResource.reload; } get isError(): boolean { - return isLoaded(this.stateResource) && hasCommandError(<CommandResource>this.stateResource.resource); + return isLoaded(this._stateResource) && hasCommandError(<CommandResource>this._stateResource.resource); } } diff --git a/alfa-client/libs/design-component/src/lib/form/checkbox-editor/checkbox-editor.component.ts b/alfa-client/libs/design-component/src/lib/form/checkbox-editor/checkbox-editor.component.ts index 121f52bb8d5778c67a38097c5766632adbdb3199..dfab859671455c3354bd14297d069ffde5474cde 100644 --- a/alfa-client/libs/design-component/src/lib/form/checkbox-editor/checkbox-editor.component.ts +++ b/alfa-client/libs/design-component/src/lib/form/checkbox-editor/checkbox-editor.component.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { Component, Input } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { CheckboxComponent } from '@ods/system'; @@ -31,7 +31,7 @@ import { ValidationErrorComponent } from '../validation-error/validation-error.c @Component({ selector: 'ods-checkbox-editor', standalone: true, - imports: [CheckboxComponent, ValidationErrorComponent, TechSharedModule, ReactiveFormsModule], + imports: [CheckboxComponent, ValidationErrorComponent, ReactiveFormsModule, ConvertForDataTestPipe], templateUrl: './checkbox-editor.component.html', }) export class CheckboxEditorComponent extends FormControlEditorAbstractComponent { diff --git a/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.html b/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.html index 4a9fe0c97298f30da5307f19c7ca79cbeca42f73..ff08ce18e4ad8cc6037b84833bd941f375a6da0f 100644 --- a/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.html +++ b/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.html @@ -34,7 +34,7 @@ [accept]="accept" [attr.data-test-id]="(label | convertForDataTest) + '-file-upload-button'" [isLoading]="uploadInProgress.loading" - class="relative w-72" + class="relative w-full max-w-72" > <ods-spinner-icon spinner size="medium" /> <ods-attachment-icon icon size="medium" /> diff --git a/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.spec.ts b/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.spec.ts index e23d68f4fd3158c668a388aad404022810f1202f..9bb05063e492ff44967a3e62cd4d23bfad2a835e 100644 --- a/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.spec.ts +++ b/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.spec.ts @@ -21,15 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule, createEmptyStateResource } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe, createEmptyStateResource } from '@alfa-client/tech-shared'; import { getElementFromFixture } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - AbstractControl, - FormGroupDirective, - ReactiveFormsModule, - UntypedFormBuilder, -} from '@angular/forms'; +import { AbstractControl, FormGroupDirective, ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; import { FileUploadButtonComponent, SpinnerIconComponent } from '@ods/system'; import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { MockComponent } from 'ng-mocks'; @@ -48,12 +43,8 @@ describe('FileUploadEditorComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - FileUploadEditorComponent, - MockComponent(SpinnerIconComponent), - MockComponent(FileUploadButtonComponent), - ], - imports: [ReactiveFormsModule, TechSharedModule], + declarations: [FileUploadEditorComponent, MockComponent(SpinnerIconComponent), MockComponent(FileUploadButtonComponent)], + imports: [ReactiveFormsModule, ConvertForDataTestPipe], providers: [ { provide: FormGroupDirective, diff --git a/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.ts b/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.ts index 0a9f5a53efe396aa9345b39f56d1b2f6ca1e1b63..2a412d827f7501dc914cf05bad19dbe00b85ebfe 100644 --- a/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.ts +++ b/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.ts @@ -21,22 +21,12 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { StateResource, TechSharedModule } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe, StateResource } from '@alfa-client/tech-shared'; import { NgForOf } from '@angular/common'; import { Component, EventEmitter, HostListener, Input, OnInit, Output } from '@angular/core'; -import { - ControlContainer, - FormGroupDirective, - ReactiveFormsModule, - UntypedFormArray, - UntypedFormControl, -} from '@angular/forms'; +import { ControlContainer, FormGroupDirective, ReactiveFormsModule, UntypedFormArray, UntypedFormControl } from '@angular/forms'; import { Resource } from '@ngxp/rest'; -import { - AttachmentIconComponent, - FileUploadButtonComponent, - SpinnerIconComponent, -} from '@ods/system'; +import { AttachmentIconComponent, FileUploadButtonComponent, SpinnerIconComponent } from '@ods/system'; import { uniqueId } from 'lodash-es'; import { FormControlEditorAbstractComponent } from '../formcontrol-editor.abstract.component'; @@ -51,13 +41,10 @@ import { FormControlEditorAbstractComponent } from '../formcontrol-editor.abstra SpinnerIconComponent, ReactiveFormsModule, NgForOf, - TechSharedModule, + ConvertForDataTestPipe, ], }) -export class FileUploadEditorComponent - extends FormControlEditorAbstractComponent - implements OnInit -{ +export class FileUploadEditorComponent extends FormControlEditorAbstractComponent implements OnInit { @Input() label: string = ''; @Input() parentFormArrayName: string; @Input() accept: string = '*/*'; @@ -88,9 +75,7 @@ export class FileUploadEditorComponent buildFormArray(fileLinkList: string[]): void { this.fileLinkControls.clear(); - fileLinkList.forEach((link: string) => - this.fileLinkControls.push(new UntypedFormControl(link)), - ); + fileLinkList.forEach((link: string) => this.fileLinkControls.push(new UntypedFormControl(link))); } upload(file: File): void { diff --git a/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.html b/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.html index ab4172edc10957129320faf3a6533cfe9d1c77ce..837b069ad149e2e7e2eb08305e54e8ab74df16f5 100644 --- a/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.html +++ b/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.html @@ -24,7 +24,7 @@ --> <ods-file-upload-button - class="w-72" + class="w-full max-w-72" [id]="uploadFileId" [isLoading]="uploadInProgress" [accept]="accept" diff --git a/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.ts b/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.ts index 4ae84174d1a25498142f7c5f0b8584172b5aff40..a62e384fb3c9ff9c15b453cc9927438d1e1790c4 100644 --- a/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.ts +++ b/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule, isNotNil } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe, isNotNil } from '@alfa-client/tech-shared'; import { Component, EventEmitter, HostListener, Input, Output } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { FileUploadButtonComponent, SpinnerIconComponent } from '@ods/system'; @@ -32,7 +32,7 @@ import { FormControlEditorAbstractComponent } from '../formcontrol-editor.abstra selector: 'ods-single-file-upload-editor', templateUrl: './single-file-upload-editor.component.html', standalone: true, - imports: [FileUploadButtonComponent, SpinnerIconComponent, ReactiveFormsModule, TechSharedModule], + imports: [FileUploadButtonComponent, SpinnerIconComponent, ReactiveFormsModule, ConvertForDataTestPipe], }) export class SingleFileUploadEditorComponent extends FormControlEditorAbstractComponent { @Input() label: string = ''; diff --git a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.ts b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.ts index 88059147b43c73716251cd6999184bba085a3479..cfdd66512de073b74f0dbfd2bbed633573f9651f 100644 --- a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.ts +++ b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; @@ -32,13 +32,7 @@ import { ValidationErrorComponent } from '../validation-error/validation-error.c @Component({ selector: 'ods-text-editor', standalone: true, - imports: [ - CommonModule, - ReactiveFormsModule, - TechSharedModule, - TextInputComponent, - ValidationErrorComponent, - ], + imports: [CommonModule, ReactiveFormsModule, TextInputComponent, ValidationErrorComponent, ConvertForDataTestPipe], templateUrl: './text-editor.component.html', }) export class TextEditorComponent extends FormControlEditorAbstractComponent { diff --git a/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.ts b/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.ts index be0fc9b4f33d4ca6ddceb6912c8dc82c769e3ac5..c7032ef03b58627369f4857d0b2bda4546d092b5 100644 --- a/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.ts +++ b/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; @@ -32,13 +32,7 @@ import { ValidationErrorComponent } from '../validation-error/validation-error.c @Component({ selector: 'ods-textarea-editor', standalone: true, - imports: [ - CommonModule, - ReactiveFormsModule, - TechSharedModule, - TextareaComponent, - ValidationErrorComponent, - ], + imports: [CommonModule, ReactiveFormsModule, TextareaComponent, ValidationErrorComponent, ConvertForDataTestPipe], templateUrl: './textarea-editor.component.html', }) export class TextareaEditorComponent extends FormControlEditorAbstractComponent { diff --git a/alfa-client/libs/design-component/src/lib/routing-button/routing-button.component.ts b/alfa-client/libs/design-component/src/lib/routing-button/routing-button.component.ts index 2a25cd22e5df3e74e404a3fd986d737b29ab5a2c..98346f3903e1cff4b363c5f4f4dc49243ce84c7d 100644 --- a/alfa-client/libs/design-component/src/lib/routing-button/routing-button.component.ts +++ b/alfa-client/libs/design-component/src/lib/routing-button/routing-button.component.ts @@ -1,22 +1,26 @@ import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; import { RouterLink } from '@angular/router'; +import { ButtonVariants, buttonVariants } from '@ods/system'; @Component({ selector: 'ods-routing-button', standalone: true, imports: [CommonModule, RouterLink], host: { class: 'block' }, - template: `<a - [routerLink]="'/' + linkPath" - [attr.data-test-id]="dataTestId" - class="block min-h-9 w-fit min-w-32 rounded bg-primary px-4 py-2 text-sm font-medium text-white shadow-sm outline-focus hover:bg-primary-hover focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2" - > - {{ text }} + template: `<a [routerLink]="'/' + linkPath" [attr.data-test-id]="dataTestId" [ngClass]="buttonVariants({ size, variant })"> + <ng-content select="[icon]" /> + @if (text) { + <p class="flex-grow">{{ text }}</p> + } </a>`, }) export class RoutingButtonComponent { @Input() linkPath: string; @Input() text: string; @Input() dataTestId: string; + @Input() variant: ButtonVariants['variant']; + @Input() size: ButtonVariants['size']; + + readonly buttonVariants = buttonVariants; } diff --git a/alfa-client/libs/design-system/run_helm_test.sh b/alfa-client/libs/design-system/run_helm_test.sh old mode 100755 new mode 100644 diff --git a/alfa-client/libs/design-system/src/index.ts b/alfa-client/libs/design-system/src/index.ts index 467032047c06e4ae9c4a6e3948cc13a704b8761d..e7ae662925633f6c656ce0c64ba919debf94b774 100644 --- a/alfa-client/libs/design-system/src/index.ts +++ b/alfa-client/libs/design-system/src/index.ts @@ -52,6 +52,7 @@ export * from './lib/icons/bescheid-upload-icon/bescheid-upload-icon.component'; export * from './lib/icons/check-circle-icon/check-circle-icon.component'; export * from './lib/icons/check-icon/check-icon.component'; export * from './lib/icons/close-icon/close-icon.component'; +export * from './lib/icons/delete-icon/delete-icon.component'; export * from './lib/icons/delete-vorgang-finally-icon/delete-vorgang-finally-icon.component'; export * from './lib/icons/discard-vorgang-icon/discard-vorgang-icon.component'; export * from './lib/icons/edit-icon/edit-icon.component'; diff --git a/alfa-client/libs/design-system/src/lib/button/button.component.ts b/alfa-client/libs/design-system/src/lib/button/button.component.ts index 46b0308c205dff5a889142e76693dd27cffc30bb..15a9b7efdc261b462f3dade0f93b2a6902e36507 100644 --- a/alfa-client/libs/design-system/src/lib/button/button.component.ts +++ b/alfa-client/libs/design-system/src/lib/button/button.component.ts @@ -64,22 +64,24 @@ export const buttonVariants = cva( { variant: 'primary', destructive: true, - class: '[&]:hover:enabled:bg-destructive-primary-hover [&]:bg-destructive [&]:outline-destructive', + class: + '[&]:hover:enabled:bg-destructive-primary-hover [&]:bg-destructive [&]:outline-destructive [&]:focus-visible:bg-destructive-primary-hover', }, { variant: 'outline', destructive: true, - class: '[&]:border-destructive [&]:text-destructive [&]:hover:enabled:bg-destructive-hover', + class: + '[&]:border-destructive [&]:text-destructive [&]:hover:enabled:bg-destructive-hover [&]:focus-visible:bg-destructive-hover', }, { variant: 'ghost', destructive: true, - class: '[&]:text-destructive [&]:hover:enabled:bg-destructive-hover', + class: '[&]:text-destructive [&]:hover:enabled:bg-destructive-hover [&]:focus-visible:bg-destructive-hover', }, ], }, ); -type ButtonVariants = VariantProps<typeof buttonVariants>; +export type ButtonVariants = VariantProps<typeof buttonVariants>; @Component({ selector: 'ods-button', diff --git a/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-link-item/dropdown-menu-link-item.component.ts b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-link-item/dropdown-menu-link-item.component.ts index 52b3e46d6ac1e69ce02472bec600580c6e7663af..045191b56a76618a85600a82757607f267b4c8e4 100644 --- a/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-link-item/dropdown-menu-link-item.component.ts +++ b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-link-item/dropdown-menu-link-item.component.ts @@ -5,7 +5,7 @@ import { LinkComponent } from '../../link/link.component'; @Component({ selector: 'ods-dropdown-menu-link-item', standalone: true, - imports: [LinkComponent, OpenLinkIconComponent], + imports: [OpenLinkIconComponent, LinkComponent], styles: [':host {@apply first:mt-2}'], template: ` <ods-link [url]="url" class="bg-whitetext" [openInNewTab]="true"> <div class="flex items-center gap-2 px-4 py-3"> diff --git a/alfa-client/libs/design-system/src/lib/form/checkbox/checkbox.component.ts b/alfa-client/libs/design-system/src/lib/form/checkbox/checkbox.component.ts index 120fa956bb755ed800f6742dfe7ddfe69d5acd38..ffadf796c9031418fda5463896a1452351f2e109 100644 --- a/alfa-client/libs/design-system/src/lib/form/checkbox/checkbox.component.ts +++ b/alfa-client/libs/design-system/src/lib/form/checkbox/checkbox.component.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; @@ -29,7 +29,7 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; @Component({ selector: 'ods-checkbox', standalone: true, - imports: [CommonModule, ReactiveFormsModule, TechSharedModule], + imports: [CommonModule, ReactiveFormsModule, ConvertForDataTestPipe], template: ` <div> <div class="relative flex items-start gap-3 text-start"> diff --git a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.spec.ts b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.spec.ts index 0972a93d2bce07621c9426953b0374f4e3167d6f..fee4fa492f168106fce4c7f8c97dc6b31a956ddd 100644 --- a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.spec.ts +++ b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.spec.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { getElementFromFixture } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { faker } from '@faker-js/faker'; @@ -37,7 +37,7 @@ describe('FileUploadButtonComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [FileUploadButtonComponent, TechSharedModule], + imports: [FileUploadButtonComponent, ConvertForDataTestPipe], }).compileComponents(); fixture = TestBed.createComponent(FileUploadButtonComponent); diff --git a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.ts b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.ts index 8a1f968b27776f44ab77b0931867fc39487e13d5..3e111b19ad208b4b4505a67bb8ef343ae6de0d2e 100644 --- a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.ts +++ b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.ts @@ -21,14 +21,14 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { Component, ElementRef, Input, ViewChild } from '@angular/core'; @Component({ selector: 'ods-file-upload-button', standalone: true, - imports: [CommonModule, TechSharedModule], + imports: [CommonModule, ConvertForDataTestPipe], styles: [':host {@apply inline-flex}'], templateUrl: './file-upload-button.component.html', }) diff --git a/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.spec.ts b/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.spec.ts index 6d1f5b7eb8b1fab21996dd2991b2b09780edf82e..974db9b7c5c5dc93f83768157da9d570cfb0a2d3 100644 --- a/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.spec.ts +++ b/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.spec.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { convertForDataTest } from '@alfa-client/tech-shared'; +import { convertForDataTest, ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { getElementFromFixture } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; @@ -37,7 +37,7 @@ describe('TextInputComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [ReactiveFormsModule, TextInputComponent], + imports: [ReactiveFormsModule, TextInputComponent, ConvertForDataTestPipe], }).compileComponents(); fixture = TestBed.createComponent(TextInputComponent); diff --git a/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts b/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts index 1b038667fb82ad7c9832ded8ed18185eb1cd8780..ca6a007c19e49ebb481ff0655b407cc3076a9c08 100644 --- a/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts +++ b/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts @@ -21,11 +21,12 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { convertForDataTest, EMPTY_STRING, TechSharedModule } from '@alfa-client/tech-shared'; +import { convertForDataTest, ConvertForDataTestPipe, EMPTY_STRING } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { cva, VariantProps } from 'class-variance-authority'; +import { uniqueId } from 'lodash-es'; const textInputVariants = cva( [ @@ -50,7 +51,7 @@ type TextInputVariants = VariantProps<typeof textInputVariants>; @Component({ selector: 'ods-text-input', standalone: true, - imports: [CommonModule, ReactiveFormsModule, TechSharedModule], + imports: [CommonModule, ReactiveFormsModule, ConvertForDataTestPipe], template: ` <div class="relative"> <label *ngIf="showLabel" [for]="id" class="text-md mb-2 block font-medium text-text"> @@ -86,7 +87,7 @@ export class TextInputComponent { @Input({ required: true }) set label(label: string) { this.inputLabel = label; - this.id = convertForDataTest(label); + this.id = `${convertForDataTest(label)}-${uniqueId()}`; } @Input() placeholder: string = ''; @Input() autocomplete: string = 'off'; diff --git a/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.spec.ts b/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.spec.ts index 872bec5354754d00e3f7d64eb724b20ed447e56c..580f9cab71a29070581554c29320b4ca86cd83fe 100644 --- a/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.spec.ts +++ b/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.spec.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { convertForDataTest } from '@alfa-client/tech-shared'; +import { convertForDataTest, ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { getElementFromFixture } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; @@ -37,7 +37,7 @@ describe('TextareaComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [ReactiveFormsModule, TextareaComponent], + imports: [ReactiveFormsModule, TextareaComponent, ConvertForDataTestPipe], }).compileComponents(); fixture = TestBed.createComponent(TextareaComponent); diff --git a/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts b/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts index ddc4a66781c0334c956a0d0b1b283b74110d2d38..f3eb84af9d638567a3bcbdc644b400abf344643e 100644 --- a/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts +++ b/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { EMPTY_STRING, TechSharedModule, convertForDataTest } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe, EMPTY_STRING, convertForDataTest } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { Component, ElementRef, Input, ViewChild } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; @@ -37,8 +37,7 @@ const textareaVariants = cva( variant: { default: 'border-primary-600/50 focus-visible:outline-focus focus-visible:border-background-200 hover:border-primary-hover', - error: - 'border-error/50 hover:border-error focus-visible:outline-error focus-visible:border-background-200', + error: 'border-error/50 hover:border-error focus-visible:outline-error focus-visible:border-background-200', }, }, defaultVariants: { @@ -51,7 +50,7 @@ type TextareaVariants = VariantProps<typeof textareaVariants>; @Component({ selector: 'ods-textarea', standalone: true, - imports: [CommonModule, ReactiveFormsModule, TechSharedModule], + imports: [CommonModule, ReactiveFormsModule, ConvertForDataTestPipe], template: ` <div class="mt-2"> <label *ngIf="showLabel" [for]="id" class="text-md mb-2 block font-medium text-text"> @@ -61,7 +60,7 @@ type TextareaVariants = VariantProps<typeof textareaVariants>; [id]="id" [formControl]="fieldControl" [rows]="rows" - [ngClass]="[textareaVariants({ variant }), isResizable ? 'resize' : 'resize-none']" + [ngClass]="[textareaVariants({ variant }), isResizable ? 'resize-y' : 'resize-none']" [placeholder]="placeholder" [autocomplete]="autocomplete" [attr.aria-required]="required" diff --git a/alfa-client/libs/design-system/src/lib/icons/delete-icon/delete-icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icons/delete-icon/delete-icon.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..354449bdfb0652606ec23dee7b970a5d793fd292 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/icons/delete-icon/delete-icon.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { DeleteIconComponent } from './delete-icon.component'; + +describe('DeleteIconComponent', () => { + let component: DeleteIconComponent; + let fixture: ComponentFixture<DeleteIconComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [DeleteIconComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(DeleteIconComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/libs/design-system/src/lib/icons/delete-icon/delete-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/delete-icon/delete-icon.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..fc06f683c6790f219c7c08fb258764b35cdf2b6c --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/icons/delete-icon/delete-icon.component.ts @@ -0,0 +1,27 @@ +import { CommonModule } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { twMerge } from 'tailwind-merge'; +import { IconVariants, iconVariants } from '../iconVariants'; + +@Component({ + selector: 'ods-delete-icon', + standalone: true, + imports: [CommonModule], + template: `<svg + viewBox="0 0 24 24" + xmlns="http://www.w3.org/2000/svg" + [ngClass]="[twMerge(iconVariants({ size }), 'fill-error', class)]" + aria-hidden="true" + > + <path + d="M7 21C6.45 21 5.97917 20.8042 5.5875 20.4125C5.19583 20.0208 5 19.55 5 19V6H4V4H9V3H15V4H20V6H19V19C19 19.55 18.8042 20.0208 18.4125 20.4125C18.0208 20.8042 17.55 21 17 21H7ZM17 6H7V19H17V6ZM9 17H11V8H9V17ZM13 17H15V8H13V17Z" + /> + </svg> `, +}) +export class DeleteIconComponent { + @Input() size: IconVariants['size'] = 'medium'; + @Input() class: string = ''; + + readonly iconVariants = iconVariants; + readonly twMerge = twMerge; +} diff --git a/alfa-client/libs/design-system/src/lib/icons/delete-icon/delete-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/delete-icon/delete-icon.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..4602289bc57c1be551e4bf2ba29003ab4bd7de31 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/icons/delete-icon/delete-icon.stories.ts @@ -0,0 +1,27 @@ +import type { Meta, StoryObj } from '@storybook/angular'; + +import { DeleteIconComponent } from './delete-icon.component'; + +const meta: Meta<DeleteIconComponent> = { + title: 'Icons/Delete icon', + component: DeleteIconComponent, + excludeStories: /.*Data$/, + tags: ['autodocs'], +}; + +export default meta; +type Story = StoryObj<DeleteIconComponent>; + +export const Default: Story = { + args: { size: 'large' }, + argTypes: { + size: { + control: 'select', + options: ['small', 'medium', 'large', 'extra-large', 'full'], + description: 'Size of icon. Property "full" means 100%', + table: { + defaultValue: { summary: 'medium' }, + }, + }, + }, +}; diff --git a/alfa-client/libs/design-system/src/lib/navbar/nav-item/nav-item.component.spec.ts b/alfa-client/libs/design-system/src/lib/navbar/nav-item/nav-item.component.spec.ts index 81485f802c48588260d6b38b383de316984fa55d..f4fd0fc39d030ec83824c3c8c0a7daefe3764de6 100644 --- a/alfa-client/libs/design-system/src/lib/navbar/nav-item/nav-item.component.spec.ts +++ b/alfa-client/libs/design-system/src/lib/navbar/nav-item/nav-item.component.spec.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { convertForDataTest, TechSharedModule } from '@alfa-client/tech-shared'; +import { convertForDataTest, ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { getElementFromFixture, Mock, mock } from '@alfa-client/test-utils'; import { importProvidersFrom } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; @@ -37,7 +37,7 @@ describe('NavItemComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [NavItemComponent, TechSharedModule], + imports: [NavItemComponent, ConvertForDataTestPipe], providers: [ { provide: Router, diff --git a/alfa-client/libs/design-system/src/lib/navbar/nav-item/nav-item.component.ts b/alfa-client/libs/design-system/src/lib/navbar/nav-item/nav-item.component.ts index ac28440c045dd78e514f7f898d0f241b8e88921c..a3bd688e8120d42fba03efcde48d23510fdc66e7 100644 --- a/alfa-client/libs/design-system/src/lib/navbar/nav-item/nav-item.component.ts +++ b/alfa-client/libs/design-system/src/lib/navbar/nav-item/nav-item.component.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { Component, HostBinding, Input } from '@angular/core'; import { RouterLink, RouterLinkActive } from '@angular/router'; @@ -29,13 +29,11 @@ import { RouterLink, RouterLinkActive } from '@angular/router'; @Component({ selector: 'ods-nav-item', standalone: true, - imports: [CommonModule, RouterLink, RouterLinkActive, TechSharedModule], + imports: [CommonModule, RouterLink, RouterLinkActive, ConvertForDataTestPipe], template: `<a [routerLink]="path" routerLinkActive="bg-selected-light border-selected" - class="flex min-h-8 items-center gap-2 rounded-2xl border border-transparent - px-4 py-2 outline-2 outline-offset-2 outline-focus hover:border-primary - focus-visible:border-background-200 focus-visible:outline" + class="flex min-h-8 items-center gap-2 rounded-2xl border border-transparent px-4 py-2 outline-2 outline-offset-2 outline-focus hover:border-primary focus-visible:border-background-200 focus-visible:outline" [attr.data-test-id]="'link-path-' + path | convertForDataTest" > <ng-content select="[icon]" /> diff --git a/alfa-client/libs/externe-fachstelle/src/lib/externe-fachstelle-list-item-container/externe-fachstelle-list-item/externe-fachstelle-list-item.component.ts b/alfa-client/libs/externe-fachstelle/src/lib/externe-fachstelle-list-item-container/externe-fachstelle-list-item/externe-fachstelle-list-item.component.ts index 51d26eecb5813638527dc472c75d3ea22b744233..274c1b9090b1b6e299db74c41b9a1e08cb1dd62c 100644 --- a/alfa-client/libs/externe-fachstelle/src/lib/externe-fachstelle-list-item-container/externe-fachstelle-list-item/externe-fachstelle-list-item.component.ts +++ b/alfa-client/libs/externe-fachstelle/src/lib/externe-fachstelle-list-item-container/externe-fachstelle-list-item/externe-fachstelle-list-item.component.ts @@ -22,7 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { StateResource } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { SpinnerComponent } from '@alfa-client/ui'; import { ExterneFachstelleResource } from '@alfa-client/zustaendige-stelle-shared'; import { Component, Input } from '@angular/core'; import { ExternalUnitIconComponent, PublicAdministrationIconComponent } from '@ods/system'; @@ -30,7 +30,7 @@ import { ExternalUnitIconComponent, PublicAdministrationIconComponent } from '@o @Component({ selector: 'alfa-externe-fachstelle-list-item', standalone: true, - imports: [PublicAdministrationIconComponent, ExternalUnitIconComponent, UiModule], + imports: [PublicAdministrationIconComponent, ExternalUnitIconComponent, SpinnerComponent], templateUrl: './externe-fachstelle-list-item.component.html', }) export class ExterneFachstelleListItemComponent { diff --git a/alfa-client/libs/forwarding/src/lib/forward-by-ozgcloud-button-container/forward-by-ozgcloud-button-container.component.spec.ts b/alfa-client/libs/forwarding/src/lib/forward-by-ozgcloud-button-container/forward-by-ozgcloud-button-container.component.spec.ts index 0bdb21fd38ad815027918f1b3e13b7a1818f57d4..8aab319a28e6ed8a3cd49270fdd27a42e2ed09f3 100644 --- a/alfa-client/libs/forwarding/src/lib/forward-by-ozgcloud-button-container/forward-by-ozgcloud-button-container.component.spec.ts +++ b/alfa-client/libs/forwarding/src/lib/forward-by-ozgcloud-button-container/forward-by-ozgcloud-button-container.component.spec.ts @@ -1,3 +1,4 @@ +import { HasLinkPipe } from '@alfa-client/tech-shared'; import { existsAsHtmlElement, notExistsAsHtmlElement } from '@alfa-client/test-utils'; import { VorgangWithEingangLinkRel } from '@alfa-client/vorgang-shared'; import { ComponentFixture, TestBed } from '@angular/core/testing'; @@ -17,7 +18,7 @@ describe('ForwardByOzgcloudButtonContainerComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [ForwardByOzgcloudButtonContainerComponent], + imports: [ForwardByOzgcloudButtonContainerComponent, HasLinkPipe], declarations: [ MockComponent(ButtonWithSpinnerComponent), MockComponent(ForwardVorgangIconComponent), diff --git a/alfa-client/libs/forwarding/src/lib/forward-by-ozgcloud-button-container/forward-by-ozgcloud-button-container.component.ts b/alfa-client/libs/forwarding/src/lib/forward-by-ozgcloud-button-container/forward-by-ozgcloud-button-container.component.ts index b00da7ddb3c481ac14502f9091ec29c4b9af2748..f5fbad7ed1280171822f6746847c08887dbaff75 100644 --- a/alfa-client/libs/forwarding/src/lib/forward-by-ozgcloud-button-container/forward-by-ozgcloud-button-container.component.ts +++ b/alfa-client/libs/forwarding/src/lib/forward-by-ozgcloud-button-container/forward-by-ozgcloud-button-container.component.ts @@ -1,4 +1,4 @@ -import { TechSharedModule } from '@alfa-client/tech-shared'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; @@ -8,7 +8,7 @@ import { ForwardVorgangIconComponent, TooltipDirective } from '@ods/system'; @Component({ selector: 'alfa-forward-by-ozgcloud-button-container', standalone: true, - imports: [CommonModule, TechSharedModule, ButtonWithSpinnerComponent, ForwardVorgangIconComponent, TooltipDirective], + imports: [CommonModule, ButtonWithSpinnerComponent, ForwardVorgangIconComponent, TooltipDirective, HasLinkPipe], templateUrl: './forward-by-ozgcloud-button-container.component.html', styles: [':host {@apply empty:hidden}'], }) diff --git a/alfa-client/libs/forwarding/src/lib/forwarding.module.ts b/alfa-client/libs/forwarding/src/lib/forwarding.module.ts index 56ba3f3ad8c2a79a91c9cbe1dd619140d63a9427..973cf7b7a1603273e98ca30ee0bd511c57bb9cc1 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding.module.ts +++ b/alfa-client/libs/forwarding/src/lib/forwarding.module.ts @@ -21,12 +21,19 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; import { CommandSharedModule } from '@alfa-client/command-shared'; import { ForwardingSharedModule } from '@alfa-client/forwarding-shared'; -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { FormatDateWithTimePipe, HasLinkPipe, ToEmbeddedResourcesPipe } from '@alfa-client/tech-shared'; +import { + ExpansionPanelComponent, + OzgcloudStrokedButtonWithSpinnerComponent, + OzgcloudTextEditorComponent, + SpinnerComponent, +} from '@alfa-client/ui'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatIcon } from '@angular/material/icon'; import { VorgangForwardFormComponent } from './vorgang-forwarding-container/vorgang-forward-formular/vorgang-forward-form/vorgang-forward-form.component'; import { VorgangForwardFormularComponent } from './vorgang-forwarding-container/vorgang-forward-formular/vorgang-forward-formular.component'; import { VorgangForwardingContainerComponent } from './vorgang-forwarding-container/vorgang-forwarding-container.component'; @@ -35,7 +42,20 @@ import { VorgangForwardingInfoComponent } from './vorgang-forwarding-container/v import { VorgangForwardZustellenContainerComponent } from './vorgang-forwarding-zustellen-container/vorgang-forward-zustellen-container.component'; @NgModule({ - imports: [CommonModule, TechSharedModule, ForwardingSharedModule, CommandSharedModule, UiModule], + imports: [ + CommonModule, + ForwardingSharedModule, + CommandSharedModule, + OzgcloudTextEditorComponent, + OzgcloudStrokedButtonWithSpinnerComponent, + SpinnerComponent, + FormatDateWithTimePipe, + MatIcon, + HasLinkPipe, + ToEmbeddedResourcesPipe, + ExpansionPanelComponent, + ReactiveFormsModule, + ], declarations: [ VorgangForwardZustellenContainerComponent, VorgangForwardingContainerComponent, diff --git a/alfa-client/libs/forwarding/src/lib/vorgang-forwarding-container/vorgang-forward-formular/vorgang-forward-form/vorgang-forward-form.component.spec.ts b/alfa-client/libs/forwarding/src/lib/vorgang-forwarding-container/vorgang-forward-formular/vorgang-forward-form/vorgang-forward-form.component.spec.ts index 19d141bc8d2ff6553331a408380f77d29ee028cd..d4de767de8c460d74794b21ec61a5152ee38d2c6 100644 --- a/alfa-client/libs/forwarding/src/lib/vorgang-forwarding-container/vorgang-forward-formular/vorgang-forward-form/vorgang-forward-form.component.spec.ts +++ b/alfa-client/libs/forwarding/src/lib/vorgang-forwarding-container/vorgang-forward-formular/vorgang-forward-form/vorgang-forward-form.component.spec.ts @@ -21,15 +21,15 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { mock } from '@alfa-client/test-utils'; +import { OzgcloudStrokedButtonWithSpinnerComponent, OzgcloudTextEditorComponent } from '@alfa-client/ui'; +import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIcon } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { mock } from '@alfa-client/test-utils'; -import { OzgcloudStrokedButtonWithSpinnerComponent, TextEditorComponent } from '@alfa-client/ui'; -import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; import { MockComponent } from 'ng-mocks'; import { VorgangForwardFormComponent } from './vorgang-forward-form.component'; @@ -54,7 +54,7 @@ describe('VorgangForwardFormComponent', () => { VorgangForwardFormComponent, MatIcon, MockComponent(OzgcloudStrokedButtonWithSpinnerComponent), - MockComponent(TextEditorComponent), + MockComponent(OzgcloudTextEditorComponent), ], imports: [MatFormFieldModule, MatInputModule, ReactiveFormsModule, BrowserAnimationsModule], providers: [ @@ -112,10 +112,7 @@ describe('VorgangForwardFormComponent', () => { component.patchEmail(); - expect(formService.patchField).toHaveBeenCalledWith( - 'email', - vorgangWithEingang.eingang.zustaendigeStelle.email, - ); + expect(formService.patchField).toHaveBeenCalledWith('email', vorgangWithEingang.eingang.zustaendigeStelle.email); }); }); }); diff --git a/alfa-client/libs/hint-shared/src/lib/hint-shared.module.ts b/alfa-client/libs/hint-shared/src/lib/hint-shared.module.ts index e0304dd1d6259a58a58fa0f66405cb22c7c64ba8..482c311a15767e88f3c95d8db8d7f8c2523611c9 100644 --- a/alfa-client/libs/hint-shared/src/lib/hint-shared.module.ts +++ b/alfa-client/libs/hint-shared/src/lib/hint-shared.module.ts @@ -21,10 +21,9 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { ApiRootModule } from '@alfa-client/api-root-shared'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { ApiRootModule } from '@alfa-client/api-root-shared'; -import { TechSharedModule } from '@alfa-client/tech-shared'; import { EffectsModule } from '@ngrx/effects'; import { StoreModule } from '@ngrx/store'; import { HintEffects } from './+state/hint.effects'; @@ -38,7 +37,6 @@ import { HintService } from './hint.service'; CommonModule, StoreModule.forFeature(HINT_FEATURE_KEY, reducer), EffectsModule.forFeature([HintEffects]), - TechSharedModule, ApiRootModule, ], providers: [HintService, HintFacade, HintRepository], diff --git a/alfa-client/libs/hint/src/lib/hint.module.ts b/alfa-client/libs/hint/src/lib/hint.module.ts index 37fa3fb082fb9ee488c5ee44648ac4cda32f3d93..d72695756dffe723cb6532ff1a558ce17477e2ef 100644 --- a/alfa-client/libs/hint/src/lib/hint.module.ts +++ b/alfa-client/libs/hint/src/lib/hint.module.ts @@ -21,16 +21,15 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; import { ApiRootModule } from '@alfa-client/api-root-shared'; import { HintSharedModule } from '@alfa-client/hint-shared'; -import { TechSharedModule } from '@alfa-client/tech-shared'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { HintContainerComponent } from './hint-container/hint-container.component'; import { UserNoOrganisationsEinheitIdHintComponent } from './hint-container/user-no-organisations-einheit-id-hint/user-no-organisations-einheit-id-hint.component'; @NgModule({ - imports: [CommonModule, TechSharedModule, ApiRootModule, HintSharedModule], + imports: [CommonModule, ApiRootModule, HintSharedModule], declarations: [UserNoOrganisationsEinheitIdHintComponent, HintContainerComponent], exports: [HintContainerComponent], }) diff --git a/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-bescheid/historie-item-bescheid-status/historie-item-bescheid-status.component.spec.ts b/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-bescheid/historie-item-bescheid-status/historie-item-bescheid-status.component.spec.ts index a47331f8708e9ef6f86be744fe00a40eb307d539..cea37b23a9a580a7daf7f10cadda775444d6cebe 100644 --- a/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-bescheid/historie-item-bescheid-status/historie-item-bescheid-status.component.spec.ts +++ b/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-bescheid/historie-item-bescheid-status/historie-item-bescheid-status.component.spec.ts @@ -42,7 +42,8 @@ describe('HistorieItemBescheidStatusComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [HistorieItemBescheidStatusComponent, ConvertToBooleanPipe, FormatFullDatePipe], + imports: [ConvertToBooleanPipe, FormatFullDatePipe], + declarations: [HistorieItemBescheidStatusComponent], }).compileComponents(); fixture = TestBed.createComponent(HistorieItemBescheidStatusComponent); diff --git a/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-vorgang-created/historie-item-vorgang-created.component.spec.ts b/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-vorgang-created/historie-item-vorgang-created.component.spec.ts index 97a69102871a05a4114818db1c0b44bdfb113c79..1fb501bf07dfb0fbf0c966f35582ac9894178582 100644 --- a/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-vorgang-created/historie-item-vorgang-created.component.spec.ts +++ b/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-vorgang-created/historie-item-vorgang-created.component.spec.ts @@ -21,12 +21,12 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { registerLocaleData } from '@angular/common'; -import localeDe from '@angular/common/locales/de'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormatDateWithTimePipe } from '@alfa-client/tech-shared'; import { getElementFromFixture } from '@alfa-client/test-utils'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { registerLocaleData } from '@angular/common'; +import localeDe from '@angular/common/locales/de'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; import { HistorieItemVorgangCreatedComponent } from './historie-item-vorgang-created.component'; @@ -43,7 +43,8 @@ describe('HistorieItemVorgangCreatedComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [FormatDateWithTimePipe, HistorieItemVorgangCreatedComponent], + imports: [FormatDateWithTimePipe], + declarations: [HistorieItemVorgangCreatedComponent], }).compileComponents(); }); diff --git a/alfa-client/libs/historie/src/lib/historie.module.ts b/alfa-client/libs/historie/src/lib/historie.module.ts index 7c064391c2e621a96da017383c07edb67ec65f7e..c9675a36427c958658176eac4776cbc1fdf23c9d 100644 --- a/alfa-client/libs/historie/src/lib/historie.module.ts +++ b/alfa-client/libs/historie/src/lib/historie.module.ts @@ -23,11 +23,20 @@ */ import { CommandSharedModule } from '@alfa-client/command-shared'; import { HistorieSharedModule } from '@alfa-client/historie-shared'; -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { + ConvertToBooleanPipe, + FormatDateWithTimePipe, + FormatToPrettyDatePipe, + HasLinkPipe, + ToEmbeddedResourcesPipe, +} from '@alfa-client/tech-shared'; +import { AccordionComponent, AppIconComponent, SpinnerComponent } from '@alfa-client/ui'; import { UserProfileModule } from '@alfa-client/user-profile'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { MatExpansionPanel, MatExpansionPanelTitle } from '@angular/material/expansion'; +import { MatIcon } from '@angular/material/icon'; +import { FormatFullDatePipe } from '../../../tech-shared/src/lib/pipe/format-full-date.pipe'; import { HistorieContainerComponent } from './historie-container/historie-container.component'; import { ExpansionPanelWithUserComponent } from './historie-container/historie-list/expansion-panel-with-user/expansion-panel-with-user.component'; import { HistorieItemAktenzeichenComponent } from './historie-container/historie-list/historie-item-aktenzeichen/historie-item-aktenzeichen.component'; @@ -52,11 +61,21 @@ import { HistorieListComponent } from './historie-container/historie-list/histor @NgModule({ imports: [ CommonModule, - TechSharedModule, HistorieSharedModule, UserProfileModule, - UiModule, CommandSharedModule, + MatExpansionPanel, + MatExpansionPanelTitle, + MatIcon, + ConvertToBooleanPipe, + FormatFullDatePipe, + HasLinkPipe, + AppIconComponent, + FormatDateWithTimePipe, + FormatToPrettyDatePipe, + SpinnerComponent, + AccordionComponent, + ToEmbeddedResourcesPipe, ], declarations: [ HistorieContainerComponent, diff --git a/alfa-client/libs/kommentar-shared/src/lib/kommentar-shared.module.ts b/alfa-client/libs/kommentar-shared/src/lib/kommentar-shared.module.ts index f87a70b3cbc9d588e2f2ea0b002d0590724279ef..de0954a3f8febb42069459356746526f8a9bc977 100644 --- a/alfa-client/libs/kommentar-shared/src/lib/kommentar-shared.module.ts +++ b/alfa-client/libs/kommentar-shared/src/lib/kommentar-shared.module.ts @@ -21,12 +21,11 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { VorgangSharedModule } from '@alfa-client/vorgang-shared'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { VorgangSharedModule } from '@alfa-client/vorgang-shared'; @NgModule({ - imports: [CommonModule, TechSharedModule, VorgangSharedModule], + imports: [CommonModule, VorgangSharedModule], }) export class KommentarSharedModule {} diff --git a/alfa-client/libs/kommentar/src/lib/kommentar.module.ts b/alfa-client/libs/kommentar/src/lib/kommentar.module.ts index 978a2bf16d4cdd9e1c53149ffc1aefefab5e8cdb..4c9da054bee43f9411bd2e93ce3c4242246bf3aa 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar.module.ts +++ b/alfa-client/libs/kommentar/src/lib/kommentar.module.ts @@ -21,14 +21,15 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; import { BinaryFileModule } from '@alfa-client/binary-file'; import { KommentarSharedModule } from '@alfa-client/kommentar-shared'; -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { ConvertForDataTestPipe, FormatDateWithTimePipe, HasLinkPipe } from '@alfa-client/tech-shared'; +import { ExpansionPanelComponent, OzgcloudStrokedButtonWithSpinnerComponent, TextAreaEditorComponent } from '@alfa-client/ui'; import { UserProfileModule } from '@alfa-client/user-profile'; import { VorgangSharedModule } from '@alfa-client/vorgang-shared'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; import { KommentarFormComponent } from './kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component'; import { KommentarListInVorgangContainerComponent } from './kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component'; import { KommentarListInVorgangComponent } from './kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component'; @@ -38,11 +39,16 @@ import { KommentarListItemInVorgangComponent } from './kommentar-list-in-vorgang imports: [ CommonModule, VorgangSharedModule, - UiModule, KommentarSharedModule, - TechSharedModule, UserProfileModule, BinaryFileModule, + ReactiveFormsModule, + TextAreaEditorComponent, + OzgcloudStrokedButtonWithSpinnerComponent, + ConvertForDataTestPipe, + HasLinkPipe, + FormatDateWithTimePipe, + ExpansionPanelComponent, ], declarations: [ KommentarListInVorgangContainerComponent, diff --git a/alfa-client/libs/loesch-anforderung/src/lib/loesch-anforderung.module.ts b/alfa-client/libs/loesch-anforderung/src/lib/loesch-anforderung.module.ts index 4841c7b2b27decf170b93076d58369f9aa9d4a58..ff527cfc478f145690f5a846abb7fbfb1bff33ec 100644 --- a/alfa-client/libs/loesch-anforderung/src/lib/loesch-anforderung.module.ts +++ b/alfa-client/libs/loesch-anforderung/src/lib/loesch-anforderung.module.ts @@ -22,8 +22,8 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { LoeschAnforderungSharedModule } from '@alfa-client/loesch-anforderung-shared'; -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; +import { IconButtonWithSpinnerComponent, OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; import { VorgangSharedModule } from '@alfa-client/vorgang-shared'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; @@ -45,9 +45,10 @@ import { LoeschenAnfordernButtonComponent } from './loeschen-anfordern-button-co imports: [ CommonModule, LoeschAnforderungSharedModule, - TechSharedModule, - UiModule, VorgangSharedModule, + OzgcloudStrokedButtonWithSpinnerComponent, + IconButtonWithSpinnerComponent, + HasLinkPipe, RequestVorgangDeletionIconComponent, ButtonWithSpinnerComponent, DeleteVorgangFinallyIconComponent, diff --git a/alfa-client/libs/navigation-shared/src/lib/navigation-shared.module.ts b/alfa-client/libs/navigation-shared/src/lib/navigation-shared.module.ts index b596ca2b99d19f47cd1e08dfdffbf0c9307b2130..16fde28370c70d812f2e55f778b474ac5afc834e 100644 --- a/alfa-client/libs/navigation-shared/src/lib/navigation-shared.module.ts +++ b/alfa-client/libs/navigation-shared/src/lib/navigation-shared.module.ts @@ -23,7 +23,6 @@ */ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { TechSharedModule } from '@alfa-client/tech-shared'; import { EffectsModule } from '@ngrx/effects'; import { StoreModule } from '@ngrx/store'; import { NavigationEffects } from './+state/navigation.effects'; @@ -36,7 +35,6 @@ import { NavigationService } from './navigation.service'; CommonModule, StoreModule.forFeature(fromNavigation.NAVIGATION_FEATURE_KEY, fromNavigation.reducer), EffectsModule.forFeature([NavigationEffects]), - TechSharedModule, ], providers: [NavigationFacade, NavigationService], }) diff --git a/alfa-client/libs/navigation/src/lib/header-container/header/header.component.spec.ts b/alfa-client/libs/navigation/src/lib/header-container/header/header.component.spec.ts index 34bfb94cc20aad98d03a09e66c82578fb694ea97..3566cb04a61f9fac5fbfb37af6fa8e8faefc19bf 100644 --- a/alfa-client/libs/navigation/src/lib/header-container/header/header.component.spec.ts +++ b/alfa-client/libs/navigation/src/lib/header-container/header/header.component.spec.ts @@ -22,7 +22,6 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { AccessibilityButtonComponent } from '@alfa-client/common'; -import { UiModule } from '@alfa-client/ui'; import { HelpMenuComponent } from '@alfa-client/user-assistance'; import { UserProfileInHeaderContainerComponent } from '@alfa-client/user-profile'; import { UserSettingsContainerComponent } from '@alfa-client/user-settings'; @@ -38,7 +37,6 @@ describe('HeaderComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [UiModule], declarations: [ HeaderComponent, MockComponent(HeaderLogoComponent), diff --git a/alfa-client/libs/navigation/src/lib/navigation.module.spec.ts b/alfa-client/libs/navigation/src/lib/navigation.module.spec.ts index 8cb65e6da40705f8e87e00a461202ff56ce23fb7..a4f111d64e4aef9ee2f22a302917397ce923cbd5 100644 --- a/alfa-client/libs/navigation/src/lib/navigation.module.spec.ts +++ b/alfa-client/libs/navigation/src/lib/navigation.module.spec.ts @@ -24,7 +24,7 @@ import { TestBed } from '@angular/core/testing'; import { NavigationModule } from './navigation.module'; -describe('UiModule', () => { +describe('NavigationModule', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [NavigationModule], diff --git a/alfa-client/libs/navigation/src/lib/navigation.module.ts b/alfa-client/libs/navigation/src/lib/navigation.module.ts index 67cd2f216c40a0e850204b31089771c3912fffda..37ee7178625f6fbd7ffb92228dfb25f04cffacd7 100644 --- a/alfa-client/libs/navigation/src/lib/navigation.module.ts +++ b/alfa-client/libs/navigation/src/lib/navigation.module.ts @@ -22,7 +22,6 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { AccessibilityButtonComponent } from '@alfa-client/common'; -import { UiModule } from '@alfa-client/ui'; import { UserAssistanceModule } from '@alfa-client/user-assistance'; import { UserProfileModule } from '@alfa-client/user-profile'; import { UserSettingsModule } from '@alfa-client/user-settings'; @@ -38,7 +37,6 @@ import { HeaderComponent } from './header-container/header/header.component'; declarations: [HeaderComponent, HeaderContainerComponent, HeaderLogoComponent], imports: [ CommonModule, - UiModule, RouterModule, VorgangSharedUiModule, UserProfileModule, diff --git a/alfa-client/libs/organisations-einheit/src/lib/organisations-einheit-list-item-container/organisations-einheit-list-item/organisations-einheit-list-item.component.ts b/alfa-client/libs/organisations-einheit/src/lib/organisations-einheit-list-item-container/organisations-einheit-list-item/organisations-einheit-list-item.component.ts index f4fc21b66bd7915eeb58bcc6537f4c644a78a509..05558ae4b77e69cb7b278d5862fa0662c4823a93 100644 --- a/alfa-client/libs/organisations-einheit/src/lib/organisations-einheit-list-item-container/organisations-einheit-list-item/organisations-einheit-list-item.component.ts +++ b/alfa-client/libs/organisations-einheit/src/lib/organisations-einheit-list-item-container/organisations-einheit-list-item/organisations-einheit-list-item.component.ts @@ -22,7 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { StateResource } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { SpinnerComponent } from '@alfa-client/ui'; import { OrganisationsEinheitResource } from '@alfa-client/zustaendige-stelle-shared'; import { Component, Input } from '@angular/core'; import { ExternalUnitIconComponent, PublicAdministrationIconComponent } from '@ods/system'; @@ -30,7 +30,7 @@ import { ExternalUnitIconComponent, PublicAdministrationIconComponent } from '@o @Component({ selector: 'alfa-organisations-einheit-list-item', standalone: true, - imports: [ExternalUnitIconComponent, PublicAdministrationIconComponent, UiModule], + imports: [ExternalUnitIconComponent, PublicAdministrationIconComponent, SpinnerComponent], templateUrl: './organisations-einheit-list-item.component.html', }) export class OrganisationsEinheitListItemComponent { diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.spec.ts index c3fd2f97ae173d6ef591e90cc8c3eedc2194bf8f..5b5beec8bf365ee4a043970eb471f592faeb4ed7 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.spec.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.spec.ts @@ -29,9 +29,9 @@ import { FileUploadComponent, IconButtonWithSpinnerComponent, OzgcloudStrokedButtonWithSpinnerComponent, + OzgcloudTextEditorComponent, SpinnerComponent, TextAreaEditorComponent, - TextEditorComponent, } from '@alfa-client/ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; @@ -58,10 +58,7 @@ describe('PostfachMailFormComponent', () => { ...mock(PostfachService), getSettings: jest.fn().mockReturnValue(of(createPostfachSettings())), }; - const formService: PostfachMailFormservice = new PostfachMailFormservice( - new FormBuilder(), - useFromMock(postfachService), - ); + const formService: PostfachMailFormservice = new PostfachMailFormservice(new FormBuilder(), useFromMock(postfachService)); const dialogService: Mock<DialogService> = mock(DialogService); beforeEach(async () => { @@ -69,7 +66,7 @@ describe('PostfachMailFormComponent', () => { declarations: [ PostfachMailFormComponent, MockComponent(TextAreaEditorComponent), - MockComponent(TextEditorComponent), + MockComponent(OzgcloudTextEditorComponent), MockComponent(IconButtonWithSpinnerComponent), MockComponent(OzgcloudStrokedButtonWithSpinnerComponent), MockComponent(PostfachNachrichtReplyEditorContainerComponent), diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-date/postfach-mail-date.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-date/postfach-mail-date.component.spec.ts index 5a488822426b781de116fa4204e9133a6c3d3565..ca8fd42b29448ed3b4e56f55c00eca3f50d758a5 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-date/postfach-mail-date.component.spec.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-date/postfach-mail-date.component.spec.ts @@ -21,12 +21,12 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { registerLocaleData } from '@angular/common'; -import localeDe from '@angular/common/locales/de'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Direction } from '@alfa-client/postfach-shared'; import { FormatDateWithTimePipe, HasLinkPipe } from '@alfa-client/tech-shared'; import { getElementFromFixture } from '@alfa-client/test-utils'; +import { registerLocaleData } from '@angular/common'; +import localeDe from '@angular/common/locales/de'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { createPostfachMailResource } from 'libs/postfach-shared/test/postfach'; import { PostfachMailDateComponent } from './postfach-mail-date.component'; @@ -41,7 +41,8 @@ describe('PostfachMailDateComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [PostfachMailDateComponent, HasLinkPipe, FormatDateWithTimePipe], + imports: [HasLinkPipe, FormatDateWithTimePipe], + declarations: [PostfachMailDateComponent], }).compileComponents(); }); diff --git a/alfa-client/libs/postfach/src/lib/postfach.module.ts b/alfa-client/libs/postfach/src/lib/postfach.module.ts index e206c35d6c8efaad6336bf8f3740e1f075f5ada7..2a6fe82af2922461a8ed345f322b54e754f2ccec 100644 --- a/alfa-client/libs/postfach/src/lib/postfach.module.ts +++ b/alfa-client/libs/postfach/src/lib/postfach.module.ts @@ -23,11 +23,24 @@ */ import { BinaryFileModule } from '@alfa-client/binary-file'; import { ON_PAGE, PostfachSharedModule } from '@alfa-client/postfach-shared'; -import { UiModule } from '@alfa-client/ui'; +import { ConvertForDataTestPipe, FormatDateWithTimePipe, HasLinkPipe, ToEmbeddedResourcesPipe } from '@alfa-client/tech-shared'; +import { + BackButtonComponent, + CheckboxEnumEditorComponent, + IconButtonWithSpinnerComponent, + OzgcloudIconComponent, + OzgcloudStrokedButtonWithSpinnerComponent, + OzgcloudTextEditorComponent, + SpinnerComponent, + SubnavigationComponent, + TextAreaEditorComponent, +} from '@alfa-client/ui'; import { UserProfileModule } from '@alfa-client/user-profile'; import { VorgangSharedUiModule } from '@alfa-client/vorgang-shared-ui'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatIcon } from '@angular/material/icon'; import { RouterModule, Routes } from '@angular/router'; import { ButtonComponent, MailboxIconComponent, PlusIconComponent, TooltipDirective } from '@ods/system'; import { PostfachMailButtonContainerComponent } from './postfach-mail-button-container/postfach-mail-button-container.component'; @@ -63,11 +76,25 @@ const routes: Routes = [ imports: [ CommonModule, RouterModule.forChild(routes), - UiModule, PostfachSharedModule, UserProfileModule, VorgangSharedUiModule, BinaryFileModule, + OzgcloudStrokedButtonWithSpinnerComponent, + HasLinkPipe, + CheckboxEnumEditorComponent, + ReactiveFormsModule, + OzgcloudTextEditorComponent, + TextAreaEditorComponent, + MatIcon, + OzgcloudIconComponent, + FormatDateWithTimePipe, + SpinnerComponent, + ToEmbeddedResourcesPipe, + ConvertForDataTestPipe, + SubnavigationComponent, + BackButtonComponent, + IconButtonWithSpinnerComponent, ButtonComponent, PlusIconComponent, MailboxIconComponent, diff --git a/alfa-client/libs/resource-redirect-shared/src/lib/resource-redirect-shared.module.ts b/alfa-client/libs/resource-redirect-shared/src/lib/resource-redirect-shared.module.ts index c595c6eed1d99ffe27153f717583e2f99b8f4248..33ef83703dab9eb294a07b39e499349780932399 100644 --- a/alfa-client/libs/resource-redirect-shared/src/lib/resource-redirect-shared.module.ts +++ b/alfa-client/libs/resource-redirect-shared/src/lib/resource-redirect-shared.module.ts @@ -21,10 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule } from '@alfa-client/tech-shared'; import { NgModule } from '@angular/core'; -@NgModule({ - imports: [TechSharedModule], -}) +@NgModule({}) export class ResourceRedirectSharedModule {} diff --git a/alfa-client/libs/tech-shared/src/index.ts b/alfa-client/libs/tech-shared/src/index.ts index f2c01ec546c183620b05b39ad37f6af73368cddd..6fbc4e5294b1490dd9924a225715b0007c0ba80f 100644 --- a/alfa-client/libs/tech-shared/src/index.ts +++ b/alfa-client/libs/tech-shared/src/index.ts @@ -29,6 +29,7 @@ export * from './lib/error/error.handler'; export * from './lib/error/error.util'; export * from './lib/form.util'; export * from './lib/http.util'; +export * from './lib/injector/injector.service'; export * from './lib/keyboard.util'; export * from './lib/message-code'; export * from './lib/ngrx/actions'; @@ -57,7 +58,6 @@ export * from './lib/resource/resource.rxjs.operator'; export * from './lib/resource/resource.service'; export * from './lib/resource/resource.util'; export * from './lib/service/formservice.abstract'; -export * from './lib/tech-shared.module'; export * from './lib/tech.model'; export * from './lib/tech.util'; export * from './lib/validation/tech.validation.util'; diff --git a/alfa-client/libs/tech-shared/src/lib/decorator/error.decorator.util.ts b/alfa-client/libs/tech-shared/src/lib/decorator/error.decorator.util.ts index 669b6872398a4d9a3539741ec84fad461375f445..f02936d4fbd11d5a37b30d5e1864323bc0fa9cb1 100644 --- a/alfa-client/libs/tech-shared/src/lib/decorator/error.decorator.util.ts +++ b/alfa-client/libs/tech-shared/src/lib/decorator/error.decorator.util.ts @@ -22,10 +22,10 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { HttpErrorHandler } from '../error/error.handler'; -import { TechSharedModule } from '../tech-shared.module'; +import { InjectorService } from '../injector/injector.service'; export function injectHttpErrorHandler(): HttpErrorHandler { - return TechSharedModule.injector.get(HttpErrorHandler); + return InjectorService.getInjector().get(HttpErrorHandler); } export function enableInterceptorDefaultHandling(httpErrorHandler: HttpErrorHandler): void { diff --git a/alfa-client/libs/tech-shared/src/lib/injector/injector.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/injector/injector.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..1833f3fd12e12fa277a131186d3a27623a3c2251 --- /dev/null +++ b/alfa-client/libs/tech-shared/src/lib/injector/injector.service.spec.ts @@ -0,0 +1,30 @@ +import { Injector } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { InjectorService } from './injector.service'; + +describe('InjectorService', () => { + let injector: Injector; + let injectorService: InjectorService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [InjectorService, { provide: Injector, useValue: {} }], + }); + injector = TestBed.inject(Injector); + injectorService = TestBed.inject(InjectorService); + }); + + it('should be created', () => { + expect(injectorService).toBeTruthy(); + }); + + it('should set and get the injector', () => { + expect(InjectorService.getInjector()).toBe(injector); + }); + + describe('getInjector', () => { + it('should return the injector', () => { + expect(InjectorService.getInjector()).toBe(injector); + }); + }); +}); diff --git a/alfa-client/libs/tech-shared/src/lib/injector/injector.service.ts b/alfa-client/libs/tech-shared/src/lib/injector/injector.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..eb2ad9d101376adff380bc8930f5e0274503ddbb --- /dev/null +++ b/alfa-client/libs/tech-shared/src/lib/injector/injector.service.ts @@ -0,0 +1,16 @@ +import { Injectable, Injector } from '@angular/core'; + +@Injectable({ + providedIn: 'root', +}) +export class InjectorService { + private static injector: Injector; + + constructor(injector: Injector) { + InjectorService.injector = injector; + } + + public static getInjector(): Injector { + return InjectorService.injector; + } +} diff --git a/alfa-client/libs/tech-shared/src/lib/keyboard.util.spec.ts b/alfa-client/libs/tech-shared/src/lib/keyboard.util.spec.ts index 10b46493b6c1d89755bddaefb378a4691ac82cae..92ba5f3e69a27a05a50ee8fbdf1ec33f70b776cf 100644 --- a/alfa-client/libs/tech-shared/src/lib/keyboard.util.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/keyboard.util.spec.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { createKeydownKeyboardEvent } from '../../../test-utils/src/lib/keyboard'; +import { createKeydownKeyboardEvent } from 'libs/test-utils/src/lib/keyboard'; import { ARROW_DOWN_KEY, ARROW_UP_KEY, diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/convert-api-error-to-error-messages.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/convert-api-error-to-error-messages.pipe.ts index 20392c34d74bdcd980c5f3ba961f6f4be8484dae..e57e531260cb15aa718a6193fd624b5fc277c917 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/convert-api-error-to-error-messages.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/convert-api-error-to-error-messages.pipe.ts @@ -25,7 +25,10 @@ import { ApiError, EMPTY_STRING, getMessageForIssue, Issue } from '@alfa-client/ import { Pipe, PipeTransform } from '@angular/core'; import { isNil } from 'lodash-es'; -@Pipe({ name: 'convertApiErrorToErrorMessages' }) +@Pipe({ + name: 'convertApiErrorToErrorMessages', + standalone: true, +}) export class ConvertApiErrorToErrorMessagesPipe implements PipeTransform { transform(value: ApiError) { if (isNil(value)) { diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/convert-for-data-test.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/convert-for-data-test.pipe.ts index b1873901646b2c270a3e353158821aed99a19059..dd6bb93c51596fd3d4e6f40973e1050c94f83330 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/convert-for-data-test.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/convert-for-data-test.pipe.ts @@ -25,7 +25,10 @@ import { Pipe, PipeTransform } from '@angular/core'; import { isNil } from 'lodash-es'; import { convertForDataTest } from '../tech.util'; -@Pipe({ name: 'convertForDataTest' }) +@Pipe({ + name: 'convertForDataTest', + standalone: true, +}) export class ConvertForDataTestPipe implements PipeTransform { transform(value: string): string { return isNil(value) ? null : convertForDataTest(value); diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.ts index 24f50446e27078791793cb671bee05d3cef19868..7ce05836fe5a7e410c9467cc4a676c7fa13c9338 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.ts @@ -27,14 +27,15 @@ import { InvalidParam, ProblemDetail } from '../tech.model'; import { EMPTY_STRING } from '../tech.util'; import { getMessageForInvalidParam } from '../validation/tech.validation.util'; -@Pipe({ name: 'convertProblemDetailToErrorMessages' }) +@Pipe({ + name: 'convertProblemDetailToErrorMessages', + standalone: true, +}) export class ConvertProblemDetailToErrorMessagesPipe implements PipeTransform { transform(value: ProblemDetail) { if (isNil(value)) { return []; } - return value.invalidParams.map((invalidParam: InvalidParam) => - getMessageForInvalidParam(EMPTY_STRING, invalidParam), - ); + return value.invalidParams.map((invalidParam: InvalidParam) => getMessageForInvalidParam(EMPTY_STRING, invalidParam)); } } diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/convert-to-boolean.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/convert-to-boolean.pipe.ts index daac6384c220168403ffc3fdb50395bbee2dc4e1..ad5da3e0789786d617ee3e61d7ac56c075c43cae 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/convert-to-boolean.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/convert-to-boolean.pipe.ts @@ -24,7 +24,10 @@ import { Pipe, PipeTransform } from '@angular/core'; import { convertToBoolean } from '../tech.util'; -@Pipe({ name: 'convertToBoolean' }) +@Pipe({ + name: 'convertToBoolean', + standalone: true, +}) export class ConvertToBooleanPipe implements PipeTransform { public transform(booleanStr: string): boolean { return convertToBoolean(booleanStr); diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/enum-to-label.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/enum-to-label.pipe.ts index 194e92483d10610441c53b3924f84e0d550cf307..38033a71822e29d42e25b491e28b5dd956d062e8 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/enum-to-label.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/enum-to-label.pipe.ts @@ -24,7 +24,10 @@ import { Pipe, PipeTransform } from '@angular/core'; import { isNil } from 'lodash-es'; -@Pipe({ name: 'enumToLabel' }) +@Pipe({ + name: 'enumToLabel', + standalone: true, +}) export class EnumToLabelPipe implements PipeTransform { transform(enumValue: any, enumLabel: any) { return isNil(enumValue) || isNil(enumLabel) ? null : enumLabel[enumValue]; diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/file-size-plain.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/file-size-plain.pipe.ts index 186326278800e742fb80e860f070d0d7c308afc9..d18d294fa363a63a4e54686a8e8370d042195304 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/file-size-plain.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/file-size-plain.pipe.ts @@ -23,7 +23,10 @@ */ import { Pipe, PipeTransform } from '@angular/core'; -@Pipe({ name: 'fileSizePlain' }) +@Pipe({ + name: 'fileSizePlain', + standalone: true, +}) export class FileSizePlainPipe implements PipeTransform { readonly kB = 1024; readonly MB = Math.pow(this.kB, 2); diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/file-size.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/file-size.pipe.ts index 327058ea9ccd0dc223546898463addb963061d7f..db4f54706322fda80474fca4e0a6876876e84d50 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/file-size.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/file-size.pipe.ts @@ -23,7 +23,10 @@ */ import { Pipe, PipeTransform } from '@angular/core'; -@Pipe({ name: 'fileSize' }) +@Pipe({ + name: 'fileSize', + standalone: true, +}) export class FileSizePipe implements PipeTransform { readonly kB = 1024; readonly MB = Math.pow(this.kB, 2); diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/format-date-with-time.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/format-date-with-time.pipe.ts index fc33dcc8a3fa493b49c8b944a23231aed86e2e21..7d95383257bd84540653acef2140d74ecac8d267 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/format-date-with-time.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/format-date-with-time.pipe.ts @@ -24,11 +24,12 @@ import { Pipe, PipeTransform } from '@angular/core'; import { formatFullDateWithTimeAndDay, formatFullDateWithTimeWithoutSeconds } from '../date.util'; -@Pipe({ name: 'formatDateWithTimePipe' }) +@Pipe({ + name: 'formatDateWithTimePipe', + standalone: true, +}) export class FormatDateWithTimePipe implements PipeTransform { transform(date: Date, withSeconds: boolean = true): string { - return withSeconds ? - formatFullDateWithTimeAndDay(date) - : formatFullDateWithTimeWithoutSeconds(date); + return withSeconds ? formatFullDateWithTimeAndDay(date) : formatFullDateWithTimeWithoutSeconds(date); } } diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/format-date-without-year-with-time.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/format-date-without-year-with-time.pipe.ts index 42694b05a7c55be2d0069129125e25d85ad2c107..f2835bd7e653ec1d7e0ebab6388e7cd1bf086c44 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/format-date-without-year-with-time.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/format-date-without-year-with-time.pipe.ts @@ -24,7 +24,10 @@ import { Pipe, PipeTransform } from '@angular/core'; import { formatDateWithoutYearWithTime } from '../date.util'; -@Pipe({ name: 'formatDateWithoutYearWithTime' }) +@Pipe({ + name: 'formatDateWithoutYearWithTime', + standalone: true, +}) export class FormatDateWithoutYearWithTimePipe implements PipeTransform { transform(date: Date): string { return formatDateWithoutYearWithTime(date); diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/format-full-date.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/format-full-date.pipe.ts index 250167b0bcf28a441ee744360e5f687676778da5..c9bec878f1e56d9fdb740cbcb1bc971d4cb4501a 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/format-full-date.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/format-full-date.pipe.ts @@ -25,7 +25,10 @@ import { Pipe, PipeTransform } from '@angular/core'; import { isString } from 'lodash-es'; import { formatFullDate } from '../date.util'; -@Pipe({ name: 'formatFullDatePipe' }) +@Pipe({ + name: 'formatFullDatePipe', + standalone: true, +}) export class FormatFullDatePipe implements PipeTransform { transform(date: Date | string): string { date = isString(date) ? new Date(date) : date; diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/format-to-pretty-date.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/format-to-pretty-date.pipe.ts index 054f4f8b9c6226fd82eacc6b4b368a8955bfdef9..0d16ccd7a7dd6cd3c9c1404070de177f621e86b9 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/format-to-pretty-date.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/format-to-pretty-date.pipe.ts @@ -24,7 +24,10 @@ import { Pipe, PipeTransform } from '@angular/core'; import { formatToPrettyDate } from '../date.util'; -@Pipe({ name: 'formatToPrettyDate' }) +@Pipe({ + name: 'formatToPrettyDate', + standalone: true, +}) export class FormatToPrettyDatePipe implements PipeTransform { transform(date: Date): string { return formatToPrettyDate(date); diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/get-url.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/get-url.pipe.ts index c41e3024cd91c233094847e8ba43771d50c965a7..d936124c617e2ad94b4c901be87a9987714fc76c 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/get-url.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/get-url.pipe.ts @@ -24,7 +24,10 @@ import { Pipe, PipeTransform } from '@angular/core'; import { Resource, ResourceUri, getUrl } from '@ngxp/rest'; -@Pipe({ name: 'getUrl' }) +@Pipe({ + name: 'getUrl', + standalone: true, +}) export class GetUrlPipe implements PipeTransform { transform(resource: Resource, link: string): ResourceUri { return getUrl(resource, link); diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/has-any-link.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/has-any-link.pipe.ts index 1bf5a803a8af9e39cce2211b854db6871ed8907d..ec9083014c9e2527df574f2367d2bfd8b4e7d6dc 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/has-any-link.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/has-any-link.pipe.ts @@ -26,7 +26,10 @@ import { Resource } from '@ngxp/rest'; import { LinkRelationName } from '../resource/resource.model'; import { hasAnyLink } from '../tech.util'; -@Pipe({ name: 'hasAnyLink' }) +@Pipe({ + name: 'hasAnyLink', + standalone: true, +}) export class HasAnyLinkPipe implements PipeTransform { transform(resource: Resource, ...links: LinkRelationName[]): boolean { return hasAnyLink(resource, ...links); diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/has-link.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/has-link.pipe.ts index d2d15cb1eaa008c7ec87667924c230c1d9546365..34abe1a2f2d071b4419c93e64cd8950d9f96a6a4 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/has-link.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/has-link.pipe.ts @@ -24,7 +24,10 @@ import { Pipe, PipeTransform } from '@angular/core'; import { Resource, hasLink } from '@ngxp/rest'; -@Pipe({ name: 'hasLink' }) +@Pipe({ + name: 'hasLink', + standalone: true, +}) export class HasLinkPipe implements PipeTransform { transform(resource: Resource, link: string): boolean { return hasLink(resource, link); diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/not-has-any-link.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/not-has-any-link.pipe.ts index 19d64e5599d3b377cb9e4bac93782ce5e1cb988b..b04c9a7b613a2e6b03f1fec4f0115f902aa2629e 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/not-has-any-link.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/not-has-any-link.pipe.ts @@ -26,7 +26,10 @@ import { Resource } from '@ngxp/rest'; import { LinkRelationName } from '../resource/resource.model'; import { notHasAnyLink } from '../tech.util'; -@Pipe({ name: 'notHasAnyLink' }) +@Pipe({ + name: 'notHasAnyLink', + standalone: true, +}) export class NotHasAnyLinkPipe implements PipeTransform { transform(resource: Resource, ...links: LinkRelationName[]): boolean { return notHasAnyLink(resource, ...links); diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/not-has-link.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/not-has-link.pipe.ts index 8c8f879b0388c490b209dfdbf1a9abe126a721bc..018d49e877e90b56dd0ad0438c86b09b186af2f8 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/not-has-link.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/not-has-link.pipe.ts @@ -24,7 +24,10 @@ import { Pipe, PipeTransform } from '@angular/core'; import { Resource, hasLink } from '@ngxp/rest'; -@Pipe({ name: 'notHasLink' }) +@Pipe({ + name: 'notHasLink', + standalone: true, +}) export class NotHasLinkPipe implements PipeTransform { transform(resource: Resource, link: string): boolean { return !hasLink(resource, link); diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts index 537bd91348a6722854d153bc7c7ceec53aff17a8..dbb7025753327feff619bd1a0559951bf8b6ebe0 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts @@ -28,7 +28,10 @@ import { LinkRelationName } from '../resource/resource.model'; import { ListResource } from '../resource/resource.util'; import { EMPTY_ARRAY } from '../tech.util'; -@Pipe({ name: 'toEmbeddedResources' }) +@Pipe({ + name: 'toEmbeddedResources', + standalone: true, +}) export class ToEmbeddedResourcesPipe implements PipeTransform { transform(listResource: ListResource, linkRel: LinkRelationName): Resource[] { if (isNil(listResource) || isNil(linkRel)) return EMPTY_ARRAY; diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/to-resource-uri.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/to-resource-uri.pipe.ts index d102cc20129903fa363c4c5b7708ee4c7cb70e6b..9ac1e3aaa42f8121843ce0effb45caa1c020edeb 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/to-resource-uri.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/to-resource-uri.pipe.ts @@ -26,7 +26,10 @@ import { Resource, ResourceUri } from '@ngxp/rest'; import { isNil } from 'lodash-es'; import { toResourceUri } from '../resource/resource.util'; -@Pipe({ name: 'toResourceUri' }) +@Pipe({ + name: 'toResourceUri', + standalone: true, +}) export class ToResourceUriPipe implements PipeTransform { transform(resource: Resource, linkRel?: string): ResourceUri { if (isNil(resource)) { diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/to-traffic-light-tooltip.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/to-traffic-light-tooltip.pipe.ts index f0e66e4fd889a11a9908cb32a760c95eb6e454e3..ab1c286a7c1e5a1a593a4c4d58f41593be42ef21 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/to-traffic-light-tooltip.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/to-traffic-light-tooltip.pipe.ts @@ -24,7 +24,10 @@ import { Pipe, PipeTransform } from '@angular/core'; import { isPast, isToday, isValid, parseISO } from 'date-fns'; -@Pipe({ name: 'toTrafficLightTooltip' }) +@Pipe({ + name: 'toTrafficLightTooltip', + standalone: true, +}) export class ToTrafficLightTooltipPipe implements PipeTransform { transform(date: Date): string { date = isValid(date) ? date : parseISO(date as unknown as string); diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/to-traffic-light.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/to-traffic-light.pipe.ts index 83f4e421d1ec0453adeb716aec47eb06689407dc..1763a26143e09e51458b019dab3a402e78ea0e3d 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/to-traffic-light.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/to-traffic-light.pipe.ts @@ -24,7 +24,10 @@ import { Pipe, PipeTransform } from '@angular/core'; import { isPast, isToday, isValid, parseISO } from 'date-fns'; -@Pipe({ name: 'toTrafficLight' }) +@Pipe({ + name: 'toTrafficLight', + standalone: true, +}) export class ToTrafficLightPipe implements PipeTransform { transform(date: Date): string { date = isValid(date) ? date : parseISO(date as unknown as string); diff --git a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts index 76fac14c0bfe11b7f9b97a634e922aad14a417ca..60c4640d92c10a70d0bec7d763d80a8f9618ff33 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts @@ -29,7 +29,7 @@ import { cold } from 'jest-marbles'; import { DummyLinkRel, DummyListLinkRel } from 'libs/tech-shared/test/dummy'; import { createDummyListResource, createDummyResource, createFilledDummyListResource } from 'libs/tech-shared/test/resource'; import { BehaviorSubject, Observable, of } from 'rxjs'; -import { singleCold, singleHot } from '../../../test/marbles'; +import { multipleCold, singleCold, singleHot } from '../../../test/marbles'; import { EMPTY_ARRAY } from '../tech.util'; import { ResourceListService } from './list-resource.service'; import { CreateResourceData, LinkRelationName, ListItemResource, ListResourceServiceConfig } from './resource.model'; @@ -84,16 +84,22 @@ describe('ListResourceService', () => { isInvalidResourceCombinationSpy = jest.spyOn(ResourceUtil, 'isInvalidResourceCombination').mockReturnValue(true); }); + it('should have debounce', () => { + service.getList().subscribe(); + + expect(service.handleChanges).not.toHaveBeenCalled(); + }); + it('should handle config resource changed', fakeAsync(() => { service.getList().subscribe(); - tick(); + tick(50); expect(service.handleChanges).toHaveBeenCalledWith(listStateResource, baseResource); })); it('should call isInvalidResourceCombinationSpy', fakeAsync(() => { service.getList().subscribe(); - tick(); + tick(50); expect(isInvalidResourceCombinationSpy).toHaveBeenCalled(); })); @@ -305,25 +311,27 @@ describe('ListResourceService', () => { describe('create', () => { const toCreate: unknown = {}; + const returnResource: Resource = createDummyResource(); beforeEach(() => { service.listResource.value.resource = listResource; + resourceRepository.createResource.mockReturnValue(of(returnResource)); }); it('should throw error if link is not present', () => { service.listResource.next(createStateResource(createDummyListResource())); - expect(() => service.create(toCreate)).toThrowError('No creation link exists.'); + expect(() => service.create(toCreate)).toThrow('No creation link exists.'); }); it('should throw error if list resource is empty', () => { service.listResource.next(createEmptyStateResource()); - expect(() => service.create(toCreate)).toThrowError('No list resource available.'); + expect(() => service.create(toCreate)).toThrow('No list resource available.'); }); it('should trigger resourceLoader', () => { - service.create(toCreate); + service.create(toCreate).subscribe(); const createResourceData: CreateResourceData<ListResource> = { resource: listResource, @@ -335,11 +343,11 @@ describe('ListResourceService', () => { it('should return value', () => { const returnResource: Resource = createDummyResource(); - resourceRepository.createResource.mockReturnValue(singleHot(returnResource)); + resourceRepository.createResource.mockReturnValue(singleCold(returnResource, '-a')); - const createdResource: Observable<Resource> = service.create(toCreate); + const createdResource: Observable<StateResource<Resource>> = service.create(toCreate); - expect(createdResource).toBeObservable(singleCold(returnResource)); + expect(createdResource).toBeObservable(multipleCold(createEmptyStateResource(true), createStateResource(returnResource))); }); }); @@ -437,7 +445,7 @@ describe('ListResourceService', () => { it('should throw error if prev link is not present', () => { service.listResource.next(createStateResource(listResource)); - expect(() => service.prev()).toThrowError('There is no previous page.'); + expect(() => service.prev()).toThrow('There is no previous page.'); }); it('should call resourceLoader with prev link', () => { @@ -465,7 +473,7 @@ describe('ListResourceService', () => { it('should throw error if next link is not present', () => { service.listResource.next(createStateResource(listResource)); - expect(() => service.next()).toThrowError('There is no next page.'); + expect(() => service.next()).toThrow('There is no next page.'); }); it('should call resourceLoader with next link', () => { diff --git a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.ts b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.ts index 50cee3aa72fb828211d7a70dadc5cdca3d5f55c2..852a8299c56d256d93bf778e9600ab0717edc00f 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.ts @@ -23,7 +23,7 @@ */ import { Resource, ResourceUri, getUrl, hasLink } from '@ngxp/rest'; import { isEqual, isNil, isNull } from 'lodash-es'; -import { BehaviorSubject, Observable, combineLatest, filter, first, map, startWith, tap } from 'rxjs'; +import { BehaviorSubject, Observable, combineLatest, debounceTime, filter, first, map, startWith, tap } from 'rxjs'; import { isNotNull, isNotUndefined } from '../tech.util'; import { CreateResourceData, ListItemResource, ListResourceServiceConfig } from './resource.model'; import { ResourceRepository } from './resource.repository'; @@ -58,11 +58,12 @@ export class ResourceListService<B extends Resource, T extends ListResource, I e constructor( private config: ListResourceServiceConfig<B>, - private repository: ResourceRepository, + private repository: ResourceRepository<I>, ) {} public getList(): Observable<StateResource<T>> { return combineLatest([this.listResource.asObservable(), this.getConfigResource()]).pipe( + debounceTime(50), tap(([stateResource, configResource]) => { this.handleChanges(stateResource, configResource); }), @@ -105,9 +106,12 @@ export class ResourceListService<B extends Resource, T extends ListResource, I e this.listResource.next(createEmptyStateResource()); } - public create(toCreate: unknown): Observable<Resource> { + public create(toCreate: unknown): Observable<StateResource<I>> { this.verifyBeforeCreation(); - return this.repository.createResource(this.buildCreateResourceData(toCreate, this.config.createLinkRel)); + return this.repository.createResource(this.buildCreateResourceData(toCreate, this.config.createLinkRel)).pipe( + map((listItemResource: I) => createStateResource(listItemResource)), + startWith(createEmptyStateResource<I>(true)), + ); } private verifyBeforeCreation(): void { diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.spec.ts index bbd264a3587623c8af04f1f293fb0c5e3c6a639c..cade44ce12d85185a6b00d1804d6bc22ba4f27e3 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.spec.ts @@ -22,6 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { mock, useFromMock } from '@alfa-client/test-utils'; +import { TestBed } from '@angular/core/testing'; import { faker } from '@faker-js/faker'; import { Resource, ResourceFactory, ResourceUri, getUrl } from '@ngxp/rest'; import { DummyLinkRel, DummyListLinkRel } from 'libs/tech-shared/test/dummy'; @@ -42,7 +43,11 @@ describe('ResourceRepository', () => { resourceFactory.from.mockReturnValue(resourceWrapper); resourceFactory.fromId.mockReturnValue(resourceWrapper); - repository = new ResourceRepository(useFromMock(resourceFactory)); + TestBed.configureTestingModule({ + providers: [{ provide: ResourceFactory, useValue: useFromMock(resourceFactory) }], + }); + + repository = TestBed.inject(ResourceRepository); }); it('should be created', () => { diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts index d8f90a78eb269f096a4f159237d07926ad130881..33d37b87af453f7fb777dd2ca69d8cf7a8f394c4 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts @@ -21,17 +21,17 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Injectable } from '@angular/core'; -import { Resource, ResourceFactory, ResourceUri, getUrl } from '@ngxp/rest'; +import { inject, Injectable } from '@angular/core'; +import { getUrl, Resource, ResourceFactory, ResourceUri } from '@ngxp/rest'; import { Observable } from 'rxjs'; import { CreateResourceData, LinkRelationName, SaveResourceData } from './resource.model'; import { ListResource } from './resource.util'; @Injectable({ providedIn: 'root' }) -export class ResourceRepository { - static SEARCH_PARAM: string = 'searchBy'; +export class ResourceRepository<T extends Resource = Resource> { + private resourceFactory = inject(ResourceFactory); - constructor(private resourceFactory: ResourceFactory) {} + static SEARCH_PARAM: string = 'searchBy'; public getListResource(resource: Resource, linkRel: string): Observable<ListResource> { const uriWithoutParameter: string = this.getUrlWithoutParameter(getUrl(resource, linkRel)); @@ -45,7 +45,7 @@ export class ResourceRepository { return uri; } - public createResource(createResourceData: CreateResourceData<Resource>): Observable<Resource> { + public createResource(createResourceData: CreateResourceData<Resource>): Observable<T> { return this.resourceFactory.from(createResourceData.resource).post(createResourceData.linkRel, createResourceData.toCreate); } diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.service.spec.ts index 7a045fa7514ae98cf24c58209a709551fb0def98..87869c5c4e0aa1dff4a3050b95ed26abd476c0d6 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource.service.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.service.spec.ts @@ -82,16 +82,22 @@ describe('ResourceService', () => { isInvalidResourceCombinationSpy = jest.spyOn(ResourceUtil, 'isInvalidResourceCombination').mockReturnValue(true); }); + it('should have debounce', () => { + service.get().subscribe(); + + expect(service.handleResourceChanges).not.toHaveBeenCalled(); + }); + it('should handle config resource changed', fakeAsync(() => { service.get().subscribe(); - tick(); + tick(50); expect(service.handleResourceChanges).toHaveBeenCalledWith(stateResource, configResource); })); it('should call isInvalidResourceCombinationSpy', fakeAsync(() => { service.get().subscribe(); - tick(); + tick(50); expect(isInvalidResourceCombinationSpy).toHaveBeenCalled(); })); @@ -497,7 +503,7 @@ describe('ResourceService', () => { const thrownError$: Observable<StateResource<unknown>> = service.handleError(error); expect.assertions(1); - expect(lastValueFrom(thrownError$)).rejects.toThrowError('Internal Server Error'); + expect(lastValueFrom(thrownError$)).rejects.toThrow('Internal Server Error'); }); }); diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.service.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.service.ts index 990005991995cce82ed108fe0c6f7cd64a1ac1c0..1953e85ff4691dec3b95771a73f1bc1c7283efd1 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource.service.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.service.ts @@ -24,7 +24,20 @@ import { HttpErrorResponse } from '@angular/common/http'; import { getUrl, hasLink, Resource, ResourceUri } from '@ngxp/rest'; import { isEqual, isNull } from 'lodash-es'; -import { BehaviorSubject, catchError, combineLatest, filter, first, map, Observable, of, startWith, tap, throwError } from 'rxjs'; +import { + BehaviorSubject, + catchError, + combineLatest, + debounceTime, + filter, + first, + map, + Observable, + of, + startWith, + tap, + throwError, +} from 'rxjs'; import { isUnprocessableEntity } from '../http.util'; import { HttpError } from '../tech.model'; import { isNotNull } from '../tech.util'; @@ -57,6 +70,7 @@ export abstract class ResourceService<B extends Resource, T extends Resource> { public get(): Observable<StateResource<T>> { return combineLatest([this.stateResource.asObservable(), this.getConfigResource()]).pipe( + debounceTime(50), tap(([stateResource, configResource]) => this.handleResourceChanges(stateResource, configResource)), filter(([stateResource]) => !isInvalidResourceCombination(stateResource, this.configResource)), mapToFirst<T, B>(), diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts index 068bdad4584c8956198ed8aa008b2b9a5516cc96..3bfc293f96169bd19c2db03eb6c3030a15d8a8f1 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts @@ -22,7 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Resource } from '@ngxp/rest'; -import { createCommandStateResource } from '../../../../command-shared/test/command'; +import { createCommandStateResource } from 'libs/command-shared/test/command'; import { DummyListLinkRel } from '../../../test/dummy'; import { createApiError } from '../../../test/error'; import { createDummyListResource, createDummyResource, toResource } from '../../../test/resource'; diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.ts index e90e4a2702d5185cde6f244b5075bfc237952026..201e8100c1682cafdeb57d86521d0b60b99a7b36 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Resource, ResourceUri, getEmbeddedResource, getUrl, hasLink } from '@ngxp/rest'; +import { getEmbeddedResource, getUrl, hasLink, Resource, ResourceUri } from '@ngxp/rest'; import { isEqual, isNil, isNull } from 'lodash-es'; import { HttpError } from '../tech.model'; import { encodeUrlForEmbedding, isNotNull } from '../tech.util'; @@ -42,6 +42,10 @@ export function createEmptyStateResource<T>(loading: boolean = false): StateReso return createStateResource(null, loading); } +export function createLoadingStateResource<T>(): StateResource<T> { + return createEmptyStateResource(true); +} + export function createStateResource<T>(resource: T, loading: boolean = false): StateResource<T> { return { loading, loaded: !isNil(resource), reload: false, resource }; } @@ -50,10 +54,7 @@ export function createErrorStateResource<T>(error: HttpError): StateResource<any return { ...createEmptyStateResource<T>(), error, loaded: true }; } -export function doIfLoadingRequired( - stateResource: StateResource<any>, - runable: () => void, -): boolean { +export function doIfLoadingRequired(stateResource: StateResource<any>, runable: () => void): boolean { if (isLoadingRequired(stateResource)) { runable(); return true; @@ -82,10 +83,7 @@ export function toResourceUri(resource: Resource, linkRel?: string): string { return encodeUrlForEmbedding(url); } -export function doOnValidStateResource( - stateResource: StateResource<Resource>, - actionOnValid: () => void, -): void { +export function doOnValidStateResource(stateResource: StateResource<Resource>, actionOnValid: () => void): void { if (isValidStateResource(stateResource)) actionOnValid(); } @@ -93,10 +91,7 @@ export function isValidStateResource(stateResource: StateResource<unknown>): boo return stateResource.loaded && isNotNull(stateResource.resource); } -export function getEmbeddedResources<T>( - stateResource: StateResource<Resource>, - linkRel: string, -): T[] { +export function getEmbeddedResources<T>(stateResource: StateResource<Resource>, linkRel: string): T[] { if (isNil(stateResource) || isNil(stateResource.resource)) { return []; } @@ -115,12 +110,8 @@ export function containsLoading(stateResources: StateResource<Resource>[]): bool return stateResources.findIndex((stateResources) => stateResources.loading) > -1; } -export function getSuccessfullyLoaded<T extends Resource>( - stateResources: StateResource<T>[], -): StateResource<T>[] { - return stateResources.filter( - (stateResource) => isLoaded(stateResource) && !hasStateResourceError(stateResource), - ); +export function getSuccessfullyLoaded<T extends Resource>(stateResources: StateResource<T>[]): StateResource<T>[] { + return stateResources.filter((stateResource) => isLoaded(stateResource) && !hasStateResourceError(stateResource)); } export function isEmptyStateResource<T extends Resource>(stateResource: StateResource<T>): boolean { @@ -135,8 +126,7 @@ export function isInvalidResourceCombination<T extends Resource, B extends Resou return ( stateResource.reload || (!stateResource.loading && - ((!stateResource.loaded && isNotNull(baseResource)) || - (stateResource.loaded && isNull(baseResource)))) + ((!stateResource.loaded && isNotNull(baseResource)) || (stateResource.loaded && isNull(baseResource)))) ); } diff --git a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.spec.ts b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.spec.ts index 47119c7a1b2aba5e369af100593d58569dee002a..05e53e161df3758106375d53082cbf77dcd697e2 100644 --- a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.spec.ts @@ -25,9 +25,9 @@ import { CommandResource } from '@alfa-client/command-shared'; import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { Resource } from '@ngxp/rest'; import { cold } from 'jest-marbles'; +import { createCommandResource } from 'libs/command-shared/test/command'; import { createInvalidParam, createProblemDetail } from 'libs/tech-shared/test/error'; import { Observable, of } from 'rxjs'; -import { createCommandResource } from '../../../../command-shared/test/command'; import { StateResource, createEmptyStateResource, diff --git a/alfa-client/libs/tech-shared/src/lib/tech-shared.module.spec.ts b/alfa-client/libs/tech-shared/src/lib/tech-shared.module.spec.ts deleted file mode 100644 index 740aaee232ce8c6bcebc45bf4b5f585cd504e530..0000000000000000000000000000000000000000 --- a/alfa-client/libs/tech-shared/src/lib/tech-shared.module.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { TechSharedModule } from './tech-shared.module'; -import { TestBed } from '@angular/core/testing'; - -describe('TechSharedModule', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [TechSharedModule], - }).compileComponents(); - }); - - it('should create', () => { - expect(TechSharedModule).toBeDefined(); - }); -}); diff --git a/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts b/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts deleted file mode 100644 index be795a66c9f36138e235125f6bd2995ce64da5da..0000000000000000000000000000000000000000 --- a/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { CommonModule } from '@angular/common'; -import { HTTP_INTERCEPTORS } from '@angular/common/http'; -import { Injector, NgModule } from '@angular/core'; -import { HttpBinaryFileInterceptor } from './interceptor/http-binary-file.interceptor'; -import { HttpXsrfInterceptor } from './interceptor/http-xsrf.interceptor'; -import { XhrInterceptor } from './interceptor/xhr.interceptor'; -import { ConvertApiErrorToErrorMessagesPipe } from './pipe/convert-api-error-to-error-messages.pipe'; -import { ConvertForDataTestPipe } from './pipe/convert-for-data-test.pipe'; -import { ConvertProblemDetailToErrorMessagesPipe } from './pipe/convert-problem-detail-to-error-messages.pipe'; -import { ConvertToBooleanPipe } from './pipe/convert-to-boolean.pipe'; -import { EnumToLabelPipe } from './pipe/enum-to-label.pipe'; -import { FileSizePlainPipe } from './pipe/file-size-plain.pipe'; -import { FileSizePipe } from './pipe/file-size.pipe'; -import { FormatDateWithTimePipe } from './pipe/format-date-with-time.pipe'; -import { FormatDateWithoutYearWithTimePipe } from './pipe/format-date-without-year-with-time.pipe'; -import { FormatFullDatePipe } from './pipe/format-full-date.pipe'; -import { FormatToPrettyDatePipe } from './pipe/format-to-pretty-date.pipe'; -import { GetUrlPipe } from './pipe/get-url.pipe'; -import { HasAnyLinkPipe } from './pipe/has-any-link.pipe'; -import { HasLinkPipe } from './pipe/has-link.pipe'; -import { NotHasAnyLinkPipe } from './pipe/not-has-any-link.pipe'; -import { NotHasLinkPipe } from './pipe/not-has-link.pipe'; -import { ToEmbeddedResourcesPipe } from './pipe/to-embedded-resource.pipe'; -import { ToResourceUriPipe } from './pipe/to-resource-uri.pipe'; -import { ToTrafficLightTooltipPipe } from './pipe/to-traffic-light-tooltip.pipe'; -import { ToTrafficLightPipe } from './pipe/to-traffic-light.pipe'; - -@NgModule({ - imports: [CommonModule], - declarations: [ - FormatToPrettyDatePipe, - FormatFullDatePipe, - EnumToLabelPipe, - FormatDateWithTimePipe, - FormatDateWithoutYearWithTimePipe, - HasLinkPipe, - HasAnyLinkPipe, - NotHasLinkPipe, - NotHasAnyLinkPipe, - ToResourceUriPipe, - ToTrafficLightPipe, - ToTrafficLightTooltipPipe, - ToEmbeddedResourcesPipe, - ConvertForDataTestPipe, - FileSizePipe, - FileSizePlainPipe, - GetUrlPipe, - ConvertToBooleanPipe, - ConvertApiErrorToErrorMessagesPipe, - ConvertProblemDetailToErrorMessagesPipe, - ], - exports: [ - FormatToPrettyDatePipe, - FormatFullDatePipe, - EnumToLabelPipe, - FormatDateWithTimePipe, - FormatDateWithoutYearWithTimePipe, - HasLinkPipe, - HasAnyLinkPipe, - NotHasLinkPipe, - NotHasAnyLinkPipe, - ToResourceUriPipe, - ToTrafficLightPipe, - ToTrafficLightTooltipPipe, - ToEmbeddedResourcesPipe, - ConvertForDataTestPipe, - FileSizePipe, - FileSizePlainPipe, - GetUrlPipe, - ConvertToBooleanPipe, - ConvertApiErrorToErrorMessagesPipe, - ConvertProblemDetailToErrorMessagesPipe, - ], - providers: [ - { - provide: HTTP_INTERCEPTORS, - useClass: XhrInterceptor, - multi: true, - }, - { - provide: HTTP_INTERCEPTORS, - useClass: HttpXsrfInterceptor, - multi: true, - }, - { - provide: HTTP_INTERCEPTORS, - useClass: HttpBinaryFileInterceptor, - multi: true, - }, - ], -}) -export class TechSharedModule { - public static injector: Injector; - - constructor(private injector: Injector) { - TechSharedModule.injector = this.injector; - } -} diff --git a/alfa-client/libs/tech-shared/test/data-test.ts b/alfa-client/libs/tech-shared/test/data-test.ts index 98db6b1f6fb58fa31cc9353c8440c442bbfb4112..795b2dee30c083f71da5842c2cc64738c3dd9da4 100644 --- a/alfa-client/libs/tech-shared/test/data-test.ts +++ b/alfa-client/libs/tech-shared/test/data-test.ts @@ -38,3 +38,7 @@ export function getDataTestIdOf(value: string): string { export function getDataTestIdAttributeOf(value: string): string { return `[dataTestId="${value}"]`; } + +export function getDynamicDataTestIdAttributOf(value: string): string { + return `[ng-reflect-data-test-id="${value}"]`; +} diff --git a/alfa-client/libs/tech-shared/test/marbles.ts b/alfa-client/libs/tech-shared/test/marbles.ts index ea8e04237504cc8104ddb569ce574dd66c6ad362..fecda8769f38a80dd34c693c9ca39bf175a69eef 100644 --- a/alfa-client/libs/tech-shared/test/marbles.ts +++ b/alfa-client/libs/tech-shared/test/marbles.ts @@ -34,3 +34,7 @@ export function singleCold(object: any, frame: string = 'a'): ObservableWithSubs export function singleColdCompleted(object: any, frame: string = 'a'): ObservableWithSubscriptions { return cold(`(${frame}|)`, { a: object }); } + +export function multipleCold(first: any, second: any): ObservableWithSubscriptions { + return cold('ab', { a: first, b: second }); +} diff --git a/alfa-client/libs/test-utils/src/lib/mocking.ts b/alfa-client/libs/test-utils/src/lib/mocking.ts index a5e3137a17d3fed7c81cd72e350599195cd079f7..0fb616db60420994880e9acfddec1d0d37e10486 100644 --- a/alfa-client/libs/test-utils/src/lib/mocking.ts +++ b/alfa-client/libs/test-utils/src/lib/mocking.ts @@ -47,3 +47,9 @@ export function mockClass(clazz: any): Mock<any> { export function createSpy(clazz: any, functionName: string) { return jest.spyOn(clazz.prototype, functionName); } + +export function mockGetValue(object: any, name: string, returnValue: any): void { + Object.defineProperty(object, name, { + get: jest.fn(() => returnValue), + }); +} diff --git a/alfa-client/libs/test-utils/src/lib/model.ts b/alfa-client/libs/test-utils/src/lib/model.ts index d89ed415513a8528908c72641e609bc43c86c7c7..1094ac96376b5a8d2d81cf5a7ebf13c69aa2a550 100644 --- a/alfa-client/libs/test-utils/src/lib/model.ts +++ b/alfa-client/libs/test-utils/src/lib/model.ts @@ -29,3 +29,7 @@ export interface EventData<T> { name: string; data?: unknown; } + +export const MockEvent = { + CLICK: 'clickEmitter', +}; diff --git a/alfa-client/libs/ui/src/index.ts b/alfa-client/libs/ui/src/index.ts index 8571055878c35b394402ba51f45953717cc14090..2db371a18e23b0b2d01eb93bcf1738bd8ef43f61 100644 --- a/alfa-client/libs/ui/src/index.ts +++ b/alfa-client/libs/ui/src/index.ts @@ -35,7 +35,7 @@ export * from './lib/ui/editor/autocomplete-editor/autocomplete-editor.component export * from './lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component'; export * from './lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.model'; export * from './lib/ui/editor/date-editor/date-editor.component'; -export * from './lib/ui/editor/text-editor/text-editor.component'; +export * from './lib/ui/editor/text-editor/ozgcloud-text-editor.component'; export * from './lib/ui/editor/textarea-editor/textarea-editor.component'; export * from './lib/ui/expansion-panel/expansion-panel.component'; export * from './lib/ui/file-upload/file-upload.component'; @@ -50,10 +50,11 @@ export * from './lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozg export * from './lib/ui/ozgcloud-dialog/ozgcloud-dialog.result'; export * from './lib/ui/ozgcloud-dialog/ozgcloud-dialog.service'; export * from './lib/ui/ozgcloud-icon/ozgcloud-icon.component'; +export * from './lib/ui/ozgcloud-menu/ozgcloud-menu.component'; export * from './lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component'; export * from './lib/ui/ozgcloud-routing-button/ozgcloud-routing-button.component'; export * from './lib/ui/ozgcloud-svgicon/ozgcloud-svgicon.component'; +export * from './lib/ui/slide-toggle/slide-toggle.component'; export * from './lib/ui/spinner-transparency/spinner-transparency.component'; export * from './lib/ui/spinner/spinner.component'; export * from './lib/ui/subnavigation/subnavigation.component'; -export * from './lib/ui/ui.module'; diff --git a/alfa-client/libs/ui/src/lib/icon/app-icon/app-icon.component.spec.ts b/alfa-client/libs/ui/src/lib/icon/app-icon/app-icon.component.spec.ts index b39b315dbd6786a3a84db361281b369d5936319f..c773235e923ae95da36cb21391770c50c7abff31 100644 --- a/alfa-client/libs/ui/src/lib/icon/app-icon/app-icon.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/icon/app-icon/app-icon.component.spec.ts @@ -32,8 +32,7 @@ describe('AppIconComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [AppIconComponent], - imports: [MatIcon, MatIconTestingModule], + imports: [MatIcon, MatIconTestingModule, AppIconComponent], }).compileComponents(); }); diff --git a/alfa-client/libs/ui/src/lib/icon/app-icon/app-icon.component.ts b/alfa-client/libs/ui/src/lib/icon/app-icon/app-icon.component.ts index 0b93d2c2448eebae700b8a64cefa5972962c63d2..a09417be79e311588262813e850535ef718acc62 100644 --- a/alfa-client/libs/ui/src/lib/icon/app-icon/app-icon.component.ts +++ b/alfa-client/libs/ui/src/lib/icon/app-icon/app-icon.component.ts @@ -22,10 +22,13 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Component } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; @Component({ selector: 'ozgcloud-app-icon', templateUrl: './app-icon.component.html', styleUrls: ['./app-icon.component.scss'], + standalone: true, + imports: [MatIcon], }) export class AppIconComponent {} diff --git a/alfa-client/libs/ui/src/lib/icon/postfach-icon/postfach-icon.component.spec.ts b/alfa-client/libs/ui/src/lib/icon/postfach-icon/postfach-icon.component.spec.ts index 7d0696427c9216a9e49c27678c1f5f4a4705fc39..a5ce3c8c702872b119526e7d95378a83519890a4 100644 --- a/alfa-client/libs/ui/src/lib/icon/postfach-icon/postfach-icon.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/icon/postfach-icon/postfach-icon.component.spec.ts @@ -37,8 +37,7 @@ describe('PostfachIconComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [PostfachIconComponent], - imports: [MatIconTestingModule, MatBadgeModule, MatBadge, MatIcon], + imports: [MatIconTestingModule, MatBadgeModule, MatBadge, MatIcon, PostfachIconComponent], }).compileComponents(); }); diff --git a/alfa-client/libs/ui/src/lib/icon/postfach-icon/postfach-icon.component.ts b/alfa-client/libs/ui/src/lib/icon/postfach-icon/postfach-icon.component.ts index 3ad4d01502824949af23604158bf16a87a285663..684c8781ea0697ab90cba9389672c905ca6eac66 100644 --- a/alfa-client/libs/ui/src/lib/icon/postfach-icon/postfach-icon.component.ts +++ b/alfa-client/libs/ui/src/lib/icon/postfach-icon/postfach-icon.component.ts @@ -22,11 +22,15 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Component, Input } from '@angular/core'; +import { MatBadge } from '@angular/material/badge'; +import { MatIcon } from '@angular/material/icon'; @Component({ selector: 'ozgcloud-postfach-icon', templateUrl: './postfach-icon.component.html', styleUrls: ['./postfach-icon.component.scss'], + standalone: true, + imports: [MatIcon, MatBadge], }) export class PostfachIconComponent { @Input() showBadge: boolean = false; diff --git a/alfa-client/libs/ui/src/lib/snackbar/snackbar-close-button/snackbar-close-button.component.spec.ts b/alfa-client/libs/ui/src/lib/snackbar/snackbar-close-button/snackbar-close-button.component.spec.ts index a591c897b1738a689568c6a03ced8812f7dcf382..51f5f1b134195d3ac4b0805afe63784571e084ae 100644 --- a/alfa-client/libs/ui/src/lib/snackbar/snackbar-close-button/snackbar-close-button.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/snackbar/snackbar-close-button/snackbar-close-button.component.spec.ts @@ -36,8 +36,7 @@ describe('SnackbarCloseButtonComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [SnackbarCloseButtonComponent], - imports: [MatIcon], + imports: [MatIcon, SnackbarCloseButtonComponent], }).compileComponents(); }); diff --git a/alfa-client/libs/ui/src/lib/snackbar/snackbar-close-button/snackbar-close-button.component.ts b/alfa-client/libs/ui/src/lib/snackbar/snackbar-close-button/snackbar-close-button.component.ts index 53d5bc40186fedcf833b1c0fff3d36043b9e94a5..6a4ea9b58c108f02f1d77900517f673d8d6abc85 100644 --- a/alfa-client/libs/ui/src/lib/snackbar/snackbar-close-button/snackbar-close-button.component.ts +++ b/alfa-client/libs/ui/src/lib/snackbar/snackbar-close-button/snackbar-close-button.component.ts @@ -22,11 +22,15 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Component, EventEmitter, Output } from '@angular/core'; +import { MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; @Component({ selector: 'ozgcloud-snackbar-close-button', templateUrl: './snackbar-close-button.component.html', styleUrls: ['./snackbar-close-button.component.scss'], + standalone: true, + imports: [MatIconButton, MatIcon], }) export class SnackbarCloseButtonComponent { @Output() close: EventEmitter<void> = new EventEmitter(); diff --git a/alfa-client/libs/ui/src/lib/snackbar/snackbar-error/snackbar-error.component.spec.ts b/alfa-client/libs/ui/src/lib/snackbar/snackbar-error/snackbar-error.component.spec.ts index 1421a91855149895f44da33bfd0ca59bde2562b3..c18e96c89e4b583be68444c10eb324c6a6def687 100644 --- a/alfa-client/libs/ui/src/lib/snackbar/snackbar-error/snackbar-error.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/snackbar/snackbar-error/snackbar-error.component.spec.ts @@ -21,10 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { mock } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatIconModule } from '@angular/material/icon'; import { MAT_SNACK_BAR_DATA, MatSnackBarRef } from '@angular/material/snack-bar'; -import { mock } from '@alfa-client/test-utils'; import { MockComponent } from 'ng-mocks'; import { SnackbarCloseButtonComponent } from '../snackbar-close-button/snackbar-close-button.component'; import { SnackBarData } from '../snackbar.model'; @@ -39,8 +39,7 @@ describe('SnackbarErrorComponent', () => { beforeEach(async () => { TestBed.configureTestingModule({ - imports: [MatIconModule], - declarations: [SnackbarErrorComponent, MockComponent(SnackbarCloseButtonComponent)], + imports: [MatIconModule, SnackbarErrorComponent, MockComponent(SnackbarCloseButtonComponent)], providers: [ { provide: MAT_SNACK_BAR_DATA, diff --git a/alfa-client/libs/ui/src/lib/snackbar/snackbar-error/snackbar-error.component.ts b/alfa-client/libs/ui/src/lib/snackbar/snackbar-error/snackbar-error.component.ts index 19a27fa8e545a2a41163231130c27e314c36546e..06b3709ca34f4d498af78de05fd014f6051fa089 100644 --- a/alfa-client/libs/ui/src/lib/snackbar/snackbar-error/snackbar-error.component.ts +++ b/alfa-client/libs/ui/src/lib/snackbar/snackbar-error/snackbar-error.component.ts @@ -21,20 +21,21 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Inject } from '@angular/core'; +import { Component, inject } from '@angular/core'; import { MAT_SNACK_BAR_DATA, MatSnackBarRef } from '@angular/material/snack-bar'; +import { SnackbarCloseButtonComponent } from '../snackbar-close-button/snackbar-close-button.component'; import { SnackBarData } from '../snackbar.model'; @Component({ selector: 'ozgcloud-snackbar-error', templateUrl: './snackbar-error.component.html', styleUrls: ['./snackbar-error.component.scss'], + standalone: true, + imports: [SnackbarCloseButtonComponent], }) export class SnackbarErrorComponent { - constructor( - @Inject(MAT_SNACK_BAR_DATA) public data: SnackBarData, - public snackBarRef: MatSnackBarRef<SnackbarErrorComponent>, - ) {} + public snackBarRef = inject(MatSnackBarRef<SnackbarErrorComponent>); + public data = inject<SnackBarData>(MAT_SNACK_BAR_DATA); get message(): string { return this.data.message; diff --git a/alfa-client/libs/ui/src/lib/snackbar/snackbar-info/snackbar-info.component.html b/alfa-client/libs/ui/src/lib/snackbar/snackbar-info/snackbar-info.component.html index 82103c833a2a75df2b91c919f2525931faffcd0e..fbf8300ce5d82495204a97a46483af9dcfe385c6 100644 --- a/alfa-client/libs/ui/src/lib/snackbar/snackbar-info/snackbar-info.component.html +++ b/alfa-client/libs/ui/src/lib/snackbar/snackbar-info/snackbar-info.component.html @@ -25,14 +25,8 @@ --> <div data-test-id="snackbar-message">{{ message }}</div> -<button - *ngIf="showRevokeButton()" - data-test-id="snackbar-revoke-button" - mat-button - color="primary" - (click)="revoke()" -> - Rückgängig -</button> +@if (showRevokeButton()) { + <button data-test-id="snackbar-revoke-button" mat-button color="primary" (click)="revoke()">Rückgängig</button> +} <ozgcloud-snackbar-close-button (close)="close()"></ozgcloud-snackbar-close-button> diff --git a/alfa-client/libs/ui/src/lib/snackbar/snackbar-info/snackbar-info.component.spec.ts b/alfa-client/libs/ui/src/lib/snackbar/snackbar-info/snackbar-info.component.spec.ts index 55ce0007b68eb332719107661899b82c67c8cd59..62d87fd9bfd6983d7f217c6484a9ae937f237fc2 100644 --- a/alfa-client/libs/ui/src/lib/snackbar/snackbar-info/snackbar-info.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/snackbar/snackbar-info/snackbar-info.component.spec.ts @@ -21,10 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { mock } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatIconModule } from '@angular/material/icon'; import { MAT_SNACK_BAR_DATA, MatSnackBarModule, MatSnackBarRef } from '@angular/material/snack-bar'; -import { mock } from '@alfa-client/test-utils'; import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel'; import { createCommandResource } from 'libs/command-shared/test/command'; import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; @@ -47,8 +47,7 @@ describe('SnackbarInfoComponent', () => { beforeEach(async () => { TestBed.configureTestingModule({ - imports: [MatSnackBarModule, MatIconModule], - declarations: [SnackbarInfoComponent, MockComponent(SnackbarCloseButtonComponent)], + imports: [MatSnackBarModule, MatIconModule, SnackbarInfoComponent, MockComponent(SnackbarCloseButtonComponent)], providers: [ { provide: MAT_SNACK_BAR_DATA, diff --git a/alfa-client/libs/ui/src/lib/snackbar/snackbar-info/snackbar-info.component.ts b/alfa-client/libs/ui/src/lib/snackbar/snackbar-info/snackbar-info.component.ts index e1431695e2ff15b6959bf0e7d6a30623f9cb6248..cad0471768531cac51e1227280b62d528f967309 100644 --- a/alfa-client/libs/ui/src/lib/snackbar/snackbar-info/snackbar-info.component.ts +++ b/alfa-client/libs/ui/src/lib/snackbar/snackbar-info/snackbar-info.component.ts @@ -21,22 +21,24 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Inject } from '@angular/core'; -import { MAT_SNACK_BAR_DATA, MatSnackBarRef } from '@angular/material/snack-bar'; import { isRevokeable } from '@alfa-client/command-shared'; +import { Component, inject } from '@angular/core'; +import { MatButton } from '@angular/material/button'; +import { MAT_SNACK_BAR_DATA, MatSnackBarRef } from '@angular/material/snack-bar'; import { isUndefined } from 'lodash-es'; +import { SnackbarCloseButtonComponent } from '../snackbar-close-button/snackbar-close-button.component'; import { SnackBarData } from '../snackbar.model'; @Component({ selector: 'ozgcloud-snackbar-info', templateUrl: './snackbar-info.component.html', styleUrls: ['./snackbar-info.component.scss'], + standalone: true, + imports: [MatButton, SnackbarCloseButtonComponent], }) export class SnackbarInfoComponent { - constructor( - @Inject(MAT_SNACK_BAR_DATA) public data: SnackBarData, - public snackBarRef: MatSnackBarRef<SnackbarInfoComponent>, - ) {} + public snackBarRef = inject(MatSnackBarRef<SnackbarInfoComponent>); + public data = inject<SnackBarData>(MAT_SNACK_BAR_DATA); get message(): string { return this.data.message; diff --git a/alfa-client/libs/ui/src/lib/snackbar/snackbar.service.ts b/alfa-client/libs/ui/src/lib/snackbar/snackbar.service.ts index 98b7170fe7e634e14ac0528a86f8f1467fedaabf..6e0ecf60e609bb66d8fe6fbbf2d823fcd2208266 100644 --- a/alfa-client/libs/ui/src/lib/snackbar/snackbar.service.ts +++ b/alfa-client/libs/ui/src/lib/snackbar/snackbar.service.ts @@ -21,11 +21,11 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { ComponentType } from '@angular/cdk/overlay'; -import { Injectable } from '@angular/core'; -import { MatSnackBar, MatSnackBarConfig, MatSnackBarRef } from '@angular/material/snack-bar'; import { CommandResource, CommandStatus } from '@alfa-client/command-shared'; import { isNotUndefined } from '@alfa-client/tech-shared'; +import { ComponentType } from '@angular/cdk/overlay'; +import { inject, Injectable } from '@angular/core'; +import { MatSnackBar, MatSnackBarConfig, MatSnackBarRef } from '@angular/material/snack-bar'; import { isUndefined } from 'lodash-es'; import { Subscription } from 'rxjs'; import { SnackbarErrorComponent } from './snackbar-error/snackbar-error.component'; @@ -33,14 +33,14 @@ import { SnackbarInfoComponent } from './snackbar-info/snackbar-info.component'; @Injectable({ providedIn: 'root' }) export class SnackBarService { + private snackBar = inject(MatSnackBar); + private subscription: Subscription; snackBarRef: MatSnackBarRef<SnackbarInfoComponent | SnackbarErrorComponent>; private durationTime: number = 10000; - constructor(private snackBar: MatSnackBar) {} - public show(commandResource: CommandResource, message: string, revokeAction?: () => void): void { if (commandResource.status === CommandStatus.ERROR) { this.showError(message); diff --git a/alfa-client/libs/ui/src/lib/ui/accordion/accordion.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/accordion/accordion.component.spec.ts index 8c9259c77a6edab755a16d357e8ac422b5154e5e..7a5b60d6c39ba17230d0bab3aa5088c9c5d54e62 100644 --- a/alfa-client/libs/ui/src/lib/ui/accordion/accordion.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/accordion/accordion.component.spec.ts @@ -31,8 +31,7 @@ describe('AccordionComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [AccordionComponent], - imports: [MatAccordion], + imports: [MatAccordion, AccordionComponent], }).compileComponents(); }); diff --git a/alfa-client/libs/ui/src/lib/ui/accordion/accordion.component.ts b/alfa-client/libs/ui/src/lib/ui/accordion/accordion.component.ts index 36001957eb55aef18fb3bb4013e4f3eac6973149..2327c0401e3f59cef0999f8b5e263bdb5148fe69 100644 --- a/alfa-client/libs/ui/src/lib/ui/accordion/accordion.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/accordion/accordion.component.ts @@ -22,11 +22,14 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Component, Input } from '@angular/core'; +import { MatAccordion } from '@angular/material/expansion'; @Component({ selector: 'ozgcloud-accordion', templateUrl: './accordion.component.html', styleUrls: ['./accordion.component.scss'], + standalone: true, + imports: [MatAccordion], }) export class AccordionComponent { @Input() multi: boolean = false; diff --git a/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.ts b/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.ts index 14ad27f618eb07409005dabcb61ce581a6462134..a5c00893b3fa0fe9c3745afa4a750f395f06df70 100644 --- a/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.ts @@ -22,11 +22,18 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Component, Input } from '@angular/core'; +import { MatIconAnchor } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; +import { RouterLink } from '@angular/router'; +import { ArrowBackIconComponent, ButtonComponent, TooltipDirective } from '@ods/system'; @Component({ selector: 'ozgcloud-back-button', templateUrl: './back-button.component.html', styleUrls: ['./back-button.component.scss'], + standalone: true, + imports: [MatIconAnchor, RouterLink, MatTooltip, MatIcon, TooltipDirective, ButtonComponent, ArrowBackIconComponent], }) export class BackButtonComponent { @Input() label: string; diff --git a/alfa-client/libs/ui/src/lib/ui/basic-dialog/basic-dialog.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/basic-dialog/basic-dialog.component.spec.ts index ec797a1c52d453daa90d440babf58f3f188a02a5..23ca3dbbc8807eff625e692c251d00cf53b93fdc 100644 --- a/alfa-client/libs/ui/src/lib/ui/basic-dialog/basic-dialog.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/basic-dialog/basic-dialog.component.spec.ts @@ -21,13 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { IconButtonWithSpinnerComponent, OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { MatIcon } from '@angular/material/icon'; -import { - IconButtonWithSpinnerComponent, - OzgcloudStrokedButtonWithSpinnerComponent, -} from '@alfa-client/ui'; import { MockComponent } from 'ng-mocks'; import { BasicDialogComponent } from './basic-dialog.component'; @@ -37,8 +34,8 @@ describe('BasicDialogComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [MatDialogModule], - declarations: [ + imports: [ + MatDialogModule, BasicDialogComponent, MatIcon, MockComponent(OzgcloudStrokedButtonWithSpinnerComponent), diff --git a/alfa-client/libs/ui/src/lib/ui/basic-dialog/basic-dialog.component.ts b/alfa-client/libs/ui/src/lib/ui/basic-dialog/basic-dialog.component.ts index e9519e80425254082dbb78cb7c75baf6e23ebe2b..cbe53ff122890939ac29bdda8e991855e3a78a53 100644 --- a/alfa-client/libs/ui/src/lib/ui/basic-dialog/basic-dialog.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/basic-dialog/basic-dialog.component.ts @@ -21,20 +21,36 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { Component, inject } from '@angular/core'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogRef, + MatDialogTitle, +} from '@angular/material/dialog'; +import { OzgcloudStrokedButtonWithSpinnerComponent } from '../ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component'; import { BasicDialogData } from './basic-dialog-data.model'; @Component({ selector: 'ozgcloud-basic-dialog', templateUrl: './basic-dialog.component.html', styleUrls: ['./basic-dialog.component.scss'], + standalone: true, + imports: [ + MatDialogTitle, + CdkScrollable, + MatDialogContent, + MatDialogActions, + OzgcloudStrokedButtonWithSpinnerComponent, + MatDialogClose, + ], }) export class BasicDialogComponent { - constructor( - public dialogRef: MatDialogRef<BasicDialogComponent>, - @Inject(MAT_DIALOG_DATA) public data: BasicDialogData, - ) {} + public dialogRef = inject(MatDialogRef<BasicDialogComponent>); + public data = inject<BasicDialogData>(MAT_DIALOG_DATA); onNoClick(): void { this.dialogRef.close(); diff --git a/alfa-client/libs/ui/src/lib/ui/dialog/dialog.service.ts b/alfa-client/libs/ui/src/lib/ui/dialog/dialog.service.ts index dfe376a9f5fb12120a0be495df47fb865610f175..cd72feef7dac8d6194e6fb83ab08e9b76e38ffa7 100644 --- a/alfa-client/libs/ui/src/lib/ui/dialog/dialog.service.ts +++ b/alfa-client/libs/ui/src/lib/ui/dialog/dialog.service.ts @@ -21,22 +21,19 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { ApiError, isNotUndefined } from '@alfa-client/tech-shared'; +import { BasicDialogComponent, BasicDialogData, FixedDialogComponent, FixedDialogData } from '@alfa-client/ui'; import { NoopScrollStrategy } from '@angular/cdk/overlay'; import { ComponentType } from '@angular/cdk/portal'; -import { Injectable } from '@angular/core'; +import { inject, Injectable } from '@angular/core'; import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; -import { ApiError, isNotUndefined } from '@alfa-client/tech-shared'; -import { - BasicDialogComponent, - BasicDialogData, - FixedDialogComponent, - FixedDialogData, -} from '@alfa-client/ui'; import { InternalServerErrorDialogComponent } from '../notification/internal-server-error-dialog/internal-server-error-dialog.component'; import { RetryInTimeDialog } from './retry-in-time.dialog'; @Injectable({ providedIn: 'root' }) export class DialogService { + private dialog = inject(MatDialog); + fixedSingleDialogRef: MatDialogRef<FixedDialogComponent>; readonly FIXED_DIALOG_CONFIG: MatDialogConfig = { @@ -67,8 +64,6 @@ export class DialogService { restoreFocus: false, }; - constructor(private dialog: MatDialog) {} - public openWidely<T>(component: ComponentType<T>, config?: MatDialogConfig): MatDialogRef<T> { return this.open<T>(component, { ...config, ...this.WIDE_DIALOG_CONFIG }); } diff --git a/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.spec.ts index d1215dcb80ea593e83277a49ba20d20e7988f671..2771e503131afefce51f6073b52866178fbc34ad 100644 --- a/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.spec.ts @@ -23,8 +23,8 @@ */ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { DownloadButtonComponent } from './download-button.component'; import { MockComponent } from 'ng-mocks'; +import { DownloadButtonComponent } from './download-button.component'; describe('DownloadButtonComponent', () => { let component: DownloadButtonComponent; @@ -32,7 +32,7 @@ describe('DownloadButtonComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [DownloadButtonComponent, MockComponent(DownloadButtonComponent)], + imports: [DownloadButtonComponent, MockComponent(DownloadButtonComponent)], }).compileComponents(); fixture = TestBed.createComponent(DownloadButtonComponent); diff --git a/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.ts b/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.ts index d1b4e7fed82b0d06bc0c814137c2caabe34fc01f..be55bf7f0df760e20fb83d53c81560dd255ff90d 100644 --- a/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.ts @@ -22,11 +22,17 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Component, Input } from '@angular/core'; +import { MatAnchor } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; +import { TooltipDirective } from '@ods/system'; @Component({ selector: 'ozgcloud-download-button', templateUrl: './download-button.component.html', styleUrls: ['./download-button.component.scss'], + standalone: true, + imports: [MatAnchor, MatTooltip, MatIcon, TooltipDirective], }) export class DownloadButtonComponent { @Input() icon: string; diff --git a/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.html index b60743ee96c5c2e579c266efbabb320bad129ddb..43edcd913d44feaaf9af68ae7e94df89215df6b9 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.html +++ b/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.html @@ -1,26 +1,26 @@ <!-- - Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - Ministerpräsidenten des Landes Schleswig-Holstein - Staatskanzlei - Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - - Lizenziert unter der EUPL, Version 1.2 oder - sobald - diese von der Europäischen Kommission genehmigt wurden - - Folgeversionen der EUPL ("Lizenz"); - Sie dürfen dieses Werk ausschließlich gemäß - dieser Lizenz nutzen. - Eine Kopie der Lizenz finden Sie hier: - - https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - - Sofern nicht durch anwendbare Rechtsvorschriften - gefordert oder in schriftlicher Form vereinbart, wird - die unter der Lizenz verbreitete Software "so wie sie - ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - ausdrücklich oder stillschweigend - verbreitet. - Die sprachspezifischen Genehmigungen und Beschränkungen - unter der Lizenz sind dem Lizenztext zu entnehmen. +Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den +Ministerpräsidenten des Landes Schleswig-Holstein +Staatskanzlei +Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + +Lizenziert unter der EUPL, Version 1.2 oder - sobald +diese von der Europäischen Kommission genehmigt wurden - +Folgeversionen der EUPL ("Lizenz"); +Sie dürfen dieses Werk ausschließlich gemäß +dieser Lizenz nutzen. +Eine Kopie der Lizenz finden Sie hier: + +https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + +Sofern nicht durch anwendbare Rechtsvorschriften +gefordert oder in schriftlicher Form vereinbart, wird +die unter der Lizenz verbreitete Software "so wie sie +ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +ausdrücklich oder stillschweigend - verbreitet. +Die sprachspezifischen Genehmigungen und Beschränkungen +unter der Lizenz sind dem Lizenztext zu entnehmen. --> <mat-form-field appearance="outline"> @@ -40,15 +40,16 @@ /> <mat-autocomplete autoActiveFirstOption #auto="matAutocomplete"> - <mat-option - *ngFor="let value of values" - [attr.data-test-id]="(value.label | convertForDataTest) + '-autocomplete-option'" - [value]="value.value" - (keyup.enter)="onSelection(value)" - (onSelectionChange)="onSelection(value)" - > - {{ value.label }} - </mat-option> + @for (value of values; track value) { + <mat-option + [attr.data-test-id]="(value.label | convertForDataTest) + '-autocomplete-option'" + [value]="value.value" + (keyup.enter)="onSelection(value)" + (onSelectionChange)="onSelection(value)" + > + {{ value.label }} + </mat-option> + } </mat-autocomplete> <mat-error> diff --git a/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.spec.ts index 609ef74f56da69e125e481e7dc187a00c383069f..c590cbe105096627b2432f84f3052e54058e09d8 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.spec.ts @@ -21,13 +21,13 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NgControl, ReactiveFormsModule, UntypedFormControl } from '@angular/forms'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { MockComponent } from 'ng-mocks'; import { ValidationErrorComponent } from '../../validation-error/validation-error.component'; import { AutocompleteEditorComponent } from './autocomplete-editor.component'; @@ -38,17 +38,15 @@ describe('AutocompleteEditorComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - AutocompleteEditorComponent, - ConvertForDataTestPipe, - MockComponent(ValidationErrorComponent), - ], imports: [ MatAutocompleteModule, MatFormFieldModule, MatInputModule, ReactiveFormsModule, BrowserAnimationsModule, + AutocompleteEditorComponent, + ConvertForDataTestPipe, + MockComponent(ValidationErrorComponent), ], providers: [ { diff --git a/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.ts b/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.ts index 1cb488f0f7025cd34f7e53a541c9b430aa557082..87aba70b5394eb65499915b9a29feef3154df301 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.ts @@ -21,28 +21,38 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - AfterViewInit, - Component, - ElementRef, - EventEmitter, - Input, - Output, - ViewChild, -} from '@angular/core'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; +import { AfterViewInit, Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatAutocomplete, MatAutocompleteTrigger } from '@angular/material/autocomplete'; +import { MatOption } from '@angular/material/core'; +import { MatError, MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatInput } from '@angular/material/input'; import { ResourceUri } from '@ngxp/rest'; import { FormControlEditorAbstractComponent } from 'libs/design-component/src/lib/form/formcontrol-editor.abstract.component'; import { isEmpty, isEqual, isNil } from 'lodash-es'; +import { ValidationErrorComponent } from '../../validation-error/validation-error.component'; @Component({ selector: 'ozgcloud-autocomplete-editor', templateUrl: './autocomplete-editor.component.html', styleUrls: ['./autocomplete-editor.component.scss'], + standalone: true, + imports: [ + MatFormField, + MatLabel, + MatInput, + MatAutocompleteTrigger, + FormsModule, + ReactiveFormsModule, + MatAutocomplete, + MatOption, + MatError, + ValidationErrorComponent, + ConvertForDataTestPipe, + ], }) -export class AutocompleteEditorComponent - extends FormControlEditorAbstractComponent - implements AfterViewInit -{ +export class AutocompleteEditorComponent extends FormControlEditorAbstractComponent implements AfterViewInit { @Input() label: string; @Input() values: Selectable[] = []; @Input() required: boolean = false; @@ -64,9 +74,7 @@ export class AutocompleteEditorComponent onEnter(): void { const selectedValue: ResourceUri = this.fieldControl.value; - isEmpty(selectedValue) ? - this.enterOnNoSelection.emit() - : this.onSelection(this.getUserProfile()); + isEmpty(selectedValue) ? this.enterOnNoSelection.emit() : this.onSelection(this.getUserProfile()); } private getUserProfile(): Selectable { diff --git a/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.spec.ts index 2a7caecd0e32ea384511381f74daa36eaecc7644..91a6537c22606b24f3358d8de8d5dbec08f7ba9b 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.spec.ts @@ -21,16 +21,15 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; -import { MatIcon } from '@angular/material/icon'; import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { MockComponent } from 'ng-mocks'; import { IconButtonWithSpinnerComponent } from '../../icon-button-with-spinner/icon-button-with-spinner.component'; import { CheckboxEnumEditorComponent } from './checkbox-enum-editor.component'; -import { UiModule } from '../../ui.module'; describe('CheckboxEnumEditorComponent', () => { let component: CheckboxEnumEditorComponent; @@ -38,13 +37,15 @@ describe('CheckboxEnumEditorComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ + declarations: [ConvertForDataTestPipe], + imports: [ + MatFormFieldModule, + ReactiveFormsModule, + BrowserAnimationsModule, CheckboxEnumEditorComponent, MatIcon, - ConvertForDataTestPipe, MockComponent(IconButtonWithSpinnerComponent), ], - imports: [UiModule, MatFormFieldModule, ReactiveFormsModule, BrowserAnimationsModule], }).compileComponents(); }); diff --git a/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.ts b/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.ts index 26e505719f2ffab18108f1f278bbc984d5e79622..0943452372c17eb48ba64b6c3e97bf9ee4067ae9 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.ts @@ -22,7 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Component, Input, OnInit } from '@angular/core'; -import { MatCheckboxChange } from '@angular/material/checkbox'; +import { MatCheckbox, MatCheckboxChange } from '@angular/material/checkbox'; import { FormControlEditorAbstractComponent } from 'libs/design-component/src/lib/form/formcontrol-editor.abstract.component'; import { CheckboxEnumEditorItem } from './checkbox-enum-editor.model'; @@ -34,11 +34,10 @@ import { CheckboxEnumEditorItem } from './checkbox-enum-editor.model'; selector: 'ozgcloud-checkbox-enum-editor', templateUrl: './checkbox-enum-editor.component.html', styleUrls: ['./checkbox-enum-editor.component.scss'], + standalone: true, + imports: [MatCheckbox], }) -export class CheckboxEnumEditorComponent - extends FormControlEditorAbstractComponent - implements OnInit -{ +export class CheckboxEnumEditorComponent extends FormControlEditorAbstractComponent implements OnInit { @Input() label: string; @Input() defaultItem: CheckboxEnumEditorItem; @Input() checkedItem: CheckboxEnumEditorItem; diff --git a/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.spec.ts index 2af729384632e5d72440e7a4dd862b921b3aea52..e8fb9e83f6c6a820f348e86b6841ef6bf00532a3 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.spec.ts @@ -43,12 +43,9 @@ describe('DateEditorComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - DateEditorComponent, - ConvertForDataTestPipe, - MockComponent(ValidationErrorComponent), - ], + declarations: [ConvertForDataTestPipe], imports: [ + ConvertForDataTestPipe, MatFormFieldModule, MatInputModule, MatIconModule, @@ -56,6 +53,8 @@ describe('DateEditorComponent', () => { MatNativeDateModule, ReactiveFormsModule, BrowserAnimationsModule, + DateEditorComponent, + MockComponent(ValidationErrorComponent), ], }).compileComponents(); }); @@ -75,9 +74,7 @@ describe('DateEditorComponent', () => { component.label = 'Ein Label'; fixture.detectChanges(); - const element: HTMLElement = fixture.nativeElement.querySelector( - '[data-test-id="Ein_Label-date-input"]', - ); + const element: HTMLElement = fixture.nativeElement.querySelector('[data-test-id="Ein_Label-date-input"]'); expect(element).toBeInstanceOf(HTMLElement); }); diff --git a/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.ts b/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.ts index c632ccf07fb72d02712a391901d9d0cc8a0d9d9b..b7dd27fb2f94c53cf4f4acfdb6bad040798348da 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.ts @@ -21,16 +21,32 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { add2000Years } from '@alfa-client/tech-shared'; +import { add2000Years, ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { Component, Input } from '@angular/core'; -import { MatDatepickerInputEvent } from '@angular/material/datepicker'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatDatepickerInputEvent, MatDatepickerModule } from '@angular/material/datepicker'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; import { isDate } from 'date-fns'; import { FormControlEditorAbstractComponent } from 'libs/design-component/src/lib/form/formcontrol-editor.abstract.component'; +import { ValidationErrorComponent } from '../../validation-error/validation-error.component'; @Component({ selector: 'ozgcloud-date-editor', templateUrl: './date-editor.component.html', styleUrls: ['./date-editor.component.scss'], + standalone: true, + imports: [ + MatFormFieldModule, + MatInputModule, + FormsModule, + ReactiveFormsModule, + MatIcon, + ValidationErrorComponent, + MatDatepickerModule, + ConvertForDataTestPipe, + ], }) export class DateEditorComponent extends FormControlEditorAbstractComponent { @Input() label: string; diff --git a/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.html index 123269b8cb6c410f812da2ce9cc447e9c043c7bc..c8501ddaa8dee9c1e93721b8f7408b5652903bde 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.html +++ b/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.html @@ -1,32 +1,32 @@ <!-- - Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - Ministerpräsidenten des Landes Schleswig-Holstein - Staatskanzlei - Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - - Lizenziert unter der EUPL, Version 1.2 oder - sobald - diese von der Europäischen Kommission genehmigt wurden - - Folgeversionen der EUPL ("Lizenz"); - Sie dürfen dieses Werk ausschließlich gemäß - dieser Lizenz nutzen. - Eine Kopie der Lizenz finden Sie hier: - - https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - - Sofern nicht durch anwendbare Rechtsvorschriften - gefordert oder in schriftlicher Form vereinbart, wird - die unter der Lizenz verbreitete Software "so wie sie - ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - ausdrücklich oder stillschweigend - verbreitet. - Die sprachspezifischen Genehmigungen und Beschränkungen - unter der Lizenz sind dem Lizenztext zu entnehmen. +Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den +Ministerpräsidenten des Landes Schleswig-Holstein +Staatskanzlei +Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + +Lizenziert unter der EUPL, Version 1.2 oder - sobald +diese von der Europäischen Kommission genehmigt wurden - +Folgeversionen der EUPL ("Lizenz"); +Sie dürfen dieses Werk ausschließlich gemäß +dieser Lizenz nutzen. +Eine Kopie der Lizenz finden Sie hier: + +https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + +Sofern nicht durch anwendbare Rechtsvorschriften +gefordert oder in schriftlicher Form vereinbart, wird +die unter der Lizenz verbreitete Software "so wie sie +ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +ausdrücklich oder stillschweigend - verbreitet. +Die sprachspezifischen Genehmigungen und Beschränkungen +unter der Lizenz sind dem Lizenztext zu entnehmen. --> <ng-container [formArrayName]="parentFormArrayName"> - <ng-container *ngFor="let hiddenInput of fileLinkControls.controls; let i = index"> + @for (hiddenInput of fileLinkControls.controls; track hiddenInput; let i = $index) { <input id="file-link-{{ i }}" type="hidden" [formControlName]="i" /> - </ng-container> + } </ng-container> <input @@ -39,10 +39,11 @@ /> <label [attr.for]="uploadFileId" matRipple [attr.aria-label]="label"> - <mat-icon *ngIf="!uploadInProgress.loading">attach_file</mat-icon> + @if (!uploadInProgress.loading) { + <mat-icon>attach_file</mat-icon> + } - <ozgcloud-spinner [stateResource]="uploadInProgress" [diameter]="22" padding="0"> - </ozgcloud-spinner> + <ozgcloud-spinner [stateResource]="uploadInProgress" [diameter]="22" padding="0"> </ozgcloud-spinner> </label> <mat-error> diff --git a/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.spec.ts index a6c2b5c8d87ad575a680c408b349146e8f21966f..2dc06d2e3d1f7ffc486f6a8f4525427281e4247e 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.spec.ts @@ -21,20 +21,15 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { ConvertForDataTestPipe, createEmptyStateResource } from '@alfa-client/tech-shared'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - AbstractControl, - FormGroupDirective, - ReactiveFormsModule, - UntypedFormBuilder, -} from '@angular/forms'; +import { AbstractControl, FormGroupDirective, ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; import { MatNativeDateModule } from '@angular/material/core'; import { MatDatepickerModule } from '@angular/material/datepicker'; -import { MatIconModule } from '@angular/material/icon'; import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { ConvertForDataTestPipe, createEmptyStateResource } from '@alfa-client/tech-shared'; import { MockComponent } from 'ng-mocks'; import { SpinnerComponent } from '../../spinner/spinner.component'; import { ValidationErrorComponent } from '../../validation-error/validation-error.component'; @@ -51,12 +46,6 @@ describe('FileUploadEditorComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - FileUploadEditorComponent, - ConvertForDataTestPipe, - MockComponent(ValidationErrorComponent), - MockComponent(SpinnerComponent), - ], imports: [ MatFormFieldModule, MatInputModule, @@ -65,6 +54,10 @@ describe('FileUploadEditorComponent', () => { MatNativeDateModule, ReactiveFormsModule, BrowserAnimationsModule, + FileUploadEditorComponent, + ConvertForDataTestPipe, + MockComponent(ValidationErrorComponent), + MockComponent(SpinnerComponent), ], providers: [ FormGroupDirective, @@ -100,9 +93,7 @@ describe('FileUploadEditorComponent', () => { component.label = 'Ein Label'; fixture.detectChanges(); - const element: HTMLElement = fixture.nativeElement.querySelector( - '[data-test-id="Ein_Label-file-upload-input"]', - ); + const element: HTMLElement = fixture.nativeElement.querySelector('[data-test-id="Ein_Label-file-upload-input"]'); expect(element).toBeInstanceOf(HTMLElement); }); diff --git a/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.ts b/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.ts index 148f7d0dd06e17e7b790ff81139f1fbca85ffc52..5c75b22163ad44971eb6bef5821b66b717336d51 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.ts @@ -21,36 +21,44 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { StateResource } from '@alfa-client/tech-shared'; -import { - Component, - ElementRef, - EventEmitter, - HostListener, - Input, - OnInit, - Output, - ViewChild, -} from '@angular/core'; +import { ConvertForDataTestPipe, StateResource } from '@alfa-client/tech-shared'; +import { Component, ElementRef, EventEmitter, HostListener, inject, Input, OnInit, Output, ViewChild } from '@angular/core'; import { ControlContainer, FormGroupDirective, + FormsModule, + ReactiveFormsModule, UntypedFormArray, UntypedFormControl, } from '@angular/forms'; +import { MatRipple } from '@angular/material/core'; +import { MatError } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; import { FormControlEditorAbstractComponent } from 'libs/design-component/src/lib/form/formcontrol-editor.abstract.component'; import { uniqueId } from 'lodash-es'; +import { SpinnerComponent } from '../../spinner/spinner.component'; +import { ValidationErrorComponent } from '../../validation-error/validation-error.component'; @Component({ selector: 'ozgcloud-file-upload-editor', templateUrl: './file-upload-editor.component.html', styleUrls: ['./file-upload-editor.component.scss'], viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }], + standalone: true, + imports: [ + FormsModule, + ReactiveFormsModule, + MatRipple, + MatIcon, + SpinnerComponent, + MatError, + ValidationErrorComponent, + ConvertForDataTestPipe, + ], }) -export class FileUploadEditorComponent - extends FormControlEditorAbstractComponent - implements OnInit -{ +export class FileUploadEditorComponent extends FormControlEditorAbstractComponent implements OnInit { + public parentForm = inject(FormGroupDirective); + @Input() label: string = ''; @Input() parentFormArrayName: string; @Input() accept: string = '*/*'; @@ -72,19 +80,13 @@ export class FileUploadEditorComponent this.setErrors(); } - constructor(public parentForm: FormGroupDirective) { - super(null); - } - override ngOnInit(): void { this.fileLinkControls = this.parentForm.form.get(this.parentFormArrayName) as UntypedFormArray; } buildFormArray(fileLinkList: string[]): void { this.fileLinkControls.clear(); - fileLinkList.forEach((link: string) => - this.fileLinkControls.push(new UntypedFormControl(link)), - ); + fileLinkList.forEach((link: string) => this.fileLinkControls.push(new UntypedFormControl(link))); } resetInput(): void { diff --git a/alfa-client/libs/ui/src/lib/ui/editor/text-editor/ozgcloud-text-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/text-editor/ozgcloud-text-editor.component.html new file mode 100644 index 0000000000000000000000000000000000000000..8dab6eb918bef8d15c6a555ef6ab253f27942700 --- /dev/null +++ b/alfa-client/libs/ui/src/lib/ui/editor/text-editor/ozgcloud-text-editor.component.html @@ -0,0 +1,66 @@ +<!-- + +Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den +Ministerpräsidenten des Landes Schleswig-Holstein +Staatskanzlei +Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + +Lizenziert unter der EUPL, Version 1.2 oder - sobald +diese von der Europäischen Kommission genehmigt wurden - +Folgeversionen der EUPL ("Lizenz"); +Sie dürfen dieses Werk ausschließlich gemäß +dieser Lizenz nutzen. +Eine Kopie der Lizenz finden Sie hier: + +https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + +Sofern nicht durch anwendbare Rechtsvorschriften +gefordert oder in schriftlicher Form vereinbart, wird +die unter der Lizenz verbreitete Software "so wie sie +ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +ausdrücklich oder stillschweigend - verbreitet. +Die sprachspezifischen Genehmigungen und Beschränkungen +unter der Lizenz sind dem Lizenztext zu entnehmen. + +--> +<mat-form-field + [subscriptSizing]="subscriptSizing" + class="compact-input" + appearance="{{ appearance }}" + [floatLabel]="readOnly || autoFocus ? 'always' : 'auto'" +> + <mat-label>{{ label }}</mat-label> + <div class="wrapper"> + <input + #inputElement + matInput + placeholder="{{ placeholder }}" + [formControl]="fieldControl" + [autocomplete]="autocomplete" + [readonly]="readOnly" + (blur)="touch()" + [required]="required" + [attr.data-test-id]="(label | convertForDataTest) + '-text-input'" + [class.with-clear-button]="showClearButton$ | async" + /> + @if (showClearButton$ | async) { + <button + data-test-id="clear-button" + class="clear-button" + type="button" + (click)="onClear()" + mat-icon-button + aria-label="Leeren" + > + <mat-icon>close</mat-icon> + </button> + } + </div> + <mat-error> + <ozgcloud-validation-error + [attr.data-test-id]="(getPlaceholderLabel() | convertForDataTest) + '-text-error'" + [invalidParams]="invalidParams" + [label]="getPlaceholderLabel()" + ></ozgcloud-validation-error> + </mat-error> +</mat-form-field> diff --git a/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.scss b/alfa-client/libs/ui/src/lib/ui/editor/text-editor/ozgcloud-text-editor.component.scss similarity index 100% rename from alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.scss rename to alfa-client/libs/ui/src/lib/ui/editor/text-editor/ozgcloud-text-editor.component.scss diff --git a/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/editor/text-editor/ozgcloud-text-editor.component.spec.ts similarity index 84% rename from alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.spec.ts rename to alfa-client/libs/ui/src/lib/ui/editor/text-editor/ozgcloud-text-editor.component.spec.ts index e2000c8388d7734d74f703d0748d531580e7454d..52c2e538297a8d30167ad14f5760bf8a79888cd9 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/editor/text-editor/ozgcloud-text-editor.component.spec.ts @@ -29,18 +29,26 @@ import { MatInputModule } from '@angular/material/input'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { MockComponent } from 'ng-mocks'; import { ValidationErrorComponent } from '../../validation-error/validation-error.component'; -import { TextEditorComponent } from './text-editor.component'; +import { OzgcloudTextEditorComponent } from './ozgcloud-text-editor.component'; -describe('TextEditorComponent', () => { - let component: TextEditorComponent; - let fixture: ComponentFixture<TextEditorComponent>; +describe('OzgcloudTextEditorComponent', () => { + let component: OzgcloudTextEditorComponent; + let fixture: ComponentFixture<OzgcloudTextEditorComponent>; const input: string = '[data-test-id="Ein_Label-text-input"]'; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TextEditorComponent, ConvertForDataTestPipe, MockComponent(ValidationErrorComponent)], - imports: [MatFormFieldModule, MatInputModule, ReactiveFormsModule, BrowserAnimationsModule], + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ + OzgcloudTextEditorComponent, + MatFormFieldModule, + MatInputModule, + ReactiveFormsModule, + BrowserAnimationsModule, + ConvertForDataTestPipe, + MockComponent(ValidationErrorComponent), + ], + imports: [], providers: [ { provide: NgControl, @@ -51,7 +59,7 @@ describe('TextEditorComponent', () => { }); beforeEach(() => { - fixture = TestBed.createComponent(TextEditorComponent); + fixture = TestBed.createComponent(OzgcloudTextEditorComponent); component = fixture.componentInstance; component.label = 'Ein Label'; fixture.detectChanges(); diff --git a/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.ts b/alfa-client/libs/ui/src/lib/ui/editor/text-editor/ozgcloud-text-editor.component.ts similarity index 69% rename from alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.ts rename to alfa-client/libs/ui/src/lib/ui/editor/text-editor/ozgcloud-text-editor.component.ts index 5e3227127c9e7b3cc451ad530262da5f36fe1cf5..9e1294a6059d8baa85f7faccdf45401af6a08c6e 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/editor/text-editor/ozgcloud-text-editor.component.ts @@ -21,21 +21,38 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { hasContent } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe, hasContent } from '@alfa-client/tech-shared'; +import { AsyncPipe } from '@angular/common'; import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; -import { SubscriptSizing } from '@angular/material/form-field'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatIconButton } from '@angular/material/button'; +import { MatError, MatFormField, MatLabel, SubscriptSizing } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatInput } from '@angular/material/input'; import { FormControlEditorAbstractComponent } from 'libs/design-component/src/lib/form/formcontrol-editor.abstract.component'; import { Observable, map, startWith } from 'rxjs'; +import { ValidationErrorComponent } from '../../validation-error/validation-error.component'; @Component({ selector: 'ozgcloud-text-editor', - templateUrl: './text-editor.component.html', - styleUrls: ['./text-editor.component.scss'], + templateUrl: './ozgcloud-text-editor.component.html', + styleUrls: ['./ozgcloud-text-editor.component.scss'], + standalone: true, + imports: [ + MatFormField, + MatLabel, + MatInput, + FormsModule, + ReactiveFormsModule, + MatIconButton, + MatIcon, + MatError, + ValidationErrorComponent, + AsyncPipe, + ConvertForDataTestPipe, + ], }) -export class TextEditorComponent - extends FormControlEditorAbstractComponent - implements OnInit, AfterViewInit -{ +export class OzgcloudTextEditorComponent extends FormControlEditorAbstractComponent implements OnInit, AfterViewInit { @ViewChild('inputElement') inputElement: ElementRef; @Input() label: string; diff --git a/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.html deleted file mode 100644 index 303e1315d5e643ebce97e74e5f9477b1ca105866..0000000000000000000000000000000000000000 --- a/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.html +++ /dev/null @@ -1,65 +0,0 @@ -<!-- - - Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - Ministerpräsidenten des Landes Schleswig-Holstein - Staatskanzlei - Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - - Lizenziert unter der EUPL, Version 1.2 oder - sobald - diese von der Europäischen Kommission genehmigt wurden - - Folgeversionen der EUPL ("Lizenz"); - Sie dürfen dieses Werk ausschließlich gemäß - dieser Lizenz nutzen. - Eine Kopie der Lizenz finden Sie hier: - - https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - - Sofern nicht durch anwendbare Rechtsvorschriften - gefordert oder in schriftlicher Form vereinbart, wird - die unter der Lizenz verbreitete Software "so wie sie - ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - ausdrücklich oder stillschweigend - verbreitet. - Die sprachspezifischen Genehmigungen und Beschränkungen - unter der Lizenz sind dem Lizenztext zu entnehmen. - ---> -<mat-form-field - [subscriptSizing]="subscriptSizing" - class="compact-input" - appearance="{{ appearance }}" - [floatLabel]="readOnly || autoFocus ? 'always' : 'auto'" -> - <mat-label>{{ label }}</mat-label> - <div class="wrapper"> - <input - #inputElement - matInput - placeholder="{{ placeholder }}" - [formControl]="fieldControl" - [autocomplete]="autocomplete" - [readonly]="readOnly" - (blur)="touch()" - [required]="required" - [attr.data-test-id]="(label | convertForDataTest) + '-text-input'" - [class.with-clear-button]="showClearButton$ | async" - /> - <button - *ngIf="showClearButton$ | async" - data-test-id="clear-button" - class="clear-button" - type="button" - (click)="onClear()" - mat-icon-button - aria-label="Leeren" - > - <mat-icon>close</mat-icon> - </button> - </div> - <mat-error> - <ozgcloud-validation-error - [attr.data-test-id]="(getPlaceholderLabel() | convertForDataTest) + '-text-error'" - [invalidParams]="invalidParams" - [label]="getPlaceholderLabel()" - ></ozgcloud-validation-error> - </mat-error> -</mat-form-field> diff --git a/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.spec.ts index 49217b8c8117ce625d8e2ff8edd9e9ab82dab845..670590d080bda2dfd50caa88d4b5894c729416a6 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.spec.ts @@ -21,12 +21,12 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NgControl, ReactiveFormsModule, UntypedFormControl } from '@angular/forms'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { MockComponent } from 'ng-mocks'; import { ValidationErrorComponent } from '../../validation-error/validation-error.component'; import { TextAreaEditorComponent } from './textarea-editor.component'; @@ -37,12 +37,15 @@ describe('TextAreaEditorComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ + imports: [ + MatFormFieldModule, + MatInputModule, + ReactiveFormsModule, + BrowserAnimationsModule, TextAreaEditorComponent, ConvertForDataTestPipe, MockComponent(ValidationErrorComponent), ], - imports: [MatFormFieldModule, MatInputModule, ReactiveFormsModule, BrowserAnimationsModule], providers: [ { provide: NgControl, @@ -67,9 +70,7 @@ describe('TextAreaEditorComponent', () => { component.label = 'Ein Label'; fixture.detectChanges(); - const element: HTMLElement = fixture.nativeElement.querySelector( - '[data-test-id="Ein_Label-textarea-input"]', - ); + const element: HTMLElement = fixture.nativeElement.querySelector('[data-test-id="Ein_Label-textarea-input"]'); expect(element).toBeInstanceOf(HTMLElement); }); diff --git a/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.ts b/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.ts index 27644f18242584d91fa7adf2008ed2de99e02857..a58f6a04d44fcf30053bc0a931d9920500165897 100644 --- a/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.ts @@ -21,19 +21,33 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { CdkTextareaAutosize } from '@angular/cdk/text-field'; import { AfterViewInit, Component, Input, ViewChild } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatError, MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatInput } from '@angular/material/input'; import { FormControlEditorAbstractComponent } from 'libs/design-component/src/lib/form/formcontrol-editor.abstract.component'; +import { ValidationErrorComponent } from '../../validation-error/validation-error.component'; @Component({ selector: 'ozgcloud-textarea-editor', templateUrl: './textarea-editor.component.html', styleUrls: ['./textarea-editor.component.scss'], + standalone: true, + imports: [ + MatFormField, + MatLabel, + MatInput, + CdkTextareaAutosize, + FormsModule, + ReactiveFormsModule, + MatError, + ValidationErrorComponent, + ConvertForDataTestPipe, + ], }) -export class TextAreaEditorComponent - extends FormControlEditorAbstractComponent - implements AfterViewInit -{ +export class TextAreaEditorComponent extends FormControlEditorAbstractComponent implements AfterViewInit { @ViewChild('autosize') autosize: CdkTextareaAutosize; @Input() placeholder: string; diff --git a/alfa-client/libs/ui/src/lib/ui/expansion-panel/expansion-panel.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/expansion-panel/expansion-panel.component.spec.ts index 4f5bc141b8ff9bbb08eaf3969caa702a88c12ec7..f8b285231242f9377479de52bdb11307422cb136 100644 --- a/alfa-client/libs/ui/src/lib/ui/expansion-panel/expansion-panel.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/expansion-panel/expansion-panel.component.spec.ts @@ -23,12 +23,7 @@ */ import { PortalModule } from '@angular/cdk/portal'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - MatAccordion, - MatExpansionPanel, - MatExpansionPanelHeader, - MatExpansionPanelTitle, -} from '@angular/material/expansion'; +import { MatAccordion, MatExpansionPanel, MatExpansionPanelHeader, MatExpansionPanelTitle } from '@angular/material/expansion'; import { MatIcon } from '@angular/material/icon'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { ExpansionPanelComponent } from './expansion-panel.component'; @@ -47,8 +42,8 @@ describe('VorgangDetailExpansionPanelComponent', () => { MatAccordion, MatIcon, MatExpansionPanelHeader, + ExpansionPanelComponent, ], - declarations: [ExpansionPanelComponent], }).compileComponents(); }); diff --git a/alfa-client/libs/ui/src/lib/ui/expansion-panel/expansion-panel.component.ts b/alfa-client/libs/ui/src/lib/ui/expansion-panel/expansion-panel.component.ts index 451efa23326b6f5d0cfbed82263a40282170c1fa..c1056c852eeb7440011bf8d9c3aa0ccf03f3764a 100644 --- a/alfa-client/libs/ui/src/lib/ui/expansion-panel/expansion-panel.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/expansion-panel/expansion-panel.component.ts @@ -21,12 +21,18 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { NgStyle } from '@angular/common'; import { Component, Input } from '@angular/core'; +import { MatIconButton } from '@angular/material/button'; +import { MatAccordion, MatExpansionPanel, MatExpansionPanelHeader, MatExpansionPanelTitle } from '@angular/material/expansion'; +import { MatIcon } from '@angular/material/icon'; @Component({ selector: 'ozgcloud-expansion-panel', templateUrl: './expansion-panel.component.html', styleUrls: ['./expansion-panel.component.scss'], + standalone: true, + imports: [MatAccordion, MatExpansionPanel, MatExpansionPanelHeader, MatExpansionPanelTitle, MatIconButton, MatIcon, NgStyle], }) export class ExpansionPanelComponent { @Input() headline: string; diff --git a/alfa-client/libs/ui/src/lib/ui/file-upload/file-upload.component.html b/alfa-client/libs/ui/src/lib/ui/file-upload/file-upload.component.html index 3421e957279595f13a6c27001c7437ef9416ebb6..6cd69f6200e7cfb864bce83488cf60467d90aad3 100644 --- a/alfa-client/libs/ui/src/lib/ui/file-upload/file-upload.component.html +++ b/alfa-client/libs/ui/src/lib/ui/file-upload/file-upload.component.html @@ -1,40 +1,34 @@ <!-- - Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - Ministerpräsidenten des Landes Schleswig-Holstein - Staatskanzlei - Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den +Ministerpräsidenten des Landes Schleswig-Holstein +Staatskanzlei +Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - Lizenziert unter der EUPL, Version 1.2 oder - sobald - diese von der Europäischen Kommission genehmigt wurden - - Folgeversionen der EUPL ("Lizenz"); - Sie dürfen dieses Werk ausschließlich gemäß - dieser Lizenz nutzen. - Eine Kopie der Lizenz finden Sie hier: +Lizenziert unter der EUPL, Version 1.2 oder - sobald +diese von der Europäischen Kommission genehmigt wurden - +Folgeversionen der EUPL ("Lizenz"); +Sie dürfen dieses Werk ausschließlich gemäß +dieser Lizenz nutzen. +Eine Kopie der Lizenz finden Sie hier: - https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - Sofern nicht durch anwendbare Rechtsvorschriften - gefordert oder in schriftlicher Form vereinbart, wird - die unter der Lizenz verbreitete Software "so wie sie - ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - ausdrücklich oder stillschweigend - verbreitet. - Die sprachspezifischen Genehmigungen und Beschränkungen - unter der Lizenz sind dem Lizenztext zu entnehmen. +Sofern nicht durch anwendbare Rechtsvorschriften +gefordert oder in schriftlicher Form vereinbart, wird +die unter der Lizenz verbreitete Software "so wie sie +ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +ausdrücklich oder stillschweigend - verbreitet. +Die sprachspezifischen Genehmigungen und Beschränkungen +unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<ng-container *ngIf="uploadInProgress$ | async as uploadInProgress"> - <input - data-test-id="file-upload-input" - [id]="myId" - type="file" - [accept]="accept" - (change)="onFileChanged($event)" - /> +@if (uploadInProgress$ | async; as uploadInProgress) { + <input data-test-id="file-upload-input" [id]="myId" type="file" [accept]="accept" (change)="onFileChanged($event)" /> <label [attr.for]="myId" matRipple aria-label="Anhang hinzufügen"> - <mat-icon *ngIf="!uploadInProgress.loading">attach_file</mat-icon> - - <ozgcloud-spinner [stateResource]="uploadInProgress" [diameter]="22" padding="0"> - </ozgcloud-spinner> + @if (!uploadInProgress.loading) { + <mat-icon>attach_file</mat-icon> + } + <ozgcloud-spinner [stateResource]="uploadInProgress" [diameter]="22" padding="0"> </ozgcloud-spinner> </label> -</ng-container> +} diff --git a/alfa-client/libs/ui/src/lib/ui/file-upload/file-upload.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/file-upload/file-upload.component.spec.ts index b823f373c545cdc4aeee52bf6a8948914942608c..a8ead2a90d69f7d2c78fab8d2f929b20d0b21c50 100644 --- a/alfa-client/libs/ui/src/lib/ui/file-upload/file-upload.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/file-upload/file-upload.component.spec.ts @@ -23,10 +23,10 @@ */ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FileUploadComponent } from './file-upload.component'; +import { SpinnerComponent } from '@alfa-client/ui'; import { MatIcon } from '@angular/material/icon'; import { MockComponent } from 'ng-mocks'; -import { SpinnerComponent } from '@alfa-client/ui'; +import { FileUploadComponent } from './file-upload.component'; describe('FileUploadComponent', () => { let component: FileUploadComponent; @@ -34,7 +34,7 @@ describe('FileUploadComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [FileUploadComponent, MatIcon, MockComponent(SpinnerComponent)], + imports: [FileUploadComponent, MatIcon, MockComponent(SpinnerComponent)], }).compileComponents(); }); diff --git a/alfa-client/libs/ui/src/lib/ui/file-upload/file-upload.component.ts b/alfa-client/libs/ui/src/lib/ui/file-upload/file-upload.component.ts index cfafed7120d1cc08ad23b9a6e9ccee79067d6d62..37c1e62075effcb3be1de49b949d143e7e439cc7 100644 --- a/alfa-client/libs/ui/src/lib/ui/file-upload/file-upload.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/file-upload/file-upload.component.ts @@ -21,15 +21,21 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, EventEmitter, Input, Output } from '@angular/core'; import { StateResource } from '@alfa-client/tech-shared'; +import { AsyncPipe } from '@angular/common'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { MatRipple } from '@angular/material/core'; +import { MatIcon } from '@angular/material/icon'; import { uniqueId } from 'lodash-es'; import { Observable } from 'rxjs'; +import { SpinnerComponent } from '../spinner/spinner.component'; @Component({ selector: 'ozgcloud-file-upload', templateUrl: './file-upload.component.html', styleUrls: ['./file-upload.component.scss'], + standalone: true, + imports: [MatRipple, MatIcon, SpinnerComponent, AsyncPipe], }) export class FileUploadComponent { @Input() accept: string = '*/*'; diff --git a/alfa-client/libs/ui/src/lib/ui/fixed-dialog/fixed-dialog.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/fixed-dialog/fixed-dialog.component.spec.ts index f74f63c0b94e179f81f32830d8ef6af5d26d7b31..119257aa82d807ddea222ba3f2534ff3a348484d 100644 --- a/alfa-client/libs/ui/src/lib/ui/fixed-dialog/fixed-dialog.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/fixed-dialog/fixed-dialog.component.spec.ts @@ -32,8 +32,7 @@ describe('FixedDialogComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [MatDialogModule, MatIcon], - declarations: [FixedDialogComponent], + imports: [MatDialogModule, MatIcon, FixedDialogComponent], providers: [ { provide: MatDialogRef, diff --git a/alfa-client/libs/ui/src/lib/ui/fixed-dialog/fixed-dialog.component.ts b/alfa-client/libs/ui/src/lib/ui/fixed-dialog/fixed-dialog.component.ts index 0a0d03890fdb4837814cc105643b81ce5277239d..a4bb9d6af8e17ec21ca27cab2fdc2027ea4d3595 100644 --- a/alfa-client/libs/ui/src/lib/ui/fixed-dialog/fixed-dialog.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/fixed-dialog/fixed-dialog.component.ts @@ -21,26 +21,32 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Inject, Injector } from '@angular/core'; -import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { NgClass, NgComponentOutlet } from '@angular/common'; +import { Component, inject, Injector, OnInit } from '@angular/core'; +import { MatIconButton } from '@angular/material/button'; +import { MAT_DIALOG_DATA, MatDialogClose, MatDialogContent, MatDialogTitle } from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; import { FixedDialogData } from './fixed-dialog-data.model'; @Component({ selector: 'ozgcloud-fixed-dialog', templateUrl: './fixed-dialog.component.html', + standalone: true, + imports: [MatDialogTitle, MatIconButton, NgClass, MatIcon, MatDialogClose, CdkScrollable, MatDialogContent, NgComponentOutlet], }) -export class FixedDialogComponent { +export class FixedDialogComponent implements OnInit { + public data = inject<FixedDialogData>(MAT_DIALOG_DATA); + private injector = inject(Injector); + componentInjector: Injector; isMinimized: boolean; - constructor( - @Inject(MAT_DIALOG_DATA) public data: FixedDialogData, - injector: Injector, - ) { + ngOnInit(): void { this.componentInjector = Injector.create({ providers: [], - parent: injector, + parent: this.injector, }); } diff --git a/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component.spec.ts index 29d0ea1951593261b40071943e1f45a5016a9371..650e50ec93147e8958d2727ec40dc1ebc0fd906b 100644 --- a/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component.spec.ts @@ -21,10 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatDialogModule } from '@angular/material/dialog'; import { MatIcon } from '@angular/material/icon'; -import { OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; import { MockComponent } from 'ng-mocks'; import { ConnectionTimeoutRetryDialogComponent } from './connection-timeout-retry-dialog.component'; @@ -34,8 +34,8 @@ describe('ConnectionTimeoutRetryDialogComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [MatDialogModule], - declarations: [ + imports: [ + MatDialogModule, ConnectionTimeoutRetryDialogComponent, MatIcon, MockComponent(OzgcloudStrokedButtonWithSpinnerComponent), diff --git a/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component.ts b/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component.ts index eb209e7c7b10c791b2252a93823748739558a813..c2cc728cf695acc35facdf24b8f87e6e6fd8bdf9 100644 --- a/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component.ts @@ -21,11 +21,16 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { CdkScrollable } from '@angular/cdk/scrolling'; import { Component } from '@angular/core'; +import { MatDialogContent, MatDialogTitle } from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; @Component({ selector: 'ozgcloud-connection-timeout-retry-dialog', templateUrl: './connection-timeout-retry-dialog.component.html', styleUrls: ['./connection-timeout-retry-dialog.component.scss'], + standalone: true, + imports: [MatDialogTitle, MatIcon, CdkScrollable, MatDialogContent], }) export class ConnectionTimeoutRetryDialogComponent {} diff --git a/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component.spec.ts index 42d3c9febfeeb164d2561b4d68dbbbb5f49dd895..6c41b694c5489b832e31696fe38554ce0cb76011 100644 --- a/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component.spec.ts @@ -21,10 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatDialogModule } from '@angular/material/dialog'; import { MatIcon } from '@angular/material/icon'; -import { OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; import { MockComponent } from 'ng-mocks'; import { ConnectionTimeoutRetryFailDialogComponent } from './connection-timeout-retry-fail-dialog.component'; @@ -34,8 +34,8 @@ describe('ConnectionTimeoutRetryFailDialogComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [MatDialogModule], - declarations: [ + imports: [ + MatDialogModule, ConnectionTimeoutRetryFailDialogComponent, MatIcon, MockComponent(OzgcloudStrokedButtonWithSpinnerComponent), diff --git a/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component.ts b/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component.ts index 858098b7e7ded139ba3b18ecf5baa1c4aef4b92c..62646a5aadf7797653253d18a866b7a33d09fe7d 100644 --- a/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component.ts @@ -21,12 +21,18 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { CdkScrollable } from '@angular/cdk/scrolling'; import { Component } from '@angular/core'; +import { MatDialogContent, MatDialogTitle } from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { OzgcloudStrokedButtonWithSpinnerComponent } from '../../ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component'; @Component({ selector: 'ozgcloud-connection-timeout-retry-fail-dialog', templateUrl: './connection-timeout-retry-fail-dialog.component.html', styleUrls: ['./connection-timeout-retry-fail-dialog.component.scss'], + standalone: true, + imports: [MatDialogTitle, MatIcon, CdkScrollable, MatDialogContent, OzgcloudStrokedButtonWithSpinnerComponent], }) export class ConnectionTimeoutRetryFailDialogComponent { reload(): void { diff --git a/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.html b/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.html index 1bb8fb6c9424bb9fb420a5f0007d61a88ffe6beb..ce20ce0990fb781b6eb31e3ce4247c1b3a4f9ca2 100644 --- a/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.html +++ b/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.html @@ -33,11 +33,15 @@ (click)="clickEmitter.emit($event)" type="button" > - <mat-icon *ngIf="icon" data-test-class="icon" [style.visibility]="isDisabled ? 'hidden' : 'visible'"> - {{ icon }} - </mat-icon> + @if (icon) { + <mat-icon data-test-class="icon" [style.visibility]="isDisabled ? 'hidden' : 'visible'"> + {{ icon }} + </mat-icon> + } - <mat-icon *ngIf="svgIcon" data-test-class="icon" [svgIcon]="svgIcon" [style.visibility]="isDisabled ? 'hidden' : 'visible'" /> + @if (svgIcon) { + <mat-icon data-test-class="icon" [svgIcon]="svgIcon" [style.visibility]="isDisabled ? 'hidden' : 'visible'" /> + } <ozgcloud-spinner [stateResource]="getStateResource()" [diameter]="22" [show]="showSpinner" padding="0" /> </button> diff --git a/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.spec.ts index 7cf06e5752ca8ebf4c3b0b797b97631bc3e04c25..365f71d7a8d7a2f24ddbe67e18e6a785b445f9a2 100644 --- a/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.spec.ts @@ -26,7 +26,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatIcon } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; import { TooltipDirective } from '@ods/system'; -import { MockComponent, MockDirective, MockModule } from 'ng-mocks'; +import { MockComponent, MockDirective } from 'ng-mocks'; import { SpinnerComponent } from '../spinner/spinner.component'; import { IconButtonWithSpinnerComponent } from './icon-button-with-spinner.component'; @@ -37,15 +37,10 @@ describe('IconButtonWithSpinnerComponent', () => { const buttonSelector = '[data-test-class="icon-button"]'; const iconSelector = '[data-test-class="icon"]'; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - IconButtonWithSpinnerComponent, - MatIcon, - MockComponent(SpinnerComponent), - MockDirective(TooltipDirective), - MockModule(MatMenuModule), - ], + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [IconButtonWithSpinnerComponent, MatIcon, MatMenuModule], + declarations: [MockComponent(SpinnerComponent), MockDirective(TooltipDirective)], }); }); diff --git a/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.ts b/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.ts index e2b8c90813ed8a2a6bf5a29ed86055569895b5ef..f83e6bfcc75341f27eaa8baa149a9c65f3fa7c57 100644 --- a/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.ts @@ -23,13 +23,21 @@ */ import { StateResource, createEmptyStateResource } from '@alfa-client/tech-shared'; import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatMenuTrigger } from '@angular/material/menu'; +import { MatTooltip } from '@angular/material/tooltip'; import { Resource } from '@ngxp/rest'; +import { TooltipDirective } from '@ods/system'; import { isNil } from 'lodash-es'; +import { SpinnerComponent } from '../spinner/spinner.component'; @Component({ selector: 'ozgcloud-icon-button-with-spinner', templateUrl: './icon-button-with-spinner.component.html', styleUrls: ['./icon-button-with-spinner.component.scss'], + standalone: true, + imports: [MatIconButton, MatTooltip, MatMenuTrigger, MatIcon, SpinnerComponent, TooltipDirective], }) export class IconButtonWithSpinnerComponent { @Input() icon: string; diff --git a/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.html b/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.html index 3ffd5acf9942d680fec448cb79b10ed6017e7b9f..7c9621388efb76c4ae8bea4640288b1ac1264150 100644 --- a/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.html +++ b/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.html @@ -1,26 +1,26 @@ <!-- - Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - Ministerpräsidenten des Landes Schleswig-Holstein - Staatskanzlei - Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den +Ministerpräsidenten des Landes Schleswig-Holstein +Staatskanzlei +Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - Lizenziert unter der EUPL, Version 1.2 oder - sobald - diese von der Europäischen Kommission genehmigt wurden - - Folgeversionen der EUPL ("Lizenz"); - Sie dürfen dieses Werk ausschließlich gemäß - dieser Lizenz nutzen. - Eine Kopie der Lizenz finden Sie hier: +Lizenziert unter der EUPL, Version 1.2 oder - sobald +diese von der Europäischen Kommission genehmigt wurden - +Folgeversionen der EUPL ("Lizenz"); +Sie dürfen dieses Werk ausschließlich gemäß +dieser Lizenz nutzen. +Eine Kopie der Lizenz finden Sie hier: - https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - Sofern nicht durch anwendbare Rechtsvorschriften - gefordert oder in schriftlicher Form vereinbart, wird - die unter der Lizenz verbreitete Software "so wie sie - ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - ausdrücklich oder stillschweigend - verbreitet. - Die sprachspezifischen Genehmigungen und Beschränkungen - unter der Lizenz sind dem Lizenztext zu entnehmen. +Sofern nicht durch anwendbare Rechtsvorschriften +gefordert oder in schriftlicher Form vereinbart, wird +die unter der Lizenz verbreitete Software "so wie sie +ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +ausdrücklich oder stillschweigend - verbreitet. +Die sprachspezifischen Genehmigungen und Beschränkungen +unter der Lizenz sind dem Lizenztext zu entnehmen. --> <h1 mat-dialog-title> @@ -30,14 +30,13 @@ <mat-dialog-content> <p data-test-id="error-message" class="error-message"> Wir sind nicht ganz sicher, was schiefgelaufen ist. Der Fehler - <span *ngIf="showId()">(ID: {{ data.issues[0].exceptionId }})</span> wurde unserem Support - gemeldet. Bitte starten sie die Anwendung neu. + @if (showId()) { + <span>(ID: {{ data.issues[0].exceptionId }})</span> + } + wurde unserem Support gemeldet. Bitte starten sie die Anwendung neu. </p> <a href="/" tabindex="-1" class="button"> - <ozgcloud-stroked-button-with-spinner - icon="refresh" - text="Neu starten" - ></ozgcloud-stroked-button-with-spinner> + <ozgcloud-stroked-button-with-spinner icon="refresh" text="Neu starten"></ozgcloud-stroked-button-with-spinner> </a> <ozgcloud-stroked-button-with-spinner icon="logout" diff --git a/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.spec.ts index ebc6907e4a0ecc725e963035137e93c5649ef558..3eb87f3f9084ad31fbd7bd508b208ec917edee1d 100644 --- a/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.spec.ts @@ -21,12 +21,12 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { mock } from '@alfa-client/test-utils'; +import { OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { MatIcon } from '@angular/material/icon'; import { faker } from '@faker-js/faker'; -import { mock } from '@alfa-client/test-utils'; -import { OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; import { OAuthService } from 'angular-oauth2-oidc'; import { createIssue } from 'libs/tech-shared/test/error'; import { MockComponent } from 'ng-mocks'; @@ -40,12 +40,12 @@ describe('InternalServerErrorDialogComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ + imports: [ + MatDialogModule, InternalServerErrorDialogComponent, MatIcon, MockComponent(OzgcloudStrokedButtonWithSpinnerComponent), ], - imports: [MatDialogModule], providers: [ { provide: MatDialogRef, @@ -83,9 +83,7 @@ describe('InternalServerErrorDialogComponent', () => { dialogData = { error: { ...{ issues: [createIssue()] }, id: exceptionId } }; fixture.detectChanges(); - expect(fixture.nativeElement).not.toHaveTextContent( - `ID: ${dialogData.error.issues[0].exceptionId}`, - ); + expect(fixture.nativeElement).not.toHaveTextContent(`ID: ${dialogData.error.issues[0].exceptionId}`); }); }); }); diff --git a/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.ts b/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.ts index cfcbff45dbacdbb63cff491fec6ac4226bbca0e5..e55158c9e1e892cd4d863842d64897b7aa82341c 100644 --- a/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.ts @@ -21,21 +21,24 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA } from '@angular/material/dialog'; import { ApiError, hasExceptionId } from '@alfa-client/tech-shared'; +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { Component, inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogContent, MatDialogTitle } from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; import { OAuthService } from 'angular-oauth2-oidc'; +import { OzgcloudStrokedButtonWithSpinnerComponent } from '../../ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component'; @Component({ selector: 'ozgcloud-internal-server-error-dialog', templateUrl: './internal-server-error-dialog.component.html', styleUrls: ['./internal-server-error-dialog.component.scss'], + standalone: true, + imports: [MatDialogTitle, MatIcon, CdkScrollable, MatDialogContent, OzgcloudStrokedButtonWithSpinnerComponent], }) export class InternalServerErrorDialogComponent { - constructor( - @Inject(MAT_DIALOG_DATA) public data: ApiError, - public authService: OAuthService, - ) {} + public data: ApiError = inject<ApiError>(MAT_DIALOG_DATA); + public authService = inject(OAuthService); showId(): boolean { return hasExceptionId(this.data); diff --git a/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.spec.ts index f5fbf2d6c35beb79bccaf3e8c87c0e62f0fd3e00..b53d242247b71270aa5585099561d595492f51cd 100644 --- a/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.spec.ts @@ -23,8 +23,8 @@ */ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { OpenUrlButtonComponent } from './open-url-button.component'; import { MockComponent } from 'ng-mocks'; +import { OpenUrlButtonComponent } from './open-url-button.component'; describe('OpenUrlButtonComponent', () => { let component: OpenUrlButtonComponent; @@ -32,7 +32,7 @@ describe('OpenUrlButtonComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [OpenUrlButtonComponent, MockComponent(OpenUrlButtonComponent)], + imports: [OpenUrlButtonComponent, MockComponent(OpenUrlButtonComponent)], }).compileComponents(); fixture = TestBed.createComponent(OpenUrlButtonComponent); diff --git a/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.ts b/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.ts index 4663a18ab9485c6db0358a3ad4f2203c950548f4..f080acaa278a60d150fa32083f2be3ecd8325b69 100644 --- a/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.ts @@ -22,11 +22,16 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Component, Input } from '@angular/core'; +import { MatAnchor } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; @Component({ selector: 'ozgcloud-open-url-button', templateUrl: './open-url-button.component.html', styleUrls: ['./open-url-button.component.scss'], + standalone: true, + imports: [MatAnchor, MatTooltip, MatIcon], }) export class OpenUrlButtonComponent { @Input() icon: string; diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.spec.ts index ee97fa55891a3b5ea04917c80ea255458f58d68b..5447abd13a916be618548326cef55e254a232963 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.spec.ts @@ -41,7 +41,7 @@ describe('OzgcloudButtonWithSpinnerComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ + imports: [ MatButton, MatRipple, OzgcloudButtonWithSpinnerComponent, diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.ts index 497704e4b948a92527d4cdaf02050658142a1aaf..fb46489bd43247e86059d332972cabfd88db9364 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.ts @@ -21,15 +21,21 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { StateResource, createEmptyStateResource } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { MatButton } from '@angular/material/button'; +import { MatTooltip } from '@angular/material/tooltip'; import { Resource } from '@ngxp/rest'; +import { TooltipDirective } from '@ods/system'; import { isNil } from 'lodash-es'; +import { OzgcloudButtonContentComponent } from '../shared/ozgcloud-button-content/ozgcloud-button-content.component'; @Component({ selector: 'ozgcloud-button-with-spinner', templateUrl: './ozgcloud-button-with-spinner.component.html', styleUrls: ['./ozgcloud-button-with-spinner.component.scss'], + standalone: true, + imports: [MatButton, MatTooltip, OzgcloudButtonContentComponent, TooltipDirective], }) export class OzgcloudButtonWithSpinnerComponent implements OnInit { @Input() icon: string; diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.spec.ts index 976c0b0c396b7dfc68b3f7e53148d1d75cf1baa8..48f65db0143ecaf0c0e6a564f1f6cd1619092934 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.spec.ts @@ -61,10 +61,7 @@ describe('IconButtonPrimaryWithSpinnerComponent', () => { it('should create aria label', () => { component.ngOnInit(); - expect(createAriaLabelForIconButtonMock).toHaveBeenCalledWith( - component.tooltip, - component.svgIcon, - ); + expect(createAriaLabelForIconButtonMock).toHaveBeenCalledWith(component.tooltip, component.svgIcon); }); it('should set aria label', () => { diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.ts index f6dd2b5094a3d5521945be70c70d6d2ac88192dd..d5fc959cc46fcc27629b9e8c48555d26cb877146 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.ts @@ -21,14 +21,20 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { createAriaLabelForIconButton, StateResource } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; import { Resource } from '@ngxp/rest'; +import { TooltipDirective } from '@ods/system'; @Component({ selector: 'ozgcloud-icon-button-primary', templateUrl: './ozgcloud-icon-button-primary.component.html', styleUrls: ['./ozgcloud-icon-button-primary.component.scss'], + standalone: true, + imports: [MatIconButton, MatTooltip, MatIcon, TooltipDirective], }) export class OzgcloudIconButtonPrimaryComponent implements OnInit { @Input() svgIcon: string; diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.spec.ts index 208868555e600c7fd81f6edc4bd1e8fd541827e6..ac0307f0125ad487682e40acba742c9245774b94 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.spec.ts @@ -41,7 +41,7 @@ describe('OzgcloudStrokedButtonWithSpinnerComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ + imports: [ MatButton, MatRipple, OzgcloudStrokedButtonWithSpinnerComponent, diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.ts index 218915f94f34808e4423af8fbffec4ee4c180349..36f102a0d7d92d5953a97f1a7b47caa9988b4591 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.ts @@ -21,15 +21,21 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { StateResource, createEmptyStateResource } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { MatButton } from '@angular/material/button'; +import { MatTooltip } from '@angular/material/tooltip'; import { Resource } from '@ngxp/rest'; +import { TooltipDirective } from '@ods/system'; import { isNil } from 'lodash-es'; +import { OzgcloudButtonContentComponent } from '../shared/ozgcloud-button-content/ozgcloud-button-content.component'; @Component({ selector: 'ozgcloud-stroked-button-with-spinner', templateUrl: './ozgcloud-stroked-button-with-spinner.component.html', styleUrls: ['./ozgcloud-stroked-button-with-spinner.component.scss'], + standalone: true, + imports: [MatButton, MatTooltip, OzgcloudButtonContentComponent, TooltipDirective], }) export class OzgcloudStrokedButtonWithSpinnerComponent implements OnInit { @Input() icon: string; diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.html b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.html index 168a6bfdaae0891449b9dd1d88b57edb7662325d..88d174c6a844f216987f40801c6e7c6cfcc35b76 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.html +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.html @@ -1,47 +1,46 @@ <!-- - Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - Ministerpräsidenten des Landes Schleswig-Holstein - Staatskanzlei - Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - - Lizenziert unter der EUPL, Version 1.2 oder - sobald - diese von der Europäischen Kommission genehmigt wurden - - Folgeversionen der EUPL ("Lizenz"); - Sie dürfen dieses Werk ausschließlich gemäß - dieser Lizenz nutzen. - Eine Kopie der Lizenz finden Sie hier: - - https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - - Sofern nicht durch anwendbare Rechtsvorschriften - gefordert oder in schriftlicher Form vereinbart, wird - die unter der Lizenz verbreitete Software "so wie sie - ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - ausdrücklich oder stillschweigend - verbreitet. - Die sprachspezifischen Genehmigungen und Beschränkungen - unter der Lizenz sind dem Lizenztext zu entnehmen. +Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den +Ministerpräsidenten des Landes Schleswig-Holstein +Staatskanzlei +Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + +Lizenziert unter der EUPL, Version 1.2 oder - sobald +diese von der Europäischen Kommission genehmigt wurden - +Folgeversionen der EUPL ("Lizenz"); +Sie dürfen dieses Werk ausschließlich gemäß +dieser Lizenz nutzen. +Eine Kopie der Lizenz finden Sie hier: + +https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + +Sofern nicht durch anwendbare Rechtsvorschriften +gefordert oder in schriftlicher Form vereinbart, wird +die unter der Lizenz verbreitete Software "so wie sie +ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +ausdrücklich oder stillschweigend - verbreitet. +Die sprachspezifischen Genehmigungen und Beschränkungen +unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<mat-icon - *ngIf="icon" - data-test-class="icon" - [class.with-text]="text" - [style.visibility]="isDisabled ? 'hidden' : 'visible'" -> - {{ icon }} -</mat-icon> - -<mat-icon - *ngIf="svgIcon" - data-test-class="icon" - [class.with-text]="text" - [svgIcon]="svgIcon" - [style.visibility]="isDisabled ? 'hidden' : 'visible'" -> -</mat-icon> - -<span *ngIf="text" class="text-sm" data-test-class="button-with-spinner-text">{{ text }}</span> - -<ozgcloud-spinner [diameter]="22" padding="0" [stateResource]="stateResource" [show]="showSpinner"> -</ozgcloud-spinner> +@if (icon) { + <mat-icon data-test-class="icon" [class.with-text]="text" [style.visibility]="isDisabled ? 'hidden' : 'visible'"> + {{ icon }} + </mat-icon> +} + +@if (svgIcon) { + <mat-icon + data-test-class="icon" + [class.with-text]="text" + [svgIcon]="svgIcon" + [style.visibility]="isDisabled ? 'hidden' : 'visible'" + > + </mat-icon> +} + +@if (text) { + <span class="text-sm" data-test-class="button-with-spinner-text">{{ text }}</span> +} + +<ozgcloud-spinner [diameter]="22" padding="0" [stateResource]="stateResource" [show]="showSpinner"> </ozgcloud-spinner> diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.spec.ts index 0a313a7ef672ecb3b215ce916ed709cb9aa83cb4..14e079e54c2bc4faa5cb355342b24850d15e9acc 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.spec.ts @@ -37,7 +37,7 @@ describe('OzgcloudButtonContentComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [MatIcon, MockComponent(SpinnerComponent), OzgcloudButtonContentComponent], + imports: [MatIcon, MockComponent(SpinnerComponent), OzgcloudButtonContentComponent], }).compileComponents(); fixture = TestBed.createComponent(OzgcloudButtonContentComponent); diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.ts index 32283456c72d2ffd653f89880ac1f42c789f9a79..4e2b5fec9f852c47df972ecaaa22531ca7a25069 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.ts @@ -21,14 +21,18 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Input } from '@angular/core'; import { StateResource } from '@alfa-client/tech-shared'; +import { Component, Input } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; import { Resource } from '@ngxp/rest'; +import { SpinnerComponent } from '../../../spinner/spinner.component'; @Component({ selector: 'ozgcloud-button-content', templateUrl: './ozgcloud-button-content.component.html', styleUrls: ['./ozgcloud-button-content.component.scss'], + standalone: true, + imports: [MatIcon, SpinnerComponent], }) export class OzgcloudButtonContentComponent { @Input() icon: string; diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.ts index da2fb2923e846b00101f7dca2dab0500a8a5c971..077780a3e1d01c0e198efc1de9f12244315b1194 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.ts @@ -23,13 +23,15 @@ */ import { Dialog, DialogConfig, DialogRef } from '@angular/cdk/dialog'; import { ComponentType } from '@angular/cdk/portal'; -import { Injectable, ViewContainerRef } from '@angular/core'; +import { inject, Injectable, ViewContainerRef } from '@angular/core'; import { isNil } from 'lodash-es'; @Injectable({ providedIn: 'root', }) export class OzgcloudDialogService { + private dialog = inject(Dialog); + readonly WIZARD_DIALOG_CONFIG: DialogConfig = { width: '1000px', restoreFocus: false, @@ -41,8 +43,6 @@ export class OzgcloudDialogService { disableClose: true, }; - constructor(private dialog: Dialog) {} - public openWizard<C, D, R = unknown>(component: ComponentType<C>, data?: D): DialogRef<R> { return this.openDialog<C, R>(component, this.buildDialogConfigWithData<D>(data, this.WIZARD_DIALOG_CONFIG)); } diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-icon/ozgcloud-icon.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-icon/ozgcloud-icon.component.spec.ts index 2f46c2cd4b354c756077397db94a28bb07382214..348a842ef697927273e2af4f7fe4337735b53e6f 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-icon/ozgcloud-icon.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-icon/ozgcloud-icon.component.spec.ts @@ -31,8 +31,7 @@ describe('OzgcloudIconComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [OzgcloudIconComponent], - imports: [MatIcon], + imports: [MatIcon, OzgcloudIconComponent], }).compileComponents(); fixture = TestBed.createComponent(OzgcloudIconComponent); diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-icon/ozgcloud-icon.component.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-icon/ozgcloud-icon.component.ts index 888c31801bbcf6a6c03fda6f6ed43d9529fbd0bb..b2e99d1f83445d4f007910fe6986c749f2600808 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-icon/ozgcloud-icon.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-icon/ozgcloud-icon.component.ts @@ -22,11 +22,14 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Component, Input } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; @Component({ selector: 'ozgcloud-icon', templateUrl: './ozgcloud-icon.component.html', styleUrls: ['./ozgcloud-icon.component.scss'], + standalone: true, + imports: [MatIcon], }) export class OzgcloudIconComponent { @Input() icon: string; diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-menu/ozgcloud-menu.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-menu/ozgcloud-menu.component.spec.ts index e967e79c2ae45c7305d4255e199f52f27220fa4e..454e44cb8d1cbbb063e1228cda44e601a1423053 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-menu/ozgcloud-menu.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-menu/ozgcloud-menu.component.spec.ts @@ -31,8 +31,7 @@ describe('OzgcloudMenuComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [OzgcloudMenuComponent], - imports: [MatMenuModule], + imports: [MatMenuModule, OzgcloudMenuComponent], }).compileComponents(); fixture = TestBed.createComponent(OzgcloudMenuComponent); diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-menu/ozgcloud-menu.component.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-menu/ozgcloud-menu.component.ts index bd007c306911e007bc515da3fab56fcc2ebc9a52..d267a8ffe01c0d07ff12b0e83d699140856b25bf 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-menu/ozgcloud-menu.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-menu/ozgcloud-menu.component.ts @@ -28,6 +28,8 @@ import { MatMenu } from '@angular/material/menu'; selector: 'ozgcloud-menu', templateUrl: './ozgcloud-menu.component.html', styleUrls: ['./ozgcloud-menu.component.scss'], + standalone: true, + imports: [MatMenu], }) export class OzgcloudMenuComponent { @ViewChild('menu', { static: true }) matMenu: MatMenu; diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.html b/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.html index 604b9441202c5c72a07489dc8715d69c339cb489..f6dd97a4e59aad87b62bc7cfa87277a51dbdd9e5 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.html +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.html @@ -1,34 +1,35 @@ <!-- - Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den - Ministerpräsidenten des Landes Schleswig-Holstein - Staatskanzlei - Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +Ministerpräsidenten des Landes Schleswig-Holstein +Staatskanzlei +Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - Lizenziert unter der EUPL, Version 1.2 oder - sobald - diese von der Europäischen Kommission genehmigt wurden - - Folgeversionen der EUPL ("Lizenz"); - Sie dürfen dieses Werk ausschließlich gemäß - dieser Lizenz nutzen. - Eine Kopie der Lizenz finden Sie hier: +Lizenziert unter der EUPL, Version 1.2 oder - sobald +diese von der Europäischen Kommission genehmigt wurden - +Folgeversionen der EUPL ("Lizenz"); +Sie dürfen dieses Werk ausschließlich gemäß +dieser Lizenz nutzen. +Eine Kopie der Lizenz finden Sie hier: - https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - Sofern nicht durch anwendbare Rechtsvorschriften - gefordert oder in schriftlicher Form vereinbart, wird - die unter der Lizenz verbreitete Software "so wie sie - ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - ausdrücklich oder stillschweigend - verbreitet. - Die sprachspezifischen Genehmigungen und Beschränkungen - unter der Lizenz sind dem Lizenztext zu entnehmen. +Sofern nicht durch anwendbare Rechtsvorschriften +gefordert oder in schriftlicher Form vereinbart, wird +die unter der Lizenz verbreitete Software "so wie sie +ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +ausdrücklich oder stillschweigend - verbreitet. +Die sprachspezifischen Genehmigungen und Beschränkungen +unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<ozgcloud-icon-button-primary - *ngIf="isPasteSupported" - [tooltip]="tooltip" - svgIcon="paste_from_clipboard" - class="paste_icon" - (clickEmitter)="onPaste()" - data-test-id="paste_from_clipboard" -> -</ozgcloud-icon-button-primary> +@if (isPasteSupported) { + <ozgcloud-icon-button-primary + [tooltip]="tooltip" + svgIcon="paste_from_clipboard" + class="paste_icon" + (clickEmitter)="onPaste()" + data-test-id="paste_from_clipboard" + > + </ozgcloud-icon-button-primary> +} diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.spec.ts index e91b91840bb1f855e5821d6eaac5949bc815181c..918ec8d7c1c8122a7f8fbf5489f3031e66f664bf 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.spec.ts @@ -50,8 +50,8 @@ describe('OzgcloudPasteTextButtonComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [MatIconTestingModule], - declarations: [ + imports: [ + MatIconTestingModule, OzgcloudPasteTextButtonComponent, MockComponent(MatIcon), MockComponent(OzgcloudIconButtonPrimaryComponent), diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.ts index de10060dbe49cd7f048adbf90f267b26a357d65f..3fa9c14b0b00126d3074923b4871ecf52594a4b1 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.ts @@ -21,13 +21,16 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { isClipboardReadSupported } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { OzgcloudIconButtonPrimaryComponent } from '../ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component'; @Component({ selector: 'ozgcloud-paste-text-button', templateUrl: './ozgcloud-paste-text-button.component.html', styleUrls: ['./ozgcloud-paste-text-button.component.scss'], + standalone: true, + imports: [OzgcloudIconButtonPrimaryComponent], }) export class OzgcloudPasteTextButtonComponent implements OnInit { @Input() tooltip: string; diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-routing-button/ozgcloud-routing-button.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-routing-button/ozgcloud-routing-button.component.spec.ts index e29ecd69fcee6fb293c466bdb7ff426d83666b4d..b789f1e69acc310ec87cedebd84a2cb2f3dad0a4 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-routing-button/ozgcloud-routing-button.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-routing-button/ozgcloud-routing-button.component.spec.ts @@ -31,8 +31,7 @@ describe('OzgcloudRoutingButtonComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [OzgcloudRoutingButtonComponent], - imports: [RouterTestingModule], + imports: [RouterTestingModule, OzgcloudRoutingButtonComponent], }).compileComponents(); fixture = TestBed.createComponent(OzgcloudRoutingButtonComponent); diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-routing-button/ozgcloud-routing-button.component.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-routing-button/ozgcloud-routing-button.component.ts index fa61fa8f609a3cc7129eaad33e8656bba754d345..92d82c8800f117c3bb8b1c9256880294c6cbc9cf 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-routing-button/ozgcloud-routing-button.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-routing-button/ozgcloud-routing-button.component.ts @@ -22,11 +22,15 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Component, Input } from '@angular/core'; +import { MatAnchor } from '@angular/material/button'; +import { RouterLink } from '@angular/router'; @Component({ selector: 'ozgcloud-routing-button', templateUrl: './ozgcloud-routing-button.component.html', styleUrls: ['./ozgcloud-routing-button.component.scss'], + standalone: true, + imports: [MatAnchor, RouterLink], }) export class OzgcloudRoutingButtonComponent { @Input() routerLinkPath: string; diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon-big/ozgcloud-svgicon-big.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon-big/ozgcloud-svgicon-big.component.spec.ts index 734f2aa0c6dabdf0b55381f37365e4f23a6002f6..6189dfc0e3720ac7d4dcfcaff706f181af7474e2 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon-big/ozgcloud-svgicon-big.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon-big/ozgcloud-svgicon-big.component.spec.ts @@ -31,8 +31,7 @@ describe('OzgcloudSvgIconBigComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [OzgcloudSvgIconBigComponent], - imports: [MatIcon], + imports: [MatIcon, OzgcloudSvgIconBigComponent], }).compileComponents(); fixture = TestBed.createComponent(OzgcloudSvgIconBigComponent); diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon-big/ozgcloud-svgicon-big.component.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon-big/ozgcloud-svgicon-big.component.ts index e99ad4a83f0a0bd6344267d353e06f994640f37b..5d7c397f0a5b0c8b0693da1b5ed8f012ec23b75b 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon-big/ozgcloud-svgicon-big.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon-big/ozgcloud-svgicon-big.component.ts @@ -22,11 +22,14 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Component, Input } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; @Component({ selector: 'ozgcloud-svgicon-big', templateUrl: './ozgcloud-svgicon-big.component.html', styleUrls: ['./ozgcloud-svgicon-big.component.scss'], + standalone: true, + imports: [MatIcon], }) export class OzgcloudSvgIconBigComponent { @Input() svgIcon: string; diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon/ozgcloud-svgicon.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon/ozgcloud-svgicon.component.spec.ts index 9ce6d63d48290d7145975d7ef01d570759571aa9..d3f63f4b2c1cb7be217ce69efbd180891efb496f 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon/ozgcloud-svgicon.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon/ozgcloud-svgicon.component.spec.ts @@ -31,8 +31,7 @@ describe('OzgcloudSvgIconComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [OzgcloudSvgIconComponent], - imports: [MatIcon], + imports: [MatIcon, OzgcloudSvgIconComponent], }).compileComponents(); fixture = TestBed.createComponent(OzgcloudSvgIconComponent); diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon/ozgcloud-svgicon.component.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon/ozgcloud-svgicon.component.ts index 7aa1d869fca7f17ad41926120aa9c5bf088bd5e8..c35c9ab18d1b5ede13f37f06f980dd88c0d2ce24 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon/ozgcloud-svgicon.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-svgicon/ozgcloud-svgicon.component.ts @@ -22,11 +22,14 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Component, Input } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; @Component({ selector: 'ozgcloud-svgicon', templateUrl: './ozgcloud-svgicon.component.html', styleUrls: ['./ozgcloud-svgicon.component.scss'], + standalone: true, + imports: [MatIcon], }) export class OzgcloudSvgIconComponent { @Input() svgIcon: string; diff --git a/alfa-client/libs/ui/src/lib/ui/progress-bar/progress-bar.component.html b/alfa-client/libs/ui/src/lib/ui/progress-bar/progress-bar.component.html index 6f992fe024c1d15d17114491373d81a50b8c0c20..3a7dda71335ccefb8982d0452826a35d8032de5d 100644 --- a/alfa-client/libs/ui/src/lib/ui/progress-bar/progress-bar.component.html +++ b/alfa-client/libs/ui/src/lib/ui/progress-bar/progress-bar.component.html @@ -1,28 +1,30 @@ <!-- - Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - Ministerpräsidenten des Landes Schleswig-Holstein - Staatskanzlei - Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den +Ministerpräsidenten des Landes Schleswig-Holstein +Staatskanzlei +Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - Lizenziert unter der EUPL, Version 1.2 oder - sobald - diese von der Europäischen Kommission genehmigt wurden - - Folgeversionen der EUPL ("Lizenz"); - Sie dürfen dieses Werk ausschließlich gemäß - dieser Lizenz nutzen. - Eine Kopie der Lizenz finden Sie hier: +Lizenziert unter der EUPL, Version 1.2 oder - sobald +diese von der Europäischen Kommission genehmigt wurden - +Folgeversionen der EUPL ("Lizenz"); +Sie dürfen dieses Werk ausschließlich gemäß +dieser Lizenz nutzen. +Eine Kopie der Lizenz finden Sie hier: - https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - Sofern nicht durch anwendbare Rechtsvorschriften - gefordert oder in schriftlicher Form vereinbart, wird - die unter der Lizenz verbreitete Software "so wie sie - ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - ausdrücklich oder stillschweigend - verbreitet. - Die sprachspezifischen Genehmigungen und Beschränkungen - unter der Lizenz sind dem Lizenztext zu entnehmen. +Sofern nicht durch anwendbare Rechtsvorschriften +gefordert oder in schriftlicher Form vereinbart, wird +die unter der Lizenz verbreitete Software "so wie sie +ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +ausdrücklich oder stillschweigend - verbreitet. +Die sprachspezifischen Genehmigungen und Beschränkungen +unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<div *ngIf="isVisible" class="progressbar-overlay" data-test-class="progressbar-overlay"> - <mat-progress-bar data-test-id="progress-bar" mode="indeterminate"></mat-progress-bar> -</div> +@if (isVisible) { + <div class="progressbar-overlay" data-test-class="progressbar-overlay"> + <mat-progress-bar data-test-id="progress-bar" mode="indeterminate"></mat-progress-bar> + </div> +} diff --git a/alfa-client/libs/ui/src/lib/ui/progress-bar/progress-bar.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/progress-bar/progress-bar.component.spec.ts index 87b2dca90e9adc2001bd595db8b24c924d93c9a4..a98db10dc48b1241047e761fd2f05a5d962d6c34 100644 --- a/alfa-client/libs/ui/src/lib/ui/progress-bar/progress-bar.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/progress-bar/progress-bar.component.spec.ts @@ -34,8 +34,7 @@ describe('ProgressBarComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ProgressBarComponent], - imports: [MatProgressBar], + imports: [MatProgressBar, ProgressBarComponent], }); }); diff --git a/alfa-client/libs/ui/src/lib/ui/progress-bar/progress-bar.component.ts b/alfa-client/libs/ui/src/lib/ui/progress-bar/progress-bar.component.ts index 69bf1807b1661c741d23ae7747d964a8c699d366..185fa2810d9fcae9d2d9a3e710e140a441fcc617 100644 --- a/alfa-client/libs/ui/src/lib/ui/progress-bar/progress-bar.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/progress-bar/progress-bar.component.ts @@ -21,14 +21,17 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Input } from '@angular/core'; import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; +import { Component, Input } from '@angular/core'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; import { Resource } from '@ngxp/rest'; @Component({ selector: 'ozgcloud-progress-bar', templateUrl: './progress-bar.component.html', styleUrls: ['./progress-bar.component.scss'], + standalone: true, + imports: [MatProgressBarModule], }) export class ProgressBarComponent { @Input() stateResource: StateResource<Resource> = createEmptyStateResource<Resource>(); diff --git a/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.ts b/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.ts index 951d47620e165deecf550d90f43930cb30405653..862f4c7ec87f24a558689fca192955ba6e95fc9c 100644 --- a/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.ts @@ -21,13 +21,18 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, EventEmitter, Input, Output } from '@angular/core'; import { EMPTY_STRING } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { MatSlideToggle } from '@angular/material/slide-toggle'; +import { MatTooltip } from '@angular/material/tooltip'; +import { TooltipDirective } from '@ods/system'; @Component({ selector: 'ozgcloud-slide-toggle', templateUrl: './slide-toggle.component.html', styleUrls: ['./slide-toggle.component.scss'], + standalone: true, + imports: [MatSlideToggle, MatTooltip, TooltipDirective], }) export class SlideToggleComponent { @Input() checked: boolean = false; diff --git a/alfa-client/libs/ui/src/lib/ui/spinner-transparency/spinner-transparency.component.html b/alfa-client/libs/ui/src/lib/ui/spinner-transparency/spinner-transparency.component.html index fa88c4170ccd839d86ed250e89eef62cccf7101f..488dfee2c9a4a858064cca4461e25ceeb64a43b9 100644 --- a/alfa-client/libs/ui/src/lib/ui/spinner-transparency/spinner-transparency.component.html +++ b/alfa-client/libs/ui/src/lib/ui/spinner-transparency/spinner-transparency.component.html @@ -1,35 +1,32 @@ <!-- - Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - Ministerpräsidenten des Landes Schleswig-Holstein - Staatskanzlei - Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den +Ministerpräsidenten des Landes Schleswig-Holstein +Staatskanzlei +Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - Lizenziert unter der EUPL, Version 1.2 oder - sobald - diese von der Europäischen Kommission genehmigt wurden - - Folgeversionen der EUPL ("Lizenz"); - Sie dürfen dieses Werk ausschließlich gemäß - dieser Lizenz nutzen. - Eine Kopie der Lizenz finden Sie hier: +Lizenziert unter der EUPL, Version 1.2 oder - sobald +diese von der Europäischen Kommission genehmigt wurden - +Folgeversionen der EUPL ("Lizenz"); +Sie dürfen dieses Werk ausschließlich gemäß +dieser Lizenz nutzen. +Eine Kopie der Lizenz finden Sie hier: - https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - Sofern nicht durch anwendbare Rechtsvorschriften - gefordert oder in schriftlicher Form vereinbart, wird - die unter der Lizenz verbreitete Software "so wie sie - ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - ausdrücklich oder stillschweigend - verbreitet. - Die sprachspezifischen Genehmigungen und Beschränkungen - unter der Lizenz sind dem Lizenztext zu entnehmen. +Sofern nicht durch anwendbare Rechtsvorschriften +gefordert oder in schriftlicher Form vereinbart, wird +die unter der Lizenz verbreitete Software "so wie sie +ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +ausdrücklich oder stillschweigend - verbreitet. +Die sprachspezifischen Genehmigungen und Beschränkungen +unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<div - *ngIf="showSpinner" - data-test-class="spinner-transparency" - class="spinner" - [style.padding]="'16px'" -> - <mat-spinner [diameter]="70"></mat-spinner> -</div> - -<ng-content *ngIf="!showSpinner" data-test-class="spinner-transparency-content"></ng-content> +@if (showSpinner) { + <div data-test-class="spinner-transparency" class="spinner" [style.padding]="'16px'"> + <mat-spinner [diameter]="70"></mat-spinner> + </div> +} @else { + <ng-content data-test-class="spinner-transparency-content"></ng-content> +} diff --git a/alfa-client/libs/ui/src/lib/ui/spinner-transparency/spinner-transparency.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/spinner-transparency/spinner-transparency.component.spec.ts index 2c1395076163f92d48f781151f13cfa4c7967888..c5c81db6154375f630b88bc874dee34a3a16ad22 100644 --- a/alfa-client/libs/ui/src/lib/ui/spinner-transparency/spinner-transparency.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/spinner-transparency/spinner-transparency.component.spec.ts @@ -38,8 +38,7 @@ describe('SpinnerTransparencyComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [SpinnerTransparencyComponent, SpinnerComponent], - imports: [MatIcon, MatProgressSpinner], + imports: [MatIcon, MatProgressSpinner, SpinnerTransparencyComponent, SpinnerComponent], }).compileComponents(); }); diff --git a/alfa-client/libs/ui/src/lib/ui/spinner-transparency/spinner-transparency.component.ts b/alfa-client/libs/ui/src/lib/ui/spinner-transparency/spinner-transparency.component.ts index bf70ce6a7764c20ab9c2bce95f7191182ec920a2..34fa02963b6363318252902d45fe6b0853fe9334 100644 --- a/alfa-client/libs/ui/src/lib/ui/spinner-transparency/spinner-transparency.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/spinner-transparency/spinner-transparency.component.ts @@ -21,14 +21,17 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Input } from '@angular/core'; import { StateResource, createEmptyStateResource } from '@alfa-client/tech-shared'; +import { Component, Input } from '@angular/core'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; import { Resource } from '@ngxp/rest'; @Component({ selector: 'ozgcloud-spinner-transparency', templateUrl: './spinner-transparency.component.html', styleUrls: ['./spinner-transparency.component.scss'], + standalone: true, + imports: [MatProgressSpinner], }) export class SpinnerTransparencyComponent { @Input() stateResource: StateResource<Resource> = createEmptyStateResource<Resource>(); diff --git a/alfa-client/libs/ui/src/lib/ui/spinner/spinner.component.html b/alfa-client/libs/ui/src/lib/ui/spinner/spinner.component.html index eaa2ab439802985584c0b7595703072d095dcae9..5a426212ea07aa4413b5f7105c1790e7498ba8a6 100644 --- a/alfa-client/libs/ui/src/lib/ui/spinner/spinner.component.html +++ b/alfa-client/libs/ui/src/lib/ui/spinner/spinner.component.html @@ -1,31 +1,37 @@ <!-- - Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - Ministerpräsidenten des Landes Schleswig-Holstein - Staatskanzlei - Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den +Ministerpräsidenten des Landes Schleswig-Holstein +Staatskanzlei +Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - Lizenziert unter der EUPL, Version 1.2 oder - sobald - diese von der Europäischen Kommission genehmigt wurden - - Folgeversionen der EUPL ("Lizenz"); - Sie dürfen dieses Werk ausschließlich gemäß - dieser Lizenz nutzen. - Eine Kopie der Lizenz finden Sie hier: +Lizenziert unter der EUPL, Version 1.2 oder - sobald +diese von der Europäischen Kommission genehmigt wurden - +Folgeversionen der EUPL ("Lizenz"); +Sie dürfen dieses Werk ausschließlich gemäß +dieser Lizenz nutzen. +Eine Kopie der Lizenz finden Sie hier: - https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - Sofern nicht durch anwendbare Rechtsvorschriften - gefordert oder in schriftlicher Form vereinbart, wird - die unter der Lizenz verbreitete Software "so wie sie - ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - ausdrücklich oder stillschweigend - verbreitet. - Die sprachspezifischen Genehmigungen und Beschränkungen - unter der Lizenz sind dem Lizenztext zu entnehmen. +Sofern nicht durch anwendbare Rechtsvorschriften +gefordert oder in schriftlicher Form vereinbart, wird +die unter der Lizenz verbreitete Software "so wie sie +ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +ausdrücklich oder stillschweigend - verbreitet. +Die sprachspezifischen Genehmigungen und Beschränkungen +unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<div *ngIf="showSpinner" class="spinner" [style.padding]="padding + 'px'"> - <mat-spinner [diameter]="diameter" data-test-class="spinner"> </mat-spinner> - <span *ngIf="text">{{ text }}</span> -</div> +@if (showSpinner) { + <div class="spinner" [style.padding]="padding + 'px'"> + <mat-spinner [diameter]="diameter" data-test-class="spinner"> </mat-spinner> + @if (text) { + <span>{{ text }}</span> + } + </div> +} -<ng-content *ngIf="!showSpinner" data-test-class="spinner-content"></ng-content> +@if (!showSpinner) { + <ng-content data-test-class="spinner-content"></ng-content> +} diff --git a/alfa-client/libs/ui/src/lib/ui/spinner/spinner.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/spinner/spinner.component.spec.ts index 8bc40b8d5ba9850a5c36c603e91fcc13827d4420..27b80e6f55c7fa9994ebaba67688ff5417f6272b 100644 --- a/alfa-client/libs/ui/src/lib/ui/spinner/spinner.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/spinner/spinner.component.spec.ts @@ -37,8 +37,7 @@ describe('SpinnerComponent', () => { beforeEach(async () => { TestBed.configureTestingModule({ - declarations: [SpinnerComponent], - imports: [MatIcon, MatProgressSpinner], + imports: [MatIcon, MatProgressSpinner, SpinnerComponent], }); }); diff --git a/alfa-client/libs/ui/src/lib/ui/spinner/spinner.component.ts b/alfa-client/libs/ui/src/lib/ui/spinner/spinner.component.ts index cfd3cfd4d3d6b17b4d046826c700c288bcb6cfe7..15350296561bdd96791a7b97e448e8be0ab6183f 100644 --- a/alfa-client/libs/ui/src/lib/ui/spinner/spinner.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/spinner/spinner.component.ts @@ -23,11 +23,14 @@ */ import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; import { Component, Input } from '@angular/core'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; @Component({ selector: 'ozgcloud-spinner', templateUrl: './spinner.component.html', styleUrls: ['./spinner.component.scss'], + standalone: true, + imports: [MatProgressSpinner], }) export class SpinnerComponent { @Input() stateResource: StateResource<unknown> = createEmptyStateResource<unknown>(); diff --git a/alfa-client/libs/ui/src/lib/ui/subnavigation/subnavigation.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/subnavigation/subnavigation.component.spec.ts index b021131cd7dae57a09c8821f81b6e0c6efa37813..6586a170653c455343d86b2c44d436a4c0defeab 100644 --- a/alfa-client/libs/ui/src/lib/ui/subnavigation/subnavigation.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/subnavigation/subnavigation.component.spec.ts @@ -30,7 +30,7 @@ describe('SubnavigationComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [SubnavigationComponent], + imports: [SubnavigationComponent], }).compileComponents(); }); diff --git a/alfa-client/libs/ui/src/lib/ui/subnavigation/subnavigation.component.ts b/alfa-client/libs/ui/src/lib/ui/subnavigation/subnavigation.component.ts index 631e4713fa20d357b911ab7c3fbb5514b5847a00..1e2deca56f9669732b166fc82adb23af30b9f699 100644 --- a/alfa-client/libs/ui/src/lib/ui/subnavigation/subnavigation.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/subnavigation/subnavigation.component.ts @@ -27,5 +27,6 @@ import { Component } from '@angular/core'; selector: 'ozgcloud-subnavigation', templateUrl: './subnavigation.component.html', styleUrls: ['./subnavigation.component.scss'], + standalone: true, }) export class SubnavigationComponent {} diff --git a/alfa-client/libs/ui/src/lib/ui/ui.module.spec.ts b/alfa-client/libs/ui/src/lib/ui/ui.module.spec.ts deleted file mode 100644 index 1133667573970cdae3c5f413d6d064c62ca94891..0000000000000000000000000000000000000000 --- a/alfa-client/libs/ui/src/lib/ui/ui.module.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { TestBed } from '@angular/core/testing'; -import { UiModule } from './ui.module'; - -describe('UiModule', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [UiModule], - }).compileComponents(); - }); - - it('should create', () => { - expect(UiModule).toBeDefined(); - }); -}); diff --git a/alfa-client/libs/ui/src/lib/ui/ui.module.ts b/alfa-client/libs/ui/src/lib/ui/ui.module.ts deleted file mode 100644 index e7c19b188d8e38ab7c45f080f52b4b3536550cc4..0000000000000000000000000000000000000000 --- a/alfa-client/libs/ui/src/lib/ui/ui.module.ts +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { CommonModule } from '@angular/common'; -import { HTTP_INTERCEPTORS } from '@angular/common/http'; -import { NgModule } from '@angular/core'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { DateFnsAdapter, MatDateFnsModule } from '@angular/material-date-fns-adapter'; -import { MatAutocompleteModule } from '@angular/material/autocomplete'; -import { MatBadgeModule } from '@angular/material/badge'; -import { MatButtonModule } from '@angular/material/button'; -import { MatButtonToggleModule } from '@angular/material/button-toggle'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { DateAdapter, MAT_DATE_LOCALE, MatRippleModule } from '@angular/material/core'; -import { MatDatepickerModule } from '@angular/material/datepicker'; -import { MatDialogModule } from '@angular/material/dialog'; -import { MatExpansionModule } from '@angular/material/expansion'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatIconModule } from '@angular/material/icon'; -import { MatInputModule } from '@angular/material/input'; -import { MatListModule } from '@angular/material/list'; -import { MatMenuModule } from '@angular/material/menu'; -import { MatProgressBarModule } from '@angular/material/progress-bar'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { MatSlideToggleModule } from '@angular/material/slide-toggle'; -import { MatSnackBarModule } from '@angular/material/snack-bar'; -import { MatTabsModule } from '@angular/material/tabs'; -import { RouterModule } from '@angular/router'; -import { - ArrowBackIconComponent, - ButtonComponent, - FileUploadButtonComponent, - SpinnerIconComponent, - TooltipDirective, -} from '@ods/system'; -import { de } from 'date-fns/locale'; -import { AppIconComponent } from '../icon/app-icon/app-icon.component'; -import { PostfachIconComponent } from '../icon/postfach-icon/postfach-icon.component'; -import { HttpConnectionTimeoutInterceptor } from '../interceptor/http-connection-timeout.interceptor'; -import { HttpErrorInterceptor } from '../interceptor/http-error.interceptor'; -import { SnackbarCloseButtonComponent } from '../snackbar/snackbar-close-button/snackbar-close-button.component'; -import { SnackbarErrorComponent } from '../snackbar/snackbar-error/snackbar-error.component'; -import { SnackbarInfoComponent } from '../snackbar/snackbar-info/snackbar-info.component'; -import { AccordionComponent } from './accordion/accordion.component'; -import { BackButtonComponent } from './back-button/back-button.component'; -import { BasicDialogComponent } from './basic-dialog/basic-dialog.component'; -import { DownloadButtonComponent } from './download-button/download-button.component'; -import { AutocompleteEditorComponent } from './editor/autocomplete-editor/autocomplete-editor.component'; -import { CheckboxEnumEditorComponent } from './editor/checkbox-enum-editor/checkbox-enum-editor.component'; -import { DateEditorComponent } from './editor/date-editor/date-editor.component'; -import { FileUploadEditorComponent } from './editor/file-upload-editor/file-upload-editor.component'; -import { TextEditorComponent } from './editor/text-editor/text-editor.component'; -import { TextAreaEditorComponent } from './editor/textarea-editor/textarea-editor.component'; -import { ExpansionPanelComponent } from './expansion-panel/expansion-panel.component'; -import { FileUploadComponent } from './file-upload/file-upload.component'; -import { FixedDialogComponent } from './fixed-dialog/fixed-dialog.component'; -import { ConnectionTimeoutRetryDialogComponent } from './http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component'; -import { ConnectionTimeoutRetryFailDialogComponent } from './http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component'; -import { IconButtonWithSpinnerComponent } from './icon-button-with-spinner/icon-button-with-spinner.component'; -import { InternalServerErrorDialogComponent } from './notification/internal-server-error-dialog/internal-server-error-dialog.component'; -import { OpenUrlButtonComponent } from './open-url-button/open-url-button.component'; -import { OzgcloudButtonWithSpinnerComponent } from './ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component'; -import { OzgcloudIconButtonPrimaryComponent } from './ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component'; -import { OzgcloudStrokedButtonWithSpinnerComponent } from './ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component'; -import { OzgcloudButtonContentComponent } from './ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component'; -import { OzgcloudIconComponent } from './ozgcloud-icon/ozgcloud-icon.component'; -import { OzgcloudMenuComponent } from './ozgcloud-menu/ozgcloud-menu.component'; -import { OzgcloudPasteTextButtonComponent } from './ozgcloud-paste-text-button/ozgcloud-paste-text-button.component'; -import { OzgcloudRoutingButtonComponent } from './ozgcloud-routing-button/ozgcloud-routing-button.component'; -import { OzgcloudSvgIconBigComponent } from './ozgcloud-svgicon-big/ozgcloud-svgicon-big.component'; -import { OzgcloudSvgIconComponent } from './ozgcloud-svgicon/ozgcloud-svgicon.component'; -import { ProgressBarComponent } from './progress-bar/progress-bar.component'; -import { SlideToggleComponent } from './slide-toggle/slide-toggle.component'; -import { SpinnerTransparencyComponent } from './spinner-transparency/spinner-transparency.component'; -import { SpinnerComponent } from './spinner/spinner.component'; -import { SubnavigationComponent } from './subnavigation/subnavigation.component'; -import { ValidationErrorComponent } from './validation-error/validation-error.component'; - -@NgModule({ - declarations: [ - SubnavigationComponent, - SpinnerComponent, - OzgcloudButtonWithSpinnerComponent, - OzgcloudStrokedButtonWithSpinnerComponent, - IconButtonWithSpinnerComponent, - ProgressBarComponent, - ExpansionPanelComponent, - SnackbarInfoComponent, - SnackbarErrorComponent, - FileUploadComponent, - DateEditorComponent, - TextEditorComponent, - TextAreaEditorComponent, - ValidationErrorComponent, - AutocompleteEditorComponent, - FixedDialogComponent, - InternalServerErrorDialogComponent, - FileUploadEditorComponent, - PostfachIconComponent, - AccordionComponent, - AppIconComponent, - SlideToggleComponent, - BackButtonComponent, - OzgcloudIconButtonPrimaryComponent, - OzgcloudIconComponent, - OzgcloudRoutingButtonComponent, - OzgcloudSvgIconComponent, - OzgcloudSvgIconBigComponent, - SpinnerTransparencyComponent, - OpenUrlButtonComponent, - DownloadButtonComponent, - ConnectionTimeoutRetryDialogComponent, - ConnectionTimeoutRetryFailDialogComponent, - SnackbarCloseButtonComponent, - BasicDialogComponent, - OzgcloudButtonContentComponent, - OzgcloudPasteTextButtonComponent, - CheckboxEnumEditorComponent, - OzgcloudMenuComponent, - ], - imports: [ - MatButtonModule, - MatIconModule, - MatProgressBarModule, - MatProgressSpinnerModule, - MatMenuModule, - MatSlideToggleModule, - MatExpansionModule, - MatRippleModule, - MatSnackBarModule, - MatCheckboxModule, - MatFormFieldModule, - MatInputModule, - MatListModule, - MatDatepickerModule, - MatDateFnsModule, - FormsModule, - ReactiveFormsModule, - MatAutocompleteModule, - MatDialogModule, - MatTabsModule, - MatBadgeModule, - CommonModule, - TechSharedModule, - RouterModule, - MatButtonToggleModule, - FileUploadButtonComponent, - SpinnerIconComponent, - TooltipDirective, - ButtonComponent, - ArrowBackIconComponent, - ], - exports: [ - MatButtonModule, - MatIconModule, - MatProgressBarModule, - MatProgressSpinnerModule, - MatMenuModule, - MatSlideToggleModule, - MatExpansionModule, - MatRippleModule, - MatSnackBarModule, - MatCheckboxModule, - MatFormFieldModule, - MatInputModule, - MatListModule, - MatDatepickerModule, - MatDateFnsModule, - FormsModule, - ReactiveFormsModule, - MatAutocompleteModule, - MatDialogModule, - MatTabsModule, - MatBadgeModule, - CommonModule, - TechSharedModule, - RouterModule, - MatButtonToggleModule, - SubnavigationComponent, - SpinnerComponent, - OzgcloudIconButtonPrimaryComponent, - OzgcloudButtonWithSpinnerComponent, - OzgcloudStrokedButtonWithSpinnerComponent, - IconButtonWithSpinnerComponent, - ProgressBarComponent, - ExpansionPanelComponent, - SnackbarInfoComponent, - SnackbarErrorComponent, - FileUploadComponent, - DateEditorComponent, - TextEditorComponent, - TextAreaEditorComponent, - ValidationErrorComponent, - AutocompleteEditorComponent, - FixedDialogComponent, - InternalServerErrorDialogComponent, - FileUploadEditorComponent, - PostfachIconComponent, - AccordionComponent, - AppIconComponent, - SlideToggleComponent, - BackButtonComponent, - OzgcloudIconComponent, - OzgcloudRoutingButtonComponent, - OzgcloudSvgIconComponent, - OzgcloudSvgIconBigComponent, - SpinnerTransparencyComponent, - OpenUrlButtonComponent, - DownloadButtonComponent, - ConnectionTimeoutRetryDialogComponent, - ConnectionTimeoutRetryFailDialogComponent, - SnackbarCloseButtonComponent, - BasicDialogComponent, - OzgcloudPasteTextButtonComponent, - CheckboxEnumEditorComponent, - FileUploadButtonComponent, - OzgcloudButtonContentComponent, - OzgcloudMenuComponent, - ], - providers: [ - { - provide: HTTP_INTERCEPTORS, - useClass: HttpErrorInterceptor, - multi: true, - }, - { - provide: HTTP_INTERCEPTORS, - useClass: HttpConnectionTimeoutInterceptor, - multi: true, - }, - { - provide: MAT_DATE_LOCALE, - useValue: de, - }, - { - provide: DateAdapter, - useClass: DateFnsAdapter, - deps: [MAT_DATE_LOCALE], - }, - ], -}) -export class UiModule {} diff --git a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.html b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.html index cdf207ba37ef266413d4dc72d8762f1a6e1e1913..673ecf065e1b890e163cf98fab0335c180bea627 100644 --- a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.html +++ b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.html @@ -1,26 +1,28 @@ <!-- - Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den - Ministerpräsidenten des Landes Schleswig-Holstein - Staatskanzlei - Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den +Ministerpräsidenten des Landes Schleswig-Holstein +Staatskanzlei +Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - Lizenziert unter der EUPL, Version 1.2 oder - sobald - diese von der Europäischen Kommission genehmigt wurden - - Folgeversionen der EUPL ("Lizenz"); - Sie dürfen dieses Werk ausschließlich gemäß - dieser Lizenz nutzen. - Eine Kopie der Lizenz finden Sie hier: +Lizenziert unter der EUPL, Version 1.2 oder - sobald +diese von der Europäischen Kommission genehmigt wurden - +Folgeversionen der EUPL ("Lizenz"); +Sie dürfen dieses Werk ausschließlich gemäß +dieser Lizenz nutzen. +Eine Kopie der Lizenz finden Sie hier: - https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - Sofern nicht durch anwendbare Rechtsvorschriften - gefordert oder in schriftlicher Form vereinbart, wird - die unter der Lizenz verbreitete Software "so wie sie - ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - ausdrücklich oder stillschweigend - verbreitet. - Die sprachspezifischen Genehmigungen und Beschränkungen - unter der Lizenz sind dem Lizenztext zu entnehmen. +Sofern nicht durch anwendbare Rechtsvorschriften +gefordert oder in schriftlicher Form vereinbart, wird +die unter der Lizenz verbreitete Software "so wie sie +ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +ausdrücklich oder stillschweigend - verbreitet. +Die sprachspezifischen Genehmigungen und Beschränkungen +unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<span *ngFor="let invalidParam of invalidParams">{{ message(invalidParam) }}</span> +@for (invalidParam of invalidParams; track invalidParam) { + <span>{{ message(invalidParam) }}</span> +} diff --git a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.spec.ts index 0b265b44ec24e326187ef0b8605fcf1a7f8f688e..2e851164cb169a9e9c085c4b1e2ca483a970d921 100644 --- a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.spec.ts @@ -33,7 +33,7 @@ describe('ValidationErrorComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ValidationErrorComponent], + imports: [ValidationErrorComponent], }).compileComponents(); }); diff --git a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.ts b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.ts index 285a9989ed250d9f14f62a7b2a8b5bc7834b907c..eae4c1e99487d7fe169a73fee93d07af75f55676 100644 --- a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.ts +++ b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.ts @@ -28,6 +28,7 @@ import { Component, Input } from '@angular/core'; selector: 'ozgcloud-validation-error', templateUrl: './validation-error.component.html', styleUrls: ['./validation-error.component.scss'], + standalone: true, }) export class ValidationErrorComponent { @Input() label: string; diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/documentation/open-documentation-button/open-documentation-button.component.html b/alfa-client/libs/user-assistance/src/lib/help-menu/documentation/open-documentation-button/open-documentation-button.component.html index 0179cbc7aac26bf1464207fa7557006d3294e87a..d3f460b90b5c7c7232d01e2b4e0674ddee2a8a8c 100644 --- a/alfa-client/libs/user-assistance/src/lib/help-menu/documentation/open-documentation-button/open-documentation-button.component.html +++ b/alfa-client/libs/user-assistance/src/lib/help-menu/documentation/open-documentation-button/open-documentation-button.component.html @@ -29,4 +29,4 @@ [targetName]="'_blank'" [tooltip]="'Öffnet in einem neuen Tab'" data-test-id="open-documentation-button" -></ozgcloud-open-url-button> +/> diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.spec.ts b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.spec.ts index ba0e572d4edad3c8e610cd869d31b40b186d8d5d..870deee5a210330b9a267bac71c674ddce7e3ae0 100644 --- a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.spec.ts +++ b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.spec.ts @@ -24,8 +24,9 @@ import { ApiRootLinkRel } from '@alfa-client/api-root-shared'; import { GetUrlPipe, HasLinkPipe, createStateResource } from '@alfa-client/tech-shared'; import { getElementFromDomRoot } from '@alfa-client/test-utils'; -import { UiModule } from '@alfa-client/ui'; +import { OzgcloudIconComponent, OzgcloudMenuComponent } from '@alfa-client/ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatMenuTrigger } from '@angular/material/menu'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { DropdownMenuComponent, @@ -34,9 +35,9 @@ import { FileIconComponent, HelpIconComponent, } from '@ods/system'; +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 { createApiRootResource } from '../../../../../libs/api-root-shared/test/api-root'; import { DocumentationComponent } from './documentation/documentation.component'; import { HelpButtonComponent } from './help-button/help-button.component'; import { HelpMenuComponent } from './help-menu.component'; @@ -54,6 +55,10 @@ describe('HelpMenuComponent', () => { HelpMenuComponent, HasLinkPipe, GetUrlPipe, + MatMenuTrigger, + MockComponent(OzgcloudMenuComponent), + MockComponent(DocumentationComponent), + MockComponent(OzgcloudIconComponent), MockComponent(DocumentationComponent), MockComponent(FileIconComponent), MockComponent(HelpIconComponent), @@ -62,7 +67,7 @@ describe('HelpMenuComponent', () => { MockComponent(DropdownMenuLinkItemComponent), MockComponent(HelpButtonComponent), ], - imports: [NoopAnimationsModule, UiModule], + imports: [NoopAnimationsModule], }).compileComponents(); fixture = TestBed.createComponent(HelpMenuComponent); diff --git a/alfa-client/libs/user-assistance/src/lib/user-assistance.module.ts b/alfa-client/libs/user-assistance/src/lib/user-assistance.module.ts index 1eda492b4fe8af82af049e37d1548a419912e98f..63fc01ce61325ce4935a8292df7314a550e83940 100644 --- a/alfa-client/libs/user-assistance/src/lib/user-assistance.module.ts +++ b/alfa-client/libs/user-assistance/src/lib/user-assistance.module.ts @@ -21,9 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; import { CommonModule } from '@angular/common'; +import { GetUrlPipe, HasLinkPipe } from '@alfa-client/tech-shared'; import { NgModule } from '@angular/core'; import { DropdownMenuComponent, @@ -32,21 +31,27 @@ import { FileIconComponent, HelpIconComponent, } from '@ods/system'; +import { MatFabButton } from '@angular/material/button'; +import { MatMenuTrigger } from '@angular/material/menu'; import { DocumentationComponent } from './help-menu/documentation/documentation.component'; import { OpenDocumentationButtonComponent } from './help-menu/documentation/open-documentation-button/open-documentation-button.component'; import { HelpButtonComponent } from './help-menu/help-button/help-button.component'; import { HelpMenuComponent } from './help-menu/help-menu.component'; +import { OpenUrlButtonComponent } from '@alfa-client/ui'; @NgModule({ imports: [ CommonModule, - TechSharedModule, + MatMenuTrigger, + HasLinkPipe, + GetUrlPipe, + MatFabButton, FileIconComponent, HelpIconComponent, DropdownMenuComponent, DropdownMenuTextItemComponent, - UiModule, DropdownMenuLinkItemComponent, + OpenUrlButtonComponent, ], declarations: [HelpMenuComponent, DocumentationComponent, OpenDocumentationButtonComponent, HelpButtonComponent], exports: [HelpMenuComponent], diff --git a/alfa-client/libs/user-profile-shared/src/lib/user-profile.repository.spec.ts b/alfa-client/libs/user-profile-shared/src/lib/user-profile.repository.spec.ts index 844d2d4ad75212bd6cd5eb3bc6ab48b5c2b84409..9b9cc5c3f622ddf766e1a43eaccbf21ea1620efc 100644 --- a/alfa-client/libs/user-profile-shared/src/lib/user-profile.repository.spec.ts +++ b/alfa-client/libs/user-profile-shared/src/lib/user-profile.repository.spec.ts @@ -22,7 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { ApiRootLinkRel, ApiRootResource } from '@alfa-client/api-root-shared'; -import { HttpErrorHandler, TechSharedModule } from '@alfa-client/tech-shared'; +import { HttpErrorHandler } from '@alfa-client/tech-shared'; import { mock, mockClass, useFromMock } from '@alfa-client/test-utils'; import { VorgangHeaderLinkRel, @@ -33,10 +33,8 @@ import { import { ResourceFactory } from '@ngxp/rest'; import { cold, hot } from 'jest-marbles'; import { createApiRootResource } from 'libs/api-root-shared/test/api-root'; -import { - createVorgangResource, - createVorgangWithEingangResource, -} from 'libs/vorgang-shared/test/vorgang'; +import { InjectorService } from 'libs/tech-shared/src/lib/injector/injector.service'; +import { createVorgangResource, createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; import { createUserProfileListResource, createUserProfileResource } from '../../test/user-profile'; import { UserProfileListResource, UserProfileResource } from './user-profile.model'; import { UserProfileRepository } from './user-profile.repository'; @@ -51,7 +49,7 @@ describe('User profile repository', () => { const userProfile: UserProfileResource = createUserProfileResource(); beforeEach(() => { - const classMock = mockClass(TechSharedModule); + const classMock = mockClass(InjectorService); classMock.injector = <any>{ get: () => useFromMock(mock(HttpErrorHandler)) }; repository = new UserProfileRepository(useFromMock(resourceFactory)); diff --git a/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.spec.ts b/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.spec.ts index 1f91ba4533ee9c3ee1b09102a7df8deb9de9b849..ab53c008163ee44d5f785b065da91de6f203363c 100644 --- a/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.spec.ts +++ b/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.spec.ts @@ -28,6 +28,7 @@ import { getUserName, UserProfileResource } from '@alfa-client/user-profile-shar import { EventEmitter } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatIcon } from '@angular/material/icon'; +import { MatMenuTrigger } from '@angular/material/menu'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { DropdownMenuButtonItemComponent, DropdownMenuComponent, LogoutIconComponent } from '@ods/system'; import { getDataTestIdAttributeOf, getDataTestIdOf } from 'libs/tech-shared/test/data-test'; @@ -49,6 +50,7 @@ describe('UserProfileInHeaderComponent', () => { declarations: [ UserProfileInHeaderComponent, MatIcon, + MatMenuTrigger, MockComponent(UserIconComponent), MockComponent(DropdownMenuComponent), MockComponent(DropdownMenuButtonItemComponent), diff --git a/alfa-client/libs/user-profile/src/lib/user-profile-in-vorgang-container/user-profile-in-vorgang/user-profile-button-container/user-profile-button-container.component.spec.ts b/alfa-client/libs/user-profile/src/lib/user-profile-in-vorgang-container/user-profile-in-vorgang/user-profile-button-container/user-profile-button-container.component.spec.ts index e8c3f33af47eabac0cc2b88028a83637a92384b1..9d67b5fbb32f740a2ae6928d0126bf1a1ac8def9 100644 --- a/alfa-client/libs/user-profile/src/lib/user-profile-in-vorgang-container/user-profile-in-vorgang/user-profile-button-container/user-profile-button-container.component.spec.ts +++ b/alfa-client/libs/user-profile/src/lib/user-profile-in-vorgang-container/user-profile-in-vorgang/user-profile-button-container/user-profile-button-container.component.spec.ts @@ -23,9 +23,9 @@ */ import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; import { mock } from '@alfa-client/test-utils'; -import { UiModule } from '@alfa-client/ui'; import { UserProfileResource, UserProfileService } from '@alfa-client/user-profile-shared'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatMenuTrigger } from '@angular/material/menu'; import { MockComponent } from 'ng-mocks'; import { BehaviorSubject } from 'rxjs'; import { OzgcloudMenuComponent } from '../../../../../../ui/src/lib/ui/ozgcloud-menu/ozgcloud-menu.component'; @@ -47,6 +47,7 @@ describe('UserProfileButtonContainerComponent', () => { TestBed.configureTestingModule({ declarations: [ UserProfileButtonContainerComponent, + MatMenuTrigger, MockComponent(UserIconComponent), MockComponent(UserProfileSearchContainerComponent), MockComponent(OzgcloudMenuComponent), @@ -57,7 +58,6 @@ describe('UserProfileButtonContainerComponent', () => { useValue: userProfileService, }, ], - imports: [UiModule], }); }); diff --git a/alfa-client/libs/user-profile/src/lib/user-profile.module.ts b/alfa-client/libs/user-profile/src/lib/user-profile.module.ts index 408ace4cfbf611228fe69933743b717961982f55..0f595e41c37ed96b7e0084656973cf7c4fc7dfa0 100644 --- a/alfa-client/libs/user-profile/src/lib/user-profile.module.ts +++ b/alfa-client/libs/user-profile/src/lib/user-profile.module.ts @@ -21,11 +21,20 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; +import { + AutocompleteEditorComponent, + IconButtonWithSpinnerComponent, + OzgcloudMenuComponent, + SpinnerComponent, +} from '@alfa-client/ui'; import { UserProfileSharedModule } from '@alfa-client/user-profile-shared'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatIcon } from '@angular/material/icon'; +import { MatMenuTrigger } from '@angular/material/menu'; +import { MatTooltip } from '@angular/material/tooltip'; import { RouterModule } from '@angular/router'; import { ButtonWithSpinnerComponent } from '@ods/component'; import { @@ -61,13 +70,20 @@ import { UserProfileComponent } from './user-profile/user-profile.component'; @NgModule({ imports: [ CommonModule, - TechSharedModule, - UiModule, UserProfileSharedModule, RouterModule, OdsUserIconComponent, LogoutIconComponent, ErrorIconComponent, + IconButtonWithSpinnerComponent, + HasLinkPipe, + MatTooltip, + SpinnerComponent, + MatMenuTrigger, + OzgcloudMenuComponent, + MatIcon, + AutocompleteEditorComponent, + ReactiveFormsModule, DropdownMenuComponent, DropdownMenuItemComponent, DropdownMenuButtonItemComponent, diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.spec.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.spec.ts index de1ccc1a69c0a17b62d37208226bc6ca96feb68c..f40d240d635937892fe39335610f9f599986b724 100644 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.spec.ts +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.spec.ts @@ -22,7 +22,6 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { HasLinkPipe, createEmptyStateResource } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { DropdownMenuComponent } from '@ods/system'; @@ -37,7 +36,7 @@ describe('UserSettingsComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [NoopAnimationsModule, UiModule], + imports: [NoopAnimationsModule], declarations: [ HasLinkPipe, UserSettingsComponent, diff --git a/alfa-client/libs/user-settings/src/lib/user-settings.module.ts b/alfa-client/libs/user-settings/src/lib/user-settings.module.ts index bafeb748dc5a3c6c145397e031924740372c07be..fce1e22c3ef1c4ba98c956b33bd3504545dc49ae 100644 --- a/alfa-client/libs/user-settings/src/lib/user-settings.module.ts +++ b/alfa-client/libs/user-settings/src/lib/user-settings.module.ts @@ -21,7 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { UiModule } from '@alfa-client/ui'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; +import { SlideToggleComponent } from '@alfa-client/ui'; import { UserSettingsSharedModule } from '@alfa-client/user-settings-shared'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; @@ -35,7 +36,15 @@ import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-cont import { UserSettingsComponent } from './user-settings-container/user-settings/user-settings.component'; @NgModule({ - imports: [CommonModule, UiModule, UserSettingsSharedModule, DropdownMenuComponent, CloseIconComponent, SettingsIconComponent], + imports: [ + CommonModule, + UserSettingsSharedModule, + DropdownMenuComponent, + CloseIconComponent, + SettingsIconComponent, + SlideToggleComponent, + HasLinkPipe, + ], declarations: [ UserSettingsContainerComponent, UserSettingsEmailBenachrichtigungComponent, diff --git a/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component.spec.ts index ebf2fa64f17b56d95828a63bb475020d4178ab76..174d105fae1120efbb26eee2df3cd12c779db4a5 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component.spec.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component.spec.ts @@ -21,45 +21,28 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { AktenzeichenEditDialogComponent } from './aktenzeichen-edit-dialog.component'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { COMMAND_ERROR_MESSAGES, CommandErrorMessage, hasCommandError, isSuccessfulDone } from '@alfa-client/command-shared'; +import { createEmptyStateResource, hasContent, isClipboardReadSupported } from '@alfa-client/tech-shared'; import { mock } from '@alfa-client/test-utils'; import { OzgcloudPasteTextButtonComponent, OzgcloudStrokedButtonWithSpinnerComponent, + OzgcloudTextEditorComponent, SnackBarService, - TextEditorComponent, } from '@alfa-client/ui'; -import { MockComponent, MockDirective } from 'ng-mocks'; import { VorgangService } from '@alfa-client/vorgang-shared'; -import { - MAT_DIALOG_DATA, - MatDialogActions, - MatDialogContent, - MatDialogRef, -} from '@angular/material/dialog'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormBuilder, ReactiveFormsModule, UntypedFormControl } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogActions, MatDialogContent, MatDialogRef } from '@angular/material/dialog'; import { MatIcon } from '@angular/material/icon'; +import { cold, hot } from 'jest-marbles'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; -import { - createEmptyStateResource, - hasContent, - isClipboardReadSupported, -} from '@alfa-client/tech-shared'; +import { MockComponent, MockDirective } from 'ng-mocks'; import { EMPTY, NEVER } from 'rxjs'; -import { FormBuilder, ReactiveFormsModule, UntypedFormControl } from '@angular/forms'; -import { cold, hot } from 'jest-marbles'; -import { - createCommandErrorResource, - createCommandResource, -} from '../../../../command-shared/test/command'; -import { - COMMAND_ERROR_MESSAGES, - CommandErrorMessage, - hasCommandError, - isSuccessfulDone, -} from '@alfa-client/command-shared'; -import { AktenzeichenEditDialogMessages } from './aktenzeichen-edit-dialog.message'; +import { createCommandErrorResource, createCommandResource } from '../../../../command-shared/test/command'; +import { AktenzeichenEditDialogComponent } from './aktenzeichen-edit-dialog.component'; import { AktenzeichenEditDialogFormservice } from './aktenzeichen-edit-dialog.formservice'; +import { AktenzeichenEditDialogMessages } from './aktenzeichen-edit-dialog.message'; jest.mock('@alfa-client/tech-shared'); const isClipboardReadSupportedMock = isClipboardReadSupported as jest.Mock; @@ -99,7 +82,7 @@ describe('AktenzeichenEditDialogComponent', () => { MockDirective(MatDialogContent), MockDirective(MatDialogActions), MockComponent(MatIcon), - MockComponent(TextEditorComponent), + MockComponent(OzgcloudTextEditorComponent), MockComponent(OzgcloudPasteTextButtonComponent), MockComponent(OzgcloudStrokedButtonWithSpinnerComponent), ], diff --git a/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component.ts b/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component.ts index 79dce7d7da127e4e47ae8086e912dcba4d95b8ae..d4744fd1411a9d59360b7e003d2f01958f2ba7ad 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component.ts @@ -21,27 +21,17 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - COMMAND_ERROR_MESSAGES, - CommandResource, - hasCommandError, - isSuccessfulDone, -} from '@alfa-client/command-shared'; -import { - createEmptyStateResource, - hasContent, - isClipboardReadSupported, - StateResource, -} from '@alfa-client/tech-shared'; +import { COMMAND_ERROR_MESSAGES, CommandResource, hasCommandError, isSuccessfulDone } from '@alfa-client/command-shared'; +import { createEmptyStateResource, hasContent, isClipboardReadSupported, StateResource } from '@alfa-client/tech-shared'; import { SnackBarService } from '@alfa-client/ui'; import { VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { Component, Inject, OnInit } from '@angular/core'; +import { UntypedFormGroup } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { map, Observable, of, startWith, tap } from 'rxjs'; import { AktenzeichenEditDialogData } from './aktenzeichen-edit-dialog.data'; -import { AktenzeichenEditDialogMessages } from './aktenzeichen-edit-dialog.message'; -import { UntypedFormGroup } from '@angular/forms'; import { AktenzeichenEditDialogFormservice } from './aktenzeichen-edit-dialog.formservice'; +import { AktenzeichenEditDialogMessages } from './aktenzeichen-edit-dialog.message'; @Component({ selector: 'alfa-aktenzeichen-edit-dialog', @@ -52,9 +42,7 @@ import { AktenzeichenEditDialogFormservice } from './aktenzeichen-edit-dialog.fo export class AktenzeichenEditDialogComponent implements OnInit { vorgang: VorgangWithEingangResource; - setAktenzeichenPending$: Observable<StateResource<CommandResource>> = of( - createEmptyStateResource<CommandResource>(), - ); + setAktenzeichenPending$: Observable<StateResource<CommandResource>> = of(createEmptyStateResource<CommandResource>()); hasAktenzeichen$: Observable<boolean>; isPasteSupported = false; @@ -73,10 +61,7 @@ export class AktenzeichenEditDialogComponent implements OnInit { ngOnInit(): void { this.isPasteSupported = isClipboardReadSupported(); this.formService.setAktenzeichen(this.vorgang.aktenzeichen); - this.hasAktenzeichen$ = this.formService - .valueChanges() - .pipe(startWith(this.vorgang.aktenzeichen)) - .pipe(map(hasContent)); + this.hasAktenzeichen$ = this.formService.valueChanges().pipe(startWith(this.vorgang.aktenzeichen)).pipe(map(hasContent)); } public onCancel(): void { @@ -88,11 +73,7 @@ export class AktenzeichenEditDialogComponent implements OnInit { this.setAktenzeichenPending$ = this.formService .submit() .pipe(startWith(createEmptyStateResource<CommandResource>(true))) - .pipe( - tap((commandStateResource: StateResource<CommandResource>) => - this.onResponse(commandStateResource.resource), - ), - ); + .pipe(tap((commandStateResource: StateResource<CommandResource>) => this.onResponse(commandStateResource.resource))); } onResponse(commandResource: CommandResource) { @@ -111,10 +92,7 @@ export class AktenzeichenEditDialogComponent implements OnInit { } getErrorMessage(commandResource: CommandResource): string { - return ( - COMMAND_ERROR_MESSAGES[commandResource.errorMessage] || - AktenzeichenEditDialogMessages.SET_FAILED - ); + return COMMAND_ERROR_MESSAGES[commandResource.errorMessage] || AktenzeichenEditDialogMessages.SET_FAILED; } paste(clipboardContent: string) { diff --git a/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.spec.ts index 1cd92c64d9b07060f04273c6007ac1c8920ca8d4..3db736ad9d3f16f89f8d4f0abe6a5a50ba44d208 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.spec.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.spec.ts @@ -21,26 +21,14 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { BescheidWizardContainerComponent } from '@alfa-client/bescheid'; import { BescheidResource, BescheidService, BescheidWizardDialogResult } from '@alfa-client/bescheid-shared'; import { CommandResource } from '@alfa-client/command-shared'; import { createEmptyStateResource, createStateResource, HasLinkPipe, StateResource } from '@alfa-client/tech-shared'; -import { - getElementComponentFromFixtureByCss, - getMockComponent, - Mock, - mock, - notExistsAsHtmlElement, - tooltipExistsWithText, - triggerEvent, -} from '@alfa-client/test-utils'; +import { createDialogRefMock, DialogRefMock, getElementComponentFromFixtureByCss, getMockComponent, Mock, mock, notExistsAsHtmlElement, tooltipExistsWithText, triggerEvent, } from '@alfa-client/test-utils'; import { OzgcloudDialogService } from '@alfa-client/ui'; import { BescheidenDialogData } from '@alfa-client/vorgang-detail'; -import { - VorgangCommandService, - VorgangService, - VorgangWithEingangLinkRel, - VorgangWithEingangResource, -} from '@alfa-client/vorgang-shared'; +import { VorgangCommandService, VorgangService, VorgangWithEingangLinkRel, VorgangWithEingangResource, } from '@alfa-client/vorgang-shared'; import { DialogRef } from '@angular/cdk/dialog'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ButtonWithSpinnerComponent } from '@ods/component'; @@ -167,60 +155,58 @@ describe('BescheidenButtonComponent', () => { }); }); - // TODO: Use this version after completed Bescheid refactoring and delete the other version below. - // describe('openBescheidenWizard', () => { - // let dialogRefMock: DialogRefMock<BescheidWizardDialogResult>; - // - // beforeEach(() => { - // dialogRefMock = createDialogRefMock<BescheidWizardDialogResult>(); - // ozgcloudDialogService.openWizard.mockReturnValue(dialogRefMock); - // }); - // - // it('should open wizard dialog', () => { - // const vorgang = createVorgangWithEingangResource(); - // component.vorgang = vorgang; - // - // component.openBescheidenWizard(); - // - // expect(ozgcloudDialogService.openWizard).toHaveBeenCalledWith(BescheidWizardContainerComponent, { - // vorgangWithEingangResource: vorgang, - // }); - // }); - // - // it('should handleBescheidWizardClosed', () => { - // component.handleBescheidWizardClosed = jest.fn(); - // const dialogResult: BescheidWizardDialogResult = { reloadVorgang: true }; - // dialogRefMock.closed = of(dialogResult); - // - // component.openBescheidenWizard(); - // - // expect(component.handleBescheidWizardClosed).toHaveBeenCalledWith(dialogResult); - // }); - // }); + describe('bescheiden icon button', () => { + beforeEach(() => { + component.showAsIconButton = true; + fixture.detectChanges(); + }); + + it('should be hidden', () => { + component.vorgang = createVorgangWithEingangResource(); + + fixture.detectChanges(); + const buttonElement = fixture.nativeElement.querySelector(bescheidenIconButton); + + expect(buttonElement).not.toBeInstanceOf(HTMLElement); + }); + + it('should be visible', () => { + component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEIDEN]); + + fixture.detectChanges(); + const buttonElement = fixture.nativeElement.querySelector(bescheidenIconButton); + + expect(buttonElement).toBeInstanceOf(HTMLElement); + }); + }); describe('openBescheidenWizard', () => { - it('should init', () => { - component.openBescheidenWizard(); + let dialogRefMock: DialogRefMock<BescheidWizardDialogResult>; - expect(bescheidService.init).toHaveBeenCalled(); + beforeEach(() => { + dialogRefMock = createDialogRefMock<BescheidWizardDialogResult>(); + ozgcloudDialogService.openWizard.mockReturnValue(dialogRefMock); }); - it('should open bescheiden dialog with existing draft', () => { - component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEID_DRAFT]); - component.openBescheidenDialogWithExistingDraft = jest.fn(); + it('should open wizard dialog', () => { + const vorgang = createVorgangWithEingangResource(); + component.vorgang = vorgang; component.openBescheidenWizard(); - expect(component.openBescheidenDialogWithExistingDraft).toHaveBeenCalled(); + expect(ozgcloudDialogService.openWizard).toHaveBeenCalledWith(BescheidWizardContainerComponent, { + vorgangWithEingangResource: vorgang, + }); }); - it('should open bescheiden dialog with new draft', () => { - component.vorgang = createVorgangWithEingangResource(); - component.openBescheidDialogWithNewDraft = jest.fn(); + it('should handleBescheidWizardClosed', () => { + component.handleBescheidWizardClosed = jest.fn(); + const dialogResult: BescheidWizardDialogResult = { reloadVorgang: true }; + dialogRefMock.closed = of(dialogResult); component.openBescheidenWizard(); - expect(component.openBescheidDialogWithNewDraft).toHaveBeenCalled(); + expect(component.handleBescheidWizardClosed).toHaveBeenCalledWith(dialogResult); }); }); diff --git a/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.ts b/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.ts index de431e7c593b4e719514f917e3325e41fab3c644..65e3c32d26e50c662463f04804b56def5f01dfca 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.ts @@ -21,19 +21,16 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { BescheidWizardContainerComponent } from '@alfa-client/bescheid'; import { BescheidResource, BescheidService, BescheidWizardDialogResult } from '@alfa-client/bescheid-shared'; import { CommandResource } from '@alfa-client/command-shared'; -import { StateResource, createEmptyStateResource, isLoaded, isNotNil } from '@alfa-client/tech-shared'; +import { createEmptyStateResource, isLoaded, isNotNil, StateResource } from '@alfa-client/tech-shared'; import { OzgcloudDialogService } from '@alfa-client/ui'; -import { - VorgangCommandService, - VorgangService, - VorgangWithEingangLinkRel, - VorgangWithEingangResource, -} from '@alfa-client/vorgang-shared'; +import { VorgangCommandService, VorgangService, VorgangWithEingangLinkRel, VorgangWithEingangResource, } from '@alfa-client/vorgang-shared'; +import { DialogRef } from '@angular/cdk/dialog'; import { Component, Input, OnInit } from '@angular/core'; import { hasLink } from '@ngxp/rest'; -import { Observable, filter, first, map, of } from 'rxjs'; +import { filter, first, map, Observable, of } from 'rxjs'; import { BescheidenDialogData } from '../../vorgang-detail-page/vorgang-detail-bescheiden/bescheiden.model'; import { VorgangDetailBescheidenComponent } from '../../vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden.component'; @@ -86,16 +83,15 @@ export class BescheidenButtonComponent implements OnInit { ); } - // TODO: Use this version after completed Bescheid refactoring and delete the other version below. - // public openBescheidenWizard(): void { - // const dialogData: BescheidenDialogData = { vorgangWithEingangResource: this.vorgang }; - // const dialogRef: DialogRef<BescheidWizardDialogResult> = this.ozgcloudDialogService.openWizard< - // BescheidWizardContainerComponent, - // BescheidenDialogData, - // BescheidWizardDialogResult - // >(BescheidWizardContainerComponent, dialogData); - // dialogRef.closed.subscribe((dialogResult: BescheidWizardDialogResult) => this.handleBescheidWizardClosed(dialogResult)); - // } + public openBescheidenWizard(): void { + const dialogData: BescheidenDialogData = { vorgangWithEingangResource: this.vorgang }; + const dialogRef: DialogRef<BescheidWizardDialogResult> = this.ozgcloudDialogService.openWizard< + BescheidWizardContainerComponent, + BescheidenDialogData, + BescheidWizardDialogResult + >(BescheidWizardContainerComponent, dialogData); + dialogRef.closed.subscribe((dialogResult: BescheidWizardDialogResult) => this.handleBescheidWizardClosed(dialogResult)); + } handleBescheidWizardClosed(dialogResult: BescheidWizardDialogResult): void { if (isNotNil(dialogResult) && dialogResult.reloadVorgang) { @@ -103,15 +99,6 @@ export class BescheidenButtonComponent implements OnInit { } } - public openBescheidenWizard(): void { - this.bescheidService.init(); - if (hasLink(this.vorgang, VorgangWithEingangLinkRel.BESCHEID_DRAFT)) { - this.openBescheidenDialogWithExistingDraft(); - } else { - this.openBescheidDialogWithNewDraft(); - } - } - openBescheidenDialogWithExistingDraft(): void { this.bescheidService .getBescheidDraftIfExists() diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-step-title/vorgang-detail-bescheiden-step-title.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-step-title/vorgang-detail-bescheiden-step-title.component.html index 31596875ea050b030f15b2960650a111764a15a1..8a82e62b23b248ab3ba1b6521b34f0b6eba6538f 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-step-title/vorgang-detail-bescheiden-step-title.component.html +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-step-title/vorgang-detail-bescheiden-step-title.component.html @@ -23,6 +23,6 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<div class="my-2 text-base font-bold text-primary-600" data-test-id="step-caption"> +<div class="text-base font-bold text-primary-600" data-test-id="step-caption"> {{ label }} </div> diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-dokument-hochladen/vorgang-detail-bescheiden-dokument-hochladen.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-dokument-hochladen/vorgang-detail-bescheiden-dokument-hochladen.component.spec.ts index 471467b8ea09fd329b97ba5a71b353556501d909..5b089dac014abc5a0da5991e964ba167b50edcf9 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-dokument-hochladen/vorgang-detail-bescheiden-dokument-hochladen.component.spec.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-dokument-hochladen/vorgang-detail-bescheiden-dokument-hochladen.component.spec.ts @@ -22,7 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { BescheidService } from '@alfa-client/bescheid-shared'; -import { HasLinkPipe, TechSharedModule } from '@alfa-client/tech-shared'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; @@ -59,7 +59,7 @@ describe('VorgangDetailBescheidenDokumentHochladenComponent', () => { MockComponent(SingleFileUploadEditorComponent), MockComponent(SpinnerIconComponent), ], - imports: [ReactiveFormsModule, TechSharedModule], + imports: [ReactiveFormsModule], providers: [ { provide: BescheidenFormService, @@ -119,10 +119,7 @@ describe('VorgangDetailBescheidenDokumentHochladenComponent', () => { component.uploadFile(file); - expect(bescheidService.uploadBescheidDocument).toHaveBeenCalledWith( - bescheidStateResource.resource, - file, - ); + expect(bescheidService.uploadBescheidDocument).toHaveBeenCalledWith(bescheidStateResource.resource, file); }); }); }); diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts index 32aba2314074dfd4c1db59679594e9cd00767f4e..df1ec6563ff01d6130ab2cf54e144c5bfc970465 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts @@ -31,8 +31,22 @@ import { LoeschAnforderungModule } from '@alfa-client/loesch-anforderung'; import { LoeschAnforderungSharedModule } from '@alfa-client/loesch-anforderung-shared'; import { PostfachModule } from '@alfa-client/postfach'; import { PostfachSharedModule } from '@alfa-client/postfach-shared'; -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { ConvertForDataTestPipe, ConvertProblemDetailToErrorMessagesPipe, HasLinkPipe } from '@alfa-client/tech-shared'; +import { + BackButtonComponent, + DateEditorComponent, + ExpansionPanelComponent, + IconButtonWithSpinnerComponent, + OzgcloudIconButtonPrimaryComponent, + OzgcloudIconComponent, + OzgcloudMenuComponent, + OzgcloudPasteTextButtonComponent, + OzgcloudStrokedButtonWithSpinnerComponent, + OzgcloudTextEditorComponent, + SpinnerComponent, + SpinnerTransparencyComponent, + SubnavigationComponent, +} from '@alfa-client/ui'; import { UserProfileModule } from '@alfa-client/user-profile'; import { UserProfileSharedModule } from '@alfa-client/user-profile-shared'; import { VorgangSharedModule } from '@alfa-client/vorgang-shared'; @@ -40,13 +54,18 @@ import { VorgangSharedUiModule } from '@alfa-client/vorgang-shared-ui'; import { WiedervorlageModule } from '@alfa-client/wiedervorlage'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatDialogActions, MatDialogContent } from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { MatMenuTrigger } from '@angular/material/menu'; +import { MatTab, MatTabContent, MatTabGroup } from '@angular/material/tabs'; import { RouterModule, Routes } from '@angular/router'; import { ButtonWithSpinnerComponent, FileUploadEditorComponent, SingleFileUploadEditorComponent, - TextEditorComponent, TextareaEditorComponent, + TextEditorComponent, } from '@ods/component'; import { ArchiveIconComponent, @@ -76,6 +95,8 @@ import { TooltipDirective, UndoIconComponent, } from '@ods/system'; +import { NotHasAnyLinkPipe } from '../../../tech-shared/src/lib/pipe/not-has-any-link.pipe'; +import { ProgressBarComponent } from '../../../ui/src/lib/ui/progress-bar/progress-bar.component'; import { AktenzeichenEditDialogComponent } from './aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component'; import { AktenzeichenEditableComponent } from './aktenzeichen-editable/aktenzeichen-editable.component'; import { AbschliessenButtonComponent } from './buttons/abschliessen-button/abschliessen-button.component'; @@ -141,8 +162,6 @@ const routes: Routes = [ CommonModule, RouterModule.forChild(routes), VorgangSharedModule, - UiModule, - TechSharedModule, WiedervorlageModule, BinaryFileModule, ForwardingModule, @@ -182,6 +201,31 @@ const routes: Routes = [ ArchiveIconComponent, CheckCircleIconComponent, CheckIconComponent, + MatDialogContent, + ReactiveFormsModule, + MatIcon, + OzgcloudPasteTextButtonComponent, + MatDialogActions, + OzgcloudStrokedButtonWithSpinnerComponent, + OzgcloudIconButtonPrimaryComponent, + HasLinkPipe, + IconButtonWithSpinnerComponent, + ExpansionPanelComponent, + MatTabGroup, + MatTab, + NotHasAnyLinkPipe, + BackButtonComponent, + ConvertForDataTestPipe, + ConvertProblemDetailToErrorMessagesPipe, + DateEditorComponent, + MatMenuTrigger, + OzgcloudIconComponent, + OzgcloudMenuComponent, + SubnavigationComponent, + ProgressBarComponent, + SpinnerTransparencyComponent, + SpinnerComponent, + OzgcloudTextEditorComponent, DropdownMenuComponent, DropdownMenuTextItemComponent, MoreIconComponent, @@ -190,6 +234,7 @@ const routes: Routes = [ TooltipDirective, EditIconComponent, DiscardVorgangIconComponent, + MatTabContent, ], declarations: [ VorgangDetailPageComponent, diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-shared-ui.module.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-shared-ui.module.ts index a6549aff7c59fa5979d55f7fbb7bb130b9c068fc..96348a1634f974b37b2626bc204283a10f82bb09 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-shared-ui.module.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-shared-ui.module.ts @@ -21,11 +21,23 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { + ConvertForDataTestPipe, + EnumToLabelPipe, + FormatToPrettyDatePipe, + HasLinkPipe, + ToEmbeddedResourcesPipe, +} from '@alfa-client/tech-shared'; +import { OzgcloudSvgIconComponent, SpinnerComponent } from '@alfa-client/ui'; import { VorgangSharedModule } from '@alfa-client/vorgang-shared'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatAutocomplete, MatAutocompleteTrigger, MatOption } from '@angular/material/autocomplete'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormField, MatFormFieldModule } from '@angular/material/form-field'; +import { MatIcon, MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; import { RouterModule } from '@angular/router'; import { TooltipDirective } from '@ods/system'; import { AktenzeichenComponent } from './aktenzeichen/aktenzeichen.component'; @@ -39,7 +51,29 @@ import { VorgangStatusTextComponent } from './vorgang-status-text/vorgang-status import { WiedervorlageIconComponent } from './wiedervorlage-icon/wiedervorlage-icon.component'; @NgModule({ - imports: [CommonModule, VorgangSharedModule, UiModule, RouterModule, TechSharedModule, TooltipDirective], + imports: [ + CommonModule, + VorgangSharedModule, + RouterModule, + FormatToPrettyDatePipe, + MatIcon, + MatIconModule, + MatInputModule, + MatFormField, + MatButtonModule, + MatFormFieldModule, + ReactiveFormsModule, + MatAutocompleteTrigger, + MatAutocomplete, + SpinnerComponent, + MatOption, + ToEmbeddedResourcesPipe, + HasLinkPipe, + ConvertForDataTestPipe, + EnumToLabelPipe, + OzgcloudSvgIconComponent, + TooltipDirective, + ], declarations: [ VorgangSearchContainerComponent, VorgangSearchComponent, diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-dot/vorgang-status-dot.component.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-dot/vorgang-status-dot.component.spec.ts index fc9be609db475e87f46dad098cf66db0129cef8e..9b833b88003f980053c56d8787bd94dfbe46aab2 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-dot/vorgang-status-dot.component.spec.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-dot/vorgang-status-dot.component.spec.ts @@ -21,9 +21,9 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; import { EnumToLabelPipe } from '@alfa-client/tech-shared'; import { VorgangResource } from '@alfa-client/vorgang-shared'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { createVorgangResource } from 'libs/vorgang-shared/test/vorgang'; import { VorgangStatusDotComponent } from './vorgang-status-dot.component'; @@ -37,7 +37,8 @@ describe('VorgangStatusDotComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [VorgangStatusDotComponent, EnumToLabelPipe], + imports: [EnumToLabelPipe], + declarations: [VorgangStatusDotComponent], }).compileComponents(); }); diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.spec.ts index c49336ccf22b1bb28fdbe874b9f898f9d1b21cf7..ec5f8e7063df5a226688de7e69752b20d5d17696 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.spec.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.spec.ts @@ -37,7 +37,8 @@ describe('VorgangStatusTextComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [EnumToLabelPipe, VorgangStatusTextComponent], + imports: [EnumToLabelPipe], + declarations: [VorgangStatusTextComponent], }).compileComponents(); }); diff --git a/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.repository.spec.ts b/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.repository.spec.ts index fa699a030e07f79ddd830ef5b171ce14be24cdc3..f322aa355155dfd54fc231023a4f7b349382b1b4 100644 --- a/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.repository.spec.ts +++ b/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.repository.spec.ts @@ -21,34 +21,22 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; import { ApiRootLinkRel, ApiRootResource } from '@alfa-client/api-root-shared'; -import { - ContentType, - GetRequestOptions, - HttpErrorHandler, - HttpHeader, -} from '@alfa-client/tech-shared'; +import { BlobWithFileName, ContentType, GetRequestOptions, HttpErrorHandler, HttpHeader } from '@alfa-client/tech-shared'; import { mock, mockClass, useFromMock } from '@alfa-client/test-utils'; +import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; import { LinkRel, ResourceFactory, ResourceUri, getUrl } from '@ngxp/rest'; -import { cold, hot } from 'jest-marbles'; import { createApiRootResource } from 'libs/api-root-shared/test/api-root'; -import { TechSharedModule } from 'libs/tech-shared/src/lib/tech-shared.module'; +import { InjectorService } from 'libs/tech-shared/src/lib/injector/injector.service'; import { createVorgangListResource, createVorgangResource, createVorgangWithEingangResource, } from 'libs/vorgang-shared/test/vorgang'; -import { - VorgangHeaderLinkRel, - VorgangListLinkRel, - VorgangWithEingangLinkRel, -} from './../vorgang.linkrel'; -import { - VorgangListResource, - VorgangResource, - VorgangWithEingangResource, -} from './../vorgang.model'; +import { Observable } from 'rxjs'; +import { singleCold, singleHot } from '../../../../tech-shared/test/marbles'; +import { VorgangHeaderLinkRel, VorgangListLinkRel, VorgangWithEingangLinkRel } from './../vorgang.linkrel'; +import { VorgangListResource, VorgangResource, VorgangWithEingangResource } from './../vorgang.model'; import { VorgangRepository } from './vorgang.repository'; describe('VorgangRepository', () => { @@ -70,7 +58,7 @@ describe('VorgangRepository', () => { const linkRel: string = 'dummyLinkRel'; beforeEach(() => { - resourceWrapper.get.mockReturnValue(hot('a', { a: vorgangListResource })); + resourceWrapper.get.mockReturnValue(singleHot(vorgangListResource)); }); it('should call resourceFactory with resource', () => { @@ -86,20 +74,17 @@ describe('VorgangRepository', () => { }); it('should return result', () => { - let result = repository.loadVorgangList(apiRootResource, linkRel); + let result: Observable<VorgangListResource> = repository.loadVorgangList(apiRootResource, linkRel); - expect(result).not.toBeNull(); - expect(result).toBeObservable(cold('a', { a: vorgangListResource })); + expect(result).toBeObservable(singleCold(vorgangListResource)); }); }); describe('getNextVorgangListPage', () => { - const vorgangListResource: VorgangListResource = createVorgangListResource([ - VorgangListLinkRel.NEXT, - ]); + const vorgangListResource: VorgangListResource = createVorgangListResource([VorgangListLinkRel.NEXT]); beforeEach(() => { - resourceWrapper.get.mockReturnValue(hot('a', { a: vorgangListResource })); + resourceWrapper.get.mockReturnValue(singleHot(vorgangListResource)); }); it('should call resourceFactory with resource', () => { @@ -115,29 +100,22 @@ describe('VorgangRepository', () => { }); it('should return result', () => { - let result = repository.getNextVorgangListPage(vorgangListResource); + let result: Observable<VorgangListResource> = repository.getNextVorgangListPage(vorgangListResource); - expect(result).not.toBeNull(); - expect(result).toBeObservable(cold('a', { a: vorgangListResource })); + expect(result).toBeObservable(singleCold(vorgangListResource)); }); }); describe('getVorgangWithEingang', () => { - const vorgangResource: VorgangResource = createVorgangResource([ - VorgangHeaderLinkRel.VORGANG_WITH_EINGANG, - ]); - const vorgangWithEingangUrl = getUrl( - vorgangResource, - VorgangHeaderLinkRel.VORGANG_WITH_EINGANG, - ); - const vorgangWithEingangResource: VorgangWithEingangResource = - createVorgangWithEingangResource(); + const vorgangResource: VorgangResource = createVorgangResource([VorgangHeaderLinkRel.VORGANG_WITH_EINGANG]); + const vorgangWithEingangUrl: string = getUrl(vorgangResource, VorgangHeaderLinkRel.VORGANG_WITH_EINGANG); + const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource(); beforeEach(() => { - const classMock = mockClass(TechSharedModule); + const classMock = mockClass(InjectorService); classMock.injector = <any>{ get: () => useFromMock(mock(HttpErrorHandler)) }; - resourceWrapper.get.mockReturnValue(hot('a', { a: vorgangWithEingangResource })); + resourceWrapper.get.mockReturnValue(singleHot(vorgangWithEingangResource)); }); it('should call resourceFactory with resource', () => { @@ -155,18 +133,17 @@ describe('VorgangRepository', () => { it('should return result', () => { let result = repository.getVorgang(vorgangWithEingangUrl); - expect(result).not.toBeNull(); - expect(result).toBeObservable(cold('a', { a: vorgangWithEingangResource })); + expect(result).toBeObservable(singleCold(vorgangWithEingangResource)); }); }); describe('getAttachments', () => { - const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource( - [VorgangWithEingangLinkRel.ATTACHMENTS], - ); + const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource([ + VorgangWithEingangLinkRel.ATTACHMENTS, + ]); beforeEach(() => { - resourceWrapper.get.mockReturnValue(hot('a', { a: vorgangWithEingangResource })); + resourceWrapper.get.mockReturnValue(singleHot(vorgangWithEingangResource)); }); it('should call resourceFactory with resource', () => { @@ -185,7 +162,7 @@ describe('VorgangRepository', () => { let result = repository.getAttachments(vorgangWithEingangResource); expect(result).not.toBeNull(); - expect(result).toBeObservable(cold('a', { a: vorgangWithEingangResource })); + expect(result).toBeObservable(singleCold(vorgangWithEingangResource)); }); }); @@ -194,7 +171,7 @@ describe('VorgangRepository', () => { const apiRootResource: ApiRootResource = createApiRootResource(); beforeEach(() => { - resourceWrapper.get.mockReturnValue(hot('a', { a: vorgangListResource })); + resourceWrapper.get.mockReturnValue(singleHot(vorgangListResource)); repository.buildSearchByUrl = jest.fn(); }); @@ -213,19 +190,9 @@ describe('VorgangRepository', () => { it('should call buildSearchByUrl', () => { const searchString: string = 'i search for...'; const limit: number = 7; - repository.searchVorgaengeBy( - apiRootResource, - searchString, - ApiRootLinkRel.SEARCH_ALLE, - limit, - ); - - expect(repository.buildSearchByUrl).toHaveBeenCalledWith( - apiRootResource, - searchString, - ApiRootLinkRel.SEARCH_ALLE, - limit, - ); + repository.searchVorgaengeBy(apiRootResource, searchString, ApiRootLinkRel.SEARCH_ALLE, limit); + + expect(repository.buildSearchByUrl).toHaveBeenCalledWith(apiRootResource, searchString, ApiRootLinkRel.SEARCH_ALLE, limit); }); }); @@ -242,11 +209,7 @@ describe('VorgangRepository', () => { _links, }; - const searchUrl: ResourceUri = repository.buildSearchByUrl( - apiRootResource, - 'searchParam', - ApiRootLinkRel.SEARCH_ALLE, - ); + const searchUrl: ResourceUri = repository.buildSearchByUrl(apiRootResource, 'searchParam', ApiRootLinkRel.SEARCH_ALLE); expect(searchUrl).toEqual(baseUrl + '&' + VorgangRepository.SEARCH_PARAM + '=searchParam'); }); @@ -254,11 +217,7 @@ describe('VorgangRepository', () => { it('should ignore unused, optional parameters', () => { const apiRoot: ApiRootResource = buildLinksWithSearch(baseUrl + '{&searchBy,limit}'); - const searchUrl: ResourceUri = repository.buildSearchByUrl( - apiRoot, - 'search', - ApiRootLinkRel.SEARCH_ALLE, - ); + const searchUrl: ResourceUri = repository.buildSearchByUrl(apiRoot, 'search', ApiRootLinkRel.SEARCH_ALLE); expect(searchUrl).toEqual(baseUrl + '&' + VorgangRepository.SEARCH_PARAM + '=search'); }); @@ -267,16 +226,9 @@ describe('VorgangRepository', () => { const limit = 5; const res = buildLinksWithSearch(baseUrl + '{&searchBy,limit}'); - const searchUrl: ResourceUri = repository.buildSearchByUrl( - res, - 'search', - ApiRootLinkRel.SEARCH_ALLE, - limit, - ); + const searchUrl: ResourceUri = repository.buildSearchByUrl(res, 'search', ApiRootLinkRel.SEARCH_ALLE, limit); - expect(searchUrl).toEqual( - baseUrl + '&' + VorgangRepository.SEARCH_PARAM + '=search&limit=' + limit, - ); + expect(searchUrl).toEqual(baseUrl + '&' + VorgangRepository.SEARCH_PARAM + '=search&limit=' + limit); }); function buildLinksWithSearch(searchHref: string): ApiRootResource { @@ -288,21 +240,16 @@ describe('VorgangRepository', () => { describe('loadMeineVorgaengeList', () => { const vorgangListResource: VorgangListResource = createVorgangListResource(); - const apiRootResource: ApiRootResource = createApiRootResource([ - ApiRootLinkRel.MEINE_VORGAENGE, - ]); + const apiRootResource: ApiRootResource = createApiRootResource([ApiRootLinkRel.MEINE_VORGAENGE]); beforeEach(() => { - resourceWrapper.get.mockReturnValue(hot('a', { a: vorgangListResource })); + resourceWrapper.get.mockReturnValue(singleHot(vorgangListResource)); }); it('should call resourceFactory with uri', () => { repository.loadMeineVorgaengeList(apiRootResource); - const urlWithoutParameter: URL = repository.getUrlWithoutParameter( - apiRootResource, - ApiRootLinkRel.MEINE_VORGAENGE, - ); + const urlWithoutParameter: URL = repository.getUrlWithoutParameter(apiRootResource, ApiRootLinkRel.MEINE_VORGAENGE); expect(resourceFactory.fromId).toHaveBeenCalledWith(urlWithoutParameter.href); }); @@ -313,17 +260,14 @@ describe('VorgangRepository', () => { }); it('should return result', () => { - let result = repository.loadMeineVorgaengeList(apiRootResource); + let result: Observable<VorgangListResource> = repository.loadMeineVorgaengeList(apiRootResource); - expect(result).not.toBeNull(); - expect(result).toBeObservable(cold('a', { a: vorgangListResource })); + expect(result).toBeObservable(singleCold(vorgangListResource)); }); }); describe('export', () => { - const vorgangWithEingang: VorgangWithEingangResource = createVorgangWithEingangResource([ - VorgangWithEingangLinkRel.EXPORT, - ]); + const vorgangWithEingang: VorgangWithEingangResource = createVorgangWithEingangResource([VorgangWithEingangLinkRel.EXPORT]); const body: Blob = new Blob(); const fileName: string = '927ee047-0123-4c36-911c-52e984accc87_Abgabe.Abgabe.0401.xdomea'; @@ -331,7 +275,7 @@ describe('VorgangRepository', () => { const httpResponse: HttpResponse<Blob> = <any>{ body, headers: { get: () => headerString } }; beforeEach(() => { - httpClient.get.mockReturnValue(hot('a', { a: httpResponse })); + httpClient.get.mockReturnValue(singleHot(httpResponse)); }); it('should call httpClient', () => { @@ -341,16 +285,13 @@ describe('VorgangRepository', () => { repository.export(vorgangWithEingang); - expect(httpClient.get).toHaveBeenCalledWith( - getUrl(vorgangWithEingang, VorgangWithEingangLinkRel.EXPORT), - requestOptions, - ); + expect(httpClient.get).toHaveBeenCalledWith(getUrl(vorgangWithEingang, VorgangWithEingangLinkRel.EXPORT), requestOptions); }); it('should return value', () => { - const result = repository.export(vorgangWithEingang); + const result: Observable<BlobWithFileName> = repository.export(vorgangWithEingang); - expect(result).toBeObservable(cold('b', { b: { blob: body, fileName } })); + expect(result).toBeObservable(singleCold({ blob: body, fileName })); }); }); diff --git a/alfa-client/libs/vorgang-shared/src/lib/vorgang-shared.module.ts b/alfa-client/libs/vorgang-shared/src/lib/vorgang-shared.module.ts index 57caef25627930944e573e0a19fa44715c2df489..b2dd59e65837996bceeedffe8e605c8d2911813f 100644 --- a/alfa-client/libs/vorgang-shared/src/lib/vorgang-shared.module.ts +++ b/alfa-client/libs/vorgang-shared/src/lib/vorgang-shared.module.ts @@ -24,7 +24,6 @@ import { BinaryFileSharedModule } from '@alfa-client/binary-file-shared'; import { CommandSharedModule } from '@alfa-client/command-shared'; import { NavigationSharedModule } from '@alfa-client/navigation-shared'; -import { TechSharedModule } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; @@ -41,7 +40,6 @@ import * as fromVorgang from './+state/vorgang.reducer'; imports: [ CommonModule, RestModule, - TechSharedModule, CommandSharedModule, BinaryFileSharedModule, RouterModule, diff --git a/alfa-client/libs/vorgang/src/lib/vorgang.module.ts b/alfa-client/libs/vorgang/src/lib/vorgang.module.ts index cf3421cb9ed957b151e3cf8948828bde38b7f6b1..d1668cea27cf0e97e402293ebfdbf49d4c396980 100644 --- a/alfa-client/libs/vorgang/src/lib/vorgang.module.ts +++ b/alfa-client/libs/vorgang/src/lib/vorgang.module.ts @@ -22,8 +22,15 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { HintModule } from '@alfa-client/hint'; -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { + ConvertForDataTestPipe, + FormatDateWithoutYearWithTimePipe, + FormatDateWithTimePipe, + FormatToPrettyDatePipe, + HasLinkPipe, + ToResourceUriPipe, +} from '@alfa-client/tech-shared'; +import { OzgcloudIconComponent, OzgcloudRoutingButtonComponent, PostfachIconComponent, SpinnerComponent } from '@alfa-client/ui'; import { UserProfileModule } from '@alfa-client/user-profile'; import { VorgangSharedModule } from '@alfa-client/vorgang-shared'; import { VorgangSharedUiModule } from '@alfa-client/vorgang-shared-ui'; @@ -31,9 +38,13 @@ import { WiedervorlageModule } from '@alfa-client/wiedervorlage'; import { ScrollingModule } from '@angular/cdk/scrolling'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; +import { MatIcon, MatIconModule } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; import { RouterModule, Routes } from '@angular/router'; import { ButtonToggleGroupComponent } from '@ods/component'; +import { HasAnyLinkPipe } from '../../../tech-shared/src/lib/pipe/has-any-link.pipe'; import { ArchiveIconComponent, ButtonToggleComponent, TooltipDirective } from '@ods/system'; import { vorgangFilterViewGuard } from './vorgang-filter-view.guard'; import { VorgangListContainerComponent } from './vorgang-list-container/vorgang-list-container.component'; @@ -169,9 +180,7 @@ const routes: Routes = [ @NgModule({ imports: [ CommonModule, - TechSharedModule, ScrollingModule, - UiModule, RouterModule.forChild(routes), VorgangSharedModule, WiedervorlageModule, @@ -182,6 +191,21 @@ const routes: Routes = [ ButtonToggleComponent, ButtonToggleGroupComponent, ArchiveIconComponent, + FormatDateWithTimePipe, + FormatDateWithoutYearWithTimePipe, + MatIcon, + MatTooltip, + MatIconModule, + FormatToPrettyDatePipe, + ToResourceUriPipe, + ConvertForDataTestPipe, + HasLinkPipe, + PostfachIconComponent, + SpinnerComponent, + ReactiveFormsModule, + OzgcloudRoutingButtonComponent, + OzgcloudIconComponent, + HasAnyLinkPipe, TooltipDirective, ], declarations: [ diff --git a/alfa-client/libs/wiedervorlage/src/lib/submit-wiedervorlage-button/submit-wiedervorlage-button.component.html b/alfa-client/libs/wiedervorlage/src/lib/submit-wiedervorlage-button/submit-wiedervorlage-button.component.html index c0d873acccd4aa1879d455928b7dbaa386bac5e7..231640ded0433d236945ca15247c90bdc3273231 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/submit-wiedervorlage-button/submit-wiedervorlage-button.component.html +++ b/alfa-client/libs/wiedervorlage/src/lib/submit-wiedervorlage-button/submit-wiedervorlage-button.component.html @@ -26,21 +26,22 @@ @if (showAsIconButton) { <ods-button-with-spinner [stateResource]="submitInProgress$ | async" + (clickEmitter)="submit()" [tooltip]="'Wiedervorlage speichern'" tooltipAriaType="aria-labelledby" variant="ghost" size="fit" - (clickEmitter)="submit()" + dataTestId="speichern-icon-button" > <ods-save-icon icon class="fill-text" /> </ods-button-with-spinner> } @else { <ods-button-with-spinner - data-test-id="speichern-button" [stateResource]="submitInProgress$ | async" + (clickEmitter)="submit()" text="Speichern" variant="outline" - (clickEmitter)="submit()" + dataTestId="speichern-button" > <ods-save-icon icon /> </ods-button-with-spinner> diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-form/wiedervorlage-form.component.spec.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-form/wiedervorlage-form.component.spec.ts index 2d573153c6a323f3a4d30f421a75af0e10cfb818..f7dfb80e9b4ab4478fc2063574cda7411e15498d 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-form/wiedervorlage-form.component.spec.ts +++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-form/wiedervorlage-form.component.spec.ts @@ -21,18 +21,14 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { SimpleChanges } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { UntypedFormBuilder, ReactiveFormsModule } from '@angular/forms'; import { BinaryFileAttachmentContainerComponent } from '@alfa-client/binary-file'; import { BinaryFileListResource } from '@alfa-client/binary-file-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; -import { DateEditorComponent, TextAreaEditorComponent, TextEditorComponent } from '@alfa-client/ui'; -import { - WiedervorlageLinkRel, - WiedervorlageResource, - WiedervorlageService, -} from '@alfa-client/wiedervorlage-shared'; +import { DateEditorComponent, OzgcloudTextEditorComponent, TextAreaEditorComponent } from '@alfa-client/ui'; +import { WiedervorlageLinkRel, WiedervorlageResource, WiedervorlageService } from '@alfa-client/wiedervorlage-shared'; +import { SimpleChanges } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; import { createBinaryFileListResource } from 'libs/binary-file-shared/test/binary-file'; import { createWiedervorlageResource } from 'libs/wiedervorlage-shared/test/wiedervorlage'; import { MockComponent } from 'ng-mocks'; @@ -45,10 +41,7 @@ describe('WiedervorlageFormComponent', () => { let component: WiedervorlageFormComponent; let fixture: ComponentFixture<WiedervorlageFormComponent>; - const formService = new WiedervorlageFormService( - new UntypedFormBuilder(), - useFromMock(mock(WiedervorlageService)), - ); + const formService = new WiedervorlageFormService(new UntypedFormBuilder(), useFromMock(mock(WiedervorlageService))); const wiedervorlageService: Mock<WiedervorlageService> = mock(WiedervorlageService); const wiedervorlage: WiedervorlageResource = createWiedervorlageResource(); @@ -57,7 +50,7 @@ describe('WiedervorlageFormComponent', () => { declarations: [ WiedervorlageFormComponent, MockComponent(DateEditorComponent), - MockComponent(TextEditorComponent), + MockComponent(OzgcloudTextEditorComponent), MockComponent(TextAreaEditorComponent), MockComponent(BinaryFileAttachmentContainerComponent), MockComponent(SubmitWiedervorlageButtonComponent), @@ -118,16 +111,12 @@ describe('WiedervorlageFormComponent', () => { }); it('should call wiedervorlage service to get attachments if links exists', () => { - const wiedervorlageWithAttachments: WiedervorlageResource = createWiedervorlageResource([ - WiedervorlageLinkRel.ATTACHMENTS, - ]); + const wiedervorlageWithAttachments: WiedervorlageResource = createWiedervorlageResource([WiedervorlageLinkRel.ATTACHMENTS]); component.wiedervorlage = wiedervorlageWithAttachments; component.updateAttachments(); - expect(wiedervorlageService.getAttachmentList).toHaveBeenCalledWith( - wiedervorlageWithAttachments, - ); + expect(wiedervorlageService.getAttachmentList).toHaveBeenCalledWith(wiedervorlageWithAttachments); }); it('should NOT call wiedervorlage service if link is not present', () => { diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-status/wiedervorlage-status.component.spec.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-status/wiedervorlage-status.component.spec.ts index ab2dd54f9740cb097bff0679157bc920bf8e762e..86383128c2a8cf444467208cd4b0fab3acdfb3fa 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-status/wiedervorlage-status.component.spec.ts +++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-status/wiedervorlage-status.component.spec.ts @@ -35,8 +35,8 @@ describe('WiedervorlageStatusComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [WiedervorlageStatusComponent, ToTrafficLightPipe], - imports: [MatIcon], + declarations: [WiedervorlageStatusComponent], + imports: [MatIcon, ToTrafficLightPipe], }).compileComponents(); }); diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage.module.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage.module.ts index 7729ab5f2f68770e3b6e2e850fc9279f3a731406..2057849d9d85c3365877c9d58fd022a8137029dc 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage.module.ts +++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage.module.ts @@ -22,13 +22,34 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { BinaryFileModule } from '@alfa-client/binary-file'; -import { TechSharedModule } from '@alfa-client/tech-shared'; -import { UiModule } from '@alfa-client/ui'; +import { + ConvertForDataTestPipe, + FormatToPrettyDatePipe, + HasLinkPipe, + ToEmbeddedResourcesPipe, + ToResourceUriPipe, + ToTrafficLightPipe, + ToTrafficLightTooltipPipe, +} from '@alfa-client/tech-shared'; +import { + BackButtonComponent, + DateEditorComponent, + ExpansionPanelComponent, + IconButtonWithSpinnerComponent, + OzgcloudStrokedButtonWithSpinnerComponent, + OzgcloudTextEditorComponent, + SpinnerComponent, + SubnavigationComponent, + TextAreaEditorComponent, +} from '@alfa-client/ui'; import { UserProfileModule } from '@alfa-client/user-profile'; import { VorgangSharedModule } from '@alfa-client/vorgang-shared'; import { VorgangSharedUiModule } from '@alfa-client/vorgang-shared-ui'; import { CommonModule, DatePipe } from '@angular/common'; import { NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; import { RouterModule, Routes } from '@angular/router'; import { ButtonWithSpinnerComponent } from '@ods/component'; import { @@ -71,12 +92,29 @@ const routes: Routes = [ imports: [ CommonModule, RouterModule.forChild(routes), - UiModule, VorgangSharedModule, - TechSharedModule, VorgangSharedUiModule, BinaryFileModule, UserProfileModule, + HasLinkPipe, + IconButtonWithSpinnerComponent, + OzgcloudStrokedButtonWithSpinnerComponent, + MatIcon, + MatTooltip, + ToTrafficLightTooltipPipe, + ToResourceUriPipe, + FormatToPrettyDatePipe, + SpinnerComponent, + ExpansionPanelComponent, + ToEmbeddedResourcesPipe, + BackButtonComponent, + ReactiveFormsModule, + OzgcloudTextEditorComponent, + TextAreaEditorComponent, + DateEditorComponent, + SubnavigationComponent, + ToTrafficLightPipe, + ConvertForDataTestPipe, ButtonWithSpinnerComponent, TooltipDirective, UpdateIconComponent, diff --git a/alfa-client/libs/zustaendige-stelle-shared/src/lib/organisations-einheit/organisations-einheit.model.ts b/alfa-client/libs/zustaendige-stelle-shared/src/lib/organisations-einheit/organisations-einheit.model.ts index a802fe79f851232dcb9c8e27beae5c64f8db2b01..2658c1475c9ca56179e0590d511a948ce3f3adf7 100644 --- a/alfa-client/libs/zustaendige-stelle-shared/src/lib/organisations-einheit/organisations-einheit.model.ts +++ b/alfa-client/libs/zustaendige-stelle-shared/src/lib/organisations-einheit/organisations-einheit.model.ts @@ -27,6 +27,7 @@ import { Resource } from '@ngxp/rest'; export interface OrganisationsEinheit { name: string; anschrift: Anschrift; + organisationEinheitId: string; } export interface Anschrift { diff --git a/alfa-client/libs/zustaendige-stelle-shared/test/organisations-einheit.ts b/alfa-client/libs/zustaendige-stelle-shared/test/organisations-einheit.ts index 2257be08968edef9d5287bf9913a6025fe57dd78..d4aa69a51af006f51b1c1ec551f5d212c1e6e647 100644 --- a/alfa-client/libs/zustaendige-stelle-shared/test/organisations-einheit.ts +++ b/alfa-client/libs/zustaendige-stelle-shared/test/organisations-einheit.ts @@ -45,6 +45,7 @@ export function createOrganisationsEinheit(): OrganisationsEinheit { return { name: faker.word.sample(), anschrift: createAnschrift(), + organisationEinheitId: faker.string.uuid(), }; } diff --git a/alfa-client/libs/zustaendige-stelle/src/lib/zustaendige-stelle.module.ts b/alfa-client/libs/zustaendige-stelle/src/lib/zustaendige-stelle.module.ts index 0ca329814a60a3bcc0ef1724dd6e82e3cd93b162..820da330c99f8e0d184b5c6b38096db8c03604bb 100644 --- a/alfa-client/libs/zustaendige-stelle/src/lib/zustaendige-stelle.module.ts +++ b/alfa-client/libs/zustaendige-stelle/src/lib/zustaendige-stelle.module.ts @@ -21,7 +21,6 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { TechSharedModule } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; @@ -50,7 +49,6 @@ import { ZustaendigeStelleHeaderComponent } from './zustaendige-stelle-header/zu CommonModule, ButtonComponent, CloseIconComponent, - TechSharedModule, InstantSearchComponent, FormsModule, ReactiveFormsModule, diff --git a/alfa-client/nx.json b/alfa-client/nx.json index 45e3e58f414b34a448360de13c8e82e818c03c45..4153173c1960cf6aeb57131d786bfb1554f09e83 100644 --- a/alfa-client/nx.json +++ b/alfa-client/nx.json @@ -103,6 +103,7 @@ } }, "useInferencePlugins": false, + "defaultBase": "main", "release": { "projects": ["admin", "alfa", "info"], "projectsRelationship": "independent" diff --git a/alfa-client/tsconfig.base.json b/alfa-client/tsconfig.base.json index 6850f74e4eb7c031308a264a51e8a4782fa9613b..f6bb4c8b2657d8acef026b997d32794971be5656 100644 --- a/alfa-client/tsconfig.base.json +++ b/alfa-client/tsconfig.base.json @@ -22,6 +22,7 @@ "@admin-client/organisations-einheit-shared": ["libs/admin/organisations-einheit-shared/src/index.ts"], "@admin-client/postfach": ["libs/admin/postfach/src/index.ts"], "@admin-client/postfach-shared": ["libs/admin/postfach-shared/src/index.ts"], + "@admin-client/reporting-shared": ["libs/admin/reporting-shared/src/index.ts"], "@admin-client/settings-shared": ["libs/admin/settings-shared/src/index.ts"], "@admin-client/shared": ["libs/admin/shared/src/index.ts"], "@admin-client/statistik": ["libs/admin/statistik/src/index.ts"],