From ffa9a5830fa6042ab4ad246ca3112a038b7454de Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 27 Oct 2023 21:30:27 +0300 Subject: [PATCH] RED-7619 remove old super type logic, add new --- .../file/annotation-permissions.utils.ts | 2 +- .../src/app/models/file/annotation.wrapper.ts | 255 ++++-------------- .../annotation-card.component.html | 6 +- .../annotation-wrapper.component.html | 4 +- .../annotation-wrapper.component.ts | 10 +- .../file-workload/file-workload.component.ts | 2 +- .../resize-annotation-dialog.component.html | 2 +- .../resize-annotation-dialog.component.ts | 55 +--- .../resize-redaction-dialog.component.html | 4 +- .../resize-redaction-dialog.component.ts | 26 +- .../services/annotation-processing.service.ts | 2 +- .../services/file-data.service.ts | 58 +--- .../services/annotation-draw.service.ts | 6 +- .../annotation-types-translations.ts | 1 + .../app/utils/sorters/super-type-sorter.ts | 1 + .../src/lib/colors/annotation-color-config.ts | 19 +- libs/red-domain/src/lib/files/super-types.ts | 61 +++++ .../src/lib/redaction-log/entity-log-entry.ts | 4 +- .../{entry-types.ts => entity-types.ts} | 4 +- .../red-domain/src/lib/redaction-log/index.ts | 2 +- 20 files changed, 180 insertions(+), 344 deletions(-) rename libs/red-domain/src/lib/redaction-log/{entry-types.ts => entity-types.ts} (70%) 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 @@
- {{ annotation.typeLabel | translate }} + {{ annotation.superTypeLabel | translate }}   {{ 'annotation.pending' | translate }}
-
+
{{ annotation.descriptor | translate }}: - {{ annotation.entity.label }} + {{ annotation.typeLabel }}
-
+
!bool(a.isChangeLogRemoved)); + annotations = annotations.filter(a => !bool(a.isIgnored)); } if (this.#isDocumine && !this.#isIqserDevMode) { diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/resize-annotation-dialog/resize-annotation-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/resize-annotation-dialog/resize-annotation-dialog.component.html index 43e9c5abc..87bb9d9af 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/resize-annotation-dialog/resize-annotation-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/resize-annotation-dialog/resize-annotation-dialog.component.html @@ -5,7 +5,7 @@
- {{ redaction.value }} + {{ data.redaction.value }}
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/resize-annotation-dialog/resize-annotation-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/resize-annotation-dialog/resize-annotation-dialog.component.ts index 91070e5c6..fb6d55108 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/resize-annotation-dialog/resize-annotation-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/resize-annotation-dialog/resize-annotation-dialog.component.ts @@ -1,8 +1,6 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, inject } from '@angular/core'; import { FormBuilder } from '@angular/forms'; import { IconButtonTypes, IqserDialogComponent } from '@iqser/common-ui'; -import { AnnotationWrapper } from '@models/file/annotation.wrapper'; -import { Dictionary, Dossier } from '@red/domain'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import { ResizeAnnotationData, ResizeAnnotationResult } from '../../../utils/dialog-types'; @@ -10,51 +8,26 @@ import { ResizeAnnotationData, ResizeAnnotationResult } from '../../../utils/dia @Component({ templateUrl: './resize-annotation-dialog.component.html', }) -export class ResizeAnnotationDialogComponent - extends IqserDialogComponent - implements OnInit -{ - readonly #dossier: Dossier; +export class ResizeAnnotationDialogComponent extends IqserDialogComponent< + ResizeAnnotationDialogComponent, + ResizeAnnotationData, + ResizeAnnotationResult +> { + readonly #dossier = inject(ActiveDossiersService).find(this.data.dossierId); readonly iconButtonTypes = IconButtonTypes; - dictionaries: Dictionary[] = []; - redaction: AnnotationWrapper; - readonly form = this.#getForm(); - - constructor( - activeDossiersService: ActiveDossiersService, - private readonly _dictionariesMapService: DictionariesMapService, - private readonly _formBuilder: FormBuilder, - ) { - super(); - this.#dossier = activeDossiersService.find(this.data.dossierId); - this.redaction = this.data.redaction; - } - - get displayedDictionaryLabel() { - const dictType = this.form.get('dictionary').value; - if (dictType) { - return this.dictionaries.find(d => d.type === dictType)?.label ?? null; - } - return null; - } - - ngOnInit() { - this.dictionaries = this._dictionariesMapService.get(this.#dossier.dossierTemplateId); - } + readonly dictionaries = inject(DictionariesMapService).get(this.#dossier.dossierTemplateId); + readonly entity = this.dictionaries.find(d => d.type === this.data.redaction.type); + readonly form = inject(FormBuilder).group({ + comment: [null], + }); save() { const formValue = this.form.getRawValue(); this.close({ comment: formValue.comment, - updateDictionary: this.redaction.entity.hasDictionary, - addToAllDossiers: this.redaction.entity.hasDictionary, - }); - } - - #getForm() { - return this._formBuilder.group({ - comment: [null], + updateDictionary: this.entity.hasDictionary, + addToAllDossiers: this.entity.hasDictionary, }); } } diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.html index 20f694aa0..403ead085 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.html @@ -26,8 +26,8 @@ {{ displayedDictionaryLabel }} - - {{ redaction.entity.label }} + + {{ redaction.typeLabel }} diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.ts index e78831197..a3f16760c 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.ts @@ -1,7 +1,6 @@ -import { Component, inject, OnInit } from '@angular/core'; +import { Component, inject } from '@angular/core'; import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { DetailsRadioOption, IconButtonTypes, IqserDialogComponent } from '@iqser/common-ui'; -import { Dictionary } from '@red/domain'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import { getResizeRedactionOptions, ResizeOptions, ResizeRedactionOption } from '../../utils/dialog-options'; @@ -10,15 +9,17 @@ import { ResizeRedactionData, ResizeRedactionResult } from '../../utils/dialog-t @Component({ templateUrl: './resize-redaction-dialog.component.html', }) -export class ResizeRedactionDialogComponent - extends IqserDialogComponent - implements OnInit -{ +export class ResizeRedactionDialogComponent extends IqserDialogComponent< + ResizeRedactionDialogComponent, + ResizeRedactionData, + ResizeRedactionResult +> { readonly #applyToAllDossiers = this.data.applyToAllDossiers ?? true; readonly #dossier = inject(ActiveDossiersService).find(this.data.dossierId); readonly iconButtonTypes = IconButtonTypes; readonly options: DetailsRadioOption[]; - dictionaries: Dictionary[] = []; + readonly dictionaries = inject(DictionariesMapService).get(this.#dossier.dossierTemplateId); + readonly entity = this.dictionaries.find(d => d.type === this.data.redaction.type); readonly redaction = this.data.redaction; readonly form: FormGroup<{ comment: FormControl; @@ -26,10 +27,7 @@ export class ResizeRedactionDialogComponent option: FormControl>; }>; - constructor( - private readonly _dictionariesMapService: DictionariesMapService, - private readonly _formBuilder: FormBuilder, - ) { + constructor(private readonly _formBuilder: FormBuilder) { super(); this.options = getResizeRedactionOptions(this.redaction, this.#dossier, false, this.#applyToAllDossiers, this.data.isApprover); this.form = this.#getForm(); @@ -43,10 +41,6 @@ export class ResizeRedactionDialogComponent return null; } - ngOnInit() { - this.dictionaries = this._dictionariesMapService.get(this.#dossier.dossierTemplateId); - } - save() { const formValue = this.form.getRawValue(); const updateDictionary = formValue.option.value === ResizeOptions.IN_DOSSIER; @@ -61,7 +55,7 @@ export class ResizeRedactionDialogComponent #getForm() { return this._formBuilder.group({ comment: [null], - dictionary: new FormControl({ value: this.redaction.entity.type, disabled: true }), + dictionary: new FormControl({ value: this.redaction.typeLabel, disabled: true }), option: this.options[0], }); } diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts index 0fb05a0b3..0c7f3215f 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts @@ -106,7 +106,7 @@ export class AnnotationProcessingService { } const childFilter: IFilter = { id: a.filterKey, - label: a.entity.label, + label: a.typeLabel, checked: false, matches: 1, metadata: { 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 202f26ea3..f064a2682 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,7 +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, IEntityLog, IEntityLogEntry, LogEntryStatuses, ViewedPage, ViewMode, ViewModes } from '@red/domain'; +import { ChangeType, ChangeTypes, EntryStates, File, IEntityLog, IEntityLogEntry, ViewedPage, ViewMode, ViewModes } from '@red/domain'; import { DictionaryService } from '@services/entity-services/dictionary.service'; import { EarmarksService } from '@services/files/earmarks.service'; import { FilesService } from '@services/files/files.service'; @@ -154,7 +154,7 @@ export class FileDataService extends EntitiesService { if (viewMode === 'STANDARD') { - return !annotation.isChangeLogRemoved; + return !annotation.isIgnored; } if (viewMode === 'DELTA') { @@ -177,13 +177,12 @@ export class FileDataService extends EntitiesService 0; + const manual = entry.manualChanges.length > 0; if (!manual && file.excludedPages.includes(pageNumber)) { continue; } - const changeLogValues = this.#getChangeLogValues(entry, file); - if (changeLogValues.hidden) { + if (entry.state === EntryStates.REMOVED) { continue; } @@ -200,14 +199,8 @@ export class FileDataService extends EntitiesService 0; if (file.numberOfAnalyses <= 1 && !file.hasUpdates && !hasManualChanges) { - return { - changeLogType: undefined, - hidden: false, - }; + return; } const viableChanges = entityLogEntry.changes?.filter(c => c.analysisNumber > 1); const lastChange = viableChanges?.sort(chronologicallyBy(x => x.dateTime)).at(-1); - const page = entityLogEntry.positions?.[0].pageNumber; + const page = entityLogEntry.positions[0].pageNumber; const viewedPage = this.#originalViewedPages.find(p => p.page === page); if (!viewedPage) { - return { - changeLogType: undefined, - hidden: lastChange ? lastChange.type === ChangeTypes.REMOVED : false, - }; + return; } // page has been seen -> let's see if it's a change @@ -249,14 +230,10 @@ export class FileDataService extends EntitiesService visibleStatuses.includes(change.annotationStatus)); + const viableManualChanges = entityLogEntry.manualChanges.filter(change => change.processed); viableManualChanges.sort(chronologicallyBy(x => x.processedDate)); const lastManualChange = viableManualChanges.at(-1); const processedTime = lastManualChange?.processedDate; @@ -264,17 +241,8 @@ export class FileDataService extends EntitiesService = { [SuperTypes.Hint]: _('annotation-type.hint'), [SuperTypes.IgnoredHint]: _('annotation-type.ignored-hint'), [SuperTypes.ManualRedaction]: _('annotation-type.manual-redaction'), + [SuperTypes.ManualHint]: _('annotation-type.manual-hint'), [SuperTypes.Recommendation]: _('annotation-type.recommendation'), [SuperTypes.Redaction]: _('annotation-type.redaction'), [SuperTypes.Skipped]: _('annotation-type.skipped'), diff --git a/apps/red-ui/src/app/utils/sorters/super-type-sorter.ts b/apps/red-ui/src/app/utils/sorters/super-type-sorter.ts index 2305bc13c..ac55b638b 100644 --- a/apps/red-ui/src/app/utils/sorters/super-type-sorter.ts +++ b/apps/red-ui/src/app/utils/sorters/super-type-sorter.ts @@ -7,5 +7,6 @@ export const SuperTypeSorter: { [key in SuperType]: number } = { [SuperTypes.Skipped]: 50, [SuperTypes.Redaction]: 1, [SuperTypes.ManualRedaction]: 2, + [SuperTypes.ManualHint]: 3, [SuperTypes.Hint]: 19, }; diff --git a/libs/red-domain/src/lib/colors/annotation-color-config.ts b/libs/red-domain/src/lib/colors/annotation-color-config.ts index 449a09075..e14871c15 100644 --- a/libs/red-domain/src/lib/colors/annotation-color-config.ts +++ b/libs/red-domain/src/lib/colors/annotation-color-config.ts @@ -1,15 +1,14 @@ import { SuperType, SuperTypes } from '../files'; import { DefaultColorType } from './default-color-type'; -export type DefaultBasedColorType = SuperType | 'updated' | 'analysis'; +export type DefaultBasedColorType = Exclude | 'updated' | 'analysis'; export const annotationDefaultColorConfig: Record = { - [SuperTypes.TextHighlight]: 'redactionColor', // not actually used - [SuperTypes.IgnoredHint]: 'ignoredHintColor', [SuperTypes.Skipped]: 'skippedColor', [SuperTypes.Redaction]: 'redactionColor', [SuperTypes.ManualRedaction]: 'redactionColor', + [SuperTypes.ManualHint]: 'redactionColor', [SuperTypes.Recommendation]: 'recommendationColor', [SuperTypes.Hint]: 'hintColor', @@ -17,19 +16,15 @@ export const annotationDefaultColorConfig: Record = { +export const annotationEntityColorConfig: Record< + Exclude, + 'hexColor' | 'recommendationHexColor' | 'skippedHexColor' +> = { [SuperTypes.IgnoredHint]: 'skippedHexColor', [SuperTypes.Skipped]: 'skippedHexColor', [SuperTypes.Redaction]: 'hexColor', [SuperTypes.ManualRedaction]: 'hexColor', + [SuperTypes.ManualHint]: 'hexColor', [SuperTypes.Recommendation]: 'recommendationHexColor', [SuperTypes.Hint]: 'hexColor', } as const; diff --git a/libs/red-domain/src/lib/files/super-types.ts b/libs/red-domain/src/lib/files/super-types.ts index 29a38db2d..12091f4e9 100644 --- a/libs/red-domain/src/lib/files/super-types.ts +++ b/libs/red-domain/src/lib/files/super-types.ts @@ -1,4 +1,5 @@ import { ValuesOf } from '@iqser/common-ui/lib/utils'; +import { EntityType, EntityTypes, EntryState, EntryStates, IEntityLogEntry } from '../redaction-log'; export const SuperTypes = { TextHighlight: 'text-highlight', @@ -6,12 +7,72 @@ export const SuperTypes = { Skipped: 'skipped', Redaction: 'redaction', ManualRedaction: 'manual', + ManualHint: 'manual-hint', Recommendation: 'recommendation', Hint: 'hint', } as const; export type SuperType = ValuesOf; +function throwWrongSuperType(entry: IEntityLogEntry): never { + console.log('throwWrongSuperType', entry); + throw new Error(`A ${entry.state} ${entry.entryType} should never be mapped to a super type`); +} + +/** + * https://knecon.atlassian.net/wiki/spaces/RED/pages/102072322/EntityLog+-+Enum+combinations + */ +export const SuperTypeMapper: Record SuperType>> = { + [EntityTypes.ENTITY]: { + [EntryStates.APPLIED]: entry => (entry.manualChanges.length ? SuperTypes.ManualRedaction : SuperTypes.Redaction), + [EntryStates.SKIPPED]: () => SuperTypes.Skipped, + [EntryStates.IGNORED]: () => SuperTypes.Redaction, + [EntryStates.REMOVED]: throwWrongSuperType, + }, + [EntityTypes.HINT]: { + [EntryStates.APPLIED]: entry => (entry.manualChanges.length ? SuperTypes.ManualHint : SuperTypes.Hint), + [EntryStates.SKIPPED]: entry => (entry.manualChanges.length ? SuperTypes.ManualHint : SuperTypes.Hint), + [EntryStates.IGNORED]: () => SuperTypes.IgnoredHint, + [EntryStates.REMOVED]: throwWrongSuperType, + }, + [EntityTypes.FALSE_POSITIVE]: { + [EntryStates.APPLIED]: throwWrongSuperType, + [EntryStates.SKIPPED]: throwWrongSuperType, + [EntryStates.IGNORED]: throwWrongSuperType, + [EntryStates.REMOVED]: throwWrongSuperType, + }, + [EntityTypes.RECOMMENDATION]: { + [EntryStates.APPLIED]: throwWrongSuperType, + [EntryStates.SKIPPED]: () => SuperTypes.Recommendation, + [EntryStates.IGNORED]: throwWrongSuperType, + [EntryStates.REMOVED]: throwWrongSuperType, + }, + [EntityTypes.FALSE_RECOMMENDATION]: { + [EntryStates.APPLIED]: throwWrongSuperType, + [EntryStates.SKIPPED]: throwWrongSuperType, + [EntryStates.IGNORED]: throwWrongSuperType, + [EntryStates.REMOVED]: throwWrongSuperType, + }, + [EntityTypes.AREA]: { + [EntryStates.APPLIED]: () => SuperTypes.Redaction, + [EntryStates.SKIPPED]: throwWrongSuperType, + [EntryStates.IGNORED]: throwWrongSuperType, + [EntryStates.REMOVED]: throwWrongSuperType, + }, + [EntityTypes.IMAGE]: { + [EntryStates.APPLIED]: () => SuperTypes.Redaction, + [EntryStates.SKIPPED]: () => SuperTypes.Skipped, + [EntryStates.IGNORED]: throwWrongSuperType, + [EntryStates.REMOVED]: throwWrongSuperType, + }, + [EntityTypes.IMAGE_HINT]: { + [EntryStates.APPLIED]: throwWrongSuperType, + [EntryStates.SKIPPED]: () => SuperTypes.Hint, + [EntryStates.IGNORED]: throwWrongSuperType, + [EntryStates.REMOVED]: throwWrongSuperType, + }, +}; + export const LowLevelFilterTypes = { [SuperTypes.Hint]: true, [SuperTypes.Redaction]: true, 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 index 9b47d1645..9a7db5e90 100644 --- a/libs/red-domain/src/lib/redaction-log/entity-log-entry.ts +++ b/libs/red-domain/src/lib/redaction-log/entity-log-entry.ts @@ -1,7 +1,7 @@ import { ITrackable } from '@iqser/common-ui'; import { IChange } from './change'; import { EntryState } from './entity-states'; -import { EntryType } from './entry-types'; +import { EntityType } from './entity-types'; import { IManualChange } from './manual-change'; import { LogEntryEngine } from './types'; @@ -12,7 +12,7 @@ export interface IEntityLogEntryPosition { export interface IEntityLogEntry extends ITrackable { type: string; - entryType: EntryType; + entryType: EntityType; state: EntryState; value: string; reason: string; diff --git a/libs/red-domain/src/lib/redaction-log/entry-types.ts b/libs/red-domain/src/lib/redaction-log/entity-types.ts similarity index 70% rename from libs/red-domain/src/lib/redaction-log/entry-types.ts rename to libs/red-domain/src/lib/redaction-log/entity-types.ts index fdc77d152..5a5bd1ea9 100644 --- a/libs/red-domain/src/lib/redaction-log/entry-types.ts +++ b/libs/red-domain/src/lib/redaction-log/entity-types.ts @@ -1,4 +1,4 @@ -export const EntryTypes = { +export const EntityTypes = { ENTITY: 'ENTITY', HINT: 'HINT', FALSE_POSITIVE: 'FALSE_POSITIVE', @@ -9,4 +9,4 @@ export const EntryTypes = { IMAGE_HINT: 'IMAGE_HINT', } as const; -export type EntryType = (typeof EntryTypes)[keyof typeof EntryTypes]; +export type EntityType = (typeof EntityTypes)[keyof typeof EntityTypes]; diff --git a/libs/red-domain/src/lib/redaction-log/index.ts b/libs/red-domain/src/lib/redaction-log/index.ts index 5ebab18b3..4091fbe7c 100644 --- a/libs/red-domain/src/lib/redaction-log/index.ts +++ b/libs/red-domain/src/lib/redaction-log/index.ts @@ -15,4 +15,4 @@ export * from './dictionary-entry-types'; export * from './entity-log'; export * from './entity-log-entry'; export * from './entity-states'; -export * from './entry-types'; +export * from './entity-types';