diff --git a/alfa-client/apps/admin-e2e/src/components/benutzer/benutzer.e2e.component.ts b/alfa-client/apps/admin-e2e/src/components/benutzer/benutzer.e2e.component.ts index 0af0f39b14cfd07cdd0ad868b8c780c1bbbea19f..7b9027ffdc33f6f5cef1980aac392859a457237d 100644 --- a/alfa-client/apps/admin-e2e/src/components/benutzer/benutzer.e2e.component.ts +++ b/alfa-client/apps/admin-e2e/src/components/benutzer/benutzer.e2e.component.ts @@ -22,154 +22,128 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import 'cypress-real-events'; -import { AdminUserE2E } from '../../model/util'; -import { exist } from '../../support/cypress.util'; +import { convertToDataTestId } from '../../support/tech-util'; -export class BenutzerE2EComponent { +export class BenutzerListE2EComponent { + private readonly headline: string = 'user-list-headline'; private readonly benutzerHinzufuegenButton: string = 'add-user-button'; - private readonly userEntry: string = 'user-entry-'; - private readonly userVorname: string = 'Vorname-text-input'; - private readonly userNachname: string = 'Nachname-text-input'; - private readonly userBenutzername: string = 'Benutzername-text-input'; - private readonly userMail: string = 'E-Mail-text-input'; - private readonly adminCheckbox: string = 'Admin-checkbox-editor'; - private readonly loeschenCheckbox: string = 'Loschen-checkbox-editor'; - private readonly userCheckbox: string = 'User-checkbox-editor'; - private readonly postCheckbox: string = 'Poststelle-checkbox-editor'; - private readonly saveButton: string = 'save-button'; - private readonly organisationsEinheitCheckbox: string = '-checkbox-editor'; + + public getHeadline(): Cypress.Chainable<Element> { + return cy.getTestElement(this.headline); + } public getHinzufuegenButton(): Cypress.Chainable<Element> { return cy.getTestElement(this.benutzerHinzufuegenButton); } - public hinzufuegenButtonIsVisible(): void { - exist(this.getHinzufuegenButton()); + public getItem(userName: string): BenutzerListItemE2EComponent { + return new BenutzerListItemE2EComponent(userName); } +} + +export class BenutzerListItemE2EComponent { + private root: string; - public clickAddUser(): void { - this.getHinzufuegenButton().click(); + private fullName: string = 'fullname'; + private email: string = 'email'; + private userName: string = 'username'; + + private roles: string = 'roles'; + + private organisationsEinheiten: string = 'organisations-einheiten'; + private noOrganisationsEinheitenText: string = 'no-organisations-einheit-text'; + + constructor(userName: string) { + this.root = convertToDataTestId(userName) + '-user-entry'; } - public addUser(user: AdminUserE2E): void { - this.enterVorname(user.vorname); - this.enterNachname(user.nachname); - this.enterBenutzername(user.benutzername); - this.enterMail(user.email); + public getRoot(): Cypress.Chainable<Element> { + return cy.getTestElement(this.root); + } - if (user.isAdmin) { - this.clickAdminCheckbox(); - } - if (user.isUser) { - this.clickUserCheckbox(); - } - if (user.isLoeschen) { - this.clickLoeschenCheckbox(); - } - if (user.isPoststelle) { - this.clickPostCheckbox(); - } + public getRoles(): Cypress.Chainable<Element> { + return this.getRoot().getTestElementWithClass(this.roles); + } - if (user.organisationseinheiten) { - for (const einheit of user.organisationseinheiten) { - this.clickOrganisationsEinheitCheckbox(einheit); - } - } - this.saveUser(); + public getOrganisationsEinheiten(): Cypress.Chainable<Element> { + return this.getRoot().getTestElementWithClass(this.organisationsEinheiten); } - public getUserEntry(user: string): Cypress.Chainable<Element> { - user = this.userEntry + user; - return cy.getTestElement(user); + public getNoOrganisationsEinheitText(): Cypress.Chainable<Element> { + return this.getRoot().getTestElementWithClass(this.noOrganisationsEinheitenText); } - public clickUserEntry(user: string): void { - this.getUserEntry(user).click(); + public getFullName(): Cypress.Chainable<Element> { + return this.getRoot().getTestElementWithClass(this.fullName); } - public stringExistsInUserEntry(phrase: string, user: string): void { - this.getUserEntry(user).within(() => { - exist(cy.contains(phrase)); - }); + public getEMail(): Cypress.Chainable<Element> { + return this.getRoot().getTestElementWithClass(this.email); } - public getVornameInput(): Cypress.Chainable<Element> { - return cy.getTestElement(this.userVorname); + public getUserName(): Cypress.Chainable<Element> { + return this.getRoot().getTestElementWithClass(this.userName); } +} + +export class BenutzerE2EComponent { + private readonly headline: string = 'benutzer-form-headline'; - public enterVorname(vorname: string): void { - this.getVornameInput().type(vorname); + private readonly userVorname: string = 'Vorname-text-input'; + private readonly userNachname: string = 'Nachname-text-input'; + private readonly userBenutzername: string = 'Benutzername-text-input'; + private readonly userMail: string = 'E-Mail-text-input'; + + private readonly adminCheckbox: string = 'Admin-checkbox-editor'; + private readonly loeschenCheckbox: string = 'Loschen-checkbox-editor'; + private readonly userCheckbox: string = 'User-checkbox-editor'; + private readonly postCheckbox: string = 'Poststelle-checkbox-editor'; + + private readonly organisationsEinheitCheckboxSuffix: string = '-checkbox-editor'; + + private readonly saveButton: string = 'save-button'; + + public getVornameInput(): Cypress.Chainable<Element> { + return cy.getTestElement(this.userVorname); } public getNachnameInput(): Cypress.Chainable<Element> { return cy.getTestElement(this.userNachname); } - public enterNachname(nachname: string): void { - this.getNachnameInput().type(nachname); - } - public getBenutzernameInput(): Cypress.Chainable<Element> { return cy.getTestElement(this.userBenutzername); } - public enterBenutzername(benutzername: string): void { - this.getBenutzernameInput().type(benutzername); - } - public getMailInput(): Cypress.Chainable<Element> { return cy.getTestElement(this.userMail); } - public enterMail(mail: string): void { - this.getMailInput().type(mail); - } - public getAdminCheckbox(): Cypress.Chainable<Element> { return cy.getTestElement(this.adminCheckbox); } - public clickAdminCheckbox(): void { - this.getAdminCheckbox().click(); - } - - public getLoeschenCheckbox() { + public getLoeschenCheckbox(): Cypress.Chainable<Element> { return cy.getTestElement(this.loeschenCheckbox); } - public clickLoeschenCheckbox(): void { - this.getLoeschenCheckbox().click(); - } - public getUserCheckbox(): Cypress.Chainable<Element> { return cy.getTestElement(this.userCheckbox); } - public clickUserCheckbox(): void { - this.getUserCheckbox().click(); - } - public getPostCheckbox(): Cypress.Chainable<Element> { return cy.getTestElement(this.postCheckbox); } - public clickPostCheckbox(): void { - this.getPostCheckbox().click(); - } - public getSaveButton(): Cypress.Chainable<Element> { return cy.getTestElement(this.saveButton); } - public saveUser(): void { - this.getSaveButton().click(); - } - public getOrganisationsEinheitCheckbox(einheit: string): Cypress.Chainable<Element> { - return cy.getTestElement(einheit + this.organisationsEinheitCheckbox); + return cy.getTestElement(einheit + this.organisationsEinheitCheckboxSuffix); } - public clickOrganisationsEinheitCheckbox(einheit: string): void { - this.getOrganisationsEinheitCheckbox(einheit).click(); + public getHeadline(): Cypress.Chainable<Element> { + return cy.getTestElement(this.headline); } } diff --git a/alfa-client/apps/admin-e2e/src/components/organisationseinheiten/organisationseinheiten-signatur.e2e.component.ts b/alfa-client/apps/admin-e2e/src/components/organisationseinheiten/organisationseinheiten-signatur.e2e.component.ts deleted file mode 100644 index e1f91229ad68813bbab4625854ddc2ed6f89b79d..0000000000000000000000000000000000000000 --- a/alfa-client/apps/admin-e2e/src/components/organisationseinheiten/organisationseinheiten-signatur.e2e.component.ts +++ /dev/null @@ -1,68 +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 { clearText, haveValue, typeText } from '../../support/cypress.util'; - -export class OrganisationseinheitenSignaturE2EComponent { - private readonly organisationsEinheitName: string = 'organisations-form-container-headline'; - private readonly signatureText: string = 'signature-textarea'; - private readonly saveSignatureButton: string = 'save-button'; - - public getOrganisationsEinheitName(): Cypress.Chainable<Element> { - return cy.getTestElement(this.organisationsEinheitName); - } - - public getSignatureText(): Cypress.Chainable<Element> { - return cy.getTestElement(this.signatureText); - } - - public setSignature(signatur: string): void { - this.clearSignature(); - typeText(this.getSignatureText(), signatur); - } - - public clearSignature(): void { - clearText(this.getSignatureText()); - } - - public getSaveButton(): Cypress.Chainable<Element> { - return cy.getTestElement(this.saveSignatureButton); - } - - public saveSignature(): void { - this.getSaveButton().click(); - } - - public hasSignature(compare: string): void { - haveValue(this.getSignatureText(), compare); - } - - public hasScrollbar(): void { - this.getSignatureText().then((textarea) => { - const scrollHeight = textarea[0].scrollHeight; - const clientHeight = textarea[0].clientHeight; - - expect(scrollHeight).to.be.greaterThan(clientHeight); - }); - } -} diff --git a/alfa-client/apps/admin-e2e/src/components/organisationseinheiten/organisationseinheiten.e2e.component.ts b/alfa-client/apps/admin-e2e/src/components/organisationseinheiten/organisationseinheiten.e2e.component.ts index 4d38f761c34b586f7da999a6a2e46a1d74056371..bfdf6b624d856e9b1a165f8984e739deccdc4a80 100644 --- a/alfa-client/apps/admin-e2e/src/components/organisationseinheiten/organisationseinheiten.e2e.component.ts +++ b/alfa-client/apps/admin-e2e/src/components/organisationseinheiten/organisationseinheiten.e2e.component.ts @@ -21,66 +21,21 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { containClass, exist, haveText, notContainClass } from '../../support/cypress.util'; export class OrganisationsEinheitenE2EComponent { private readonly organisationsEinheitenList: string = 'organisations-einheit-list'; - private readonly organisationsEinheitenName: string = 'organisations-einheit-name'; - private readonly organisationsEinheitenID: string = 'organisations-einheit-id'; private readonly organisationsEinheitHinzufuegen: string = 'add-organisationseinheit-button'; - private readonly errorColor: string = 'text-red-500'; - private readonly errorIcon: string = 'organisations-einheit-sync-error'; - - private readonly errorText: string = 'Organisationseinheit wurde nicht in den PVOG-Daten gefunden.'; + private readonly organisationsEinheitItemSuffix: string = '-organisation-item'; public getOrganisationsEinheitList(): Cypress.Chainable<Element> { return cy.getTestElement(this.organisationsEinheitenList); } - public getListItemByName(name: string): Cypress.Chainable<JQuery<HTMLElement>> { - return cy.getTestElement(this.organisationsEinheitenName).contains(name); - } - - public openOrganisationsEinheit(name: string): void { - this.getListItemByName(name).click(); - } - public getOrganisationsEinheitHinzufuegenButton(): Cypress.Chainable<Element> { return cy.getTestElement(this.organisationsEinheitHinzufuegen); } - public clickHinzufuegen(): void { - this.getOrganisationsEinheitHinzufuegenButton().click(); - } - - public organisationsEinheitContainsID(name: string, id: string): void { - this.getListItemByName(name) - .parents('a') - .within(() => { - haveText(cy.getTestElement(this.organisationsEinheitenID), id); - }); - } - - public elementIsShownAsError(name: string): void { - containClass(this.getListItemByName(name).closest('ods-list-item'), this.errorColor); - } - - public getErrorIconInElement(name: string): Cypress.Chainable<JQuery<HTMLAnchorElement>> { - return this.getListItemByName(name) - .parents('a') - .within(() => { - exist(cy.getTestElement(this.errorIcon)); - }); - } - - public getErrorTooltip(name: string): Cypress.Chainable<JQuery<HTMLElement>> { - return this.getErrorIconInElement(name) - .find('ods-exclamation-icon[mattooltip]') - .should('have.attr', 'mattooltip') - .and('include', this.errorText); - } - - public elementShowsNoError(name: string): void { - notContainClass(this.getListItemByName(name).closest('ods-list-item'), this.errorColor); + public getListItem(name: string) { + return cy.getTestElement(name + this.organisationsEinheitItemSuffix); } } diff --git a/alfa-client/apps/admin-e2e/src/components/statistik/statistik-fields-form.e2e.component.ts b/alfa-client/apps/admin-e2e/src/components/statistik/statistik-fields-form.e2e.component.ts index f3c565869006d9935a5c54de0a9fb388d73cbc3c..8936e02edbe69c765364304bc497d2be61a970da 100644 --- a/alfa-client/apps/admin-e2e/src/components/statistik/statistik-fields-form.e2e.component.ts +++ b/alfa-client/apps/admin-e2e/src/components/statistik/statistik-fields-form.e2e.component.ts @@ -1,15 +1,16 @@ import { enterWith } from '../../support/cypress.util'; export class StatistikFieldsFormE2EComponent { - private readonly locatorFormEngineInput: string = 'form-engine-input'; - private readonly locatorFormIdInput: string = 'form-id-input'; - private readonly locatorFormDataFieldInput: string = 'data-statistik-field-'; - private readonly locatorAddFieldButton: string = 'add-data-field-button'; - private readonly locatorSaveButton: string = 'save-statistik-fields-button'; - private readonly locatorCancelButton: string = 'cancel-statistik-fields-button'; + private readonly formEngineInput: string = 'form-engine-name-text-input'; + private readonly formIdInput: string = 'form-id-text-input'; + private readonly formDataFieldInput: string = 'mapping-field-'; + private readonly addDataFieldButton: string = 'add-mapping-button'; + private readonly deleteDataFieldButtonPrefix: string = 'remove-mapping-button-'; + private readonly saveButton: string = 'save-button'; + private readonly cancelButton: string = 'cancel-button'; public getFormEngineInput(): Cypress.Chainable<Element> { - return cy.getTestElement(this.locatorFormEngineInput); + return cy.getTestElement(this.formEngineInput); } public enterFormEngine(text: string): void { @@ -17,7 +18,7 @@ export class StatistikFieldsFormE2EComponent { } public getFormIdInput(): Cypress.Chainable<Element> { - return cy.getTestElement(this.locatorFormIdInput); + return cy.getTestElement(this.formIdInput); } public enterFormId(text: string): void { @@ -25,7 +26,7 @@ export class StatistikFieldsFormE2EComponent { } public getAddFieldButton(): Cypress.Chainable<Element> { - return cy.getTestElement(this.locatorAddFieldButton); + return cy.getTestElement(this.addDataFieldButton); } public addField(): void { @@ -33,15 +34,23 @@ export class StatistikFieldsFormE2EComponent { } public getDataFieldInput(index: number): Cypress.Chainable<Element> { - return cy.getTestElement(this.locatorFormDataFieldInput + index); + return cy.getTestElement(this.formDataFieldInput + index + '-text-input'); } public enterDataFieldPath(text: string, index: number): void { enterWith(this.getDataFieldInput(index), text); } + public getDataFieldDeleteButton(index: number): Cypress.Chainable<Element> { + return cy.getTestElement(this.deleteDataFieldButtonPrefix + index); + } + + public deleteDataField(index: number): void { + this.getDataFieldDeleteButton(index).click(); + } + public getSaveButton(): Cypress.Chainable<Element> { - return cy.getTestElement(this.locatorSaveButton); + return cy.getTestElement(this.saveButton); } public save(): void { @@ -49,7 +58,7 @@ export class StatistikFieldsFormE2EComponent { } public getCancelButton(): Cypress.Chainable<Element> { - return cy.getTestElement(this.locatorCancelButton); + return cy.getTestElement(this.cancelButton); } public cancel(): void { diff --git a/alfa-client/apps/admin-e2e/src/components/statistik/statistik.e2e.component.ts b/alfa-client/apps/admin-e2e/src/components/statistik/statistik.e2e.component.ts index 8748a5bad339ca0bc381d88d51c3fbe3747d0d16..b7467232f5d596a2984bc109e84180810c5e8dc3 100644 --- a/alfa-client/apps/admin-e2e/src/components/statistik/statistik.e2e.component.ts +++ b/alfa-client/apps/admin-e2e/src/components/statistik/statistik.e2e.component.ts @@ -1,14 +1,12 @@ -import { exist } from '../../support/cypress.util'; - export class StatistikE2EComponent { private readonly locatorHeaderText: string = 'statistik-header-text'; private readonly locatorWeitereFelderAuswertenButton = 'weitere-felder-auswerten-button'; - public isHeaderTextVisible(): void { - exist(cy.getTestElement(this.locatorHeaderText)); + public getHeaderText(): Cypress.Chainable<Element> { + return cy.getTestElement(this.locatorHeaderText); } - public getWeiterFelderAuswertenButton(): Cypress.Chainable<Element> { + public getWeitereFelderAuswertenButton(): Cypress.Chainable<Element> { return cy.getTestElement(this.locatorWeitereFelderAuswertenButton); } } diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts index 0b9aad6ab869bad69f47e7c59cbf0b85e39abe61..0d4a3c538f90b3621783a7f8ccc750429823434f 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts @@ -1,69 +1,60 @@ - -import { MainPage } from 'apps/admin-e2e/src/page-objects/main.po'; -import { BenutzerE2EComponent } from '../../../components/benutzer/benutzer.e2e.component'; -import { beChecked, beEnabled, contains, exist, notBeChecked, notBeEnabled } from '../../../support/cypress.util'; -import { AlfaRollen, AlfaUsers, loginAsAriane } from '../../../support/user-util'; +import { E2EBenutzerHelper } from 'apps/admin-e2e/src/helper/benutzer/benutzer.helper'; +import { E2EBenutzerVerifier } from 'apps/admin-e2e/src/helper/benutzer/benutzer.verifier'; +import { getCypressEnv, interceptWithResponse, waitOfInterceptor } from 'apps/admin-e2e/src/support/cypress-helper'; import { SnackBarE2EComponent } from '../../../components/ui/snackbar.e2e.component'; -import { SnackbarMessagesE2E } from '../../../model/util'; -import { getCypressEnv, interceptWithResponse, wait, waitOfInterceptor } from 'apps/admin-e2e/src/support/cypress-helper'; -import { AdminUserE2E, HttpMethodE2E } from '../../../model/util'; +import { AdminUserE2E, HttpMethodE2E, SnackbarMessagesE2E } from '../../../model/util'; +import { contains, notExist } from '../../../support/cypress.util'; +import { loginAsAriane } from '../../../support/user-util'; -const mainPage: MainPage = new MainPage(); -const benutzerPage: BenutzerE2EComponent = new BenutzerE2EComponent(); -const snackBar: SnackBarE2EComponent = new SnackBarE2EComponent(); +describe('Benutzer anlegen', () => { + const benutzerHelper: E2EBenutzerHelper = new E2EBenutzerHelper(); + const benutzerVerifier: E2EBenutzerVerifier = new E2EBenutzerVerifier(); -const vorname: string = 'Theo'; -const nachname: string = 'Testuser'; -const benutzername: string = 'testtheo'; -const emailAddress: string = 'theo.test@ozg-sh.de'; + const snackBar: SnackBarE2EComponent = new SnackBarE2EComponent(); -const newUser: AdminUserE2E = { - vorname: 'Theo', - nachname: 'Testuser', - benutzername: 'testtheo', - email: 'theo.test@ozg-sh.de', - isAdmin: true, - isUser: true, -} + const newUser: AdminUserE2E = { + vorname: 'Theo', + nachname: 'Testuser', + username: 'testtheo', + email: 'theo.test@ozg-sh.de', + isAdmin: true, + isUser: true, + organisationseinheiten: [], + }; -describe('Benutzer anlegen', () => { before(() => { loginAsAriane(); }); - it('should open Benutzer tab and show Hinzufuegen button', () => { - mainPage.clickBenutzerNavigationItem(); - - exist(benutzerPage.getHinzufuegenButton()); - }); - - it('should show snackbar message on error', () => { + it('should show error snackbar after save and receiving error response', () => { const interceptor: string = 'postUser'; - const url: string = getCypressEnv('keycloakUrl') + '/admin/realms/' + getCypressEnv('keycloakRealm') + '/users' + const url: string = getCypressEnv('keycloakUrl') + '/admin/realms/' + getCypressEnv('keycloakRealm') + '/users'; const errorCode: number = 500; const errorBody: string = 'Internal Server Error'; - interceptWithResponse(HttpMethodE2E.POST, url, { errorCode, errorBody }).as(interceptor); + benutzerHelper.openNewBenutzerPage(); - benutzerPage.clickAddUser(); - benutzerPage.addUser(newUser); + benutzerHelper.addBenutzer(newUser); + benutzerHelper.saveBenutzer(); waitOfInterceptor(interceptor).then(() => { contains(snackBar.getMessage(), SnackbarMessagesE2E.NUTZER_FEHLGESCHLAGEN); + snackBar.getCloseButton().click(); + notExist(snackBar.getMessage()); }); }); - it('should show snackbar message on saving user', () => { - snackBar.getCloseButton().click(); + it('should show snackbar after save', () => { + benutzerHelper.openNewBenutzerPage(); + + benutzerHelper.addBenutzer(newUser); + benutzerHelper.saveBenutzer(); - benutzerPage.saveUser(); contains(snackBar.getMessage(), SnackbarMessagesE2E.NUTZER_ANGELEGT); + snackBar.getCloseButton().click(); }); - it('should display new user in users table', () => { - benutzerPage.stringExistsInUserEntry(AlfaRollen.USER, benutzername); - benutzerPage.stringExistsInUserEntry(vorname, benutzername); - benutzerPage.stringExistsInUserEntry(nachname, benutzername); - // FEHLT NOCH: benutzerPage.stringExistsInUserEntry(AlfaRollen.ADMIN, benutzername); + it('should show created user in list', () => { + benutzerVerifier.verifyUserInList(newUser); }); }); 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 9095c63279a17ffe2cbada1f4de9f956593c0638..2a6fc233600a14024c3d62d7056afb41effa8750 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 @@ -1,110 +1,84 @@ -import { OrganisationsEinheitenE2EComponent } from 'apps/admin-e2e/src/components/organisationseinheiten/organisationseinheiten.e2e.component'; -import { ZustaendigeStelleDialogE2EComponent } from 'apps/admin-e2e/src/components/zustaendige-stelle/zustaendige-stelle-dialog.e2e.component'; +import { E2EBenutzerHelper } from 'apps/admin-e2e/src/helper/benutzer/benutzer.helper'; +import { E2EBenutzerVerifier } from 'apps/admin-e2e/src/helper/benutzer/benutzer.verifier'; +import { OrganisationsEinheitE2E } from 'apps/admin-e2e/src/model/organisations-einheit'; import { AdminUserE2E } from 'apps/admin-e2e/src/model/util'; -import { MainPage } from 'apps/admin-e2e/src/page-objects/main.po'; -import { BenutzerE2EComponent } from '../../../components/benutzer/benutzer.e2e.component'; -import { beChecked, exist, notBeChecked } from '../../../support/cypress.util'; import { loginAsAriane } from '../../../support/user-util'; describe('Organisationseinheit zu Benutzer hinzufügen', () => { - const mainPage: MainPage = new MainPage(); - const benutzerPage: BenutzerE2EComponent = new BenutzerE2EComponent(); - const organisationsEinheitenComponent: OrganisationsEinheitenE2EComponent = new OrganisationsEinheitenE2EComponent(); - const zustaendigeStelleSearchComponent: ZustaendigeStelleDialogE2EComponent = new ZustaendigeStelleDialogE2EComponent(); - const organistationsEinheitOrdnungsamt: string = 'Ordnungsamt'; - const organisationsEinheitDenkmalpflege: string = 'Denkmalpflege'; - const organisationsEinheitLiegenschaften: string = 'Liegenschaften'; - const organisationsEinheitNone: string = 'keine zuständige Stelle zugewiesen'; + const benutzerVerifier: E2EBenutzerVerifier = new E2EBenutzerVerifier(); + const benutzerHelper: E2EBenutzerHelper = new E2EBenutzerHelper(); + const vorname: string = 'Theo'; const nachname: string = 'Testuser'; + const now1 = new Date(); - const benutzername1: string = 'testtheo' + now1.getSeconds().toString() + now1.getMilliseconds().toString(); + const userName1: string = 'testtheo' + now1.getSeconds().toString() + now1.getMilliseconds().toString(); const emailAddress1: string = 'theo' + now1.getSeconds().toString() + now1.getMilliseconds().toString() + '@ozg-sh.de'; + const now2 = new Date(now1.getTime() + 1000); - const benutzername2: string = 'testtheo' + now2.getSeconds().toString() + now2.getMilliseconds().toString(); + const userName2: string = 'testtheo' + now2.getSeconds().toString() + now2.getMilliseconds().toString(); const emailAddress2: string = 'theo' + now2.getSeconds().toString() + now2.getMilliseconds().toString() + '@ozg-sh.de'; - const newUser1: AdminUserE2E = { + const userWithoutOrganisationsEinheiten: AdminUserE2E = { vorname: vorname, nachname: nachname, - benutzername: benutzername1, + username: userName1, email: emailAddress1, isUser: true, + organisationseinheiten: [], }; - const newUser2: AdminUserE2E = { + const userWithOrganisationsEinheiten: AdminUserE2E = { vorname: vorname, nachname: nachname, - benutzername: benutzername2, + username: userName2, email: emailAddress2, isUser: true, - organisationseinheiten: ['Denkmalpflege'], + organisationseinheiten: [OrganisationsEinheitE2E.DENKMALPFLEGE], }; before(() => { loginAsAriane(); }); - it('should click Hinzufügen button and show Organisationseinheiten in Benutzer page', () => { - mainPage.benutzerNavigationItemIsVisible(); - mainPage.clickBenutzerNavigationItem(); - benutzerPage.hinzufuegenButtonIsVisible(); + it('should show organisationseinheiten in formular', () => { + benutzerHelper.openNewBenutzerPage(); - benutzerPage.clickAddUser(); - exist(benutzerPage.getOrganisationsEinheitCheckbox(organisationsEinheitDenkmalpflege)); - exist(benutzerPage.getOrganisationsEinheitCheckbox(organistationsEinheitOrdnungsamt)); + benutzerVerifier.verifyOrganisationsEinheitenInFormular([ + OrganisationsEinheitE2E.DENKMALPFLEGE, + OrganisationsEinheitE2E.ORDNUNGSAMT, + ]); }); - it('should add no Organisationseinheit to new user without selection and saving', () => { - benutzerPage.addUser(newUser1); + it('should add new user without organisationseinheiten', () => { + benutzerHelper.openNewBenutzerPage(); - benutzerPage.stringExistsInUserEntry(organisationsEinheitNone, benutzername1); - }); + benutzerHelper.addBenutzerAndSave(userWithoutOrganisationsEinheiten); - it('should add Organisationseinheit to new user after selection and saving', () => { - benutzerPage.clickAddUser(); - benutzerPage.addUser(newUser2); - - benutzerPage.stringExistsInUserEntry(organisationsEinheitDenkmalpflege, benutzername2); + benutzerVerifier.verifyNoOrganisationsEinheitInBenutzerList(userName1); }); - it('should remove Organisationseinheit from existing user on deselection and save', () => { - benutzerPage.clickUserEntry(benutzername2); - beChecked(benutzerPage.getOrganisationsEinheitCheckbox(organisationsEinheitDenkmalpflege)); + it('should add new user with organisationseinheiten', () => { + benutzerHelper.openNewBenutzerPage(); - benutzerPage.clickOrganisationsEinheitCheckbox(organisationsEinheitDenkmalpflege); - benutzerPage.saveUser(); + benutzerHelper.addBenutzerAndSave(userWithOrganisationsEinheiten); - benutzerPage.stringExistsInUserEntry(organisationsEinheitNone, benutzername2); + benutzerVerifier.verfiyOrganisationsEinheitInBenutzerList(OrganisationsEinheitE2E.DENKMALPFLEGE, userName2); }); - it('should add Organisationseinheit to existing user on selection and save', () => { - benutzerPage.clickUserEntry(benutzername2); - notBeChecked(benutzerPage.getOrganisationsEinheitCheckbox(organistationsEinheitOrdnungsamt)); + it('should remove organisationseinheit from existing user', () => { + benutzerHelper.openBenutzerPage(userName2); - benutzerPage.clickOrganisationsEinheitCheckbox(organistationsEinheitOrdnungsamt); - benutzerPage.saveUser(); + benutzerHelper.editOrganisationsEinheitenAndSave([OrganisationsEinheitE2E.DENKMALPFLEGE]); - benutzerPage.stringExistsInUserEntry(organistationsEinheitOrdnungsamt, benutzername2); + benutzerVerifier.verifyNoOrganisationsEinheitInBenutzerList(userName2); }); - it('should enable new Organisationseinheit for users after adding it', () => { - mainPage.clickOrganisationsEinheitenNavigationItem(); - organisationsEinheitenComponent.clickHinzufuegen(); - zustaendigeStelleSearchComponent.enterSearchTerm(organisationsEinheitLiegenschaften); - zustaendigeStelleSearchComponent.getZustaendigeStelleTitle(0).then((title: string) => { - zustaendigeStelleSearchComponent.clickFoundItem(0); - }); - - mainPage.clickBenutzerNavigationItem(); - benutzerPage.clickUserEntry(benutzername2); + it('should add organisationseinheit to existing user', () => { + benutzerHelper.openBenutzerPage(userName2); - exist(benutzerPage.getOrganisationsEinheitCheckbox(organisationsEinheitLiegenschaften)); - }); + benutzerHelper.editOrganisationsEinheitenAndSave([OrganisationsEinheitE2E.ORDNUNGSAMT]); - it('should add new Organisationseinheit to existing user', () => { - benutzerPage.clickOrganisationsEinheitCheckbox(organisationsEinheitLiegenschaften); - benutzerPage.saveUser(); - benutzerPage.stringExistsInUserEntry(organisationsEinheitLiegenschaften, benutzername2); + benutzerVerifier.verfiyOrganisationsEinheitInBenutzerList(OrganisationsEinheitE2E.ORDNUNGSAMT, userName2); }); }); diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts index 9514df893c043a400aa61ec1e517a6007846eb68..6f2aeed20740461f3dc978afdc2b974fec471f00 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts @@ -21,45 +21,63 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { MainPage } from 'apps/admin-e2e/src/page-objects/main.po'; -import { BenutzerE2EComponent } from '../../../components/benutzer/benutzer.e2e.component'; -import { beChecked, beEnabled, exist, notBeChecked, notBeEnabled } from '../../../support/cypress.util'; +import { E2EBenutzerHelper } from 'apps/admin-e2e/src/helper/benutzer/benutzer.helper'; +import { OrganisationsEinheitE2E } from 'apps/admin-e2e/src/model/organisations-einheit'; +import { + BenutzerE2EComponent, + BenutzerListE2EComponent, + BenutzerListItemE2EComponent, +} from '../../../components/benutzer/benutzer.e2e.component'; +import { beChecked, beEnabled, contains, exist, notBeChecked, notBeEnabled } from '../../../support/cypress.util'; import { AlfaRollen, AlfaUsers, loginAsAriane } from '../../../support/user-util'; -const mainPage: MainPage = new MainPage(); -const benutzerPage: BenutzerE2EComponent = new BenutzerE2EComponent(); -const organisationsEinheitOrdnungsamt: string = 'Ordnungsamt'; -const organisationsEinheitDenkmalpflege: string = 'Denkmalpflege'; -const organisationsEinheitWirtschaftsfoerderung: string = 'Wirtschaftsförderung'; -const organisationsEinheitNone: string = 'keine zuständige Stelle zugewiesen'; -const emailAddress: string = 'peter.von.der.post@ozg-sh.de'; - describe('Benutzer und Rollen', () => { + const benutzerPage: BenutzerE2EComponent = new BenutzerE2EComponent(); + const benutzerListPage: BenutzerListE2EComponent = new BenutzerListE2EComponent(); + + //TODO In der entsprechenden json hinterlegen und darauf zugreifen + const emailAddress: string = 'peter.von.der.post@ozg-sh.de'; + + const helper: E2EBenutzerHelper = new E2EBenutzerHelper(); + before(() => { loginAsAriane(); }); - it('should open Benutzer tab and show Hinzufuegen button', () => { - mainPage.clickBenutzerNavigationItem(); + it('should show users and attributes in list', () => { + helper.openBenutzerListPage(); - exist(benutzerPage.getHinzufuegenButton()); - }); + const ariane: BenutzerListItemE2EComponent = benutzerListPage.getItem(AlfaUsers.ARAINE); + exist(ariane.getRoot()); + contains(ariane.getRoles(), AlfaRollen.USER); + + const dorothea: BenutzerListItemE2EComponent = benutzerListPage.getItem(AlfaUsers.DOROTHEA); + exist(dorothea.getRoot()); + contains(dorothea.getRoles(), AlfaRollen.USER); + + const ludwig: BenutzerListItemE2EComponent = benutzerListPage.getItem(AlfaUsers.LUDWIG); + exist(ludwig.getRoot()); + contains(ludwig.getRoles(), AlfaRollen.LOESCHEN); + contains(ludwig.getOrganisationsEinheiten(), OrganisationsEinheitE2E.ORDNUNGSAMT); + + const zelda: BenutzerListItemE2EComponent = benutzerListPage.getItem(AlfaUsers.ZELDA); + exist(zelda.getRoot()); + contains(zelda.getRoles(), AlfaRollen.USER); + contains(zelda.getOrganisationsEinheiten(), OrganisationsEinheitE2E.DENKMALPFLEGE); + contains(zelda.getOrganisationsEinheiten(), OrganisationsEinheitE2E.WIRTSCHAFTSFOERDERUNG); + + const peter: BenutzerListItemE2EComponent = benutzerListPage.getItem(AlfaUsers.PETER); + exist(peter.getRoot()); + contains(peter.getRoles(), AlfaRollen.POSTSTELLE); + contains(peter.getEMail(), emailAddress); - it('should show users and attributes in table', () => { - exist(benutzerPage.getUserEntry('ariane')); - benutzerPage.stringExistsInUserEntry(AlfaRollen.USER, AlfaUsers.DOROTHEA); - benutzerPage.stringExistsInUserEntry(organisationsEinheitOrdnungsamt, AlfaUsers.LUDWIG); - benutzerPage.stringExistsInUserEntry(AlfaRollen.USER, AlfaUsers.ZELDA); - benutzerPage.stringExistsInUserEntry(AlfaRollen.LOESCHEN, AlfaUsers.LUDWIG); - benutzerPage.stringExistsInUserEntry(organisationsEinheitDenkmalpflege, AlfaUsers.ZELDA); - benutzerPage.stringExistsInUserEntry(organisationsEinheitWirtschaftsfoerderung, AlfaUsers.ZELDA); - benutzerPage.stringExistsInUserEntry(organisationsEinheitNone, AlfaUsers.RICHARD); - benutzerPage.stringExistsInUserEntry(emailAddress, AlfaUsers.PETER); - benutzerPage.stringExistsInUserEntry(AlfaRollen.POSTSTELLE, AlfaUsers.PETER); + const richard: BenutzerListItemE2EComponent = benutzerListPage.getItem(AlfaUsers.RICHARD); + exist(richard.getRoot()); + exist(richard.getNoOrganisationsEinheitText()); }); it('should show single user screen on click', () => { - benutzerPage.clickAddUser(); + helper.openNewBenutzerPage(); exist(benutzerPage.getVornameInput()); exist(benutzerPage.getNachnameInput()); @@ -73,47 +91,47 @@ describe('Benutzer und Rollen', () => { }); it('should activate loeschen checkbox and deactivate the other two checkboxes', () => { - benutzerPage.clickLoeschenCheckbox(); + benutzerPage.getLoeschenCheckbox().click(); beChecked(benutzerPage.getLoeschenCheckbox()); notBeEnabled(benutzerPage.getUserCheckbox()); notBeEnabled(benutzerPage.getPostCheckbox()); - benutzerPage.clickLoeschenCheckbox(); + benutzerPage.getLoeschenCheckbox().click(); notBeChecked(benutzerPage.getLoeschenCheckbox()); beEnabled(benutzerPage.getUserCheckbox()); beEnabled(benutzerPage.getPostCheckbox()); }); it('should additionally activate and deactivate admin checkbox', () => { - benutzerPage.clickLoeschenCheckbox(); - benutzerPage.clickAdminCheckbox(); + benutzerPage.getLoeschenCheckbox().click(); + benutzerPage.getAdminCheckbox().click(); beChecked(benutzerPage.getLoeschenCheckbox()); beChecked(benutzerPage.getAdminCheckbox()); - benutzerPage.clickAdminCheckbox(); + benutzerPage.getAdminCheckbox().click(); notBeChecked(benutzerPage.getAdminCheckbox()); }); it('should activate user checkbox and deactivate the other two checkboxes', () => { - benutzerPage.clickLoeschenCheckbox(); - benutzerPage.clickUserCheckbox(); + benutzerPage.getLoeschenCheckbox().click(); + benutzerPage.getUserCheckbox().click(); beChecked(benutzerPage.getUserCheckbox()); notBeEnabled(benutzerPage.getLoeschenCheckbox()); notBeEnabled(benutzerPage.getPostCheckbox()); - benutzerPage.clickUserCheckbox(); + benutzerPage.getUserCheckbox().click(); notBeChecked(benutzerPage.getUserCheckbox()); beEnabled(benutzerPage.getLoeschenCheckbox()); beEnabled(benutzerPage.getPostCheckbox()); }); it('should activate post checkbox and deactivate the other two checkboxes', () => { - benutzerPage.clickPostCheckbox(); + benutzerPage.getPostCheckbox().click(); beChecked(benutzerPage.getPostCheckbox()); notBeEnabled(benutzerPage.getLoeschenCheckbox()); notBeEnabled(benutzerPage.getUserCheckbox()); - benutzerPage.clickPostCheckbox(); + benutzerPage.getPostCheckbox().click(); notBeChecked(benutzerPage.getPostCheckbox()); beEnabled(benutzerPage.getLoeschenCheckbox()); beEnabled(benutzerPage.getUserCheckbox()); diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/daria.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/daria.cy.ts index 57867568976e5deb0675a0ccd3fc52f9e5e19d79..33a06a73b83c3a839b0490f96aa17ddb42106994 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/daria.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/daria.cy.ts @@ -1,5 +1,5 @@ import { MainPage, waitForSpinnerToDisappear } from 'apps/admin-e2e/src/page-objects/main.po'; -import { exist, notExist } from 'apps/admin-e2e/src/support/cypress.util'; +import { exist, notExist, visible } from 'apps/admin-e2e/src/support/cypress.util'; import { loginAsDaria } from 'apps/admin-e2e/src/support/user-util'; import { StatistikE2EComponent } from '../../../components/statistik/statistik.e2e.component'; @@ -37,7 +37,7 @@ describe('Navigation', () => { }); it('should show header text', () => { - statistikPage.isHeaderTextVisible(); + visible(statistikPage.getHeaderText()); }); }); }); diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/safira.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/safira.cy.ts index 6f76dafdfc3161646383b34465056c2e751fa33c..005da2e5a576948787fdeb1f26165bd250b22138 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/safira.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/safira.cy.ts @@ -1,5 +1,5 @@ import { MainPage, waitForSpinnerToDisappear } from 'apps/admin-e2e/src/page-objects/main.po'; -import { exist } from 'apps/admin-e2e/src/support/cypress.util'; +import { exist, visible } from 'apps/admin-e2e/src/support/cypress.util'; import { loginAsSafira } from 'apps/admin-e2e/src/support/user-util'; import { StatistikE2EComponent } from '../../../components/statistik/statistik.e2e.component'; @@ -38,7 +38,7 @@ describe('Navigation', () => { }); it('should show page on selection', () => { - statistikPage.isHeaderTextVisible(); + visible(statistikPage.getHeaderText()); }); it('should mark navigation item as selected', () => { diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-hinzufuegen.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-hinzufuegen.cy.ts index ecdc072a69ee0a81f41aa786ccb0a23eacc4f450..c88d54bf3dac14f0f0a7b5f124a66e7d1e26d60f 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-hinzufuegen.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-hinzufuegen.cy.ts @@ -1,3 +1,4 @@ +import { convertToDataTestId } from 'apps/admin-e2e/src/support/tech-util'; import { OrganisationsEinheitenE2EComponent } from '../../../components/organisationseinheiten/organisationseinheiten.e2e.component'; import { ZustaendigeStelleDialogE2EComponent } from '../../../components/zustaendige-stelle/zustaendige-stelle-dialog.e2e.component'; import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; @@ -27,7 +28,7 @@ describe('Organisationseinheiten', () => { }); it('should show search Organisationseinheit dialog', () => { - organisationsEinheitenComponent.clickHinzufuegen(); + organisationsEinheitenComponent.getOrganisationsEinheitHinzufuegenButton().click(); exist(zustaendigeStelleSearchComponent.getZustaendigeStelleForm()); }); @@ -39,9 +40,9 @@ describe('Organisationseinheiten', () => { }); it('should add first Organisationseinheit', () => { - zustaendigeStelleSearchComponent.getZustaendigeStelleTitle(0).then((title: string) => { + zustaendigeStelleSearchComponent.getZustaendigeStelleTitle(0).then((name: string) => { zustaendigeStelleSearchComponent.clickFoundItem(0); - exist(organisationsEinheitenComponent.getListItemByName(title)); + exist(organisationsEinheitenComponent.getListItem(convertToDataTestId(name))); }); }); }); 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 91a1673e96e41b8dbdae4e4338e864a0527f816e..2b8eaeb70ab47d7845d24f973bac43f7645c25b2 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 @@ -24,52 +24,33 @@ import { OrganisationsEinheitenE2EComponent } from '../../../components/organisationseinheiten/organisationseinheiten.e2e.component'; import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; import { exist } from '../../../support/cypress.util'; -import { OrganisationsEinheitSyncResultE2E } from '../../../support/organisationseinheit'; -import { - createBauamtOrganisationsEinheit, - createDenkmalpflegeOrganisationsEinheit, - createFundstelleOrganisationsEinheit, - initOrganisationsEinheiten, -} from '../../../support/organisationseinheit-util'; import { loginAsAriane } from '../../../support/user-util'; -describe.skip('TODO: activate after fix for OZG-7391: show Organisationsheiten', () => { +describe('Organisationsheiten list', () => { const mainPage: MainPage = new MainPage(); const organisationsEinheitenTab: OrganisationsEinheitenE2EComponent = new OrganisationsEinheitenE2EComponent(); before(() => { loginAsAriane(); - initOrganisationsEinheiten([ - createBauamtOrganisationsEinheit(), - { ...createDenkmalpflegeOrganisationsEinheit(), syncResult: OrganisationsEinheitSyncResultE2E.NAME_MISMATCH }, - { ...createFundstelleOrganisationsEinheit(), syncResult: OrganisationsEinheitSyncResultE2E.NOT_FOUND_IN_PVOG }, - ]); }); - it('should show table of Organisationseinheiten', () => { + it('should show Organisationseinheiten list', () => { waitForSpinnerToDisappear(); mainPage.clickOrganisationsEinheitenNavigationItem(); + waitForSpinnerToDisappear(); exist(organisationsEinheitenTab.getOrganisationsEinheitList()); }); - it('should show identical data in Keycloak and PVOG without error', () => { - organisationsEinheitenTab.getListItemByName('Bauamt'); - organisationsEinheitenTab.organisationsEinheitContainsID('Bauamt', '248240886'); - organisationsEinheitenTab.elementShowsNoError('Bauamt'); + it('should show entry for Bauamt', () => { + exist(organisationsEinheitenTab.getListItem('Bauamt')); }); - it('should show data not found in PVOG in red color and with error icon and tooltip message', () => { - const organisationsEinheitName: string = 'Fundstelle'; - - organisationsEinheitenTab.organisationsEinheitContainsID(organisationsEinheitName, '10363455'); - organisationsEinheitenTab.elementIsShownAsError(organisationsEinheitName); - organisationsEinheitenTab.getErrorIconInElement(organisationsEinheitName); - organisationsEinheitenTab.getErrorTooltip(organisationsEinheitName); + it('should show entry for Fundstelle', () => { + exist(organisationsEinheitenTab.getListItem('Fundstelle')); }); - it('should get name for OE from PVOG, if mismatch with Keycloak, but without error', () => { - organisationsEinheitenTab.organisationsEinheitContainsID('Landesamt für Denkmalpflege', '9093371'); - organisationsEinheitenTab.elementShowsNoError('Landesamt für Denkmalpflege'); + it('should show entry for Denkmalpflege', () => { + exist(organisationsEinheitenTab.getListItem('Denkmalpflege')); }); }); diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-signaturen.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-signaturen.cy.ts deleted file mode 100644 index 1e5a19499a0ad62ca94e6cbf43aff7c18856f6d8..0000000000000000000000000000000000000000 --- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-signaturen.cy.ts +++ /dev/null @@ -1,63 +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 { OrganisationseinheitenSignaturE2EComponent } from '../../../components/organisationseinheiten/organisationseinheiten-signatur.e2e.component'; -import { OrganisationsEinheitenE2EComponent } from '../../../components/organisationseinheiten/organisationseinheiten.e2e.component'; -import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; -import { haveText } from '../../../support/cypress.util'; -import { loginAsAriane } from '../../../support/user-util'; - -describe.skip('TODO: activate after fix for OZG-7391: Signatur', () => { - const mainPage: MainPage = new MainPage(); - const signaturePage: OrganisationseinheitenSignaturE2EComponent = new OrganisationseinheitenSignaturE2EComponent(); - const organisationsEinheitenTab: OrganisationsEinheitenE2EComponent = new OrganisationsEinheitenE2EComponent(); - - const signatureText: string = 'Signatur\nmit\n\n\n\nZeilenumbruch\n\n'; - - before(() => { - loginAsAriane(); - }); - - it('should open signature page for Bauamt on click', () => { - waitForSpinnerToDisappear(); - mainPage.openOrganisationsEinheiten(); - organisationsEinheitenTab.openOrganisationsEinheit('Bauamt'); - - haveText(signaturePage.getOrganisationsEinheitName(), 'Bauamt'); - }); - - it('should show signature input with scrollbar', () => { - signaturePage.setSignature(signatureText); - signaturePage.saveSignature(); - - signaturePage.hasSignature(signatureText); - signaturePage.hasScrollbar(); - }); - - it.skip('should enter and save empty signature', () => { - signaturePage.clearSignature(); - signaturePage.saveSignature(); - - signaturePage.hasSignature(''); - }); -}); diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/statistik/statistik-fields.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/statistik/statistik-fields.cy.ts index dae58525a8d2522f3c0a241f5f24423cba928f4b..d877ae4b900417af37328322176ce8070c6d0844 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/statistik/statistik-fields.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/statistik/statistik-fields.cy.ts @@ -1,40 +1,30 @@ -import { ROUTES } from '@admin-client/shared'; +import { StatistikE2EComponent } from 'apps/admin-e2e/src/components/statistik/statistik.e2e.component'; import { StatistikFieldsFormE2EComponent } from '../../../components/statistik/statistik-fields-form.e2e.component'; -import { StatistikE2EComponent } from '../../../components/statistik/statistik.e2e.component'; -import { urlShouldEndsWith } from '../../../support/cypress-helper'; -import { exist } from '../../../support/cypress.util'; +import { exist, haveText, haveValue } from '../../../support/cypress.util'; import { loginAsDaria } from '../../../support/user-util'; describe('Felder in Statistik hinzufügen', () => { const component: StatistikE2EComponent = new StatistikE2EComponent(); const fieldsFormComponent: StatistikFieldsFormE2EComponent = new StatistikFieldsFormE2EComponent(); + const dataText1: string = 'Eingabe A'; + const dataText2: string = 'Eingabe B'; + before(() => { loginAsDaria(); }); - it('should be on statistik page', () => { - urlShouldEndsWith(ROUTES.STATISTIK); - }); - - it('should show statistik header', () => { - component.isHeaderTextVisible(); + it('should show "Weitere Felder auswerten" button', () => { + exist(component.getWeitereFelderAuswertenButton()); }); - it('should show "Weiter Felder auswerten" button', () => { - exist(component.getWeiterFelderAuswertenButton()); - }); - - it('should navigate to route', () => { - component.getWeiterFelderAuswertenButton().click(); - - urlShouldEndsWith(ROUTES.STATISTIK_NEU); - }); + it('should have all form elements after button click', () => { + component.getWeitereFelderAuswertenButton().click(); - it('should have all form elements', () => { exist(fieldsFormComponent.getFormEngineInput()); exist(fieldsFormComponent.getFormIdInput()); exist(fieldsFormComponent.getDataFieldInput(0)); + exist(fieldsFormComponent.getDataFieldDeleteButton(0)); exist(fieldsFormComponent.getAddFieldButton()); exist(fieldsFormComponent.getSaveButton()); exist(fieldsFormComponent.getCancelButton()); @@ -46,9 +36,22 @@ describe('Felder in Statistik hinzufügen', () => { exist(fieldsFormComponent.getDataFieldInput(1)); }); + it('should enter text in both data fields', () => { + fieldsFormComponent.enterDataFieldPath(dataText1, 0); + fieldsFormComponent.enterDataFieldPath(dataText2, 1); + + haveValue(fieldsFormComponent.getDataFieldInput(0), dataText1); + haveValue(fieldsFormComponent.getDataFieldInput(1), dataText2); + }); + + it('should delete data fields', () => { + fieldsFormComponent.deleteDataField(0); + haveValue(fieldsFormComponent.getDataFieldInput(0), dataText2); + }); + it('should navigate to statistik on cancel', () => { fieldsFormComponent.cancel(); - urlShouldEndsWith(ROUTES.STATISTIK); + exist(component.getWeitereFelderAuswertenButton()); }); }); diff --git a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts new file mode 100644 index 0000000000000000000000000000000000000000..9c8898bc0fcddef20b538919cc20bde8bc6e1993 --- /dev/null +++ b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts @@ -0,0 +1,47 @@ +import { BenutzerE2EComponent } from '../../components/benutzer/benutzer.e2e.component'; +import { SnackBarE2EComponent } from '../../components/ui/snackbar.e2e.component'; +import { OrganisationsEinheitE2E } from '../../model/organisations-einheit'; +import { AdminUserE2E } from '../../model/util'; +import { exist, notExist } from '../../support/cypress.util'; + +export class E2EBenutzerExecutor { + private benutzerPage: BenutzerE2EComponent = new BenutzerE2EComponent(); + private snackBar: SnackBarE2EComponent = new SnackBarE2EComponent(); + + public modifyBenutzer(user: AdminUserE2E): void { + this.benutzerPage.getVornameInput().type(user.vorname); + this.benutzerPage.getNachnameInput().type(user.nachname); + this.benutzerPage.getBenutzernameInput().type(user.username); + this.benutzerPage.getMailInput().type(user.email); + + if (user.isAdmin) { + this.benutzerPage.getAdminCheckbox().click(); + } + if (user.isUser) { + this.benutzerPage.getUserCheckbox().click(); + } + if (user.isLoeschen) { + this.benutzerPage.getLoeschenCheckbox().click(); + } + if (user.isPoststelle) { + this.benutzerPage.getPostCheckbox().click(); + } + + this.modifyOrganisationsEinheiten(user.organisationseinheiten); + } + + public modifyOrganisationsEinheiten(organisationseinheiten: OrganisationsEinheitE2E[]): void { + organisationseinheiten.forEach((name: string) => this.benutzerPage.getOrganisationsEinheitCheckbox(name).click()); + } + + public saveAndCloseSnackbar(): void { + this.saveBenutzer(); + exist(this.snackBar.getMessage()); + this.snackBar.getCloseButton().click(); + notExist(this.snackBar.getMessage()); + } + + public saveBenutzer(): void { + this.benutzerPage.getSaveButton().click(); + } +} diff --git a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.helper.ts b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.helper.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f2b6be7847116296225a8c28d81fb86e37f9cf9 --- /dev/null +++ b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.helper.ts @@ -0,0 +1,48 @@ +import { OrganisationsEinheitE2E } from '../../model/organisations-einheit'; +import { AdminUserE2E } from '../../model/util'; +import { E2EBenutzerExecutor } from './benutzer.executor'; +import { E2EBenutzerNavigator } from './benutzer.navigator'; + +export class E2EBenutzerHelper { + private navigator: E2EBenutzerNavigator = new E2EBenutzerNavigator(); + private executer: E2EBenutzerExecutor = new E2EBenutzerExecutor(); + + public openBenutzerListPage(): void { + this.navigator.openBenutzerListPage(); + } + + public openNewBenutzerPage(): void { + this.navigator.openNewBenutzerPage(); + } + + public addBenutzerAndSave(user: AdminUserE2E): void { + this.addBenutzer(user); + this.executer.saveAndCloseSnackbar(); + } + + public addBenutzer(user: AdminUserE2E): void { + this.executer.modifyBenutzer(user); + } + + public openBenutzerPage(userName: string): void { + this.navigator.openBenutzerPage(userName); + } + + public editBenutzerAndSave(user: AdminUserE2E): void { + this.editBenutzer(user); + this.executer.saveAndCloseSnackbar(); + } + + public editBenutzer(user: AdminUserE2E): void { + this.executer.modifyBenutzer(user); + } + + public editOrganisationsEinheitenAndSave(organisationsEinheiten: OrganisationsEinheitE2E[]): void { + this.executer.modifyOrganisationsEinheiten(organisationsEinheiten); + this.executer.saveAndCloseSnackbar(); + } + + public saveBenutzer(): void { + this.executer.saveBenutzer(); + } +} diff --git a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.navigator.ts b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.navigator.ts new file mode 100644 index 0000000000000000000000000000000000000000..fc5eee020b1931cd7dfa074c9ae070e7c6fe5121 --- /dev/null +++ b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.navigator.ts @@ -0,0 +1,32 @@ +import { BenutzerE2EComponent, BenutzerListE2EComponent } from '../../components/benutzer/benutzer.e2e.component'; +import { MainPage } from '../../page-objects/main.po'; +import { exist } from '../../support/cypress.util'; + +export class E2EBenutzerNavigator { + private mainPage: MainPage = new MainPage(); + private benutzerListPage: BenutzerListE2EComponent = new BenutzerListE2EComponent(); + private benutzerPage: BenutzerE2EComponent = new BenutzerE2EComponent(); + + public openNewBenutzerPage(): void { + this.openBenutzerListPage(); + + this.benutzerListPage.getHinzufuegenButton().click(); + exist(this.benutzerPage.getHeadline()); + } + + public openBenutzerPage(userName: string) { + this.openBenutzerListPage(); + this.benutzerListPage.getItem(userName).getRoot().click(); + exist(this.benutzerPage.getHeadline()); + } + + public openBenutzerListPage(): void { + this.navigateToDomain(); + this.mainPage.getBenutzerNavigationItem().click(); + exist(this.benutzerListPage.getHeadline()); + } + + private navigateToDomain(): void { + this.mainPage.getHeader().getLogo().click(); + } +} diff --git a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.verifier.ts b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.verifier.ts new file mode 100644 index 0000000000000000000000000000000000000000..d0c33452341f51de81cefee2d0f7f0e610532c7b --- /dev/null +++ b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.verifier.ts @@ -0,0 +1,47 @@ +import { + BenutzerE2EComponent, + BenutzerListE2EComponent, + BenutzerListItemE2EComponent, +} from '../../components/benutzer/benutzer.e2e.component'; +import { AdminUserE2E } from '../../model/util'; +import { contains, exist } from '../../support/cypress.util'; +import { AlfaRollen } from '../../support/user-util'; + +export class E2EBenutzerVerifier { + private noOrganisationsEinheitAssignedText: string = 'keine zuständige Stelle zugewiesen'; + + private benutzerListPage: BenutzerListE2EComponent = new BenutzerListE2EComponent(); + private benutzerPage: BenutzerE2EComponent = new BenutzerE2EComponent(); + + public verfiyOrganisationsEinheitInBenutzerList(organisationsEinheit: string, userName: string): void { + const benutzerItem: BenutzerListItemE2EComponent = this.getBenutzerItem(userName); + contains(benutzerItem.getOrganisationsEinheiten(), organisationsEinheit); + } + + public verifyNoOrganisationsEinheitInBenutzerList(userName: string): void { + const benutzerItem: BenutzerListItemE2EComponent = this.getBenutzerItem(userName); + contains(benutzerItem.getNoOrganisationsEinheitText(), this.noOrganisationsEinheitAssignedText); + } + + public verifyOrganisationsEinheitenInFormular(organisationsEinheiten: string[]): void { + organisationsEinheiten.forEach((organisationsEinheit) => { + exist(this.benutzerPage.getOrganisationsEinheitCheckbox(organisationsEinheit)); + }); + } + + public verifyUserInList(user: AdminUserE2E): void { + const benutzer: BenutzerListItemE2EComponent = this.getBenutzerItem(user.username); + contains(benutzer.getUserName(), user.username); + contains(benutzer.getFullName(), user.vorname); + contains(benutzer.getFullName(), user.nachname); + + if (user.isUser) contains(benutzer.getRoles(), AlfaRollen.USER); + if (user.isLoeschen) contains(benutzer.getRoles(), AlfaRollen.LOESCHEN); + if (user.isPoststelle) contains(benutzer.getRoles(), AlfaRollen.POSTSTELLE); + if (user.isAdmin) contains(benutzer.getRoles(), AlfaRollen.ADMIN); + } + + private getBenutzerItem(userName: string): BenutzerListItemE2EComponent { + return this.benutzerListPage.getItem(userName); + } +} diff --git a/alfa-client/apps/admin-e2e/src/model/organisations-einheit.ts b/alfa-client/apps/admin-e2e/src/model/organisations-einheit.ts new file mode 100644 index 0000000000000000000000000000000000000000..9870f7e3f1292df175cd154c88c59fbd60a94f26 --- /dev/null +++ b/alfa-client/apps/admin-e2e/src/model/organisations-einheit.ts @@ -0,0 +1,5 @@ +export enum OrganisationsEinheitE2E { + ORDNUNGSAMT = 'Ordnungsamt', + DENKMALPFLEGE = 'Denkmalpflege', + WIRTSCHAFTSFOERDERUNG = 'Wirtschaftsförderung', +} diff --git a/alfa-client/apps/admin-e2e/src/model/util.ts b/alfa-client/apps/admin-e2e/src/model/util.ts index a6e185610f221306000e326517a8906ecb1c1f6f..03041ea28be5dae394e7df97d6bf38ae72d2a182 100644 --- a/alfa-client/apps/admin-e2e/src/model/util.ts +++ b/alfa-client/apps/admin-e2e/src/model/util.ts @@ -1,3 +1,5 @@ +import { OrganisationsEinheitE2E } from './organisations-einheit'; + /* * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den * Ministerpräsidenten des Landes Schleswig-Holstein @@ -41,11 +43,11 @@ export enum HttpMethodE2E { export interface AdminUserE2E { vorname: string; nachname: string; - benutzername: string; + username: string; email: string; isAdmin?: boolean; isUser?: boolean; isLoeschen?: boolean; isPoststelle?: boolean; - organisationseinheiten?: string[]; + organisationseinheiten: OrganisationsEinheitE2E[]; } diff --git a/alfa-client/apps/admin-e2e/src/support/cypress.util.ts b/alfa-client/apps/admin-e2e/src/support/cypress.util.ts index 505762fe8f5193921ee7b5bffb76234f5b21393b..637963609081aa8cddbd24bbf5f56369b80cf0ef 100644 --- a/alfa-client/apps/admin-e2e/src/support/cypress.util.ts +++ b/alfa-client/apps/admin-e2e/src/support/cypress.util.ts @@ -122,13 +122,13 @@ export function enter(element: Cypress.Chainable<Element>): void { element.clear().type(CypressKeyboardActions.ENTER); } -export function enterWith(element: Cypress.Chainable<JQuery<HTMLElement>>, value: string, delayBeforeEnter: number = 200): void { +export function enterWith(element: Cypress.Chainable<Element>, value: string, delayBeforeEnter: number = 200): void { element.clear().type(value); wait(delayBeforeEnter); element.type(CypressKeyboardActions.ENTER); } -export function typeText(element: Cypress.Chainable<JQuery<HTMLElement>>, value: string): void { +export function typeText(element: Cypress.Chainable<Element>, value: string): void { element.type(value); } diff --git a/alfa-client/apps/admin-e2e/src/support/tech-util.ts b/alfa-client/apps/admin-e2e/src/support/tech-util.ts new file mode 100644 index 0000000000000000000000000000000000000000..a1bbcb74ae2b53c9fc3fc05bbcab81896c4e183e --- /dev/null +++ b/alfa-client/apps/admin-e2e/src/support/tech-util.ts @@ -0,0 +1,15 @@ +export function convertToDataTestId(value: string): string { + if (value == null || value == undefined) { + return ''; + } + value = replaceAllWhitespaces(value, '_'); + return simpleTransliteration(value); +} + +export function replaceAllWhitespaces(value: string, replaceWith: string): string { + return value.replace(/ /g, replaceWith); +} + +export function simpleTransliteration(value: string) { + return value.normalize('NFKD').replace(/[^-A-Za-z0-9_]/g, ''); +} diff --git a/alfa-client/apps/admin-e2e/src/support/user-util.ts b/alfa-client/apps/admin-e2e/src/support/user-util.ts index 46f07823c27eee9c7872cc8f72a39a33a5326548..d5e7462638087a82b1e4d365e0a59e11932962e5 100644 --- a/alfa-client/apps/admin-e2e/src/support/user-util.ts +++ b/alfa-client/apps/admin-e2e/src/support/user-util.ts @@ -23,7 +23,8 @@ */ import { UserE2E } from '../model/user'; import { HeaderE2EComponent } from '../page-objects/header.po'; -import { MainPage } from '../page-objects/main.po'; +import { MainPage, waitForSpinnerToDisappear } from '../page-objects/main.po'; +import { wait } from './cypress-helper'; export function loginAsAriane(): void { login(UserJsonPath.ARIANE); @@ -43,6 +44,8 @@ export function loginAsSafira(): void { function login(userJson: string): void { cy.fixture(userJson).then((user) => loginByUi(user)); + waitForSpinnerToDisappear(); + wait(3000, 'Wait for initial navigation is done'); } // Hinweis: cacheAcrossSpecs: true lässt Tests umfallen @@ -85,10 +88,11 @@ export enum AlfaRollen { USER = 'VERWALTUNG_USER', LOESCHEN = 'VERWALTUNG_LOESCHEN', POSTSTELLE = 'VERWALTUNG_POSTSTELLE', - ADMIN = 'ADMIN_ADMIN' + ADMIN = 'ADMIN_ADMIN', } export enum AlfaUsers { + ARAINE = 'ariane', DOROTHEA = 'dorothea', LUDWIG = 'ludwig', PETER = 'peter', diff --git a/alfa-client/apps/alfa-e2e/src/components/attachment/attachment.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/attachment/attachment.e2e.component.ts index c7988c3ce98a476aa50c0a28b1341331a790d4e4..7e7207e39038dfd923b4b1560bdda6864496a0f2 100644 --- a/alfa-client/apps/alfa-e2e/src/components/attachment/attachment.e2e.component.ts +++ b/alfa-client/apps/alfa-e2e/src/components/attachment/attachment.e2e.component.ts @@ -48,6 +48,10 @@ export class AttachmentListE2EComponent { return new AttachmentE2EItem(fileName); } + public getLoadingOrErrorItem(fileName: string): LoadingErrorAttachmentE2EItem { + return new LoadingErrorAttachmentE2EItem(fileName); + } + public getDownloadAttachmentsButton(): Cypress.Chainable<JQuery<HTMLElement>> { return this.getRoot().findTestElementWithClass(this.downloadAttachmentsButton); } @@ -79,3 +83,16 @@ class AttachmentE2EItem { return this.getRoot().findTestElementWithClass(this.locatorDownloadButton); } } + +class LoadingErrorAttachmentE2EItem { + private readonly root: string; + private readonly attachmentSuffix: string = '-file-upload-list-item-attachment-upload'; + + constructor(private fileName: string) { + this.root = convertToDataTestId(this.fileName) + this.attachmentSuffix; + } + + public getRoot() { + return cy.getTestElement(this.root); + } +} diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-mail.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-mail.cy.ts index 83ccb2b2cac8628bf8755dacc14c81a9acd7d65a..044306b1063a79e993a306928e4a1bf7d9cbf827 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-mail.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-mail.cy.ts @@ -22,61 +22,27 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { faker } from '@faker-js/faker'; -import { - AttachmentContainerE2EComponent, - AttachmentListE2EComponent, -} from 'apps/alfa-e2e/src/components/attachment/attachment.e2e.component'; +import { AttachmentContainerE2EComponent, AttachmentListE2EComponent, } from 'apps/alfa-e2e/src/components/attachment/attachment.e2e.component'; import { BinaryFileSnackbarMessageE2E } from 'apps/alfa-e2e/src/model/binary-file'; import { PostfachMailFormularE2EComponent } from '../../../components/postfach/postfach-mail-formular.e2e.component'; -import { - PostfachMailE2EComponent, - PostfachMailListItem, -} from '../../../components/postfach/postfach-mail.e2e.component'; +import { PostfachMailE2EComponent, PostfachMailListItem } from '../../../components/postfach/postfach-mail.e2e.component'; import { FixedDialogE2EComponent } from '../../../components/ui/fixed-dialog.e2e.component'; import { SnackBarE2EComponent } from '../../../components/ui/snackbar.e2e.component'; import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-list.e2e.component'; import { VorgangSubnavigationE2EComponent } from '../../../components/vorgang/vorgang-subnavigation'; import { ClientAttributeNameE2E, ClientAttributesE2E, VorgangE2E } from '../../../model/vorgang'; -import { - PostfachMailItemE2E, - PostfachNachrichtSnackbarMessageE2E, - VorgangAttachedItemClientE2E, - VorgangAttachedItemE2E, -} from '../../../model/vorgang-attached-item'; +import { PostfachMailItemE2E, PostfachNachrichtSnackbarMessageE2E, VorgangAttachedItemClientE2E, VorgangAttachedItemE2E, } from '../../../model/vorgang-attached-item'; import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; import { PostfachMailPage } from '../../../page-objects/postfach-mail.component.po'; import { VorgangPage } from '../../../page-objects/vorgang.po'; import { expectIconWithBadge, expectIconWithoutBadge } from '../../../support/angular.util'; import { dropCollections, readFileFromDownloads } from '../../../support/cypress-helper'; -import { - beChecked, - contains, - exist, - notBeChecked, - notBeVisible, - notExist, - visible, -} from '../../../support/cypress.util'; -import { - TEST_FILE_WITHOUT_CONTENT, - TEST_FILE_WITH_CONTENT, - TEST_FILE_WITH_CONTENT_4_MB, -} from '../../../support/data.util'; +import { beChecked, contains, exist, notBeChecked, notBeVisible, notExist, visible } from '../../../support/cypress.util'; +import { TEST_FILE_WITH_CONTENT, TEST_FILE_WITH_CONTENT_4_MB, TEST_FILE_WITHOUT_CONTENT } from '../../../support/data.util'; import { uploadEmptyFile, uploadFile } from '../../../support/file-upload'; import { initUsermanagerUsers, loginAsSabine } from '../../../support/user-util'; -import { - createPostfachNachrichtAttachedItem, - createPostfachNachrichtReplyItem, - initVorgangAttachedItem, -} from '../../../support/vorgang-attached-item-util'; -import { - buildVorgang, - createHasNewPostfachNachrichtClientAttribute, - createHasPostfachNachrichtClientAttribute, - createVorgang, - initVorgaenge, - objectIds, -} from '../../../support/vorgang-util'; +import { createPostfachNachrichtAttachedItem, createPostfachNachrichtReplyItem, initVorgangAttachedItem, } from '../../../support/vorgang-attached-item-util'; +import { buildVorgang, createHasNewPostfachNachrichtClientAttribute, createHasPostfachNachrichtClientAttribute, createVorgang, initVorgaenge, objectIds, } from '../../../support/vorgang-util'; describe('PostfachMail', () => { const mainPage: MainPage = new MainPage(); @@ -87,20 +53,16 @@ describe('PostfachMail', () => { const postfachMailContainer: PostfachMailE2EComponent = vorgangPage.getPostfachMailcontainer(); const subnavigation: VorgangSubnavigationE2EComponent = vorgangPage.getSubnavigation(); const fixedDialog: FixedDialogE2EComponent = vorgangPage.getFixedDialog(); - const postfachMailFormular: PostfachMailFormularE2EComponent = - vorgangPage.getPostfachMailFormular(); - const attachmentContainer: AttachmentContainerE2EComponent = - postfachMailFormular.getAttachmentContainer(); + const postfachMailFormular: PostfachMailFormularE2EComponent = vorgangPage.getPostfachMailFormular(); + const attachmentContainer: AttachmentContainerE2EComponent = postfachMailFormular.getAttachmentContainer(); const attachmentList: AttachmentListE2EComponent = attachmentContainer.getList(); const postfachMailPage: PostfachMailPage = new PostfachMailPage(); const clientAttributes: ClientAttributesE2E = { [VorgangAttachedItemClientE2E.OZGCLOUD_NACHRICHTEN_MANAGER]: { - [ClientAttributeNameE2E.HAS_NEW_POSTFACH_NACHRICHT]: - createHasNewPostfachNachrichtClientAttribute(true), - [ClientAttributeNameE2E.HAS_POSTFACH_NACHRICHT]: - createHasPostfachNachrichtClientAttribute(true), + [ClientAttributeNameE2E.HAS_NEW_POSTFACH_NACHRICHT]: createHasNewPostfachNachrichtClientAttribute(true), + [ClientAttributeNameE2E.HAS_POSTFACH_NACHRICHT]: createHasPostfachNachrichtClientAttribute(true), }, }; @@ -149,9 +111,7 @@ describe('PostfachMail', () => { describe('mail icon with badge', () => { it('should be visible and have a badge', () => { - const postfachStatusIcon: HTMLElement = vorgangList - .getListItem(vorgangWithReply.name) - .getPostfachIconMatIcon(); + const postfachStatusIcon: HTMLElement = vorgangList.getListItem(vorgangWithReply.name).getPostfachIconMatIcon(); expectIconWithBadge(postfachStatusIcon); }); }); @@ -273,10 +233,7 @@ describe('PostfachMail', () => { }); it('should show attachment with content after uploading it', () => { - uploadFile( - postfachMailFormular.getAttachmentContainer().getUploadInput(), - TEST_FILE_WITH_CONTENT, - ); + uploadFile(postfachMailFormular.getAttachmentContainer().getUploadInput(), TEST_FILE_WITH_CONTENT); waitForSpinnerToDisappear(); exist(attachmentList.getItem(TEST_FILE_WITH_CONTENT).getRoot()); @@ -305,26 +262,16 @@ describe('PostfachMail', () => { }); describe('attach file > 3 MB', () => { - it('should show error snackbar', () => { - uploadFile( - postfachMailFormular.getAttachmentContainer().getUploadInput(), - TEST_FILE_WITH_CONTENT_4_MB, - ); + it('should show failed upload', () => { + uploadFile(postfachMailFormular.getAttachmentContainer().getUploadInput(), TEST_FILE_WITH_CONTENT_4_MB); waitForSpinnerToDisappear(); - exist(snackbar.getMessage()); + exist(attachmentList.getLoadingOrErrorItem(TEST_FILE_WITH_CONTENT_4_MB).getRoot()); contains( - snackbar.getMessage(), + attachmentList.getLoadingOrErrorItem(TEST_FILE_WITH_CONTENT_4_MB).getRoot(), BinaryFileSnackbarMessageE2E.ATTACHMENT_NOT_ADDED.replace('{size}', '3MB'), ); }); - - it('should close snackbar on close button', () => { - snackbar.getCloseButton().click(); - - notExist(snackbar.getCloseButton()); - notExist(snackbar.getMessage()); - }); }); describe('reply option button', () => { @@ -356,9 +303,7 @@ describe('PostfachMail', () => { }); it('should show postfach mail in list', () => { - const postfachMailItem: PostfachMailListItem = postfachMailContainer.getListItem( - postfachMailToSend.subject, - ); + const postfachMailItem: PostfachMailListItem = postfachMailContainer.getListItem(postfachMailToSend.subject); exist(postfachMailItem.getRoot()); exist(postfachMailItem.getUserProfile().getRoot()); @@ -370,9 +315,7 @@ describe('PostfachMail', () => { describe('click on postfach mail item with attachment', () => { it('should show postfach item list', () => { - const postfachMailItem: PostfachMailListItem = postfachMailContainer.getListItem( - postfachMailToSend.subject, - ); + const postfachMailItem: PostfachMailListItem = postfachMailContainer.getListItem(postfachMailToSend.subject); postfachMailItem.getRoot().click(); waitForSpinnerToDisappear(); @@ -380,34 +323,27 @@ describe('PostfachMail', () => { }); it('should contain mail item with attachment', () => { - const postfachListItem: PostfachMailListItem = postfachMailPage.getListItem( - postfachMailToSend.subject, - ); + const postfachListItem: PostfachMailListItem = postfachMailPage.getListItem(postfachMailToSend.subject); - exist( - postfachListItem - .getAttachmentContainer() - .getList() - .getItem(TEST_FILE_WITH_CONTENT) - .getRoot(), - ); + exist(postfachListItem.getAttachmentContainer().getList().getItem(TEST_FILE_WITH_CONTENT).getRoot()); }); it('should download attachment after click', () => { - const postfachListItem: PostfachMailListItem = postfachMailPage.getListItem( - postfachMailToSend.subject, - ); + const postfachListItem: PostfachMailListItem = postfachMailPage.getListItem(postfachMailToSend.subject); - postfachListItem - .getAttachmentContainer() - .getList() - .getItem(TEST_FILE_WITH_CONTENT) - .getDownloadButton() - .click(); + postfachListItem.getAttachmentContainer().getList().getItem(TEST_FILE_WITH_CONTENT).getDownloadButton().click(); waitForSpinnerToDisappear(); exist(readFileFromDownloads(TEST_FILE_WITHOUT_CONTENT)); }); + + it('should not contain failed upload', () => { + const postfachListItem: PostfachMailListItem = postfachMailPage.getListItem(postfachMailToSend.subject); + + notExist( + postfachListItem.getAttachmentContainer().getList().getLoadingOrErrorItem(TEST_FILE_WITH_CONTENT_4_MB).getRoot(), + ); + }); }); describe('click on back button', () => { @@ -451,10 +387,7 @@ describe('PostfachMail', () => { }); it('should show text for no postfach attached', () => { - contains( - postfachMailContainer.getNoPostfachText(), - 'Dieser Vorgang ist nicht mit einem Postfach verknüpft.', - ); + contains(postfachMailContainer.getNoPostfachText(), 'Dieser Vorgang ist nicht mit einem Postfach verknüpft.'); }); it('should navigate back to list', () => { @@ -498,10 +431,7 @@ describe('PostfachMail', () => { }); it('should show text', () => { - contains( - postfachMailContainer.getListItem(postfachMailReply.subject).getText(), - postfachMailReply.mailBody, - ); + contains(postfachMailContainer.getListItem(postfachMailReply.subject).getText(), postfachMailReply.mailBody); }); }); @@ -566,9 +496,7 @@ describe('PostfachMail', () => { }); it('should be visible and not have a badge', () => { - const postfachStatusIcon: HTMLElement = vorgangList - .getListItem(vorgangWithReply.name) - .getPostfachIconMatIcon(); + const postfachStatusIcon: HTMLElement = vorgangList.getListItem(vorgangWithReply.name).getPostfachIconMatIcon(); expectIconWithoutBadge(postfachStatusIcon); }); }); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/wiedervorlage-attachment/wiedervorlage-attachment.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/wiedervorlage-attachment/wiedervorlage-attachment.cy.ts index 753c03ac4bec195c51eef3dffe2de7058e58ccb1..a32737f51ba4be5eb46a092f211db36236f239cf 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/wiedervorlage-attachment/wiedervorlage-attachment.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/wiedervorlage-attachment/wiedervorlage-attachment.cy.ts @@ -21,47 +21,26 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - AttachmentContainerE2EComponent, - AttachmentListE2EComponent, -} from 'apps/alfa-e2e/src/components/attachment/attachment.e2e.component'; +import { AttachmentContainerE2EComponent, AttachmentListE2EComponent, } from 'apps/alfa-e2e/src/components/attachment/attachment.e2e.component'; import { WiedervorlageSubnavigationE2EComponent } from 'apps/alfa-e2e/src/components/wiedervorlage/wiedervorlage-subnavigation'; -import { BinaryFileSnackbarMessageE2E } from 'apps/alfa-e2e/src/model/binary-file'; import { WiedervorlageE2E } from 'apps/alfa-e2e/src/model/wiedervorlage'; -import { - dropCollections, - readFileFromDownloads, - wait, -} from 'apps/alfa-e2e/src/support/cypress-helper'; +import { dropCollections, readFileFromDownloads, wait } from 'apps/alfa-e2e/src/support/cypress-helper'; import { initVorgangAttachedItem } from 'apps/alfa-e2e/src/support/vorgang-attached-item-util'; import { SnackBarE2EComponent } from '../../../components/ui/snackbar.e2e.component'; import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-list.e2e.component'; import { WiedervorlageInVorgangE2EComponent } from '../../../components/wiedervorlage/wiedervorlage-in-vorgang.e2e.component'; import { WiedervorlageE2EComponent } from '../../../components/wiedervorlage/wiedervorlage-page.e2e.component'; +import { BinaryFileSnackbarMessageE2E } from '../../../model/binary-file'; import { VorgangE2E } from '../../../model/vorgang'; import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; import { VorgangPage } from '../../../page-objects/vorgang.po'; import { WiedervorlagePage } from '../../../page-objects/wiedervorlage.po'; -import { - containClass, - contains, - exist, - haveLength, - notContainClass, - notExist, -} from '../../../support/cypress.util'; -import { - TEST_FILE_WITHOUT_CONTENT, - TEST_FILE_WITH_CONTENT, - TEST_FILE_WITH_CONTENT_46MB, -} from '../../../support/data.util'; +import { containClass, contains, exist, haveLength, notContainClass, notExist } from '../../../support/cypress.util'; +import { TEST_FILE_WITH_CONTENT, TEST_FILE_WITH_CONTENT_46MB, TEST_FILE_WITHOUT_CONTENT } from '../../../support/data.util'; import { uploadEmptyFile, uploadFile } from '../../../support/file-upload'; import { loginAsSabine } from '../../../support/user-util'; import { createVorgang, initVorgang, objectIds } from '../../../support/vorgang-util'; -import { - createWiedervorlageAttachedItem, - createWiedervorlageItem, -} from '../../../support/wiedervorlage-util'; +import { createWiedervorlageAttachedItem, createWiedervorlageItem } from '../../../support/wiedervorlage-util'; describe('Wiedervorlage attachments', () => { const mainPage: MainPage = new MainPage(); @@ -74,13 +53,10 @@ describe('Wiedervorlage attachments', () => { const wiedervorlageContainerInVorgang = vorgangPage.getWiedervorlagenContainer(); const wiedervorlagePage: WiedervorlagePage = new WiedervorlagePage(); - const wiedervorlageContainer: WiedervorlageE2EComponent = - wiedervorlagePage.getWiedervorlageContainer(); - const attachmentContainer: AttachmentContainerE2EComponent = - wiedervorlageContainer.getAttachmentContainer(); + const wiedervorlageContainer: WiedervorlageE2EComponent = wiedervorlagePage.getWiedervorlageContainer(); + const attachmentContainer: AttachmentContainerE2EComponent = wiedervorlageContainer.getAttachmentContainer(); const attachmentList: AttachmentListE2EComponent = attachmentContainer.getList(); - const subnavigation: WiedervorlageSubnavigationE2EComponent = - wiedervorlagePage.getSubnavigation(); + const subnavigation: WiedervorlageSubnavigationE2EComponent = wiedervorlagePage.getSubnavigation(); const snackbar: SnackBarE2EComponent = mainPage.getSnackBar(); @@ -140,23 +116,17 @@ describe('Wiedervorlage attachments', () => { exist(attachmentList.getItem(TEST_FILE_WITH_CONTENT).getRoot()); }); - it('should error snackbar after upload to large file', { defaultCommandTimeout: 30000 }, () => { + it('should show failed upload', { defaultCommandTimeout: 30000 }, () => { uploadFile(attachmentContainer.getUploadInput(), TEST_FILE_WITH_CONTENT_46MB); waitForSpinnerToDisappear(); - exist(snackbar.getMessage()); + exist(attachmentList.getLoadingOrErrorItem(TEST_FILE_WITH_CONTENT_46MB).getRoot()); contains( - snackbar.getMessage(), + attachmentList.getLoadingOrErrorItem(TEST_FILE_WITH_CONTENT_46MB).getRoot(), BinaryFileSnackbarMessageE2E.ATTACHMENT_NOT_ADDED.replace('{size}', '40MB'), ); }); - it('should close snackbar on close button', () => { - snackbar.getCloseButton().click(); - - notExist(snackbar.getMessage()); - }); - it('should download attachment on click', () => { attachmentList.getItem(TEST_FILE_WITH_CONTENT).getDownloadButton().click(); waitForSpinnerToDisappear(); @@ -169,10 +139,7 @@ describe('Wiedervorlage attachments', () => { wiedervorlageContainer.getSpeichernButton().click(); exist(snackbar.getMessage()); - contains( - snackbar.getMessage(), - 'Die Wiedervorlage "' + WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF + '" wurde angelegt', - ); + contains(snackbar.getMessage(), 'Die Wiedervorlage "' + WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF + '" wurde angelegt'); exist(snackbar.getCloseButton()); }); @@ -183,9 +150,7 @@ describe('Wiedervorlage attachments', () => { }); it('should show attachments on wiedervorlage in vorgang-detail after save ', () => { - wiedervorlageContainerInVorgang - .getWiedervorlage(WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF) - .expandItem(); + wiedervorlageContainerInVorgang.getWiedervorlage(WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF).expandItem(); exist( wiedervorlageContainerInVorgang @@ -203,6 +168,14 @@ describe('Wiedervorlage attachments', () => { .getItem(TEST_FILE_WITH_CONTENT) .getRoot(), ); + notExist( + wiedervorlageContainerInVorgang + .getWiedervorlage(WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF) + .getAttachmentContainer() + .getList() + .getLoadingOrErrorItem(TEST_FILE_WITH_CONTENT_46MB) + .getRoot(), + ); }); it('should download empty attachment on click in list', () => { @@ -233,8 +206,9 @@ describe('Wiedervorlage attachments', () => { }); describe('Delete attachment', () => { - const wiedervorlageComp: WiedervorlageInVorgangE2EComponent = - wiedervorlageContainerInVorgang.getWiedervorlage(WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF); + const wiedervorlageComp: WiedervorlageInVorgangE2EComponent = wiedervorlageContainerInVorgang.getWiedervorlage( + WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF, + ); it('should open wiedervorlage page', () => { wiedervorlageComp.getLink().click(); @@ -256,66 +230,41 @@ describe('Wiedervorlage attachments', () => { wiedervorlageContainer.getSpeichernButton().click(); exist(snackbar.getMessage()); - contains( - snackbar.getMessage(), - `Die Wiedervorlage "${WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF}" wurde gespeichert`, - ); + contains(snackbar.getMessage(), `Die Wiedervorlage "${WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF}" wurde gespeichert`); snackbar.getCloseButton().click(); }); - it('(Skip reason in OZG-4658) check attachments in wiedervorlage list', () => { + it('check attachments in wiedervorlage list', () => { waitForSpinnerToDisappear(); wiedervorlageComp.getExpandButton(); wiedervorlageComp.expandItem(); - notExist( - wiedervorlageComp - .getAttachmentContainer() - .getList() - .getItem(TEST_FILE_WITHOUT_CONTENT) - .getRoot(), - ); - exist( - wiedervorlageComp - .getAttachmentContainer() - .getList() - .getItem(TEST_FILE_WITH_CONTENT) - .getRoot(), - ); + notExist(wiedervorlageComp.getAttachmentContainer().getList().getItem(TEST_FILE_WITHOUT_CONTENT).getRoot()); + exist(wiedervorlageComp.getAttachmentContainer().getList().getItem(TEST_FILE_WITH_CONTENT).getRoot()); }); }); describe('switch to wiedervorlage without attachments', () => { - const wiedervorlageComp: WiedervorlageInVorgangE2EComponent = - wiedervorlageContainerInVorgang.getWiedervorlage(wiedervorlage.betreff); + const wiedervorlageComp: WiedervorlageInVorgangE2EComponent = wiedervorlageContainerInVorgang.getWiedervorlage( + wiedervorlage.betreff, + ); it('should not show any attachments', () => { wiedervorlageComp.getLink().click(); waitForSpinnerToDisappear(); - notExist( - wiedervorlageComp - .getAttachmentContainer() - .getList() - .getItem(TEST_FILE_WITHOUT_CONTENT) - .getRoot(), - ); - notExist( - wiedervorlageComp - .getAttachmentContainer() - .getList() - .getItem(TEST_FILE_WITH_CONTENT) - .getRoot(), - ); + notExist(wiedervorlageComp.getAttachmentContainer().getList().getItem(TEST_FILE_WITHOUT_CONTENT).getRoot()); + notExist(wiedervorlageComp.getAttachmentContainer().getList().getItem(TEST_FILE_WITH_CONTENT).getRoot()); wiedervorlagePage.getSubnavigation().navigateBack(); }); }); describe('Same number of attachments after status change', () => { - const wiedervorlageComp: WiedervorlageInVorgangE2EComponent = - wiedervorlageContainerInVorgang.getWiedervorlage(WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF); + const wiedervorlageComp: WiedervorlageInVorgangE2EComponent = wiedervorlageContainerInVorgang.getWiedervorlage( + WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF, + ); it('should open wiedervorlage page', () => { wait(500); @@ -332,10 +281,7 @@ describe('Wiedervorlage attachments', () => { waitForSpinnerToDisappear(); containClass(wiedervorlageContainer.getStatusDot(), 'erledigt'); - contains( - snackBar.getMessage(), - `Die Wiedervorlage ${WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF} wurde erledigt`, - ); + contains(snackBar.getMessage(), `Die Wiedervorlage ${WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF} wurde erledigt`); }); it('should close snackBar on close', () => { @@ -350,10 +296,7 @@ describe('Wiedervorlage attachments', () => { waitForSpinnerToDisappear(); notContainClass(wiedervorlageContainer.getStatusDot(), 'erledigt'); - contains( - snackBar.getMessage(), - `Die Wiedervorlage ${WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF} wurde wiedereröffnet`, - ); + contains(snackBar.getMessage(), `Die Wiedervorlage ${WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF} wurde wiedereröffnet`); }); it('should close snackBar on close', () => { @@ -385,10 +328,7 @@ describe('Wiedervorlage attachments', () => { waitForSpinnerToDisappear(); exist(snackbar.getMessage()); - contains( - snackbar.getMessage(), - `Die Wiedervorlage "${WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF}" wurde gespeichert`, - ); + contains(snackbar.getMessage(), `Die Wiedervorlage "${WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF}" wurde gespeichert`); }); it('should close snackBar on close', () => { @@ -398,26 +338,15 @@ describe('Wiedervorlage attachments', () => { }); it('(Skip reason in OZG-4658) should have no attachments after save', () => { - const wiedervorlageComp: WiedervorlageInVorgangE2EComponent = - wiedervorlageContainerInVorgang.getWiedervorlage(WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF); + const wiedervorlageComp: WiedervorlageInVorgangE2EComponent = wiedervorlageContainerInVorgang.getWiedervorlage( + WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF, + ); wiedervorlageComp.getExpandButton(); wiedervorlageComp.expandItem(); - notExist( - wiedervorlageComp - .getAttachmentContainer() - .getList() - .getItem(TEST_FILE_WITHOUT_CONTENT) - .getRoot(), - ); - notExist( - wiedervorlageComp - .getAttachmentContainer() - .getList() - .getItem(TEST_FILE_WITH_CONTENT) - .getRoot(), - ); + notExist(wiedervorlageComp.getAttachmentContainer().getList().getItem(TEST_FILE_WITHOUT_CONTENT).getRoot()); + notExist(wiedervorlageComp.getAttachmentContainer().getList().getItem(TEST_FILE_WITH_CONTENT).getRoot()); }); }); }); diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak-formservice.spec.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak-formservice.spec.ts index 865f904f83dbfd0ad22873ec8578531815b1c8dd..6fe0a332ba918b071d6bddfb712e7b4e177a4891 100644 --- a/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak-formservice.spec.ts +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak-formservice.spec.ts @@ -26,6 +26,7 @@ import { Injectable } from '@angular/core'; import { TestBed } from '@angular/core/testing'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, UrlSegment } from '@angular/router'; +import { faker } from '@faker-js/faker/.'; import { createDummy, Dummy } from 'libs/tech-shared/test/dummy'; import { singleCold, singleHot } from 'libs/tech-shared/test/marbles'; import { createSpy, mock, Mock } from 'libs/test-utils/src/lib/mocking'; @@ -261,6 +262,19 @@ describe('KeycloakFormService', () => { expect(isInvalid).toBeTruthy(); }); }); + + describe('get id', () => { + const patchConfigId: string = faker.string.alphanumeric(); + const patchConfig: PatchConfig = { id: patchConfigId, doPatch: false }; + + it('should return id from patch config', () => { + service._patchConfig = patchConfig; + + const id: string = service.getId(); + + expect(id).toBe(patchConfigId); + }); + }); }); @Injectable() @@ -268,6 +282,7 @@ export class TestKeycloakFormService extends KeycloakFormService<Dummy> { public static readonly FIELD: string = 'attribute'; public static SUBMIT_OBSERVABLE = () => of(createEmptyStateResource()); + public static DELETE_OBSERVABLE = () => of(createEmptyStateResource()); public static LOAD_OBSERVABLE = () => of(createEmptyStateResource()); _initForm(): FormGroup { @@ -287,4 +302,8 @@ export class TestKeycloakFormService extends KeycloakFormService<Dummy> { _doSubmit(): Observable<StateResource<Dummy>> { return TestKeycloakFormService.SUBMIT_OBSERVABLE(); } + + _doDelete(): Observable<StateResource<Dummy>> { + return TestKeycloakFormService.DELETE_OBSERVABLE(); + } } diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak-formservice.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak-formservice.ts index ecd71702a2a6d3e6176dc5890bdc9cd61dc7fe7c..49a2e6c84e3fdbf69b22ca324ee0100a34ae6763 100644 --- a/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak-formservice.ts +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak-formservice.ts @@ -94,6 +94,10 @@ export abstract class KeycloakFormService<T> { public isInvalid(): boolean { return this.form.invalid; } + + public getId(): string { + return this._patchConfig.id; + } } export interface PatchConfig { diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts index ae9c56bedd57177e3bac765ec968d7d00660794d..d0806e198efa5090d375832bbd313ca99482149b 100644 --- a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts @@ -415,6 +415,29 @@ describe('UserRepository', () => { }); }); + describe('deleteUser', () => { + const userId: string = faker.string.uuid(); + + beforeEach(() => { + kcAdminClient.users = <any>{ + del: jest.fn().mockReturnValue(Promise.resolve(undefined)), + }; + }); + + it('should call kcAdminClient users del', () => { + repository.deleteUser(userId); + + expect(kcAdminClient.users['del']).toHaveBeenCalledWith({ id: userId }); + }); + + it('should return void', (done) => { + repository.deleteUser(userId).subscribe((result: void) => { + expect(result).toBeUndefined(); + done(); + }); + }); + }); + describe('getUsers', () => { const user: User = createUser(); const userArray: User[] = [user, user, user]; diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts index 130176623c25c1cf1f848643b0a5687906fbae34..a5df128a7de4ceb8bd71c4d2edc337078b57bcca 100644 --- a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts @@ -151,6 +151,10 @@ export class UserRepository { return throwError(() => new Error('An error occurred while saving the user.')); } + public deleteUser(userId: string): Observable<void> { + return from(this.kcAdminClient.users.del({ id: userId })); + } + public getUsers(): Observable<User[]> { return from(this.kcAdminClient.users.find()).pipe( map((userReps: UserRepresentation[]): User[] => 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 e3ce2fb8bd6153796bea9bf82422718d2324721e..89072ed299d081cfe531c40579b4de859a3e41f1 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 @@ -37,3 +37,5 @@ export interface Postfach { } export declare type PostfachResource = SettingItemResource<Postfach>; + +export const POSTFACH_NACHRICHT_UPLOADED_ATTACHMENTS: string = 'POSTFACH_NACHRICHT_UPLOADED_ATTACHMENTS'; diff --git a/alfa-client/libs/admin/shared/src/index.ts b/alfa-client/libs/admin/shared/src/index.ts index 8f0992f8376dfb02cbd0096e33f516ac819f3d97..4257af281863dad5164a007d329fa6efea4f2c5a 100644 --- a/alfa-client/libs/admin/shared/src/index.ts +++ b/alfa-client/libs/admin/shared/src/index.ts @@ -1,4 +1,5 @@ export * from './lib/admin-cancel-button/admin-cancel-button.component'; +export * from './lib/admin-delete-open-dialog-button/admin-delete-open-dialog-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-delete-open-dialog-button/admin-delete-open-dialog-button.component.html b/alfa-client/libs/admin/shared/src/lib/admin-delete-open-dialog-button/admin-delete-open-dialog-button.component.html new file mode 100644 index 0000000000000000000000000000000000000000..c006d95c841f7f9686e98a762901b99511a7e101 --- /dev/null +++ b/alfa-client/libs/admin/shared/src/lib/admin-delete-open-dialog-button/admin-delete-open-dialog-button.component.html @@ -0,0 +1,3 @@ +<ods-open-dialog-button variant="outline_error" label="Löschen" dataTestId="delete-button"> + <ods-delete-icon icon /> +</ods-open-dialog-button> diff --git a/alfa-client/libs/admin/shared/src/lib/admin-delete-open-dialog-button/admin-delete-open-dialog-button.component.spec.ts b/alfa-client/libs/admin/shared/src/lib/admin-delete-open-dialog-button/admin-delete-open-dialog-button.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..3250b9c18a432b0f5e8fe523fdb25d79e82f10be --- /dev/null +++ b/alfa-client/libs/admin/shared/src/lib/admin-delete-open-dialog-button/admin-delete-open-dialog-button.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { OpenDialogButtonComponent } from '@ods/component'; +import { DeleteIconComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { AdminDeleteOpenDialogButtonComponent } from './admin-delete-open-dialog-button.component'; + +describe('AdminDeleteOpenDialogButtonComponent', () => { + let component: AdminDeleteOpenDialogButtonComponent; + let fixture: ComponentFixture<AdminDeleteOpenDialogButtonComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AdminDeleteOpenDialogButtonComponent], + declarations: [MockComponent(OpenDialogButtonComponent), MockComponent(DeleteIconComponent)], + }).compileComponents(); + + fixture = TestBed.createComponent(AdminDeleteOpenDialogButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/libs/admin/shared/src/lib/admin-delete-open-dialog-button/admin-delete-open-dialog-button.component.ts b/alfa-client/libs/admin/shared/src/lib/admin-delete-open-dialog-button/admin-delete-open-dialog-button.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..f9bcd3472723a4cfe91fbc91f897fedd16b76db9 --- /dev/null +++ b/alfa-client/libs/admin/shared/src/lib/admin-delete-open-dialog-button/admin-delete-open-dialog-button.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import { OpenDialogButtonComponent } from '@ods/component'; +import { DeleteIconComponent } from '@ods/system'; + +@Component({ + selector: 'admin-delete-open-dialog-button', + standalone: true, + imports: [DeleteIconComponent, OpenDialogButtonComponent], + templateUrl: './admin-delete-open-dialog-button.component.html', +}) +export class AdminDeleteOpenDialogButtonComponent {} 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 index 8bd6a5f92932e22006b3b8e2cb353a9c3fa93eb1..ccd9cc7ea4c19f667ba950072f96795375c8cbd9 100644 --- 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 @@ -2,5 +2,6 @@ (clickEmitter)="submit()" text="Speichern" dataTestId="save-button" + data-test-id="save" [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 index 52a303f378e824677dd6518126ae838ebd416e3a..baee873bfd7c0db07a9295de75844d638edaead5 100644 --- 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 @@ -4,7 +4,7 @@ import { dispatchEventFromFixture, getMockComponent, Mock, MockEvent } from '@al 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 { getDataTestIdOf } 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'; @@ -17,7 +17,7 @@ describe('AdminSaveButtonComponent', () => { let formService: Mock<AbstractFormService<Resource>>; - const saveButton: string = getDataTestIdAttributeOf('save-button'); + const saveButton: string = getDataTestIdOf('save'); const stateResource: StateResource<Resource> = createStateResource(createDummyResource()); 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 a2bc7e4bfe5efdec1af21b9ad1da7deaccf1a21f..3abca44e4a1aa07b3bceb119a0caf010014c02ed 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 @@ -23,12 +23,11 @@ */ 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 { 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'; @@ -36,8 +35,6 @@ describe('StatistikContainerComponent', () => { let component: StatistikContainerComponent; let fixture: ComponentFixture<StatistikContainerComponent>; - const evaluateAdditionalFieldsTestId: string = getDataTestIdAttributeOf('weitere-felder-auswerten-button'); - let aggregationMappingService: Mock<AggregationMappingService>; beforeEach(async () => { @@ -68,16 +65,6 @@ describe('StatistikContainerComponent', () => { expect(component).toBeTruthy(); }); - describe('template', () => { - describe('weiter felder auswerten button', () => { - it('should exists', () => { - fixture.detectChanges(); - - existsAsHtmlElement(fixture, evaluateAdditionalFieldsTestId); - }); - }); - }); - describe('on init', () => { const stateResource: StateResource<AggregationMappingListResource> = createStateResource( createAggregationMappingListResource(), 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 27805c87fe074bae41311083bc1aed20d5aaeaef..ce24e7184c9f832dec08b205237303ce3cd25af7 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 @@ -7,18 +7,25 @@ [formControlName]="StatistikFieldsFormService.FIELD_FORM_ENGINE_NAME" label="Formengine" placeholder="Tragen Sie hier die Formengine des Formulars ein." - data-test-id="form-engine-name-input" + data-test-id="form-engine-name" + dataTestId="form-engine-name" ></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" + data-test-id="form-id" + dataTestId="form-id" ></ods-text-editor> </div> <statistik-fields-form-mapping /> </form> - <ods-button text="Datenfeld hinzufügen" dataTestId="add-mapping-button" (clickEmitter)="formService.addMapping()"> + <ods-button + text="Datenfeld hinzufügen" + dataTestId="add-mapping-button" + data-test-id="add-mapping" + (clickEmitter)="formService.addMapping()" + > <ods-plus-icon icon class="fill-whitetext" /> </ods-button> 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 a0154fd3137315cfbfd12187d70f0ffb43635df5..e124d07cf71b81b1c0ee692d87cd25ed8e8b59cd 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 @@ -6,7 +6,7 @@ import { FormBuilder, FormControl, FormGroup, ReactiveFormsModule } from '@angul 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 { 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'; @@ -17,9 +17,9 @@ describe('AdminStatistikFieldsFormComponent', () => { let component: AdminStatistikFieldsFormComponent; let fixture: ComponentFixture<AdminStatistikFieldsFormComponent>; - const formEngineNameInputTestId: string = getDataTestIdOf('form-engine-name-input'); - const formIdInputTestId: string = getDataTestIdOf('form-id-input'); - const addMappingButton: string = getDataTestIdAttributeOf('add-mapping-button'); + const formEngineNameInputTestId: string = getDataTestIdOf('form-engine-name'); + const formIdInputTestId: string = getDataTestIdOf('form-id'); + const addMappingButton: string = getDataTestIdOf('add-mapping'); const formBuilder: FormBuilder = new FormBuilder(); 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 index 2ce86b545b1039b795911cf172f154b9e2b97871..569fc993f66170c76ad2cad6c28679b36e86e210 100644 --- 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 @@ -10,6 +10,7 @@ formControlName="sourcePath" label="Pfad des Datenfeldes" placeholder="Tragen Sie hier den gesamten Pfad des Datenfeldes ein, das Sie auswerten möchten." + [dataTestId]="'mapping-field-' + i" [attr.data-test-id]="'mapping-field-' + i" ></ods-text-editor> <ods-button @@ -19,6 +20,7 @@ destructive="true" (clickEmitter)="formService.removeMapping(i)" [dataTestId]="'remove-mapping-button-' + i" + [attr.data-test-id]="'remove-mapping-' + i" > <ods-delete-icon icon /> </ods-button> 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 index 61cd006e429951cde3657be7688b30063cc2e6eb..d06746e48f9660298e3c4e2d305a1404cd0e8605 100644 --- 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 @@ -5,7 +5,7 @@ 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 { getDataTestIdOf } 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'; @@ -15,7 +15,7 @@ describe('AdminStatistikFieldsFormMappingComponent', () => { let fixture: ComponentFixture<AdminStatistikFieldsFormMappingComponent>; const mappingField: string = getDataTestIdOf('mapping-field-0'); - const removeMappingButton: string = getDynamicDataTestIdAttributOf('remove-mapping-button-0'); + const removeMappingButton: string = getDataTestIdOf('remove-mapping-0'); const formBuilder: FormBuilder = new FormBuilder(); diff --git a/alfa-client/libs/admin/user-shared/src/lib/user.service.spec.ts b/alfa-client/libs/admin/user-shared/src/lib/user.service.spec.ts index 28e7e8cce9ce062979c43175587834aa818724ea..fce4d7d2cc427160ab70357168b5fbc347e7df8e 100644 --- a/alfa-client/libs/admin/user-shared/src/lib/user.service.spec.ts +++ b/alfa-client/libs/admin/user-shared/src/lib/user.service.spec.ts @@ -101,4 +101,21 @@ describe('UserService', () => { expect(user).toBeObservable(cold('ab', { a: createEmptyStateResource(true), b: userStateResource })); }); }); + + describe('deleteInKeycloak', () => { + it('should call userRepository delete', () => { + service._deleteInKeycloak(user.id); + + expect(repository.deleteUser).toHaveBeenCalledWith(user.id); + }); + + it('should return void', (done) => { + repository.deleteUser.mockReturnValue(of(undefined)); + + service._deleteInKeycloak(user.id).subscribe((result: void) => { + expect(result).toBeUndefined(); + done(); + }); + }); + }); }); diff --git a/alfa-client/libs/admin/user-shared/src/lib/user.service.ts b/alfa-client/libs/admin/user-shared/src/lib/user.service.ts index e927702221df953f2c5882fa6e8791ca98e0929e..d65103108f19ee160c78a8897f447ce7621b2bb0 100644 --- a/alfa-client/libs/admin/user-shared/src/lib/user.service.ts +++ b/alfa-client/libs/admin/user-shared/src/lib/user.service.ts @@ -47,7 +47,7 @@ export class UserService extends KeycloakResourceService<User> { } _deleteInKeycloak(id: string): Observable<void> { - throw new Error('Method not implemented.'); + return this.userRepository.deleteUser(id); } public getUserById(userId: string): Observable<StateResource<User>> { diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-button/user-form-delete-button-container.component.html b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-button/user-form-delete-button-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..b49a93cae8a97f0cf12a2e10c50abacc140ab8b6 --- /dev/null +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-button/user-form-delete-button-container.component.html @@ -0,0 +1 @@ +<admin-delete-open-dialog-button /> \ No newline at end of file diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-button/user-form-delete-button-container.component.spec.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-button/user-form-delete-button-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec691fc665e848da93f5c649141ec8d34c180e61 --- /dev/null +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-button/user-form-delete-button-container.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { UserFormDeleteButtonContainerComponent } from './user-form-delete-button-container.component'; + +describe('UserFormDeleteButtonComponent', () => { + let component: UserFormDeleteButtonContainerComponent; + let fixture: ComponentFixture<UserFormDeleteButtonContainerComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [UserFormDeleteButtonContainerComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(UserFormDeleteButtonContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-button/user-form-delete-button-container.component.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-button/user-form-delete-button-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..2c66a5500b2e177a0f0a39aedad3f1ccd5e7e3e9 --- /dev/null +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-button/user-form-delete-button-container.component.ts @@ -0,0 +1,13 @@ +import { AdminDeleteOpenDialogButtonComponent } from '@admin-client/shared'; +import { DIALOG_COMPONENT } from '@alfa-client/ui'; +import { Component } from '@angular/core'; +import { UserDeleteDialogContainerComponent } from '../user-form-delete-dialog-container/user-delete-dialog-container.component'; + +@Component({ + selector: 'admin-user-form-delete-container-button', + standalone: true, + imports: [AdminDeleteOpenDialogButtonComponent], + providers: [{ provide: DIALOG_COMPONENT, useValue: UserDeleteDialogContainerComponent }], + templateUrl: './user-form-delete-button-container.component.html', +}) +export class UserFormDeleteButtonContainerComponent {} diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog-container.component.html b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..367d0a4abbbd1f76c76468fe03e27403935a7577 --- /dev/null +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog-container.component.html @@ -0,0 +1,6 @@ +<admin-user-delete-dialog + [username]="formService.getUserName()" + [deleteUserStateResource]="deleteUserStateResource$ | async" + (delete)="deleteUser()" + data-test-id="delete-dialog" +/> diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog-container.component.spec.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..474c396b29e6f618186fafc524113a0a19c18097 --- /dev/null +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog-container.component.spec.ts @@ -0,0 +1,124 @@ +import { ROUTES } from '@admin-client/shared'; +import { UserService } from '@admin-client/user-shared'; +import { NavigationService } from '@alfa-client/navigation-shared'; +import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; +import { dispatchEventFromFixture, getMockComponent, Mock, mock } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { faker } from '@faker-js/faker/locale/de'; +import { Observable, of } from 'rxjs'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { createUserFormGroup } from '../../../../test/form'; +import { UserFormService } from '../user.formservice'; +import { UserDeleteDialogContainerComponent } from './user-delete-dialog-container.component'; +import { UserDeleteDialogComponent } from './user-delete-dialog/user-delete-dialog.component'; + +describe('UserDeleteDialogContainerComponent', () => { + let component: UserDeleteDialogContainerComponent; + let fixture: ComponentFixture<UserDeleteDialogContainerComponent>; + + const deletDialogLocator: string = getDataTestIdOf('delete-dialog'); + + let formService: Mock<UserFormService>; + let userService: Mock<UserService>; + let navigationService: Mock<NavigationService>; + + beforeEach(async () => { + formService = mock(UserFormService); + userService = mock(UserService); + navigationService = mock(NavigationService); + formService = { + ...mock(UserFormService), + form: createUserFormGroup(), + delete: jest.fn(), + } as any; + + await TestBed.configureTestingModule({ + imports: [UserDeleteDialogContainerComponent, UserDeleteDialogComponent], + providers: [ + { provide: UserFormService, useValue: formService }, + { provide: UserService, useValue: userService }, + { provide: NavigationService, useValue: navigationService }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(UserDeleteDialogContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('user form delete dialog', () => { + it('should be called', () => { + const username: string = faker.word.sample(); + const stateResource: StateResource<unknown> = createEmptyStateResource(); + formService.getUserName = jest.fn().mockReturnValue(username); + component.deleteUserStateResource$ = of(stateResource); + + fixture.detectChanges(); + + const deleteDialog: UserDeleteDialogComponent = getMockComponent(fixture, UserDeleteDialogComponent); + expect(deleteDialog.username).toBe(username); + expect(deleteDialog.deleteUserStateResource).toBe(stateResource); + }); + + it('should call deleteUser on emit delete', () => { + component.deleteUser = jest.fn(); + + dispatchEventFromFixture(fixture, deletDialogLocator, 'delete'); + + expect(component.deleteUser).toHaveBeenCalled(); + }); + }); + + describe('component', () => { + describe('deleteUser', () => { + const userId: string = faker.string.uuid(); + const loadingStateResource: StateResource<unknown> = createEmptyStateResource(true); + const loadingStateResource$: Observable<StateResource<unknown>> = of(loadingStateResource); + const loadingDoneStateResource$: Observable<StateResource<unknown>> = of(createEmptyStateResource()); + + beforeEach(() => { + userService.delete = jest.fn().mockReturnValue(loadingStateResource$); + formService.getId = jest.fn().mockReturnValue(userId); + }); + + it('should call formService getId', () => { + component.deleteUser(); + + expect(formService.getId).toHaveBeenCalled(); + }); + + it('should call userService delete', () => { + component.deleteUser(); + + expect(userService.delete).toHaveBeenCalledWith(userId); + }); + + it('should set deleteUserStateResource$', () => { + component.deleteUser(); + + expect(component.deleteUserStateResource$).toBeObservable(singleColdCompleted(loadingStateResource)); + }); + + it('should not navigate on loading', () => { + component.deleteUser(); + component.deleteUserStateResource$.subscribe(); + + expect(navigationService.navigate).not.toHaveBeenCalled(); + }); + + it('should navigate on delete success', () => { + userService.delete.mockReturnValue(loadingDoneStateResource$); + + component.deleteUser(); + component.deleteUserStateResource$.subscribe(); + + expect(navigationService.navigate).toHaveBeenCalledWith(ROUTES.BENUTZER); + }); + }); + }); +}); diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog-container.component.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..fb3f0e0a9ae2e286b4ab6e49d4f4e79965b65dc5 --- /dev/null +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog-container.component.ts @@ -0,0 +1,35 @@ +import { ROUTES } from '@admin-client/shared'; +import { UserService } from '@admin-client/user-shared'; +import { NavigationService } from '@alfa-client/navigation-shared'; +import { createEmptyStateResource, isNotLoading, StateResource } from '@alfa-client/tech-shared'; +import { AsyncPipe } from '@angular/common'; +import { Component, inject } from '@angular/core'; +import { Observable, of, tap } from 'rxjs'; +import { UserFormService } from '../user.formservice'; +import { UserDeleteDialogComponent } from './user-delete-dialog/user-delete-dialog.component'; + +@Component({ + selector: 'admin-delete-dialog-container', + standalone: true, + imports: [UserDeleteDialogComponent, AsyncPipe], + templateUrl: './user-delete-dialog-container.component.html', +}) +export class UserDeleteDialogContainerComponent { + public readonly formService = inject(UserFormService); + public readonly userService = inject(UserService); + public readonly navigationService = inject(NavigationService); + + public deleteUserStateResource$: Observable<StateResource<unknown>> = of(createEmptyStateResource()); + + public deleteUser(): void { + this.deleteUserStateResource$ = this.userService + .delete(this.formService.getId()) + .pipe(tap((state: StateResource<unknown>) => this.navigateOnDeleteSuccess(state))); + } + + private navigateOnDeleteSuccess(state: StateResource<any>): void { + if (isNotLoading(state)) { + this.navigationService.navigate(ROUTES.BENUTZER); + } + } +} diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog/user-delete-dialog.component.html b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog/user-delete-dialog.component.html new file mode 100644 index 0000000000000000000000000000000000000000..83b4694f02ef4fb61dbb8b65d0e83e114b69840d --- /dev/null +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog/user-delete-dialog.component.html @@ -0,0 +1,16 @@ +<div class="block bg-background-100 flex flex-col gap-4 p-8"> + <p>Sind Sie sicher, dass sie <span class="font-bold">{{ username }}</span> löschen möchten?</p> + <p>Hinweis: Die zugewiesenen Vorgänge bleiben bestehen.</p> + + <div class="flex justify-between"> + <ods-cancel-dialog-button data-test-id="dialog-cancel-button-host" /> + <ods-button-with-spinner + [stateResource]="deleteUserStateResource" + (clickEmitter)="delete.emit()" + variant="primary" + text="Löschen" + dataTestId="dialog-delete" + data-test-id="dialog-delete-button-host" + /> + </div> +</div> diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog/user-delete-dialog.component.spec.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog/user-delete-dialog.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..e2cfff1676a8048f0c8cc896450e25437533e39d --- /dev/null +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog/user-delete-dialog.component.spec.ts @@ -0,0 +1,57 @@ +import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; +import { dispatchEventFromFixture, existsAsHtmlElement, getMockComponent, MockEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ButtonWithSpinnerComponent, CancelDialogButtonComponent } from '@ods/component'; +import { MockComponent } from 'ng-mocks'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { UserDeleteDialogComponent } from './user-delete-dialog.component'; + +describe('UserFormDeleteDialogComponent', () => { + let component: UserDeleteDialogComponent; + let fixture: ComponentFixture<UserDeleteDialogComponent>; + + const deleteButton: string = getDataTestIdOf('dialog-delete-button-host'); + const cancelButton: string = getDataTestIdOf('dialog-cancel-button-host'); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [UserDeleteDialogComponent], + declarations: [MockComponent(CancelDialogButtonComponent), MockComponent(ButtonWithSpinnerComponent)], + }).compileComponents(); + + fixture = TestBed.createComponent(UserDeleteDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('template', () => { + describe('cancel button', () => { + it('should exist', () => { + existsAsHtmlElement(fixture, cancelButton); + }); + }); + + describe('delete button', () => { + it('should exist', () => { + const stateResource: StateResource<unknown> = createEmptyStateResource(); + component.deleteUserStateResource = stateResource; + + fixture.detectChanges(); + + expect(getMockComponent(fixture, ButtonWithSpinnerComponent).stateResource).toBe(stateResource); + }); + + it('should emit delete on click', () => { + component.delete.emit = jest.fn(); + + dispatchEventFromFixture(fixture, deleteButton, MockEvent.CLICK); + + expect(component.delete.emit).toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog/user-delete-dialog.component.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog/user-delete-dialog.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ced40bf330256dd8bd455248717390d1fdc4b62 --- /dev/null +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-delete-dialog-container/user-delete-dialog/user-delete-dialog.component.ts @@ -0,0 +1,16 @@ +import { StateResource } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { ButtonWithSpinnerComponent, CancelDialogButtonComponent } from '@ods/component'; + +@Component({ + selector: 'admin-user-delete-dialog', + standalone: true, + imports: [ButtonWithSpinnerComponent, CancelDialogButtonComponent], + templateUrl: './user-delete-dialog.component.html', +}) +export class UserDeleteDialogComponent { + @Input() username: string; + @Input() deleteUserStateResource: StateResource<unknown>; + + @Output() delete: EventEmitter<void> = new EventEmitter<void>(); +} diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-headline/user-form-headline.component.html b/alfa-client/libs/admin/user/src/lib/user-form/user-form-headline/user-form-headline.component.html index 56c74fd10047e5dece25229b0888dbbe70f9ed12..c352d3863a3f95b25eabe0b448501702592f2db1 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form-headline/user-form-headline.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-headline/user-form-headline.component.html @@ -1,7 +1,7 @@ -<h1 class="heading-1 mb-4"> - @if(isPatch){ +<h1 class="heading-1 mb-4" data-test-id="benutzer-form-headline"> + @if (isPatch) { Benutzer bearbeiten } @else { Benutzer anlegen } -</h1> \ No newline at end of file +</h1> diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html b/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html index 98a2303f351d72dfe65d7710ec73d7566cfdacd7..129d8476634e65400913eb770ac3f6b9c9ff017a 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html @@ -5,30 +5,38 @@ <h3 class="text-md block font-medium text-text">Administration</h3> <div class="flex items-center gap-2"> <ods-checkbox-editor [formControlName]="UserFormService.ADMIN" label="Admin" inputId="admin" /> - <ods-info-icon + <button tooltip='Wird nur in Kombination mit "User" verwendet. Diese Rolle kann Funktionen in Keycloak und der Administration konfigurieren, z.B. Benutzer anlegen, Gruppen erstellen bzw. Organisationseinheiten hinzufügen und Rollen zuweisen.' - /> + > + <ods-info-icon /> + </button> </div> </div> <div [formGroupName]="UserFormService.ALFA_GROUP" class="flex flex-col gap-2"> <h3 class="text-md block font-medium text-text">Alfa</h3> <div class="flex items-center gap-2"> <ods-checkbox-editor [formControlName]="UserFormService.LOESCHEN" label="Löschen" inputId="delete" /> - <ods-info-icon + <button tooltip='Diese Rolle hat dieselben Rechte wie die Rolle "User". Zusätzlich kann "Löschen" ausgewählte Vorgänge aus Alfa löschen. Diese Rolle sollten zwei Benutzer haben, da das Löschen einem Vieraugen-Prinzip folgt.' - /> + > + <ods-info-icon /> + </button> </div> <div class="flex items-center gap-2"> <ods-checkbox-editor [formControlName]="UserFormService.USER" label="User" inputId="user" /> - <ods-info-icon + <button tooltip='Diese Rolle kann alle Vorgänge sehen und bearbeiten, wenn diese seiner Organisationseinheit zugewiesen sind. Ist kompatibel mit "Löschen" und "Admin".' - /> + > + <ods-info-icon /> + </button> </div> <div class="flex items-center gap-2"> <ods-checkbox-editor [formControlName]="UserFormService.POSTSTELLE" label="Poststelle" inputId="post_office" /> - <ods-info-icon + <button tooltip='Diese Rolle kann ausschließlich alle neu eingegangenen Vorgänge sehen und anderen Benutzern zuweisen. Sie sollte nur einem Benutzer zugewiesen sein. Dieser sollte keine weiteren Rollen besitzen. (Sie ist aber kompatibel mit der "Admin")' - /> + > + <ods-info-icon /> + </button> </div> </div> </div> diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.html b/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.html index 0277da75dbb4169dd33e4927d89702b1105ce9d9..064289aa47b5e6ff3e9e37656407d30cd0d52c8d 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.html @@ -3,4 +3,4 @@ (clickEmitter)="submit()" text="Speichern" dataTestId="save-button" -/> \ No newline at end of file +/> diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.html b/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.html index dcab3c25b5a05434e0eedd7f56e889914253b5d7..5ce59646fde16f7fd3299848b2615f318685e536 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.html @@ -32,6 +32,11 @@ [formGroupParent]="formService.form" [formGroupOrganisationsEinheiten]="formService.getOrganisationsEinheitenGroup()" /> - <admin-user-form-save-button /> + <div class="flex justify-between"> + <admin-user-form-save-button /> + @if (formService.isPatch()) { + <admin-user-form-delete-container-button data-test-id="delete-button-container"/> + } + </div> </div> </ods-spinner> diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.spec.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.spec.ts index 085f2fe196fdb6d881240f4485527e72123b51ba..160ab43ceea91f4c2fd18bc37ca506e99edfa033 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.spec.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.spec.ts @@ -23,7 +23,8 @@ */ import { User } from '@admin-client/user-shared'; import { createEmptyStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared'; -import { getMockComponent, mock, Mock, notExistsAsHtmlElement } from '@alfa-client/test-utils'; +import { existsAsHtmlElement, getMockComponent, mock, Mock, notExistsAsHtmlElement } from '@alfa-client/test-utils'; +import { DIALOG_COMPONENT } from '@alfa-client/ui'; import { CommonModule } from '@angular/common'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormGroup, ReactiveFormsModule } from '@angular/forms'; @@ -47,6 +48,7 @@ describe('UserFormComponent', () => { let formService: Mock<UserFormService>; const userContent: string = getDataTestIdOf('user-content'); + const deleteButtonContainer: string = getDataTestIdOf('delete-button-container'); beforeEach(async () => { formService = <any>{ @@ -67,7 +69,7 @@ describe('UserFormComponent', () => { MockComponent(UserFormRolesComponent), MockComponent(UserFormHeadlineComponent), ], - providers: [{ provide: UserFormService, useValue: formService }], + providers: [{ provide: DIALOG_COMPONENT, useValue: {} }], }) .overrideComponent(UserFormComponent, { set: { @@ -130,7 +132,6 @@ describe('UserFormComponent', () => { it('should exist with input', () => { const formDataComponent: UserFormDataComponent = getMockComponent(fixture, UserFormDataComponent); - expect(formDataComponent).toBeTruthy(); expect(formDataComponent.formGroupParent).toBe(component.formService.form); }); }); @@ -151,7 +152,6 @@ describe('UserFormComponent', () => { UserFormOrganisationsEinheitListComponent, ); - expect(organisationsEinheitListComponent).toBeTruthy(); expect(organisationsEinheitListComponent.formGroupParent).toBe(component.formService.form); expect(organisationsEinheitListComponent.formGroupOrganisationsEinheiten).toBe( component.formService.getOrganisationsEinheitenGroup(), @@ -167,4 +167,22 @@ describe('UserFormComponent', () => { notExistsAsHtmlElement(fixture, userContent); }); }); + + describe('admin delete button container', () => { + it('should exist', () => { + formService.isPatch.mockReturnValue(true); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, deleteButtonContainer); + }); + + it('should not exist', () => { + formService.isPatch.mockReturnValue(false); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, deleteButtonContainer); + }); + }); }); diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.ts index 03199641945f4841fcd0360b025262c2136d9ef3..a533ff55e37698883943902df16183dc776b22c2 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.ts @@ -29,6 +29,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { SpinnerComponent } from '@ods/component'; import { Observable } from 'rxjs'; import { UserFormDataComponent } from './user-form-data/user-form-data.component'; +import { UserFormDeleteButtonContainerComponent } from './user-form-delete-button/user-form-delete-button-container.component'; import { UserFormHeadlineComponent } from './user-form-headline/user-form-headline.component'; import { UserFormOrganisationsEinheitListComponent } from './user-form-organisations-einheit-list/user-form-organisations-einheit-list.component'; import { UserFormRolesComponent } from './user-form-roles/user-form-roles.component'; @@ -44,12 +45,13 @@ import { UserFormService } from './user.formservice'; FormsModule, ReactiveFormsModule, AsyncPipe, + SpinnerComponent, UserFormDataComponent, UserFormRolesComponent, UserFormOrganisationsEinheitListComponent, UserFormHeadlineComponent, UserFormSaveButtonComponent, - SpinnerComponent, + UserFormDeleteButtonContainerComponent, ], }) export class UserFormComponent implements OnInit { 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 85dd58354b2597416aad10898d5c437edb445cfe..3be33cbcdfd5b941af8ce9ef4a51c63160419bb5 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 @@ -30,7 +30,7 @@ import { createEmptyStateResource, createStateResource, StateResource } from '@a import { Mock, mock } from '@alfa-client/test-utils'; import { SnackBarService } from '@alfa-client/ui'; import { fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { AbstractControl, FormControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { AbstractControl, FormControl, FormGroup, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { ActivatedRoute, UrlSegment } from '@angular/router'; import { faker } from '@faker-js/faker/locale/de'; import { cold } from 'jest-marbles'; @@ -45,6 +45,7 @@ import SpyInstance = jest.SpyInstance; describe('UserFormService', () => { let formService: UserFormService; + let roleGroup: UntypedFormGroup; let alfaGroup: UntypedFormGroup; let organisationsEinheitenGroup: UntypedFormGroup; @@ -62,7 +63,14 @@ describe('UserFormService', () => { ]); beforeEach(() => { - service = { ...mock(UserService), refresh: jest.fn(), create: jest.fn(), save: jest.fn(), getUserById: jest.fn() }; + service = { + ...mock(UserService), + refresh: jest.fn(), + create: jest.fn(), + save: jest.fn(), + delete: jest.fn(), + getUserById: jest.fn(), + }; adminOrganisationsEinheitService = { ...mock(AdminOrganisationsEinheitService), getAll: jest.fn().mockReturnValue(of(adminOrganisationsEinheitList)), @@ -456,4 +464,14 @@ describe('UserFormService', () => { expect(formService._initOrganisationsEinheiten$.unsubscribe).toHaveBeenCalled(); }); }); + + describe('get userName', () => { + it('should return form control value of userName', () => { + formService.form = new FormGroup({ [UserFormService.USERNAME]: new FormControl('userNameDummy') }); + + const userName: string = formService.getUserName(); + + expect(userName).toBe('userNameDummy'); + }); + }); }); diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts index e7e537b362cf5938842d80e3ededcf7297665b78..a456872659a6b1ebd15a0bb570080b5834069fdd 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts @@ -263,4 +263,8 @@ export class UserFormService extends KeycloakFormService<User> implements OnDest ngOnDestroy(): void { this._initOrganisationsEinheiten$.unsubscribe(); } + + public getUserName(): string { + return this.form.get(UserFormService.USERNAME).value; + } } 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 153e3e19deecd0653b83ae9fc7e516f85b6a8716..c131614ac1e604fb3afc63765f97d57ad73e9c17 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 @@ -23,7 +23,7 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<h1 class="heading-1 mb-4">Benutzer & Rollen</h1> +<h1 class="heading-1 mb-4" data-test-id="user-list-headline">Benutzer & Rollen</h1> <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) { diff --git a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-data/user-data.component.html b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-data/user-data.component.html index 7d455acd981b3767f809810878baea7ebedd5cf1..a09af6b607a48ed6e0bf6bddec4dedae9a1ebd46 100644 --- a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-data/user-data.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-data/user-data.component.html @@ -4,13 +4,13 @@ <span class="sr-only">E-Mail:</span> <ods-mailbox-icon size="small" class="stroke-gray-600" /> </dt> - <dd>{{ user.email }}</dd> + <dd data-test-class="email">{{ user.email }}</dd> </div> <div class="flex items-center gap-2"> <dt> <span class="sr-only">Benutzername:</span> <ods-person-icon /> </dt> - <dd>{{ user.username }}</dd> + <dd data-test-class="username">{{ user.username }}</dd> </div> -</dl> \ No newline at end of file +</dl> diff --git a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-organisations-einheiten/user-organisations-einheiten.component.html b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-organisations-einheiten/user-organisations-einheiten.component.html index 550037d391c229139ce5248398ff7715a6e730d4..2836ffd0b61913f495192bfa344d376fb79b6584 100644 --- a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-organisations-einheiten/user-organisations-einheiten.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-organisations-einheiten/user-organisations-einheiten.component.html @@ -1,18 +1,18 @@ <h4 class="sr-only">Zuständige Stellen</h4> @if (organisationsEinheiten.length > 0) { - <ul class="list-outside list-disc pl-4"> - @for(group of organisationsEinheiten | slice: 0 : MAX_GROUPS_TO_DISPLAY; track $index) { + <ul class="list-outside list-disc pl-4" data-test-class="organisations-einheiten"> + @for (group of organisationsEinheiten | slice: 0 : MAX_GROUPS_TO_DISPLAY; track $index) { <li>{{ group }}</li> } </ul> @if (organisationsEinheiten.length > MAX_GROUPS_TO_DISPLAY) { - @if(organisationsEinheiten.length - MAX_GROUPS_TO_DISPLAY === 1 ){ + @if (organisationsEinheiten.length - MAX_GROUPS_TO_DISPLAY === 1) { <p class="pl-4 text-gray-500">und 1 weiterer</p> } @else { <p class="pl-4 text-gray-500">und {{ organisationsEinheiten.length - MAX_GROUPS_TO_DISPLAY }} weitere</p> } } } @else { - <p> keine zuständige Stelle zugewiesen </p> -} \ No newline at end of file + <p data-test-class="no-organisations-einheit-text">keine zuständige Stelle zugewiesen</p> +} diff --git a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-roles/user-roles.component.html b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-roles/user-roles.component.html index 26b29dd6d1082879467997191335242a734aac76..f9f7e74372668a5ecf0a74c01808bc675c20327c 100644 --- a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-roles/user-roles.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-roles/user-roles.component.html @@ -1,4 +1,4 @@ -<dl class="flex flex-wrap gap-2"> +<dl class="flex flex-wrap gap-2" data-test-class="roles"> <dt class="sr-only">Rollen:</dt> @for (role of roles; track $index) { <dd diff --git a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user.component.html b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user.component.html index b19df22eb0537d270a9485c8a03b39bf04108939..cda8fb80181aea98d263a1928f683852722a18d7 100644 --- a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user.component.html @@ -1,7 +1,7 @@ -<ods-list-item [path]="user.id" [attr.data-test-id]="'user-entry-' + user.username"> +<ods-list-item [path]="user.id" [attr.data-test-id]="(user.username | convertForDataTest) + '-user-entry'"> <div class="flex-1 basis-1/2"> <div class="mb-2 flex flex-wrap items-center gap-3"> - <h3 class="text-md font-semibold">{{ user | toUserName }}</h3> + <h3 class="text-md font-semibold" data-test-class="fullname">{{ user | toUserName }}</h3> <admin-user-roles [roles]="user | toUserRoles" /> </div> diff --git a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user.component.spec.ts b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user.component.spec.ts index afd371e8c6812b03a5b6b671545b4e4344c18ac3..42da5233cedfd9c1dd176fb8973f1b7ea388dc48 100644 --- a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user.component.spec.ts +++ b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user.component.spec.ts @@ -1,3 +1,4 @@ +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { getMockComponent } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ListItemComponent } from '@ods/system'; @@ -17,6 +18,7 @@ describe('UserComponent', () => { await TestBed.configureTestingModule({ imports: [ UserComponent, + ConvertForDataTestPipe, MockComponent(ListItemComponent), MockComponent(UserRolesComponent), MockComponent(UserDataComponent), diff --git a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user.component.ts b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user.component.ts index f46a2dc2950c2f651dc2e313a4831cbf10ca6ba8..49a54feaafe1f7b2444813699b7eeb2a15fc9487 100644 --- a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user.component.ts +++ b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user.component.ts @@ -1,4 +1,5 @@ import { ToUserNamePipe, ToUserRolesPipe, User } from '@admin-client/user-shared'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { NgForOf } from '@angular/common'; import { Component, Input } from '@angular/core'; import { ListItemComponent } from '@ods/system'; @@ -17,6 +18,7 @@ import { UserRolesComponent } from './user-roles/user-roles.component'; UserDataComponent, UserRolesComponent, ToUserRolesPipe, + ConvertForDataTestPipe, ], templateUrl: './user.component.html', }) 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 6fee5ec006a52da9172c6491cc0bf38c4a0ba0df..24cbaccf50af06a9560638b4ea80884a05de7e07 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.model.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.model.ts @@ -118,3 +118,5 @@ export function createInitialWizard(): Wizard { bescheidCreated: false, }; } + +export const BESCHEID_UPLOADED_ATTACHMENTS: string = 'bescheid_uploaded_attachments'; \ No newline at end of file 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 index 977ca30abc3c3200416749391b488b397e75731c..9fbf45a5ca814d6ed15691e08259f1a664f836e0 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.spec.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.spec.ts @@ -24,7 +24,7 @@ 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 { createEmptyStateResource, createErrorStateResource, 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'; @@ -39,12 +39,12 @@ import { createCommandErrorStateResource, createCommandResource, createCommandSt 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 { createBescheid, 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 { Bescheid, BESCHEID_UPLOADED_ATTACHMENTS, BescheidDocument, BescheidResource, BescheidWizardStep, createEmptyBescheidDocument, createEmptyUploadInProgress, createInitialWizard, } from './bescheid.model'; import { BescheidService2 } from './bescheid2.service'; import { DocumentLinkRel } from './document.linkrel'; import { DocumentResource } from './document.model'; @@ -115,16 +115,25 @@ describe('BescheidService', () => { 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', () => { + beforeEach(() => { + service._clearUploadedFiles = jest.fn(); + }); + it('should reload postfach list', () => { service.exit(); expect(postfachService.setPostfachMailOnReload).toHaveBeenCalled(); }); + + it('should clear uploaded files', () => { + service.exit(); + + expect(service._clearUploadedFiles).toHaveBeenCalled(); + }); }); describe('skipBescheidCreation', () => { @@ -441,113 +450,16 @@ describe('BescheidService', () => { expect(binaryFileService.getFiles).not.toHaveBeenCalled(); }); - it('should emit attachments state', () => { + it('should add files', () => { 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); + service.loadAttachments(bescheidResourceWithAttachments); - expect(service.getAttachments()).toBeObservable( - singleCold({ ...createEmptyBescheidAttachments(), uploadStateResource: binaryFileStateResource } as BescheidAttachments), + expect(binaryFileService.addFiles).toHaveBeenCalledWith( + BESCHEID_UPLOADED_ATTACHMENTS, + getEmbeddedResources(binaryFileListStateResource, BinaryFileListLinkRel.FILE_LIST), ); }); }); @@ -885,11 +797,21 @@ describe('BescheidService', () => { }); describe('setActiveStep', () => { + beforeEach(() => { + service._clearUploadedFiles = jest.fn(); + }); + it('should emit changed active step', () => { service.setActiveStep(BescheidWizardStep.DokumenteHochladen); expect(service.getActiveStep()).toBeObservable(singleCold(BescheidWizardStep.DokumenteHochladen)); }); + + it('should clear uploaded files', () => { + service.setActiveStep(BescheidWizardStep.DokumenteHochladen); + + expect(service._clearUploadedFiles).toHaveBeenCalled(); + }); }); describe('getBescheidDraft', () => { @@ -939,23 +861,6 @@ describe('BescheidService', () => { }); }); - 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(); @@ -972,4 +877,12 @@ describe('BescheidService', () => { ); }); }); + + describe('clear uploaded files', () => { + it('should call binary files service', () => { + service._clearUploadedFiles(); + + expect(binaryFileService.clearUploadedFiles).toHaveBeenCalledWith(BESCHEID_UPLOADED_ATTACHMENTS); + }); + }); }); diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.ts index 3c5d8191390993f76b6456a8577d895b57dd6f55..8a48a4dbdf043a0994ac12c2a298a6ae2be2fb3e 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.ts @@ -1,6 +1,6 @@ import { Bescheid, - BescheidAttachments, + BESCHEID_UPLOADED_ATTACHMENTS, BescheidDocument, BescheidLinkRel, BescheidResource, @@ -11,7 +11,6 @@ import { buildCreateBescheidDocumentFromFileProps, buildSendBescheidCommandProps, buildUpdateBescheidCommandProps, - createEmptyBescheidAttachments, createEmptyBescheidDocument, createEmptyUploadInProgress, createInitialWizard, @@ -35,7 +34,6 @@ import { import { PostfachService } from '@alfa-client/postfach-shared'; import { createEmptyStateResource, - createLoadingStateResource, filterIsLoadedOrHasError, getEmbeddedResources, hasStateResourceError, @@ -63,17 +61,16 @@ export class BescheidService2 { 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(); + this._clearUploadedFiles(); } public skipBescheidCreation( @@ -173,50 +170,10 @@ export class BescheidService2 { getEmbeddedResources<BinaryFileResource>(stateResource, BinaryFileListLinkRel.FILE_LIST), ), ) - .subscribe((files: BinaryFileResource[]) => this._attachments$.next({ ...this._attachments$.value, items: files })); + .subscribe((files: BinaryFileResource[]) => this.binaryFileService.addFiles(BESCHEID_UPLOADED_ATTACHMENTS, 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 @@ -321,10 +278,6 @@ export class BescheidService2 { return this.bescheidResourceService.get(); } - public getAttachments(): Observable<BescheidAttachments> { - return this._attachments$.asObservable(); - } - public getBescheidDocument(): Observable<BescheidDocument> { return this._bescheidDocument$.asObservable(); } @@ -338,6 +291,7 @@ export class BescheidService2 { } public setActiveStep(step: BescheidWizardStep): void { + this._clearUploadedFiles(); this._wizard$.next({ ...this._wizard$.value, activeStep: step }); } @@ -369,14 +323,6 @@ export class BescheidService2 { 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, @@ -384,4 +330,8 @@ export class BescheidService2 { create: createEmptyStateResource(), }); } + + _clearUploadedFiles(): void { + this.binaryFileService.clearUploadedFiles(BESCHEID_UPLOADED_ATTACHMENTS); + } } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-list-in-vorgang-container/bescheid-list-in-vorgang/bescheid-list-in-vorgang.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-list-in-vorgang-container/bescheid-list-in-vorgang/bescheid-list-in-vorgang.component.html index 9689b2ae63c8a501ddaaf0d483212624e7c4fac6..f845d98c061a412f27ba24bbac1b22653cca7046 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-list-in-vorgang-container/bescheid-list-in-vorgang/bescheid-list-in-vorgang.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-list-in-vorgang-container/bescheid-list-in-vorgang/bescheid-list-in-vorgang.component.html @@ -47,6 +47,7 @@ data-test-class="binary-file-container-in-bescheid" [resource]="bescheid" [linkRel]="bescheidLinkRel.ATTACHMENTS" + [listOrientation]="BinaryFileListOrientation.VERTICAL" ></alfa-binary-file-list-container> </ods-bescheid-wrapper> </div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-list-in-vorgang-container/bescheid-list-in-vorgang/bescheid-list-in-vorgang.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-list-in-vorgang-container/bescheid-list-in-vorgang/bescheid-list-in-vorgang.component.ts index 843a0c6a69cc75f34b898e9605049a7128024372..559483edb769643b7e4ecb340429de8e51f12906 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-list-in-vorgang-container/bescheid-list-in-vorgang/bescheid-list-in-vorgang.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-list-in-vorgang-container/bescheid-list-in-vorgang/bescheid-list-in-vorgang.component.ts @@ -23,6 +23,7 @@ */ import { BescheidLinkRel, BescheidListLinkRel, BescheidListResource, BescheidStatus } from '@alfa-client/bescheid-shared'; import { Component, Input } from '@angular/core'; +import { BinaryFileListOrientation } from '../../../../../binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive'; @Component({ selector: 'alfa-bescheid-list-in-vorgang', @@ -32,6 +33,8 @@ import { Component, Input } from '@angular/core'; export class BescheidListInVorgangComponent { @Input() public bescheidList: BescheidListResource; + public readonly BinaryFileListOrientation = BinaryFileListOrientation; + public readonly bescheidListLinkRel = BescheidListLinkRel; public readonly bescheidLinkRel = BescheidLinkRel; public readonly bescheidStatus = BescheidStatus; 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 deleted file mode 100644 index 622107cd6a88a6410e8c7bcdc7e08fd262f1635b..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.html +++ /dev/null @@ -1,21 +0,0 @@ -<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 deleted file mode 100644 index 92f027903e7ddb01410294bcced6f60759882b68..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.spec.ts +++ /dev/null @@ -1,165 +0,0 @@ -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 deleted file mode 100644 index b5a60cd795a7f6b7b918ce39a5fd5b45c1b3cb63..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -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 deleted file mode 100644 index c34bfce43f0959f56aa16e8a993f31b61bec0839..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.html +++ /dev/null @@ -1,6 +0,0 @@ -<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 deleted file mode 100644 index 9c2cdd8df598bfddfb8b6fc3512066f44d58cc65..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.spec.ts +++ /dev/null @@ -1,123 +0,0 @@ -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 deleted file mode 100644 index 50d2dea88ea12ba5fec926d895ff47044f017409..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.ts +++ /dev/null @@ -1,27 +0,0 @@ -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/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 index 456fdbcb23a9cc1bca7ce775ccef70e8a544cf14..4f1ad6be37b4cce3aaca666cd2e5d41b3d25fbc9 100644 --- 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 @@ -26,13 +26,20 @@ </ods-textarea-editor> </div> - <alfa-bescheid-wizard-dokumente-hochladen-summary - [isBescheidDocumentMissing]="false" - data-test-id="bescheid-versenden-dokumente" - ></alfa-bescheid-wizard-dokumente-hochladen-summary> + <alfa-bescheid-wizard-document-file-container data-test-id="bescheid-document-file"> + </alfa-bescheid-wizard-document-file-container> + @if (bescheidResource | hasLink: BescheidLinkRel.ATTACHMENTS) { + <alfa-binary-file-list-container + [resource]="bescheidResource" + [linkRel]="BescheidLinkRel.ATTACHMENTS" + [listOrientation]="BinaryFileListOrientation.VERTICAL" + data-test-id="bescheid-attachments" + ></alfa-binary-file-list-container> + } </div> + @if ( - (bescheidResource | hasLink: bescheidLinkRel.UPDATE) || (bescheidResource | hasLink: bescheidLinkRel.BESCHEIDEN_UND_SENDEN) + (bescheidResource | hasLink: BescheidLinkRel.UPDATE) || (bescheidResource | hasLink: BescheidLinkRel.BESCHEIDEN_UND_SENDEN) ) { <ods-button-with-spinner class="self-end" 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 index e605449d8037e5d69d614a7a796060abb43a5c8f..3f2dd5b69457b1b28b56291e838c633fc17b120f 100644 --- 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 @@ -1,21 +1,12 @@ import { BescheidLinkRel, BescheidWizardDialogResult } from '@alfa-client/bescheid-shared'; -import { CommandResource } from '@alfa-client/command-shared'; +import { BinaryFileListContainerComponent } from '@alfa-client/binary-file'; 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 { existsAsHtmlElement, mock, Mock, notExistsAsHtmlElement, 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'; @@ -26,19 +17,18 @@ 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 { getDataTestIdAttributeOf, getDataTestIdOf } from '../../../../../../../../tech-shared/test/data-test'; +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 { BescheidWizardDocumentFileContainerComponent } from '../../../document-file-container/bescheid-wizard-document-file-container.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 = getDataTestIdAttributeOf('send-button'); + const attachmentsTestId: string = getDataTestIdOf('bescheid-attachments'); const empfaengerTestId: string = getDataTestIdOf('bescheid-nachricht-empfaenger'); let bescheidService: Mock<BescheidService2>; @@ -56,10 +46,11 @@ describe('BescheidWizardBescheidVersendenSendenComponent', () => { await TestBed.configureTestingModule({ declarations: [ BescheidWizardBescheidVersendenSendenComponent, - MockComponent(BescheidWizardDokumenteHochladenSummaryComponent), MockComponent(ButtonWithSpinnerComponent), MockComponent(TextareaEditorComponent), MockComponent(TextEditorComponent), + MockComponent(BinaryFileListContainerComponent), + MockComponent(BescheidWizardDocumentFileContainerComponent), HasLinkPipe, ReactiveFormsModule, ], @@ -246,68 +237,21 @@ describe('BescheidWizardBescheidVersendenSendenComponent', () => { }); }); - describe('dokumente hochladen summary', () => { + describe('attachment list', () => { it('should exists', () => { - existsAsHtmlElement(fixture, dokumenteTestsId); - }); + component.bescheidResource = createBescheidResource([BescheidLinkRel.ATTACHMENTS]); - it('should have inputs', () => { - const dokumentComponent: BescheidWizardDokumenteHochladenSummaryComponent = - getElementComponentFromFixtureByCss<BescheidWizardDokumenteHochladenSummaryComponent>(fixture, dokumenteTestsId); + fixture.detectChanges(); - expect(dokumentComponent.isBescheidDocumentMissing).toBe(false); + existsAsHtmlElement(fixture, attachmentsTestId); }); - 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', () => { + component.bescheidResource = createBescheidResource(); - 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' }); + fixture.detectChanges(); - expect(component.submit).toHaveBeenCalled(); - }); - }); - }); + notExistsAsHtmlElement(fixture, attachmentsTestId); }); }); }); 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 index 5d03f994ed85918c979d7101e8d6b4ec14a59ee3..9f773a07f9008af8d653888cf198ed2a6b5ef11b 100644 --- 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 @@ -4,6 +4,7 @@ import { createEmptyStateResource, StateResource } from '@alfa-client/tech-share import { DialogRef } from '@angular/cdk/dialog'; import { Component, inject, Input } from '@angular/core'; import { Observable, of } from 'rxjs'; +import { BinaryFileListOrientation } from '../../../../../../../../binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive'; import { BescheidFormService } from '../../../../bescheid.formservice'; @Component({ @@ -22,8 +23,9 @@ export class BescheidWizardBescheidVersendenSendenComponent { public focusBetreff: boolean = false; public focusNachricht: boolean = false; - public readonly bescheidLinkRel = BescheidLinkRel; + public readonly BescheidLinkRel = BescheidLinkRel; public readonly formServiceClass = BescheidFormService; + public readonly BinaryFileListOrientation = BinaryFileListOrientation; public submit(): void { this._resetFocus(); 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 index 28a81da1c3c872131b56f1db53765a0608729194..7ab41e6c8a8e3b45c0f237d0de9eef96a4dfbd02 100644 --- 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 @@ -1,14 +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> + <alfa-bescheid-wizard-document-file-container data-test-id="bescheid-document-file"> + </alfa-bescheid-wizard-document-file-container> + @if (bescheidResource | hasLink: BescheidLinkRel.ATTACHMENTS) { + <alfa-binary-file-list-container + [resource]="bescheidResource" + [linkRel]="BescheidLinkRel.ATTACHMENTS" + [listOrientation]="BinaryFileListOrientation.VERTICAL" + data-test-id="bescheid-attachments" + ></alfa-binary-file-list-container> + } <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)) { + @if ((bescheidResource | hasLink: BescheidLinkRel.UPDATE) || (bescheidResource | hasLink: BescheidLinkRel.BESCHEIDEN)) { <ods-button-with-spinner class="self-end" [stateResource]="submitStateResource$ | async" 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 index 40f0c44f14dc4e3e6c458f061f0c549cacd1763d..e73903700e781b9d36618c3a503f42395793fb21 100644 --- 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 @@ -1,4 +1,5 @@ import { BescheidLinkRel, BescheidWizardDialogResult } from '@alfa-client/bescheid-shared'; +import { BinaryFileListContainerComponent } from '@alfa-client/binary-file'; import { CommandResource } from '@alfa-client/command-shared'; import { createEmptyStateResource, @@ -28,14 +29,14 @@ import { createProblemDetail } from '../../../../../../../../tech-shared/test/er 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 { BescheidWizardDocumentFileContainerComponent } from '../../../document-file-container/bescheid-wizard-document-file-container.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 attachmentsTestId: string = getDataTestIdOf('bescheid-attachments'); const submitButtonTestId: string = getDataTestIdAttributeOf('confirm-and-save-button'); let formService: Mock<BescheidFormService>; @@ -52,7 +53,8 @@ describe('BescheidWizardBescheidVersendenSpeichernComponent', () => { declarations: [ BescheidWizardBescheidVersendenSpeichernComponent, MockComponent(BescheidWizardAntragBescheidenSummaryComponent), - MockComponent(BescheidWizardDokumenteHochladenSummaryComponent), + MockComponent(BinaryFileListContainerComponent), + MockComponent(BescheidWizardDocumentFileContainerComponent), MockComponent(ButtonWithSpinnerComponent), HasLinkPipe, ], @@ -118,66 +120,73 @@ describe('BescheidWizardBescheidVersendenSpeichernComponent', () => { }); describe('template', () => { - describe('dokumente hochladen summary', () => { + describe('attachment list', () => { it('should exists', () => { - existsAsHtmlElement(fixture, dokumenteTestsId); + component.bescheidResource = createBescheidResource([BescheidLinkRel.ATTACHMENTS]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, attachmentsTestId); }); - it('should have inputs', () => { - const dokumentComponent: BescheidWizardDokumenteHochladenSummaryComponent = - getElementComponentFromFixtureByCss<BescheidWizardDokumenteHochladenSummaryComponent>(fixture, dokumenteTestsId); + it('should NOT exists', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); - expect(dokumentComponent.isBescheidDocumentMissing).toBe(false); + notExistsAsHtmlElement(fixture, attachmentsTestId); }); + }); - describe('submit button', () => { - it('should exists with update link', () => { - component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); + describe('submit button', () => { + it('should exists with update link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); - fixture.detectChanges(); + fixture.detectChanges(); - existsAsHtmlElement(fixture, dokumenteTestsId); - }); + existsAsHtmlElement(fixture, submitButtonTestId); + }); - it('should exists with bescheiden link', () => { - component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN]); + it('should exists with bescheiden link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN]); - fixture.detectChanges(); + fixture.detectChanges(); - existsAsHtmlElement(fixture, dokumenteTestsId); - }); + existsAsHtmlElement(fixture, submitButtonTestId); + }); - it('should NOT exists on missing links', () => { - component.bescheidResource = createBescheidResource(); + it('should NOT exists on missing links', () => { + component.bescheidResource = createBescheidResource(); - fixture.detectChanges(); + fixture.detectChanges(); - notExistsAsHtmlElement(fixture, submitButtonTestId); - }); + notExistsAsHtmlElement(fixture, submitButtonTestId); + }); - it('should have inputs', () => { - component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN]); - const submitCommandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); - component.submitStateResource$ = of(submitCommandStateResource); + 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); + fixture.detectChanges(); + const submitButtonComponent: ButtonWithSpinnerComponent = getElementComponentFromFixtureByCss<ButtonWithSpinnerComponent>( + fixture, + submitButtonTestId, + ); - expect(submitButtonComponent.stateResource).toEqual(submitCommandStateResource); - }); + expect(submitButtonComponent.stateResource).toEqual(submitCommandStateResource); + }); - describe('output', () => { - describe('clickEmitter', () => { - it('should call handler', () => { - component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN]); - component.submit = jest.fn(); - fixture.detectChanges(); + 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' }); + triggerEvent({ fixture, elementSelector: submitButtonTestId, name: 'clickEmitter' }); - expect(component.submit).toHaveBeenCalled(); - }); + 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 index f7ee9b36506b3b783c70df4e5238eb690a7bb0c2..4f6bf47fb09a2a4e3653fa43f32cacd95962aff4 100644 --- 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 @@ -4,6 +4,7 @@ import { createEmptyStateResource, StateResource } from '@alfa-client/tech-share import { DialogRef } from '@angular/cdk/dialog'; import { Component, inject, Input } from '@angular/core'; import { Observable, of } from 'rxjs'; +import { BinaryFileListOrientation } from '../../../../../../../../binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive'; import { BescheidFormService } from '../../../../bescheid.formservice'; @Component({ @@ -18,7 +19,8 @@ export class BescheidWizardBescheidVersendenSpeichernComponent { public submitStateResource$: Observable<StateResource<CommandResource>> = of(createEmptyStateResource<CommandResource>()); - public readonly bescheidLinkRel = BescheidLinkRel; + public readonly BinaryFileListOrientation = BinaryFileListOrientation; + public readonly BescheidLinkRel = BescheidLinkRel; public submit(): void { this.submitStateResource$ = this.formService 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 index 749ab02b1417d171af7d7549c1c2994d4116fc04..26fb71e977b88813e501e3adcebe112e4077c3fb 100644 --- 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 @@ -112,12 +112,6 @@ describe('BescheidWizardDokumenteHochladenComponent', () => { }); describe('onWeiterClick', () => { - it('should finish adding attachments', () => { - component.onWeiterClick(); - - expect(bescheidService.finishAddingAttachments).toHaveBeenCalled(); - }); - it('should finish adding bescheid document', () => { component.onWeiterClick(); 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 index eb90a6109b54253184476b5b3542bd31f0851d94..c15d92820a7e08b122ed18f729dc344adc8f8a58 100644 --- 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 @@ -45,7 +45,6 @@ export class BescheidWizardDokumenteHochladenContainerComponent implements OnIni } public onWeiterClick(): void { - this.bescheidService.finishAddingAttachments(); this.bescheidService.finishAddingBescheidDocument(); this.bescheidService.setActiveStep(BescheidWizardStep.BescheidVersenden); } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/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 index b8c80fafbcec28185f7ff568c8b5357c197b1503..ecfcc883fa7680734dbf7dacb9c81fb197f6c5de 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/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 @@ -34,6 +34,12 @@ </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> + <ods-file-upload-list-container + [parentFormArrayName]="BescheidFormService.FIELD_ATTACHMENTS" + [fileUploadType]="BESCHEID_UPLOADED_ATTACHMENTS" + [filesResource]="bescheidResource" + [filesLinkRel]="BescheidLinkRel.ATTACHMENTS" + [listOrientation]="BinaryFileListOrientation.VERTICAL" + data-test-id="bescheid-attachments" + ></ods-file-upload-list-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 index 5ed6c9e5d11f1e5ebbe9fda0b395d70bc856c323..dd6eaf2ac287739ddbc00314a685b410f6740151 100644 --- 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 @@ -21,11 +21,11 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { FileUploadListContainerComponent } from '@alfa-client/binary-file'; 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'; @@ -35,14 +35,14 @@ describe('BescheidWizardDokumenteHochladenSummaryComponent', () => { const missingBescheidErrorMessageTestId: string = getDataTestIdOf('missing-bescheid-document-error-message'); const documentFileTestId: string = getDataTestIdOf('bescheid-document-file'); - const attachmentFilesTestId: string = getDataTestIdOf('bescheid-attachment-files'); + const attachmentFilesTestId: string = getDataTestIdOf('bescheid-attachments'); beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ BescheidWizardDokumenteHochladenSummaryComponent, MockComponent(BescheidWizardDocumentFileContainerComponent), - MockComponent(BescheidWizardAttachmentFilesContainerComponent), + MockComponent(FileUploadListContainerComponent), ], }).compileComponents(); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/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 index 6bf136b2492c45205aa1fe115c3a033d92c1d174..7337d6cc572a2218be84e2c81b7c4da8f3109d86 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/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,12 +21,21 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { BESCHEID_UPLOADED_ATTACHMENTS, BescheidLinkRel, BescheidResource } from '@alfa-client/bescheid-shared'; import { Component, Input } from '@angular/core'; +import { BinaryFileListOrientation } from '../../../../../../../binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive'; +import { BescheidFormService } from '../../../bescheid.formservice'; @Component({ selector: 'alfa-bescheid-wizard-dokumente-hochladen-summary', templateUrl: './bescheid-wizard-dokumente-hochladen-summary.component.html', }) export class BescheidWizardDokumenteHochladenSummaryComponent { + @Input() bescheidResource: BescheidResource; @Input() isBescheidDocumentMissing: boolean; + + public readonly BESCHEID_UPLOADED_ATTACHMENTS = BESCHEID_UPLOADED_ATTACHMENTS; + public readonly BescheidLinkRel = BescheidLinkRel; + public readonly BescheidFormService = BescheidFormService; + public readonly BinaryFileListOrientation = BinaryFileListOrientation; } 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 index 0442de58d2afd83f13f0adb7f928829302ffcea2..c81df29d6b8b5c614834ca40e8fd419ad24088cc 100644 --- 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 @@ -1,5 +1,7 @@ -<alfa-bescheid-wizard-upload-attachment-button - [attachments]="attachments$ | async" - (uploadFile)="uploadFile($event)" +<ods-multi-file-upload-editor + label="Anhang hochladen" + [fileUploadType]="BESCHEID_UPLOADED_ATTACHMENTS" + [uploadResource]="bescheidResource" + [uploadLinkRelation]="BescheidLinkRel.UPLOAD_ATTACHMENT" data-test-id="upload-attachment-button" -></alfa-bescheid-wizard-upload-attachment-button> +></ods-multi-file-upload-editor> 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 index 6035095eb818710798ad643934245f0ad1cf503f..4cbffd3fd1f894ec6b10e64f579b8021e6c86d72 100644 --- 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 @@ -1,37 +1,15 @@ -import { BescheidAttachments, BescheidResource } from '@alfa-client/bescheid-shared'; -import { getElementComponentFromFixtureByCss, Mock, mock, triggerEvent } from '@alfa-client/test-utils'; +import { MultiFileUploadEditorComponent } from '@alfa-client/binary-file'; 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 }], + declarations: [BescheidWizardUploadAttachmentButtonContainerComponent, MockComponent(MultiFileUploadEditorComponent)], }).compileComponents(); createComponent(); @@ -43,59 +21,7 @@ describe('BescheidWizardUploadAttachmentButtonContainerComponent', () => { 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); - }); - }); - }); - }); + it('should create', () => { + expect(component).toBeTruthy(); }); }); 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 index 620adb8db26f04e7dc6b810c37c6acdef0c12d4e..527ce7e4280a9523aa396e918cac1436441f685e 100644 --- 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 @@ -1,7 +1,5 @@ -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'; +import { BESCHEID_UPLOADED_ATTACHMENTS, BescheidLinkRel, BescheidResource } from '@alfa-client/bescheid-shared'; +import { Component, Input } from '@angular/core'; @Component({ selector: 'alfa-bescheid-wizard-upload-attachment-button-container', @@ -10,11 +8,6 @@ import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/besc 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); - } + public readonly BESCHEID_UPLOADED_ATTACHMENTS = BESCHEID_UPLOADED_ATTACHMENTS; + public readonly BescheidLinkRel = BescheidLinkRel; } 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 deleted file mode 100644 index daa2be54c067aee56f12918fc97895d4a9cfd87f..0000000000000000000000000000000000000000 --- 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 +++ /dev/null @@ -1,11 +0,0 @@ -<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 deleted file mode 100644 index 91693776e3fecd1def3f2f7ce3cde0c54acefa23..0000000000000000000000000000000000000000 --- 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 +++ /dev/null @@ -1,80 +0,0 @@ -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 { 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'); - - 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 deleted file mode 100644 index 0ec17648a4f94e19a0b6184e4a2cbb68f1b6edcd..0000000000000000000000000000000000000000 --- 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 +++ /dev/null @@ -1,32 +0,0 @@ -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.module.ts b/alfa-client/libs/bescheid/src/lib/bescheid.module.ts index e4e7092380ee0cdc7f9e1c206af6e03863b13b0c..f098c06d4ec7b163b55a8bad5f60c7682521866c 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid.module.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid.module.ts @@ -22,24 +22,12 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { BescheidSharedModule } from '@alfa-client/bescheid-shared'; -import { BinaryFileModule } from '@alfa-client/binary-file'; +import { BinaryFileModule, FileUploadListContainerComponent, MultiFileUploadEditorComponent } from '@alfa-client/binary-file'; import { CommandSharedModule } from '@alfa-client/command-shared'; -import { - ConvertForDataTestPipe, - ConvertProblemDetailToErrorMessagesPipe, - GetUrlPipe, - HasLinkPipe, - ToEmbeddedResourcesPipe, -} from '@alfa-client/tech-shared'; +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 { 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'; @@ -48,31 +36,10 @@ 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 { - DateEditorComponent, - ExpansionPanelComponent, - OzgcloudStrokedButtonWithSpinnerComponent, - SpinnerComponent, -} from '@alfa-client/ui'; +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, - CheckIconComponent, - CloseIconComponent, - RadioButtonCardComponent, - SaveIconComponent, - SendIconComponent, - SpinnerIconComponent, - StampIconComponent, -} from '@ods/system'; +import { AttachmentComponent, AttachmentWrapperComponent, BescheidGenerateIconComponent, BescheidStatusTextComponent, BescheidUploadIconComponent, BescheidWrapperComponent, ButtonCardComponent, ButtonComponent, CheckIconComponent, 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/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component'; @@ -80,8 +47,6 @@ import { BescheidWizardAbschliessenDialogContainerComponent } from './bescheid-w 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'; @@ -102,7 +67,6 @@ import { BescheidWizardStepperComponent } from './bescheid-wizard-container/besc 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'; @@ -146,6 +110,8 @@ import { BescheidWizardWeiterButtonComponent } from './bescheid-wizard-container TextareaEditorComponent, ConvertForDataTestPipe, ConvertProblemDetailToErrorMessagesPipe, + FileUploadListContainerComponent, + MultiFileUploadEditorComponent, ], declarations: [ BescheidInVorgangContainerComponent, @@ -179,9 +145,6 @@ import { BescheidWizardWeiterButtonComponent } from './bescheid-wizard-container BescheidWizardDocumentFileContainerComponent, BescheidWizardDocumentFileComponent, BescheidWizardUploadAttachmentButtonContainerComponent, - BescheidWizardUploadAttachmentButtonComponent, - BescheidWizardAttachmentFilesContainerComponent, - BescheidWizardAttachmentFilesComponent, BescheidWizardBescheidVersendenContainerComponent, BescheidWizardBescheidVersendenFormComponent, BescheidWizardBescheidVersendenSummaryComponent, diff --git a/alfa-client/libs/binary-file/src/index.ts b/alfa-client/libs/binary-file/src/index.ts index 0797fec271485748cb2070218373df404cf2f29b..4b274b2c74e7e1542d6f68309e12d91a6ab4a7e2 100644 --- a/alfa-client/libs/binary-file/src/index.ts +++ b/alfa-client/libs/binary-file/src/index.ts @@ -27,6 +27,7 @@ export * from './lib/binary-file-list-container/binary-file-list-container.compo export * from './lib/binary-file-uri-container/binary-file-uri-container.component'; export * from './lib/binary-file.module'; export * from './lib/binary-file2-container/binary-file2-container.component'; +export * from './lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive'; export * from './lib/file-upload-list-container/file-upload-list-container.component'; export * from './lib/horizontal-binary-file-list/horizontal-binary-file-list.component'; export * from './lib/multi-file-upload-editor/multi-file-upload-editor.component'; diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.spec.ts b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.spec.ts index 379778effd26148200f2700038bb76a38fa23bb7..ccf5fe67622d5cfa056b44b26d29ceed6f4f09ef 100644 --- a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.spec.ts +++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.spec.ts @@ -4,6 +4,7 @@ import { mock, Mock } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { faker } from '@faker-js/faker'; import { expect } from '@jest/globals'; +import { Resource } from '@ngxp/rest'; import { cold } from 'jest-marbles'; import { MockComponent } from 'ng-mocks'; import { EMPTY, of } from 'rxjs'; @@ -37,41 +38,64 @@ describe('FileUploadListContainerComponent', () => { fixture.detectChanges(); }); - describe('component', () => { - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); + describe('component', () => { it('should have default value', () => { expect(component.listOrientation).toEqual(BinaryFileListOrientation.HORIZONTAL); }); - describe('ngOnInit', () => { + describe('set files resource', () => { + beforeEach(() => { + component._initFileList = jest.fn(); + }); + + it('should set value', () => { + const resource: Resource = createDummyResource(); + + component.filesResource = resource; + + expect(component._filesResource).toEqual(resource); + }); + + it('should init file list', () => { + component.filesResource = createDummyResource(); + + expect(component._initFileList).toHaveBeenCalled(); + }); + }); + + describe('_initFileList', () => { beforeEach(() => { binaryFileService.getFiles.mockReturnValue(EMPTY); }); describe('on existing files', () => { + const filesLinkRel = DummyLinkRel.DUMMY; + const filesResource: Resource = createDummyResource([filesLinkRel]); + beforeEach(() => { - component.filesResource = createDummyResource([DummyLinkRel.DUMMY]); - component.filesLinkRel = DummyLinkRel.DUMMY; + component.filesResource = filesResource; + component.filesLinkRel = filesLinkRel; component.fileUploadType = faker.word.noun(); }); it('should load existing files', () => { - component.filesResource = createDummyResource([DummyLinkRel.DUMMY]); - component.filesLinkRel = DummyLinkRel.DUMMY; + component.filesResource = filesResource; + component.filesLinkRel = filesLinkRel; - component.ngOnInit(); + component._initFileList(); - expect(binaryFileService.getFiles).toHaveBeenCalledWith(component.filesResource, component.filesLinkRel); + expect(binaryFileService.getFiles).toHaveBeenCalledWith(filesResource, filesLinkRel); }); it('should add loaded files', () => { const stateResource: StateResource<BinaryFileListResource> = createStateResource(createBinaryFileListResource()); binaryFileService.getFiles.mockReturnValue(of(stateResource)); - component.ngOnInit(); + component._initFileList(); component.uploadedFiles$.subscribe(); expect(binaryFileService.addFiles).toHaveBeenCalledWith( @@ -84,7 +108,7 @@ describe('FileUploadListContainerComponent', () => { const stateResource: StateResource<BinaryFileListResource> = createStateResource(createBinaryFileListResource()); binaryFileService.getFiles.mockReturnValue(of(stateResource)); - component.ngOnInit(); + component._initFileList(); component.uploadedFiles$.subscribe(); expect(binaryFileService.getUploadedFiles).toHaveBeenCalledWith(component.fileUploadType); @@ -96,26 +120,28 @@ describe('FileUploadListContainerComponent', () => { const uploadedFiles: UploadFile[] = [createUploadFile()]; binaryFileService.getUploadedFiles.mockReturnValue(cold('-a', { a: uploadedFiles })); - component.ngOnInit(); + component._initFileList(); expect(component.uploadedFiles$).toBeObservable(cold('a-b', { a: {}, b: uploadedFiles })); }); }); describe('on none existing files', () => { + const filesResource: Resource = createDummyResource(); + beforeEach(() => { - component.filesResource = createDummyResource(); + component.filesResource = filesResource; component.filesLinkRel = DummyLinkRel.DUMMY; }); it('should NOT load existing files', () => { - component.ngOnInit(); + component._initFileList(); expect(binaryFileService.getFiles).not.toHaveBeenCalled(); }); it('should get uploaded files', () => { - component.ngOnInit(); + component._initFileList(); expect(binaryFileService.getUploadedFiles).toHaveBeenCalledWith(component.fileUploadType); }); @@ -124,7 +150,7 @@ describe('FileUploadListContainerComponent', () => { const uploadFile: UploadFile = createUploadFile(); binaryFileService.getUploadedFiles = jest.fn().mockReturnValue(singleColdCompleted(uploadFile)); - component.ngOnInit(); + component._initFileList(); expect(component.uploadedFiles$).toBeObservable(singleColdCompleted(uploadFile)); }); diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.ts b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.ts index b469cf13efa570da4d4e4ca4374d4a75043592fb..406726ee4de247d678fe64489969016d1f1ed878 100644 --- a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.ts +++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.ts @@ -7,7 +7,7 @@ import { } from '@alfa-client/binary-file-shared'; import { getEmbeddedResources, isLoaded, StateResource } from '@alfa-client/tech-shared'; import { AsyncPipe } from '@angular/common'; -import { Component, inject, Input, OnInit } from '@angular/core'; +import { Component, inject, Input } from '@angular/core'; import { hasLink, Resource } from '@ngxp/rest'; import { filter, map, Observable, startWith, switchMap } from 'rxjs'; import { tap } from 'rxjs/operators'; @@ -20,19 +20,30 @@ import { FileUploadListComponent } from './file-upload-list/file-upload-list.com templateUrl: './file-upload-list-container.component.html', imports: [FileUploadListComponent, AsyncPipe], }) -export class FileUploadListContainerComponent implements OnInit { +export class FileUploadListContainerComponent { @Input() fileUploadType: string; @Input() parentFormArrayName: string; @Input() listOrientation: BinaryFileListOrientation = BinaryFileListOrientation.HORIZONTAL; - @Input() filesResource: Resource; - @Input() filesLinkRel: string; + + @Input() set filesResource(value: Resource) { + this._filesResource = value; + this._initFileList(); + } + + @Input() set filesLinkRel(value: string) { + this._filesLinkRel = value; + this._initFileList(); + } + private readonly binaryFileService: BinaryFileService = inject(BinaryFileService); public uploadedFiles$: Observable<UploadFileByIdentifier>; + _filesResource: Resource; + _filesLinkRel: string; - ngOnInit(): void { - if (hasLink(this.filesResource, this.filesLinkRel)) { - this.uploadedFiles$ = this.binaryFileService.getFiles(this.filesResource, this.filesLinkRel).pipe( + _initFileList(): void { + if (hasLink(this._filesResource, this._filesLinkRel)) { + this.uploadedFiles$ = this.binaryFileService.getFiles(this._filesResource, this._filesLinkRel).pipe( filter(isLoaded), map((files: StateResource<BinaryFileListResource>) => getEmbeddedResources(files, BinaryFileListLinkRel.FILE_LIST)), tap((binaryFileResources: BinaryFileResource[]) => diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.html b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.html index edb77f9c7dc133422248b79b4f99f1204900a46c..c6e0aa4b1713a6ba70cd5fa9ae98d8d5265c1f5d 100644 --- a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.html +++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.html @@ -5,7 +5,7 @@ [errorMessages]="uploadFile.uploadedFile.error | convertProblemDetailToErrorMessages" description="Anhang wird hochgeladen" [isLoading]="uploadFile.uploadedFile.loading" - data-test-id="file-upload-list-item-attachment-upload" + [attr.data-test-id]="(uploadFile.fileToUpload.name | convertForDataTest) + '-file-upload-list-item-attachment-upload'" ></ods-attachment> } @else if (uploadFile.uploadedFile.resource) { <ods-attachment-wrapper> @@ -13,7 +13,7 @@ [file]="uploadFile.uploadedFile.resource" [deletable]="true" (startDelete)="delete.emit({ key, binaryFileResource: $event })" - data-test-id="file-upload-list-item-uploaded" + [attr.data-test-id]="(uploadFile.uploadedFile.resource.name | convertForDataTest) + '-file-upload-list-item-uploaded'" > </alfa-binary-file2-container> </ods-attachment-wrapper> diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.spec.ts b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.spec.ts index f60c72fda9d26b37343f543116eee01113fc394b..8b1321620c75ccdb5cfeba566b46abdaead8fb95 100644 --- a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.spec.ts +++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.spec.ts @@ -1,6 +1,8 @@ import { BinaryFile2ContainerComponent, BinaryFileModule } from '@alfa-client/binary-file'; import { BinaryFileResource } from '@alfa-client/binary-file-shared'; import { + convertForDataTest, + ConvertForDataTestPipe, ConvertProblemDetailToErrorMessagesPipe, createEmptyStateResource, createErrorStateResource, @@ -29,12 +31,16 @@ describe('FileUploadListItemComponent', () => { let component: FileUploadListItemComponent; let fixture: ComponentFixture<FileUploadListItemComponent>; - const attachmentTestId: string = getDataTestIdOf('file-upload-list-item-attachment-upload'); - const binaryFileContainerTestId: string = getDataTestIdOf('file-upload-list-item-uploaded'); + const file: File = createFile(); + const binaryFileResource: BinaryFileResource = createBinaryFileResource(); + const attachmentTestId: string = getDataTestIdOf(convertForDataTest(file.name) + '-file-upload-list-item-attachment-upload'); + const binaryFileContainerTestId: string = getDataTestIdOf( + convertForDataTest(binaryFileResource.name) + '-file-upload-list-item-uploaded', + ); beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [FileUploadListItemComponent, ConvertProblemDetailToErrorMessagesPipe], + imports: [FileUploadListItemComponent, ConvertProblemDetailToErrorMessagesPipe, ConvertForDataTestPipe], declarations: [MockModule(BinaryFileModule), MockComponent(BinaryFile2ContainerComponent)], }).compileComponents(); @@ -50,8 +56,6 @@ describe('FileUploadListItemComponent', () => { }); describe('template', () => { - const file: File = createFile(); - beforeEach(() => { component.uploadFile.fileToUpload = file; }); @@ -74,7 +78,7 @@ describe('FileUploadListItemComponent', () => { }); it('should NOT exists on loaded', () => { - component.uploadFile.uploadedFile = createStateResource(createBinaryFileResource()); + component.uploadFile.uploadedFile = createStateResource(binaryFileResource); fixture.detectChanges(); @@ -82,7 +86,7 @@ describe('FileUploadListItemComponent', () => { }); it('should have inputs', () => { - component.uploadFile.fileToUpload = createFile(); + component.uploadFile.fileToUpload = file; component.uploadFile.uploadedFile = createEmptyStateResource(true); fixture.detectChanges(); @@ -97,7 +101,7 @@ describe('FileUploadListItemComponent', () => { describe('uploaded file', () => { it('should exists', () => { - component.uploadFile.uploadedFile = createStateResource(createBinaryFileResource()); + component.uploadFile.uploadedFile = createStateResource(binaryFileResource); fixture.detectChanges(); @@ -113,7 +117,7 @@ describe('FileUploadListItemComponent', () => { }); it('should have inputs', () => { - component.uploadFile.uploadedFile = createStateResource(createBinaryFileResource()); + component.uploadFile.uploadedFile = createStateResource(binaryFileResource); fixture.detectChanges(); @@ -131,7 +135,6 @@ describe('FileUploadListItemComponent', () => { it('should emit', () => { component.delete.emit = jest.fn(); component.key = 'test'; - const binaryFileResource: BinaryFileResource = createBinaryFileResource(); component.uploadFile.uploadedFile = createStateResource(binaryFileResource); fixture.detectChanges(); diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.ts b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.ts index 25527119bdaa6e87a88335557e8bf8e13054127d..854f6f0466ac5d5f8589c244f751ce2493e82f76 100644 --- a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.ts +++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.ts @@ -1,6 +1,6 @@ import { BinaryFileModule } from '@alfa-client/binary-file'; import { FileToDelete, UploadFile } from '@alfa-client/binary-file-shared'; -import { ConvertProblemDetailToErrorMessagesPipe } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe, ConvertProblemDetailToErrorMessagesPipe } from '@alfa-client/tech-shared'; import { Component, EventEmitter, Input, Output } from '@angular/core'; import { AttachmentComponent, AttachmentWrapperComponent } from '@ods/system'; @@ -8,7 +8,13 @@ import { AttachmentComponent, AttachmentWrapperComponent } from '@ods/system'; selector: 'ods-file-upload-list-item', standalone: true, templateUrl: './file-upload-list-item.component.html', - imports: [AttachmentComponent, AttachmentWrapperComponent, BinaryFileModule, ConvertProblemDetailToErrorMessagesPipe], + imports: [ + AttachmentComponent, + AttachmentWrapperComponent, + BinaryFileModule, + ConvertProblemDetailToErrorMessagesPipe, + ConvertForDataTestPipe, + ], }) export class FileUploadListItemComponent { @Input() key: string; diff --git a/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.spec.ts b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.spec.ts index 0620a5f50612f4eeb3243f599d57fc9e1d1e3353..dc42e69a0f52518ba01f5f3ddf2009ef04e344e9 100644 --- a/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.spec.ts +++ b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.spec.ts @@ -1,7 +1,8 @@ -import { BinaryFileService, ToUploadFile } from '@alfa-client/binary-file-shared'; +import { BinaryFileService, FileUploadType, ToUploadFile } from '@alfa-client/binary-file-shared'; import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { existsAsHtmlElement, getElementComponentFromFixtureByCss, mock, Mock } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { faker } from '@faker-js/faker/.'; import { expect } from '@jest/globals'; import { getUrl, Resource } from '@ngxp/rest'; import { FileUploadButtonComponent, SpinnerIconComponent } from '@ods/system'; @@ -17,7 +18,8 @@ describe('MultiFileUploadEditorComponent', () => { let component: MultiFileUploadEditorComponent; let fixture: ComponentFixture<MultiFileUploadEditorComponent>; - const uploadLinkRel: string = 'upload'; + const fileUploadType: FileUploadType = faker.word.noun(); + const uploadLinkRel: string = faker.word.noun(); const uploadResource: Resource = createDummyResource([uploadLinkRel]); const buttonTestId: string = getDataTestIdOf('Ein_Label-file-upload-button'); @@ -58,6 +60,14 @@ describe('MultiFileUploadEditorComponent', () => { describe('component', () => { describe('ngOnInit', () => { + it('should get upload in progress', () => { + component.fileUploadType = fileUploadType; + + component.ngOnInit(); + + expect(binaryFileService.isUploadInProgress).toHaveBeenCalledWith(fileUploadType); + }); + it('should set upload in progress', () => { binaryFileService.isUploadInProgress = jest.fn().mockReturnValue(of(true)); diff --git a/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.ts b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.ts index f69f78656a70336abe6b7a9cd72d8c12051177f4..4c057b3f3d7b52b25dc63164e62f06bb054b83c8 100644 --- a/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.ts +++ b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.ts @@ -1,6 +1,5 @@ import { BinaryFileModule } from '@alfa-client/binary-file'; import { BinaryFileService, FileUploadType } from '@alfa-client/binary-file-shared'; -import { KOMMENTAR_UPLOADED_ATTACHMENTS } from '@alfa-client/kommentar-shared'; import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; import { AsyncPipe } from '@angular/common'; import { Component, HostListener, inject, Input, OnInit } from '@angular/core'; @@ -39,7 +38,7 @@ export class MultiFileUploadEditorComponent implements OnInit { public readonly uploadButtonId: string = uniqueId(); ngOnInit(): void { - this.isUploadInProgress$ = this.binaryFileService.isUploadInProgress(KOMMENTAR_UPLOADED_ATTACHMENTS); + this.isUploadInProgress$ = this.binaryFileService.isUploadInProgress(this.fileUploadType); } @HostListener('change', ['$event.target.files']) diff --git a/alfa-client/libs/binary-file/src/lib/multi-file-upload/multi-file-upload.component.html b/alfa-client/libs/binary-file/src/lib/multi-file-upload/multi-file-upload.component.html new file mode 100644 index 0000000000000000000000000000000000000000..184ac868f9f594da443f6f89b969ce1cc85b1dfc --- /dev/null +++ b/alfa-client/libs/binary-file/src/lib/multi-file-upload/multi-file-upload.component.html @@ -0,0 +1,13 @@ +<ods-file-upload-list-container + [parentFormArrayName]="filesFormFieldName" + [fileUploadType]="fileUploadType" + [filesResource]="filesResource" + [filesLinkRel]="filesLinkRelation" + data-test-id="file-list" +></ods-file-upload-list-container> +<ods-multi-file-upload-editor + [fileUploadType]="fileUploadType" + [uploadResource]="uploadResource" + [uploadLinkRelation]="uploadLinkRelation" + data-test-id="multi-file-upload-editor" +></ods-multi-file-upload-editor> \ No newline at end of file diff --git a/alfa-client/libs/binary-file/src/lib/multi-file-upload/multi-file-upload.component.spec.ts b/alfa-client/libs/binary-file/src/lib/multi-file-upload/multi-file-upload.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..70679e7411aabf14b7d08d7bf855a40edc41242b --- /dev/null +++ b/alfa-client/libs/binary-file/src/lib/multi-file-upload/multi-file-upload.component.spec.ts @@ -0,0 +1,92 @@ +import { FileUploadListContainerComponent, MultiFileUploadEditorComponent } from '@alfa-client/binary-file'; +import { FileUploadType } from '@alfa-client/binary-file-shared'; +import { existsAsHtmlElement, getElementComponentFromFixtureByCss } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { faker } from '@faker-js/faker/.'; +import { expect } from '@jest/globals'; +import { Resource } from '@ngxp/rest'; +import { MockComponent } from 'ng-mocks'; +import { getDataTestIdOf } from '../../../../tech-shared/test/data-test'; +import { DummyLinkRel } from '../../../../tech-shared/test/dummy'; +import { createDummyResource } from '../../../../tech-shared/test/resource'; +import { MultiFileUploadComponent } from './multi-file-upload.component'; + +describe('MultiFileUploadComponent', () => { + let component: MultiFileUploadComponent; + let fixture: ComponentFixture<MultiFileUploadComponent>; + + const fileUploadListTestId: string = getDataTestIdOf('file-list'); + const fileUploadEditorTestId: string = getDataTestIdOf('multi-file-upload-editor'); + + const fileUploadType: FileUploadType = faker.word.noun(); + const uploadLinkRel: string = DummyLinkRel.DUMMY; + const uploadResource: Resource = createDummyResource(); + const filesLinkRel: string = DummyLinkRel.DUMMY; + const filesResource: Resource = createDummyResource(); + const formFieldsName: string = faker.word.noun(); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MultiFileUploadComponent], + declarations: [MockComponent(MultiFileUploadEditorComponent), MockComponent(FileUploadListContainerComponent)], + }).compileComponents(); + + fixture = TestBed.createComponent(MultiFileUploadComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('template', () => { + beforeEach(() => { + component.filesFormFieldName = formFieldsName; + component.fileUploadType = fileUploadType; + component.uploadResource = uploadResource; + component.uploadLinkRelation = uploadLinkRel; + component.filesResource = filesResource; + component.filesLinkRelation = filesLinkRel; + }); + + describe('file upload list', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, fileUploadListTestId); + }); + + it('should have inputs', () => { + fixture.detectChanges(); + + const fileUploadListComponent: FileUploadListContainerComponent = getElementComponentFromFixtureByCss( + fixture, + fileUploadListTestId, + ); + + expect(fileUploadListComponent.parentFormArrayName).toEqual(formFieldsName); + expect(fileUploadListComponent.fileUploadType).toEqual(fileUploadType); + expect(fileUploadListComponent.filesResource).toEqual(filesResource); + expect(fileUploadListComponent.filesLinkRel).toEqual(filesLinkRel); + }); + }); + + describe('file upload editor', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, fileUploadEditorTestId); + }); + + it('should have inputs', () => { + fixture.detectChanges(); + + const fileUploadEditorComponent: MultiFileUploadEditorComponent = getElementComponentFromFixtureByCss( + fixture, + fileUploadEditorTestId, + ); + + expect(fileUploadEditorComponent.fileUploadType).toEqual(fileUploadType); + expect(fileUploadEditorComponent.uploadResource).toEqual(uploadResource); + expect(fileUploadEditorComponent.uploadLinkRelation).toEqual(uploadLinkRel); + }); + }); + }); +}); diff --git a/alfa-client/libs/binary-file/src/lib/multi-file-upload/multi-file-upload.component.ts b/alfa-client/libs/binary-file/src/lib/multi-file-upload/multi-file-upload.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..56234cb550a4fdcaf31529f5a0af54457eb94623 --- /dev/null +++ b/alfa-client/libs/binary-file/src/lib/multi-file-upload/multi-file-upload.component.ts @@ -0,0 +1,22 @@ +import { FileUploadType } from '@alfa-client/binary-file-shared'; +import { Component, Input } from '@angular/core'; +import { Resource } from '@ngxp/rest'; +import { BinaryFileListOrientation } from '../directive/binary-file-list-orientation/binary-file-list-orientation.directive'; +import { FileUploadListContainerComponent } from '../file-upload-list-container/file-upload-list-container.component'; +import { MultiFileUploadEditorComponent } from '../multi-file-upload-editor/multi-file-upload-editor.component'; + +@Component({ + selector: 'ods-multi-file-upload', + standalone: true, + templateUrl: './multi-file-upload.component.html', + imports: [FileUploadListContainerComponent, MultiFileUploadEditorComponent], +}) +export class MultiFileUploadComponent { + @Input({ required: true }) filesFormFieldName: string; + @Input({ required: true }) fileUploadType: FileUploadType; + @Input({ required: true }) uploadResource: Resource; + @Input({ required: true }) uploadLinkRelation: string; + @Input({ required: true }) filesResource: Resource; + @Input({ required: true }) filesLinkRelation: string; + @Input() listOrientation: BinaryFileListOrientation = BinaryFileListOrientation.HORIZONTAL; +} diff --git a/alfa-client/libs/design-component/src/index.ts b/alfa-client/libs/design-component/src/index.ts index 745720be72b8665fb259372141e6ab5537efbfbe..9eec827c3a019115cc42c751521816fdde5c87a7 100644 --- a/alfa-client/libs/design-component/src/index.ts +++ b/alfa-client/libs/design-component/src/index.ts @@ -22,6 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ export * from './lib/button-with-spinner/button-with-spinner.component'; +export * from './lib/cancel-dialog-button/cancel-dialog-button.component'; export * from './lib/download-button/download-button.component'; export * from './lib/form/button-toggle-group/button-toggle-group.component'; export * from './lib/form/checkbox-editor/checkbox-editor.component'; @@ -30,5 +31,6 @@ export * from './lib/form/formcontrol-editor.abstract.component'; export * from './lib/form/single-file-upload-editor/single-file-upload-editor.component'; export * from './lib/form/text-editor/text-editor.component'; export * from './lib/form/textarea-editor/textarea-editor.component'; +export * from './lib/open-dialog-button/open-dialog-button.component'; export * from './lib/routing-button/routing-button.component'; export * from './lib/spinner/spinner.component'; diff --git a/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.spec.ts b/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..110c81e4d4072ef0417676ea9966a7fa3394f144 --- /dev/null +++ b/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.spec.ts @@ -0,0 +1,47 @@ +import { dispatchEventFromFixture, mock, Mock, MockEvent } from '@alfa-client/test-utils'; +import { OzgcloudDialogService } from '@alfa-client/ui'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ButtonComponent } from '@ods/system'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { MockComponent } from 'ng-mocks'; +import { CancelDialogButtonComponent } from './cancel-dialog-button.component'; + +describe('CancelDialogButtonComponent', () => { + let component: CancelDialogButtonComponent; + let fixture: ComponentFixture<CancelDialogButtonComponent>; + + let dialogService: Mock<OzgcloudDialogService>; + + const cancelDialog: string = getDataTestIdOf('cancel-dialog'); + + beforeEach(async () => { + dialogService = mock(OzgcloudDialogService); + + await TestBed.configureTestingModule({ + imports: [CancelDialogButtonComponent], + declarations: [MockComponent(ButtonComponent)], + providers: [ + { + provide: OzgcloudDialogService, + useValue: dialogService, + }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(CancelDialogButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('on button click', () => { + it('should call dialog service to close all', () => { + dispatchEventFromFixture(fixture, cancelDialog, MockEvent.CLICK); + + expect(dialogService.closeAll).toHaveBeenCalled(); + }); + }); +}); diff --git a/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.ts b/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..5d80db0f4e7755c1a2bd9ae9eb7b921c3cf58349 --- /dev/null +++ b/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.ts @@ -0,0 +1,23 @@ +import { OzgcloudDialogService } from '@alfa-client/ui'; +import { Component, inject } from '@angular/core'; +import { ButtonComponent } from '@ods/system'; + +@Component({ + selector: 'ods-cancel-dialog-button', + standalone: true, + imports: [ButtonComponent], + template: `<ods-button + (clickEmitter)="cancel()" + variant="outline" + text="Abbrechen" + dataTestId="cancel-dialog" + data-test-id="cancel-dialog" + />`, +}) +export class CancelDialogButtonComponent { + public readonly dialogService = inject(OzgcloudDialogService); + + public cancel(): void { + this.dialogService.closeAll(); + } +} diff --git a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.html b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.html index c4901be8608a9e1162963472472090a19fad3a5a..c4c009107436b4b7a8837c0fa9c31c4add1008d6 100644 --- a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.html +++ b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.html @@ -29,7 +29,8 @@ [placeholder]="placeholder" [autocomplete]="autocomplete" [variant]="variant" - [attr.data-test-id]="(label | convertForDataTest) + '-text-editor'" + [attr.data-test-id]="dataTestId + '-text-editor'" + [dataTestId]="dataTestId" [required]="isRequired" [focus]="focus" [showLabel]="showLabel" @@ -38,6 +39,6 @@ error [invalidParams]="invalidParams" [label]="label" - [attr.data-test-id]="(label | convertForDataTest) + '-text-editor-error'" + [attr.data-test-id]="dataTestId + '-text-editor-error'" ></ods-validation-error> </ods-text-input> diff --git a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.spec.ts b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.spec.ts index 7774ab8ddcebff345d1d62853e8ced4e0773adae..e6dce44b7e467a5d99d3e45667f05c716e29fc68 100644 --- a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.spec.ts +++ b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.spec.ts @@ -35,8 +35,9 @@ describe('TextEditorComponent', () => { let fixture: ComponentFixture<TextEditorComponent>; const labelText: string = faker.word.noun(); - const inputTestId: string = getDataTestIdOf(labelText + '-text-editor'); - const errorId: string = getDataTestIdOf(labelText + '-text-editor-error'); + const dataTestId: string = faker.string.alphanumeric(10); + const inputTestId: string = getDataTestIdOf(dataTestId + '-text-editor'); + const errorId: string = getDataTestIdOf(dataTestId + '-text-editor-error'); beforeEach(async () => { await TestBed.configureTestingModule({ @@ -47,6 +48,7 @@ describe('TextEditorComponent', () => { fixture = TestBed.createComponent(TextEditorComponent); component = fixture.componentInstance; component.label = labelText; + component.dataTestId = dataTestId; fixture.detectChanges(); }); 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 cfdd66512de073b74f0dbfd2bbed633573f9651f..45f7c42c8f3f609567e89d3075411ac652eb8882 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 @@ -42,6 +42,7 @@ export class TextEditorComponent extends FormControlEditorAbstractComponent { @Input() isRequired: boolean = false; @Input() focus: boolean = false; @Input() showLabel: boolean = true; + @Input() dataTestId: string; get variant(): string { return this.invalidParams.length > 0 ? 'error' : 'default'; diff --git a/alfa-client/libs/design-component/src/lib/open-dialog-button/open-dialog-button.component.spec.ts b/alfa-client/libs/design-component/src/lib/open-dialog-button/open-dialog-button.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..8cbe8c1ae06eabaea31340ddd8eb31f710cab503 --- /dev/null +++ b/alfa-client/libs/design-component/src/lib/open-dialog-button/open-dialog-button.component.spec.ts @@ -0,0 +1,104 @@ +import { OzgCloudComponentFactory } from '@alfa-client/tech-shared'; +import { dispatchEventFromFixture, Mock, mock, MockEvent, mockGetValue } from '@alfa-client/test-utils'; +import { DIALOG_COMPONENT, OzgcloudDialogService } from '@alfa-client/ui'; +import { ComponentType } from '@angular/cdk/portal'; +import { ComponentRef, Injector, ViewContainerRef } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ButtonComponent } from '@ods/system'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { OpenDialogButtonComponent } from './open-dialog-button.component'; + +describe('OpenDialogButtonComponent', () => { + let component: OpenDialogButtonComponent; + let fixture: ComponentFixture<OpenDialogButtonComponent>; + + let dialogComponent: Mock<ComponentType<any>>; + let componentFactory: Mock<OzgCloudComponentFactory>; + let dialogService: Mock<OzgcloudDialogService>; + let viewContainerRef: Mock<ViewContainerRef>; + let injector: Mock<Injector>; + + const openDialog: string = getDataTestIdOf('open-dialog'); + + const componentRef: ComponentRef<any> = <any>{ instance: { constructor: null } }; + const dialogResponse: any = {}; + + beforeEach(async () => { + dialogComponent = {}; + componentFactory = mock(OzgCloudComponentFactory); + dialogService = { ...mock(OzgcloudDialogService), openInContext: jest.fn().mockReturnValue({ closed: of(dialogResponse) }) }; + viewContainerRef = mock(ViewContainerRef as any); + injector = mock(Injector as any); + + await TestBed.configureTestingModule({ + imports: [OpenDialogButtonComponent], + declarations: [MockComponent(ButtonComponent)], + providers: [ + { + provide: DIALOG_COMPONENT, + useValue: dialogComponent, + }, + { + provide: OzgCloudComponentFactory, + useValue: componentFactory, + }, + { + provide: OzgcloudDialogService, + useValue: dialogService, + }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(OpenDialogButtonComponent); + component = fixture.componentInstance; + mockGetValue(component, 'viewContainerRef', viewContainerRef); + mockGetValue(component, 'injector', injector); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('on button click', () => { + beforeEach(() => { + component._createComponent = jest.fn().mockReturnValue(componentRef); + }); + + it('should call create component factory to create component', () => { + dispatchEventFromFixture(fixture, openDialog, MockEvent.CLICK); + + expect(component._createComponent).toHaveBeenCalled(); + }); + + it('should call dialog service to open dialog', () => { + dispatchEventFromFixture(fixture, openDialog, MockEvent.CLICK); + + expect(dialogService.openInContext).toHaveBeenCalledWith(componentRef.instance.constructor, viewContainerRef); + }); + }); + + describe('open', () => { + beforeEach(() => { + component._createComponent = jest.fn().mockReturnValue(componentRef); + }); + + it('should emit close emitter on dialog close', () => { + component.close.emit = jest.fn(); + + component.open(); + + expect(component.close.emit).toHaveBeenCalled(); + }); + }); + + describe('create component', () => { + it('should call component factory to create component', () => { + component._createComponent(); + + expect(componentFactory.createComponent).toHaveBeenCalledWith(dialogComponent, injector); + }); + }); +}); diff --git a/alfa-client/libs/design-component/src/lib/open-dialog-button/open-dialog-button.component.ts b/alfa-client/libs/design-component/src/lib/open-dialog-button/open-dialog-button.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..2815aab6fd3ed8601930bfe061fecc23fc0e4704 --- /dev/null +++ b/alfa-client/libs/design-component/src/lib/open-dialog-button/open-dialog-button.component.ts @@ -0,0 +1,49 @@ +import { OzgCloudComponentFactory } from '@alfa-client/tech-shared'; +import { DIALOG_COMPONENT, OzgcloudDialogService } from '@alfa-client/ui'; +import { ComponentType } from '@angular/cdk/portal'; +import { Component, ComponentRef, EventEmitter, inject, Injector, Input, Output, ViewContainerRef } from '@angular/core'; +import { ButtonComponent, ButtonVariants } from '@ods/system'; +import { first } from 'rxjs'; + +@Component({ + selector: 'ods-open-dialog-button', + standalone: true, + imports: [ButtonComponent], + template: `<ods-button + (clickEmitter)="open()" + [variant]="variant" + [text]="label" + [dataTestId]="dataTestId" + data-test-id="open-dialog" + > + <ng-container icon> + <ng-content select="[icon]" /> + </ng-container> + </ods-button>`, +}) +export class OpenDialogButtonComponent { + private readonly component: ComponentType<any> = inject(DIALOG_COMPONENT); + private readonly componentFactory = inject(OzgCloudComponentFactory); + + private readonly dialogService = inject(OzgcloudDialogService); + + readonly viewContainerRef = inject(ViewContainerRef); + private readonly injector = inject(Injector); + + @Input() label: string; + @Input() dataTestId: string; + @Input() variant: ButtonVariants['variant'] = 'primary'; + + @Output() close: EventEmitter<void> = new EventEmitter(); + + public open(): void { + this.dialogService + .openInContext(this._createComponent().instance.constructor, this.viewContainerRef) + .closed.pipe(first()) + .subscribe(this.close.emit); + } + + _createComponent(): ComponentRef<any> { + return this.componentFactory.createComponent<any>(this.component, this.injector); + } +} 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 f7805648f827ff51ca7fde46354aec02345a0fa3..c0f7892c3c2c5184571b175dbff2326591415495 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 @@ -39,6 +39,8 @@ export const buttonVariants = cva( primary: 'bg-primary text-whitetext shadow-md hover:enabled:bg-primary-hover focus-visible:bg-primary-hover', outline: 'border border-primary bg-background-50 text-primary shadow-md hover:enabled:bg-ghost-hover focus-visible:bg-ghost-hover focus-visible:border-background-200', + outline_error: + 'border border-error bg-background-50 text-error shadow-md hover:enabled:bg-ghost-hover focus-visible:bg-ghost-hover focus-visible:border-background-200', ghost: 'border border-transparent hover:enabled:bg-ghost-hover text-primary focus-visible:border-background-200 focus-visible:bg-ghost-hover font-semibold [&]:focus-visible:outline-offset-1', }, 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 ca6a007c19e49ebb481ff0655b407cc3076a9c08..1b8bf5fdf47948bbc9374b01086238c3e41c0ac3 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,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { convertForDataTest, ConvertForDataTestPipe, EMPTY_STRING } from '@alfa-client/tech-shared'; +import { convertForDataTest, ConvertForDataTestPipe, EMPTY_STRING, isNotUndefined } 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'; @@ -70,7 +70,7 @@ type TextInputVariants = VariantProps<typeof textInputVariants>; [autocomplete]="autocomplete" [attr.aria-required]="required" [attr.aria-invalid]="variant === 'error'" - [attr.data-test-id]="(inputLabel | convertForDataTest) + '-text-input'" + [attr.data-test-id]="_dataTestId + '-text-input'" (click)="clickEmitter.emit()" #inputElement /> @@ -88,6 +88,7 @@ export class TextInputComponent { @Input({ required: true }) set label(label: string) { this.inputLabel = label; this.id = `${convertForDataTest(label)}-${uniqueId()}`; + this._dataTestId = convertForDataTest(this.inputLabel); } @Input() placeholder: string = ''; @Input() autocomplete: string = 'off'; @@ -97,6 +98,9 @@ export class TextInputComponent { @Input() withPrefix: boolean = false; @Input() withSuffix: boolean = false; @Input() showLabel: boolean = true; + @Input() set dataTestId(value: string) { + if (isNotUndefined(value)) this._dataTestId = value; + } @Input() set focus(value: boolean) { if (value && this.inputElement) { @@ -108,5 +112,6 @@ export class TextInputComponent { inputLabel: string; id: string; + _dataTestId: string; textInputVariants = textInputVariants; } diff --git a/alfa-client/libs/historie/src/lib/historie.module.ts b/alfa-client/libs/historie/src/lib/historie.module.ts index c9675a36427c958658176eac4776cbc1fdf23c9d..e0b620b84ae95157372eb714c2dba636e8fe448f 100644 --- a/alfa-client/libs/historie/src/lib/historie.module.ts +++ b/alfa-client/libs/historie/src/lib/historie.module.ts @@ -34,7 +34,7 @@ import { AccordionComponent, AppIconComponent, SpinnerComponent } from '@alfa-cl 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 { MatExpansionPanel, MatExpansionPanelHeader, 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'; @@ -76,6 +76,7 @@ import { HistorieListComponent } from './historie-container/historie-list/histor SpinnerComponent, AccordionComponent, ToEmbeddedResourcesPipe, + MatExpansionPanelHeader, ], declarations: [ HistorieContainerComponent, diff --git a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts index 98a918c03eb9d525d9bc2977f1885838dd873da3..1ceecd9e1f16e3309e234235887150f8e5c6ee3a 100644 --- a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts +++ b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts @@ -24,16 +24,19 @@ import { BinaryFileService } from '@alfa-client/binary-file-shared'; import { CommandOrder, CommandResource, CommandService, CreateCommand } from '@alfa-client/command-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { createEmptyStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared'; +import { createEmptyStateResource, createStateResource, EMPTY_STRING, StateResource } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { faker } from '@faker-js/faker'; import { expect } from '@jest/globals'; +import { ResourceUri } from '@ngxp/rest'; import { cold, hot } from 'jest-marbles'; import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel'; import { createCommandResource } from 'libs/command-shared/test/command'; import { createKommentar, createKommentarListResource, createKommentarResource } from 'libs/kommentar-shared/test/kommentar'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; import { of } from 'rxjs'; +import { singleCold } from '../../../tech-shared/test/marbles'; import { KommentarLinkRel, KommentarListLinkRel } from './kommentar.linkrel'; import { Kommentar, KOMMENTAR_UPLOADED_ATTACHMENTS, KommentarListResource, KommentarResource } from './kommentar.model'; import { KommentarRepository } from './kommentar.repository'; @@ -327,4 +330,78 @@ describe('KommentarService', () => { expect(binaryFileService.clearUploadedFiles).toHaveBeenCalledWith(KOMMENTAR_UPLOADED_ATTACHMENTS); }); }); + + describe('is new kommentar formular visible', () => { + it('should emit true', () => { + service._currentlyEdited$.next(EMPTY_STRING); + service.formularVisibility$.next(true); + + expect(service.isFormularVisible()).toBeObservable(singleCold(true)); + }); + + it('should emit false if any kommentar is being edited', () => { + service._currentlyEdited$.next(faker.internet.url()); + service.formularVisibility$.next(true); + + expect(service.isFormularVisible()).toBeObservable(singleCold(false)); + }); + + it('should emit false if not visible', () => { + service._currentlyEdited$.next(EMPTY_STRING); + service.formularVisibility$.next(false); + + expect(service.isFormularVisible()).toBeObservable(singleCold(false)); + }); + }); + + describe('show new kommentar formular', () => { + beforeEach(() => { + service.setCurrentlyEdited = jest.fn(); + }); + + it('should set currently edited to empty string', () => { + service.showFormular(); + + expect(service.setCurrentlyEdited).toHaveBeenCalledWith(EMPTY_STRING); + }); + + it('should set formular visibility', () => { + service.showFormular(); + + expect(service.formularVisibility$).toBeObservable(singleCold(true)); + }); + }); + + describe('set currently edited kommentar uri', () => { + beforeEach(() => { + service.clearUploadedFiles = jest.fn(); + service.hideFormular = jest.fn(); + }); + + it('should clear uploaded files', () => { + service.setCurrentlyEdited(faker.internet.url()); + + expect(service.clearUploadedFiles).toHaveBeenCalled(); + }); + + it('should hide kommentar creation formular', () => { + service.setCurrentlyEdited(faker.internet.url()); + + expect(service.hideFormular).toHaveBeenCalled(); + }); + + it('should NOT hide kommentar creation formular', () => { + service.setCurrentlyEdited(EMPTY_STRING); + + expect(service.hideFormular).not.toHaveBeenCalled(); + }); + + it('should emit currently edited resource uri', () => { + const resourceUri: ResourceUri = faker.internet.url(); + + service.setCurrentlyEdited(resourceUri); + + expect(service._currentlyEdited$).toBeObservable(singleCold(resourceUri)); + }); + }); }); diff --git a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts index 27efa8ae9da9e852906f3917b070e27e9faeca2d..6749d94ff0079091abf5f3a42d6c67786b171d08 100644 --- a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts +++ b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts @@ -24,13 +24,13 @@ import { BinaryFileListResource, BinaryFileService } from '@alfa-client/binary-file-shared'; import { CommandOrder, CommandResource, CommandService, CreateCommand, isDone } from '@alfa-client/command-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { createEmptyStateResource, createStateResource, doIfLoadingRequired, StateResource } from '@alfa-client/tech-shared'; +import { createEmptyStateResource, createStateResource, doIfLoadingRequired, EMPTY_STRING, isNotEmpty, StateResource, } from '@alfa-client/tech-shared'; import { VorgangResource, VorgangService } from '@alfa-client/vorgang-shared'; import { Injectable } from '@angular/core'; import { Params } from '@angular/router'; -import { hasLink, Resource } from '@ngxp/rest'; +import { hasLink, Resource, ResourceUri } from '@ngxp/rest'; import { isNil } from 'lodash-es'; -import { BehaviorSubject, Observable, of, Subscription } from 'rxjs'; +import { BehaviorSubject, combineLatest, Observable, of, Subscription } from 'rxjs'; import { map, startWith, tap } from 'rxjs/operators'; import { KommentarLinkRel, KommentarListLinkRel } from './kommentar.linkrel'; import { Kommentar, KOMMENTAR_UPLOADED_ATTACHMENTS, KommentarListResource, KommentarResource } from './kommentar.model'; @@ -42,6 +42,7 @@ export class KommentarService { createEmptyStateResource<KommentarListResource>(), ); readonly formularVisibility$: BehaviorSubject<boolean> = new BehaviorSubject(false); + readonly _currentlyEdited$: BehaviorSubject<ResourceUri> = new BehaviorSubject(''); private navigationSub: Subscription; @@ -104,7 +105,9 @@ export class KommentarService { } public isFormularVisible(): Observable<boolean> { - return this.formularVisibility$.asObservable(); + return combineLatest([this.formularVisibility$, this._currentlyEdited$]).pipe( + map(([isVisible, currentlyEdited]) => isVisible && currentlyEdited === EMPTY_STRING), + ); } public canCreateNewKommentar(kommentareListResource: KommentarListResource): Observable<boolean> { @@ -114,6 +117,7 @@ export class KommentarService { } public showFormular(): void { + this.setCurrentlyEdited(EMPTY_STRING); this.formularVisibility$.next(true); } @@ -170,4 +174,16 @@ export class KommentarService { public clearUploadedFiles(): void { this.binaryFileService.clearUploadedFiles(KOMMENTAR_UPLOADED_ATTACHMENTS); } + + public getCurrentlyEdited(): Observable<ResourceUri> { + return this._currentlyEdited$.asObservable(); + } + + public setCurrentlyEdited(resourceUri: ResourceUri): void { + this.clearUploadedFiles(); + if (isNotEmpty(resourceUri)) { + this.hideFormular(); + } + this._currentlyEdited$.next(resourceUri); + } } diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.html b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.html index 8a5168bf1dc59de260e7e7a5ece9c9a6167153c1..ccb901c94fa17fc98518b6abfdd9e202058c2e8a 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.html +++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.html @@ -27,19 +27,14 @@ <ozgcloud-textarea-editor [formControlName]="formServiceClass.TEXT" label="Kommentar" [required]="true"> </ozgcloud-textarea-editor> - <ods-file-upload-list-container - [parentFormArrayName]="formServiceClass.FIELD_ATTACHMENTS" - [fileUploadType]="KOMMENTAR_UPLOADED_ATTACHMENTS" - [filesResource]="kommentar" - [filesLinkRel]="KommentarLinkRel.ATTACHMENTS" - data-test-id="kommentar-multi-file-upload-list" - ></ods-file-upload-list-container> - <ods-multi-file-upload-editor - [fileUploadType]="KOMMENTAR_UPLOADED_ATTACHMENTS" - [uploadResource]="kommentarListStateResource.resource" - [uploadLinkRelation]="kommentarListLinkRel.UPLOAD_FILE" - data-test-id="kommentar-multi-file-upload-editor" - ></ods-multi-file-upload-editor> + <ods-multi-file-upload + [filesFormFieldName]="formServiceClass.FIELD_ATTACHMENTS" + [fileUploadType]="KOMMENTAR_UPLOADED_ATTACHMENTS" + [uploadResource]="kommentarListStateResource.resource" + [uploadLinkRelation]="kommentarListLinkRel.UPLOAD_FILE" + [filesResource]="kommentar" + [filesLinkRelation]="KommentarLinkRel.ATTACHMENTS" + ></ods-multi-file-upload> <div class="buttons"> <ozgcloud-stroked-button-with-spinner diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.spec.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.spec.ts index 15d300ef0ad665960ee7349b31d2678d60ac7c30..9753cc7fa2dafde144f13618d84c55a24b1bc1a3 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.spec.ts +++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.spec.ts @@ -21,11 +21,11 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BinaryFileAttachmentContainerComponent, FileUploadListContainerComponent, MultiFileUploadEditorComponent, } from '@alfa-client/binary-file'; +import { BinaryFileAttachmentContainerComponent } from '@alfa-client/binary-file'; import { CommandResource } from '@alfa-client/command-shared'; -import { KOMMENTAR_UPLOADED_ATTACHMENTS, KommentarLinkRel, KommentarListLinkRel, KommentarListResource, KommentarService, } from '@alfa-client/kommentar-shared'; +import { KommentarLinkRel, KommentarListResource, KommentarService } from '@alfa-client/kommentar-shared'; import { createEmptyStateResource, createErrorStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared'; -import { existsAsHtmlElement, getElementComponentFromFixtureByCss, Mock, mock, triggerEvent, useFromMock, } from '@alfa-client/test-utils'; +import { existsAsHtmlElement, Mock, mock, triggerEvent, useFromMock } from '@alfa-client/test-utils'; import { OzgcloudStrokedButtonWithSpinnerComponent, TextAreaEditorComponent } from '@alfa-client/ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; @@ -34,6 +34,7 @@ import { expect } from '@jest/globals'; import { MockComponent } from 'ng-mocks'; import { EMPTY, of } from 'rxjs'; import { createBinaryFileListResource } from '../../../../../binary-file-shared/test/binary-file'; +import { MultiFileUploadComponent } from '../../../../../binary-file/src/lib/multi-file-upload/multi-file-upload.component'; import { createSuccessfullyDoneCommandStateResource } from '../../../../../command-shared/test/command'; import { createKommentarListResource, createKommentarResource } from '../../../../../kommentar-shared/test/kommentar'; import { getDataTestIdOf } from '../../../../../tech-shared/test/data-test'; @@ -47,8 +48,6 @@ describe('KommentarFormComponent', () => { let fixture: ComponentFixture<KommentarFormComponent>; const cancelButtonTestId: string = getDataTestIdOf('cancel-button'); - const fileUploadListTestId: string = getDataTestIdOf('kommentar-multi-file-upload-list'); - const fileUploadEditorTestId: string = getDataTestIdOf('kommentar-multi-file-upload-editor'); const kommentarListStateResource: StateResource<KommentarListResource> = createStateResource(createKommentarListResource()); @@ -67,8 +66,7 @@ describe('KommentarFormComponent', () => { MockComponent(TextAreaEditorComponent), MockComponent(OzgcloudStrokedButtonWithSpinnerComponent), MockComponent(BinaryFileAttachmentContainerComponent), - MockComponent(FileUploadListContainerComponent), - MockComponent(MultiFileUploadEditorComponent), + MockComponent(MultiFileUploadComponent), ], imports: [MatFormFieldModule, ReactiveFormsModule], providers: [ @@ -198,43 +196,6 @@ describe('KommentarFormComponent', () => { }); describe('template', () => { - describe('file upload list', () => { - it('should exists', () => { - existsAsHtmlElement(fixture, fileUploadListTestId); - }); - - it('should have inputs', () => { - fixture.detectChanges(); - - const fileUploadListComponent: FileUploadListContainerComponent = getElementComponentFromFixtureByCss( - fixture, - fileUploadListTestId, - ); - - expect(fileUploadListComponent.parentFormArrayName).toEqual(KommentarFormService.FIELD_ATTACHMENTS); - expect(fileUploadListComponent.fileUploadType).toEqual(KOMMENTAR_UPLOADED_ATTACHMENTS); - }); - }); - - describe('file upload editor', () => { - it('should exists', () => { - existsAsHtmlElement(fixture, fileUploadEditorTestId); - }); - - it('should have inputs', () => { - fixture.detectChanges(); - - const fileUploadEditorComponent: MultiFileUploadEditorComponent = getElementComponentFromFixtureByCss( - fixture, - fileUploadEditorTestId, - ); - - expect(fileUploadEditorComponent.fileUploadType).toEqual(KOMMENTAR_UPLOADED_ATTACHMENTS); - expect(fileUploadEditorComponent.uploadResource).toEqual(component.kommentarListStateResource.resource); - expect(fileUploadEditorComponent.uploadLinkRelation).toEqual(KommentarListLinkRel.UPLOAD_FILE); - }); - }); - describe('cancel button', () => { it('should exists', () => { existsAsHtmlElement(fixture, cancelButtonTestId); diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.html b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.html index 8b432f5eee5589efc42249c5bfdf3f64a631b818..30f142acca7a7374f7e11d554c238f72a235b1ae 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.html +++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.html @@ -27,6 +27,7 @@ <ozgcloud-expansion-panel headline="Kommentare"> <alfa-kommentar-list-in-vorgang [kommentarListStateResource]="kommentarListStateResource" + [currentlyEdited]="kommentarService.getCurrentlyEdited() | async" data-test-id="kommentar-list-in-vorgang" > </alfa-kommentar-list-in-vorgang> diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.spec.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.spec.ts index 44794b0072f9b661cd22120938e0a045e9b5d330..1fa11168673776f20130a7be5616abb0ac84380a 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.spec.ts +++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.spec.ts @@ -70,6 +70,14 @@ describe('KommentarListInVorgangContainerComponent', () => { expect(component).toBeTruthy(); }); + describe('ng on init', () => { + it('should call kommentar service isFormularVisible', () => { + component.ngOnInit(); + + expect(kommentarService.isFormularVisible).toHaveBeenCalled(); + }); + }); + describe('ng on changes', () => { beforeEach(() => { kommentarService.isFormularVisible.mockReturnValue(new Observable((o) => o.next(false))); @@ -78,12 +86,6 @@ describe('KommentarListInVorgangContainerComponent', () => { ); }); - it('should call kommentar service isFormularVisible', () => { - component.ngOnChanges(); - - expect(kommentarService.isFormularVisible).toHaveBeenCalled(); - }); - it('should call kommentar service getKommentareByVorgang', () => { component.ngOnChanges(); diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.ts index 8c601d9240a060ca4ceb9cd18a9b9964198eae83..21d3159a29496a6927f7076de4734ff03c663f44 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.ts +++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.ts @@ -21,10 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Input, OnChanges } from '@angular/core'; import { KommentarListResource, KommentarService } from '@alfa-client/kommentar-shared'; import { StateResource } from '@alfa-client/tech-shared'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { Component, inject, Input, OnChanges, OnInit } from '@angular/core'; import { mergeMap, Observable } from 'rxjs'; @Component({ @@ -32,25 +32,24 @@ import { mergeMap, Observable } from 'rxjs'; templateUrl: './kommentar-list-in-vorgang-container.component.html', styleUrls: ['./kommentar-list-in-vorgang-container.component.scss'], }) -export class KommentarListInVorgangContainerComponent implements OnChanges { +export class KommentarListInVorgangContainerComponent implements OnChanges, OnInit { @Input() vorgangStateResource: StateResource<VorgangWithEingangResource>; - showFormular$: Observable<boolean>; + public readonly kommentarService = inject(KommentarService); + + public showFormular$: Observable<boolean>; kommentarListStateResource$: Observable<StateResource<KommentarListResource>>; canCreateNewKommentar$: Observable<boolean>; - constructor(private kommentarService: KommentarService) {} + ngOnInit(): void { + this.showFormular$ = this.kommentarService.isFormularVisible(); + } ngOnChanges(): void { this.reloadKommentarListOnVorgangReload(); - this.showFormular$ = this.kommentarService.isFormularVisible(); - this.kommentarListStateResource$ = this.kommentarService.getKommentareByVorgang( - this.vorgangStateResource.resource, - ); + this.kommentarListStateResource$ = this.kommentarService.getKommentareByVorgang(this.vorgangStateResource.resource); this.canCreateNewKommentar$ = this.kommentarListStateResource$.pipe( - mergeMap((stateResource) => - this.kommentarService.canCreateNewKommentar(stateResource.resource), - ), + mergeMap((stateResource) => this.kommentarService.canCreateNewKommentar(stateResource.resource)), ); } diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component.html b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component.html index be3ecc3720ffb2e967b888e54243eb72a5234c11..75ccfb30068aad3b5d8e2847618a3267cb0fb400 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component.html +++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component.html @@ -27,5 +27,6 @@ *ngFor="let kommentar of kommentare" [kommentar]="kommentar" [kommentarListStateResource]="kommentarListStateResource" + [currentlyEdited]="currentlyEdited" > </alfa-kommentar-list-item-in-vorgang> diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component.ts index 4519d517cefe76995824afd7b45b8651ac354b8a..1d7212702a1b398d0da13637dc24e598d1f5bf8d 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component.ts +++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component.ts @@ -21,10 +21,11 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Input, OnChanges } from '@angular/core'; import { KommentarListResource, KommentarResource } from '@alfa-client/kommentar-shared'; -import { KommentarListLinkRel } from 'libs/kommentar-shared/src/lib/kommentar.linkrel'; import { getEmbeddedResources, StateResource } from '@alfa-client/tech-shared'; +import { Component, Input, OnChanges } from '@angular/core'; +import { ResourceUri } from '@ngxp/rest'; +import { KommentarListLinkRel } from 'libs/kommentar-shared/src/lib/kommentar.linkrel'; @Component({ selector: 'alfa-kommentar-list-in-vorgang', @@ -33,17 +34,15 @@ import { getEmbeddedResources, StateResource } from '@alfa-client/tech-shared'; }) export class KommentarListInVorgangComponent implements OnChanges { @Input() kommentarListStateResource: StateResource<KommentarListResource>; + @Input() currentlyEdited: ResourceUri; - kommentare: KommentarResource[]; + public kommentare: KommentarResource[]; ngOnChanges(): void { this.kommentare = this.getKommentare(); } getKommentare(): KommentarResource[] { - return getEmbeddedResources( - this.kommentarListStateResource, - KommentarListLinkRel.KOMMENTAR_LIST, - ); + return getEmbeddedResources(this.kommentarListStateResource, KommentarListLinkRel.KOMMENTAR_LIST); } } diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.spec.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.spec.ts index 127b7fda5dd6f18ac336393aa425dd3903e94ee7..c5a1d190d2f95214dd39f60e95119fbda5d9e9ba 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.spec.ts +++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.spec.ts @@ -21,26 +21,17 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { KommentarLinkRel, KommentarResource, KommentarService } from '@alfa-client/kommentar-shared'; +import { ConvertForDataTestPipe, FormatDateWithTimePipe, HasLinkPipe } from '@alfa-client/tech-shared'; +import { getElementFromFixture, mock } from '@alfa-client/test-utils'; +import { UserProfileInKommentarContainerComponent } from '@alfa-client/user-profile'; import { registerLocaleData } from '@angular/common'; import localeDe from '@angular/common/locales/de'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - KommentarLinkRel, - KommentarListLinkRel, - KommentarService, -} from '@alfa-client/kommentar-shared'; -import { - ConvertForDataTestPipe, - createStateResource, - FormatDateWithTimePipe, - HasLinkPipe, -} from '@alfa-client/tech-shared'; -import { getElementFromFixture, mock } from '@alfa-client/test-utils'; -import { UserProfileInKommentarContainerComponent } from '@alfa-client/user-profile'; -import { - createKommentarListResource, - createKommentarResource, -} from 'libs/kommentar-shared/test/kommentar'; +import { faker } from '@faker-js/faker/.'; +import { expect } from '@jest/globals'; +import { getUrl } from '@ngxp/rest'; +import { createKommentarResource } from 'libs/kommentar-shared/test/kommentar'; import { getDataTestClassOf } from 'libs/tech-shared/test/data-test'; import { MockComponent } from 'ng-mocks'; import { KommentarFormComponent } from '../../kommentar-form/kommentar-form.component'; @@ -85,6 +76,37 @@ describe('KommentarListItemInVorgangComponent', () => { expect(component).toBeTruthy(); }); + describe('set currently edited', () => { + const kommentar: KommentarResource = createKommentarResource(); + + it('should set edit mode to false on same currently edited resource uri', () => { + component.editMode = false; + component.kommentar = kommentar; + + component.currentlyEdited = getUrl(kommentar); + + expect(component.editMode).toBe(false); + }); + + it('should set edit mode to false on different currently edited resource uri', () => { + component.editMode = true; + component.kommentar = kommentar; + + component.currentlyEdited = faker.internet.url(); + + expect(component.editMode).toBe(false); + }); + + it('should set edit mode to true', () => { + component.editMode = true; + component.kommentar = kommentar; + + component.currentlyEdited = getUrl(kommentar); + + expect(component.editMode).toBe(true); + }); + }); + describe('user profile', () => { it('should be visible on existing link', () => { component.kommentar = createKommentarResource([KommentarLinkRel.CREATED_BY]); @@ -105,18 +127,9 @@ describe('KommentarListItemInVorgangComponent', () => { }); }); - describe('kommentare attachments', () => { - it('should be loaded', () => { - const kommentarResource = createKommentarResource(); - component.kommentar = kommentarResource; - - component.ngOnInit(); - - expect(kommentarService.getAttachments).toHaveBeenCalledWith(kommentarResource); - }); - }); - describe('edit', () => { + const kommentar: KommentarResource = createKommentarResource(); + it('should change editMode', () => { component.kommentar = createKommentarResource([KommentarLinkRel.EDIT]); @@ -125,12 +138,20 @@ describe('KommentarListItemInVorgangComponent', () => { expect(component.editMode).toBeTruthy(); }); - it('should not change editMode', () => { - component.kommentar = createKommentarResource(); + it('should NOT change editMode', () => { + component.kommentar = kommentar; component.edit(); expect(component.editMode).toBeFalsy(); }); + + it('should set currently edited kommetar uri', () => { + component.kommentar = kommentar; + + component.edit(); + + expect(kommentarService.setCurrentlyEdited).toHaveBeenCalledWith(getUrl(kommentar)); + }); }); }); diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.ts index cf6a951f4bd32c241281ce7c3207092387f92ce1..7da6b91741e10ca74fdb3a4572d43190481826d5 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.ts +++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.ts @@ -21,35 +21,32 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BinaryFileListResource } from '@alfa-client/binary-file-shared'; import { KommentarLinkRel, KommentarListResource, KommentarResource, KommentarService } from '@alfa-client/kommentar-shared'; -import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; -import { Component, Input, OnInit } from '@angular/core'; -import { hasLink } from '@ngxp/rest'; -import { Observable, of } from 'rxjs'; +import { StateResource } from '@alfa-client/tech-shared'; +import { Component, inject, Input } from '@angular/core'; +import { getUrl, hasLink, ResourceUri } from '@ngxp/rest'; @Component({ selector: 'alfa-kommentar-list-item-in-vorgang', templateUrl: './kommentar-list-item-in-vorgang.component.html', styleUrls: ['./kommentar-list-item-in-vorgang.component.scss'], }) -export class KommentarListItemInVorgangComponent implements OnInit { +export class KommentarListItemInVorgangComponent { @Input() kommentar: KommentarResource; - @Input() kommentarListStateResource: StateResource<KommentarListResource>; - attachments$: Observable<StateResource<BinaryFileListResource>> = of(createEmptyStateResource<BinaryFileListResource>()); - editMode: boolean = false; + @Input() set currentlyEdited(value: ResourceUri) { + this.editMode &&= value === getUrl(this.kommentar); + } - readonly kommentarLinkRel = KommentarLinkRel; + public kommentarService = inject(KommentarService); - constructor(public kommentarService: KommentarService) {} + public editMode: boolean = false; - ngOnInit(): void { - this.attachments$ = this.kommentarService.getAttachments(this.kommentar); - } + public readonly kommentarLinkRel = KommentarLinkRel; - edit(): void { + public edit(): void { this.editMode = hasLink(this.kommentar, KommentarLinkRel.EDIT); + this.kommentarService.setCurrentlyEdited(getUrl(this.kommentar)); } } diff --git a/alfa-client/libs/kommentar/src/lib/kommentar.module.ts b/alfa-client/libs/kommentar/src/lib/kommentar.module.ts index 3a8e4dd40a4a53552567b81b69fad3af2c230312..70d991da2a329dee09ccc3758fe80305d0347434 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar.module.ts +++ b/alfa-client/libs/kommentar/src/lib/kommentar.module.ts @@ -32,6 +32,7 @@ import { NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { FileUploadListContainerComponent } from '../../../binary-file/src/lib/file-upload-list-container/file-upload-list-container.component'; import { MultiFileUploadEditorComponent } from '../../../binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component'; +import { MultiFileUploadComponent } from '../../../binary-file/src/lib/multi-file-upload/multi-file-upload.component'; 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'; @@ -46,6 +47,7 @@ import { KommentarListItemInVorgangComponent } from './kommentar-list-in-vorgang BinaryFileModule, MultiFileUploadEditorComponent, FileUploadListContainerComponent, + MultiFileUploadComponent, ReactiveFormsModule, TextAreaEditorComponent, OzgcloudStrokedButtonWithSpinnerComponent, diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts index f26deaae319cf2f62a1dc3c0aebce901dff4709d..678219f735fd5882a763a535687688c630bd5045 100644 --- a/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts +++ b/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts @@ -21,40 +21,21 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - BinaryFileListResource, - BinaryFileResource, - BinaryFileService, -} from '@alfa-client/binary-file-shared'; +import { BinaryFileService } from '@alfa-client/binary-file-shared'; import { CommandResource, CommandService } from '@alfa-client/command-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { - StateResource, - createEmptyStateResource, - createStateResource, -} from '@alfa-client/tech-shared'; -import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; +import { createEmptyStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared'; +import { Mock, mock } from '@alfa-client/test-utils'; import { SnackBarService } from '@alfa-client/ui'; import { VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { TestBed } from '@angular/core/testing'; import { MatDialog } from '@angular/material/dialog'; -import { - createBinaryFileListResource, - createBinaryFileResource, -} from 'libs/binary-file-shared/test/binary-file'; +import { expect } from '@jest/globals'; import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel'; -import { - createCommandErrorResource, - createCommandResource, -} from 'libs/command-shared/test/command'; +import { createCommandErrorResource, createCommandResource } from 'libs/command-shared/test/command'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; import { BehaviorSubject, of } from 'rxjs'; -import { - createPostfachFeatures, - createPostfachMail, - createPostfachMailListResource, - createPostfachMailResource, - createPostfachSettings, -} from '../../test/postfach'; +import { createPostfachFeatures, createPostfachMail, createPostfachMailListResource, createPostfachMailResource, createPostfachSettings, } from '../../test/postfach'; import { PostfachFacade } from './+state/postfach.facade'; import { PostfachMailLinkRel, PostfachMailListLinkRel } from './postfach.linkrel'; import { PostfachMessages } from './postfach.message'; @@ -72,8 +53,8 @@ describe('PostfachService', () => { const vorgangService: Mock<VorgangService> = mock(VorgangService); const snackbarService: Mock<SnackBarService> = mock(SnackBarService); const dialog: Mock<MatDialog> = <Mock<MatDialog>>{ closeAll: jest.fn() }; - const binaryFileService: Mock<BinaryFileService> = mock(BinaryFileService); const postfachFacade: Mock<PostfachFacade> = mock(PostfachFacade); + const binaryFileService: Mock<BinaryFileService> = mock(BinaryFileService); const urlChangedParams = {}; @@ -83,16 +64,21 @@ describe('PostfachService', () => { repository = mock(PostfachRepository); - service = new PostfachService( - useFromMock(repository), - useFromMock(commandService), - useFromMock(navigationService), - useFromMock(vorgangService), - useFromMock(snackbarService), - useFromMock(dialog), - useFromMock(binaryFileService), - useFromMock(postfachFacade), - ); + TestBed.configureTestingModule({ + providers: [ + { provide: CommandService, useValue: commandService }, + { provide: NavigationService, useValue: navigationService }, + { provide: VorgangService, useValue: vorgangService }, + { provide: SnackBarService, useValue: snackbarService }, + { provide: MatDialog, useValue: dialog }, + { provide: PostfachFacade, useValue: postfachFacade }, + { provide: BinaryFileService, useValue: binaryFileService }, + { provide: PostfachRepository, useValue: repository }, + PostfachService, + ], + }); + + service = TestBed.inject(PostfachService); }); it('should be created', () => { @@ -101,8 +87,7 @@ describe('PostfachService', () => { describe('send message', () => { const postfachMail: PostfachMail = createPostfachMail(); - const commandStateResource: StateResource<CommandResource> = - createStateResource(createCommandResource()); + const commandStateResource: StateResource<CommandResource> = createStateResource(createCommandResource()); beforeEach(() => { commandService.createCommand.mockReturnValue(of(commandStateResource)); @@ -144,9 +129,7 @@ describe('PostfachService', () => { }); it('should not execute on pending command', () => { - commandService.createCommand.mockReturnValue( - of(createStateResource(createCommandResource([CommandLinkRel.UPDATE]))), - ); + commandService.createCommand.mockReturnValue(of(createStateResource(createCommandResource([CommandLinkRel.UPDATE])))); service.sendMail(postfachMail); @@ -159,8 +142,7 @@ describe('PostfachService', () => { const postfachNachricht: PostfachMailResource = createPostfachMailResource(); const nachricht: PostfachMail = createPostfachMail(); - const commandStateResource: StateResource<CommandResource> = - createStateResource(createCommandResource()); + const commandStateResource: StateResource<CommandResource> = createStateResource(createCommandResource()); it('should call doSendNachricht', () => { service.doSendNachricht = jest.fn(); @@ -183,12 +165,8 @@ describe('PostfachService', () => { beforeEach(() => { service.handleSendPostfachMailIsDone = jest.fn(); - commandService.createCommand.mockReturnValue( - of(createStateResource(createCommandResource())), - ); - vorgangService.getPendingSendPostfachMailCommand.mockReturnValue( - of(createStateResource(createCommandResource())), - ); + commandService.createCommand.mockReturnValue(of(createStateResource(createCommandResource()))); + vorgangService.getPendingSendPostfachMailCommand.mockReturnValue(of(createStateResource(createCommandResource()))); }); it('should call vorgang service and set command on loading', () => { @@ -210,9 +188,7 @@ describe('PostfachService', () => { }); it('should NOT call handleSendPostfachMailIsDone if command is pending', () => { - commandService.createCommand.mockReturnValue( - of(createStateResource(createCommandResource([CommandLinkRel.UPDATE]))), - ); + commandService.createCommand.mockReturnValue(of(createStateResource(createCommandResource([CommandLinkRel.UPDATE])))); service.resendMail(postfachMailResource); expect(service.handleSendPostfachMailIsDone).not.toHaveBeenCalled(); @@ -231,8 +207,7 @@ describe('PostfachService', () => { }); describe('handleSendNachrichtCommand', () => { - const commandStateResource: StateResource<CommandResource> = - createStateResource(createCommandResource()); + const commandStateResource: StateResource<CommandResource> = createStateResource(createCommandResource()); beforeEach(() => { service.commandIsDone = jest.fn(); @@ -241,9 +216,7 @@ describe('PostfachService', () => { it('should call vorgang service', () => { service.handleSendNachrichtCommand(commandStateResource); - expect(vorgangService.setPendingSendPostfachMailCommand).toHaveBeenCalledWith( - commandStateResource, - ); + expect(vorgangService.setPendingSendPostfachMailCommand).toHaveBeenCalledWith(commandStateResource); }); it('should call commandIsDone', () => { @@ -277,10 +250,7 @@ describe('PostfachService', () => { service.commandIsDone(commandStateResource); - expect(snackbarService.show).toHaveBeenCalledWith( - commandStateResource.resource, - PostfachMessages.SEND_SUCCESSFUL, - ); + expect(snackbarService.show).toHaveBeenCalledWith(commandStateResource.resource, PostfachMessages.SEND_SUCCESSFUL); }); }); @@ -392,9 +362,7 @@ describe('PostfachService', () => { service.pollSendPostfachMailCommand = jest.fn(); commandService.pollCommand.mockReturnValue(of(createStateResource(createCommandResource()))); - vorgangService.getPendingSendPostfachMailCommand.mockReturnValue( - of(createStateResource(createCommandResource())), - ); + vorgangService.getPendingSendPostfachMailCommand.mockReturnValue(of(createStateResource(createCommandResource()))); }); it('should call navigation service', () => { @@ -405,15 +373,12 @@ describe('PostfachService', () => { }); describe('resetHasNewPostfachNachrichten', () => { - const postfachListNachrichtenResource: PostfachMailListResource = - createPostfachMailListResource(); + const postfachListNachrichtenResource: PostfachMailListResource = createPostfachMailListResource(); it('should call doResetHasNewPostfachNachrichten', () => { service.getPostfachMailListByVorgang = jest.fn(); service.doResetHasNewPostfachNachrichten = jest.fn(); - (<any>service.getPostfachMailListByVorgang).mockReturnValue( - of(postfachListNachrichtenResource), - ); + (<any>service.getPostfachMailListByVorgang).mockReturnValue(of(postfachListNachrichtenResource)); service.resetHasNewPostfachNachrichten(); @@ -423,28 +388,24 @@ describe('PostfachService', () => { describe('doResetHasNewPostfachNachrichten', () => { describe('on existing link', () => { - const postfachNachrichtenListResource: PostfachMailListResource = - createPostfachMailListResource([PostfachMailListLinkRel.RESET_HAS_NEW_POSTFACH_NACHRICHT]); + const postfachNachrichtenListResource: PostfachMailListResource = createPostfachMailListResource([ + PostfachMailListLinkRel.RESET_HAS_NEW_POSTFACH_NACHRICHT, + ]); beforeEach(() => { service.postfachMailList$.next(createStateResource(postfachNachrichtenListResource)); - repository.resetHasNewPostfachNachrichten.mockReturnValue( - of(postfachNachrichtenListResource), - ); + repository.resetHasNewPostfachNachrichten.mockReturnValue(of(postfachNachrichtenListResource)); }); it('should call repository if link exists', () => { service.doResetHasNewPostfachNachrichten(); - expect(repository.resetHasNewPostfachNachrichten).toHaveBeenCalledWith( - postfachNachrichtenListResource, - ); + expect(repository.resetHasNewPostfachNachrichten).toHaveBeenCalledWith(postfachNachrichtenListResource); }); }); it('should NOT call repository if link not exists', () => { - const postfachNachrichtenListResource: PostfachMailListResource = - createPostfachMailListResource(); + const postfachNachrichtenListResource: PostfachMailListResource = createPostfachMailListResource(); service.postfachMailList$.next(createStateResource(postfachNachrichtenListResource)); service.doResetHasNewPostfachNachrichten(); @@ -460,9 +421,7 @@ describe('PostfachService', () => { repository.loadPostfachMailList.mockReturnValue(of(postfachMailList)); service.setPostfachMailListLoading = jest.fn(); service.setPostfachMailList = jest.fn(); - vorgangService.getVorgangWithEingang.mockReturnValue( - of(createStateResource(createVorgangWithEingangResource())), - ); + vorgangService.getVorgangWithEingang.mockReturnValue(of(createStateResource(createVorgangWithEingangResource()))); service.postfachMailList$.next(createEmptyStateResource()); }); @@ -492,8 +451,7 @@ describe('PostfachService', () => { }); describe('handleSendPostfachMailIsDone', () => { - const stateResource: StateResource<CommandResource> = - createStateResource(createCommandResource()); + const stateResource: StateResource<CommandResource> = createStateResource(createCommandResource()); beforeEach(() => { service.setPollingFalse = jest.fn(); @@ -521,26 +479,6 @@ describe('PostfachService', () => { }); }); - describe('loadAttachments', () => { - const postfachNachricht: PostfachMailResource = createPostfachMailResource(); - const fileListStateResource: StateResource<BinaryFileListResource> = createStateResource( - createBinaryFileListResource(), - ); - - beforeEach(() => { - binaryFileService.getFiles.mockReturnValue(of(fileListStateResource)); - }); - - it('should call binaryFile service with resource', () => { - service.loadAttachments(postfachNachricht); - - expect(binaryFileService.getFiles).toHaveBeenCalledWith( - postfachNachricht, - PostfachMailLinkRel.ATTACHMENTS, - ); - }); - }); - describe('isDownloadPdfInProgress', () => { const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource(); @@ -582,54 +520,9 @@ describe('PostfachService', () => { }); }); - describe('getAttachments', () => { - const postfachNachricht: PostfachMailResource = createPostfachMailResource(); - const binaryFileResource: BinaryFileResource = createBinaryFileResource(); - const BinaryFileListResource: BinaryFileListResource = createBinaryFileListResource([ - binaryFileResource, - ]); - - beforeEach(() => { - postfachFacade.getAttachmentList.mockReturnValue( - of(createStateResource(BinaryFileListResource)), - ); - }); - - it('should get attachments', () => { - service.getAttachments(postfachNachricht); - - expect(postfachFacade.getAttachmentList).toHaveBeenCalled(); - }); - - it('should load attachments if loading is required', () => { - postfachFacade.getAttachmentList.mockReturnValue(of(createEmptyStateResource())); - - service.getAttachments(postfachNachricht).subscribe(); - - expect(postfachFacade.loadAttachmentList).toHaveBeenCalledWith(postfachNachricht); - }); - - it('should return value', (done) => { - service.getAttachments(postfachNachricht).subscribe((attachments: BinaryFileResource[]) => { - expect(attachments).toEqual([binaryFileResource]); - done(); - }); - }); - }); - - describe('clearAttachmentList', () => { - it('should call facade', () => { - service.clearAttachmentList(); - - expect(postfachFacade.clearAttachmentList).toHaveBeenCalled(); - }); - }); - describe('getFeatures', () => { it('should return features by list stateResource', (done) => { - service.postfachMailList$ = new BehaviorSubject( - createStateResource(createPostfachMailListResource()), - ); + service.postfachMailList$ = new BehaviorSubject(createStateResource(createPostfachMailListResource())); service.getFeatures().subscribe((features) => { expect(features).toEqual(createPostfachFeatures()); @@ -640,9 +533,7 @@ describe('PostfachService', () => { describe('getSettings', () => { it('should return settings by list stateResource', (done) => { - service.postfachMailList$ = new BehaviorSubject( - createStateResource(createPostfachMailListResource()), - ); + service.postfachMailList$ = new BehaviorSubject(createStateResource(createPostfachMailListResource())); service.getSettings().subscribe((settings) => { expect(settings).toEqual(createPostfachSettings()); @@ -650,4 +541,16 @@ describe('PostfachService', () => { }); }); }); + + describe('close open dialogs', () => { + beforeEach(() => { + service.clearUploadedFiles = jest.fn(); + }); + + it('should clear uploaded files', () => { + service.closeOpenDialogs(); + + expect(service.clearUploadedFiles).toHaveBeenCalled(); + }); + }); }); diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts index 189ab9a2059f0941773bc7754a8929799889bf30..e39019766d5f873a246643dec3c951cc4e2efd39 100644 --- a/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts +++ b/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts @@ -21,55 +21,38 @@ * 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 { - CommandResource, - CommandService, - doIfCommandIsDone, - hasCommandError, - isDone, - isPending, -} from '@alfa-client/command-shared'; +import { POSTFACH_NACHRICHT_UPLOADED_ATTACHMENTS } from '@admin-client/postfach-shared'; +import { BinaryFileService } from '@alfa-client/binary-file-shared'; +import { CommandResource, CommandService, doIfCommandIsDone, hasCommandError, isDone, isPending, } from '@alfa-client/command-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { - StateResource, - createEmptyStateResource, - createStateResource, - doIfLoadingRequired, - getEmbeddedResources, - isNotNull, - isNotUndefined, -} from '@alfa-client/tech-shared'; +import { createEmptyStateResource, createStateResource, doIfLoadingRequired, isNotNull, isNotUndefined, StateResource, } from '@alfa-client/tech-shared'; import { SnackBarService } from '@alfa-client/ui'; import { VorgangResource, VorgangService } from '@alfa-client/vorgang-shared'; -import { Injectable } from '@angular/core'; +import { inject, Injectable } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Params } from '@angular/router'; -import { Resource, hasLink } from '@ngxp/rest'; +import { hasLink, Resource } from '@ngxp/rest'; import { isNil, isNull } from 'lodash-es'; -import { BehaviorSubject, Observable, Subscription, combineLatest } from 'rxjs'; +import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; import { first, map, take, tap } from 'rxjs/operators'; import { PostfachFacade } from './+state/postfach.facade'; import { PostfachMailLinkRel, PostfachMailListLinkRel } from './postfach.linkrel'; import { PostfachMessages } from './postfach.message'; -import { - CreatePostfachMailCommand, - PostfachFeatures, - PostfachMail, - PostfachMailListResource, - PostfachMailResource, - PostfachSettings, -} from './postfach.model'; +import { CreatePostfachMailCommand, PostfachFeatures, PostfachMail, PostfachMailListResource, PostfachMailResource, PostfachSettings, } from './postfach.model'; import { PostfachRepository } from './postfach.repository'; import { createResendPostfachMailCommand, createSendPostfachMailCommand } from './postfach.util'; @Injectable({ providedIn: 'root' }) export class PostfachService { + private readonly repository = inject(PostfachRepository); + private readonly commandService = inject(CommandService); + private readonly navigationService = inject(NavigationService); + private readonly vorgangService = inject(VorgangService); + private readonly snackbarService = inject(SnackBarService); + private readonly dialog = inject(MatDialog); + private readonly postfachFacade = inject(PostfachFacade); + private readonly binaryFileService = inject(BinaryFileService); + private readonly isPollSendPostachMail: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); postfachMailList$: BehaviorSubject<StateResource<PostfachMailListResource>> = new BehaviorSubject< StateResource<PostfachMailListResource> @@ -82,16 +65,7 @@ export class PostfachService { private vorgangSubscription: Subscription; private postfachNachrichtenListSubscription: Subscription; - constructor( - private repository: PostfachRepository, - private commandService: CommandService, - private navigationService: NavigationService, - private vorgangService: VorgangService, - private snackbarService: SnackBarService, - private dialog: MatDialog, - private binaryFileService: BinaryFileService, - private postfachFacade: PostfachFacade, - ) { + constructor() { this.listenToNavigation(); } @@ -193,6 +167,7 @@ export class PostfachService { closeOpenDialogs(): void { this.dialog.closeAll(); + this.clearUploadedFiles(); } unsubscribe(): void { @@ -299,10 +274,6 @@ export class PostfachService { this.postfachMailList$.next(createStateResource(postfachMailList)); } - public loadAttachments(postfachNachricht: PostfachMailResource): Observable<StateResource<BinaryFileListResource>> { - return this.binaryFileService.getFiles(postfachNachricht, PostfachMailLinkRel.ATTACHMENTS); - } - public isDownloadPdfInProgress(): Observable<boolean> { return combineLatest([this.vorgangService.getVorgangWithEingang(), this.postfachFacade.isDownloadPdfInProgress()]).pipe( tap(([vorgang, isDownloadInProgress]) => { @@ -318,21 +289,6 @@ export class PostfachService { this.postfachFacade.startDownloadPdf(); } - public getAttachments(postfachNachricht: PostfachMailResource): Observable<BinaryFileResource[]> { - return this.postfachFacade.getAttachmentList().pipe( - tap((attachmentList) => - doIfLoadingRequired(attachmentList, () => this.postfachFacade.loadAttachmentList(postfachNachricht)), - ), - map((binaryFileListResource: StateResource<BinaryFileListResource>) => - getEmbeddedResources(binaryFileListResource, BinaryFileListLinkRel.FILE_LIST), - ), - ); - } - - public clearAttachmentList(): void { - this.postfachFacade.clearAttachmentList(); - } - public getFeatures(): Observable<PostfachFeatures> { return this.getPostfachMailListByVorgang().pipe( map((listStateResource: StateResource<PostfachMailListResource>) => listStateResource.resource.features), @@ -344,4 +300,8 @@ export class PostfachService { map((listStateResource: StateResource<PostfachMailListResource>) => listStateResource.resource.settings), ); } + + public clearUploadedFiles(): void { + this.binaryFileService.clearUploadedFiles(POSTFACH_NACHRICHT_UPLOADED_ATTACHMENTS); + } } diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-button-container/postfach-mail-button-container.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-button-container/postfach-mail-button-container.component.spec.ts index 7ac87155bd62df629b16f7b90a8485f833e7cea5..e520088dd7a78278b713934277034613dd2d9cff 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-button-container/postfach-mail-button-container.component.spec.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-button-container/postfach-mail-button-container.component.spec.ts @@ -22,23 +22,15 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { PostfachMailFormComponent } from '@alfa-client/postfach'; -import { - PostfachMailFormDialogData, - PostfachMailListResource, - PostfachService, -} from '@alfa-client/postfach-shared'; -import { - HasLinkPipe, - StateResource, - createErrorStateResource, - createStateResource, -} from '@alfa-client/tech-shared'; +import { PostfachMailFormDialogData, PostfachMailListResource, PostfachService } from '@alfa-client/postfach-shared'; +import { createErrorStateResource, createStateResource, HasLinkPipe, StateResource } from '@alfa-client/tech-shared'; import { mock } from '@alfa-client/test-utils'; import { DialogService } from '@alfa-client/ui'; import { VorgangHeaderLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { getEmpfaenger } from '@alfa-client/vorgang-shared-ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { faker } from '@faker-js/faker'; +import { expect } from '@jest/globals'; import { createCommandResource } from 'libs/command-shared/test/command'; import { createPostfachMailListResource } from 'libs/postfach-shared/test/postfach'; import { createApiError } from 'libs/tech-shared/test/error'; @@ -62,11 +54,7 @@ describe('PostfachMailButtonContainerComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - PostfachMailButtonContainerComponent, - HasLinkPipe, - MockComponent(PostfachMailButtonComponent), - ], + declarations: [PostfachMailButtonContainerComponent, HasLinkPipe, MockComponent(PostfachMailButtonComponent)], providers: [ { provide: DialogService, @@ -92,9 +80,7 @@ describe('PostfachMailButtonContainerComponent', () => { }); describe('vorgang changes', () => { - const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource([ - VorgangHeaderLinkRel.POSTFACH_MAILS, - ]); + const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource([VorgangHeaderLinkRel.POSTFACH_MAILS]); beforeEach(() => { component.loadPendingSendPostfachMailCommand = jest.fn(); @@ -117,9 +103,7 @@ describe('PostfachMailButtonContainerComponent', () => { describe('loadPendingSendPostfachMailCommand', () => { beforeEach(() => { component.closeDialog = jest.fn(); - postfachService.getPendingSendPostfachMailCommand.mockReturnValue( - of(createStateResource(createCommandResource())), - ); + postfachService.getPendingSendPostfachMailCommand.mockReturnValue(of(createStateResource(createCommandResource()))); }); it('should call postfach service', () => { @@ -136,9 +120,7 @@ describe('PostfachMailButtonContainerComponent', () => { }); describe('loadPostfachMailListStateResource', () => { - const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource([ - VorgangHeaderLinkRel.POSTFACH_MAILS, - ]); + const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource([VorgangHeaderLinkRel.POSTFACH_MAILS]); beforeEach(() => { postfachService.getPostfachMailListByGivenVorgang.mockReturnValue(of({})); @@ -157,11 +139,21 @@ describe('PostfachMailButtonContainerComponent', () => { const postfachMailListStateResource: StateResource<PostfachMailListResource> = createStateResource(createPostfachMailListResource()); + beforeEach(() => { + dialogService.openFixed.mockReturnValue({ afterClosed: jest.fn().mockReturnValue(of(null)) }); + }); + it('should open new dialog with given data', () => { component.openPostfachMailDialog(postfachMailListStateResource); expect(dialogService.openFixed).toHaveBeenCalled(); }); + + it('should clear upload files after dialog was closed', () => { + component.openPostfachMailDialog(postfachMailListStateResource); + + expect(postfachService.clearUploadedFiles).toHaveBeenCalled(); + }); }); describe('closeDialog', () => { @@ -197,9 +189,7 @@ describe('PostfachMailButtonContainerComponent', () => { const empfanger: string = faker.person.firstName(); getEmpfaengerMock.mockReturnValue(empfanger); - const dialogData: PostfachMailFormDialogData = component.buildDialogData( - postfachMailListStateResource, - ); + const dialogData: PostfachMailFormDialogData = component.buildDialogData(postfachMailListStateResource); expect(dialogData.empfaenger).toEqual(empfanger); }); @@ -211,9 +201,7 @@ describe('PostfachMailButtonContainerComponent', () => { }); it('should set title', () => { - const dialogData: PostfachMailFormDialogData = component.buildDialogData( - postfachMailListStateResource, - ); + const dialogData: PostfachMailFormDialogData = component.buildDialogData(postfachMailListStateResource); expect(dialogData.title).toEqual(PostfachMailButtonContainerComponent.TITLE); }); diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-button-container/postfach-mail-button-container.component.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-button-container/postfach-mail-button-container.component.ts index 8670a6d75fb62befcdc6d7a3e07c0ac2b677107f..5810ca247015c57bbed5ea36e94c45c05c287601 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-button-container/postfach-mail-button-container.component.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-button-container/postfach-mail-button-container.component.ts @@ -22,20 +22,15 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { CommandResource } from '@alfa-client/command-shared'; -import { - PostfachMailFormDialogData, - PostfachMailListLinkRel, - PostfachMailListResource, - PostfachService, -} from '@alfa-client/postfach-shared'; -import { StateResource, hasStateResourceError, isNotNull, isNotUndefined } from '@alfa-client/tech-shared'; +import { PostfachMailFormDialogData, PostfachMailListLinkRel, PostfachMailListResource, PostfachService, } from '@alfa-client/postfach-shared'; +import { hasStateResourceError, isNotNull, isNotUndefined, StateResource } from '@alfa-client/tech-shared'; import { DialogService, FixedDialogComponent } from '@alfa-client/ui'; import { VorgangHeaderLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { getEmpfaenger } from '@alfa-client/vorgang-shared-ui'; import { Component, Input } from '@angular/core'; import { MatDialogRef } from '@angular/material/dialog'; import { hasLink } from '@ngxp/rest'; -import { Observable } from 'rxjs'; +import { first, Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; import { PostfachMailFormComponent } from '../postfach-mail-form/postfach-mail-form.component'; @@ -51,6 +46,7 @@ export class PostfachMailButtonContainerComponent { public get vorgang(): VorgangWithEingangResource { return this._vorgang; } + @Input() public set vorgang(value: VorgangWithEingangResource) { this._vorgang = value; @@ -59,6 +55,7 @@ export class PostfachMailButtonContainerComponent { this.loadPendingSendPostfachMailCommand(); } } + @Input() showAsIconButton: boolean; @Input() text: string; @Input() toolTip: string; @@ -76,9 +73,7 @@ export class PostfachMailButtonContainerComponent { ) {} loadPostfachMailListStateResource(): void { - this.postfachMailListStateResource$ = this.postfachService.getPostfachMailListByGivenVorgang( - this.vorgang, - ); + this.postfachMailListStateResource$ = this.postfachService.getPostfachMailListByGivenVorgang(this.vorgang); } loadPendingSendPostfachMailCommand(): void { @@ -88,26 +83,20 @@ export class PostfachMailButtonContainerComponent { } closeDialog(commandStateResource: StateResource<CommandResource>): void { - if ( - !hasStateResourceError(commandStateResource) && - commandStateResource.loaded && - isNotUndefined(this.dialogRef) - ) { + if (!hasStateResourceError(commandStateResource) && commandStateResource.loaded && isNotUndefined(this.dialogRef)) { this.dialogService.closeAll(); } } - public openPostfachMailDialog( - postfachMailListStateResource: StateResource<PostfachMailListResource>, - ): void { - this.dialogRef = this.dialogService.openFixed( - this.buildDialogData(postfachMailListStateResource), - ); + public openPostfachMailDialog(postfachMailListStateResource: StateResource<PostfachMailListResource>): void { + this.dialogRef = this.dialogService.openFixed(this.buildDialogData(postfachMailListStateResource)); + this.dialogRef + .afterClosed() + .pipe(first()) + .subscribe(() => this.postfachService.clearUploadedFiles()); } - buildDialogData( - postfachMailListStateResource: StateResource<PostfachMailListResource>, - ): PostfachMailFormDialogData { + buildDialogData(postfachMailListStateResource: StateResource<PostfachMailListResource>): PostfachMailFormDialogData { return { component: PostfachMailFormComponent, title: PostfachMailButtonContainerComponent.TITLE, diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.html b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.html index 187cd25d070f87a75faa3b08db3ce643671ac439..56e1c490b8b2e01e5644eda045e3f210d56eb1de 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.html +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.html @@ -45,9 +45,14 @@ > </ozgcloud-textarea-editor> - <alfa-postfach-nachricht-attachment-container - [postfachNachricht]="dialogData.postfachNachricht" - ></alfa-postfach-nachricht-attachment-container> + <ods-multi-file-upload + [filesFormFieldName]="formServiceClass.FIELD_ATTACHMENTS" + [fileUploadType]="POSTFACH_NACHRICHT_UPLOADED_ATTACHMENTS" + [uploadResource]="dialogData.postfachMailListStateResource.resource" + [uploadLinkRelation]="PostfachMailListLinkRel.UPLOAD_ATTACHMENT" + [filesResource]="dialogData.postfachNachricht" + [filesLinkRelation]="PostfachMailLinkRel.ATTACHMENTS" + ></ods-multi-file-upload> <div class="button-bar-bottom space-between"> <ozgcloud-stroked-button-with-spinner 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 5b5beec8bf365ee4a043970eb471f592faeb4ed7..6eac1a58938ad4d04061bc0d05a29d00dcd61d7d 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 @@ -24,15 +24,7 @@ import { PostfachService } from '@alfa-client/postfach-shared'; import { createStateResource } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; -import { - DialogService, - FileUploadComponent, - IconButtonWithSpinnerComponent, - OzgcloudStrokedButtonWithSpinnerComponent, - OzgcloudTextEditorComponent, - SpinnerComponent, - TextAreaEditorComponent, -} from '@alfa-client/ui'; +import { DialogService, FileUploadComponent, IconButtonWithSpinnerComponent, OzgcloudStrokedButtonWithSpinnerComponent, OzgcloudTextEditorComponent, SpinnerComponent, TextAreaEditorComponent, } from '@alfa-client/ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; import { MAT_DIALOG_DATA } from '@angular/material/dialog'; @@ -40,14 +32,14 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { createCommandResource } from 'libs/command-shared/test/command'; -import { PostfachTestFactory, createPostfachSettings } from 'libs/postfach-shared/test/postfach'; +import { createPostfachSettings, PostfachTestFactory } from 'libs/postfach-shared/test/postfach'; import { MockComponent } from 'ng-mocks'; import { of } from 'rxjs'; import { PostfachMailFormComponent } from './postfach-mail-form.component'; import { PostfachMailFormservice } from './postfach-mail.formservice'; -import { PostfachNachrichtAttachmentContainerComponent } from './postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component'; import { PostfachNachrichtReplyEditorContainerComponent } from './postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component'; +import { MultiFileUploadComponent } from '../../../../binary-file/src/lib/multi-file-upload/multi-file-upload.component'; import * as CommandUtil from '../../../../command-shared/src/lib/command.util'; describe('PostfachMailFormComponent', () => { @@ -72,7 +64,7 @@ describe('PostfachMailFormComponent', () => { MockComponent(PostfachNachrichtReplyEditorContainerComponent), MockComponent(SpinnerComponent), MockComponent(FileUploadComponent), - MockComponent(PostfachNachrichtAttachmentContainerComponent), + MockComponent(MultiFileUploadComponent), ], imports: [MatFormFieldModule, MatInputModule, ReactiveFormsModule, BrowserAnimationsModule], providers: [ diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.ts index ca025479a0a9cecc88383647a3864487d9db8017..e5c1c3514301810c4a832ac3b16952bc5e22515f 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.ts @@ -21,16 +21,16 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { CommandResource } from '@alfa-client/command-shared'; -import { PostfachMailFormDialogData } from '@alfa-client/postfach-shared'; -import { StateResource, createEmptyStateResource, isNotNil } from '@alfa-client/tech-shared'; +import { CommandResource, isSuccessfulDone } from '@alfa-client/command-shared'; +import { PostfachMailFormDialogData, PostfachMailLinkRel, PostfachMailListLinkRel } from '@alfa-client/postfach-shared'; +import { createEmptyStateResource, isNotNil, StateResource } from '@alfa-client/tech-shared'; import { DialogService } from '@alfa-client/ui'; import { Component, Inject, OnInit } from '@angular/core'; import { MAT_DIALOG_DATA } from '@angular/material/dialog'; import { Observable, of, tap } from 'rxjs'; import { PostfachMailFormservice } from './postfach-mail.formservice'; -import * as CommandUtil from '../../../../command-shared/src/lib/command.util'; +import { POSTFACH_NACHRICHT_UPLOADED_ATTACHMENTS } from '@admin-client/postfach-shared'; @Component({ selector: 'alfa-postfach-mail-form', @@ -41,9 +41,11 @@ import * as CommandUtil from '../../../../command-shared/src/lib/command.util'; export class PostfachMailFormComponent implements OnInit { public readonly formServiceClass = PostfachMailFormservice; - public sendInProgress$: Observable<StateResource<CommandResource>> = of( - createEmptyStateResource<CommandResource>(), - ); + public sendInProgress$: Observable<StateResource<CommandResource>> = of(createEmptyStateResource<CommandResource>()); + + public readonly PostfachMailListLinkRel = PostfachMailListLinkRel; + public readonly PostfachMailLinkRel = PostfachMailLinkRel; + public readonly POSTFACH_NACHRICHT_UPLOADED_ATTACHMENTS = POSTFACH_NACHRICHT_UPLOADED_ATTACHMENTS; constructor( private dialogService: DialogService, @@ -65,14 +67,12 @@ export class PostfachMailFormComponent implements OnInit { this.sendInProgress$ = this.formService .submit() .pipe( - tap((commandStateResource: StateResource<CommandResource>) => - this.closeDialogsOnSuccessfulSubmit(commandStateResource), - ), + tap((commandStateResource: StateResource<CommandResource>) => this.closeDialogsOnSuccessfulSubmit(commandStateResource)), ); } closeDialogsOnSuccessfulSubmit(commandStateResource: StateResource<CommandResource>): void { - if (CommandUtil.isSuccessfulDone(commandStateResource.resource)) { + if (isSuccessfulDone(commandStateResource.resource)) { this.dialogService.closeAll(); } } diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.html b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.html deleted file mode 100644 index c907494c101d39d7b8e9e7cf6adf26eaced8363b..0000000000000000000000000000000000000000 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.html +++ /dev/null @@ -1,32 +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. - ---> -<alfa-binary-file-attachment-container - [formArrayName]="formServiceClass.FIELD_ATTACHMENTS" - [existFiles]="attachments$ | async" - [uploadStateResource]="postfachNachrichtListStateResource$ | async" - [linkRelUploadAttachment]="postfachMailListLinkRel.UPLOAD_ATTACHMENT" -> -</alfa-binary-file-attachment-container> diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.scss b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.scss deleted file mode 100644 index 54c4f3eb8c92af93694c03cdf577fed23cf9f86b..0000000000000000000000000000000000000000 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.scss +++ /dev/null @@ -1,23 +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. - */ diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.spec.ts deleted file mode 100644 index 61948618124f3cb14813d3ba6a1cf365345e1d78..0000000000000000000000000000000000000000 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.spec.ts +++ /dev/null @@ -1,150 +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 { ComponentFixture, TestBed } from '@angular/core/testing'; -import { BinaryFileAttachmentContainerComponent } from '@alfa-client/binary-file'; -import { BinaryFileResource } from '@alfa-client/binary-file-shared'; -import { - PostfachMailListLinkRel, - PostfachMailListResource, - PostfachService, -} from '@alfa-client/postfach-shared'; -import { StateResource, createStateResource } from '@alfa-client/tech-shared'; -import { Mock, getMockComponent, mock } from '@alfa-client/test-utils'; -import { createBinaryFileResource } from 'libs/binary-file-shared/test/binary-file'; -import { - PostfachTestFactory, - createPostfachMailListResource, -} from 'libs/postfach-shared/test/postfach'; -import { MockComponent } from 'ng-mocks'; -import { of } from 'rxjs'; -import { PostfachMailFormservice } from '../postfach-mail.formservice'; -import { PostfachNachrichtAttachmentContainerComponent } from './postfach-nachricht-attachment-container.component'; - -describe('PostfachNachrichtAttachmentContainerComponent', () => { - let component: PostfachNachrichtAttachmentContainerComponent; - let fixture: ComponentFixture<PostfachNachrichtAttachmentContainerComponent>; - - const service: Mock<PostfachService> = mock(PostfachService); - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - PostfachNachrichtAttachmentContainerComponent, - MockComponent(BinaryFileAttachmentContainerComponent), - ], - providers: [ - { - provide: PostfachService, - useValue: service, - }, - ], - }).compileComponents(); - - fixture = TestBed.createComponent(PostfachNachrichtAttachmentContainerComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('ngOnInit', () => { - beforeEach(() => { - component.initAttachments = jest.fn(); - }); - - it('should get list stateResource', () => { - component.ngOnInit(); - - expect(service.getPostfachMailListByVorgang).toHaveBeenCalled(); - }); - - it('should initAttachments on existing postfachNachricht', () => { - component.postfachNachricht = PostfachTestFactory.POSTFACH_NACHRICHT_RESOURCE; - - component.ngOnInit(); - - expect(component.initAttachments).toHaveBeenCalled(); - }); - - it('should not init attachments on missing postfachNachricht', () => { - component.postfachNachricht = undefined; - - component.ngOnInit(); - - expect(component.initAttachments).not.toHaveBeenCalled(); - }); - }); - - describe('binary file attachment container', () => { - it('should be called with formArrayName', () => { - const binaryFileAttachmentContainer: BinaryFileAttachmentContainerComponent = - getMockComponent(fixture, BinaryFileAttachmentContainerComponent); - expect(binaryFileAttachmentContainer.formArrayName).toBe( - PostfachMailFormservice.FIELD_ATTACHMENTS, - ); - }); - - it('should be called with existFiles', () => { - const attachments: BinaryFileResource[] = [createBinaryFileResource()]; - component.attachments$ = of(attachments); - - fixture.detectChanges(); - - const binaryFileAttachmentContainer: BinaryFileAttachmentContainerComponent = - getMockComponent(fixture, BinaryFileAttachmentContainerComponent); - expect(binaryFileAttachmentContainer.existFiles).toBe(attachments); - }); - - it('should be called with upload stateResource', () => { - const listStateResource: StateResource<PostfachMailListResource> = createStateResource( - createPostfachMailListResource(), - ); - component.postfachNachrichtListStateResource$ = of(listStateResource); - - fixture.detectChanges(); - - const binaryFileAttachmentContainer: BinaryFileAttachmentContainerComponent = - getMockComponent(fixture, BinaryFileAttachmentContainerComponent); - expect(binaryFileAttachmentContainer.uploadStateResource).toBe(listStateResource); - }); - - it('should be called with linkRel upload attachment', () => { - const binaryFileAttachmentContainer: BinaryFileAttachmentContainerComponent = - getMockComponent(fixture, BinaryFileAttachmentContainerComponent); - expect(binaryFileAttachmentContainer.linkRelUploadAttachment).toBe( - PostfachMailListLinkRel.UPLOAD_ATTACHMENT, - ); - }); - }); - - describe('ngOnDestroy', () => { - it('should clear attachments', () => { - component.ngOnDestroy(); - - expect(service.clearAttachmentList).toHaveBeenCalled(); - }); - }); -}); diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.ts deleted file mode 100644 index 0d3b7339b30a9ca15d03d791d60db92e7e42299b..0000000000000000000000000000000000000000 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.ts +++ /dev/null @@ -1,72 +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 { BinaryFileResource } from '@alfa-client/binary-file-shared'; -import { - PostfachMailLinkRel, - PostfachMailListLinkRel, - PostfachMailListResource, - PostfachMailResource, - PostfachService, -} from '@alfa-client/postfach-shared'; -import { FormProvider, StateResource, isNotNil } from '@alfa-client/tech-shared'; -import { Component, Input, OnDestroy } from '@angular/core'; -import { hasLink } from '@ngxp/rest'; -import { Observable, of } from 'rxjs'; -import { PostfachMailFormservice } from '../postfach-mail.formservice'; - -@Component({ - selector: 'alfa-postfach-nachricht-attachment-container', - templateUrl: './postfach-nachricht-attachment-container.component.html', - styleUrls: ['./postfach-nachricht-attachment-container.component.scss'], - viewProviders: [FormProvider], -}) -export class PostfachNachrichtAttachmentContainerComponent implements OnDestroy { - @Input() postfachNachricht: PostfachMailResource; - - postfachNachrichtListStateResource$: Observable<StateResource<PostfachMailListResource>>; - attachments$: Observable<BinaryFileResource[]> = of<BinaryFileResource[]>([]); - - public readonly postfachMailListLinkRel = PostfachMailListLinkRel; - public readonly formServiceClass = PostfachMailFormservice; - - constructor(private postfachService: PostfachService) {} - - ngOnInit(): void { - this.postfachNachrichtListStateResource$ = this.postfachService.getPostfachMailListByVorgang(); - - if (isNotNil(this.postfachNachricht)) { - this.initAttachments(); - } - } - - initAttachments(): void { - if (hasLink(this.postfachNachricht, PostfachMailLinkRel.ATTACHMENTS)) { - this.attachments$ = this.postfachService.getAttachments(this.postfachNachricht); - } - } - - ngOnDestroy(): void { - this.postfachService.clearAttachmentList(); - } -} diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-attachments/postfach-mail-attachments.component.html b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-attachments/postfach-mail-attachments.component.html deleted file mode 100644 index 0c91966fbcdcafe6c47f4d31cfd9557b6fbdf7d3..0000000000000000000000000000000000000000 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-attachments/postfach-mail-attachments.component.html +++ /dev/null @@ -1,27 +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. - ---> -<alfa-vertical-binary-file-list [binaryFileListStateResource]="attachments$ | async"> -</alfa-vertical-binary-file-list> diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-attachments/postfach-mail-attachments.component.scss b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-attachments/postfach-mail-attachments.component.scss deleted file mode 100644 index 87ec96c5bc70794e99e27966a5de96750909f80d..0000000000000000000000000000000000000000 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-attachments/postfach-mail-attachments.component.scss +++ /dev/null @@ -1,31 +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. - */ -.files { - display: flex; - flex-wrap: wrap; - margin: 4px -4px; - flex-direction: row; - max-width: 100%; - align-items: flex-start; -} diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-attachments/postfach-mail-attachments.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-attachments/postfach-mail-attachments.component.spec.ts deleted file mode 100644 index 8556f6a6ce7f3b8b95a34ec9a387e04817c367b1..0000000000000000000000000000000000000000 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-attachments/postfach-mail-attachments.component.spec.ts +++ /dev/null @@ -1,90 +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 { registerLocaleData } from '@angular/common'; -import localeDe from '@angular/common/locales/de'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { BinaryFileListResource } from '@alfa-client/binary-file-shared'; -import { PostfachMailResource, PostfachService } from '@alfa-client/postfach-shared'; -import { ConvertForDataTestPipe, createStateResource } from '@alfa-client/tech-shared'; -import { Mock, mock } from '@alfa-client/test-utils'; -import { SpinnerComponent } from '@alfa-client/ui'; -import { createBinaryFileListResource } from 'libs/binary-file-shared/test/binary-file'; -import { createPostfachMailResource } from 'libs/postfach-shared/test/postfach'; -import { MockComponent } from 'ng-mocks'; -import { of } from 'rxjs'; -import { PostfachMailAttachmentsComponent } from './postfach-mail-attachments.component'; -import { VerticalBinaryFileListComponent } from '@alfa-client/binary-file'; - -registerLocaleData(localeDe); - -describe('PostfachMailAttachmentsComponent', () => { - let component: PostfachMailAttachmentsComponent; - let fixture: ComponentFixture<PostfachMailAttachmentsComponent>; - - const postfachNachricht: PostfachMailResource = createPostfachMailResource(); - - const postfachService: Mock<PostfachService> = mock(PostfachService); - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - PostfachMailAttachmentsComponent, - ConvertForDataTestPipe, - MockComponent(VerticalBinaryFileListComponent), - MockComponent(SpinnerComponent), - ], - providers: [ - { - provide: PostfachService, - useValue: postfachService, - }, - ], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PostfachMailAttachmentsComponent); - component = fixture.componentInstance; - component.postfachNachricht = postfachNachricht; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('ngOnChanges', () => { - const attachmentList: BinaryFileListResource = createBinaryFileListResource(); - - beforeEach(() => { - postfachService.loadAttachments.mockReturnValue(of(createStateResource(attachmentList))); - }); - - it('should call service', () => { - component.ngOnChanges(); - - expect(postfachService.loadAttachments).toHaveBeenCalledWith(postfachNachricht); - }); - }); -}); diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-attachments/postfach-mail-attachments.component.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-attachments/postfach-mail-attachments.component.ts deleted file mode 100644 index b88457f2c228477973d769cbfa164f7da8f09b31..0000000000000000000000000000000000000000 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-attachments/postfach-mail-attachments.component.ts +++ /dev/null @@ -1,47 +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 { Component, Input, OnChanges } from '@angular/core'; -import { BinaryFileListResource } from '@alfa-client/binary-file-shared'; -import { PostfachMailResource, PostfachService } from '@alfa-client/postfach-shared'; -import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; -import { Observable, of } from 'rxjs'; - -@Component({ - selector: 'alfa-postfach-mail-attachments', - templateUrl: './postfach-mail-attachments.component.html', - styleUrls: ['./postfach-mail-attachments.component.scss'], -}) -export class PostfachMailAttachmentsComponent implements OnChanges { - @Input() postfachNachricht: PostfachMailResource; - - attachments$: Observable<StateResource<BinaryFileListResource>> = of( - createEmptyStateResource<BinaryFileListResource>(), - ); - - constructor(private postfachService: PostfachService) {} - - ngOnChanges(): void { - this.attachments$ = this.postfachService.loadAttachments(this.postfachNachricht); - } -} diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component.html b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component.html index b87d049868c0c54e15b1e20eb351dca3c483ad98..b9a11494ce9e63d735f2829904d138b8670a1eb3 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component.html +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component.html @@ -37,9 +37,11 @@ > </alfa-outgoing-mail> -<alfa-postfach-mail-attachments - *ngIf="(postfachMail | hasLink: postfachNachrichtLinkRel.ATTACHMENTS) && onPage" - data-test-id="postfach-mail-attachments-container" - [postfachNachricht]="postfachMail" -> -</alfa-postfach-mail-attachments> + +@if((postfachMail | hasLink: postfachNachrichtLinkRel.ATTACHMENTS) && onPage){ +<alfa-binary-file-list-container + [resource]="postfachMail" + [linkRel]="PostfachMailLinkRel.ATTACHMENTS" + [listOrientation]="BinaryFileListOrientation.VERTICAL" + data-test-id="postfach-mail-attachments-container"></alfa-binary-file-list-container> +} diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component.spec.ts index 02fedf3b44d53fe51c05ef688c6f638b831ced6c..24c3fe590a36fde09fb1acb5b0a5fa1bf214982f 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component.spec.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component.spec.ts @@ -21,27 +21,18 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - Direction, - ON_PAGE, - PostfachMailLinkRel, - PostfachMailResource, -} from '@alfa-client/postfach-shared'; -import { HasLinkPipe, StateResource, createStateResource } from '@alfa-client/tech-shared'; -import { - existsAsHtmlElement, - getMockComponent, - notExistsAsHtmlElement, -} from '@alfa-client/test-utils'; +import { BinaryFileListContainerComponent } from '@alfa-client/binary-file'; +import { Direction, ON_PAGE, PostfachMailLinkRel, PostfachMailResource } from '@alfa-client/postfach-shared'; +import { createStateResource, HasLinkPipe, StateResource } from '@alfa-client/tech-shared'; +import { existsAsHtmlElement, getMockComponent, notExistsAsHtmlElement } from '@alfa-client/test-utils'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { createPostfachMailResource } from 'libs/postfach-shared/test/postfach'; import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; import { MockComponent } from 'ng-mocks'; import { IncommingMailComponent } from './incomming-mail/incomming-mail.component'; import { OutgoingMailComponent } from './outgoing-mail/outgoing-mail.component'; -import { PostfachMailAttachmentsComponent } from './postfach-mail-attachments/postfach-mail-attachments.component'; import { PostfachMailComponent } from './postfach-mail.component'; describe('PostfachMailComponent', () => { @@ -50,9 +41,7 @@ describe('PostfachMailComponent', () => { const postfachIncomingNachricht: string = getDataTestIdOf('postfach-incoming-nachricht'); const postfachOutgoingNachricht: string = getDataTestIdOf('postfach-outgoing-nachricht'); - const postfachNachrichtAttachments: string = getDataTestIdOf( - 'postfach-mail-attachments-container', - ); + const postfachNachrichtAttachments: string = getDataTestIdOf('postfach-mail-attachments-container'); beforeEach(async () => { await TestBed.configureTestingModule({ @@ -61,7 +50,7 @@ describe('PostfachMailComponent', () => { PostfachMailComponent, MockComponent(IncommingMailComponent), MockComponent(OutgoingMailComponent), - MockComponent(PostfachMailAttachmentsComponent), + MockComponent(BinaryFileListContainerComponent), ], providers: [ { @@ -94,9 +83,7 @@ describe('PostfachMailComponent', () => { }); describe('on existing link and page', () => { - const postfachNachricht: PostfachMailResource = createPostfachMailResource([ - PostfachMailLinkRel.ATTACHMENTS, - ]); + const postfachNachricht: PostfachMailResource = createPostfachMailResource([PostfachMailLinkRel.ATTACHMENTS]); beforeEach(() => { component.onPage = true; @@ -108,17 +95,6 @@ describe('PostfachMailComponent', () => { existsAsHtmlElement(fixture, postfachNachrichtAttachments); }); - - it('should be called with postfachNachricht', () => { - fixture.detectChanges(); - - const postfachAttachmentsComponent: PostfachMailAttachmentsComponent = getMockComponent( - fixture, - PostfachMailAttachmentsComponent, - ); - - expect(postfachAttachmentsComponent.postfachNachricht).toBe(postfachNachricht); - }); }); }); @@ -140,19 +116,13 @@ describe('PostfachMailComponent', () => { describe('call', () => { it('should be with postfachNachricht', () => { - const outgoingMailComponent: OutgoingMailComponent = getMockComponent( - fixture, - OutgoingMailComponent, - ); + const outgoingMailComponent: OutgoingMailComponent = getMockComponent(fixture, OutgoingMailComponent); expect(outgoingMailComponent.postfachMail).toBe(outgoingPostfachNachricht); }); it('should be with vorgangStateResource', () => { - const outgoingMailComponent: OutgoingMailComponent = getMockComponent( - fixture, - OutgoingMailComponent, - ); + const outgoingMailComponent: OutgoingMailComponent = getMockComponent(fixture, OutgoingMailComponent); expect(outgoingMailComponent.vorgangStateResource).toBe(vorgangStateResource); }); @@ -194,10 +164,7 @@ describe('PostfachMailComponent', () => { describe('call', () => { it('should be with postfachNachricht', () => { - const incomingMailComponent: IncommingMailComponent = getMockComponent( - fixture, - IncommingMailComponent, - ); + const incomingMailComponent: IncommingMailComponent = getMockComponent(fixture, IncommingMailComponent); expect(incomingMailComponent.postfachMail).toBe(incomingPostfachNachricht); }); diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component.ts index 25bde83011fce2fe074aa2945a06894458bcb4e0..50cb1511c6d09b34bb4b19a65e1d1d5eb5508440 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component.ts @@ -21,12 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - ON_PAGE, - PostfachMailLinkRel, - PostfachMailResource, - isIncomingMail, -} from '@alfa-client/postfach-shared'; +import { BinaryFileListOrientation } from '@alfa-client/binary-file'; +import { isIncomingMail, ON_PAGE, PostfachMailLinkRel, PostfachMailResource } from '@alfa-client/postfach-shared'; import { StateResource } from '@alfa-client/tech-shared'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { Component, Inject, Input } from '@angular/core'; @@ -47,4 +43,7 @@ export class PostfachMailComponent { public get isIncomingMail(): boolean { return isIncomingMail(this.postfachMail); } + + protected readonly BinaryFileListOrientation = BinaryFileListOrientation; + protected readonly PostfachMailLinkRel = PostfachMailLinkRel; } diff --git a/alfa-client/libs/postfach/src/lib/postfach.module.ts b/alfa-client/libs/postfach/src/lib/postfach.module.ts index 2a6fe82af2922461a8ed345f322b54e754f2ccec..88fd93b41fff801fb308bfc6a227483cc5042fc4 100644 --- a/alfa-client/libs/postfach/src/lib/postfach.module.ts +++ b/alfa-client/libs/postfach/src/lib/postfach.module.ts @@ -24,17 +24,7 @@ import { BinaryFileModule } from '@alfa-client/binary-file'; import { ON_PAGE, PostfachSharedModule } from '@alfa-client/postfach-shared'; 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 { 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'; @@ -43,10 +33,10 @@ 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 { MultiFileUploadComponent } from '../../../binary-file/src/lib/multi-file-upload/multi-file-upload.component'; import { PostfachMailButtonContainerComponent } from './postfach-mail-button-container/postfach-mail-button-container.component'; import { PostfachMailButtonComponent } from './postfach-mail-button-container/postfach-mail-button/postfach-mail-button.component'; import { PostfachMailFormComponent } from './postfach-mail-form/postfach-mail-form.component'; -import { PostfachNachrichtAttachmentContainerComponent } from './postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component'; import { PostfachNachrichtReplyEditorContainerComponent } from './postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component'; import { PostfachMailListContainerComponent } from './postfach-mail-list-container/postfach-mail-list-container.component'; import { PostfachMailListComponent } from './postfach-mail-list-container/postfach-mail-list/postfach-mail-list.component'; @@ -55,7 +45,6 @@ import { OutgoingMailErrorContainerComponent } from './postfach-mail-list-contai import { OutgoingMailErrorComponent } from './postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component'; import { OutgoingMailComponent } from './postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail.component'; import { PostfachNachrichtEditButtonContainerComponent } from './postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/postfach-nachricht-edit-button-container/postfach-nachricht-edit-button-container.component'; -import { PostfachMailAttachmentsComponent } from './postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-attachments/postfach-mail-attachments.component'; import { PostfachMailDateComponent } from './postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-date/postfach-mail-date.component'; import { PostfachMailComponent } from './postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component'; import { PostfachMailPdfButtonContainerComponent } from './postfach-mail-pdf-button-container/postfach-mail-pdf-button-container.component'; @@ -99,6 +88,7 @@ const routes: Routes = [ PlusIconComponent, MailboxIconComponent, TooltipDirective, + MultiFileUploadComponent, ], declarations: [ PostfachMailListContainerComponent, @@ -114,12 +104,10 @@ const routes: Routes = [ OutgoingMailErrorComponent, PostfachMailDateComponent, OutgoingMailErrorContainerComponent, - PostfachMailAttachmentsComponent, PostfachMailButtonComponent, PostfachMailPdfButtonContainerComponent, PostfachMailPdfButtonComponent, PostfachNachrichtEditButtonContainerComponent, - PostfachNachrichtAttachmentContainerComponent, PostfachNachrichtReplyEditorContainerComponent, ], exports: [PostfachMailListContainerComponent, PostfachMailButtonContainerComponent, PostfachMailFormComponent], diff --git a/alfa-client/libs/tech-shared/src/index.ts b/alfa-client/libs/tech-shared/src/index.ts index 6fbc4e5294b1490dd9924a225715b0007c0ba80f..be9ebae3ab1b5b0b13a375f8bd097acbfa8c11e8 100644 --- a/alfa-client/libs/tech-shared/src/index.ts +++ b/alfa-client/libs/tech-shared/src/index.ts @@ -57,6 +57,7 @@ export * from './lib/resource/resource.repository'; export * from './lib/resource/resource.rxjs.operator'; export * from './lib/resource/resource.service'; export * from './lib/resource/resource.util'; +export * from './lib/service/component.factory'; export * from './lib/service/formservice.abstract'; export * from './lib/tech.model'; export * from './lib/tech.util'; diff --git a/alfa-client/libs/tech-shared/src/lib/service/component.factory.spec.ts b/alfa-client/libs/tech-shared/src/lib/service/component.factory.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..32fb2f6d84f6be4f3699b21359aa61395a0d50f8 --- /dev/null +++ b/alfa-client/libs/tech-shared/src/lib/service/component.factory.spec.ts @@ -0,0 +1,101 @@ +import { Mock, mock, mockGetValue } from '@alfa-client/test-utils'; +import { ApplicationRef, ComponentRef, EnvironmentInjector, Injector, ViewRef } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { OzgCloudComponentFactory } from './component.factory'; + +import { ComponentType } from '@angular/cdk/portal'; + +jest.mock('@angular/core', () => ({ + ...jest.requireActual('@angular/core'), + createComponent: jest.fn(), +})); + +describe('OzgCloudComponentFactory', () => { + let factory: OzgCloudComponentFactory; + + let appRef: Mock<ApplicationRef>; + let envInjector: Mock<EnvironmentInjector>; + + beforeEach(() => { + appRef = mock(ApplicationRef); + envInjector = mock(EnvironmentInjector as any); + + factory = TestBed.inject(OzgCloudComponentFactory); + + mockGetValue(factory, 'appRef', appRef); + mockGetValue(factory, 'envInjector', envInjector); + }); + + it('should be created', () => { + expect(factory).toBeTruthy(); + }); + + describe('create component', () => { + let createComponentSpy: jest.SpyInstance; + const injectorMock: Mock<Injector> = mock(Injector as any); + const componentRefMock: Mock<ComponentRef<any>> = mock(ComponentRef as any); + + const componentType: ComponentType<any> = <any>{}; + const injector: Injector = <any>{}; + + beforeEach(() => { + createComponentSpy = jest.spyOn(require('@angular/core'), 'createComponent').mockReturnValue(componentRefMock); + factory._createElementInjector = jest.fn().mockReturnValue(injectorMock); + factory._registerComponentToChangeDetection = jest.fn(); + }); + + it('should call createComponent', () => { + factory.createComponent(componentType, injector); + + expect(createComponentSpy).toHaveBeenCalledWith(componentType, { + environmentInjector: envInjector, + elementInjector: injectorMock, + }); + }); + + it('should register component to angulars change detection', () => { + factory.createComponent(componentType, injector); + + expect(factory._registerComponentToChangeDetection).toHaveBeenCalledWith(componentRefMock); + }); + + it('should return created component', () => { + const componentRef: ComponentRef<any> = factory.createComponent(componentType, injector); + + expect(componentRef).toBe(componentRefMock); + }); + }); + + describe('create element injector', () => { + const injectorMock: Mock<Injector> = mock(Injector as any); + + let createSpy: jest.SpyInstance; + + beforeEach(() => { + createSpy = jest.spyOn(Injector, 'create').mockReturnValue(injectorMock as Injector); + }); + + it('should create an injector by given parent selector', () => { + factory._createElementInjector(injectorMock); + + expect(createSpy).toHaveBeenCalled(); + }); + + it('should return created injector', () => { + const injector: Injector = factory._createElementInjector(injectorMock); + + expect(injector).toBe(injectorMock); + }); + }); + + describe('register component to angulars change detection', () => { + const hostView: ViewRef = <any>{}; + const componentRef: ComponentRef<any> = <any>{ hostView }; + + it('should set hostview to appRef', () => { + factory._registerComponentToChangeDetection(componentRef); + + expect(appRef.attachView).toHaveBeenCalledWith(hostView); + }); + }); +}); diff --git a/alfa-client/libs/tech-shared/src/lib/service/component.factory.ts b/alfa-client/libs/tech-shared/src/lib/service/component.factory.ts new file mode 100644 index 0000000000000000000000000000000000000000..e54497e9fc92bbb198891d487ddcf7565ffab139 --- /dev/null +++ b/alfa-client/libs/tech-shared/src/lib/service/component.factory.ts @@ -0,0 +1,25 @@ +import { ComponentType } from '@angular/cdk/portal'; +import { ApplicationRef, ComponentRef, createComponent, EnvironmentInjector, inject, Injectable, Injector } from '@angular/core'; + +@Injectable({ providedIn: 'root' }) +export class OzgCloudComponentFactory { + private readonly appRef = inject(ApplicationRef); + private readonly envInjector = inject(EnvironmentInjector); + + public createComponent<T>(componentType: ComponentType<any>, parentInjector: Injector): ComponentRef<T> { + const component: ComponentRef<any> = <ComponentRef<any>>createComponent(componentType, { + environmentInjector: this.envInjector, + elementInjector: this._createElementInjector(parentInjector), + }); + this._registerComponentToChangeDetection(component); + return component; + } + + _createElementInjector(parentInjector: Injector): Injector { + return Injector.create({ providers: [], parent: parentInjector }); + } + + _registerComponentToChangeDetection(component: ComponentRef<any>): void { + this.appRef.attachView(component.hostView); + } +} diff --git a/alfa-client/libs/test-utils/src/lib/model.ts b/alfa-client/libs/test-utils/src/lib/model.ts index 1094ac96376b5a8d2d81cf5a7ebf13c69aa2a550..b2564a9ddf9869f6511f01c27ac61a0de6943879 100644 --- a/alfa-client/libs/test-utils/src/lib/model.ts +++ b/alfa-client/libs/test-utils/src/lib/model.ts @@ -30,6 +30,6 @@ export interface EventData<T> { data?: unknown; } -export const MockEvent = { - CLICK: 'clickEmitter', -}; +export enum MockEvent { + CLICK = 'clickEmitter', +} diff --git a/alfa-client/libs/ui/src/index.ts b/alfa-client/libs/ui/src/index.ts index 2db371a18e23b0b2d01eb93bcf1738bd8ef43f61..76832535931b3342403ac5674f6f866c4c7eb58f 100644 --- a/alfa-client/libs/ui/src/index.ts +++ b/alfa-client/libs/ui/src/index.ts @@ -47,6 +47,7 @@ export * from './lib/ui/open-url-button/open-url-button.component'; export * from './lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component'; export * from './lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component'; export * from './lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component'; +export * from './lib/ui/ozgcloud-dialog/ozgcloud-dialog.model'; 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'; 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 cd72feef7dac8d6194e6fb83ab08e9b76e38ffa7..48e0bf00d2f803bbe0d4cdcd95c0ff0e84479aa1 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 @@ -30,6 +30,10 @@ import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dial import { InternalServerErrorDialogComponent } from '../notification/internal-server-error-dialog/internal-server-error-dialog.component'; import { RetryInTimeDialog } from './retry-in-time.dialog'; +/** + * @deprecated use {@link OzgcloudDialogService} instead + * @see OzgcloudDialogService + */ @Injectable({ providedIn: 'root' }) export class DialogService { private dialog = inject(MatDialog); diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.model.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..441d097a057ac2121ffd01610740f149e6d6d5b1 --- /dev/null +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.model.ts @@ -0,0 +1,4 @@ +import { ComponentType } from '@angular/cdk/portal'; +import { InjectionToken } from '@angular/core'; + +export const DIALOG_COMPONENT: InjectionToken<ComponentType<any>> = new InjectionToken<ComponentType<any>>('DialogComponent'); diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.spec.ts index 91585f64a670993693cd3eb2202a181dc9d805ae..b95396349c8cb79f0e97601877a7fcd108529e56 100644 --- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.spec.ts +++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.spec.ts @@ -22,7 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Mock, mock } from '@alfa-client/test-utils'; -import { Dialog, DialogConfig } from '@angular/cdk/dialog'; +import { Dialog, DialogConfig, DialogRef } from '@angular/cdk/dialog'; import { TestBed } from '@angular/core/testing'; import { OzgcloudDialogService } from './ozgcloud-dialog.service'; @@ -82,6 +82,26 @@ describe('OzgcloudDialogService', () => { }); }); + describe('open in context', () => { + const dialogRefMock: Mock<DialogRef> = mock(DialogRef); + + beforeEach(() => { + service.openInCallingComponentContext = jest.fn().mockReturnValue(dialogRefMock); + }); + + it('should call open in calling component context', () => { + service.openInContext(component, viewContainerRef, dialogData); + + expect(service.openInCallingComponentContext).toHaveBeenCalledWith(component, viewContainerRef, dialogData); + }); + + it('should return dialog ref', () => { + const dialogRef: DialogRef = service.openInContext(component, viewContainerRef, dialogData); + + expect(dialogRef).toBe(dialogRefMock); + }); + }); + describe('openInCallingComponentContext', () => { it('should open dialog with data', () => { service.openInCallingComponentContext(component, viewContainerRef, dialogData); 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 077780a3e1d01c0e198efc1de9f12244315b1194..aebed88efe5a54fafce9ec09283f0314c744fc5e 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 @@ -30,7 +30,7 @@ import { isNil } from 'lodash-es'; providedIn: 'root', }) export class OzgcloudDialogService { - private dialog = inject(Dialog); + private readonly dialog = inject(Dialog); readonly WIZARD_DIALOG_CONFIG: DialogConfig = { width: '1000px', @@ -47,10 +47,21 @@ export class OzgcloudDialogService { return this.openDialog<C, R>(component, this.buildDialogConfigWithData<D>(data, this.WIZARD_DIALOG_CONFIG)); } + /** + * @deprecated use openInContext instead + */ public open<C, D = unknown, R = unknown>(component: ComponentType<C>, data?: D): DialogRef<R> { return this.openDialog(component, this.buildDialogConfigWithData(data)); } + public openInContext<C, D = unknown, R = unknown>( + component: ComponentType<C>, + viewContainerRef: ViewContainerRef, + data?: D, + ): DialogRef<R> { + return this.openInCallingComponentContext<C, D, R>(component, viewContainerRef, data); + } + public openFullScreenDialog<C, D = unknown, R = unknown>( component: ComponentType<C>, viewContainerRef: ViewContainerRef, @@ -59,6 +70,7 @@ export class OzgcloudDialogService { return this.openInCallingComponentContext<C, D, R>(component, viewContainerRef, data, this.GREY_BLUR_CONFIG); } + //TODO private machen und openInContext bei den jeweiligen Stellen nutzen public openInCallingComponentContext<C, D = unknown, R = unknown>( component: ComponentType<C>, viewContainerRef: ViewContainerRef, diff --git a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.model.ts b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.model.ts index 2da311b309c80898da51eca6ee5aa04714b8bfff..a9fbef74f589c2a26460d6e0b600a09d01f9f8d7 100644 --- a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.model.ts +++ b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.model.ts @@ -36,8 +36,11 @@ export interface Wiedervorlage { } export interface WiedervorlageResource extends Wiedervorlage, Resource {} + export interface WiedervorlageListResource extends ListResource {} export interface BinaryFileListByWiedervorlageUri { [uri: ResourceUri]: BehaviorSubject<StateResource<BinaryFileListResource>>; } + +export const WIEDERVORLAGE_UPLOADED_ATTACHMENTS = 'wiedervorlage_uploaded_attachments'; diff --git a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.spec.ts b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.spec.ts index b9cc7466f7eeb8425289ce68dc5e5fa0745a74bb..3b37f2ba12ba7a1fe70501e190a918d95d8d1430 100644 --- a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.spec.ts +++ b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.spec.ts @@ -21,49 +21,28 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BinaryFileListResource, BinaryFileService } from '@alfa-client/binary-file-shared'; +import { BinaryFileService } from '@alfa-client/binary-file-shared'; import { CommandOrder, CommandResource, CommandService } from '@alfa-client/command-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { - StateResource, - createEmptyStateResource, - createStateResource, - decodeUrlFromEmbedding, -} from '@alfa-client/tech-shared'; +import * as TechShared from '@alfa-client/tech-shared'; +import { createEmptyStateResource, createStateResource, decodeUrlFromEmbedding, StateResource } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { SnackBarService } from '@alfa-client/ui'; -import { - VorgangResource, - VorgangService, - VorgangWithEingangResource, -} from '@alfa-client/vorgang-shared'; +import { VorgangResource, VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { expect } from '@jest/globals'; import { getUrl } from '@ngxp/rest'; import { cold, hot } from 'jest-marbles'; -import { createBinaryFileListResource } from 'libs/binary-file-shared/test/binary-file'; import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel'; import { createCommandResource } from 'libs/command-shared/test/command'; -import { - createVorgangResource, - createVorgangWithEingangResource, -} from 'libs/vorgang-shared/test/vorgang'; -import { - createWiedervorlage, - createWiedervorlageListResource, - createWiedervorlageResource, -} from 'libs/wiedervorlage-shared/test/wiedervorlage'; +import { createVorgangResource, createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; +import { createWiedervorlage, createWiedervorlageListResource, createWiedervorlageResource, } from 'libs/wiedervorlage-shared/test/wiedervorlage'; import { of } from 'rxjs'; import { WiedervorlageLinkRel, WiedervorlageListLinkRel } from './wiedervorlage.linkrel'; import { WiedervorlageMessages } from './wiedervorlage.message'; -import { - Wiedervorlage, - WiedervorlageListResource, - WiedervorlageResource, -} from './wiedervorlage.model'; +import { Wiedervorlage, WIEDERVORLAGE_UPLOADED_ATTACHMENTS, WiedervorlageListResource, WiedervorlageResource, } from './wiedervorlage.model'; import { WiedervorlageRepository } from './wiedervorlage.repository'; import { WiedervorlageService } from './wiedervorlage.service'; -import * as TechShared from '@alfa-client/tech-shared'; - jest.mock('@alfa-client/tech-shared', () => mockAsEsModule('@alfa-client/tech-shared')); function mockAsEsModule(module: string) { @@ -86,9 +65,7 @@ describe('WiedervorlageService', () => { const wiedervorlageResource: WiedervorlageResource = createWiedervorlageResource(); const wiedervorlage: Wiedervorlage = createWiedervorlage(); const commandResource: CommandResource = createCommandResource(); - const commandResourceWithEffectedResourceLink: CommandResource = createCommandResource([ - CommandLinkRel.EFFECTED_RESOURCE, - ]); + const commandResourceWithEffectedResourceLink: CommandResource = createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]); beforeEach(() => { repository = mock(WiedervorlageRepository); @@ -112,11 +89,9 @@ describe('WiedervorlageService', () => { describe('getWiedervorlageList', () => { const wiedervorlageList: WiedervorlageListResource = createWiedervorlageListResource(); - const wiedervorlageListStateResource: StateResource<WiedervorlageListResource> = - createStateResource(wiedervorlageList); + const wiedervorlageListStateResource: StateResource<WiedervorlageListResource> = createStateResource(wiedervorlageList); - const vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource> = - createStateResource(vorgangResource); + const vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource> = createStateResource(vorgangResource); beforeEach(() => { vorgangService.getVorgangWithEingang.mockReturnValue(of(vorgangWithEingangStateResource)); @@ -129,18 +104,12 @@ describe('WiedervorlageService', () => { }); it('should return values', () => { - vorgangService.getVorgangWithEingang.mockReturnValue( - hot('-a', { a: vorgangWithEingangStateResource }), - ); - service.wiedervorlageList$.asObservable = jest - .fn() - .mockReturnValue(hot('-a', { a: wiedervorlageListStateResource })); + vorgangService.getVorgangWithEingang.mockReturnValue(hot('-a', { a: vorgangWithEingangStateResource })); + service.wiedervorlageList$.asObservable = jest.fn().mockReturnValue(hot('-a', { a: wiedervorlageListStateResource })); const result = service.getWiedervorlageList(); - expect(result).toBeObservable( - cold('ab', { a: createEmptyStateResource(true), b: wiedervorlageListStateResource }), - ); + expect(result).toBeObservable(cold('ab', { a: createEmptyStateResource(true), b: wiedervorlageListStateResource })); }); it.skip('should call loadWiedervorlagenByVorgang if required', (done) => { @@ -159,9 +128,7 @@ describe('WiedervorlageService', () => { it('should NOT call loadWiedervorlagenByVorgang if already loaded', () => { service.loadWiedervorlagenByVorgang = jest.fn(); - service.wiedervorlageList$.asObservable = jest - .fn() - .mockReturnValue(of(wiedervorlageListStateResource)); + service.wiedervorlageList$.asObservable = jest.fn().mockReturnValue(of(wiedervorlageListStateResource)); service.getWiedervorlageList(); @@ -176,9 +143,7 @@ describe('WiedervorlageService', () => { createStateResource(wiedervorlageListResource); it('should return initial value', () => { - service.wiedervorlageList$.asObservable = jest - .fn() - .mockReturnValue(hot('-a', { a: wiedervorlageListResource })); + service.wiedervorlageList$.asObservable = jest.fn().mockReturnValue(hot('-a', { a: wiedervorlageListResource })); const result = service.getWiedervorlageListByGivenVorgang(vorgang); @@ -206,8 +171,7 @@ describe('WiedervorlageService', () => { describe('getWiedervorlage', () => { const wiedervorlage: WiedervorlageResource = createWiedervorlageResource(); - const wiedervorlageStateResource: StateResource<WiedervorlageResource> = - createStateResource(wiedervorlage); + const wiedervorlageStateResource: StateResource<WiedervorlageResource> = createStateResource(wiedervorlage); beforeEach(() => { navigationService.getDecodedParam.mockReturnValue(getUrl(wiedervorlageResource)); @@ -215,15 +179,11 @@ describe('WiedervorlageService', () => { }); it('should return initial values', () => { - service.wiedervorlage$.asObservable = jest - .fn() - .mockReturnValue(hot('-a', { a: wiedervorlageStateResource })); + service.wiedervorlage$.asObservable = jest.fn().mockReturnValue(hot('-a', { a: wiedervorlageStateResource })); const result = service.getWiedervorlage(); - expect(result).toBeObservable( - cold('ab', { a: createEmptyStateResource(true), b: wiedervorlageStateResource }), - ); + expect(result).toBeObservable(cold('ab', { a: createEmptyStateResource(true), b: wiedervorlageStateResource })); }); it('should set loading to true', () => { @@ -237,9 +197,7 @@ describe('WiedervorlageService', () => { it('should call navigationService', () => { service.getWiedervorlage().subscribe(); - expect(navigationService.getDecodedParam).toHaveBeenCalledWith( - WiedervorlageService.encodedWiedervorlageUriParam, - ); + expect(navigationService.getDecodedParam).toHaveBeenCalledWith(WiedervorlageService.encodedWiedervorlageUriParam); }); it('should call repository', () => { @@ -257,9 +215,7 @@ describe('WiedervorlageService', () => { describe('saveWiedervorlage', () => { beforeEach(() => { - commandService.createCommand.mockReturnValue( - of(createStateResource(commandResourceWithEffectedResourceLink)), - ); + commandService.createCommand.mockReturnValue(of(createStateResource(commandResourceWithEffectedResourceLink))); }); it('should return initial value and mapped value', () => { @@ -280,11 +236,10 @@ describe('WiedervorlageService', () => { it('should call command service', () => { service.saveWiedervorlage(wiedervorlageResource, wiedervorlage).subscribe(); - expect(commandService.createCommand).toHaveBeenCalledWith( - wiedervorlageResource, - WiedervorlageLinkRel.EDIT, - { order: CommandOrder.EDIT_WIEDERVORLAGE, body: wiedervorlage }, - ); + expect(commandService.createCommand).toHaveBeenCalledWith(wiedervorlageResource, WiedervorlageLinkRel.EDIT, { + order: CommandOrder.EDIT_WIEDERVORLAGE, + body: wiedervorlage, + }); }); it('should set submit-in-progress on loading', () => { @@ -300,10 +255,7 @@ describe('WiedervorlageService', () => { service.saveWiedervorlage(wiedervorlageResource, wiedervorlage).subscribe(); - const expectedMessage = WiedervorlageMessages.SAVED.replace( - '{betreff}', - wiedervorlage.betreff, - ); + const expectedMessage = WiedervorlageMessages.SAVED.replace('{betreff}', wiedervorlage.betreff); expect(service.proceedAfterReceiveCommand).toHaveBeenCalledWith( createStateResource(commandResourceWithEffectedResourceLink), expectedMessage, @@ -317,15 +269,11 @@ describe('WiedervorlageService', () => { }); it('should return intitial value and mapped value', () => { - commandService.createCommand.mockReturnValue( - hot('-a', { a: createStateResource(commandResource) }), - ); + commandService.createCommand.mockReturnValue(hot('-a', { a: createStateResource(commandResource) })); const result = service.createWiedervorlage(wiedervorlage); - expect(result).toBeObservable( - cold('ab', { a: createEmptyStateResource(true), b: createStateResource(commandResource) }), - ); + expect(result).toBeObservable(cold('ab', { a: createEmptyStateResource(true), b: createStateResource(commandResource) })); }); it('should set submit-in-progress on loading', () => { @@ -352,23 +300,18 @@ describe('WiedervorlageService', () => { service.createWiedervorlage(wiedervorlage).subscribe(); - const expectedMessage = WiedervorlageMessages.CREATED.replace( - '{betreff}', - wiedervorlage.betreff, - ); - expect(service.proceedAfterReceiveCommand).toHaveBeenCalledWith( - createStateResource(commandResource), - expectedMessage, - ); + const expectedMessage = WiedervorlageMessages.CREATED.replace('{betreff}', wiedervorlage.betreff); + expect(service.proceedAfterReceiveCommand).toHaveBeenCalledWith(createStateResource(commandResource), expectedMessage); }); }); describe('proceedAfterRecieveCommand', () => { + beforeEach(() => { + service.clearUploadedFiles = jest.fn(); + }); + it('should set reload on wiedervorlageList', () => { - service.proceedAfterReceiveCommand( - createStateResource(commandResourceWithEffectedResourceLink), - null, - ); + service.proceedAfterReceiveCommand(createStateResource(commandResourceWithEffectedResourceLink), null); expect(service.wiedervorlageList$.value.reload).toBe(true); }); @@ -383,15 +326,15 @@ describe('WiedervorlageService', () => { snackbarService.show = jest.fn(); const snackbarMessage: string = 'XX wurde XX'; - service.proceedAfterReceiveCommand( - createStateResource(commandResourceWithEffectedResourceLink), - snackbarMessage, - ); + service.proceedAfterReceiveCommand(createStateResource(commandResourceWithEffectedResourceLink), snackbarMessage); - expect(snackbarService.show).toHaveBeenCalledWith( - commandResourceWithEffectedResourceLink, - snackbarMessage, - ); + expect(snackbarService.show).toHaveBeenCalledWith(commandResourceWithEffectedResourceLink, snackbarMessage); + }); + + it('should clear uploaded files', () => { + service.proceedAfterReceiveCommand(createStateResource(commandResourceWithEffectedResourceLink), null); + + expect(service.clearUploadedFiles).toHaveBeenCalled(); }); }); @@ -399,24 +342,22 @@ describe('WiedervorlageService', () => { const wiedervorlageResource: WiedervorlageResource = createWiedervorlageResource(); beforeEach(() => { - commandService.createCommand.mockReturnValue( - of(createStateResource(commandResourceWithEffectedResourceLink)), - ); + commandService.createCommand.mockReturnValue(of(createStateResource(commandResourceWithEffectedResourceLink))); (<any>service).reloadWiedervorlageList = jest.fn(); (<any>service).loadAndSetWiedervorlageByUrl = jest.fn(); service.wiedervorlage$.next(createStateResource(wiedervorlageResource)); + service.clearUploadedFiles = jest.fn(); }); describe('wiedervorlage erledigen', () => { it('should call commandService', () => { service.erledigen(); - expect(commandService.createCommand).toHaveBeenCalledWith( - wiedervorlageResource, - WiedervorlageLinkRel.ERLEDIGEN, - { order: CommandOrder.WIEDERVORLAGE_ERLEDIGEN, body: null }, - ); + expect(commandService.createCommand).toHaveBeenCalledWith(wiedervorlageResource, WiedervorlageLinkRel.ERLEDIGEN, { + order: CommandOrder.WIEDERVORLAGE_ERLEDIGEN, + body: null, + }); }); it('should reload wiedervorlage', () => { @@ -433,17 +374,22 @@ describe('WiedervorlageService', () => { `Die Wiedervorlage ${wiedervorlageResource.betreff} wurde erledigt`, ); }); + + it('should clear uploaded files', () => { + service.erledigen(); + + expect(service.clearUploadedFiles).toHaveBeenCalled(); + }); }); describe('wiedervorlage wiedereroeffnen', () => { it('should call commandService', () => { service.wiedereroeffnen(); - expect(commandService.createCommand).toHaveBeenCalledWith( - wiedervorlageResource, - WiedervorlageLinkRel.WIEDEREROEFFNEN, - { order: CommandOrder.WIEDERVORLAGE_WIEDEREROEFFNEN, body: null }, - ); + expect(commandService.createCommand).toHaveBeenCalledWith(wiedervorlageResource, WiedervorlageLinkRel.WIEDEREROEFFNEN, { + order: CommandOrder.WIEDERVORLAGE_WIEDEREROEFFNEN, + body: null, + }); }); it('should reload wiedervorlage', () => { @@ -460,6 +406,12 @@ describe('WiedervorlageService', () => { `Die Wiedervorlage ${wiedervorlageResource.betreff} wurde wiedereröffnet`, ); }); + + it('should clear uploaded files', () => { + service.wiedereroeffnen(); + + expect(service.clearUploadedFiles).toHaveBeenCalled(); + }); }); }); @@ -467,9 +419,7 @@ describe('WiedervorlageService', () => { const message: string = 'SnackbarMessage'; it('should call service if command is done', () => { - const commandResource: CommandResource = createCommandResource([ - CommandLinkRel.EFFECTED_RESOURCE, - ]); + const commandResource: CommandResource = createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]); service.showSnackBar(commandResource, message); @@ -491,7 +441,6 @@ describe('WiedervorlageService', () => { service.setWiedervorlageListReload = jest.fn(); (<any>service).forceWiedervorlageReload = jest.fn(); - service.clearAttachmentList = jest.fn(); service.clearWiedervorlagenList = jest.fn(); }); @@ -511,12 +460,6 @@ describe('WiedervorlageService', () => { expect((<any>service).forceWiedervorlageReload).toHaveBeenCalled(); }); - - it('should clear attachments', () => { - service.onNavigation({}); - - expect(service.clearAttachmentList).toHaveBeenCalled(); - }); }); describe('to vorgang list', () => { @@ -525,48 +468,6 @@ describe('WiedervorlageService', () => { expect(service.clearWiedervorlagenList).toHaveBeenCalled(); }); - - it('should clear attachments', () => { - service.onNavigation({}); - - expect(service.clearAttachmentList).toHaveBeenCalled(); - }); - }); - }); - - describe('load attachments', () => { - const binaryFileListResource: BinaryFileListResource = createBinaryFileListResource(); - const binaryFileStateResource: StateResource<BinaryFileListResource> = - createStateResource(binaryFileListResource); - - beforeEach(() => { - binaryFileService.getFiles.mockReturnValue(of(binaryFileStateResource)); - service.setAttachmentLoading = jest.fn(); - }); - - it('should set attachment state resource on loading', () => { - service.loadAttachments(wiedervorlageResource); - - expect(service.setAttachmentLoading).toHaveBeenCalledWith(wiedervorlageResource); - }); - - it('should call file service', () => { - service.loadAttachments(wiedervorlageResource); - - expect(binaryFileService.getFiles).toHaveBeenCalledWith( - wiedervorlageResource, - WiedervorlageLinkRel.ATTACHMENTS, - ); - }); - - it('should set loaded resource into state resource', () => { - service.loadAttachments(wiedervorlageResource); - - service.getAttachmentList(wiedervorlageResource); - const result: StateResource<BinaryFileListResource> = - service.attachmentListByWiedervorlage[getUrl(wiedervorlageResource)].value; - - expect(result).toEqual(binaryFileStateResource); }); }); @@ -618,4 +519,12 @@ describe('WiedervorlageService', () => { expect(repository.getWiedervorlage).toHaveBeenCalledWith(decodedUrl); }); }); + + describe('clearUploadedFiles', () => { + it('should call binary file service', () => { + service.clearUploadedFiles(); + + expect(binaryFileService.clearUploadedFiles).toHaveBeenCalledWith(WIEDERVORLAGE_UPLOADED_ATTACHMENTS); + }); + }); }); diff --git a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.ts b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.ts index 691da275eaed51ea51269561b8c979daa388153a..38a7b041ad76c71ef06a78f5f7184a0260fd31f0 100644 --- a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.ts +++ b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.ts @@ -21,42 +21,21 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BinaryFileListResource, BinaryFileService } from '@alfa-client/binary-file-shared'; -import { - CommandOrder, - CommandResource, - CommandService, - CreateCommand, - isDone, -} from '@alfa-client/command-shared'; +import { BinaryFileService } from '@alfa-client/binary-file-shared'; +import { CommandOrder, CommandResource, CommandService, CreateCommand, isDone } from '@alfa-client/command-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { - StateResource, - createEmptyStateResource, - createStateResource, - decodeUrlFromEmbedding, - doIfLoadingRequired, - hasStateResourceError, - isNotNull, - isNotUndefined, - replacePlaceholder, -} from '@alfa-client/tech-shared'; +import { createEmptyStateResource, createStateResource, decodeUrlFromEmbedding, doIfLoadingRequired, hasStateResourceError, isNotNull, isNotUndefined, replacePlaceholder, StateResource, } from '@alfa-client/tech-shared'; import { SnackBarService } from '@alfa-client/ui'; import { VorgangHeaderLinkRel, VorgangResource, VorgangService } from '@alfa-client/vorgang-shared'; import { Injectable, OnDestroy } from '@angular/core'; import { Params } from '@angular/router'; -import { ResourceUri, getUrl, hasLink } from '@ngxp/rest'; +import { hasLink, ResourceUri } from '@ngxp/rest'; import { isEqual, isNil, isNull, isUndefined } from 'lodash-es'; -import { BehaviorSubject, Observable, Subscription, combineLatest } from 'rxjs'; +import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; import { filter, map, startWith, tap } from 'rxjs/operators'; import { WiedervorlageLinkRel, WiedervorlageListLinkRel } from './wiedervorlage.linkrel'; import { WiedervorlageMessages } from './wiedervorlage.message'; -import { - BinaryFileListByWiedervorlageUri, - Wiedervorlage, - WiedervorlageListResource, - WiedervorlageResource, -} from './wiedervorlage.model'; +import { Wiedervorlage, WIEDERVORLAGE_UPLOADED_ATTACHMENTS, WiedervorlageListResource, WiedervorlageResource, } from './wiedervorlage.model'; import { WiedervorlageRepository } from './wiedervorlage.repository'; import { WiedervorlageRoutes } from './wiedervorlage.route'; import { createErledigenCommand, createWiedereroeffnenCommand } from './wiedervorlage.util'; @@ -65,14 +44,12 @@ import { createErledigenCommand, createWiedereroeffnenCommand } from './wiedervo export class WiedervorlageService implements OnDestroy { static encodedWiedervorlageUriParam: string = 'wiedervorlageUrl'; - readonly wiedervorlageList$: BehaviorSubject<StateResource<WiedervorlageListResource>> = - new BehaviorSubject<StateResource<WiedervorlageListResource>>( - createEmptyStateResource<WiedervorlageListResource>(), - ); - readonly wiedervorlage$: BehaviorSubject<StateResource<WiedervorlageResource>> = - new BehaviorSubject<StateResource<WiedervorlageResource>>( - createEmptyStateResource<WiedervorlageResource>(), - ); + readonly wiedervorlageList$: BehaviorSubject<StateResource<WiedervorlageListResource>> = new BehaviorSubject< + StateResource<WiedervorlageListResource> + >(createEmptyStateResource<WiedervorlageListResource>()); + readonly wiedervorlage$: BehaviorSubject<StateResource<WiedervorlageResource>> = new BehaviorSubject< + StateResource<WiedervorlageResource> + >(createEmptyStateResource<WiedervorlageResource>()); readonly submitInProgress$: BehaviorSubject<StateResource<CommandResource>> = new BehaviorSubject< StateResource<CommandResource> @@ -81,15 +58,11 @@ export class WiedervorlageService implements OnDestroy { readonly erledigenCommand$: BehaviorSubject<StateResource<CommandResource>> = new BehaviorSubject< StateResource<CommandResource> >(createEmptyStateResource<CommandResource>()); - readonly wiedereroeffnenCommand$: BehaviorSubject<StateResource<CommandResource>> = - new BehaviorSubject<StateResource<CommandResource>>( - createEmptyStateResource<CommandResource>(), - ); - - attachmentListByWiedervorlage = <BinaryFileListByWiedervorlageUri>{}; + readonly wiedereroeffnenCommand$: BehaviorSubject<StateResource<CommandResource>> = new BehaviorSubject< + StateResource<CommandResource> + >(createEmptyStateResource<CommandResource>()); private subscription: Subscription; - private attachmentSubscription: Subscription; constructor( private repository: WiedervorlageRepository, @@ -103,15 +76,10 @@ export class WiedervorlageService implements OnDestroy { } public getWiedervorlageList(): Observable<StateResource<WiedervorlageListResource>> { - return combineLatest([ - this.wiedervorlageList$.asObservable(), - this.vorgangService.getVorgangWithEingang(), - ]).pipe( + return combineLatest([this.wiedervorlageList$.asObservable(), this.vorgangService.getVorgangWithEingang()]).pipe( tap(([wiedervorlageList, vorgangResource]) => { if (isNotNull(vorgangResource.resource)) { - doIfLoadingRequired(wiedervorlageList, () => - this.loadWiedervorlagenByVorgang(vorgangResource.resource), - ); + doIfLoadingRequired(wiedervorlageList, () => this.loadWiedervorlagenByVorgang(vorgangResource.resource)); } }), map(([wiedervorlageList]) => wiedervorlageList), @@ -122,22 +90,18 @@ export class WiedervorlageService implements OnDestroy { public getWiedervorlageListByGivenVorgang( vorgangResource: VorgangResource, ): Observable<StateResource<WiedervorlageListResource>> { - doIfLoadingRequired(this.wiedervorlageList$.value, () => - this.loadWiedervorlagenByVorgang(vorgangResource), - ); + doIfLoadingRequired(this.wiedervorlageList$.value, () => this.loadWiedervorlagenByVorgang(vorgangResource)); return this.wiedervorlageList$.asObservable(); } loadWiedervorlagenByVorgang(vorgangResource: VorgangResource): void { if (hasLink(vorgangResource, VorgangHeaderLinkRel.WIEDERVORLAGEN)) { - const subscription: Subscription = this.repository - .getWiedervorlageList(vorgangResource) - .subscribe((wiedervorlagenList) => { - if (!isNull(wiedervorlagenList)) { - this.setWiedervorlagenList(wiedervorlagenList); - subscription.unsubscribe(); - } - }); + const subscription: Subscription = this.repository.getWiedervorlageList(vorgangResource).subscribe((wiedervorlagenList) => { + if (!isNull(wiedervorlagenList)) { + this.setWiedervorlagenList(wiedervorlagenList); + subscription.unsubscribe(); + } + }); } else { this.clearWiedervorlagenList(); } @@ -152,10 +116,6 @@ export class WiedervorlageService implements OnDestroy { ); } - setWiedervorlageListLoading(): void { - this.wiedervorlageList$.next({ ...this.wiedervorlageList$.value, loading: true }); - } - setWiedervorlagenList(wiedervorlagenList: WiedervorlageListResource): void { this.wiedervorlageList$.next(createStateResource(wiedervorlagenList)); } @@ -176,26 +136,19 @@ export class WiedervorlageService implements OnDestroy { private loadAndSetWiedervorlageByUrl(url: ResourceUri): void { this.setWiedervorlageLoading(); - const subscription: Subscription = this.repository - .getWiedervorlage(url) - .subscribe((wiedervorlage) => { - this.wiedervorlage$.next(createStateResource(wiedervorlage)); - subscription.unsubscribe(); - }); + const subscription: Subscription = this.repository.getWiedervorlage(url).subscribe((wiedervorlage) => { + this.wiedervorlage$.next(createStateResource(wiedervorlage)); + subscription.unsubscribe(); + }); } public isNewWiedervorlage(): boolean { - return isEqual( - this.navigationService.getParam(WiedervorlageService.encodedWiedervorlageUriParam), - WiedervorlageRoutes.NEW, - ); + return isEqual(this.navigationService.getParam(WiedervorlageService.encodedWiedervorlageUriParam), WiedervorlageRoutes.NEW); } private listenToNavigation(): void { this.unsubscribe(); - this.subscription = this.navigationService - .urlChanged() - .subscribe((params) => this.onNavigation(params)); + this.subscription = this.navigationService.urlChanged().subscribe((params) => this.onNavigation(params)); } onNavigation(params: Params): void { @@ -203,19 +156,13 @@ export class WiedervorlageService implements OnDestroy { this.setWiedervorlageListReload(); this.forceWiedervorlageReload(); this.submitInProgress$.next(createEmptyStateResource<CommandResource>()); - this.clearAttachmentList(); } if (NavigationService.isVorgangListPage(params)) { this.clearWiedervorlagenList(); this.submitInProgress$.next(createEmptyStateResource<CommandResource>()); - this.clearAttachmentList(); } } - clearAttachmentList(): void { - this.attachmentListByWiedervorlage = <BinaryFileListByWiedervorlageUri>{}; - } - clearWiedervorlagenList(): void { this.wiedervorlageList$.next(createEmptyStateResource<WiedervorlageListResource>()); } @@ -232,30 +179,20 @@ export class WiedervorlageService implements OnDestroy { } private getWiedervorlageUri(): ResourceUri { - return this.navigationService.getDecodedParam( - WiedervorlageService.encodedWiedervorlageUriParam, - ); + return this.navigationService.getDecodedParam(WiedervorlageService.encodedWiedervorlageUriParam); } setWiedervorlageLoading(): void { this.wiedervorlage$.next({ ...this.wiedervorlage$.value, loading: true }); } - public createWiedervorlage( - wiedervorlage: Wiedervorlage, - ): Observable<StateResource<CommandResource>> { + public createWiedervorlage(wiedervorlage: Wiedervorlage): Observable<StateResource<CommandResource>> { this.setSubmitInProgressLoading(); - return this.createCreateWiedervorlageCommand( - this.wiedervorlageList$.value.resource, - wiedervorlage, - ).pipe( + return this.createCreateWiedervorlageCommand(this.wiedervorlageList$.value.resource, wiedervorlage).pipe( filter((commandStateResource) => !commandStateResource.loading), tap((commandStateResource) => - this.proceedAfterReceiveCommand( - commandStateResource, - this.buildMessage(WiedervorlageMessages.CREATED, wiedervorlage), - ), + this.proceedAfterReceiveCommand(commandStateResource, this.buildMessage(WiedervorlageMessages.CREATED, wiedervorlage)), ), startWith(createEmptyStateResource<CommandResource>(true)), ); @@ -285,10 +222,7 @@ export class WiedervorlageService implements OnDestroy { return this.createSaveWiedervorlageCommand(wiedervorlageResource, wiedervorlage).pipe( filter((commandStateResource) => !commandStateResource.loading), tap((commandStateResource) => - this.proceedAfterReceiveCommand( - commandStateResource, - this.buildMessage(WiedervorlageMessages.SAVED, wiedervorlage), - ), + this.proceedAfterReceiveCommand(commandStateResource, this.buildMessage(WiedervorlageMessages.SAVED, wiedervorlage)), ), startWith(createEmptyStateResource<CommandResource>(true)), ); @@ -313,10 +247,7 @@ export class WiedervorlageService implements OnDestroy { return { order: CommandOrder.EDIT_WIEDERVORLAGE, body: wiedervorlage }; } - proceedAfterReceiveCommand( - commandStateResource: StateResource<CommandResource>, - message: string, - ): void { + proceedAfterReceiveCommand(commandStateResource: StateResource<CommandResource>, message: string): void { this.submitInProgress$.next({ ...this.submitInProgress$.value, resource: commandStateResource.resource, @@ -325,6 +256,7 @@ export class WiedervorlageService implements OnDestroy { this.submitInProgress$.next(createStateResource(commandStateResource.resource)); this.snackbarService.show(commandStateResource.resource, message); this.setWiedervorlageListReload(); + this.clearUploadedFiles(); } else if (hasStateResourceError(commandStateResource)) { this.submitInProgress$.next(createStateResource(commandStateResource.resource)); } @@ -370,6 +302,7 @@ export class WiedervorlageService implements OnDestroy { this.buildMessage(snackBarMessage, this.wiedervorlage$.value.resource), ); commandStateSubj.next(commandStateResource); + this.clearUploadedFiles(); commandSubscription.unsubscribe(); } }); @@ -393,45 +326,6 @@ export class WiedervorlageService implements OnDestroy { } } - public getAttachmentList( - wiedervorlage: WiedervorlageResource, - ): Observable<StateResource<BinaryFileListResource>> { - const uri: ResourceUri = getUrl(wiedervorlage); - - if (isNil(this.attachmentListByWiedervorlage[uri])) { - this.attachmentListByWiedervorlage[uri] = new BehaviorSubject( - createEmptyStateResource<any>(), - ); - } else { - this.attachmentListByWiedervorlage[uri].next(createEmptyStateResource<any>()); - } - - doIfLoadingRequired(this.attachmentListByWiedervorlage[uri].value, () => - this.loadAttachments(wiedervorlage), - ); - - return this.attachmentListByWiedervorlage[uri].asObservable(); - } - - loadAttachments(wiedervorlage: WiedervorlageResource): void { - this.setAttachmentLoading(wiedervorlage); - if (!isNil(this.attachmentSubscription)) this.attachmentSubscription.unsubscribe(); - this.attachmentSubscription = this.binaryFileService - .getFiles(wiedervorlage, WiedervorlageLinkRel.ATTACHMENTS) - .subscribe((fileList) => { - if (fileList.loaded) { - this.attachmentListByWiedervorlage[getUrl(wiedervorlage)].next(fileList); - } - }); - } - - setAttachmentLoading(wiedervorlage: WiedervorlageResource): void { - this.attachmentListByWiedervorlage[getUrl(wiedervorlage)].next({ - ...this.attachmentListByWiedervorlage[getUrl(wiedervorlage)].value, - loading: true, - }); - } - public getSubmitInProgress(): Observable<StateResource<CommandResource>> { return this.submitInProgress$.asObservable(); } @@ -451,4 +345,8 @@ export class WiedervorlageService implements OnDestroy { .getWiedervorlage(decodedUrl) .pipe(map((wiedervorlage) => hasLink(wiedervorlage, WiedervorlageLinkRel.EDIT))); } + + public clearUploadedFiles(): void { + this.binaryFileService.clearUploadedFiles(WIEDERVORLAGE_UPLOADED_ATTACHMENTS); + } } diff --git a/alfa-client/libs/wiedervorlage/src/lib/submit-wiedervorlage-button/submit-wiedervorlage-button.component.spec.ts b/alfa-client/libs/wiedervorlage/src/lib/submit-wiedervorlage-button/submit-wiedervorlage-button.component.spec.ts index 5dfb7fa67a2f94ba32302be9866c2c8c5d0af972..e5090f94ee1d5a9a24dd5e603e10f726e03ef5e0 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/submit-wiedervorlage-button/submit-wiedervorlage-button.component.spec.ts +++ b/alfa-client/libs/wiedervorlage/src/lib/submit-wiedervorlage-button/submit-wiedervorlage-button.component.spec.ts @@ -23,7 +23,7 @@ */ import { CommandResource } from '@alfa-client/command-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { StateResource, createStateResource } from '@alfa-client/tech-shared'; +import { createStateResource, StateResource } from '@alfa-client/tech-shared'; import { mock } from '@alfa-client/test-utils'; import { OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; import { WiedervorlageService } from '@alfa-client/wiedervorlage-shared'; @@ -89,15 +89,15 @@ describe('SubmitWiedervorlageButtonComponent', () => { expect(component).toBeTruthy(); }); - describe('navigateIfCommandIsDone', () => { + describe('navigate if command is done', () => { it('should navigate on success', () => { - component.navigateIfCommandIsDone(commandWithError); + component._navigateIfCommandIsDone(commandWithError); expect(navigationService.navigateRelativeTo).toHaveBeenCalled(); }); it('should NOT navigate on loading', () => { - component.navigateIfCommandIsDone({ ...commandWithError, loading: true }); + component._navigateIfCommandIsDone({ ...commandWithError, loading: true }); expect(navigationService.navigateRelativeTo).toHaveBeenCalledWith('../../', activatedRoute); }); diff --git a/alfa-client/libs/wiedervorlage/src/lib/submit-wiedervorlage-button/submit-wiedervorlage-button.component.ts b/alfa-client/libs/wiedervorlage/src/lib/submit-wiedervorlage-button/submit-wiedervorlage-button.component.ts index 788e3229c23f99a1fe11f4d0b2c257e0bde00350..2aa76ca8705a9c54fc601aea707527e5e1a3f04e 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/submit-wiedervorlage-button/submit-wiedervorlage-button.component.ts +++ b/alfa-client/libs/wiedervorlage/src/lib/submit-wiedervorlage-button/submit-wiedervorlage-button.component.ts @@ -52,11 +52,11 @@ export class SubmitWiedervorlageButtonComponent { submit(): void { this.submitInProgress$ = this.formService.submit().pipe( filter((command) => !command.loading), - tap((commandWithError) => this.navigateIfCommandIsDone(commandWithError)), + tap((commandWithError) => this._navigateIfCommandIsDone(commandWithError)), ); } - navigateIfCommandIsDone(command: StateResource<CommandResource>): void { + _navigateIfCommandIsDone(command: StateResource<CommandResource>): void { if (!command.loading && isDone(command.resource)) { this.navigateToVorgangDetailPage(); } diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component.html b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component.html deleted file mode 100644 index 8687a058f25e38cf8042c87506b1e181a4f43e76..0000000000000000000000000000000000000000 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component.html +++ /dev/null @@ -1,31 +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. - ---> -<alfa-vertical-binary-file-list - [binaryFileListStateResource]="attachments$ | async" - [deletable]="false" - data-test-id="wiedervorlage-attachment-list" -> -</alfa-vertical-binary-file-list> diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component.scss b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component.scss deleted file mode 100644 index 7648e3a3481646fbc80529a3a7b59e980b88eb1c..0000000000000000000000000000000000000000 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component.scss +++ /dev/null @@ -1,32 +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. - */ -:host { - display: flex; - margin: 0 -4px; -} - -.attachments { - display: flex; - flex-wrap: wrap; -} diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component.spec.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component.spec.ts deleted file mode 100644 index a462e5aa51ac4cddeebe82a611ece3bc0ae6ef3c..0000000000000000000000000000000000000000 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component.spec.ts +++ /dev/null @@ -1,64 +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 { ComponentFixture, TestBed } from '@angular/core/testing'; -import { ToEmbeddedResourcesPipe } from '@alfa-client/tech-shared'; -import { mock } from '@alfa-client/test-utils'; -import { WiedervorlageService } from '@alfa-client/wiedervorlage-shared'; -import { MockComponent } from 'ng-mocks'; -import { of } from 'rxjs'; -import { WiedervorlageAttachmentListContainerComponent } from './wiedervorlage-attachment-list-container.component'; -import { VerticalBinaryFileListComponent } from '@alfa-client/binary-file'; - -describe('WiedervorlageAttachmentListContainerComponent', () => { - let component: WiedervorlageAttachmentListContainerComponent; - let fixture: ComponentFixture<WiedervorlageAttachmentListContainerComponent>; - - const wiedervorlageService = { ...mock(WiedervorlageService), getAttachmentList: () => of(null) }; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - WiedervorlageAttachmentListContainerComponent, - ToEmbeddedResourcesPipe, - MockComponent(VerticalBinaryFileListComponent), - ], - providers: [ - { - provide: WiedervorlageService, - useValue: wiedervorlageService, - }, - ], - }); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(WiedervorlageAttachmentListContainerComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component.ts deleted file mode 100644 index 93f9f0e59fb650f7074b4fe4223cecbf08a86292..0000000000000000000000000000000000000000 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component.ts +++ /dev/null @@ -1,51 +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 { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; -import { BinaryFileListResource } from '@alfa-client/binary-file-shared'; -import { StateResource } from '@alfa-client/tech-shared'; -import { WiedervorlageResource, WiedervorlageService } from '@alfa-client/wiedervorlage-shared'; -import { Observable } from 'rxjs'; - -@Component({ - selector: 'alfa-wiedervorlage-attachment-list-container', - templateUrl: './wiedervorlage-attachment-list-container.component.html', - styleUrls: ['./wiedervorlage-attachment-list-container.component.scss'], -}) -export class WiedervorlageAttachmentListContainerComponent implements OnChanges { - @Input() wiedervorlage: WiedervorlageResource; - - attachments$: Observable<StateResource<BinaryFileListResource>>; - - constructor(public service: WiedervorlageService) {} - - ngOnChanges(changes: SimpleChanges): void { - if (changes.wiedervorlage) { - this.loadAttachments(); - } - } - - loadAttachments(): void { - this.attachments$ = this.service.getAttachmentList(this.wiedervorlage); - } -} diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.html b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.html index bdef88d210bb2d4b5e240b70f638a0efeb10c9e3..ee68f8fe3530ede164cfbc82544a053121a95cc8 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.html +++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.html @@ -23,10 +23,7 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<div - [attr.data-test-id]="wiedervorlageResource.betreff | convertForDataTest" - class="container text-sm" -> +<div [attr.data-test-id]="wiedervorlageResource.betreff | convertForDataTest" class="container text-sm"> <div class="row"> <alfa-wiedervorlage-status data-test-class="status" @@ -36,20 +33,18 @@ </alfa-wiedervorlage-status> <alfa-link-with-user-name-tooltip-container - *ngIf="wiedervorlageResource | hasLink: linkRel.EDIT; else content" + *ngIf="wiedervorlageResource | hasLink: WiedervorlageLinkRel.EDIT; else content" routerLinkString="wiedervorlage/{{ wiedervorlageResource | toResourceUri }}" [tooltipTemplate]="tooltip" [resource]="wiedervorlageResource" - [linkRel]="linkRel.CREATED_BY" + [linkRel]="WiedervorlageLinkRel.CREATED_BY" data-test-class="link" > <ng-container *ngTemplateOutlet="content"></ng-container> </alfa-link-with-user-name-tooltip-container> <ng-template #content> - <span class="date" data-test-class="frist">{{ - wiedervorlageResource.frist | formatToPrettyDate - }}</span> + <span class="date" data-test-class="frist">{{ wiedervorlageResource.frist | formatToPrettyDate }}</span> <span class="name" data-test-class="betreff">{{ wiedervorlageResource.betreff }}</span> </ng-template> @@ -67,16 +62,17 @@ [tooltipTemplate]="tooltip" [text]="wiedervorlageResource.beschreibung" [resource]="wiedervorlageResource" - [linkRel]="linkRel.CREATED_BY" + [linkRel]="WiedervorlageLinkRel.CREATED_BY" > </alfa-text-with-user-name-tooltip-container> - <alfa-wiedervorlage-attachment-list-container - *ngIf="wiedervorlageResource | hasLink: linkRel.ATTACHMENTS" - data-test-id="wiedervorlage-attachment-list-in-vorgang" - [wiedervorlage]="wiedervorlageResource" - class="attachments" - > - </alfa-wiedervorlage-attachment-list-container> + @if (wiedervorlageResource | hasLink: WiedervorlageLinkRel.ATTACHMENTS) { + <alfa-binary-file-list-container + [resource]="wiedervorlageResource" + [linkRel]="WiedervorlageLinkRel.ATTACHMENTS" + [listOrientation]="BinaryFileListOrientation.VERTICAL" + data-test-id="wiedervorlage-attachment-list-in-vorgang" + ></alfa-binary-file-list-container> + } </div> </div> diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.spec.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.spec.ts index 6673dc39b36123bb4d9bdd8bbb3e06e1e1dc2dc1..f4be1ef8b0b40d801398a057032c8b44020f97c4 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.spec.ts +++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.spec.ts @@ -21,20 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - ConvertForDataTestPipe, - FormatToPrettyDatePipe, - HasLinkPipe, - ToResourceUriPipe, - ToTrafficLightTooltipPipe, - formatFullDate, -} from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe, formatFullDate, FormatToPrettyDatePipe, HasLinkPipe, ToResourceUriPipe, ToTrafficLightTooltipPipe, } from '@alfa-client/tech-shared'; import { dispatchEventFromFixture } from '@alfa-client/test-utils'; import { ExpansionPanelComponent } from '@alfa-client/ui'; -import { - LinkWithUserNameTooltipContainerComponent, - TextWithUserNameTooltipContainerComponent, -} from '@alfa-client/user-profile'; +import { LinkWithUserNameTooltipContainerComponent, TextWithUserNameTooltipContainerComponent } from '@alfa-client/user-profile'; import { WiedervorlageResource } from '@alfa-client/wiedervorlage-shared'; import { registerLocaleData } from '@angular/common'; import localeDe from '@angular/common/locales/de'; @@ -48,7 +38,6 @@ import { TooltipDirective } from '@ods/system'; import { createWiedervorlageResource } from 'libs/wiedervorlage-shared/test/wiedervorlage'; import { MockComponent, MockDirective } from 'ng-mocks'; import { WiedervorlageStatusComponent } from '../../../wiedervorlage-status/wiedervorlage-status.component'; -import { WiedervorlageAttachmentListContainerComponent } from './wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component'; import { WiedervorlageInVorgangExpandButtonComponent } from './wiedervorlage-in-vorgang-expand-button/wiedervorlage-in-vorgang-expand-button.component'; import { WiedervorlageInVorgangComponent } from './wiedervorlage-in-vorgang.component'; @@ -74,7 +63,6 @@ describe('WiedervorlageInVorgangComponent', () => { HasLinkPipe, MockComponent(ExpansionPanelComponent), MockComponent(WiedervorlageStatusComponent), - MockComponent(WiedervorlageAttachmentListContainerComponent), MockComponent(WiedervorlageInVorgangExpandButtonComponent), MockComponent(LinkWithUserNameTooltipContainerComponent), MockComponent(TextWithUserNameTooltipContainerComponent), diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.ts index ee5f2a95c847513473d46821392820ff39650081..727acc5acd01ca8aac2eacb639f4780ecf5db9b3 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.ts +++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.ts @@ -21,13 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Input, OnInit } from '@angular/core'; import { formatFullDate, replacePlaceholders } from '@alfa-client/tech-shared'; -import { - WiedervorlageLinkRel, - WiedervorlageMessages, - WiedervorlageResource, -} from '@alfa-client/wiedervorlage-shared'; +import { WiedervorlageLinkRel, WiedervorlageMessages, WiedervorlageResource } from '@alfa-client/wiedervorlage-shared'; +import { Component, Input, OnInit } from '@angular/core'; +import { BinaryFileListOrientation } from '../../../../../../binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive'; @Component({ selector: 'alfa-wiedervorlage-in-vorgang', @@ -40,7 +37,8 @@ export class WiedervorlageInVorgangComponent implements OnInit { tooltip: string; expanded: boolean; - readonly linkRel = WiedervorlageLinkRel; + public readonly WiedervorlageLinkRel = WiedervorlageLinkRel; + public readonly BinaryFileListOrientation = BinaryFileListOrientation; ngOnInit(): void { this.tooltip = this.formatTooltip(); diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-form/wiedervorlage-form.component.html b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-form/wiedervorlage-form.component.html index 014b5ba17d0289e7b339f6409cf0e32acb7b1194..d7c191e5c0ceca89a1123b107fa04c210d4a4938 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-form/wiedervorlage-form.component.html +++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-form/wiedervorlage-form.component.html @@ -45,14 +45,14 @@ > </ozgcloud-date-editor> - <alfa-binary-file-attachment-container - data-test-id="wiedervorlage-attachment-list" - [existFiles]="attachments$ | async" - [formArrayName]="formServiceClass.FIELD_ATTACHMENTS" - [uploadStateResource]="wiedervorlageListStateResource" - [linkRelUploadAttachment]="wiedervorlageListLinkrel.UPLOAD_FILE" - > - </alfa-binary-file-attachment-container> + <ods-multi-file-upload + [filesFormFieldName]="formServiceClass.FIELD_ATTACHMENTS" + [fileUploadType]="WIEDERVORLAGE_UPLOADED_ATTACHMENTS" + [uploadResource]="wiedervorlageListStateResource.resource" + [uploadLinkRelation]="WiedervorlageListLinkRel.UPLOAD_FILE" + [filesResource]="wiedervorlage" + [filesLinkRelation]="WiedervorlageLinkRel.ATTACHMENTS" + ></ods-multi-file-upload> <alfa-submit-wiedervorlage-button class="submit-button"></alfa-submit-wiedervorlage-button> </form> 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 f7dfb80e9b4ab4478fc2063574cda7411e15498d..014466c7f15afb5a0ca42498b5f7f4db16f7f36e 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 @@ -22,17 +22,16 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { BinaryFileAttachmentContainerComponent } from '@alfa-client/binary-file'; -import { BinaryFileListResource } from '@alfa-client/binary-file-shared'; +import { createStateResource, StateResource } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { DateEditorComponent, OzgcloudTextEditorComponent, TextAreaEditorComponent } from '@alfa-client/ui'; -import { WiedervorlageLinkRel, WiedervorlageResource, WiedervorlageService } from '@alfa-client/wiedervorlage-shared'; +import { WiedervorlageListResource, 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 { createWiedervorlageListResource, createWiedervorlageResource } from 'libs/wiedervorlage-shared/test/wiedervorlage'; import { MockComponent } from 'ng-mocks'; -import { of } from 'rxjs'; +import { MultiFileUploadComponent } from '../../../../../../binary-file/src/lib/multi-file-upload/multi-file-upload.component'; import { SubmitWiedervorlageButtonComponent } from '../../../submit-wiedervorlage-button/submit-wiedervorlage-button.component'; import { WiedervorlageFormComponent } from './wiedervorlage-form.component'; import { WiedervorlageFormService } from './wiedervorlage.formservice'; @@ -44,6 +43,9 @@ describe('WiedervorlageFormComponent', () => { const formService = new WiedervorlageFormService(new UntypedFormBuilder(), useFromMock(mock(WiedervorlageService))); const wiedervorlageService: Mock<WiedervorlageService> = mock(WiedervorlageService); const wiedervorlage: WiedervorlageResource = createWiedervorlageResource(); + const wiedervorlaeListStateResource: StateResource<WiedervorlageListResource> = createStateResource( + createWiedervorlageListResource(), + ); beforeEach(async () => { await TestBed.configureTestingModule({ @@ -54,6 +56,7 @@ describe('WiedervorlageFormComponent', () => { MockComponent(TextAreaEditorComponent), MockComponent(BinaryFileAttachmentContainerComponent), MockComponent(SubmitWiedervorlageButtonComponent), + MockComponent(MultiFileUploadComponent), ], imports: [ReactiveFormsModule], providers: [ @@ -74,6 +77,7 @@ describe('WiedervorlageFormComponent', () => { fixture = TestBed.createComponent(WiedervorlageFormComponent); component = fixture.componentInstance; + component.wiedervorlageListStateResource = wiedervorlaeListStateResource; fixture.detectChanges(); }); @@ -87,7 +91,6 @@ describe('WiedervorlageFormComponent', () => { beforeEach(() => { component.wiedervorlage = wiedervorlage; component.patchWiedervorlage = jest.fn(); - component.updateAttachments = jest.fn(); }); it('should call patchWiedervorlage', () => { @@ -95,37 +98,6 @@ describe('WiedervorlageFormComponent', () => { expect(component.patchWiedervorlage).toHaveBeenCalled(); }); - - it('should call updateAttachments', () => { - component.ngOnChanges(simpleChanges); - - expect(component.updateAttachments).toHaveBeenCalled(); - }); - }); - - describe('updateAttachments', () => { - const binaryFileListResource: BinaryFileListResource = createBinaryFileListResource(); - - beforeEach(() => { - wiedervorlageService.getAttachmentList.mockReturnValue(of(binaryFileListResource)); - }); - - it('should call wiedervorlage service to get attachments if links exists', () => { - const wiedervorlageWithAttachments: WiedervorlageResource = createWiedervorlageResource([WiedervorlageLinkRel.ATTACHMENTS]); - component.wiedervorlage = wiedervorlageWithAttachments; - - component.updateAttachments(); - - expect(wiedervorlageService.getAttachmentList).toHaveBeenCalledWith(wiedervorlageWithAttachments); - }); - - it('should NOT call wiedervorlage service if link is not present', () => { - component.wiedervorlage = wiedervorlage; - - component.updateAttachments(); - - expect(wiedervorlageService.getAttachmentList).not.toHaveBeenCalledWith(wiedervorlage); - }); }); describe('patch wiedervorlage', () => { diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-form/wiedervorlage-form.component.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-form/wiedervorlage-form.component.ts index 06cc5576e632fbde55113894af5e653247ac1780..24f0d1af790e44119b13eb4fd6d5a4d9acb58f0d 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-form/wiedervorlage-form.component.ts +++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-form/wiedervorlage-form.component.ts @@ -21,20 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; -import { BinaryFileListLinkRel, BinaryFileResource } from '@alfa-client/binary-file-shared'; -import { StateResource, getEmbeddedResources, isNotNil } from '@alfa-client/tech-shared'; -import { - WiedervorlageLinkRel, - WiedervorlageListLinkRel, - WiedervorlageListResource, - WiedervorlageResource, - WiedervorlageService, -} from '@alfa-client/wiedervorlage-shared'; -import { hasLink } from '@ngxp/rest'; +import { isNotNil, StateResource } from '@alfa-client/tech-shared'; +import { WIEDERVORLAGE_UPLOADED_ATTACHMENTS, WiedervorlageLinkRel, WiedervorlageListLinkRel, WiedervorlageListResource, WiedervorlageResource, } from '@alfa-client/wiedervorlage-shared'; +import { Component, inject, Input, OnChanges, SimpleChanges } from '@angular/core'; import { isNull } from 'lodash-es'; -import { Observable, of } from 'rxjs'; -import { map } from 'rxjs/operators'; import { WiedervorlageFormService } from './wiedervorlage.formservice'; //TODO Container Component zwischenschalten @@ -47,39 +37,19 @@ export class WiedervorlageFormComponent implements OnChanges { @Input() wiedervorlageListStateResource: StateResource<WiedervorlageListResource>; @Input() wiedervorlage: WiedervorlageResource; - attachments$: Observable<BinaryFileResource[]> = of([]); + public readonly formService = inject(WiedervorlageFormService); - readonly formServiceClass = WiedervorlageFormService; - readonly wiedervorlageListLinkrel = WiedervorlageListLinkRel; - - constructor( - public formService: WiedervorlageFormService, - private wiedervorlageService: WiedervorlageService, - ) {} + public readonly formServiceClass = WiedervorlageFormService; + public readonly WiedervorlageListLinkRel = WiedervorlageListLinkRel; + public readonly WiedervorlageLinkRel = WiedervorlageLinkRel; + public readonly WIEDERVORLAGE_UPLOADED_ATTACHMENTS = WIEDERVORLAGE_UPLOADED_ATTACHMENTS; ngOnChanges(changes: SimpleChanges): void { if (changes.wiedervorlage && isNotNil(this.wiedervorlage)) { - this.updateAttachments(); this.patchWiedervorlage(); } } - updateAttachments(): void { - if (hasLink(this.wiedervorlage, WiedervorlageLinkRel.ATTACHMENTS)) { - this.attachments$ = this.wiedervorlageService - .getAttachmentList(this.wiedervorlage) - .pipe( - map((attachmentList) => - getEmbeddedResources<BinaryFileResource>( - attachmentList, - BinaryFileListLinkRel.FILE_LIST, - ), - ), - ); - } else { - this.attachments$ = of([]); - } - } patchWiedervorlage(): void { if (!isNull(this.wiedervorlage)) { this.formService.patch(this.wiedervorlage); diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage.module.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage.module.ts index 2057849d9d85c3365877c9d58fd022a8137029dc..7fe2f1babb5a64816093254a75dd52cfe1b6fb3e 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage.module.ts +++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage.module.ts @@ -22,26 +22,8 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { BinaryFileModule } from '@alfa-client/binary-file'; -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 { 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'; @@ -52,20 +34,14 @@ import { MatIcon } from '@angular/material/icon'; import { MatTooltip } from '@angular/material/tooltip'; import { RouterModule, Routes } from '@angular/router'; import { ButtonWithSpinnerComponent } from '@ods/component'; -import { - CheckCircleIconComponent, - PlusIconComponent, - SaveIconComponent, - TooltipDirective, - UpdateIconComponent, -} from '@ods/system'; +import { CheckCircleIconComponent, PlusIconComponent, SaveIconComponent, TooltipDirective, UpdateIconComponent, } from '@ods/system'; +import { MultiFileUploadComponent } from '../../../binary-file/src/lib/multi-file-upload/multi-file-upload.component'; import { CreateWiedervorlageButtonContainerComponent } from './create-wiedervorlage-button-container/create-wiedervorlage-button-container.component'; import { ErledigenButtonContainerComponent } from './erledigen-button-container/erledigen-button-container.component'; import { SubmitWiedervorlageButtonComponent } from './submit-wiedervorlage-button/submit-wiedervorlage-button.component'; import { WiedereroeffnenButtonContainerComponent } from './wiedereroeffnen-button-container/wiedereroeffnen-button-container.component'; import { WiedervorlageListInVorgangContainerComponent } from './wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang-container.component'; import { WiedervorlageCreateButtonComponent } from './wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-create-button/wiedervorlage-create-button.component'; -import { WiedervorlageAttachmentListContainerComponent } from './wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component'; import { WiedervorlageInVorgangExpandButtonComponent } from './wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang-expand-button/wiedervorlage-in-vorgang-expand-button.component'; import { WiedervorlageInVorgangComponent } from './wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component'; import { WiedervorlageListInVorgangComponent } from './wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-list-in-vorgang.component'; @@ -121,6 +97,7 @@ const routes: Routes = [ PlusIconComponent, CheckCircleIconComponent, SaveIconComponent, + MultiFileUploadComponent, ], declarations: [ WiedervorlagePageComponent, @@ -138,7 +115,6 @@ const routes: Routes = [ WiedereroeffnenButtonContainerComponent, ErledigenButtonContainerComponent, CreateWiedervorlageButtonContainerComponent, - WiedervorlageAttachmentListContainerComponent, WiedervorlageBreadcrumbContainerComponent, WiedervorlageInVorgangExpandButtonComponent, ],