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 f6ebdd5f3..a576bfbfe 100644 --- a/apps/red-ui/src/app/models/file/annotation.wrapper.ts +++ b/apps/red-ui/src/app/models/file/annotation.wrapper.ts @@ -9,8 +9,10 @@ import { Dictionary, Earmark, EntityTypes, + EntryState, EntryStates, FalsePositiveSuperTypes, + IEntityLog, IEntityLogEntry, ILegalBasis, IPoint, @@ -209,6 +211,7 @@ export class AnnotationWrapper implements IListable { static fromData( logEntry: IEntityLogEntry, + allLogEntries: IEntityLogEntry[], dictionary: Dictionary, changeLogType: ChangeType, legalBasisList: ILegalBasis[], @@ -268,7 +271,13 @@ export class AnnotationWrapper implements IListable { const lastRelevantManualChange = logEntry.manualChanges?.at(-1); annotationWrapper.lastManualChange = lastRelevantManualChange?.manualRedactionType; - annotationWrapper.pending = lastRelevantManualChange && !lastRelevantManualChange.processed; + annotationWrapper.pending = logEntry.state === EntryStates.PENDING; + if (annotationWrapper.pending) { + const removedEntry = allLogEntries.find( + (e: IEntityLogEntry) => e.id === annotationWrapper.id && e.state === EntryStates.REMOVED, + ); + logEntry.oldState = removedEntry?.state; + } annotationWrapper.superType = SuperTypeMapper[logEntry.entryType][logEntry.state](logEntry); annotationWrapper.superTypeLabel = annotationTypesTranslations[annotationWrapper.superType]; @@ -277,9 +286,13 @@ export class AnnotationWrapper implements IListable { annotationWrapper.typeLabel = dictionary?.virtual ? undefined : dictionary?.label; - const colorKey = annotationEntityColorConfig[annotationWrapper.superType]; - const defaultColor = annotationDefaultColorConfig[annotationWrapper.superType]; - annotationWrapper.color = dictionary ? (dictionary[colorKey] as string) : (defaultColors[defaultColor] as string); + if (annotationWrapper.pending) { + annotationWrapper.color = defaultColors[annotationDefaultColorConfig.analysis] as string; + } else { + const colorKey = annotationEntityColorConfig[annotationWrapper.superType]; + const defaultColor = annotationDefaultColorConfig[annotationWrapper.superType]; + annotationWrapper.color = dictionary ? (dictionary[colorKey] as string) : (defaultColors[defaultColor] as string); + } annotationWrapper['entry'] = logEntry; return annotationWrapper; 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 99c2ed520..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 @@ -10,7 +10,7 @@
{{ annotation.superTypeLabel | translate }}   - + {{ 'annotation.pending' | translate }}
diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.ts b/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.ts index f62a1a538..322593075 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.ts @@ -18,17 +18,4 @@ export class AnnotationCardComponent { @Input() isSelected = false; constructor(readonly multiSelectService: MultiSelectService) {} - - get pending() { - return ( - this.annotation.pending && - ((this.annotation.isModifyDictionary && - !this.annotation.isRemovedLocally && - !this.annotation.hasBeenForcedHint && - this.annotation.lastManualChange !== ManualRedactionTypes.LEGAL_BASIS_CHANGE && - this.annotation.lastManualChange !== ManualRedactionTypes.RESIZE_LOCALLY) || - this.annotation.type === ImageCategory.SIGNATURE || - this.annotation.IMAGE_HINT) - ); - } } diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-details/annotation-details.component.scss b/apps/red-ui/src/app/modules/file-preview/components/annotation-details/annotation-details.component.scss index 1110e38ca..8a2928722 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-details/annotation-details.component.scss +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-details/annotation-details.component.scss @@ -6,7 +6,6 @@ } .popover { - width: 260px; padding: 10px; border-radius: 3px; background-color: var(--iqser-grey-1); 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 40599598d..2f51ba0c8 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 @@ -229,6 +229,7 @@ export class FileDataService extends EntitiesService= 0; i--) { + points.push(this.#bottomLeft(positions[i], pageHeight)); + points.push(this.#topLeft(positions[i], pageHeight)); + } + + points.push(this.#topRight(positions[0], pageHeight)); + return points; + } + + #topLeft(rectangle: IRectangle, pageHeight: number): IPoint { + const x = rectangle.topLeft.x; + const y = pageHeight - (rectangle.topLeft.y + rectangle.height); + return { x, y }; + } + + #topRight(rectangle: IRectangle, pageHeight: number): IPoint { + const x = rectangle.topLeft.x + rectangle.width; + const y = pageHeight - (rectangle.topLeft.y + rectangle.height); + return { x, y }; + } + + #bottomRight(rectangle: IRectangle, pageHeight: number): IPoint { + const x = rectangle.topLeft.x + rectangle.width; + const y = pageHeight - rectangle.topLeft.y; + return { x, y }; + } + + #bottomLeft(rectangle: IRectangle, pageHeight: number): IPoint { + const x = rectangle.topLeft.x; + const y = pageHeight - rectangle.topLeft.y; + return { x, y }; + } } diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts index 90da413ac..09fc4f9a7 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts @@ -243,6 +243,10 @@ export class PdfViewer { return new this.#instance.Core.Annotations.TextHighlightAnnotation(); } + polyline() { + return new this.#instance.Core.Annotations.PolylineAnnotation(); + } + isTextHighlight(annotation: Annotation): annotation is TextHighlightAnnotation { return annotation instanceof this.#instance.Core.Annotations.TextHighlightAnnotation; } diff --git a/libs/common-ui b/libs/common-ui index 3ea4e45b8..ecf9c8912 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit 3ea4e45b87b94868370492c475864390d984f65d +Subproject commit ecf9c8912e366fdcc0a454d112c0f3252245666a diff --git a/libs/red-domain/src/lib/files/super-types.ts b/libs/red-domain/src/lib/files/super-types.ts index 27412a27e..02f2c80db 100644 --- a/libs/red-domain/src/lib/files/super-types.ts +++ b/libs/red-domain/src/lib/files/super-types.ts @@ -19,18 +19,15 @@ function wrongSuperTypeHandler(): never | undefined { } function resolveRedactionType(entry: IEntityLogEntry, hint = false) { + if (entry.state === EntryStates.PENDING && entry.oldState) { + return SuperTypeMapper[entry.entryType][entry.oldState](entry); + } + const redaction = hint ? SuperTypes.Hint : SuperTypes.Redaction; const manualRedaction = hint ? SuperTypes.ManualHint : SuperTypes.ManualRedaction; - const manualChanges = entry.manualChanges; - const hasEngines = entry.engines.length; - const lastRelevantManualChange = manualChanges?.at(-1); - if (!!lastRelevantManualChange && !hasEngines) { - const pending = lastRelevantManualChange && !lastRelevantManualChange.processed; - if (pending && entry.dictionaryEntry) { - return redaction; - } - return manualRedaction; + if (!entry.engines.length) { + return entry.state === EntryStates.PENDING && entry.dictionaryEntry ? redaction : manualRedaction; } return redaction; } @@ -44,48 +41,56 @@ export const SuperTypeMapper: Record SuperTypes.Skipped, [EntryStates.IGNORED]: () => SuperTypes.Skipped, [EntryStates.REMOVED]: wrongSuperTypeHandler, + [EntryStates.PENDING]: entry => resolveRedactionType(entry), }, [EntityTypes.HINT]: { [EntryStates.APPLIED]: wrongSuperTypeHandler, [EntryStates.SKIPPED]: entry => resolveRedactionType(entry, true), [EntryStates.IGNORED]: () => SuperTypes.IgnoredHint, [EntryStates.REMOVED]: wrongSuperTypeHandler, + [EntryStates.PENDING]: entry => resolveRedactionType(entry), }, [EntityTypes.FALSE_POSITIVE]: { [EntryStates.APPLIED]: wrongSuperTypeHandler, [EntryStates.SKIPPED]: wrongSuperTypeHandler, [EntryStates.IGNORED]: wrongSuperTypeHandler, [EntryStates.REMOVED]: wrongSuperTypeHandler, + [EntryStates.PENDING]: entry => resolveRedactionType(entry), }, [EntityTypes.RECOMMENDATION]: { [EntryStates.APPLIED]: wrongSuperTypeHandler, [EntryStates.SKIPPED]: () => SuperTypes.Recommendation, [EntryStates.IGNORED]: wrongSuperTypeHandler, [EntryStates.REMOVED]: wrongSuperTypeHandler, + [EntryStates.PENDING]: entry => resolveRedactionType(entry), }, [EntityTypes.FALSE_RECOMMENDATION]: { [EntryStates.APPLIED]: wrongSuperTypeHandler, [EntryStates.SKIPPED]: wrongSuperTypeHandler, [EntryStates.IGNORED]: wrongSuperTypeHandler, [EntryStates.REMOVED]: wrongSuperTypeHandler, + [EntryStates.PENDING]: entry => resolveRedactionType(entry), }, [EntityTypes.AREA]: { [EntryStates.APPLIED]: () => SuperTypes.Redaction, [EntryStates.SKIPPED]: wrongSuperTypeHandler, [EntryStates.IGNORED]: wrongSuperTypeHandler, [EntryStates.REMOVED]: wrongSuperTypeHandler, + [EntryStates.PENDING]: entry => resolveRedactionType(entry), }, [EntityTypes.IMAGE]: { [EntryStates.APPLIED]: () => SuperTypes.Redaction, [EntryStates.SKIPPED]: () => SuperTypes.Skipped, [EntryStates.IGNORED]: () => SuperTypes.Skipped, [EntryStates.REMOVED]: wrongSuperTypeHandler, + [EntryStates.PENDING]: entry => resolveRedactionType(entry), }, [EntityTypes.IMAGE_HINT]: { [EntryStates.APPLIED]: wrongSuperTypeHandler, [EntryStates.SKIPPED]: () => SuperTypes.Hint, [EntryStates.IGNORED]: () => SuperTypes.IgnoredHint, [EntryStates.REMOVED]: wrongSuperTypeHandler, + [EntryStates.PENDING]: entry => resolveRedactionType(entry), }, }; 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 21d94933f..2efa68491 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 @@ -14,6 +14,7 @@ export interface IEntityLogEntry extends ITrackable { type: string; entryType: EntityType; state: EntryState; + oldState?: EntryState; value: string; reason: string; matchedRule: string; diff --git a/libs/red-domain/src/lib/redaction-log/entity-states.ts b/libs/red-domain/src/lib/redaction-log/entity-states.ts index 2507f1bdb..60725eef0 100644 --- a/libs/red-domain/src/lib/redaction-log/entity-states.ts +++ b/libs/red-domain/src/lib/redaction-log/entity-states.ts @@ -3,6 +3,7 @@ export const EntryStates = { SKIPPED: 'SKIPPED', IGNORED: 'IGNORED', REMOVED: 'REMOVED', + PENDING: 'PENDING', } as const; export type EntryState = (typeof EntryStates)[keyof typeof EntryStates];