diff --git a/apps/red-ui/src/app/modules/admin/admin-routing.module.ts b/apps/red-ui/src/app/modules/admin/admin-routing.module.ts
index 0f8631355..a29289c29 100644
--- a/apps/red-ui/src/app/modules/admin/admin-routing.module.ts
+++ b/apps/red-ui/src/app/modules/admin/admin-routing.module.ts
@@ -61,6 +61,19 @@ const dossierTemplateIdRoutes: IqserRoutes = [
},
loadChildren: () => import('./screens/rules/rules.module').then(m => m.RulesModule),
},
+ {
+ path: 'component-rules',
+ component: BaseDossierTemplateScreenComponent,
+ canActivate: [CompositeRouteGuard, IqserPermissionsGuard],
+ data: {
+ routeGuards: [IqserAuthGuard, RedRoleGuard],
+ permissions: {
+ allow: [Roles.rules.read],
+ redirectTo: 'info',
+ },
+ },
+ loadChildren: () => import('./screens/component-rules/component-rules.module').then(m => m.ComponentRulesModule),
+ },
{
path: 'file-attributes',
component: BaseDossierTemplateScreenComponent,
diff --git a/apps/red-ui/src/app/modules/admin/admin.module.ts b/apps/red-ui/src/app/modules/admin/admin.module.ts
index fc8df4e81..495528870 100644
--- a/apps/red-ui/src/app/modules/admin/admin.module.ts
+++ b/apps/red-ui/src/app/modules/admin/admin.module.ts
@@ -57,6 +57,7 @@ import { DossierTemplateActionsComponent } from './shared/components/dossier-tem
import { IqserUsersModule } from '@iqser/common-ui/lib/users';
import { TenantPipe } from '@iqser/common-ui/lib/tenants';
import { SelectComponent } from '@shared/components/select/select.component';
+import { ComponentRulesService } from './services/component-rules.service';
const dialogs = [
AddEditCloneDossierTemplateDialogComponent,
@@ -97,7 +98,7 @@ const components = [
@NgModule({
declarations: [...components],
- providers: [AdminDialogService, AuditService, DigitalSignatureService, RulesService, SmtpConfigService],
+ providers: [AdminDialogService, AuditService, DigitalSignatureService, RulesService, ComponentRulesService, SmtpConfigService],
imports: [
CommonModule,
SharedModule,
diff --git a/apps/red-ui/src/app/modules/admin/screens/component-rules/component-rules.module.ts b/apps/red-ui/src/app/modules/admin/screens/component-rules/component-rules.module.ts
new file mode 100644
index 000000000..14c171ff2
--- /dev/null
+++ b/apps/red-ui/src/app/modules/admin/screens/component-rules/component-rules.module.ts
@@ -0,0 +1,26 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+import { ComponentRulesScreenComponent } from './rules-screen/component-rules-screen.component';
+import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
+import { PendingChangesGuard } from '@guards/can-deactivate.guard';
+import { TranslateModule } from '@ngx-translate/core';
+import { IconButtonComponent } from '@iqser/common-ui';
+import { FormsModule } from '@angular/forms';
+import { MatIconModule } from '@angular/material/icon';
+
+const routes = [{ path: '', component: ComponentRulesScreenComponent, canDeactivate: [PendingChangesGuard] }];
+
+@NgModule({
+ declarations: [ComponentRulesScreenComponent],
+ imports: [
+ RouterModule.forChild(routes),
+ CommonModule,
+ MonacoEditorModule,
+ TranslateModule,
+ IconButtonComponent,
+ FormsModule,
+ MatIconModule,
+ ],
+})
+export class ComponentRulesModule {}
diff --git a/apps/red-ui/src/app/modules/admin/screens/component-rules/rules-screen/component-rules-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/component-rules/rules-screen/component-rules-screen.component.html
new file mode 100644
index 000000000..13c6432f7
--- /dev/null
+++ b/apps/red-ui/src/app/modules/admin/screens/component-rules/rules-screen/component-rules-screen.component.html
@@ -0,0 +1,26 @@
+
+
+
+
+
diff --git a/apps/red-ui/src/app/modules/admin/screens/component-rules/rules-screen/component-rules-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/component-rules/rules-screen/component-rules-screen.component.scss
new file mode 100644
index 000000000..0d44f017a
--- /dev/null
+++ b/apps/red-ui/src/app/modules/admin/screens/component-rules/rules-screen/component-rules-screen.component.scss
@@ -0,0 +1,67 @@
+:host {
+ flex-grow: 1;
+ overflow: hidden;
+ padding: 15px 0 0 15px;
+}
+
+ngx-monaco-editor {
+ height: 100%;
+ width: 100%;
+}
+
+.header-container {
+ display: flex;
+ align-items: center;
+ padding-bottom: 15px;
+ margin-left: 30px;
+
+ .error {
+ color: red;
+ font-size: 8px;
+ font-weight: 500;
+ margin-left: 20px;
+ font-style: italic;
+ }
+}
+
+.changes-box {
+ flex-direction: column;
+ justify-content: center;
+ align-items: start;
+ gap: 10px;
+
+ > div {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+ }
+
+ .errors {
+ cursor: pointer;
+
+ .icon {
+ scale: 0.7;
+ }
+
+ :first-child {
+ display: flex;
+ align-items: center;
+ gap: 0.5em;
+ font-weight: 500;
+ /* TODO: Update this to --iqser-error when added */
+ color: #dd4d50;
+ }
+
+ .face-up {
+ transform: rotate(90deg);
+ }
+
+ margin-right: 0;
+ }
+
+ .actions {
+ gap: 24px;
+ }
+}
diff --git a/apps/red-ui/src/app/modules/admin/screens/component-rules/rules-screen/component-rules-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/component-rules/rules-screen/component-rules-screen.component.ts
new file mode 100644
index 000000000..c17ee1beb
--- /dev/null
+++ b/apps/red-ui/src/app/modules/admin/screens/component-rules/rules-screen/component-rules-screen.component.ts
@@ -0,0 +1,216 @@
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, ElementRef, OnInit, signal, ViewChild } from '@angular/core';
+import { PermissionsService } from '@services/permissions.service';
+import { IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
+import { saveAs } from 'file-saver';
+import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
+import { firstValueFrom } from 'rxjs';
+import { DOSSIER_TEMPLATE_ID } from '@red/domain';
+import { EditorThemeService } from '@services/editor-theme.service';
+import { ComponentCanDeactivate } from '@guards/can-deactivate.guard';
+import { Debounce, getParam } from '@iqser/common-ui/lib/utils';
+import { ComponentRulesService } from '../../../services/component-rules.service';
+import ICodeEditor = monaco.editor.ICodeEditor;
+import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
+import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorConstructionOptions;
+
+interface SyntaxError {
+ line: number;
+ column: number;
+ message: string;
+}
+
+@Component({
+ templateUrl: './component-rules-screen.component.html',
+ styleUrls: ['./component-rules-screen.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ComponentRulesScreenComponent implements OnInit, ComponentCanDeactivate {
+ readonly iconButtonTypes = IconButtonTypes;
+ readonly editorOptions: IStandaloneEditorConstructionOptions = {
+ theme: 'vs',
+ language: 'java',
+ automaticLayout: true,
+ readOnly: !this.permissionsService.canEditRules(),
+ glyphMargin: true,
+ };
+ initialLines: string[] = [];
+ currentLines: string[] = [];
+ isLeaving = false;
+ @ViewChild('fileInput')
+ private _fileInput: ElementRef;
+ private _codeEditor: ICodeEditor;
+ private _decorations: string[] = [];
+ readonly #errorGlyphs = signal([]);
+ readonly numberOfErrors = computed(() => this.#errorGlyphs().length);
+ readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID);
+
+ constructor(
+ readonly permissionsService: PermissionsService,
+ private readonly _componentRulesService: ComponentRulesService,
+ private readonly _changeDetectorRef: ChangeDetectorRef,
+ private readonly _toaster: Toaster,
+ private readonly _loadingService: LoadingService,
+ private readonly _editorThemeService: EditorThemeService,
+ ) {}
+
+ set isLeavingPage(isLeaving: boolean) {
+ this.isLeaving = isLeaving;
+ this._changeDetectorRef.detectChanges();
+ }
+
+ get changed(): boolean {
+ return this.currentLines.toString() !== this.initialLines.toString();
+ }
+
+ get codeEditorText() {
+ return this.currentLines.join('\n');
+ }
+
+ set codeEditorText($event: any) {
+ this.currentLines = $event.split('\n');
+ this.codeEditorTextChanged();
+ this._closeProblemsView();
+ }
+
+ async ngOnInit() {
+ await this._initialize();
+ }
+
+ onCodeEditorInit(editor: ICodeEditor) {
+ 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));
+ 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);
+ }
+
+ goToErrors() {
+ this._codeEditor.trigger(null, 'editor.action.marker.next', null);
+ }
+
+ async save(): Promise {
+ this._loadingService.start();
+ this._removeErrorMarkers();
+ await firstValueFrom(
+ this._componentRulesService.uploadRules({
+ rules: this._codeEditor.getModel().getValue(),
+ dossierTemplateId: this.#dossierTemplateId,
+ }),
+ ).then(
+ async () => {
+ await this._initialize();
+ this._toaster.success(_('component-rules-screen.success.generic'));
+ },
+ error => {
+ const errors = error.error as SyntaxError[] | undefined;
+ this._drawErrorMarkers(errors);
+ this._loadingService.stop();
+ this._toaster.error(_('component-rules-screen.error.generic'));
+ },
+ );
+ }
+
+ revert(): void {
+ this.currentLines = this.initialLines;
+ this._decorations = this._codeEditor?.deltaDecorations(this._decorations, []) || [];
+ this._removeErrorMarkers();
+ this._changeDetectorRef.detectChanges();
+ this._loadingService.stop();
+ }
+
+ download(): void {
+ const content = this._codeEditor.getModel().getValue();
+ const blob = new Blob([content], {
+ type: 'text/plain;charset=utf-8',
+ });
+ saveAs(blob, 'rules.txt');
+ }
+
+ upload($event): void {
+ const file: File = $event.target.files[0];
+ const fileReader = new FileReader();
+
+ if (file) {
+ fileReader.onload = () => {
+ this._codeEditor.getModel().setValue(fileReader.result as string);
+ this._fileInput.nativeElement.value = null;
+ };
+ fileReader.readAsText(file);
+ }
+ }
+
+ private _isNew(entry: string): boolean {
+ return this.initialLines.indexOf(entry) < 0 && entry?.trim().length > 0;
+ }
+
+ private _makeDecorationFor(entry: string): IModelDeltaDecoration {
+ const line = this.currentLines.indexOf(entry) + 1;
+
+ return {
+ range: new monaco.Range(line, 1, line, 1),
+ options: { isWholeLine: true, className: 'changed-row-marker' },
+ } as IModelDeltaDecoration;
+ }
+
+ private _drawErrorMarkers(errors: SyntaxError[] | undefined) {
+ const model = this._codeEditor?.getModel();
+ if (!model || !errors?.length) {
+ return;
+ }
+ const markers = [];
+ const glyphs = [];
+ errors
+ .filter(e => e.line > 0)
+ .forEach(e => {
+ const endColumn = model.getLineLength(e.line) + 1;
+ markers.push({
+ message: e.message,
+ severity: monaco.MarkerSeverity.Error,
+ startLineNumber: e.line,
+ startColumn: e.column,
+ endLineNumber: e.line,
+ endColumn,
+ });
+ glyphs.push({
+ range: new monaco.Range(e.line, e.column, e.line, endColumn),
+ options: {
+ glyphMarginClassName: 'error-glyph-margin',
+ },
+ });
+ });
+ this.#errorGlyphs.set(this._codeEditor.deltaDecorations(this.#errorGlyphs(), glyphs));
+ (window as any).monaco.editor.setModelMarkers(model, model.id, markers);
+ }
+
+ private _closeProblemsView() {
+ this._codeEditor.trigger(null, 'closeMarkersNavigation', null);
+ }
+
+ private _removeErrorMarkers() {
+ 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();
+ }
+
+ private async _initialize() {
+ this._loadingService.start();
+ await firstValueFrom(this._componentRulesService.download(this.#dossierTemplateId)).then(
+ rules => {
+ this.currentLines = this.initialLines = rules.rules.split('\n');
+ this.revert();
+ },
+ () => this._loadingService.stop(),
+ );
+ }
+}
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 978ec8419..0d44f017a 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
@@ -51,7 +51,7 @@ ngx-monaco-editor {
gap: 0.5em;
font-weight: 500;
/* TODO: Update this to --iqser-error when added */
- color: var(--iqser-red-1);
+ color: #dd4d50;
}
.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 a38f1facb..2635ec949 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
@@ -1,4 +1,4 @@
-import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, OnInit, signal, ViewChild } from '@angular/core';
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, ElementRef, OnInit, signal, ViewChild } from '@angular/core';
import { PermissionsService } from '@services/permissions.service';
import { IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
import { saveAs } from 'file-saver';
@@ -25,7 +25,6 @@ interface SyntaxError {
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RulesScreenComponent implements OnInit, ComponentCanDeactivate {
- readonly numberOfErrors = signal(0);
readonly iconButtonTypes = IconButtonTypes;
readonly editorOptions: IStandaloneEditorConstructionOptions = {
theme: 'vs',
@@ -41,7 +40,8 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate {
private _fileInput: ElementRef;
private _codeEditor: ICodeEditor;
private _decorations: string[] = [];
- private _errorGlyphs: string[] = [];
+ readonly #errorGlyphs = signal([]);
+ readonly numberOfErrors = computed(() => this.#errorGlyphs().length);
readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID);
constructor(
@@ -69,6 +69,7 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate {
set codeEditorText($event: any) {
this.currentLines = $event.split('\n');
this.codeEditorTextChanged();
+ this._closeProblemsView();
}
async ngOnInit() {
@@ -87,17 +88,16 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate {
@Debounce()
codeEditorTextChanged() {
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('keyboard', 'editor.action.marker.next', null);
+ this._codeEditor.trigger(null, 'editor.action.marker.next', null);
}
async save(): Promise {
this._loadingService.start();
- this.numberOfErrors.set(0);
+ this._removeErrorMarkers();
await firstValueFrom(
this._rulesService.uploadRules({
rules: this._codeEditor.getModel().getValue(),
@@ -106,7 +106,6 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate {
).then(
async () => {
await this._initialize();
- this._removeErrorMarkers();
this._toaster.success(_('rules-screen.success.generic'));
},
error => {
@@ -186,19 +185,22 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate {
},
});
});
- this.numberOfErrors.set(markers.length);
- this._errorGlyphs = this._codeEditor.deltaDecorations(this._errorGlyphs, glyphs);
+ this.#errorGlyphs.set(this._codeEditor.deltaDecorations(this.#errorGlyphs(), glyphs));
(window as any).monaco.editor.setModelMarkers(model, model.id, markers);
}
+ private _closeProblemsView() {
+ this._codeEditor.trigger(null, 'closeMarkersNavigation', null);
+ }
+
private _removeErrorMarkers() {
const model = this._codeEditor?.getModel();
if (!model) {
return;
}
(window as any).monaco.editor.setModelMarkers(model, model.id, []);
- this._errorGlyphs = this._codeEditor?.deltaDecorations(this._errorGlyphs, []) || [];
- this.numberOfErrors.set(0);
+ this.#errorGlyphs.set(this._codeEditor.deltaDecorations(this.#errorGlyphs(), []) || []);
+ this._closeProblemsView();
}
private async _initialize() {
diff --git a/apps/red-ui/src/app/modules/admin/services/component-rules.service.ts b/apps/red-ui/src/app/modules/admin/services/component-rules.service.ts
new file mode 100644
index 000000000..74b4ffa61
--- /dev/null
+++ b/apps/red-ui/src/app/modules/admin/services/component-rules.service.ts
@@ -0,0 +1,16 @@
+import { Injectable } from '@angular/core';
+import { GenericService } from '@iqser/common-ui';
+import { IComponentRules } from '@red/domain';
+
+@Injectable()
+export class ComponentRulesService extends GenericService {
+ protected readonly _defaultModelPath = 'rules';
+
+ download(dossierTemplateId: string) {
+ return this._getOne([dossierTemplateId]);
+ }
+
+ uploadRules(body: IComponentRules) {
+ return this._post(body);
+ }
+}
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 c6d00944c..71888466f 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
@@ -33,10 +33,9 @@ export class AdminSideNavComponent implements OnInit {
readonly translations = adminSideNavTranslations;
readonly currentUser = getCurrentUser();
readonly roles = Roles;
+ prefix: string;
readonly isDocumine = this.#config.IS_DOCUMINE;
readonly canAccessRulesInDocumine = this.isDocumine && !this.#config.RULE_EDITOR_DEV_ONLY;
- prefix: string;
-
readonly items: { readonly [key in AdminSideNavType]: NavItem[] } = {
settings: [
{
@@ -100,6 +99,14 @@ export class AdminSideNavComponent implements OnInit {
label: _('admin-side-nav.rule-editor'),
show: (this.isIqserDevMode || this.canAccessRulesInDocumine) && this._permissionsService.has(Roles.rules.read),
},
+ {
+ screen: 'component-rules',
+ label: _('admin-side-nav.component-rule-editor'),
+ show:
+ this.isDocumine &&
+ (this.isIqserDevMode || this.canAccessRulesInDocumine) &&
+ this._permissionsService.has(Roles.rules.read),
+ },
{
screen: 'default-colors',
label: _('admin-side-nav.default-colors'),
diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json
index 42bf5941f..b022421b1 100644
--- a/apps/red-ui/src/assets/config/config.json
+++ b/apps/red-ui/src/assets/config/config.json
@@ -3,7 +3,7 @@
"ADMIN_CONTACT_URL": null,
"API_URL": "https://dan.iqser.cloud",
"APP_NAME": "RedactManager",
- "IS_DOCUMINE": false,
+ "IS_DOCUMINE": true,
"RULE_EDITOR_DEV_ONLY": false,
"AUTO_READ_TIME": 3,
"BACKEND_APP_VERSION": "4.4.40",
@@ -18,8 +18,8 @@
"SELECTION_MODE": "structural",
"MANUAL_BASE_URL": "https://docs.redactmanager.com/preview",
"ANNOTATIONS_THRESHOLD": 1000,
- "THEME": "redact",
- "BASE_TRANSLATIONS_DIRECTORY": "/assets/i18n/redact/",
+ "THEME": "scm",
+ "BASE_TRANSLATIONS_DIRECTORY": "/assets/i18n/scm/",
"AVAILABLE_NOTIFICATIONS_DAYS": 30,
"AVAILABLE_OLD_NOTIFICATIONS_MINUTES": 60,
"NOTIFICATIONS_THRESHOLD": 1000,
diff --git a/apps/red-ui/src/assets/i18n/redact/de.json b/apps/red-ui/src/assets/i18n/redact/de.json
index 491127258..fbcb70ed8 100644
--- a/apps/red-ui/src/assets/i18n/redact/de.json
+++ b/apps/red-ui/src/assets/i18n/redact/de.json
@@ -234,6 +234,7 @@
},
"admin-side-nav": {
"audit": "",
+ "component-rule-editor": "",
"configurations": "",
"default-colors": "",
"dictionary": "",
@@ -557,6 +558,19 @@
"title": "Aktion bestätigen"
}
},
+ "component-rules-screen": {
+ "error": {
+ "generic": ""
+ },
+ "errors-found": "",
+ "revert-changes": "",
+ "save-changes": "",
+ "success": {
+ "generic": ""
+ },
+ "title": "",
+ "warning-text": ""
+ },
"configurations": "Einstellungen",
"confirm-archive-dossier": {
"archive": "",
diff --git a/apps/red-ui/src/assets/i18n/redact/en.json b/apps/red-ui/src/assets/i18n/redact/en.json
index 90be40ba8..a2a36c885 100644
--- a/apps/red-ui/src/assets/i18n/redact/en.json
+++ b/apps/red-ui/src/assets/i18n/redact/en.json
@@ -234,6 +234,7 @@
},
"admin-side-nav": {
"audit": "Audit",
+ "component-rule-editor": "",
"configurations": "Configurations",
"default-colors": "Default Colors",
"dictionary": "Dictionary",
@@ -557,6 +558,19 @@
"title": "Confirm Action"
}
},
+ "component-rules-screen": {
+ "error": {
+ "generic": ""
+ },
+ "errors-found": "",
+ "revert-changes": "",
+ "save-changes": "",
+ "success": {
+ "generic": ""
+ },
+ "title": "",
+ "warning-text": ""
+ },
"configurations": "Configurations",
"confirm-archive-dossier": {
"archive": "Archive Dossier",
diff --git a/apps/red-ui/src/assets/i18n/scm/de.json b/apps/red-ui/src/assets/i18n/scm/de.json
index d1471dccf..2147d843e 100644
--- a/apps/red-ui/src/assets/i18n/scm/de.json
+++ b/apps/red-ui/src/assets/i18n/scm/de.json
@@ -234,6 +234,7 @@
},
"admin-side-nav": {
"audit": "",
+ "component-rule-editor": "",
"configurations": "",
"default-colors": "",
"dictionary": "",
@@ -557,6 +558,19 @@
"title": "Aktion bestätigen"
}
},
+ "component-rules-screen": {
+ "error": {
+ "generic": ""
+ },
+ "errors-found": "",
+ "revert-changes": "",
+ "save-changes": "",
+ "success": {
+ "generic": ""
+ },
+ "title": "",
+ "warning-text": ""
+ },
"configurations": "Einstellungen",
"confirm-archive-dossier": {
"archive": "",
diff --git a/apps/red-ui/src/assets/i18n/scm/en.json b/apps/red-ui/src/assets/i18n/scm/en.json
index caf96dbd9..61d544385 100644
--- a/apps/red-ui/src/assets/i18n/scm/en.json
+++ b/apps/red-ui/src/assets/i18n/scm/en.json
@@ -234,6 +234,7 @@
},
"admin-side-nav": {
"audit": "Audit",
+ "component-rule-editor": "Component Rule Editor",
"configurations": "Configurations",
"default-colors": "Default Colors",
"dictionary": "Dictionary",
@@ -557,6 +558,19 @@
"title": "Confirm Action"
}
},
+ "component-rules-screen": {
+ "error": {
+ "generic": "Something went wrong... Component rules update failed!"
+ },
+ "errors-found": "{errors, plural, one{An error} other{{errors} errors}} found in rules",
+ "revert-changes": "Revert",
+ "save-changes": "Save Changes",
+ "success": {
+ "generic": "Component rules updated!"
+ },
+ "title": "Component Rule Editor",
+ "warning-text": "Warning: experimental feature!"
+ },
"configurations": "Configurations",
"confirm-archive-dossier": {
"archive": "Archive Dossier",
@@ -2213,7 +2227,7 @@
"error": {
"generic": "Something went wrong... Rules update failed!"
},
- "errors-found": "",
+ "errors-found": "{errors, plural, one{An error} other{{errors} errors}} found in rules",
"revert-changes": "Revert",
"save-changes": "Save Changes",
"success": {
diff --git a/libs/red-domain/src/lib/shared/component-rules.ts b/libs/red-domain/src/lib/shared/component-rules.ts
new file mode 100644
index 000000000..c2f8c5fb2
--- /dev/null
+++ b/libs/red-domain/src/lib/shared/component-rules.ts
@@ -0,0 +1,13 @@
+/**
+ * Object containing a string of Drools rules.
+ */
+export interface IComponentRules {
+ /**
+ * The DossierTemplate Id for these rules
+ */
+ dossierTemplateId?: string;
+ /**
+ * The actual string of rules.
+ */
+ rules?: string;
+}
diff --git a/libs/red-domain/src/lib/shared/index.ts b/libs/red-domain/src/lib/shared/index.ts
index 3c25911a6..b6973f8bf 100644
--- a/libs/red-domain/src/lib/shared/index.ts
+++ b/libs/red-domain/src/lib/shared/index.ts
@@ -11,3 +11,4 @@ export * from './admin-side-nav-types';
export * from './charts';
export * from './app-config';
export * from './system-preferences';
+export * from './component-rules';