diff --git a/apps/red-ui/src/app/models/file/annotation-permissions.utils.ts b/apps/red-ui/src/app/models/file/annotation-permissions.utils.ts index 4a70ac52c..5d64803f6 100644 --- a/apps/red-ui/src/app/models/file/annotation-permissions.utils.ts +++ b/apps/red-ui/src/app/models/file/annotation-permissions.utils.ts @@ -32,7 +32,7 @@ export const canChangeLegalBasis = (annotation: AnnotationWrapper, canAddRedacti canAddRedaction && annotation.isRedacted && !annotation.pending; export const canRecategorizeAnnotation = (annotation: AnnotationWrapper, canRecategorize: boolean) => - canRecategorize && (annotation.isImage || annotation.hintDictionary) && !annotation.pending; + canRecategorize && (annotation.isImage || annotation.HINT) && !annotation.pending; export const canResizeAnnotation = (annotation: AnnotationWrapper, canAddRedaction: boolean) => canAddRedaction && 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 a4807fed9..996bb68c8 100644 --- a/apps/red-ui/src/app/models/file/annotation.wrapper.ts +++ b/apps/red-ui/src/app/models/file/annotation.wrapper.ts @@ -4,81 +4,67 @@ import { annotationEntityColorConfig, AnnotationIconType, ChangeType, - ChangeTypes, Dictionary, Earmark, + EntityTypes, EntryStates, - EntryTypes, FalsePositiveSuperTypes, IComment, IEntityLogEntry, ILegalBasis, - IManualChange, IPoint, IRectangle, LogEntryEngine, LogEntryEngines, - LogEntryStatuses, LowLevelFilterTypes, ManualRedactionTypes, SuperType, + SuperTypeMapper, SuperTypes, } from '@red/domain'; import { annotationTypesTranslations } from '@translations/annotation-types-translations'; -import { chronologicallyBy, timestampOf } from '../../modules/file-preview/services/file-data.service'; export class AnnotationWrapper implements IListable { - [x: string]: unknown; - + id: string; superType: SuperType; - typeValue: string; + superTypeLabel: string; + type: string; + typeLabel?: string; color: string; - entity: Dictionary; comments: IComment[] = []; firstTopLeftPoint: IPoint; - id: string; shortContent: string; content: string; value: string; - typeLabel: string; pageNumber: number; - HINT = false; - redaction = false; - status: string; dictionaryOperation = false; - positions: IRectangle[]; - recommendationType: string; + positions: IRectangle[] = []; legalBasisValue: string; // AREA === rectangle AREA = false; - section?: string; - reference: string[]; - imported = false; + HINT = false; IMAGE = false; + section?: string; + reference: string[] = []; + imported = false; manual = false; pending = false; - hintDictionary = false; textAfter?: string; textBefore?: string; isChangeLogEntry = false; - changeLogType?: 'ADDED' | 'REMOVED' | 'CHANGED'; - engines?: LogEntryEngine[]; + engines: LogEntryEngine[] = []; hasBeenResized: boolean; hasBeenRecategorized: boolean; hasLegalBasisChanged: boolean; hasBeenForcedHint: boolean; hasBeenForcedRedaction: boolean; hasBeenRemovedByManualOverride: boolean; - legalBasisList: ILegalBasis[] = []; + isIgnored = false; get searchKey(): string { return this.id; } - get isChangeLogRemoved() { - return this.changeLogType === 'REMOVED'; - } - get descriptor() { return this.isModifyDictionary ? _('dictionary') : _('type'); } @@ -113,10 +99,6 @@ export class AnnotationWrapper implements IListable { return this.type?.toLowerCase() === 'ocr'; } - get type() { - return this.typeValue; - } - get topLevelFilter() { return !LowLevelFilterTypes[this.superType]; } @@ -146,7 +128,7 @@ export class AnnotationWrapper implements IListable { return 'hexagon'; } - if (this.isHint || this.isIgnoredHint) { + if (this.HINT) { return 'circle'; } @@ -214,33 +196,28 @@ export class AnnotationWrapper implements IListable { annotationWrapper.id = earmark.id; annotationWrapper.pageNumber = earmark.positions[0].page; annotationWrapper.superType = SuperTypes.TextHighlight; - annotationWrapper.typeValue = SuperTypes.TextHighlight; + annotationWrapper.type = SuperTypes.TextHighlight; annotationWrapper.value = 'Imported'; annotationWrapper.color = earmark.hexColor; annotationWrapper.positions = earmark.positions; annotationWrapper.firstTopLeftPoint = earmark.positions[0]?.topLeft; - annotationWrapper.typeLabel = annotationTypesTranslations[annotationWrapper.superType]; + annotationWrapper.superTypeLabel = annotationTypesTranslations[annotationWrapper.superType]; return annotationWrapper; } static fromData( logEntry: IEntityLogEntry, - dictionaries: Dictionary[], + dictionary: Dictionary, changeLogType: ChangeType, legalBasisList: ILegalBasis[], - hintDictionary: boolean, isDocumine: boolean, ) { const annotationWrapper = new AnnotationWrapper(); annotationWrapper.id = logEntry.id; annotationWrapper.isChangeLogEntry = !!changeLogType; - annotationWrapper.changeLogType = changeLogType; - annotationWrapper.legalBasisList = legalBasisList; - annotationWrapper.redaction = logEntry.entryType === EntryTypes.ENTITY; - annotationWrapper.HINT = logEntry.entryType === EntryTypes.HINT; - annotationWrapper.typeValue = logEntry.type; + annotationWrapper.type = 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; @@ -253,102 +230,64 @@ export class AnnotationWrapper implements IListable { annotationWrapper.textBefore = logEntry.textBefore; annotationWrapper.textAfter = logEntry.textAfter; annotationWrapper.dictionaryOperation = logEntry.dictionaryEntry; - annotationWrapper.IMAGE = logEntry.entryType === EntryTypes.IMAGE; + + annotationWrapper.HINT = logEntry.entryType === EntityTypes.HINT; + annotationWrapper.IMAGE = logEntry.entryType === EntityTypes.IMAGE; + annotationWrapper.AREA = logEntry.entryType === EntityTypes.AREA; + + annotationWrapper.isIgnored = logEntry.state === EntryStates.IGNORED; + annotationWrapper.imported = logEntry.imported; annotationWrapper.legalBasisValue = logEntry.legalBasis; annotationWrapper.comments = []; //logEntry.comments || []; annotationWrapper.manual = logEntry.manualChanges?.length > 0; - annotationWrapper.engines = logEntry.engines; + annotationWrapper.engines = logEntry.engines ?? []; annotationWrapper.section = logEntry.section; annotationWrapper.reference = logEntry.reference || []; - annotationWrapper.AREA = logEntry.entryType === EntryTypes.AREA; - annotationWrapper.hintDictionary = hintDictionary; annotationWrapper.hasBeenResized = !!logEntry.manualChanges?.find( - c => c.manualRedactionType === ManualRedactionTypes.RESIZE && c.annotationStatus === LogEntryStatuses.APPROVED, + c => c.manualRedactionType === ManualRedactionTypes.RESIZE && c.processed, ); annotationWrapper.hasBeenRecategorized = !!logEntry.manualChanges?.find( - c => c.manualRedactionType === ManualRedactionTypes.RECATEGORIZE && c.annotationStatus === LogEntryStatuses.APPROVED, + c => c.manualRedactionType === ManualRedactionTypes.RECATEGORIZE && c.processed, ); annotationWrapper.hasLegalBasisChanged = !!logEntry.manualChanges?.find( - c => c.manualRedactionType === ManualRedactionTypes.LEGAL_BASIS_CHANGE && c.annotationStatus === LogEntryStatuses.APPROVED, + c => c.manualRedactionType === ManualRedactionTypes.LEGAL_BASIS_CHANGE && c.processed, ); annotationWrapper.hasBeenForcedHint = !!logEntry.manualChanges?.find( - c => c.manualRedactionType === ManualRedactionTypes.FORCE_HINT && c.annotationStatus === LogEntryStatuses.APPROVED, + c => c.manualRedactionType === ManualRedactionTypes.FORCE_HINT && c.processed, ); annotationWrapper.hasBeenForcedRedaction = !!logEntry.manualChanges?.find( - c => c.manualRedactionType === ManualRedactionTypes.FORCE_REDACT && c.annotationStatus === LogEntryStatuses.APPROVED, + c => c.manualRedactionType === ManualRedactionTypes.FORCE_REDACT && c.processed, ); annotationWrapper.hasBeenRemovedByManualOverride = !!logEntry.manualChanges?.find( - c => c.manualRedactionType === ManualRedactionTypes.REMOVE_LOCALLY && c.annotationStatus === LogEntryStatuses.APPROVED, + c => c.manualRedactionType === ManualRedactionTypes.REMOVE_LOCALLY && c.processed, ); - this.#createContent(annotationWrapper, logEntry, isDocumine); + this.#createContent(annotationWrapper, logEntry, isDocumine, legalBasisList); this.#setSuperType(annotationWrapper, logEntry); - this.#handleRecommendations(annotationWrapper, logEntry); - annotationWrapper.typeLabel = this.#getTypeLabel(annotationWrapper); + annotationWrapper.superTypeLabel = annotationTypesTranslations[annotationWrapper.superType]; - const entity = dictionaries.find(d => d.type === annotationWrapper.typeValue); - annotationWrapper.entity = entity?.virtual ? null : entity; + annotationWrapper.typeLabel = dictionary.virtual ? undefined : dictionary.label; const colorKey = annotationEntityColorConfig[annotationWrapper.superType]; - annotationWrapper.color = entity[colorKey] as string; + annotationWrapper.color = dictionary[colorKey] as string; + annotationWrapper['entry'] = logEntry; return annotationWrapper; } - static #getTypeLabel(annotation: AnnotationWrapper): string { - if (annotation.superType === SuperTypes.ManualRedaction && annotation.hintDictionary) { - return _('annotation-type.manual-hint'); - } - return annotationTypesTranslations[annotation.superType]; - } - - static #handleRecommendations(annotationWrapper: AnnotationWrapper, logEntry: IEntityLogEntry) { - if (annotationWrapper.superType === SuperTypes.Recommendation) { - annotationWrapper.recommendationType = logEntry.type; - } - } - 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 && - logEntry.entryType === EntryTypes.ENTITY - ) { - annotationWrapper.superType = SuperTypes.Redaction; - return; - } - - annotationWrapper.pending = !lastRelevantManualChange.processed; - - annotationWrapper.superType = this.#selectSuperType(logEntry, lastRelevantManualChange, annotationWrapper.hintDictionary); - } else { - 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 (logEntry.entryType === EntryTypes.ENTITY) { - annotationWrapper.superType = SuperTypes.Redaction; - } else if (logEntry.entryType === EntryTypes.HINT) { - annotationWrapper.superType = SuperTypes.Hint; - } else { - annotationWrapper.superType = SuperTypes.Skipped; - } - } + const lastRelevantManualChange = logEntry.manualChanges?.at(-1); + annotationWrapper.pending = lastRelevantManualChange && !lastRelevantManualChange.processed; + annotationWrapper.superType = SuperTypeMapper[logEntry.entryType][logEntry.state](logEntry); } - static #createContent(annotationWrapper: AnnotationWrapper, logEntry: IEntityLogEntry, isDocumine: boolean) { + static #createContent( + annotationWrapper: AnnotationWrapper, + logEntry: IEntityLogEntry, + isDocumine: boolean, + legalBasisList: ILegalBasis[], + ) { let content = ''; if (logEntry.matchedRule) { content += `Rule ${logEntry.matchedRule} matched${isDocumine ? ':' : ''} \n\n`; @@ -381,15 +320,13 @@ export class AnnotationWrapper implements IListable { content += `${prefix} "${logEntry.section}"`; } - annotationWrapper.shortContent = this.#getShortContent(annotationWrapper) || content; + annotationWrapper.shortContent = this.#getShortContent(annotationWrapper, legalBasisList) || content; annotationWrapper.content = content; } - static #getShortContent(annotationWrapper: AnnotationWrapper) { + static #getShortContent(annotationWrapper: AnnotationWrapper, legalBasisList: ILegalBasis[]) { if (annotationWrapper.legalBasis) { - const lb = annotationWrapper.legalBasisList.find( - lbm => lbm.reason?.toLowerCase().includes(annotationWrapper.legalBasis.toLowerCase()), - ); + const lb = legalBasisList.find(lbm => lbm.reason?.toLowerCase().includes(annotationWrapper.legalBasis.toLowerCase())); if (lb) { return lb.name; } @@ -397,98 +334,4 @@ export class AnnotationWrapper implements IListable { return annotationWrapper.legalBasis; } - - static #selectSuperType(logEntry: IEntityLogEntry, lastManualChange: IManualChange, isHintDictionary: boolean): SuperType { - switch (lastManualChange.manualRedactionType) { - case ManualRedactionTypes.ADD_LOCALLY: - return SuperTypes.ManualRedaction; - case ManualRedactionTypes.ADD_TO_DICTIONARY: - return isHintDictionary ? SuperTypes.Hint : SuperTypes.Redaction; - case ManualRedactionTypes.REMOVE_LOCALLY: - switch (lastManualChange.annotationStatus) { - case LogEntryStatuses.APPROVED: - return isHintDictionary ? SuperTypes.IgnoredHint : SuperTypes.Skipped; - case LogEntryStatuses.DECLINED: { - if (isHintDictionary) { - return SuperTypes.Hint; - } - - if (logEntry.entryType === EntryTypes.ENTITY) { - return SuperTypes.Redaction; - } - - return SuperTypes.Skipped; - } - } - break; - case ManualRedactionTypes.REMOVE_FROM_DICTIONARY: - if (logEntry.entryType === EntryTypes.ENTITY) { - if (lastManualChange.processed) { - switch (lastManualChange.annotationStatus) { - case LogEntryStatuses.APPROVED: - return SuperTypes.Skipped; - case LogEntryStatuses.DECLINED: - return SuperTypes.Redaction; - } - } - return SuperTypes.Redaction; - } - - 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; - } - } - - return isHintDictionary ? SuperTypes.Hint : SuperTypes.Skipped; - case ManualRedactionTypes.FORCE_REDACT: - switch (lastManualChange.annotationStatus) { - case LogEntryStatuses.APPROVED: - return SuperTypes.Redaction; - case LogEntryStatuses.DECLINED: - return isHintDictionary ? SuperTypes.IgnoredHint : SuperTypes.Skipped; - } - break; - case ManualRedactionTypes.FORCE_HINT: - switch (lastManualChange.annotationStatus) { - case LogEntryStatuses.APPROVED: - return SuperTypes.Hint; - case LogEntryStatuses.DECLINED: - return SuperTypes.IgnoredHint; - } - break; - case ManualRedactionTypes.RECATEGORIZE: - if (logEntry.entryType === EntryTypes.RECOMMENDATION) { - return SuperTypes.Recommendation; - } - - if (logEntry.entryType === EntryTypes.ENTITY) { - return SuperTypes.Redaction; - } - - if (logEntry.entryType === EntryTypes.HINT) { - return SuperTypes.Hint; - } - - return isHintDictionary ? SuperTypes.IgnoredHint : SuperTypes.Skipped; - case ManualRedactionTypes.LEGAL_BASIS_CHANGE: - return logEntry.type === SuperTypes.ManualRedaction ? SuperTypes.ManualRedaction : SuperTypes.Redaction; - case ManualRedactionTypes.RESIZE: - if (logEntry.entryType === EntryTypes.RECOMMENDATION) { - return SuperTypes.Recommendation; - } - - 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; - } - } } diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.html b/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.html index 1b5004da6..50a482417 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.html @@ -8,19 +8,19 @@