diff --git a/alfa-client/apps/alfa-e2e/docker-compose.yml b/alfa-client/apps/alfa-e2e/docker-compose.yml index 4437108a00c7c9d20850ae18afe70e8eb8101f8f..efbb27de9070db53e35dc0e0c7c3d41ed9015966 100644 --- a/alfa-client/apps/alfa-e2e/docker-compose.yml +++ b/alfa-client/apps/alfa-e2e/docker-compose.yml @@ -123,6 +123,7 @@ services: - OZGCLOUD_VORGANG_BESCHEID_0_FORM_ID=KFAS_STAGE_KI_10_Haltverbot_LANDESHACKATHON - OZGCLOUD_FEATURE_COLLABORATION_ENABLED=true - OZGCLOUD_BARRIEREFREIHEIT_URL=https://static.dev.sh.ozg-cloud.de/barrierefreiheit + - OZGCLOUD_IMPRESSUM_URL=https://static.dev.sh.ozg-cloud.de/impressum ports: - 8080:8080 - 5000:5000 diff --git a/alfa-client/apps/alfa-e2e/src/components/user-assistance/help-menu.component.e2e.ts b/alfa-client/apps/alfa-e2e/src/components/user-assistance/help-menu.component.e2e.ts index 04851d1ee40caab11dc5aec3fb28a84363ef1e5e..5ab11fa7526cd1e48787ff4cf43cf60228b2ab19 100644 --- a/alfa-client/apps/alfa-e2e/src/components/user-assistance/help-menu.component.e2e.ts +++ b/alfa-client/apps/alfa-e2e/src/components/user-assistance/help-menu.component.e2e.ts @@ -26,6 +26,7 @@ export class HelpMenuE2EComponent { private readonly button: string = 'help-menu-button'; private readonly dropdownButton: string ='dropdown-button'; private readonly openDocumentationButton: string = 'open-documentation-button'; + private readonly openImpressumButton: string = 'impressum'; public getRoot() { return cy.getTestElementWithOid(this.root); @@ -42,4 +43,8 @@ export class HelpMenuE2EComponent { public getOpenDocumentationButton() { return this.getRoot().getTestElementWithOid(this.openDocumentationButton); } + + public getImpressumButton(): Cypress.Chainable<Element> { + return cy.getTestElement(this.openImpressumButton) + } } diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/user-assistance/help-menu.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/user-assistance/help-menu.cy.ts index b0d1fade8eabd902c3fe3e34b9c6f5763a3a66c2..f5339303dd44a7842ba56156999b4e6a9ba55817 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/user-assistance/help-menu.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/user-assistance/help-menu.cy.ts @@ -44,14 +44,20 @@ describe('Help Menu', () => { dropCollections(); }); - describe('open documentation', () => { - it('should show "open documentation" button', () => { + describe('open help menu', () => { + it('should show "open documentation"', () => { helpMenu.getRoot().click(); exist(helpMenu.getOpenDocumentationButton()); }); - it('should open file', () => { + it('should show Impressum button', () => { + helpMenu.getRoot().click(); + + exist(helpMenu.getImpressumButton()); + }); + + it('should open documentation', () => { helpMenu .getOpenDocumentationButton() .find('a') @@ -60,5 +66,10 @@ describe('Help Menu', () => { .url() .should('include', 'benutzerleitfaden'); }); + + it('should contain Impressum link text', () => { + helpMenu.getRoot().click(); + helpMenu.getImpressumButton().find('a').should('have.attr', 'href').and('contain', 'impressum'); + }); }); }); diff --git a/alfa-client/libs/api-root-shared/src/lib/api-root.model.ts b/alfa-client/libs/api-root-shared/src/lib/api-root.model.ts index 0786840d01e7e6c4f0ae6e57e107a77efdc2fade..c03829b96e8049f9472d5cb482c78774264c3e6a 100644 --- a/alfa-client/libs/api-root-shared/src/lib/api-root.model.ts +++ b/alfa-client/libs/api-root-shared/src/lib/api-root.model.ts @@ -29,6 +29,7 @@ export interface ApiRoot { javaVersion: string; production: boolean; barrierefreiheitUrl: string; + impressumUrl: string; } export interface ApiRootResource extends ApiRoot, Resource {} diff --git a/alfa-client/libs/api-root-shared/test/api-root.ts b/alfa-client/libs/api-root-shared/test/api-root.ts index f0f8b4a7f3f717cc71c13609c159ce85d09f56c9..b18613718166ac6c923ac2ffdbd349da1f529d13 100644 --- a/alfa-client/libs/api-root-shared/test/api-root.ts +++ b/alfa-client/libs/api-root-shared/test/api-root.ts @@ -34,6 +34,7 @@ export function createApiRoot(): ApiRoot { buildTime: '1', javaVersion: '1', production: false, - barrierefreiheitUrl: 'https://example.com/', + barrierefreiheitUrl: 'https://example-barrierefreiheit.com/', + impressumUrl: 'https://example-impressum.com/', }; } diff --git a/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-link-item/dropdown-menu-link-item.component.spec.ts b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-link-item/dropdown-menu-link-item.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..c97938ebf924672b181116c59a40f3e7906971c1 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-link-item/dropdown-menu-link-item.component.spec.ts @@ -0,0 +1,40 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { getMockComponent } from '@alfa-client/test-utils'; +import { faker } from '@faker-js/faker'; +import { LinkComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { DropdownMenuLinkItemComponent } from './dropdown-menu-link-item.component'; + +describe('DropdownMenuLinkItemComponent', () => { + let component: DropdownMenuLinkItemComponent; + let fixture: ComponentFixture<DropdownMenuLinkItemComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [DropdownMenuLinkItemComponent, MockComponent(LinkComponent)], + }).compileComponents(); + + fixture = TestBed.createComponent(DropdownMenuLinkItemComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('template', () => { + describe('link', () => { + it('should exist with input', () => { + component.url = faker.word.sample(); + + fixture.detectChanges(); + + const link: LinkComponent = getMockComponent(fixture, LinkComponent); + expect(link).toBeTruthy(); + expect(link.url).toBe(component.url); + }); + }); + }); +}); diff --git a/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-link-item/dropdown-menu-link-item.component.ts b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-link-item/dropdown-menu-link-item.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d0258ddbcfd211a1ebc538e8ac38de7a0ca34c0 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-link-item/dropdown-menu-link-item.component.ts @@ -0,0 +1,20 @@ +import { Component, Input } from '@angular/core'; +import { LinkComponent } from '@ods/system'; +import { OpenLinkIconComponent } from '../../icons/open-link-icon/open-link-icon.component'; + +@Component({ + selector: 'ods-dropdown-menu-link-item', + standalone: true, + imports: [LinkComponent, OpenLinkIconComponent], + styles: [':host {@apply first:mt-2}'], + template: ` <ods-link [url]="url" class="bg-whitetext"> + <div class="flex items-center gap-2 px-4 py-3"> + <p class="text-primary">{{ text }}</p> + <ods-open-link-icon size="small" /> + </div> + </ods-link>`, +}) +export class DropdownMenuLinkItemComponent { + @Input() url: string; + @Input() text: string; +} diff --git a/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-text-item/dropdown-menu-text-item.component.ts b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-text-item/dropdown-menu-text-item.component.ts index f4ecc939dbea7c502369dbf706406d80822c9e09..1282e9fbd302e1eea24300083e52ddee62309544 100644 --- a/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-text-item/dropdown-menu-text-item.component.ts +++ b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-text-item/dropdown-menu-text-item.component.ts @@ -5,10 +5,10 @@ import { Component, Input } from '@angular/core'; selector: 'ods-dropdown-menu-text-item', standalone: true, imports: [CommonModule], - styles: [':host {@apply flex min-h-12 items-start gap-4 px-4 py-3 text-start first:mt-2 last:mb-2}'], + styles: [':host {@apply flex min-h-12 items-start gap-4 px-4 py-3 text-start first:mt-2}'], template: ` <ng-content select="[icon]" /> - <div class="w-80"> + <div class="w-80 whitespace-normal"> <p class="mb-1 text-base font-medium">{{ title }}</p> <p class="mb-3 text-sm font-normal">{{ description }}</p> <ng-content select="[additionalContent]" /> diff --git a/alfa-client/libs/design-system/src/lib/icons/open-link-icon/open-link-icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icons/open-link-icon/open-link-icon.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..391bb8a99d42df4aeeadb2aec507e2419a765ef5 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/icons/open-link-icon/open-link-icon.component.spec.ts @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { OpenLinkIconComponent } from './open-link-icon.component'; + +describe('OpenLinkIconComponent', () => { + let component: OpenLinkIconComponent; + let fixture: ComponentFixture<OpenLinkIconComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [OpenLinkIconComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(OpenLinkIconComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/libs/design-system/src/lib/icons/open-link-icon/open-link-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/open-link-icon/open-link-icon.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..3e0eac83af3beceece4b2920665bb8266f169f46 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/icons/open-link-icon/open-link-icon.component.ts @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { NgClass } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { twMerge } from 'tailwind-merge'; +import { iconVariants, IconVariants } from '../iconVariants'; + +@Component({ + selector: 'ods-open-link-icon', + standalone: true, + imports: [NgClass], + template: `<svg + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + [ngClass]="twMerge(iconVariants({ size }), 'fill-primary', class)" + > + <path + d="M5 21c-.55 0-1.02-.196-1.413-.587A1.926 1.926 0 0 1 3 19V5c0-.55.196-1.02.587-1.413A1.926 1.926 0 0 1 5 3h7v2H5v14h14v-7h2v7c0 .55-.196 1.02-.587 1.413A1.926 1.926 0 0 1 19 21H5Zm4.7-5.3-1.4-1.4L17.6 5H14V3h7v7h-2V6.4l-9.3 9.3Z" + /> + </svg>`, +}) +export class OpenLinkIconComponent { + @Input() size: IconVariants['size'] = 'medium'; + @Input() class: string = undefined; + + readonly iconVariants = iconVariants; + readonly twMerge = twMerge; +} diff --git a/alfa-client/libs/design-system/src/lib/icons/open-link-icon/open-link-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/open-link-icon/open-link-icon.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..8941a073fa54c45de732de7cfa2b1870514d85a0 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/icons/open-link-icon/open-link-icon.stories.ts @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import type { Meta, StoryObj } from '@storybook/angular'; + +import { OpenLinkIconComponent } from './open-link-icon.component'; + +const meta: Meta<OpenLinkIconComponent> = { + title: 'Icons/Open link icon', + component: OpenLinkIconComponent, + excludeStories: /.*Data$/, + tags: ['autodocs'], +}; + +export default meta; +type Story = StoryObj<OpenLinkIconComponent>; + +export const Default: Story = { + args: { size: 'medium' }, + argTypes: { + size: { + control: 'select', + options: ['small', 'medium', 'large', 'extra-large', 'full'], + description: 'Size of icon. Property "full" means 100%', + table: { + defaultValue: { summary: 'medium' }, + }, + }, + }, +}; diff --git a/alfa-client/libs/design-system/src/lib/link/link.component.ts b/alfa-client/libs/design-system/src/lib/link/link.component.ts index 3331d0c65b04128f6954a52a2a22b43da50308e2..f88685017f515629a9ddd03da090d498d15c5be4 100644 --- a/alfa-client/libs/design-system/src/lib/link/link.component.ts +++ b/alfa-client/libs/design-system/src/lib/link/link.component.ts @@ -11,7 +11,7 @@ import { twMerge } from 'tailwind-merge'; [href]="url" [class]=" twMerge( - 'block rounded border-2 border-transparent text-text outline-2 outline-offset-2 outline-focus hover:border-primary-600 focus-visible:border-transparent focus-visible:outline', + 'block rounded border-2 border-transparent text-text hover:bg-neutral-100 focus:border-focus focus:outline-none dark:hover:bg-neutral-700', class ) " diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/documentation/documentation.component.html b/alfa-client/libs/user-assistance/src/lib/help-menu/documentation/documentation.component.html index bc56dba4cc337d7d6d7f633330173b50797d0187..f3fc4cab0df5ed822fccbd154a447e7177c24988 100644 --- a/alfa-client/libs/user-assistance/src/lib/help-menu/documentation/documentation.component.html +++ b/alfa-client/libs/user-assistance/src/lib/help-menu/documentation/documentation.component.html @@ -23,4 +23,13 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<alfa-open-documentation-button [url]="url"></alfa-open-documentation-button> +<ods-dropdown-menu-text-item + class="border-b border-b-grayborder border-t-grayborder bg-whitetext first:border-t" + title="Benutzerleitfaden" + description="Alle Funktionen der Allgemeinen Fachanwendung (Alfa) erklärt." +> + <ods-file-icon icon fileType="pdf" size="large"></ods-file-icon> + <alfa-open-documentation-button additionalContent [url]="url" data-test-id="documentations-component" /> +</ods-dropdown-menu-text-item> + + diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/documentation/documentation.component.spec.ts b/alfa-client/libs/user-assistance/src/lib/help-menu/documentation/documentation.component.spec.ts index efc735e3cf593002792658acffd7053851e06e54..b7307c4a9f800117718ab72571c87289e011907c 100644 --- a/alfa-client/libs/user-assistance/src/lib/help-menu/documentation/documentation.component.spec.ts +++ b/alfa-client/libs/user-assistance/src/lib/help-menu/documentation/documentation.component.spec.ts @@ -22,6 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { DropdownMenuTextItemComponent, FileIconComponent } from '@ods/system'; import { MockComponent } from 'ng-mocks'; import { DocumentationComponent } from './documentation.component'; import { OpenDocumentationButtonComponent } from './open-documentation-button/open-documentation-button.component'; @@ -32,7 +33,12 @@ describe('DocumentationComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [DocumentationComponent, MockComponent(OpenDocumentationButtonComponent)], + declarations: [ + DocumentationComponent, + MockComponent(OpenDocumentationButtonComponent), + MockComponent(DropdownMenuTextItemComponent), + MockComponent(FileIconComponent), + ], }).compileComponents(); fixture = TestBed.createComponent(DocumentationComponent); diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/help-button/help-button.component.html b/alfa-client/libs/user-assistance/src/lib/help-menu/help-button/help-button.component.html new file mode 100644 index 0000000000000000000000000000000000000000..c2e1745ad17aa6a42614f563d95e15dfa57266e8 --- /dev/null +++ b/alfa-client/libs/user-assistance/src/lib/help-menu/help-button/help-button.component.html @@ -0,0 +1,4 @@ +<div class="flex items-center text-ozggray-800 dark:text-ozggray-300"> + <ods-help-icon /> + <div class="ml-1 text-sm font-medium">Hilfe</div> +</div> \ No newline at end of file diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/help-button/help-button.component.spec.ts b/alfa-client/libs/user-assistance/src/lib/help-menu/help-button/help-button.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..4430d6bc1e3b154ae0ec0868fb49504296a1782b --- /dev/null +++ b/alfa-client/libs/user-assistance/src/lib/help-menu/help-button/help-button.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HelpIconComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { HelpButtonComponent } from './help-button.component'; + +describe('HelpButtonComponent', () => { + let component: HelpButtonComponent; + let fixture: ComponentFixture<HelpButtonComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [HelpButtonComponent, MockComponent(HelpIconComponent)], + }).compileComponents(); + + fixture = TestBed.createComponent(HelpButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/help-button/help-button.component.ts b/alfa-client/libs/user-assistance/src/lib/help-menu/help-button/help-button.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..ace8b9adf1443414b53c935ec317ffe96a7df317 --- /dev/null +++ b/alfa-client/libs/user-assistance/src/lib/help-menu/help-button/help-button.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'alfa-help-button', + templateUrl: './help-button.component.html', +}) +export class HelpButtonComponent {} diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.html b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.html index ae214c9fa7b6f83e80e493c5613053f953e931fb..24ee1e914732e11ea00e3dad00a7cffea735b000 100644 --- a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.html +++ b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.html @@ -26,28 +26,18 @@ <ods-dropdown-menu buttonClass="rounded-lg p-2 hover:bg-neutral-100 focus:bg-neutral-200 focus:outline-none dark:hover:bg-neutral-700 dark:focus:bg-neutral-600" > - <div - button-content - *ngIf="enabled" - data-test-id="help-menu-button" - class="flex items-center text-ozggray-800 dark:text-ozggray-300" - > - <ods-help-icon /> - <div class="ml-1 text-sm font-medium">Hilfe</div> - </div> + @if (enabled) { + <alfa-help-button button-content data-test-id="help-menu-button" /> + } - <ods-dropdown-menu-text-item - *ngIf="apiRootStateResource?.resource | hasLink: apiRootLinkRel.DOCUMENTATIONS" - class="border-b border-b-grayborder border-t-grayborder bg-whitetext first:border-t" - title="Benutzerleitfaden" - description="Alle Funktionen der Allgemeinen Fachanwendung (Alfa) erklärt." - > - <ods-file-icon icon fileType="pdf" size="large"></ods-file-icon> + @if (apiRootStateResource?.resource | hasLink: apiRootLinkRel.DOCUMENTATIONS) { <alfa-documentation - additionalContent - data-test-id="documentations-component" [url]="apiRootStateResource.resource | getUrl: apiRootLinkRel.DOCUMENTATIONS" - > - </alfa-documentation> - </ods-dropdown-menu-text-item> + data-test-id="documentation" + /> + } + + @if (apiRootStateResource?.resource?.impressumUrl) { + <ods-dropdown-menu-link-item [url]="apiRootStateResource.resource.impressumUrl" text="Impressum" data-test-id="impressum" /> + } </ods-dropdown-menu> diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.spec.ts b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.spec.ts index 96f154ac92d70d4dbba6bdd86dcabb4122468d04..80c975b0d3a74e0221754a65ab6f127823b20e03 100644 --- a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.spec.ts +++ b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.spec.ts @@ -31,7 +31,9 @@ import { DropdownMenuComponent, DropdownMenuTextItemComponent, FileIconComponent import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { MockComponent } from 'ng-mocks'; import { createApiRootResource } from '../../../../../libs/api-root-shared/test/api-root'; +import { DropdownMenuLinkItemComponent } from '../../../../design-system/src/lib/dropdown-menu/dropdown-menu-link-item/dropdown-menu-link-item.component'; import { DocumentationComponent } from './documentation/documentation.component'; +import { HelpButtonComponent } from './help-button/help-button.component'; import { HelpMenuComponent } from './help-menu.component'; describe('HelpMenuComponent', () => { @@ -39,6 +41,7 @@ describe('HelpMenuComponent', () => { let fixture: ComponentFixture<HelpMenuComponent>; const helpMenuButton: string = getDataTestIdOf('help-menu-button'); + const impressumLink: string = getDataTestIdOf('impressum'); beforeEach(async () => { await TestBed.configureTestingModule({ @@ -51,6 +54,8 @@ describe('HelpMenuComponent', () => { MockComponent(HelpIconComponent), MockComponent(DropdownMenuTextItemComponent), MockComponent(DropdownMenuComponent), + MockComponent(DropdownMenuLinkItemComponent), + MockComponent(HelpButtonComponent), ], imports: [NoopAnimationsModule, UiModule], }).compileComponents(); @@ -89,7 +94,7 @@ describe('HelpMenuComponent', () => { describe('component', () => { describe('hasMenuItems', () => { - it('should return true if at least 1 menu item exists', () => { + it('should return true if documentation Link exists', () => { component.apiRootStateResource = createStateResource(createApiRootResource([ApiRootLinkRel.DOCUMENTATIONS])); const res: boolean = component.hasMenuItems(); @@ -97,11 +102,20 @@ describe('HelpMenuComponent', () => { expect(res).toBeTruthy(); }); - it('should return false if no menu item exists', () => { + it('should return true if impressumUrl exists', () => { component.apiRootStateResource = createStateResource(createApiRootResource()); const res: boolean = component.hasMenuItems(); + expect(res).toBeTruthy(); + }); + + it('should return false', () => { + component.apiRootStateResource = createStateResource(createApiRootResource()); + component.apiRootStateResource.resource.impressumUrl = null; + + const res: boolean = component.hasMenuItems(); + expect(res).toBeFalsy(); }); }); @@ -110,13 +124,16 @@ describe('HelpMenuComponent', () => { describe('template', () => { describe('help menu button', () => { it('should be hidden', () => { - const item = getElementFromDomRoot(fixture, helpMenuButton); + component.enabled = false; + fixture.detectChanges(); + + const item = getElementFromDomRoot(fixture, helpMenuButton); expect(item).not.toBeInstanceOf(HTMLElement); }); it('should be shown', () => { - component.apiRootStateResource = createStateResource(createApiRootResource([ApiRootLinkRel.DOCUMENTATIONS])); + component.enabled = true; fixture.detectChanges(); @@ -124,5 +141,38 @@ describe('HelpMenuComponent', () => { expect(item).toBeInstanceOf(HTMLElement); }); }); + + describe('alfa-documentation', () => { + it('should be hidden if no documentation link', () => { + const documentation = getElementFromDomRoot(fixture, getDataTestIdOf('documentation')); + + expect(documentation).not.toBeInstanceOf(HTMLElement); + }); + + it('should be shown', () => { + component.apiRootStateResource = createStateResource(createApiRootResource([ApiRootLinkRel.DOCUMENTATIONS])); + + fixture.detectChanges(); + + const documentation = getElementFromDomRoot(fixture, getDataTestIdOf('documentation')); + expect(documentation).toBeInstanceOf(HTMLElement); + }); + }); + + describe('ods-dropdown-menu-link', () => { + it('should be hidden if no impressumUrl', () => { + component.apiRootStateResource.resource.impressumUrl = null; + + fixture.detectChanges(); + + const impressum = getElementFromDomRoot(fixture, impressumLink); + expect(impressum).not.toBeInstanceOf(HTMLElement); + }); + + it('should be shown if impressumUrl', () => { + const impressum = getElementFromDomRoot(fixture, impressumLink); + expect(impressum).toBeInstanceOf(HTMLElement); + }); + }); }); }); diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.ts b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.ts index 3b6fbf490e2df7635ec7bed024ea67a2855db3a6..2c8fb3b9e0d656b74f5bbd765b779c35bdaf5a99 100644 --- a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.ts +++ b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.ts @@ -25,13 +25,13 @@ import { ApiRootLinkRel, ApiRootResource } from '@alfa-client/api-root-shared'; import { StateResource } from '@alfa-client/tech-shared'; import { Component, Input } from '@angular/core'; import { hasLink } from '@ngxp/rest'; +import { isNil } from 'lodash-es'; @Component({ selector: 'alfa-help-menu', templateUrl: './help-menu.component.html', }) export class HelpMenuComponent { - @Input() set apiRootStateResource(value: StateResource<ApiRootResource>) { this._apiRootStateResource = value; this.enabled = this.hasMenuItems(); @@ -48,6 +48,14 @@ export class HelpMenuComponent { public readonly apiRootLinkRel = ApiRootLinkRel; public hasMenuItems(): boolean { - return [hasLink(this.apiRootStateResource?.resource, ApiRootLinkRel.DOCUMENTATIONS)].filter((isTrue) => isTrue).length > 0; + return this.hasDocumentationLink() || this.hasImpressumUrl(); + } + + private hasImpressumUrl(): boolean { + return !isNil(this.apiRootStateResource?.resource?.impressumUrl); + } + + private hasDocumentationLink(): boolean { + return hasLink(this.apiRootStateResource?.resource, ApiRootLinkRel.DOCUMENTATIONS); } } diff --git a/alfa-client/libs/user-assistance/src/lib/user-assistance.module.ts b/alfa-client/libs/user-assistance/src/lib/user-assistance.module.ts index 70fb69b6d2ae8b0a50142d79ca356b1a7b19fb6e..e75061efe20c27262b6bb4f59b389fc4ecedfee7 100644 --- a/alfa-client/libs/user-assistance/src/lib/user-assistance.module.ts +++ b/alfa-client/libs/user-assistance/src/lib/user-assistance.module.ts @@ -26,8 +26,10 @@ import { UiModule } from '@alfa-client/ui'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { DropdownMenuComponent, DropdownMenuTextItemComponent, FileIconComponent, HelpIconComponent } from '@ods/system'; +import { DropdownMenuLinkItemComponent } from '../../../design-system/src/lib/dropdown-menu/dropdown-menu-link-item/dropdown-menu-link-item.component'; import { DocumentationComponent } from './help-menu/documentation/documentation.component'; import { OpenDocumentationButtonComponent } from './help-menu/documentation/open-documentation-button/open-documentation-button.component'; +import { HelpButtonComponent } from './help-menu/help-button/help-button.component'; import { HelpMenuComponent } from './help-menu/help-menu.component'; @NgModule({ @@ -39,8 +41,9 @@ import { HelpMenuComponent } from './help-menu/help-menu.component'; DropdownMenuComponent, DropdownMenuTextItemComponent, UiModule, + DropdownMenuLinkItemComponent, ], - declarations: [HelpMenuComponent, DocumentationComponent, OpenDocumentationButtonComponent], + declarations: [HelpMenuComponent, DocumentationComponent, OpenDocumentationButtonComponent, HelpButtonComponent], exports: [HelpMenuComponent], }) export class UserAssistanceModule {} diff --git a/alfa-client/tsconfig.base.json b/alfa-client/tsconfig.base.json index 645b71e1ced60632f86bbe1484b8d0ba45b27c84..6850f74e4eb7c031308a264a51e8a4782fa9613b 100644 --- a/alfa-client/tsconfig.base.json +++ b/alfa-client/tsconfig.base.json @@ -18,7 +18,6 @@ "paths": { "@admin-client/configuration": ["libs/admin/configuration/src/index.ts"], "@admin-client/configuration-shared": ["libs/admin/configuration-shared/src/index.ts"], - "@admin/keycloak-shared": ["libs/admin/keycloak-shared/src/index.ts"], "@admin-client/organisations-einheit": ["libs/admin/organisations-einheit/src/index.ts"], "@admin-client/organisations-einheit-shared": ["libs/admin/organisations-einheit-shared/src/index.ts"], "@admin-client/postfach": ["libs/admin/postfach/src/index.ts"], @@ -28,6 +27,7 @@ "@admin-client/statistik": ["libs/admin/statistik/src/index.ts"], "@admin-client/user": ["libs/admin/user/src/index.ts"], "@admin-client/user-shared": ["libs/admin/user-shared/src/index.ts"], + "@admin/keycloak-shared": ["libs/admin/keycloak-shared/src/index.ts"], "@alfa-client/api-root-shared": ["libs/api-root-shared/src/index.ts"], "@alfa-client/app-shared": ["libs/app-shared/src/index.ts"], "@alfa-client/bescheid": ["libs/bescheid/src/index.ts"], @@ -77,7 +77,7 @@ "@alfa-client/zustaendige-stelle-shared": ["libs/zustaendige-stelle-shared/src/index.ts"], "@authentication": ["libs/authentication/src/index.ts"], "@ods/component": ["libs/design-component/src/index.ts"], - "@ods/system": ["libs/design-system/src/index.ts"], + "@ods/system": ["libs/design-system/src/index.ts"] } }, "exclude": ["node_modules", "tmp"]