DM-508 - WIP on replacing RSSResponse with new ComponentLog

This commit is contained in:
Valentin Mihai 2023-09-27 21:25:00 +03:00
parent bb2a899da3
commit b970838d52
17 changed files with 200 additions and 206 deletions

View File

@ -1,34 +1,34 @@
<section class="dialog">
<div [translate]="'rss-dialog.title'" class="dialog-header heading-l"></div>
<div [translate]="'component-log-dialog.title'" class="dialog-header heading-l"></div>
<hr />
<div class="dialog-content" id="scm-edit">
<div *ngIf="scmData() as scmEntry" class="table output-data">
<div class="table-header">{{ 'rss-dialog.table-header.component' | translate }}</div>
<div class="table-header">{{ 'rss-dialog.table-header.value' | translate }}</div>
<div class="table-header">{{ 'rss-dialog.table-header.transformation-rule' | translate }}</div>
<div class="table-header">{{ 'rss-dialog.table-header.annotation-references' | translate }}</div>
<div class="table-header">{{ 'component-log-dialog.table-header.component' | translate }}</div>
<div class="table-header">{{ 'component-log-dialog.table-header.value' | translate }}</div>
<div class="table-header">{{ 'component-log-dialog.table-header.transformation-rule' | translate }}</div>
<div class="table-header">{{ 'component-log-dialog.table-header.annotation-references' | translate }}</div>
<ng-container *ngFor="let entry of scmEntry.result | keyvalue: originalOrder; let index = index">
<div class="bold">{{ entry.key }}</div>
<ng-container *ngFor="let entry of scmEntry.componentValues; let index = index">
<div class="bold">{{ entry.value }}</div>
<div [id]="getValueCellId(index)">
<iqser-editable-input
(save)="saveEdit($event, entry.value.originalKey)"
(save)="saveEdit($event, entry.value)"
[canEdit]="canEdit"
[cancelTooltip]="'rss-dialog.actions.cancel-edit' | translate"
[editTooltip]="'rss-dialog.actions.edit' | translate"
[cancelTooltip]="'component-log-dialog.actions.cancel-edit' | translate"
[editTooltip]="'component-log-dialog.actions.edit' | translate"
[id]="'value-' + index"
[parentId]="getValueCellId(index)"
[saveTooltip]="'rss-dialog.actions.save' | translate"
[value]="entry.value.value ?? entry.value.originalValue"
[saveTooltip]="'component-log-dialog.actions.save' | translate"
[value]="entry.value ?? entry.originalValue"
[attr.helpModeKey]="'scm_edit_DIALOG'"
>
<ng-container slot="editing">
<iqser-circle-button
(action)="undo(entry.value.originalKey)"
*ngIf="entry.value.value && canEdit"
(action)="undo(entry.value)"
*ngIf="entry.value && canEdit"
[showDot]="true"
[tooltip]="'rss-dialog.actions.undo' | translate: { value: entry.value.originalValue } | replaceNbsp"
[tooltip]="'component-log-dialog.actions.undo' | translate: { value: entry.originalValue } | replaceNbsp"
[attr.help-mode-key]="'scm_undo_DIALOG'"
class="ml-2"
icon="red:undo"
@ -36,26 +36,24 @@
</ng-container>
</iqser-editable-input>
</div>
<div>{{ entry.value.transformation }}</div>
<div>{{ entry.componentRuleId }}</div>
<div>
<ul *ngIf="entry.value.scmAnnotations; else noAnnotations" class="pl-0">
<ul *ngIf="entry.componentLogEntityReferences; else noReferences" class="pl-0">
<li
*ngFor="let annotation of entry.value.scmAnnotations"
*ngFor="let reference of entry.componentLogEntityReferences"
[innerHTML]="
'rss-dialog.annotations'
'component-log-dialog.annotations'
| translate
: {
ruleNumber: annotation.ruleIdentifier,
pageCount: annotation.pages.length,
pages: annotation.pages.join(','),
type: annotation.displayName
ruleNumber: reference.entityRuleId,
pageCount: reference.page
}
"
class="mb-8"
></li>
</ul>
<ng-template #noAnnotations>-</ng-template>
<ng-template #noReferences>-</ng-template>
</div>
</ng-container>
</div>
@ -64,7 +62,7 @@
<div class="dialog-actions">
<iqser-icon-button
(action)="exportJSON()"
[label]="'rss-dialog.actions.export-json' | translate"
[label]="'component-log-dialog.actions.export-json' | translate"
[submit]="true"
[type]="iconButtonTypes.primary"
[attr.help-mode-key]="'scm_export_DIALOG'"
@ -72,7 +70,7 @@
<iqser-icon-button
(action)="exportXML()"
[label]="'rss-dialog.actions.export-xml' | translate"
[label]="'component-log-dialog.actions.export-xml' | translate"
[type]="iconButtonTypes.primary"
[attr.help-mode-key]="'scm_export_DIALOG'"
></iqser-icon-button>
@ -84,9 +82,9 @@
label="Export All"
></iqser-icon-button>
<div [translate]="'rss-dialog.actions.close'" class="all-caps-label cancel" mat-dialog-close></div>
<div [translate]="'component-log-dialog.actions.close'" class="all-caps-label cancel" mat-dialog-close></div>
<mat-checkbox (change)="toggleOpenScmDialogByDefault()" [checked]="openScmDialogByDefault()" class="ml-auto" color="primary"
>{{ 'rss-dialog.actions.display-by-default' | translate }}
>{{ 'component-log-dialog.actions.display-by-default' | translate }}
</mat-checkbox>
</div>

View File

@ -5,11 +5,11 @@ import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/materia
import { ReplaceNbspPipe } from '@common-ui/pipes/replace-nbsp.pipe';
import { BaseDialogComponent, CircleButtonComponent, EditableInputComponent, IconButtonComponent } from '@iqser/common-ui';
import { TranslateModule } from '@ngx-translate/core';
import { IFile, RssEntry, WorkflowFileStatuses } from '@red/domain';
import { ComponentLogEntry, IFile, WorkflowFileStatuses } from '@red/domain';
import { FilesMapService } from '@services/files/files-map.service';
import { RssService } from '@services/files/rss.service';
import { UserPreferenceService } from '@users/user-preference.service';
import { firstValueFrom } from 'rxjs';
import { ComponentLogService } from '@services/files/component-log.service';
interface ScmData {
file: IFile;
@ -34,12 +34,12 @@ interface ScmData {
],
})
export class StructuredComponentManagementDialogComponent extends BaseDialogComponent implements OnInit {
readonly scmData = signal<RssEntry | undefined>(undefined);
readonly scmData = signal<ComponentLogEntry | undefined>(undefined);
readonly openScmDialogByDefault = signal(this.userPreferences.getOpenScmDialogByDefault());
constructor(
protected readonly _dialogRef: MatDialogRef<StructuredComponentManagementDialogComponent>,
private readonly _rssService: RssService,
private readonly _componentLogService: ComponentLogService,
readonly userPreferences: UserPreferenceService,
private readonly _filesMapService: FilesMapService,
@Inject(MAT_DIALOG_DATA) readonly data: ScmData,
@ -62,18 +62,22 @@ export class StructuredComponentManagementDialogComponent extends BaseDialogComp
originalOrder = (): number => 0;
exportJSON() {
return firstValueFrom(this._rssService.exportJSON(this.data.file.dossierId, this.data.file.fileId, this.data.file.filename));
return firstValueFrom(
this._componentLogService.exportJSON(this.data.file.dossierId, this.data.file.fileId, this.data.file.filename),
);
}
exportXML() {
return firstValueFrom(this._rssService.exportXML(this.data.file.dossierId, this.data.file.fileId, this.data.file.filename));
return firstValueFrom(
this._componentLogService.exportXML(this.data.file.dossierId, this.data.file.fileId, this.data.file.filename),
);
}
async exportAllInDossier() {
const allFilesInDossier = this._filesMapService.get(this.data.file.dossierId);
for (const file of allFilesInDossier) {
await firstValueFrom(this._rssService.exportJSON(file.dossierId, file.fileId, file.filename));
await firstValueFrom(this._rssService.exportXML(file.dossierId, file.fileId, file.filename));
await firstValueFrom(this._componentLogService.exportJSON(file.dossierId, file.fileId, file.filename));
await firstValueFrom(this._componentLogService.exportXML(file.dossierId, file.fileId, file.filename));
}
}
@ -89,20 +93,22 @@ export class StructuredComponentManagementDialogComponent extends BaseDialogComp
async undo(originalKey: string) {
this._loadingService.start();
await firstValueFrom(this._rssService.revertOverride(this.data.file.dossierId, this.data.file.fileId, [originalKey]));
await firstValueFrom(this._componentLogService.revertOverride(this.data.file.dossierId, this.data.file.fileId, [originalKey]));
await this.#loadData();
}
async saveEdit(event: string, originalKey: string) {
this._loadingService.start();
await firstValueFrom(this._rssService.override(this.data.file.dossierId, this.data.file.fileId, { [originalKey]: event }));
await firstValueFrom(this._componentLogService.override(this.data.file.dossierId, this.data.file.fileId, { [originalKey]: event }));
await this.#loadData();
}
async #loadData(): Promise<void> {
this._loadingService.start();
const rssData = await firstValueFrom(this._rssService.getRSSData(this.data.file.dossierId, this.data.file.fileId));
this.scmData.set(rssData);
const componentLogData = await firstValueFrom(
this._componentLogService.getComponentLogData(this.data.file.dossierId, this.data.file.fileId),
);
this.scmData.set(componentLogData);
this._loadingService.stop();
}
}

View File

@ -1,33 +1,33 @@
import { Injectable } from '@angular/core';
import { GenericService, QueryParam } from '@iqser/common-ui';
import { IRssData, IRssEntry, RssEntry } from '@red/domain';
import { catchError, map, tap } from 'rxjs/operators';
import { Observable, of } from 'rxjs';
import { HttpHeaders } from '@angular/common/http';
import { saveAs } from 'file-saver';
import { ComponentLogEntry, IComponentLogData, IComponentLogEntry } from '@red/domain';
@Injectable({ providedIn: 'root' })
export class RssService extends GenericService<void> {
export class ComponentLogService extends GenericService<void> {
protected readonly _defaultModelPath = 'import-redactions';
getRSSData(dossierId: string, fileId: string): Observable<RssEntry> {
getComponentLogData(dossierId: string, fileId: string): Observable<ComponentLogEntry> {
const queryParams: QueryParam[] = [];
queryParams.push({ key: 'fileId', value: fileId });
return this._getOne<IRssData>([dossierId], 'rss/detailed', queryParams).pipe(
map(data => data.files[0]),
catchError(() => of({} as IRssEntry)),
map(data => new RssEntry(data)),
return this._getOne<IComponentLogData>([dossierId], 'componentLog', queryParams).pipe(
map(data => data.componentLogEntries[0]),
catchError(() => of({} as IComponentLogEntry)),
map(data => new ComponentLogEntry(data)),
);
}
getRSSExportData(dossierId: string, fileId: string): Observable<any> {
getComponentLogExportData(dossierId: string, fileId: string): Observable<any> {
const queryParams: QueryParam[] = [];
queryParams.push({ key: 'fileId', value: fileId });
return this._getOne<any>([dossierId], 'rss', queryParams).pipe(
map(data => data.files[0]),
catchError(() => of({} as IRssEntry)),
catchError(() => of({} as IComponentLogEntry)),
);
}
@ -39,8 +39,8 @@ export class RssService extends GenericService<void> {
return this._post({ components }, `rss/override/revert/${dossierId}/${fileId}`);
}
exportJSON(dossierId: string, fileId: string, name: string): Observable<RssEntry> {
return this.getRSSExportData(dossierId, fileId).pipe(
exportJSON(dossierId: string, fileId: string, name: string): Observable<ComponentLogEntry> {
return this.getComponentLogExportData(dossierId, fileId).pipe(
tap(data => {
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
saveAs(blob, name + '.rss.json');
@ -49,7 +49,7 @@ export class RssService extends GenericService<void> {
}
exportXML(dossierId: string, fileId: string, name: string): Observable<string> {
return this._getRSSDataAsXML(dossierId, fileId).pipe(
return this._getComponentLogDataAsXML(dossierId, fileId).pipe(
tap(data => {
const blob = new Blob([data], { type: 'application/xml' });
saveAs(blob, name + '.rss.xml');
@ -57,7 +57,7 @@ export class RssService extends GenericService<void> {
);
}
private _getRSSDataAsXML(dossierId: string, fileId: string) {
private _getComponentLogDataAsXML(dossierId: string, fileId: string) {
const queryParams: QueryParam[] = [];
queryParams.push({ key: 'fileId', value: fileId });

View File

@ -1,9 +1,9 @@
{
"ADMIN_CONTACT_NAME": null,
"ADMIN_CONTACT_URL": null,
"API_URL": "https://dan.iqser.cloud",
"API_URL": "https://dan1.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",
@ -13,13 +13,13 @@
"MAX_RETRIES_ON_SERVER_ERROR": 3,
"OAUTH_CLIENT_ID": "redaction",
"OAUTH_IDP_HINT": null,
"OAUTH_URL": "https://dan.iqser.cloud/auth",
"OAUTH_URL": "https://dan1.iqser.cloud/auth",
"RECENT_PERIOD_IN_HOURS": 24,
"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,

View File

@ -558,6 +558,26 @@
"title": "Aktion bestätigen"
}
},
"component-log-dialog": {
"actions": {
"cancel-edit": "Cancel",
"close": "Close",
"display-by-default": "",
"edit": "Edit",
"export-json": "Export JSON",
"export-xml": "Export XML",
"save": "Save",
"undo": "Undo"
},
"annotations": "<strong>{type}</strong> found on {pageCount, plural, one{page} other{pages}} {pages} by rule #{ruleNumber}",
"table-header": {
"annotation-references": "Annotation references",
"component": "Component",
"transformation-rule": "Transformation rule",
"value": "Value"
},
"title": "Structured Component Management"
},
"component-rules-screen": {
"error": {
"generic": ""
@ -2232,26 +2252,6 @@
"red-user-admin": "Benutzer-Admin",
"regular": "Regulär"
},
"rss-dialog": {
"actions": {
"cancel-edit": "Cancel",
"close": "Close",
"display-by-default": "",
"edit": "Edit",
"export-json": "Export JSON",
"export-xml": "Export XML",
"save": "Save",
"undo": "Undo"
},
"annotations": "<strong>{type}</strong> found on {pageCount, plural, one{page} other{pages}} {pages} by rule #{ruleNumber}",
"table-header": {
"annotation-references": "Annotation references",
"component": "Component",
"transformation-rule": "Transformation rule",
"value": "Value"
},
"title": "Structured Component Management"
},
"search": {
"active-dossiers": "ganze Plattform",
"all-dossiers": "all documents",

View File

@ -558,6 +558,26 @@
"title": "Confirm Action"
}
},
"component-log-dialog": {
"actions": {
"cancel-edit": "Cancel",
"close": "Close",
"display-by-default": "Display by default when opening documents",
"edit": "Edit",
"export-json": "Export JSON",
"export-xml": "Export XML",
"save": "Save",
"undo": "Undo to: {value}"
},
"annotations": "<strong>{type}</strong> found on {pageCount, plural, one{page} other{pages}} {pages} by rule #{ruleNumber}",
"table-header": {
"annotation-references": "Annotation references",
"component": "Component",
"transformation-rule": "Transformation rule",
"value": "Value"
},
"title": "Component View"
},
"component-rules-screen": {
"error": {
"generic": ""
@ -1778,8 +1798,8 @@
"licensed-page-count": "Licensed Pages",
"licensed-retention-capacity": "Licensed Retention Capacity",
"licensed-to": "Licensed to",
"section-title": "Licensing Details",
"licensing-period": "Licensing Period"
"licensing-period": "Licensing Period",
"section-title": "Licensing Details"
},
"page-usage": {
"cumulative-pages": "Cumulative Pages",
@ -2237,26 +2257,6 @@
"red-user-admin": "Users Admin",
"regular": "Regular"
},
"rss-dialog": {
"actions": {
"cancel-edit": "Cancel",
"close": "Close",
"display-by-default": "",
"edit": "Edit",
"export-json": "Export JSON",
"export-xml": "Export XML",
"save": "Save",
"undo": "Undo"
},
"annotations": "<strong>{type}</strong> found on {pageCount, plural, one{page} other{pages}} {pages} by rule #{ruleNumber}",
"table-header": {
"annotation-references": "Annotation references",
"component": "Component",
"transformation-rule": "Transformation rule",
"value": "Value"
},
"title": "Structured Component Management"
},
"search-screen": {
"cols": {
"assignee": "Assignee",

View File

@ -558,6 +558,26 @@
"title": "Aktion bestätigen"
}
},
"component-log-dialog": {
"actions": {
"cancel-edit": "Cancel",
"close": "Close",
"display-by-default": "",
"edit": "Edit",
"export-json": "Export JSON",
"export-xml": "Export XML",
"save": "Save",
"undo": "Undo"
},
"annotations": "<strong>{type}</strong> found on {pageCount, plural, one{page} other{pages}} {pages} by rule #{ruleNumber}",
"table-header": {
"annotation-references": "Annotation references",
"component": "Component",
"transformation-rule": "Transformation rule",
"value": "Value"
},
"title": "Structured Component Management"
},
"component-rules-screen": {
"error": {
"generic": ""
@ -2237,26 +2257,6 @@
"red-user-admin": "Benutzer-Admin",
"regular": "Regulär"
},
"rss-dialog": {
"actions": {
"cancel-edit": "",
"close": "",
"display-by-default": "",
"edit": "",
"export-json": "",
"export-xml": "",
"save": "",
"undo": ""
},
"annotations": "",
"table-header": {
"annotation-references": "",
"component": "",
"transformation-rule": "",
"value": ""
},
"title": ""
},
"search-screen": {
"cols": {
"assignee": "Bevollmächtigter",

View File

@ -558,6 +558,26 @@
"title": "Confirm Action"
}
},
"component-log-dialog": {
"actions": {
"cancel-edit": "Cancel",
"close": "Close",
"display-by-default": "Display by default when opening documents",
"edit": "Edit",
"export-json": "Export JSON",
"export-xml": "Export XML",
"save": "Save",
"undo": "Undo to: {value}"
},
"annotations": "<strong>{type}</strong> found on {pageCount, plural, one{page} other{pages}} {pages} by rule #{ruleNumber}",
"table-header": {
"annotation-references": "Annotation references",
"component": "Component",
"transformation-rule": "Transformation rule",
"value": "Value"
},
"title": "Component View"
},
"component-rules-screen": {
"error": {
"generic": "Something went wrong... Component rules update failed!"
@ -1778,8 +1798,8 @@
"licensed-page-count": "Licensed Pages",
"licensed-retention-capacity": "Licensed Retention Capacity",
"licensed-to": "Licensed to",
"section-title": "Licensing Details",
"licensing-period": "Licensing Period"
"licensing-period": "Licensing Period",
"section-title": "Licensing Details"
},
"page-usage": {
"cumulative-pages": "Cumulative Pages",
@ -2237,26 +2257,6 @@
"red-user-admin": "Users Admin",
"regular": "Regular"
},
"rss-dialog": {
"actions": {
"cancel-edit": "Cancel",
"close": "Close",
"display-by-default": "Display by default when opening documents",
"edit": "Edit",
"export-json": "Export JSON",
"export-xml": "Export XML",
"save": "Save",
"undo": "Undo to: {value}"
},
"annotations": "<strong>{type}</strong> found on {pageCount, plural, one{page} other{pages}} {pages} by rule #{ruleNumber}",
"table-header": {
"annotation-references": "Annotation references",
"component": "Component",
"transformation-rule": "Transformation rule",
"value": "Value"
},
"title": "Component View"
},
"search-screen": {
"cols": {
"assignee": "Assignee",

View File

@ -28,4 +28,4 @@ export * from './lib/license';
export * from './lib/digital-signature';
export * from './lib/watermarks';
export * from './lib/colors';
export * from './lib/rss';
export * from './lib/component-log';

View File

@ -0,0 +1,7 @@
import { IComponentLogEntry } from './component-log-entry';
export interface IComponentLogData {
analysisNumber: number;
componentRulesVersion: number;
componentLogEntries: Array<IComponentLogEntry>;
}

View File

@ -0,0 +1,16 @@
import { ComponentValue, IComponentValue } from './component-value';
export interface IComponentLogEntry {
name: string;
componentValues: IComponentValue[];
}
export class ComponentLogEntry implements IComponentLogEntry {
readonly name: string;
readonly componentValues: ComponentValue[];
constructor(entry: IComponentLogEntry) {
this.name = entry.name;
this.componentValues = entry.componentValues;
}
}

View File

@ -0,0 +1,27 @@
export interface ComponentLogEntityReference {
readonly id: string;
readonly type: string;
readonly entityRuleId: string;
readonly page: number;
}
export interface IComponentValue {
readonly value: string;
readonly originalValue: string;
readonly componentRuleId: string;
readonly componentLogEntityReferences: ComponentLogEntityReference[];
}
export class ComponentValue implements IComponentValue {
readonly value: string;
readonly originalValue: string;
readonly componentRuleId: string;
readonly componentLogEntityReferences: ComponentLogEntityReference[];
constructor(value: IComponentValue) {
this.value = value.value;
this.originalValue = value.originalValue;
this.componentRuleId = value.componentRuleId;
this.componentLogEntityReferences = value.componentLogEntityReferences ?? [];
}
}

View File

@ -0,0 +1,3 @@
export * from './component-log-data';
export * from './component-log-entry';
export * from './component-value';

View File

@ -1,3 +0,0 @@
export * from './rss-data';
export * from './rss-entry';
export * from './rss-result';

View File

@ -1,5 +0,0 @@
import { IRssEntry } from './rss-entry';
export interface IRssData {
files: Array<IRssEntry>;
}

View File

@ -1,22 +0,0 @@
import { IRssResult, RssResult } from './rss-result';
export interface IRssEntry {
filename: string;
result: Record<string, IRssResult>;
}
export class RssEntry implements IRssEntry {
readonly filename: string;
readonly result: Record<string, RssResult>;
constructor(entry: IRssEntry) {
this.filename = entry.filename;
const mappedResult: Record<string, RssResult> = {};
for (const key of Object.keys(entry.result)) {
const newKey = key.replace(new RegExp('_', 'g'), ' ');
mappedResult[newKey] = new RssResult(entry.result[key], key);
}
this.result = mappedResult;
}
}

View File

@ -1,33 +0,0 @@
export interface IScmAnnotation {
readonly type: string;
readonly pages: number[];
readonly ruleIdentifier: string;
readonly reason: string;
}
export interface IRssResult {
readonly value: string;
readonly originalValue: string;
readonly scmAnnotations: IScmAnnotation[];
readonly transformation: string;
}
export type RssResultAnnotation = IScmAnnotation & { readonly displayName: string };
export class RssResult implements IRssResult {
readonly value: string;
readonly originalValue: string;
readonly scmAnnotations: RssResultAnnotation[];
readonly transformation: string;
constructor(result: IRssResult, readonly originalKey: string) {
this.value = result.value;
this.originalValue = result.originalValue;
const scmAnnotations = result.scmAnnotations ?? [];
this.scmAnnotations = scmAnnotations.map(annotation => ({
...annotation,
displayName: annotation.reason.split('found')?.[0]?.trim(),
}));
this.transformation = result.transformation;
}
}