From d5215656fbd32ee4f7d51200ef64cfbb6408f083 Mon Sep 17 00:00:00 2001 From: Valentin Mihai Date: Fri, 22 Mar 2024 15:56:35 +0200 Subject: [PATCH] RED-8692 - Automatic code validation in the rule editor --- .../rules-screen/rules-screen.component.html | 9 +- .../rules-screen/rules-screen.component.scss | 16 +- .../rules-screen/rules-screen.component.ts | 108 ++++++++----- .../translations/rules-screen-translations.ts | 2 + .../src/app/services/editor-theme.service.ts | 8 + apps/red-ui/src/assets/i18n/redact/de.json | 151 +++++++++--------- apps/red-ui/src/assets/i18n/redact/en.json | 5 +- apps/red-ui/src/assets/i18n/scm/de.json | 151 +++++++++--------- apps/red-ui/src/assets/i18n/scm/en.json | 5 +- .../src/assets/icons/general/alert-circle.svg | 4 +- .../icons/general/alert-warning-circle.svg | 13 ++ apps/red-ui/src/styles.scss | 24 ++- 12 files changed, 293 insertions(+), 203 deletions(-) create mode 100644 apps/red-ui/src/assets/icons/general/alert-warning-circle.svg diff --git a/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.html index 84390cb22..993091559 100644 --- a/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.html @@ -9,7 +9,14 @@
- +
+ + +
diff --git a/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.scss index 0d44f017a..3156386dc 100644 --- a/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.scss +++ b/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.scss @@ -40,18 +40,30 @@ ngx-monaco-editor { .errors { cursor: pointer; + align-items: flex-start; .icon { scale: 0.7; } + .found-errors { + margin-top: 4px; + display: flex; + flex-direction: column; + gap: 5px; + } + :first-child { display: flex; - align-items: center; + align-items: flex-start; gap: 0.5em; font-weight: 500; /* TODO: Update this to --iqser-error when added */ - color: #dd4d50; + color: var(--iqser-red-1); + + .warning { + color: var(--iqser-warn); + } } .face-up { diff --git a/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.ts index 176491e25..174fdaea8 100644 --- a/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.ts @@ -17,6 +17,13 @@ interface SyntaxError { line: number; column: number; message: string; + warning: boolean; +} + +interface UploadResponse { + blacklistErrorMessages: SyntaxError[]; + syntaxErrorMessages: SyntaxError[]; + deprecatedWarnings: SyntaxError[]; } const RULE_VALIDATION_TIMEOUT = 2000; @@ -41,11 +48,13 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate { currentLines: string[] = []; isLeaving = false; readonly type: IRules['ruleFileType']; - private _codeEditor: ICodeEditor; - private _decorations: string[] = []; readonly #errorGlyphs = signal([]); - readonly numberOfErrors = computed(() => this.#errorGlyphs().length); + readonly numberOfErrors = computed(() => this.#errors().filter(e => !e.warning).length); + readonly numberOfWarnings = computed(() => this.#errors().filter(e => e.warning).length); readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); + #codeEditor: ICodeEditor; + #decorations: string[] = []; + #errors = signal([]); #ruleValidationTimeout: number = null; set isLeavingPage(isLeaving: boolean) { @@ -65,7 +74,7 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate { this.currentLines = $event.split('\n'); this.codeEditorTextChanged(); this.validateRules(); - this._closeProblemsView(); + this.#closeProblemsView(); } constructor( @@ -81,84 +90,97 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate { } async ngOnInit() { - await this._initialize(); + await this.#initialize(); } validateRules() { + if (!this.changed) { + this.#removeErrorMarkers(); + } if (this.#ruleValidationTimeout) { clearTimeout(this.#ruleValidationTimeout); } this.#ruleValidationTimeout = window.setTimeout(async () => { - await this.#uploadRules(true); + if (this.changed) { + await this.#uploadRules(true); + } }, RULE_VALIDATION_TIMEOUT); } async onCodeEditorInit(editor: ICodeEditor): Promise { - this._codeEditor = editor; + this.#codeEditor = editor; for (const theme of this._editorThemeService.themes) { (window as any).monaco.editor.defineTheme(theme, this._editorThemeService.configurations[theme]); } (window as any).monaco.editor.setTheme(this._editorThemeService.getTheme(true)); - await this._configureSyntaxHighlighting(); + await this.#configureSyntaxHighlighting(); this._changeDetectorRef.detectChanges(); } @Debounce() codeEditorTextChanged() { - const newDecorations = this.currentLines.filter(entry => this._isNew(entry)).map(entry => this._makeDecorationFor(entry)); - this._decorations = this._codeEditor.deltaDecorations(this._decorations, newDecorations); + const newDecorations = this.currentLines.filter(entry => this.#isNew(entry)).map(entry => this.#makeDecorationFor(entry)); + this.#decorations = this.#codeEditor.deltaDecorations(this.#decorations, newDecorations); } goToErrors() { - this._codeEditor.trigger(null, 'editor.action.marker.next', null); + this.#codeEditor.trigger(null, 'editor.action.marker.next', null); } async save(): Promise { this._loadingService.start(); - this._removeErrorMarkers(); + this.#removeErrorMarkers(); await this.#uploadRules(); } async #uploadRules(dryRun = false) { return firstValueFrom( this._rulesService.uploadRules({ - rules: this._getValue(), + rules: this.#getValue(), dossierTemplateId: this.#dossierTemplateId, ruleFileType: this.type, dryRun, }), ).then( - async response => { - if (dryRun) { - console.log('RESPONSE: ', response); - return; + async (response: UploadResponse) => { + const errors = this.#mapErrors(response); + this.#drawErrorMarkers(errors); + if (!dryRun) { + await this.#initialize(); + this._toaster.success(rulesScreenTranslations[this.type]['success.generic']); } - await this._initialize(); - this._toaster.success(rulesScreenTranslations[this.type]['success-generic']); }, error => { - const errors = error.error as SyntaxError[] | undefined; - this._drawErrorMarkers(errors); + const errors = this.#mapErrors(error.error); + this.#drawErrorMarkers(errors); this._loadingService.stop(); - this._toaster.success(rulesScreenTranslations[this.type]['error-generic']); + this._toaster.error(rulesScreenTranslations[this.type]['error.generic']); }, ); } revert(): void { this.currentLines = this.initialLines; - this._decorations = this._codeEditor?.deltaDecorations(this._decorations, []) || []; - this._removeErrorMarkers(); + this.#decorations = this.#codeEditor?.deltaDecorations(this.#decorations, []) || []; + this.#removeErrorMarkers(); this._changeDetectorRef.detectChanges(); this._loadingService.stop(); } - private _getValue(): string { - this._codeEditor.getModel().setEOL(monaco.editor.EndOfLineSequence.LF); - return this._codeEditor.getModel().getValue(); + #mapErrors(response: UploadResponse) { + return [ + ...response.blacklistErrorMessages, + ...response.syntaxErrorMessages, + ...response.deprecatedWarnings.map(w => ({ ...w, warning: true })), + ]; } - private async _configureSyntaxHighlighting() { + #getValue(): string { + this.#codeEditor.getModel().setEOL(monaco.editor.EndOfLineSequence.LF); + return this.#codeEditor.getModel().getValue(); + } + + async #configureSyntaxHighlighting() { const languages = (window as any).monaco.languages.getLanguages(); const javaLang = languages.find(l => l.id === 'java'); const { language: config } = await javaLang.loader(); @@ -191,11 +213,11 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate { }); } - private _isNew(entry: string): boolean { + #isNew(entry: string): boolean { return this.initialLines.indexOf(entry) < 0 && entry?.trim().length > 0; } - private _makeDecorationFor(entry: string): IModelDeltaDecoration { + #makeDecorationFor(entry: string): IModelDeltaDecoration { const line = this.currentLines.indexOf(entry) + 1; return { @@ -204,8 +226,8 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate { } as IModelDeltaDecoration; } - private _drawErrorMarkers(errors: SyntaxError[] | undefined) { - const model = this._codeEditor?.getModel(); + #drawErrorMarkers(errors: SyntaxError[] | undefined) { + const model = this.#codeEditor?.getModel(); if (!model || !errors?.length) { return; } @@ -217,7 +239,7 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate { const endColumn = model.getLineLength(e.line) + 1; markers.push({ message: e.message, - severity: monaco.MarkerSeverity.Error, + severity: e.warning ? monaco.MarkerSeverity.Warning : monaco.MarkerSeverity.Error, startLineNumber: e.line, startColumn: e.column, endLineNumber: e.line, @@ -226,29 +248,31 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate { glyphs.push({ range: new monaco.Range(e.line, e.column, e.line, endColumn), options: { - glyphMarginClassName: 'error-glyph-margin', + glyphMarginClassName: `glyph-margin ${e.warning ? 'warning' : 'error'}`, }, }); }); - this.#errorGlyphs.set(this._codeEditor.deltaDecorations(this.#errorGlyphs(), glyphs)); + this.#errors.set(errors); + this.#errorGlyphs.set(this.#codeEditor.deltaDecorations(this.#errorGlyphs(), glyphs)); (window as any).monaco.editor.setModelMarkers(model, model.id, markers); } - private _closeProblemsView(): void { - this._codeEditor.trigger(null, 'closeMarkersNavigation', null); + #closeProblemsView(): void { + this.#codeEditor.trigger(null, 'closeMarkersNavigation', null); } - private _removeErrorMarkers(): void { - const model = this._codeEditor?.getModel(); + #removeErrorMarkers(): void { + const model = this.#codeEditor?.getModel(); if (!model) { return; } (window as any).monaco.editor.setModelMarkers(model, model.id, []); - this.#errorGlyphs.set(this._codeEditor.deltaDecorations(this.#errorGlyphs(), []) || []); - this._closeProblemsView(); + this.#errors.set([]); + this.#errorGlyphs.set(this.#codeEditor.deltaDecorations(this.#errorGlyphs(), []) || []); + this.#closeProblemsView(); } - private async _initialize() { + async #initialize() { this._loadingService.start(); await firstValueFrom(this._rulesService.download(this.#dossierTemplateId, this.type)).then( rules => { diff --git a/apps/red-ui/src/app/modules/admin/translations/rules-screen-translations.ts b/apps/red-ui/src/app/modules/admin/translations/rules-screen-translations.ts index f802b8397..2fb57874c 100644 --- a/apps/red-ui/src/app/modules/admin/translations/rules-screen-translations.ts +++ b/apps/red-ui/src/app/modules/admin/translations/rules-screen-translations.ts @@ -7,6 +7,7 @@ export const rulesScreenTranslations: Record<'ENTITY' | 'COMPONENT', Record{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", @@ -1064,6 +1056,14 @@ "title": "{length} {length, plural, one{Dossier-Vorlage} other{Dossier-Vorlagen}}" } }, + "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.", @@ -1249,15 +1249,6 @@ "title": "{length} {length, plural, one{Wörterbuch} other{Wörterbücher}}" } }, - "entity": { - "info": { - "actions": { - "revert": "Revert", - "save": "Save changes" - }, - "heading": "Edit entity" - } - }, "entity-rules-screen": { "error": { "generic": "Something went wrong... Entity rules update failed!" @@ -1269,7 +1260,17 @@ "generic": "Entity rules updated!" }, "title": "Entity rule editor", - "warning-text": "Warning: experimental feature!" + "warning-text": "Warning: experimental feature!", + "warnings-found": "" + }, + "entity": { + "info": { + "actions": { + "revert": "Revert", + "save": "Save changes" + }, + "heading": "Edit entity" + } }, "error": { "deleted-entity": { @@ -1277,13 +1278,13 @@ "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": { @@ -1301,12 +1302,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", @@ -1317,6 +1312,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": { @@ -1532,15 +1533,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", @@ -1550,6 +1542,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", @@ -1820,13 +1821,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", @@ -1840,6 +1834,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", @@ -1857,7 +1852,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", @@ -1865,6 +1859,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", @@ -1956,16 +1957,16 @@ "warnings-subtitle": "Do not show again options", "warnings-title": "Prompts and dialogs settings" }, - "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": { @@ -2192,12 +2193,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", @@ -2221,6 +2216,12 @@ "no-match": "Keine Dokumente entsprechen Ihren aktuellen Filtern.", "table-header": "{length} {length, plural, one{Suchergebnis} other{Suchergebnisse}}" }, + "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": { @@ -2472,4 +2473,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 03c15a5b7..ea81e20cf 100644 --- a/apps/red-ui/src/assets/i18n/redact/en.json +++ b/apps/red-ui/src/assets/i18n/redact/en.json @@ -1260,7 +1260,8 @@ "generic": "Entity rules updated!" }, "title": "Entity rule editor", - "warning-text": "Warning: experimental feature!" + "warning-text": "Warning: experimental feature!", + "warnings-found": "{warnings, plural, one{A warning} other{{warnings} warnings}} found in rules" }, "entity": { "info": { @@ -2472,4 +2473,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 1c8e23bcb..02879b21a 100644 --- a/apps/red-ui/src/assets/i18n/scm/de.json +++ b/apps/red-ui/src/assets/i18n/scm/de.json @@ -255,9 +255,6 @@ "watermarks": "Watermarks" }, "analysis-disabled": "Analysis disabled", - "annotation": { - "pending": "(Pending analysis)" - }, "annotation-actions": { "accept-recommendation": { "label": "Empfehlung annehmen" @@ -316,14 +313,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" @@ -336,15 +333,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" }, @@ -377,6 +374,9 @@ "skipped": "Übersprungen", "text-highlight": "Earmark" }, + "annotation": { + "pending": "(Pending analysis)" + }, "archived-dossiers-listing": { "no-data": { "title": "No archived dossiers." @@ -582,18 +582,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": { @@ -602,6 +598,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?", @@ -946,13 +946,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": { @@ -1021,14 +1021,6 @@ "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", @@ -1064,6 +1056,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.", @@ -1249,15 +1249,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!" @@ -1269,7 +1260,17 @@ "generic": "Entity rules updated!" }, "title": "Entity rule editor", - "warning-text": "Warning: experimental feature!" + "warning-text": "Warning: experimental feature!", + "warnings-found": "" + }, + "entity": { + "info": { + "actions": { + "revert": "Revert", + "save": "Save changes" + }, + "heading": "Edit entity" + } }, "error": { "deleted-entity": { @@ -1277,13 +1278,13 @@ "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": { @@ -1301,12 +1302,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", @@ -1317,6 +1312,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": { @@ -1532,15 +1533,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", @@ -1550,6 +1542,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", @@ -1820,13 +1821,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", @@ -1840,6 +1834,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", @@ -1857,7 +1852,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", @@ -1865,6 +1859,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", @@ -1956,16 +1957,16 @@ "warnings-subtitle": "Do not show again options", "warnings-title": "Prompts and dialogs settings" }, - "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": { @@ -2192,12 +2193,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", @@ -2221,6 +2216,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": { @@ -2472,4 +2473,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 477962ec0..12e2bc996 100644 --- a/apps/red-ui/src/assets/i18n/scm/en.json +++ b/apps/red-ui/src/assets/i18n/scm/en.json @@ -1260,7 +1260,8 @@ "generic": "Entity rules updated!" }, "title": "Entity rule editor", - "warning-text": "Warning: experimental feature!" + "warning-text": "Warning: experimental feature!", + "warnings-found": "{warnings, plural, one{A warning} other{{warnings} warnings}} found in rules" }, "entity": { "info": { @@ -2472,4 +2473,4 @@ } }, "yesterday": "Yesterday" -} \ No newline at end of file +} diff --git a/apps/red-ui/src/assets/icons/general/alert-circle.svg b/apps/red-ui/src/assets/icons/general/alert-circle.svg index 2723dc6dc..caf5efcd5 100644 --- a/apps/red-ui/src/assets/icons/general/alert-circle.svg +++ b/apps/red-ui/src/assets/icons/general/alert-circle.svg @@ -3,8 +3,8 @@ warning - - + + diff --git a/apps/red-ui/src/assets/icons/general/alert-warning-circle.svg b/apps/red-ui/src/assets/icons/general/alert-warning-circle.svg new file mode 100644 index 000000000..97142f88f --- /dev/null +++ b/apps/red-ui/src/assets/icons/general/alert-warning-circle.svg @@ -0,0 +1,13 @@ + + + warning + + + + + + + + + + diff --git a/apps/red-ui/src/styles.scss b/apps/red-ui/src/styles.scss index 43bd48938..a09022d4c 100644 --- a/apps/red-ui/src/styles.scss +++ b/apps/red-ui/src/styles.scss @@ -39,9 +39,29 @@ src: url('./assets/styles/fonts/Inter-VariableFont.ttf') format('truetype'); } -.error-glyph-margin { - background: url('./assets/icons/general/alert-circle.svg') no-repeat center; +.glyph-margin { background-size: 80%; + + &.error { + background: url('assets/icons/general/alert-circle.svg') no-repeat center; + } + + &.warning { + background: url('assets/icons/general/alert-warning-circle.svg') no-repeat center; + } +} + +.codicon-error { + background: url('assets/icons/general/alert-circle.svg') no-repeat center; +} + +.codicon-warning { + background: url('assets/icons/general/alert-warning-circle.svg') no-repeat center; +} + +.codicon-error::before, +.codicon-warning::before { + visibility: hidden; } @include common-variables.configureLight(