Skip to content
Snippets Groups Projects
Commit 4432477a authored by Bernhard Fürst's avatar Bernhard Fürst
Browse files

OZG-7405 OZG-7410 Replace ozgcloud-menu with ods-dropdown-menu

parent dcf4132e
Branches
Tags
1 merge request!3OZG-7405 Replace ozgcloud-menu with ods-dropdown-menu
Showing
with 245 additions and 75 deletions
......@@ -29,8 +29,8 @@ export * from './lib/bescheid-wrapper/bescheid-wrapper.component';
export * from './lib/button-card/button-card.component';
export * from './lib/button/button.component';
export * from './lib/dropdown-menu/dropdown-menu-item-button/dropdown-menu-item-button.component';
export * from './lib/dropdown-menu/dropdown-menu-item/dropdown-menu-item.component';
export * from './lib/dropdown-menu/dropdown-menu-item-text/dropdown-menu-item-text.component';
export * from './lib/dropdown-menu/dropdown-menu-item/dropdown-menu-item.component';
export * from './lib/dropdown-menu/dropdown-menu/dropdown-menu.component';
export * from './lib/form/button-toggle/button-toggle.component';
export * from './lib/form/checkbox/checkbox.component';
......@@ -53,6 +53,7 @@ export * from './lib/icons/error-icon/error-icon.component';
export * from './lib/icons/exclamation-icon/exclamation-icon.component';
export * from './lib/icons/external-unit-icon/external-unit-icon.component';
export * from './lib/icons/file-icon/file-icon.component';
export * from './lib/icons/help-icon/help-icon.component';
export * from './lib/icons/iconVariants';
export * from './lib/icons/logout-icon/logout-icon.component';
export * from './lib/icons/mailbox-icon/mailbox-icon.component';
......
/*
* Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HelpIconComponent } from './help-icon.component';
describe('HelpIconComponent', () => {
let component: HelpIconComponent;
let fixture: ComponentFixture<HelpIconComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HelpIconComponent],
}).compileComponents();
fixture = TestBed.createComponent(HelpIconComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
/*
* 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 { NgClass } from '@angular/common';
import { Component, Input } from '@angular/core';
import { twMerge } from 'tailwind-merge';
import { IconVariants, iconVariants } from '../iconVariants';
@Component({
selector: 'ods-help-icon',
standalone: true,
imports: [NgClass],
template: `<svg
[ngClass]="twMerge(iconVariants({ size }), 'fill-black', class)"
aria-hidden="true"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11.95 18C12.3 18 12.5958 17.8792 12.8375 17.6375C13.0792 17.3958 13.2 17.1 13.2 16.75C13.2 16.4 13.0792 16.1042 12.8375 15.8625C12.5958 15.6208 12.3 15.5 11.95 15.5C11.6 15.5 11.3042 15.6208 11.0625 15.8625C10.8208 16.1042 10.7 16.4 10.7 16.75C10.7 17.1 10.8208 17.3958 11.0625 17.6375C11.3042 17.8792 11.6 18 11.95 18ZM11.05 14.15H12.9C12.9 13.6 12.9625 13.1667 13.0875 12.85C13.2125 12.5333 13.5667 12.1 14.15 11.55C14.5833 11.1167 14.925 10.7042 15.175 10.3125C15.425 9.92083 15.55 9.45 15.55 8.9C15.55 7.96667 15.2083 7.25 14.525 6.75C13.8417 6.25 13.0333 6 12.1 6C11.15 6 10.3792 6.25 9.7875 6.75C9.19583 7.25 8.78333 7.85 8.55 8.55L10.2 9.2C10.2833 8.9 10.4708 8.575 10.7625 8.225C11.0542 7.875 11.5 7.7 12.1 7.7C12.6333 7.7 13.0333 7.84583 13.3 8.1375C13.5667 8.42917 13.7 8.75 13.7 9.1C13.7 9.43333 13.6 9.74583 13.4 10.0375C13.2 10.3292 12.95 10.6 12.65 10.85C11.9167 11.5 11.4667 11.9917 11.3 12.325C11.1333 12.6583 11.05 13.2667 11.05 14.15ZM12 22C10.6167 22 9.31667 21.7375 8.1 21.2125C6.88333 20.6875 5.825 19.975 4.925 19.075C4.025 18.175 3.3125 17.1167 2.7875 15.9C2.2625 14.6833 2 13.3833 2 12C2 10.6167 2.2625 9.31667 2.7875 8.1C3.3125 6.88333 4.025 5.825 4.925 4.925C5.825 4.025 6.88333 3.3125 8.1 2.7875C9.31667 2.2625 10.6167 2 12 2C13.3833 2 14.6833 2.2625 15.9 2.7875C17.1167 3.3125 18.175 4.025 19.075 4.925C19.975 5.825 20.6875 6.88333 21.2125 8.1C21.7375 9.31667 22 10.6167 22 12C22 13.3833 21.7375 14.6833 21.2125 15.9C20.6875 17.1167 19.975 18.175 19.075 19.075C18.175 19.975 17.1167 20.6875 15.9 21.2125C14.6833 21.7375 13.3833 22 12 22ZM12 20C14.2333 20 16.125 19.225 17.675 17.675C19.225 16.125 20 14.2333 20 12C20 9.76667 19.225 7.875 17.675 6.325C16.125 4.775 14.2333 4 12 4C9.76667 4 7.875 4.775 6.325 6.325C4.775 7.875 4 9.76667 4 12C4 14.2333 4.775 16.125 6.325 17.675C7.875 19.225 9.76667 20 12 20Z"
/>
</svg>`,
})
export class HelpIconComponent {
@Input() size: IconVariants['size'] = 'medium';
@Input() class: string = undefined;
protected readonly iconVariants = iconVariants;
protected readonly twMerge = twMerge;
}
/*
* 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 type { Meta, StoryObj } from '@storybook/angular';
import { HelpIconComponent } from './help-icon.component';
const meta: Meta<HelpIconComponent> = {
title: 'Icons/Help icon',
component: HelpIconComponent,
excludeStories: /.*Data$/,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<HelpIconComponent>;
export const Default: Story = {
args: { size: 'large' },
argTypes: {
size: {
control: 'select',
options: ['small', 'medium', 'large', 'extra-large', 'full'],
description: 'Size of icon. Property "full" means 100%',
table: {
defaultValue: { summary: 'medium' },
},
},
},
};
......@@ -30,5 +30,4 @@ import { Component, Input } from '@angular/core';
})
export class DocumentationComponent {
@Input() url: string;
@Input() menuTitle: string;
}
......@@ -23,31 +23,29 @@
unter der Lizenz sind dem Lizenztext zu entnehmen.
-->
<button
*ngIf="getNumberOfMenuItems() > 0"
mat-fab
extended
[matMenuTriggerFor]="helpMenu.matMenu"
<ods-dropdown-menu>
<div
button-content
*ngIf="buttonEnabled"
data-test-id="help-menu-button"
class="flex items-center text-ozggray-800 dark:text-ozggray-300"
>
<div class="flex items-center text-ozggray-800 dark:text-ozggray-300">
<ozgcloud-icon class="mr-1" icon="help_outline"></ozgcloud-icon>
<div>Hilfe</div>
<ods-help-icon />
<div class="ml-1 text-sm font-medium">Hilfe</div>
</div>
</button>
<ozgcloud-menu #helpMenu>
<ozgcloud-menu-item
<ods-dropdown-menu-item-text
*ngIf="apiRootStateResource?.resource | hasLink: apiRootLinkRel.DOCUMENTATIONS"
headline="Benutzerleitfaden"
text="Alle Funktionen der Allgemeinen Fachanwendung (Alfa) erklärt."
icon="pdf_file"
#benutzerleitfadenMenuItem
class="border-b border-b-grayborder border-t-grayborder bg-white 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-documentation
additionalContent
data-test-id="documentations-component"
[menuTitle]="benutzerleitfadenMenuItem.headline"
[url]="apiRootStateResource.resource | getUrl: apiRootLinkRel.DOCUMENTATIONS"
>
</alfa-documentation>
</ozgcloud-menu-item>
</ozgcloud-menu>
</ods-dropdown-menu-item-text>
</ods-dropdown-menu>
......@@ -21,17 +21,13 @@
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ApiRootLinkRel } from '@alfa-client/api-root-shared';
import {
GetUrlPipe,
HasLinkPipe,
createEmptyStateResource,
createStateResource,
} from '@alfa-client/tech-shared';
import { GetUrlPipe, HasLinkPipe, createStateResource } from '@alfa-client/tech-shared';
import { getElementFromDomRoot } from '@alfa-client/test-utils';
import { MenuItemComponent, OzgcloudIconComponent, UiModule } from '@alfa-client/ui';
import { MenuItemComponent, UiModule } from '@alfa-client/ui';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { DropdownMenuComponent, DropdownMenuItemTextComponent, FileIconComponent, HelpIconComponent } from '@ods/system';
import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
import { MockComponent } from 'ng-mocks';
import { createApiRootResource } from '../../../../../libs/api-root-shared/test/api-root';
......@@ -43,7 +39,6 @@ describe('HelpMenuComponent', () => {
let fixture: ComponentFixture<HelpMenuComponent>;
const helpMenuButton: string = getDataTestIdOf('help-menu-button');
const documentationsComponent: string = getDataTestIdOf('documentations-component');
beforeEach(async () => {
await TestBed.configureTestingModule({
......@@ -53,10 +48,12 @@ describe('HelpMenuComponent', () => {
GetUrlPipe,
MockComponent(MenuItemComponent),
MockComponent(DocumentationComponent),
MockComponent(OzgcloudIconComponent),
MockComponent(DocumentationComponent),
MockComponent(FileIconComponent),
MockComponent(HelpIconComponent),
MockComponent(DropdownMenuItemTextComponent),
MockComponent(DropdownMenuComponent),
],
imports: [UiModule, NoopAnimationsModule],
imports: [NoopAnimationsModule, UiModule],
}).compileComponents();
fixture = TestBed.createComponent(HelpMenuComponent);
......@@ -69,50 +66,65 @@ describe('HelpMenuComponent', () => {
expect(component).toBeTruthy();
});
describe('help menu button', () => {
it('should be hidden', () => {
const item = getElementFromDomRoot(fixture, helpMenuButton);
describe('input', () => {
describe('apiRootStateResource', () => {
it('should set buttonEnabled to true', () => {
component.hasMenuItems = jest.fn().mockReturnValue(true);
component.apiRootStateResource = createStateResource(createApiRootResource([ApiRootLinkRel.DOCUMENTATIONS]));
expect(item).not.toBeInstanceOf(HTMLElement);
fixture.detectChanges();
expect(component.buttonEnabled).toBeTruthy();
});
it('should be shown', () => {
component.apiRootStateResource = createStateResource(
createApiRootResource([ApiRootLinkRel.DOCUMENTATIONS]),
);
it('should set buttonEnabled to false', () => {
component.hasMenuItems = jest.fn().mockReturnValue(false);
component.apiRootStateResource = createStateResource(createApiRootResource());
fixture.detectChanges();
const item = getElementFromDomRoot(fixture, helpMenuButton);
expect(item).toBeInstanceOf(HTMLElement);
expect(component.buttonEnabled).toBeFalsy();
});
});
});
describe('getNumberOfMenuItems', () => {
it('should return 1', () => {
component.apiRootStateResource = createStateResource(
createApiRootResource([ApiRootLinkRel.DOCUMENTATIONS]),
);
describe('component', () => {
describe('hasMenuItems', () => {
it('should return true if at least 1 menu item exists', () => {
component.apiRootStateResource = createStateResource(createApiRootResource([ApiRootLinkRel.DOCUMENTATIONS]));
const result = component.getNumberOfMenuItems();
const res: boolean = component.hasMenuItems();
expect(result).toEqual(1);
expect(res).toBeTruthy();
});
it('should return 0 if state resource is null', () => {
component.apiRootStateResource = null;
it('should return false if no menu item exists', () => {
component.apiRootStateResource = createStateResource(createApiRootResource());
const res: boolean = component.hasMenuItems();
expect(res).toBeFalsy();
});
});
});
const result = component.getNumberOfMenuItems();
// TODO: Remove code. UI testing should be in E2E not in Unit Tests.
describe.skip('template', () => {
describe('help menu button', () => {
it('should be hidden', () => {
const item = getElementFromDomRoot(fixture, helpMenuButton);
expect(result).toEqual(0);
expect(item).not.toBeInstanceOf(HTMLElement);
});
it('should return 0 if resource is null', () => {
component.apiRootStateResource = createEmptyStateResource();
it('should be shown', () => {
component.apiRootStateResource = createStateResource(createApiRootResource([ApiRootLinkRel.DOCUMENTATIONS]));
const result = component.getNumberOfMenuItems();
fixture.detectChanges();
expect(result).toEqual(0);
const item = getElementFromDomRoot(fixture, helpMenuButton);
expect(item).toBeInstanceOf(HTMLElement);
});
});
});
});
......@@ -31,13 +31,20 @@ import { hasLink } from '@ngxp/rest';
templateUrl: './help-menu.component.html',
})
export class HelpMenuComponent {
@Input() apiRootStateResource: StateResource<ApiRootResource>;
private _apiRootStateResource: StateResource<ApiRootResource>;
@Input() set apiRootStateResource(value: StateResource<ApiRootResource>) {
this._apiRootStateResource = value;
this.buttonEnabled = this.hasMenuItems();
}
get apiRootStateResource(): StateResource<ApiRootResource> {
return this._apiRootStateResource;
}
readonly apiRootLinkRel = ApiRootLinkRel;
buttonEnabled: boolean = false;
public getNumberOfMenuItems(): number {
return [hasLink(this.apiRootStateResource?.resource, ApiRootLinkRel.DOCUMENTATIONS)].filter(
(isTrue) => isTrue,
).length;
public hasMenuItems(): boolean {
return [hasLink(this.apiRootStateResource?.resource, ApiRootLinkRel.DOCUMENTATIONS)].filter((isTrue) => isTrue).length > 0;
}
}
......@@ -25,12 +25,21 @@ import { TechSharedModule } from '@alfa-client/tech-shared';
import { UiModule } from '@alfa-client/ui';
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { DropdownMenuComponent, DropdownMenuItemTextComponent, FileIconComponent, HelpIconComponent } from '@ods/system';
import { DocumentationComponent } from './help-menu/documentation/documentation.component';
import { OpenDocumentationButtonComponent } from './help-menu/documentation/open-documentation-button/open-documentation-button.component';
import { HelpMenuComponent } from './help-menu/help-menu.component';
@NgModule({
imports: [CommonModule, TechSharedModule, UiModule],
imports: [
CommonModule,
TechSharedModule,
FileIconComponent,
HelpIconComponent,
DropdownMenuComponent,
DropdownMenuItemTextComponent,
UiModule,
],
declarations: [HelpMenuComponent, DocumentationComponent, OpenDocumentationButtonComponent],
exports: [HelpMenuComponent],
})
......
......@@ -102,7 +102,7 @@ describe('VorgangDetailMoreMenuComponent', () => {
});
it('should call isButtonDisabled', () => {
const spy = jest.spyOn(component, 'isButtonEnabled');
const spy = jest.spyOn(component, 'hasMenuItems');
component.vorgangWithEingangChanged();
......@@ -110,11 +110,11 @@ describe('VorgangDetailMoreMenuComponent', () => {
});
});
describe('isButtonEnabled', () => {
describe('hasMenuItems', () => {
it('should return true if at least 1 menu item exists', () => {
component.menuItems.reset([new DropdownMenuItemTextComponent()]);
const res: boolean = component.isButtonEnabled();
const res: boolean = component.hasMenuItems();
expect(res).toBeTruthy();
});
......@@ -122,7 +122,7 @@ describe('VorgangDetailMoreMenuComponent', () => {
it('should return false if no menu item exists', () => {
component.menuItems.reset([]);
const res: boolean = component.isButtonEnabled();
const res: boolean = component.hasMenuItems();
expect(res).toBeFalsy();
});
......
......@@ -51,10 +51,10 @@ export class VorgangDetailMoreMenuComponent implements OnChanges {
public vorgangWithEingangChanged(): void {
this.changeDetectorRef.detectChanges();
this.buttonEnabled = this.isButtonEnabled();
this.buttonEnabled = this.hasMenuItems();
}
public isButtonEnabled(): boolean {
public hasMenuItems(): boolean {
return this.menuItems?.length > 0;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment