From c94ef488446dfddfe16ad48461fd60edd51c8539 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Mon, 23 Oct 2023 17:58:18 +0300 Subject: [PATCH] RED-7619 wip migration to entity log --- apps/red-ui/src/app/app.module.ts | 2 +- .../src/app/models/file/annotation.wrapper.ts | 212 ++++++++++-------- .../services/file-data.service.ts | 46 ++-- .../services/files/redaction-log.service.ts | 21 +- libs/common-ui | 2 +- .../src/lib/legal-basis/legal-basis.ts | 6 +- .../src/lib/redaction-log/entity-log-entry.ts | 40 ++++ .../src/lib/redaction-log/entity-log.ts | 13 ++ .../src/lib/redaction-log/entity-states.ts | 8 + .../src/lib/redaction-log/entry-types.ts | 11 + .../red-domain/src/lib/redaction-log/index.ts | 4 + 11 files changed, 224 insertions(+), 141 deletions(-) create mode 100644 libs/red-domain/src/lib/redaction-log/entity-log-entry.ts create mode 100644 libs/red-domain/src/lib/redaction-log/entity-log.ts create mode 100644 libs/red-domain/src/lib/redaction-log/entity-states.ts create mode 100644 libs/red-domain/src/lib/redaction-log/entry-types.ts diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index d6d506950..66a4c04cd 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -156,7 +156,7 @@ export const appModuleFactory = (config: AppConfig) => { enabled: false, }, REDACTION_LOG: { - enabled: false, + enabled: true, }, VIEWED_PAGES: { enabled: false, diff --git a/apps/red-ui/src/app/models/file/annotation.wrapper.ts b/apps/red-ui/src/app/models/file/annotation.wrapper.ts index 91c88b5bc..f27200460 100644 --- a/apps/red-ui/src/app/models/file/annotation.wrapper.ts +++ b/apps/red-ui/src/app/models/file/annotation.wrapper.ts @@ -9,13 +9,15 @@ import { DefaultColors, Dictionary, Earmark, + EntryStates, + EntryTypes, FalsePositiveSuperTypes, IComment, + IEntityLogEntry, ILegalBasis, IManualChange, IPoint, IRectangle, - IRedactionLogEntry, LogEntryEngine, LogEntryEngines, LogEntryStatuses, @@ -296,7 +298,7 @@ export class AnnotationWrapper implements IListable { } static fromData( - redactionLogEntry: IRedactionLogEntry, + logEntry: IEntityLogEntry, dictionaries: Dictionary[], defaultColors: DefaultColors, changeLogType: ChangeType, @@ -306,56 +308,61 @@ export class AnnotationWrapper implements IListable { ) { const annotationWrapper = new AnnotationWrapper(); - annotationWrapper.id = redactionLogEntry.id; + annotationWrapper.id = logEntry.id; annotationWrapper.isChangeLogEntry = !!changeLogType; annotationWrapper.changeLogType = changeLogType; annotationWrapper.legalBasisList = legalBasisList; - annotationWrapper.redaction = redactionLogEntry.redacted; - annotationWrapper.hint = redactionLogEntry.hint; - annotationWrapper.typeValue = redactionLogEntry.type; - annotationWrapper.value = redactionLogEntry.value; - annotationWrapper.firstTopLeftPoint = redactionLogEntry.positions[0]?.topLeft; - annotationWrapper.pageNumber = redactionLogEntry.positions[0]?.page; - annotationWrapper.positions = redactionLogEntry.positions; - annotationWrapper.textBefore = redactionLogEntry.textBefore; - annotationWrapper.textAfter = redactionLogEntry.textAfter; - annotationWrapper.dictionaryOperation = redactionLogEntry.dictionaryEntry; - annotationWrapper.image = redactionLogEntry.image; - annotationWrapper.imported = redactionLogEntry.imported; - annotationWrapper.legalBasisValue = redactionLogEntry.legalBasis; - annotationWrapper.comments = redactionLogEntry.comments || []; - annotationWrapper.manual = redactionLogEntry.manualChanges?.length > 0; - annotationWrapper.engines = redactionLogEntry.engines; - annotationWrapper.section = redactionLogEntry.section; - annotationWrapper.reference = redactionLogEntry.reference || []; - annotationWrapper.rectangle = redactionLogEntry.rectangle; + annotationWrapper.redaction = logEntry.entryType === EntryTypes.ENTITY; + annotationWrapper.hint = logEntry.entryType === EntryTypes.HINT; + annotationWrapper.typeValue = logEntry.type; + annotationWrapper.value = logEntry.value; + annotationWrapper.firstTopLeftPoint = { x: logEntry.positions[0].rectangle[0], y: logEntry.positions[0].rectangle[1] }; + annotationWrapper.pageNumber = logEntry.positions[0].pageNumber; + annotationWrapper.positions = logEntry.positions.map(p => ({ + page: p.pageNumber, + height: p.rectangle[3], + width: p.rectangle[2], + topLeft: { x: p.rectangle[0], y: p.rectangle[1] }, + })); + annotationWrapper.textBefore = logEntry.textBefore; + annotationWrapper.textAfter = logEntry.textAfter; + annotationWrapper.dictionaryOperation = logEntry.dictionaryEntry; + annotationWrapper.image = logEntry.entryType === EntryTypes.IMAGE; + annotationWrapper.imported = logEntry.imported; + annotationWrapper.legalBasisValue = logEntry.legalBasis; + annotationWrapper.comments = []; //logEntry.comments || []; + annotationWrapper.manual = logEntry.manualChanges?.length > 0; + annotationWrapper.engines = logEntry.engines; + annotationWrapper.section = logEntry.section; + annotationWrapper.reference = logEntry.reference || []; + annotationWrapper.rectangle = logEntry.entryType === EntryTypes.AREA; annotationWrapper.hintDictionary = hintDictionary; - annotationWrapper.hasBeenResized = !!redactionLogEntry.manualChanges?.find( + annotationWrapper.hasBeenResized = !!logEntry.manualChanges?.find( c => c.manualRedactionType === ManualRedactionTypes.RESIZE && c.annotationStatus === LogEntryStatuses.APPROVED, ); - annotationWrapper.hasBeenRecategorized = !!redactionLogEntry.manualChanges?.find( + annotationWrapper.hasBeenRecategorized = !!logEntry.manualChanges?.find( c => c.manualRedactionType === ManualRedactionTypes.RECATEGORIZE && c.annotationStatus === LogEntryStatuses.APPROVED, ); - annotationWrapper.hasLegalBasisChanged = !!redactionLogEntry.manualChanges?.find( + annotationWrapper.hasLegalBasisChanged = !!logEntry.manualChanges?.find( c => c.manualRedactionType === ManualRedactionTypes.LEGAL_BASIS_CHANGE && c.annotationStatus === LogEntryStatuses.APPROVED, ); - annotationWrapper.hasBeenForcedHint = !!redactionLogEntry.manualChanges?.find( + annotationWrapper.hasBeenForcedHint = !!logEntry.manualChanges?.find( c => c.manualRedactionType === ManualRedactionTypes.FORCE_HINT && c.annotationStatus === LogEntryStatuses.APPROVED, ); - annotationWrapper.hasBeenForcedRedaction = !!redactionLogEntry.manualChanges?.find( + annotationWrapper.hasBeenForcedRedaction = !!logEntry.manualChanges?.find( c => c.manualRedactionType === ManualRedactionTypes.FORCE_REDACT && c.annotationStatus === LogEntryStatuses.APPROVED, ); - annotationWrapper.hasBeenRemovedByManualOverride = !!redactionLogEntry.manualChanges?.find( + annotationWrapper.hasBeenRemovedByManualOverride = !!logEntry.manualChanges?.find( c => c.manualRedactionType === ManualRedactionTypes.REMOVE_LOCALLY && c.annotationStatus === LogEntryStatuses.APPROVED, ); - annotationWrapper.legalBasisChangeValue = redactionLogEntry.manualChanges?.find( + annotationWrapper.legalBasisChangeValue = logEntry.manualChanges?.find( c => c.manualRedactionType === ManualRedactionTypes.LEGAL_BASIS_CHANGE && c.annotationStatus === LogEntryStatuses.REQUESTED, )?.propertyChanges.legalBasis; - this.#createContent(annotationWrapper, redactionLogEntry, isDocumine); - this.#setSuperType(annotationWrapper, redactionLogEntry); - this.#handleRecommendations(annotationWrapper, redactionLogEntry); - annotationWrapper.typeLabel = this.#getTypeLabel(redactionLogEntry, annotationWrapper); + this.#createContent(annotationWrapper, logEntry, isDocumine); + this.#setSuperType(annotationWrapper, logEntry); + this.#handleRecommendations(annotationWrapper, logEntry); + annotationWrapper.typeLabel = this.#getTypeLabel(logEntry, annotationWrapper); const entity = dictionaries.find(d => d.type === annotationWrapper.typeValue); annotationWrapper.entity = entity?.virtual ? null : entity; @@ -373,8 +380,8 @@ export class AnnotationWrapper implements IListable { return annotationWrapper; } - static #getTypeLabel(redactionLogEntry: IRedactionLogEntry, annotation: AnnotationWrapper): string { - if (redactionLogEntry.reason?.toLowerCase() === 'false positive') { + static #getTypeLabel(logEntry: IEntityLogEntry, annotation: AnnotationWrapper): string { + if (logEntry.reason?.toLowerCase() === 'false positive') { return annotationTypesTranslations[SuggestionAddFalsePositive]; } if (annotation.superType === SuperTypes.ManualRedaction && annotation.hintDictionary) { @@ -383,38 +390,48 @@ export class AnnotationWrapper implements IListable { return annotationTypesTranslations[annotation.superType]; } - static #handleRecommendations(annotationWrapper: AnnotationWrapper, redactionLogEntry: IRedactionLogEntry) { + static #handleRecommendations(annotationWrapper: AnnotationWrapper, logEntry: IEntityLogEntry) { if (annotationWrapper.superType === SuperTypes.Recommendation) { - annotationWrapper.recommendationType = redactionLogEntry.type; + annotationWrapper.recommendationType = logEntry.type; } } - static #setSuperType(annotationWrapper: AnnotationWrapper, entry: IRedactionLogEntry) { - if (entry.manualChanges?.length) { - const lastRelevantManualChange = entry.manualChanges?.at(-1); - const viableChanges = entry.changes.filter(c => c.analysisNumber > 1); + static #setSuperType(annotationWrapper: AnnotationWrapper, logEntry: IEntityLogEntry) { + if (logEntry.manualChanges?.length) { + const lastRelevantManualChange = logEntry.manualChanges?.at(-1); + const viableChanges = logEntry.changes.filter(c => c.analysisNumber > 1); const lastChange = viableChanges.sort(chronologicallyBy(x => x.dateTime)).at(-1); const lastChangeOccurredAfterLastManualChange = lastChange && timestampOf(lastChange.dateTime) > timestampOf(lastRelevantManualChange.processedDate); - if (lastChangeOccurredAfterLastManualChange && lastChange.type === ChangeTypes.ADDED && entry.redacted) { + if ( + lastChangeOccurredAfterLastManualChange && + lastChange.type === ChangeTypes.ADDED && + logEntry.entryType === EntryTypes.ENTITY + ) { annotationWrapper.superType = SuperTypes.Redaction; return; } annotationWrapper.pending = !lastRelevantManualChange.processed; - annotationWrapper.superType = this.#selectSuperType(entry, lastRelevantManualChange, annotationWrapper.hintDictionary); + annotationWrapper.superType = this.#selectSuperType(logEntry, lastRelevantManualChange, annotationWrapper.hintDictionary); if (lastRelevantManualChange.annotationStatus === LogEntryStatuses.REQUESTED) { annotationWrapper.recategorizationType = lastRelevantManualChange.propertyChanges.type; } } else { - if (entry.recommendation) { + if (logEntry.state === EntryStates.SKIPPED) { + if (logEntry.entryType === EntryTypes.HINT) { + annotationWrapper.superType = SuperTypes.Hint; + } else { + annotationWrapper.superType = SuperTypes.Skipped; + } + } else if (logEntry.entryType === EntryTypes.RECOMMENDATION) { annotationWrapper.superType = SuperTypes.Recommendation; - } else if (entry.redacted) { + } else if (logEntry.entryType === EntryTypes.ENTITY) { annotationWrapper.superType = SuperTypes.Redaction; - } else if (entry.hint) { + } else if (logEntry.entryType === EntryTypes.HINT) { annotationWrapper.superType = SuperTypes.Hint; } else { annotationWrapper.superType = SuperTypes.Skipped; @@ -422,18 +439,18 @@ export class AnnotationWrapper implements IListable { } } - static #createContent(annotationWrapper: AnnotationWrapper, entry: IRedactionLogEntry, isDocumine: boolean) { + static #createContent(annotationWrapper: AnnotationWrapper, logEntry: IEntityLogEntry, isDocumine: boolean) { let content = ''; - if (entry.matchedRule) { - content += `Rule ${entry.matchedRule} matched${isDocumine ? ':' : ''} \n\n`; + if (logEntry.matchedRule) { + content += `Rule ${logEntry.matchedRule} matched${isDocumine ? ':' : ''} \n\n`; } - if (entry.reason) { - if (isDocumine && entry.reason.slice(-1) === '.') { - entry.reason = entry.reason.slice(0, -1); + if (logEntry.reason) { + if (isDocumine && logEntry.reason.slice(-1) === '.') { + logEntry.reason = logEntry.reason.slice(0, -1); } - content += entry.reason + '\n\n'; + content += logEntry.reason + '\n\n'; //remove leading and trailing commas and whitespaces content = content.replace(/(^[, ]*)|([, ]*$)/g, ''); content = content.substring(0, 1).toUpperCase() + content.substring(1); @@ -447,12 +464,12 @@ export class AnnotationWrapper implements IListable { content += 'Removed by manual override'; } - if (entry.section) { + if (logEntry.section) { let prefix = `In section${isDocumine ? '' : ':'} `; if (content.length) { prefix = ` ${prefix.toLowerCase()}`; } - content += `${prefix} "${entry.section}"`; + content += `${prefix} "${logEntry.section}"`; } annotationWrapper.shortContent = this.#getShortContent(annotationWrapper) || content; @@ -472,7 +489,7 @@ export class AnnotationWrapper implements IListable { return annotationWrapper.legalBasis; } - static #selectSuperType(redactionLogEntry: IRedactionLogEntry, lastManualChange: IManualChange, isHintDictionary: boolean): SuperType { + static #selectSuperType(logEntry: IEntityLogEntry, lastManualChange: IManualChange, isHintDictionary: boolean): SuperType { switch (lastManualChange.manualRedactionType) { case ManualRedactionTypes.ADD_LOCALLY: switch (lastManualChange.annotationStatus) { @@ -503,7 +520,7 @@ export class AnnotationWrapper implements IListable { return SuperTypes.Hint; } - if (redactionLogEntry.redacted) { + if (logEntry.entryType === EntryTypes.ENTITY) { return SuperTypes.Redaction; } @@ -514,7 +531,7 @@ export class AnnotationWrapper implements IListable { } break; case ManualRedactionTypes.REMOVE_FROM_DICTIONARY: - if (redactionLogEntry.redacted) { + if (logEntry.entryType === EntryTypes.ENTITY) { if (lastManualChange.processed) { switch (lastManualChange.annotationStatus) { case LogEntryStatuses.APPROVED: @@ -524,35 +541,34 @@ export class AnnotationWrapper implements IListable { case LogEntryStatuses.REQUESTED: return SuperTypes.SuggestionRemoveDictionary; } - } else { - switch (lastManualChange.annotationStatus) { - case LogEntryStatuses.APPROVED: - case LogEntryStatuses.DECLINED: - return SuperTypes.Redaction; - case LogEntryStatuses.REQUESTED: - return SuperTypes.SuggestionRemoveDictionary; - } } - } else { - if (lastManualChange.processed) { - switch (lastManualChange.annotationStatus) { - case LogEntryStatuses.APPROVED: - return redactionLogEntry.recommendation ? SuperTypes.Recommendation : SuperTypes.Skipped; - case LogEntryStatuses.DECLINED: - return isHintDictionary ? SuperTypes.Hint : SuperTypes.Skipped; - case LogEntryStatuses.REQUESTED: - return SuperTypes.SuggestionRemoveDictionary; - } - } else { - switch (lastManualChange.annotationStatus) { - case LogEntryStatuses.APPROVED: - case LogEntryStatuses.DECLINED: - return isHintDictionary ? SuperTypes.Hint : SuperTypes.Skipped; - case LogEntryStatuses.REQUESTED: - return SuperTypes.SuggestionRemoveDictionary; - } + switch (lastManualChange.annotationStatus) { + case LogEntryStatuses.APPROVED: + case LogEntryStatuses.DECLINED: + return SuperTypes.Redaction; + case LogEntryStatuses.REQUESTED: + return SuperTypes.SuggestionRemoveDictionary; } } + + if (lastManualChange.processed) { + switch (lastManualChange.annotationStatus) { + case LogEntryStatuses.APPROVED: + return logEntry.entryType === EntryTypes.RECOMMENDATION ? SuperTypes.Recommendation : SuperTypes.Skipped; + case LogEntryStatuses.DECLINED: + return isHintDictionary ? SuperTypes.Hint : SuperTypes.Skipped; + case LogEntryStatuses.REQUESTED: + return SuperTypes.SuggestionRemoveDictionary; + } + } + + switch (lastManualChange.annotationStatus) { + case LogEntryStatuses.APPROVED: + case LogEntryStatuses.DECLINED: + return isHintDictionary ? SuperTypes.Hint : SuperTypes.Skipped; + case LogEntryStatuses.REQUESTED: + return SuperTypes.SuggestionRemoveDictionary; + } break; case ManualRedactionTypes.FORCE_REDACT: switch (lastManualChange.annotationStatus) { @@ -578,13 +594,18 @@ export class AnnotationWrapper implements IListable { switch (lastManualChange.annotationStatus) { case LogEntryStatuses.APPROVED: case LogEntryStatuses.DECLINED: { - if (redactionLogEntry.recommendation) { + if (logEntry.entryType === EntryTypes.RECOMMENDATION) { return SuperTypes.Recommendation; - } else if (redactionLogEntry.redacted) { + } + + if (logEntry.entryType === EntryTypes.ENTITY) { return SuperTypes.Redaction; - } else if (redactionLogEntry.hint) { + } + + if (logEntry.entryType === EntryTypes.HINT) { return SuperTypes.Hint; } + return isHintDictionary ? SuperTypes.IgnoredHint : SuperTypes.Skipped; } case LogEntryStatuses.REQUESTED: @@ -595,7 +616,7 @@ export class AnnotationWrapper implements IListable { switch (lastManualChange.annotationStatus) { case LogEntryStatuses.APPROVED: case LogEntryStatuses.DECLINED: - return redactionLogEntry.type === SuperTypes.ManualRedaction ? SuperTypes.ManualRedaction : SuperTypes.Redaction; + return logEntry.type === SuperTypes.ManualRedaction ? SuperTypes.ManualRedaction : SuperTypes.Redaction; case LogEntryStatuses.REQUESTED: return SuperTypes.SuggestionChangeLegalBasis; } @@ -604,17 +625,18 @@ export class AnnotationWrapper implements IListable { switch (lastManualChange.annotationStatus) { case LogEntryStatuses.APPROVED: case LogEntryStatuses.DECLINED: - if (redactionLogEntry.recommendation) { + if (logEntry.entryType === EntryTypes.RECOMMENDATION) { return SuperTypes.Recommendation; - } else if (redactionLogEntry.redacted) { - return redactionLogEntry.type === SuperTypes.ManualRedaction - ? SuperTypes.ManualRedaction - : SuperTypes.Redaction; - } else if (redactionLogEntry.hint) { + } + + if (logEntry.entryType === EntryTypes.ENTITY) { + return logEntry.type === SuperTypes.ManualRedaction ? SuperTypes.ManualRedaction : SuperTypes.Redaction; + } + + if (logEntry.entryType === EntryTypes.HINT) { return SuperTypes.Hint; } return isHintDictionary ? SuperTypes.IgnoredHint : SuperTypes.Skipped; - case LogEntryStatuses.REQUESTED: return SuperTypes.SuggestionResize; } diff --git a/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts b/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts index f69410fe2..9ab30726b 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts @@ -3,17 +3,7 @@ import { toObservable } from '@angular/core/rxjs-interop'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { EntitiesService, getConfig, Toaster } from '@iqser/common-ui'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; -import { - ChangeType, - ChangeTypes, - File, - IRedactionLog, - IRedactionLogEntry, - LogEntryStatuses, - ViewedPage, - ViewMode, - ViewModes, -} from '@red/domain'; +import { ChangeType, ChangeTypes, File, IEntityLog, IEntityLogEntry, LogEntryStatuses, ViewedPage, ViewMode, ViewModes } from '@red/domain'; import { DefaultColorsService } from '@services/entity-services/default-colors.service'; import { DictionaryService } from '@services/entity-services/dictionary.service'; import { EarmarksService } from '@services/files/earmarks.service'; @@ -132,7 +122,7 @@ export class FileDataService extends EntitiesService 0; if (!manual && file.excludedPages.includes(pageNumber)) { continue; @@ -219,17 +209,17 @@ export class FileDataService extends EntitiesService 0; + const hasManualChanges = entityLogEntry.manualChanges?.length > 0; if (file.numberOfAnalyses <= 1 && !file.hasUpdates && !hasManualChanges) { return { changeLogType: undefined, @@ -253,10 +243,10 @@ export class FileDataService extends EntitiesService c.analysisNumber > 1); + const viableChanges = entityLogEntry.changes?.filter(c => c.analysisNumber > 1); const lastChange = viableChanges?.sort(chronologicallyBy(x => x.dateTime)).at(-1); - const page = redactionLogEntry.positions?.[0].page; + const page = entityLogEntry.positions?.[0].pageNumber; const viewedPage = this.#originalViewedPages.find(p => p.page === page); if (!viewedPage) { @@ -279,7 +269,7 @@ export class FileDataService extends EntitiesService visibleStatuses.includes(change.annotationStatus)); + const viableManualChanges = entityLogEntry.manualChanges.filter(change => visibleStatuses.includes(change.annotationStatus)); viableManualChanges.sort(chronologicallyBy(x => x.processedDate)); const lastManualChange = viableManualChanges.at(-1); const isSuggestion = lastManualChange?.annotationStatus === LogEntryStatuses.REQUESTED; diff --git a/apps/red-ui/src/app/services/files/redaction-log.service.ts b/apps/red-ui/src/app/services/files/redaction-log.service.ts index 8e9133564..f8a4cf55f 100644 --- a/apps/red-ui/src/app/services/files/redaction-log.service.ts +++ b/apps/red-ui/src/app/services/files/redaction-log.service.ts @@ -1,8 +1,8 @@ import { Injectable } from '@angular/core'; -import { GenericService, QueryParam } from '@iqser/common-ui'; -import { IRedactionLog, ISectionGrid } from '@red/domain'; -import { catchError } from 'rxjs/operators'; +import { GenericService } from '@iqser/common-ui'; +import { IEntityLog, ISectionGrid } from '@red/domain'; import { firstValueFrom, of } from 'rxjs'; +import { catchError } from 'rxjs/operators'; @Injectable({ providedIn: 'root', @@ -10,16 +10,11 @@ import { firstValueFrom, of } from 'rxjs'; export class RedactionLogService extends GenericService { protected readonly _defaultModelPath = ''; - async getRedactionLog(dossierId: string, fileId: string, withManualRedactions?: boolean) { - const queryParams: QueryParam[] = []; - if (withManualRedactions) { - queryParams.push({ key: 'withManualRedactions', value: withManualRedactions }); - } - - const redactionLog$ = this._getOne([dossierId, fileId], 'redactionLog', queryParams); - const redactionLog = await firstValueFrom(redactionLog$.pipe(catchError(() => of({} as IRedactionLog)))); - redactionLog.redactionLogEntry.sort((a, b) => a.positions[0].page - b.positions[0].page); - return redactionLog; + async getEntityLog(dossierId: string, fileId: string) { + const entityLog$ = this._getOne([dossierId, fileId], 'entityLog'); + const entityLog = await firstValueFrom(entityLog$.pipe(catchError(() => of({} as IEntityLog)))); + entityLog.entityLogEntry.sort((a, b) => a.positions[0].pageNumber - b.positions[0].pageNumber); + return entityLog; } getSectionGrid(dossierId: string, fileId: string) { diff --git a/libs/common-ui b/libs/common-ui index a6383c1db..85fba4a1d 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit a6383c1dbc840115897a31567c3f5633ba78b43a +Subproject commit 85fba4a1dd57ecbb133d938552d75fceffa1099c diff --git a/libs/red-domain/src/lib/legal-basis/legal-basis.ts b/libs/red-domain/src/lib/legal-basis/legal-basis.ts index 3ec087e3a..2e750f84d 100644 --- a/libs/red-domain/src/lib/legal-basis/legal-basis.ts +++ b/libs/red-domain/src/lib/legal-basis/legal-basis.ts @@ -1,5 +1,5 @@ export interface ILegalBasis { - name: string; - description?: string; - reason?: string; + readonly name: string; + readonly description?: string; + readonly reason?: string; } diff --git a/libs/red-domain/src/lib/redaction-log/entity-log-entry.ts b/libs/red-domain/src/lib/redaction-log/entity-log-entry.ts new file mode 100644 index 000000000..9b47d1645 --- /dev/null +++ b/libs/red-domain/src/lib/redaction-log/entity-log-entry.ts @@ -0,0 +1,40 @@ +import { ITrackable } from '@iqser/common-ui'; +import { IChange } from './change'; +import { EntryState } from './entity-states'; +import { EntryType } from './entry-types'; +import { IManualChange } from './manual-change'; +import { LogEntryEngine } from './types'; + +export interface IEntityLogEntryPosition { + readonly pageNumber: number; + readonly rectangle: readonly [number, number, number, number]; +} + +export interface IEntityLogEntry extends ITrackable { + type: string; + entryType: EntryType; + state: EntryState; + value: string; + reason: string; + matchedRule: string; + legalBasis: string; + imported: boolean; + containingNodeId: number[]; + closestHeadline: string; + section: string; + color: number[]; + positions: IEntityLogEntryPosition[]; + textAfter?: string; + textBefore?: string; + startOffset?: number; + endOffset?: number; + imageHasTransparency: boolean; + dictionaryEntry: boolean; + dossierDictionaryEntry: boolean; + excluded: boolean; + changes: IChange[]; + manualChanges: IManualChange[]; + engines: LogEntryEngine[]; + reference: string[]; + importedRedactionIntersections: string[]; +} diff --git a/libs/red-domain/src/lib/redaction-log/entity-log.ts b/libs/red-domain/src/lib/redaction-log/entity-log.ts new file mode 100644 index 000000000..e53d2b900 --- /dev/null +++ b/libs/red-domain/src/lib/redaction-log/entity-log.ts @@ -0,0 +1,13 @@ +import { ILegalBasis } from '../legal-basis'; +import { IEntityLogEntry } from './entity-log-entry'; + +export interface IEntityLog { + analysisVersion: number; + analysisNumber: number; + entityLogEntry: IEntityLogEntry[]; + legalBasis: ILegalBasis[]; + dictionaryVersion: number; + dossierDictionaryVersion: number; + rulesVersion: number; + legalBasisVersion: number; +} diff --git a/libs/red-domain/src/lib/redaction-log/entity-states.ts b/libs/red-domain/src/lib/redaction-log/entity-states.ts new file mode 100644 index 000000000..2507f1bdb --- /dev/null +++ b/libs/red-domain/src/lib/redaction-log/entity-states.ts @@ -0,0 +1,8 @@ +export const EntryStates = { + APPLIED: 'APPLIED', + SKIPPED: 'SKIPPED', + IGNORED: 'IGNORED', + REMOVED: 'REMOVED', +} as const; + +export type EntryState = (typeof EntryStates)[keyof typeof EntryStates]; diff --git a/libs/red-domain/src/lib/redaction-log/entry-types.ts b/libs/red-domain/src/lib/redaction-log/entry-types.ts new file mode 100644 index 000000000..d14b051b4 --- /dev/null +++ b/libs/red-domain/src/lib/redaction-log/entry-types.ts @@ -0,0 +1,11 @@ +export const EntryTypes = { + ENTITY: 'ENTITY', + HINT: 'HINT', + FALSE_POSITIVE: 'FALSE_POSITIVE', + RECOMMENDATION: 'RECOMMENDATION', + FALSE_RECOMMENDATION: 'FALSE_RECOMMENDATION', + AREA: 'AREA', + IMAGE: 'IMAGE', +} as const; + +export type EntryType = (typeof EntryTypes)[keyof typeof EntryTypes]; diff --git a/libs/red-domain/src/lib/redaction-log/index.ts b/libs/red-domain/src/lib/redaction-log/index.ts index 3ae3bf570..5ebab18b3 100644 --- a/libs/red-domain/src/lib/redaction-log/index.ts +++ b/libs/red-domain/src/lib/redaction-log/index.ts @@ -12,3 +12,7 @@ export * from './recategorization.request'; export * from './resize.request'; export * from './manual-change'; export * from './dictionary-entry-types'; +export * from './entity-log'; +export * from './entity-log-entry'; +export * from './entity-states'; +export * from './entry-types';