From cfbc6bc83c068feb080dc9b3f69b8125e4dc869c Mon Sep 17 00:00:00 2001 From: Valentin Mihai Date: Tue, 16 Jul 2024 20:18:55 +0300 Subject: [PATCH] RED-9260 - Component Management UI --- .../src/app/modules/admin/admin.routes.ts | 8 + .../component-definitions.component.html | 123 +++++++++++++ .../component-definitions.component.scss | 118 ++++++++++++ .../component-definitions.component.ts | 139 ++++++++++++++ .../admin-side-nav.component.ts | 5 + .../component-definitions.service.ts | 51 +++++ apps/red-ui/src/assets/i18n/redact/de.json | 174 ++++++++++-------- apps/red-ui/src/assets/i18n/redact/en.json | 28 ++- apps/red-ui/src/assets/i18n/scm/de.json | 174 ++++++++++-------- apps/red-ui/src/assets/i18n/scm/en.json | 28 ++- libs/red-domain/src/index.ts | 1 + .../component-definition.ts | 32 ++++ .../src/lib/component-definitions/index.ts | 1 + 13 files changed, 724 insertions(+), 158 deletions(-) create mode 100644 apps/red-ui/src/app/modules/admin/screens/component-definitions/component-definitions.component.html create mode 100644 apps/red-ui/src/app/modules/admin/screens/component-definitions/component-definitions.component.scss create mode 100644 apps/red-ui/src/app/modules/admin/screens/component-definitions/component-definitions.component.ts create mode 100644 apps/red-ui/src/app/services/entity-services/component-definitions.service.ts create mode 100644 libs/red-domain/src/lib/component-definitions/component-definition.ts create mode 100644 libs/red-domain/src/lib/component-definitions/index.ts diff --git a/apps/red-ui/src/app/modules/admin/admin.routes.ts b/apps/red-ui/src/app/modules/admin/admin.routes.ts index 4f9aa6c32..fd10a56ab 100644 --- a/apps/red-ui/src/app/modules/admin/admin.routes.ts +++ b/apps/red-ui/src/app/modules/admin/admin.routes.ts @@ -103,6 +103,14 @@ const dossierTemplateIdRoutes: IqserRoutes = [ routeGuards: [IqserAuthGuard, RedRoleGuard], }, }, + { + path: 'components', + loadComponent: () => import('./screens/component-definitions/component-definitions.component'), + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [IqserAuthGuard, RedRoleGuard], + }, + }, { path: 'file-attributes', loadComponent: () => import('./screens/file-attributes-listing/file-attributes-listing-screen.component'), diff --git a/apps/red-ui/src/app/modules/admin/screens/component-definitions/component-definitions.component.html b/apps/red-ui/src/app/modules/admin/screens/component-definitions/component-definitions.component.html new file mode 100644 index 000000000..7f371474f --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/screens/component-definitions/component-definitions.component.html @@ -0,0 +1,123 @@ +@if (componentDefinitions$ | async; as componentDefinitions) { +
+
+
+ +
+
+ @if (permissionsService.canEditEntities()) { + + } +
+
+
+
+
+
+
{{ 'component-definitions.columns.position' | translate }}
+
{{ 'component-definitions.columns.name' | translate }}
+
+
+ + @for (component of componentDefinitions; track component) { +
+
+
+ + {{ component.rank }} +
+
{{ component.displayName }}
+
+ @if (permissionsService.canEditEntities()) { + + } + +
+
+
+ } +
+ @if (selectedComponent) { +
+
+ @if (selectedComponent.id) { +
+ } @else { +
+ } +
+ @if (form) { +
+
+
+ + +
+ +
+ + +
+ +
+ + {{ technicalName }} + +
+
+ +
+ + @if (selectedComponent.id) { +
+ } +
+
+ } +
+ } +
+
+} diff --git a/apps/red-ui/src/app/modules/admin/screens/component-definitions/component-definitions.component.scss b/apps/red-ui/src/app/modules/admin/screens/component-definitions/component-definitions.component.scss new file mode 100644 index 000000000..80af0380b --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/screens/component-definitions/component-definitions.component.scss @@ -0,0 +1,118 @@ +%item-content-style { + position: relative; + display: flex; + flex: 1; + margin: 5px; + + div:first-child { + width: 100px; + } + + div { + display: flex; + align-items: center; + justify-content: center; + + .draggable { + cursor: grab; + transform: scale(0.7); + width: 40px; + margin-left: -30px; + + ::ng-deep svg { + fill: var(--iqser-grey-7); + } + } + } + + .right-content { + visibility: hidden; + flex: 1; + justify-content: flex-end; + align-items: center; + gap: 5px; + + .arrow-right { + transform: scale(0.7); + } + } +} + +.content-container { + background-color: var(--iqser-grey-6); + + .content-header { + display: flex; + height: 50px; + background-color: var(--iqser-grey-6); + align-items: center; + padding: 0 24px; + + .actions { + display: flex; + flex: 1; + justify-content: flex-end; + } + } + + .content { + display: flex; + gap: 20px; + height: 100%; + + .components-list { + flex: 1; + background-color: var(--iqser-white); + width: 100%; + + .header { + height: 30px; + } + + .list-item { + height: 80px; + } + + .header, + .list-item { + display: flex; + border-bottom: 1px solid var(--iqser-separator); + + .item-content { + @extend %item-content-style; + } + } + + .list-item:hover, + .selected { + cursor: pointer; + + .item-content { + background-color: var(--iqser-grey-8); + + .right-content { + visibility: visible; + } + } + } + } + + section { + background-color: var(--iqser-white); + border-radius: 8px; + width: 700px; + height: 470px; + margin-right: 150px; + + .technical-name { + min-height: 16px; + } + } + } +} + +.cdk-drag-preview { + .item-content { + @extend %item-content-style; + } +} diff --git a/apps/red-ui/src/app/modules/admin/screens/component-definitions/component-definitions.component.ts b/apps/red-ui/src/app/modules/admin/screens/component-definitions/component-definitions.component.ts new file mode 100644 index 000000000..31130e284 --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/screens/component-definitions/component-definitions.component.ts @@ -0,0 +1,139 @@ +import { Component, OnInit, signal } from '@angular/core'; +import { + BaseFormComponent, + CircleButtonComponent, + IconButtonComponent, + IqserDialog, + listingProvidersFactory, + LoadingService, +} from '@iqser/common-ui'; +import { ComponentDefinitionsService } from '@services/entity-services/component-definitions.service'; +import { firstValueFrom } from 'rxjs'; +import { getParam } from '@common-ui/utils'; +import { DOSSIER_TEMPLATE_ID, IComponentDefinition } from '@red/domain'; +import { toObservable } from '@angular/core/rxjs-interop'; +import { InputWithActionComponent } from '@common-ui/inputs/input-with-action/input-with-action.component'; +import { CommonModule, NgIf } from '@angular/common'; +import { TranslateModule } from '@ngx-translate/core'; +import { PermissionsService } from '@services/permissions.service'; +import { MatIcon } from '@angular/material/icon'; +import { CdkDrag, CdkDragDrop, CdkDragHandle, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop'; +import { FormBuilder, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; +import { AdminDialogService } from '../../services/admin-dialog.service'; + +@Component({ + templateUrl: './component-definitions.component.html', + styleUrls: ['./component-definitions.component.scss'], + providers: listingProvidersFactory(ComponentDefinitionsComponent), + standalone: true, + imports: [ + IconButtonComponent, + InputWithActionComponent, + NgIf, + TranslateModule, + CommonModule, + MatIcon, + CdkDragHandle, + CdkDropList, + CdkDrag, + FormsModule, + ReactiveFormsModule, + CircleButtonComponent, + ], +}) +export default class ComponentDefinitionsComponent extends BaseFormComponent implements OnInit { + readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); + readonly #componentDefinitions = signal([]); + protected readonly componentDefinitions$ = toObservable(this.#componentDefinitions); + protected selectedComponent: IComponentDefinition | null = null; + + constructor( + private readonly _loadingService: LoadingService, + private readonly _componentDefinitionsService: ComponentDefinitionsService, + private readonly _dialog: IqserDialog, + private readonly _formBuilder: FormBuilder, + private readonly _dialogService: AdminDialogService, + protected readonly permissionsService: PermissionsService, + ) { + super(); + } + + async ngOnInit() { + this._loadingService.stop(); + await this.#loadData(); + } + + async #loadData() { + const componentDefinitions = await firstValueFrom( + this._componentDefinitionsService.getComponentDefinitions(this.#dossierTemplateId), + ); + this.#componentDefinitions.set(componentDefinitions); + } + + async createEmptyComponentDefinition() { + this.selectedComponent = { + displayName: '', + description: '', + } as IComponentDefinition; + this.initForm(); + } + + async save() { + if (this.selectedComponent.id) { + const component = { ...this.form.getRawValue(), id: this.selectedComponent.id }; + await firstValueFrom(this._componentDefinitionsService.updateComponentDefinition(this.#dossierTemplateId, component)); + } else { + const component = { + ...this.form.getRawValue(), + dossierTemplateId: this.#dossierTemplateId, + technicalName: this.technicalName, + }; + await firstValueFrom(this._componentDefinitionsService.createComponentDefinition(this.#dossierTemplateId, component)); + } + await this.#loadData(); + this.selectComponent(); + await this.initForm(); + } + + async drop(event: CdkDragDrop) { + moveItemInArray(this.#componentDefinitions(), event.previousIndex, event.currentIndex); + + const componentIds = this.#componentDefinitions().map(c => c.id); + const componentDefinitions = await firstValueFrom( + this._componentDefinitionsService.reorderComponentDefinitions(this.#dossierTemplateId, componentIds), + ); + this.#componentDefinitions.set(componentDefinitions); + } + + async deleteComponent(componentId: string) { + this._dialogService.openDialog('confirm', null, async () => { + await firstValueFrom(this._componentDefinitionsService.deleteComponentDefinitions(this.#dossierTemplateId, [componentId])); + await this.#loadData(); + }); + } + + initForm() { + this.form = this.#getForm(); + this.initialFormValue = this.form.getRawValue(); + } + + #getForm() { + return this._formBuilder.group({ + displayName: [this.selectedComponent.displayName, Validators.required], + description: [this.selectedComponent.description], + }); + } + + selectComponent(component?: IComponentDefinition) { + if (component && this.selectedComponent?.id !== component.id) { + this.selectedComponent = component; + this.initForm(); + return; + } + this.selectedComponent = null; + } + + get technicalName() { + return this.selectedComponent.technicalName ?? this.form.get('displayName')?.value?.toLowerCase().trim().replace(/\s+/g, '_'); + } +} diff --git a/apps/red-ui/src/app/modules/admin/shared/components/admin-side-nav/admin-side-nav.component.ts b/apps/red-ui/src/app/modules/admin/shared/components/admin-side-nav/admin-side-nav.component.ts index 721c2b99c..06e32ac68 100644 --- a/apps/red-ui/src/app/modules/admin/shared/components/admin-side-nav/admin-side-nav.component.ts +++ b/apps/red-ui/src/app/modules/admin/shared/components/admin-side-nav/admin-side-nav.component.ts @@ -111,6 +111,11 @@ export class AdminSideNavComponent implements OnInit { label: _('admin-side-nav.component-mappings'), show: this.isDocumine, }, + { + screen: 'components', + label: _('admin-side-nav.components'), + show: this.isDocumine, + }, { screen: 'default-colors', label: _('admin-side-nav.default-colors'), diff --git a/apps/red-ui/src/app/services/entity-services/component-definitions.service.ts b/apps/red-ui/src/app/services/entity-services/component-definitions.service.ts new file mode 100644 index 000000000..15530c08f --- /dev/null +++ b/apps/red-ui/src/app/services/entity-services/component-definitions.service.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { EntitiesService, QueryParam } from '@iqser/common-ui'; +import { ComponentDefinition, IComponentDefinition } from '@red/domain'; +import { List } from '@common-ui/utils'; +import { map } from 'rxjs/operators'; + +@Injectable({ + providedIn: 'root', +}) +export class ComponentDefinitionsService extends EntitiesService { + getComponentDefinitions(dossierTemplateId: string): Observable { + return this._http + .get(`/api/dossier-templates/${dossierTemplateId}/component-definitions`) + .pipe(map(componentDefinitions => this.#sortComponents(componentDefinitions))); + } + + createComponentDefinition(dossierTemplateId: string, componentDefinition: IComponentDefinition): Observable { + return this._http.post(`/api/dossier-templates/${dossierTemplateId}/component-definitions`, [ + componentDefinition, + ]); + } + + updateComponentDefinition(dossierTemplateId: string, componentDefinition: IComponentDefinition): Observable { + return this._http.put(`/api/dossier-templates/${dossierTemplateId}/component-definitions`, [ + componentDefinition, + ]); + } + + deleteComponentDefinitions(dossierTemplateId: string, componentIds: string[]): Observable { + const queryParams: List = [{ key: 'componentIds', value: componentIds.join(',') }]; + + return this._http.delete(`/api/dossier-templates/${dossierTemplateId}/component-definitions`, { + params: this._queryParams(queryParams), + }); + } + + reorderComponentDefinitions(dossierTemplateId: string, componentIds: string[]): Observable { + const queryParams: List = [{ key: 'componentIds', value: componentIds.join(',') }]; + + return this._http + .get(`/api/dossier-templates/${dossierTemplateId}/component-definitions/reorder`, { + params: this._queryParams(queryParams), + }) + .pipe(map(componentDefinitions => this.#sortComponents(componentDefinitions))); + } + + #sortComponents(componentDefinitions: IComponentDefinition[]) { + return componentDefinitions.sort((a, b) => a.rank - b.rank); + } +} diff --git a/apps/red-ui/src/assets/i18n/redact/de.json b/apps/red-ui/src/assets/i18n/redact/de.json index 51226c471..9aa4ef101 100644 --- a/apps/red-ui/src/assets/i18n/redact/de.json +++ b/apps/red-ui/src/assets/i18n/redact/de.json @@ -249,6 +249,7 @@ "audit": "Benutzeraktivitäten", "component-mappings": "Komponenten-Mappings", "component-rule-editor": "", + "components": "", "configurations": "Systemkonfiguration", "default-colors": "Standardfarben", "dictionary": "Wörterbuch", @@ -271,9 +272,6 @@ "watermarks": "Wasserzeichen" }, "analysis-disabled": "", - "annotation": { - "pending": "(Analyse steht aus)" - }, "annotation-actions": { "accept-recommendation": { "label": "Empfehlung annehmen" @@ -329,14 +327,14 @@ "error": "Rekategorisierung des Bilds fehlgeschlagen: {error}", "success": "Bild wurde einer neuen Kategorie zugeordnet." }, - "remove": { - "error": "Entfernen der Schwärzung fehlgeschlagen: {error}", - "success": "Schwärzung wurde entfernt" - }, "remove-hint": { "error": "Entfernen des Hinweises fehlgeschlagen: {error}", "success": "Hinweis wurde entfernt" }, + "remove": { + "error": "Entfernen der Schwärzung fehlgeschlagen: {error}", + "success": "Schwärzung wurde entfernt" + }, "undo": { "error": "Die Aktion konnte nicht rückgängig gemacht werden. Fehler: {error}", "success": "Rücksetzung erfolgreich" @@ -349,15 +347,15 @@ "remove-highlights": { "label": "Ausgewählte Markierungen entfernen" }, - "resize": { - "label": "Größe ändern" - }, "resize-accept": { "label": "Neue Größe speichern" }, "resize-cancel": { "label": "Größenänderung abbrechen" }, + "resize": { + "label": "Größe ändern" + }, "see-references": { "label": "Referenzen anzeigen" }, @@ -391,6 +389,9 @@ "skipped": "Ignorierte Schwärzung", "text-highlight": "Markierung" }, + "annotation": { + "pending": "(Analyse steht aus)" + }, "annotations": "Annotationen", "archived-dossiers-listing": { "no-data": { @@ -511,6 +512,28 @@ "title": "Aktion bestätigen" } }, + "component-definitions": { + "actions": { + "revert": "", + "save": "" + }, + "add-new": "", + "add-title": "", + "columns": { + "name": "", + "position": "" + }, + "edit-title": "", + "form": { + "autogenerated-label": "", + "description": "", + "description-placeholder": "", + "display-name": "", + "display-name-placeholder": "", + "technical-name-label": "" + }, + "title": "" + }, "component-download": { "disabled-tooltip": "", "json": "", @@ -613,18 +636,14 @@ "warning": "Warnung: Wiederherstellung des Benutzers nicht möglich." }, "confirmation-dialog": { - "approve-file": { - "question": "Dieses Dokument enthält ungesehene Änderungen, die sich durch die Reanalyse ergeben haben.

Möchten Sie es trotzdem freigeben?", - "title": "Warnung!" - }, "approve-file-without-analysis": { "confirmationText": "Ohne Analyse freigeben", "denyText": "Abbrechen", "question": "Analyse zur Erkennung neuer Schwärzungen erforderlich.", "title": "Warnung!" }, - "approve-multiple-files": { - "question": "Mindestens eine der ausgewählten Dateien enthält ungesehene Änderungen, die im Zuge einer Reanalyse hinzugefügt wurden.

Möchen Sie die Dateien wirklich freigeben?", + "approve-file": { + "question": "Dieses Dokument enthält ungesehene Änderungen, die sich durch die Reanalyse ergeben haben.

Möchten Sie es trotzdem freigeben?", "title": "Warnung!" }, "approve-multiple-files-without-analysis": { @@ -633,6 +652,10 @@ "question": "Für mindestens eine Datei ist ein Analyselauf zur Erkennung neuer Schwärzungen erforderlich.", "title": "Warnung" }, + "approve-multiple-files": { + "question": "Mindestens eine der ausgewählten Dateien enthält ungesehene Änderungen, die im Zuge einer Reanalyse hinzugefügt wurden.

Möchen Sie die Dateien wirklich freigeben?", + "title": "Warnung!" + }, "assign-file-to-me": { "question": { "multiple": "Dieses Dokument wird gerade von einer anderen Person geprüft.

Möchten Sie sich die Datei dennoch zuweisen?", @@ -1002,13 +1025,13 @@ "recent": "Neu ({hours} h)", "unassigned": "Keinem Bearbeiter zugewiesen" }, - "reanalyse": { - "action": "Datei analysieren" - }, "reanalyse-dossier": { "error": "Einplanung der Dateien für die Reanalyse fehlgeschlagen. Bitte versuchen Sie es noch einmal.", "success": "Dateien für Reanalyse vorgesehen." }, + "reanalyse": { + "action": "Datei analysieren" + }, "start-auto-analysis": "Auto-Analyse aktivieren", "stop-auto-analysis": "Auto-Analyse anhalten", "table-col-names": { @@ -1078,19 +1101,10 @@ "total-documents": "Dokumente", "total-people": "{count} {count, plural, one{Benutzer} other {Benutzer}}" }, - "dossier-templates": { - "label": "Dossier-Vorlagen", - "status": { - "active": "Aktiv", - "inactive": "Inaktiv", - "incomplete": "Unvollständig" - } - }, "dossier-templates-listing": { "action": { "clone": "Vorlage klonen", - "delete": "Vorlage löschen", - "edit": "Vorlage bearbeiten" + "delete": "Vorlage löschen" }, "add-new": "Neue Dossier-Vorlage", "bulk": { @@ -1121,6 +1135,14 @@ "title": "{length} {length, plural, one{Dossier-Vorlage} other{Dossier-Vorlagen}}" } }, + "dossier-templates": { + "label": "Dossier-Vorlagen", + "status": { + "active": "Aktiv", + "inactive": "Inaktiv", + "incomplete": "Unvollständig" + } + }, "dossier-watermark-selector": { "heading": "Wasserzeichen auf Dokumenten", "no-watermark": "Kein Wasserzeichen in der Dossier-Vorlage verfügbar:
Bitten Sie Ihren Admin, eines zu konfigurieren.", @@ -1316,15 +1338,6 @@ "title": "{length} {length, plural, one{Wörterbuch} other{Wörterbücher}}" } }, - "entity": { - "info": { - "actions": { - "revert": "Zurücksetzen", - "save": "Änderungen speichern" - }, - "heading": "Entität bearbeiten" - } - }, "entity-rules-screen": { "error": { "generic": "Fehler: Aktualisierung der Entitätsregeln fehlgeschlagen." @@ -1339,19 +1352,28 @@ "warning-text": "Warnung: experimentelle Funktion!", "warnings-found": "{warnings, plural, one{A warning} other{{warnings} warnings}} in Regeln gefunden" }, + "entity": { + "info": { + "actions": { + "revert": "Zurücksetzen", + "save": "Änderungen speichern" + }, + "heading": "Entität bearbeiten" + } + }, "error": { "deleted-entity": { "dossier": { "action": "Zurück zur Übersicht", "label": "Dieses Dossier wurde gelöscht!" }, - "file": { - "action": "Zurück zum Dossier", - "label": "Diese Datei wurde gelöscht!" - }, "file-dossier": { "action": "Zurück zur Übersicht", "label": "Das Dossier dieser Datei wurde gelöscht!" + }, + "file": { + "action": "Zurück zum Dossier", + "label": "Diese Datei wurde gelöscht!" } }, "file-preview": { @@ -1369,12 +1391,6 @@ }, "exact-date": "{day}. {month} {year} um {hour}:{minute} Uhr", "file": "Datei", - "file-attribute": { - "update": { - "error": "Aktualisierung des Werts für das Datei-Attribut fehlgeschlagen. Bitte versuchen Sie es noch einmal.", - "success": "Der Wert für das Dateiattribut wurde erfolgreich aktualisiert." - } - }, "file-attribute-encoding-types": { "ascii": "ASCII", "iso": "ISO-8859-1", @@ -1385,6 +1401,12 @@ "number": "Nummer", "text": "Freier Text" }, + "file-attribute": { + "update": { + "error": "Aktualisierung des Werts für das Datei-Attribut fehlgeschlagen. Bitte versuchen Sie es noch einmal.", + "success": "Der Wert für das Dateiattribut wurde erfolgreich aktualisiert." + } + }, "file-attributes-configurations": { "cancel": "Abbrechen", "form": { @@ -1602,15 +1624,6 @@ "csv": "Die Datei-Attribute wurden erfolgreich aus der hochgeladenen CSV-Datei importiert." } }, - "filter": { - "analysis": "Analyse erforderlich", - "comment": "Kommentare", - "hint": "Nur Hinweise", - "image": "Bilder", - "none": "Keine Annotationen", - "redaction": "Schwärzungen", - "updated": "Aktualisiert" - }, "filter-menu": { "filter-options": "Filteroptionen", "filter-types": "Filter", @@ -1620,6 +1633,15 @@ "unseen-pages": "Nur Annotationen auf ungesehenen Seiten", "with-comments": "Nur Annotationen mit Kommentaren" }, + "filter": { + "analysis": "Analyse erforderlich", + "comment": "Kommentare", + "hint": "Nur Hinweise", + "image": "Bilder", + "none": "Keine Annotationen", + "redaction": "Schwärzungen", + "updated": "Aktualisiert" + }, "filters": { "assigned-people": "Bearbeiter", "documents-status": "Dokumentenstatus", @@ -1898,13 +1920,6 @@ "user-promoted-to-approver": "{user} wurde im Dossier {dossierHref, select, null{{dossierName}} other{{dossierName}}} zum Genehmiger ernannt!", "user-removed-as-dossier-member": "{user} wurde als Mitglied von: {dossierHref, select, null{{dossierName}} other{{dossierName}}} entfernt!" }, - "notifications": { - "button-text": "Benachrichtigungen", - "deleted-dossier": "Gelöschtes Dossier", - "label": "Benachrichtigungen", - "mark-all-as-read": "Alle als gelesen markieren", - "mark-as": "Als {type, select, read{gelesen} unread{ungelesen} other{}} markieren" - }, "notifications-screen": { "category": { "email-notifications": "E-Mail-Benachrichtigungen", @@ -1918,6 +1933,7 @@ "dossier": "Benachrichtigungen zu Dossiers", "other": "Andere Benachrichtigungen" }, + "options-title": "Wählen Sie aus, bei welchen Aktivitäten Sie benachrichtigt werden möchten", "options": { "ASSIGN_APPROVER": "Wenn ich einem Dokument als Genehmiger zugewiesen werde", "ASSIGN_REVIEWER": "Wenn ich einem Dokument als Prüfer zugewiesen werde", @@ -1935,7 +1951,6 @@ "USER_PROMOTED_TO_APPROVER": "Wenn ich Genehmiger in einem Dossier werde", "USER_REMOVED_AS_DOSSIER_MEMBER": "Wenn ich die Dossier-Mitgliedschaft verliere" }, - "options-title": "Wählen Sie aus, bei welchen Aktivitäten Sie benachrichtigt werden möchten", "schedule": { "daily": "Tägliche Zusammenfassung", "instant": "Sofort", @@ -1943,6 +1958,13 @@ }, "title": "Benachrichtigungseinstellungen" }, + "notifications": { + "button-text": "Benachrichtigungen", + "deleted-dossier": "Gelöschtes Dossier", + "label": "Benachrichtigungen", + "mark-all-as-read": "Alle als gelesen markieren", + "mark-as": "Als {type, select, read{gelesen} unread{ungelesen} other{}} markieren" + }, "ocr": { "confirmation-dialog": { "cancel": "Abbrechen", @@ -2034,16 +2056,16 @@ "warnings-label": "Dialoge und Meldungen", "warnings-subtitle": "„Nicht mehr anzeigen“-Optionen" }, - "processing": { - "basic": "Verarbeitung läuft", - "ocr": "OCR" - }, "processing-status": { "ocr": "OCR", "pending": "Ausstehend", "processed": "verarbeitet", "processing": "Verarbeitung läuft" }, + "processing": { + "basic": "Verarbeitung läuft", + "ocr": "OCR" + }, "readonly": "Lesemodus", "readonly-archived": "Lesemodus (archiviert)", "redact-text": { @@ -2279,12 +2301,6 @@ "red-user-admin": "Benutzeradmin", "regular": "regulärer Benutzer" }, - "search": { - "active-dossiers": "Dokumente in aktiven Dossiers", - "all-dossiers": "Alle Dokumente", - "placeholder": "Dokumente durchsuchen...", - "this-dossier": "In diesem Dossier" - }, "search-screen": { "cols": { "assignee": "Bearbeiter", @@ -2308,6 +2324,12 @@ "no-match": "Suchbegriff wurde in keinem der Dokumente gefunden.", "table-header": "{length} {length, plural, one{Suchergebnis} other{Suchergebnisse}}" }, + "search": { + "active-dossiers": "Dokumente in aktiven Dossiers", + "all-dossiers": "Alle Dokumente", + "placeholder": "Dokumente durchsuchen...", + "this-dossier": "In diesem Dossier" + }, "seconds": "Sekunden", "size": "Größe", "smtp-auth-config": { @@ -2563,4 +2585,4 @@ } }, "yesterday": "Gestern" -} \ No newline at end of file +} diff --git a/apps/red-ui/src/assets/i18n/redact/en.json b/apps/red-ui/src/assets/i18n/redact/en.json index b91aa7e12..048d1168c 100644 --- a/apps/red-ui/src/assets/i18n/redact/en.json +++ b/apps/red-ui/src/assets/i18n/redact/en.json @@ -249,6 +249,7 @@ "audit": "Audit", "component-mappings": "Component mappings", "component-rule-editor": "", + "components": "Components", "configurations": "Configurations", "default-colors": "Default colors", "dictionary": "Dictionary", @@ -511,6 +512,28 @@ "title": "Confirm action" } }, + "component-definitions": { + "actions": { + "revert": "Revert", + "save": "Save Changes" + }, + "add-new": "New Component", + "add-title": "Add new definition", + "columns": { + "name": "name", + "position": "pos." + }, + "edit-title": "Edit {displayName} definition", + "form": { + "autogenerated-label": "Autogenerated based on the initial display name", + "description": "Description", + "description-placeholder": "Description", + "display-name": "Display Name", + "display-name-placeholder": "Display Name", + "technical-name-label": "Technical name" + }, + "title": "{length} {length, plural, one{component} other{components}}" + }, "component-download": { "disabled-tooltip": "", "json": "", @@ -1081,8 +1104,7 @@ "dossier-templates-listing": { "action": { "clone": "Clone template", - "delete": "Delete template", - "edit": "Edit template" + "delete": "Delete template" }, "add-new": "New dossier template", "bulk": { @@ -2563,4 +2585,4 @@ } }, "yesterday": "Yesterday" -} \ No newline at end of file +} diff --git a/apps/red-ui/src/assets/i18n/scm/de.json b/apps/red-ui/src/assets/i18n/scm/de.json index a2e32ced8..58e927522 100644 --- a/apps/red-ui/src/assets/i18n/scm/de.json +++ b/apps/red-ui/src/assets/i18n/scm/de.json @@ -249,6 +249,7 @@ "audit": "Audit", "component-mappings": "Component mappings", "component-rule-editor": "Component rule editor", + "components": "", "configurations": "Configurations", "default-colors": "Default colors", "dictionary": "Dictionary", @@ -271,9 +272,6 @@ "watermarks": "Watermarks" }, "analysis-disabled": "Analysis disabled", - "annotation": { - "pending": "(Pending analysis)" - }, "annotation-actions": { "accept-recommendation": { "label": "Empfehlung annehmen" @@ -329,14 +327,14 @@ "error": "Rekategorisierung des Bildes gescheitert: {error}", "success": "Bild wurde einer neuen Kategorie zugeordnet." }, - "remove": { - "error": "Fehler beim Entfernen der Schwärzung: {error}", - "success": "Schwärzung entfernt!" - }, "remove-hint": { "error": "Failed to remove hint: {error}", "success": "Hint removed!" }, + "remove": { + "error": "Fehler beim Entfernen der Schwärzung: {error}", + "success": "Schwärzung entfernt!" + }, "undo": { "error": "Die Aktion konnte nicht rückgängig gemacht werden. Fehler: {error}", "success": "erfolgreich Rückgängig gemacht" @@ -349,15 +347,15 @@ "remove-highlights": { "label": "Remove selected earmarks" }, - "resize": { - "label": "Größe ändern" - }, "resize-accept": { "label": "Größe speichern" }, "resize-cancel": { "label": "Größenänderung abbrechen" }, + "resize": { + "label": "Größe ändern" + }, "see-references": { "label": "See references" }, @@ -391,6 +389,9 @@ "skipped": "Übersprungen", "text-highlight": "Earmark" }, + "annotation": { + "pending": "(Pending analysis)" + }, "annotations": "Annotations", "archived-dossiers-listing": { "no-data": { @@ -511,6 +512,28 @@ "title": "Aktion bestätigen" } }, + "component-definitions": { + "actions": { + "revert": "", + "save": "" + }, + "add-new": "", + "add-title": "", + "columns": { + "name": "", + "position": "" + }, + "edit-title": "", + "form": { + "autogenerated-label": "", + "description": "", + "description-placeholder": "", + "display-name": "", + "display-name-placeholder": "", + "technical-name-label": "" + }, + "title": "" + }, "component-download": { "disabled-tooltip": "All files must be processed to be able to export the components as JSON or XML", "json": "Download as JSON", @@ -613,18 +636,14 @@ "warning": "Achtung: Diese Aktion kann nicht rückgängig gemacht werden!" }, "confirmation-dialog": { - "approve-file": { - "question": "Dieses Dokument enthält ungesehene Änderungen. Möchten Sie es trotzdem genehmigen?", - "title": "Warnung!" - }, "approve-file-without-analysis": { "confirmationText": "Approve without analysis", "denyText": "Cancel", "question": "Analysis required to detect new components.", "title": "Warning!" }, - "approve-multiple-files": { - "question": "Mindestens eine der ausgewählten Dateien enthält ungesehene Änderungen. Möchten Sie sie trotzdem genehmigen?", + "approve-file": { + "question": "Dieses Dokument enthält ungesehene Änderungen. Möchten Sie es trotzdem genehmigen?", "title": "Warnung!" }, "approve-multiple-files-without-analysis": { @@ -633,6 +652,10 @@ "question": "Analysis required to detect new components for at least one file.", "title": "Warning" }, + "approve-multiple-files": { + "question": "Mindestens eine der ausgewählten Dateien enthält ungesehene Änderungen. Möchten Sie sie trotzdem genehmigen?", + "title": "Warnung!" + }, "assign-file-to-me": { "question": { "multiple": "Dieses Dokument wird gerade von einer anderen Person geprüft. Möchten Sie Reviewer werden und sich selbst dem Dokument zuweisen?", @@ -1002,13 +1025,13 @@ "recent": "Neu ({hours} h)", "unassigned": "Niemandem zugewiesen" }, - "reanalyse": { - "action": "Datei analysieren" - }, "reanalyse-dossier": { "error": "Die Dateien konnten nicht für eine Reanalyse eingeplant werden. Bitte versuchen Sie es erneut.", "success": "Dateien für Reanalyse vorgesehen." }, + "reanalyse": { + "action": "Datei analysieren" + }, "start-auto-analysis": "Enable auto-analysis", "stop-auto-analysis": "Stop auto-analysis", "table-col-names": { @@ -1078,19 +1101,10 @@ "total-documents": "Anzahl der Dokumente", "total-people": "{count} {count, plural, one{user} other {users}}" }, - "dossier-templates": { - "label": "Dossier-Vorlagen", - "status": { - "active": "Active", - "inactive": "Inactive", - "incomplete": "Incomplete" - } - }, "dossier-templates-listing": { "action": { "clone": "Clone template", - "delete": "Dossier-Vorlage", - "edit": "Vorlage bearbeiten" + "delete": "Dossier-Vorlage" }, "add-new": "Neue Dossier-Vorlage", "bulk": { @@ -1121,6 +1135,14 @@ "title": "{length} dossier {length, plural, one{template} other{templates}}" } }, + "dossier-templates": { + "label": "Dossier-Vorlagen", + "status": { + "active": "Active", + "inactive": "Inactive", + "incomplete": "Incomplete" + } + }, "dossier-watermark-selector": { "heading": "Watermarks on documents", "no-watermark": "There is no watermark defined for the dossier template.
Contact your app admin to define one.", @@ -1316,15 +1338,6 @@ "title": "{length} {length, plural, one{entity} other{entities}}" } }, - "entity": { - "info": { - "actions": { - "revert": "Revert", - "save": "Save changes" - }, - "heading": "Edit entity" - } - }, "entity-rules-screen": { "error": { "generic": "Something went wrong... Entity rules update failed!" @@ -1339,19 +1352,28 @@ "warning-text": "Warning: experimental feature!", "warnings-found": "{warnings, plural, one{A warning} other{{warnings} warnings}} found in rules" }, + "entity": { + "info": { + "actions": { + "revert": "Revert", + "save": "Save changes" + }, + "heading": "Edit entity" + } + }, "error": { "deleted-entity": { "dossier": { "action": "Zurück zur Übersicht", "label": "Dieses Dossier wurde gelöscht!" }, - "file": { - "action": "Zurück zum Dossier", - "label": "Diese Datei wurde gelöscht!" - }, "file-dossier": { "action": "Zurück zur Übersicht", "label": "Das Dossier dieser Datei wurde gelöscht!" + }, + "file": { + "action": "Zurück zum Dossier", + "label": "Diese Datei wurde gelöscht!" } }, "file-preview": { @@ -1369,12 +1391,6 @@ }, "exact-date": "{day} {month} {year} um {hour}:{minute} Uhr", "file": "Datei", - "file-attribute": { - "update": { - "error": "Failed to update file attribute value!", - "success": "File attribute value has been updated successfully!" - } - }, "file-attribute-encoding-types": { "ascii": "ASCII", "iso": "ISO-8859-1", @@ -1385,6 +1401,12 @@ "number": "Nummer", "text": "Freier Text" }, + "file-attribute": { + "update": { + "error": "Failed to update file attribute value!", + "success": "File attribute value has been updated successfully!" + } + }, "file-attributes-configurations": { "cancel": "Cancel", "form": { @@ -1602,15 +1624,6 @@ "csv": "File attributes were imported successfully from uploaded CSV file." } }, - "filter": { - "analysis": "Analyse erforderlich", - "comment": "Kommentare", - "hint": "Nut Hinweise", - "image": "Bilder", - "none": "Keine Anmerkungen", - "redaction": "Geschwärzt", - "updated": "Aktualisiert" - }, "filter-menu": { "filter-options": "Filteroptionen", "filter-types": "Filter", @@ -1620,6 +1633,15 @@ "unseen-pages": "Nur Anmerkungen auf unsichtbaren Seiten", "with-comments": "Nur Anmerkungen mit Kommentaren" }, + "filter": { + "analysis": "Analyse erforderlich", + "comment": "Kommentare", + "hint": "Nut Hinweise", + "image": "Bilder", + "none": "Keine Anmerkungen", + "redaction": "Geschwärzt", + "updated": "Aktualisiert" + }, "filters": { "assigned-people": "Beauftragt", "documents-status": "Documents state", @@ -1898,13 +1920,6 @@ "user-promoted-to-approver": "{user} wurde im Dossier {dossierHref, select, null{{dossierName}} other{{dossierName}}} zum Genehmiger ernannt!", "user-removed-as-dossier-member": "{user} wurde als Mitglied von: {dossierHref, select, null{{dossierName}} other{{dossierName}}} entfernt!" }, - "notifications": { - "button-text": "Notifications", - "deleted-dossier": "Deleted dossier", - "label": "Benachrichtigungen", - "mark-all-as-read": "Alle als gelesen markieren", - "mark-as": "Mark as {type, select, read{read} unread{unread} other{}}" - }, "notifications-screen": { "category": { "email-notifications": "E-Mail Benachrichtigungen", @@ -1918,6 +1933,7 @@ "dossier": "Dossierbezogene Benachrichtigungen", "other": "Andere Benachrichtigungen" }, + "options-title": "Wählen Sie aus, in welcher Kategorie Sie benachrichtigt werden möchten", "options": { "ASSIGN_APPROVER": "Wenn ich einem Dokument als Genehmiger zugewiesen bin", "ASSIGN_REVIEWER": "Wenn ich einem Dokument als Überprüfer zugewiesen bin", @@ -1935,7 +1951,6 @@ "USER_PROMOTED_TO_APPROVER": "Wenn ich Genehmiger in einem Dossier werde", "USER_REMOVED_AS_DOSSIER_MEMBER": "Wenn ich die Dossier-Mitgliedschaft verliere" }, - "options-title": "Wählen Sie aus, in welcher Kategorie Sie benachrichtigt werden möchten", "schedule": { "daily": "Tägliche Zusammenfassung", "instant": "Sofortig", @@ -1943,6 +1958,13 @@ }, "title": "Benachrichtigungseinstellungen" }, + "notifications": { + "button-text": "Notifications", + "deleted-dossier": "Deleted dossier", + "label": "Benachrichtigungen", + "mark-all-as-read": "Alle als gelesen markieren", + "mark-as": "Mark as {type, select, read{read} unread{unread} other{}}" + }, "ocr": { "confirmation-dialog": { "cancel": "Cancel", @@ -2034,16 +2056,16 @@ "warnings-label": "Prompts and dialogs", "warnings-subtitle": "Do not show again options" }, - "processing": { - "basic": "Processing", - "ocr": "OCR" - }, "processing-status": { "ocr": "OCR", "pending": "Pending", "processed": "Processed", "processing": "Processing" }, + "processing": { + "basic": "Processing", + "ocr": "OCR" + }, "readonly": "Lesemodus", "readonly-archived": "Read only (archived)", "redact-text": { @@ -2279,12 +2301,6 @@ "red-user-admin": "Benutzer-Admin", "regular": "Regulär" }, - "search": { - "active-dossiers": "ganze Plattform", - "all-dossiers": "all documents", - "placeholder": "Nach Dokumenten oder Dokumenteninhalt suchen", - "this-dossier": "in diesem Dossier" - }, "search-screen": { "cols": { "assignee": "Bevollmächtigter", @@ -2308,6 +2324,12 @@ "no-match": "Keine Dokumente entsprechen Ihren aktuellen Filtern.", "table-header": "{length} search {length, plural, one{result} other{results}}" }, + "search": { + "active-dossiers": "ganze Plattform", + "all-dossiers": "all documents", + "placeholder": "Nach Dokumenten oder Dokumenteninhalt suchen", + "this-dossier": "in diesem Dossier" + }, "seconds": "seconds", "size": "Size", "smtp-auth-config": { @@ -2563,4 +2585,4 @@ } }, "yesterday": "Gestern" -} \ No newline at end of file +} diff --git a/apps/red-ui/src/assets/i18n/scm/en.json b/apps/red-ui/src/assets/i18n/scm/en.json index 7cc2c4321..ca2cd01e7 100644 --- a/apps/red-ui/src/assets/i18n/scm/en.json +++ b/apps/red-ui/src/assets/i18n/scm/en.json @@ -249,6 +249,7 @@ "audit": "Audit", "component-mappings": "Component mappings", "component-rule-editor": "Component rule editor", + "components": "Components", "configurations": "Configurations", "default-colors": "Default colors", "dictionary": "Dictionary", @@ -511,6 +512,28 @@ "title": "Confirm action" } }, + "component-definitions": { + "actions": { + "revert": "Revert", + "save": "Save Changes" + }, + "add-new": "New Component", + "add-title": "Add new definition", + "columns": { + "name": "name", + "position": "pos." + }, + "edit-title": "Edit {displayName} definition", + "form": { + "autogenerated-label": "Autogenerated based on the initial display name", + "description": "Description", + "description-placeholder": "Description", + "display-name": "Display Name", + "display-name-placeholder": "Display Name", + "technical-name-label": "Technical name" + }, + "title": "{length} {length, plural, one{component} other{components}}" + }, "component-download": { "disabled-tooltip": "All files must be processed to be able to export the components as JSON or XML", "json": "Download as JSON", @@ -1081,8 +1104,7 @@ "dossier-templates-listing": { "action": { "clone": "Clone template", - "delete": "Delete template", - "edit": "Edit template" + "delete": "Delete template" }, "add-new": "New dossier template", "bulk": { @@ -2563,4 +2585,4 @@ } }, "yesterday": "Yesterday" -} \ No newline at end of file +} diff --git a/libs/red-domain/src/index.ts b/libs/red-domain/src/index.ts index 4d040b981..34cacab3f 100644 --- a/libs/red-domain/src/index.ts +++ b/libs/red-domain/src/index.ts @@ -30,3 +30,4 @@ export * from './lib/watermarks'; export * from './lib/colors'; export * from './lib/component-log'; export * from './lib/component-mappings'; +export * from './lib/component-definitions'; diff --git a/libs/red-domain/src/lib/component-definitions/component-definition.ts b/libs/red-domain/src/lib/component-definitions/component-definition.ts new file mode 100644 index 000000000..dd3befece --- /dev/null +++ b/libs/red-domain/src/lib/component-definitions/component-definition.ts @@ -0,0 +1,32 @@ +import { IListable } from '@iqser/common-ui'; + +export interface IComponentDefinition { + id: string; + dossierTemplateId: string; + technicalName: string; + displayName: string; + description: string; + rank: number; +} + +export class ComponentDefinition implements IComponentDefinition, IListable { + readonly id: string; + readonly dossierTemplateId: string; + readonly technicalName: string; + readonly displayName: string; + readonly description: string; + readonly rank: number; + + constructor(componentDefinition: IComponentDefinition) { + this.id = componentDefinition.id; + this.dossierTemplateId = componentDefinition.dossierTemplateId; + this.technicalName = componentDefinition.technicalName; + this.displayName = componentDefinition.displayName; + this.description = componentDefinition.description; + this.rank = componentDefinition.rank; + } + + get searchKey(): string { + return this.displayName; + } +} diff --git a/libs/red-domain/src/lib/component-definitions/index.ts b/libs/red-domain/src/lib/component-definitions/index.ts new file mode 100644 index 000000000..059199d9b --- /dev/null +++ b/libs/red-domain/src/lib/component-definitions/index.ts @@ -0,0 +1 @@ +export * from './component-definition';