From 50c81bcfe07a00b3255291a4d8c70a0097d9c5eb Mon Sep 17 00:00:00 2001 From: Christian Badura <93912698+cbadura@users.noreply.github.com> Date: Fri, 9 Aug 2024 07:53:21 +0200 Subject: [PATCH] Manage UI endpoints in App Detail tab (#179) * feat: add tab with table for mfe endpoints and make editable * feat: add new row functionality * feat: add delete functionality * feat: add test for delete --------- Co-authored-by: Christian Badura --- .../app-detail/add-row.directive.ts | 22 ++++++++ .../app-detail/app-detail.component.html | 54 +++++++++++++++++++ .../app-detail/app-detail.component.spec.ts | 21 ++++++++ .../app-detail/app-detail.component.ts | 17 +++++- src/app/product-store/product-store.module.ts | 4 +- src/assets/i18n/de.json | 14 +++-- src/assets/i18n/en.json | 18 +++++-- 7 files changed, 139 insertions(+), 11 deletions(-) create mode 100644 src/app/product-store/app-detail/add-row.directive.ts diff --git a/src/app/product-store/app-detail/add-row.directive.ts b/src/app/product-store/app-detail/add-row.directive.ts new file mode 100644 index 0000000..8fb22e3 --- /dev/null +++ b/src/app/product-store/app-detail/add-row.directive.ts @@ -0,0 +1,22 @@ +import { Directive, Input, HostListener } from '@angular/core' +import { Table } from 'primeng/table' + +@Directive({ + // eslint-disable-next-line @angular-eslint/directive-selector + selector: '[pAddRow]' +}) +export class AddRowDirective { + @Input() table!: Table + @Input() newRow: any + + @HostListener('click', ['$event']) + onClick(event: Event) { + // Insert a new row + this.table.value.push(this.newRow) + + // Set the new row in edit mode + this.table.initRowEdit(this.newRow) + + event.preventDefault() + } +} diff --git a/src/app/product-store/app-detail/app-detail.component.html b/src/app/product-store/app-detail/app-detail.component.html index 70f264c..a80bcb5 100644 --- a/src/app/product-store/app-detail/app-detail.component.html +++ b/src/app/product-store/app-detail/app-detail.component.html @@ -429,6 +429,60 @@ + + + + + + + {{ 'APP.ENDPOINTS.PATH' | translate }} + + + {{ 'APP.ENDPOINTS.NAME' | translate }} + + + + + + + + + + + {{ endpoint.name }} + + + + + + + + {{ endpoint.path }} + + + + + + + + + + diff --git a/src/app/product-store/app-detail/app-detail.component.spec.ts b/src/app/product-store/app-detail/app-detail.component.spec.ts index d6b1309..a7bc754 100644 --- a/src/app/product-store/app-detail/app-detail.component.spec.ts +++ b/src/app/product-store/app-detail/app-detail.component.spec.ts @@ -278,6 +278,10 @@ describe('AppDetailComponent', () => { component.appAbstract = appMfe component.formGroupMfe = form component.changeMode = 'CREATE' + component.endpoints = [ + { name: 'name', path: 'path' }, + { name: '', path: 'path' } + ] component.onSave() @@ -610,4 +614,21 @@ describe('AppDetailComponent', () => { fixture.detectChanges() expect(component.dateFormat).toEqual('dd.MM.yyyy HH:mm:ss') }) + + it('should add a row in the UI endpoints row', () => { + const returnValue = component.onAddEndpointsRow() + + expect(returnValue).toEqual({ name: '', path: '' }) + }) + + it('should delete an endpoint item', () => { + component.endpoints = [ + { name: 'name', path: 'path' }, + { name: '', path: 'path' } + ] + + component.onDeleteRow(1) + + expect(component.endpoints.length).toBe(1) + }) }) diff --git a/src/app/product-store/app-detail/app-detail.component.ts b/src/app/product-store/app-detail/app-detail.component.ts index dc78487..d7c9e5e 100644 --- a/src/app/product-store/app-detail/app-detail.component.ts +++ b/src/app/product-store/app-detail/app-detail.component.ts @@ -18,7 +18,8 @@ import { Microfrontend, Microservice, UpdateMicrofrontendRequest, - UpdateMicroserviceRequest + UpdateMicroserviceRequest, + UIEndpoint } from 'src/app/shared/generated' import { AppAbstract, ChangeMode } from '../app-search/app-search.component' @@ -80,6 +81,7 @@ export class AppDetailComponent implements OnInit, OnChanges { { label: 'Component', value: 'COMPONENT' } ] public iconItems: SelectItem[] = [] + public endpoints: UIEndpoint[] = [] public convertToUniqueStringArray = convertToUniqueStringArray constructor( @@ -173,6 +175,7 @@ export class AppDetailComponent implements OnInit, OnChanges { this.operator = this.mfe?.operator ?? false this.undeployed = this.mfe?.undeployed ?? false this.deprecated = this.mfe?.deprecated ?? false + this.endpoints = this.mfe?.endpoints ?? [] if (this.changeMode === 'COPY') { if (this.mfe?.id) { this.mfe.id = undefined @@ -255,8 +258,10 @@ export class AppDetailComponent implements OnInit, OnChanges { return } this.mfe = { ...this.formGroupMfe.value, id: this.mfe?.id } - if (this.mfe) + if (this.mfe) { this.mfe.classifications = this.convertToUniqueStringArray(this.formGroupMfe.controls['classifications'].value) + this.mfe.endpoints = this.endpoints.filter((endpoint) => !(endpoint.name === '' && endpoint.path === '')) + } this.changeMode === 'CREATE' ? this.createMfe() : this.updateMfe() } if (this.appAbstract?.appType === 'MS') { @@ -354,4 +359,12 @@ export class AppDetailComponent implements OnInit, OnChanges { ] }) } + + public onAddEndpointsRow() { + return { name: '', path: '' } + } + + public onDeleteRow(row: number) { + this.endpoints.splice(row, 1) + } } diff --git a/src/app/product-store/product-store.module.ts b/src/app/product-store/product-store.module.ts index 3619331..6c91c05 100644 --- a/src/app/product-store/product-store.module.ts +++ b/src/app/product-store/product-store.module.ts @@ -23,6 +23,7 @@ import { ProductInternComponent } from './product-detail/product-intern/product- import { ProductAppsComponent } from './product-detail/product-apps/product-apps.component' import { SlotSearchComponent } from './slot-search/slot-search.component' import { SlotDeleteComponent } from './slot-delete/slot-delete.component' +import { AddRowDirective } from './app-detail/add-row.directive' const routes: Routes = [ { @@ -67,7 +68,8 @@ const routes: Routes = [ ProductInternComponent, ProductAppsComponent, SlotSearchComponent, - SlotDeleteComponent + SlotDeleteComponent, + AddRowDirective ], imports: [ CommonModule, diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 46207e0..6204ace 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -101,6 +101,10 @@ "VIEW_MODE_LIST": "Listenansicht", "VIEW_MODE_TABLE": "Tabellenansicht" }, + "TABLE": { + "ADD_ROW": "Zeile hinzufügen", + "ADD.TOOLTIP": "Eine neue Zeile zur Tabelle hinzufügen" + }, "SEARCH": { "NOT_FOUND": "Keine Daten gefunden", "WILDCARD_SUPPORT": " (Wildcards: ?, *)", @@ -198,10 +202,12 @@ "APPS": "Komponenten", "INTERN": "Intern", "PROPERTIES": "Eigenschaften", + "ENDPOINTS": "UI-Endpunkte", "TOOLTIPS": { "APPS": "Komponenten verwalten", "INTERN": "Interne Eigenschaften", - "PROPERTIES": "Eigenschaften verwalten" + "PROPERTIES": "Eigenschaften verwalten", + "ENDPOINTS": "UI-Endpunkte verwalten" } }, "COMPONENTS": { @@ -236,7 +242,8 @@ "ICON_NAME": "Icon-Name", "NOTE": "Notiz", "EXPOSED_MODULE": "Exposed Module", - "ENDPOINTS": "UI Endpunkte", + "ENDPOINTS.NAME": "Name", + "ENDPOINTS.PATH": "Pfad zum UI-Endpunkt", "GROUP.REMOTE_MODULE": "Remote Modul", "GROUP.LOCAL_MODULE": "Modul Management Details", "GROUP.INTERNALS": "Weitere Details", @@ -260,7 +267,8 @@ "ICON_NAME": "Name eines Icons aus der PrimeNG Icon Bibliothek. Wird z.b. als Default bei Menüeinträgen benutzt", "NOTE": "Notiz", "EXPOSED_MODULE": "Exposed Module", - "ENDPOINTS": "UI Endpunkte", + "ENDPOINTS.NAME": "Name des UI-Endpunkts", + "ENDPOINTS.PATH": "Pfad zum UI-Endpunkt", "GROUP.REMOTE_MODULE": "Details des zu verwendeten Remote Moduls", "GROUP.LOCAL_MODULE": "Details der lokalen Registrierung des Moduls", "GROUP.INTERNALS": "Weitere Details der Objektverwaltung und Verwendung", diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 9aa8c8f..4c4c423 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -67,8 +67,8 @@ "MS.HEADER": "Edit Microservice", "APP": { "TOOLTIP": "Edit App properties", - "OK": "Das App wurde erfolgreich geändert", - "NOK": "Ein Fehler ist aufgetreten. Das App wurde nicht geändert." + "OK": "The Application was changed successfully", + "NOK": "An error has occurred. The Application was not changed." }, "PRODUCT": { "HEADER": "Edit Application", @@ -101,6 +101,10 @@ "VIEW_MODE_LIST": "List view", "VIEW_MODE_TABLE": "Table view" }, + "TABLE": { + "ADD_ROW": "Add row", + "ADD.TOOLTIP": "Add a new row to the table" + }, "SEARCH": { "NOT_FOUND": "No data found", "WILDCARD_SUPPORT": " Wildcards: ?, *", @@ -198,10 +202,12 @@ "APPS": "Components", "INTERN": "Internal", "PROPERTIES": "Properties", + "ENDPOINTS": "UI Endpoints", "TOOLTIPS": { "APPS": "Manage Components", "INTERN": "Internal properties", - "PROPERTIES": "Manage Properties" + "PROPERTIES": "Manage Properties", + "ENDPOINTS": "Manage UI Endpoints" } }, "COMPONENTS": { @@ -236,7 +242,8 @@ "ICON_NAME": "Icon Name", "NOTE": "Note", "EXPOSED_MODULE": "Exposed Module", - "ENDPOINTS": "UI Endpoints", + "ENDPOINTS.NAME": "Name", + "ENDPOINTS.PATH": "Path", "GROUP.REMOTE_MODULE": "Remote Module", "GROUP.LOCAL_MODULE": "Module Management Details", "GROUP.INTERNALS": "More Details", @@ -260,7 +267,8 @@ "ICON_NAME": "Name of the icons from the PrimeNG icon library. Used, for example, as a default icon for menu entries", "NOTE": "Note", "EXPOSED_MODULE": "Exposed Module", - "ENDPOINTS": "UI Endpoints", + "ENDPOINTS.NAME": "Name of the UI Endpoint", + "ENDPOINTS.PATH": "Path to the UI Endpoint", "GROUP.REMOTE_MODULE": "Details of the remote module to be used", "GROUP.LOCAL_MODULE": "Details of the module's local registration", "GROUP.INTERNALS": "More details of object management and usage",