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 7c2876e8f..51a75e509 100644 --- a/apps/red-ui/src/app/models/file/annotation.wrapper.ts +++ b/apps/red-ui/src/app/models/file/annotation.wrapper.ts @@ -58,6 +58,12 @@ export class AnnotationWrapper { changeLogType?: 'ADDED' | 'REMOVED' | 'CHANGED'; engines?: string[]; + hasBeenResized: boolean; + hasBeenRecategorized: boolean; + hasLegalBasisChanged: boolean; + hasBeenForced: boolean; + hasBeenRemovedByManualOverride: boolean; + private _origin: RedactionLogEntryWrapper; get isChangeLogRemoved() { @@ -169,6 +175,16 @@ export class AnnotationWrapper { return this.dictionaryOperation; } + get hasRedactionChanges(): boolean { + return ( + this.hasBeenResized || + this.hasBeenRecategorized || + this.hasLegalBasisChanged || + this.hasBeenForced || + this.hasBeenRemovedByManualOverride + ); + } + get isConvertedRecommendation() { return this.isRecommendation && this.superType === 'suggestion-add-dictionary'; } @@ -221,6 +237,11 @@ export class AnnotationWrapper { annotationWrapper.engines = redactionLogEntry.engines; annotationWrapper.section = redactionLogEntry.section; annotationWrapper.rectangle = redactionLogEntry.rectangle; + annotationWrapper.hasBeenResized = redactionLogEntry.hasBeenResized; + annotationWrapper.hasBeenRecategorized = redactionLogEntry.hasBeenRecategorized; + annotationWrapper.hasLegalBasisChanged = redactionLogEntry.hasLegalBasisChanged; + annotationWrapper.hasBeenForced = redactionLogEntry.hasBeenForced; + annotationWrapper.hasBeenRemovedByManualOverride = redactionLogEntry.hasBeenRemovedByManualOverride; this._createContent(annotationWrapper, redactionLogEntry); this._setSuperType(annotationWrapper, redactionLogEntry); diff --git a/apps/red-ui/src/app/models/file/redaction-log-entry.wrapper.ts b/apps/red-ui/src/app/models/file/redaction-log-entry.wrapper.ts index 9dc800a87..f3bcacbd8 100644 --- a/apps/red-ui/src/app/models/file/redaction-log-entry.wrapper.ts +++ b/apps/red-ui/src/app/models/file/redaction-log-entry.wrapper.ts @@ -46,4 +46,10 @@ export interface RedactionLogEntryWrapper { recategorizationType?: string; legalBasisChangeValue?: string; engines?: string[]; + + hasBeenResized?: boolean; + hasBeenRecategorized?: boolean; + hasLegalBasisChanged?: boolean; + hasBeenForced?: boolean; + hasBeenRemovedByManualOverride?: boolean; } diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-source/annotation-source.component.html b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-details/annotation-details.component.html similarity index 69% rename from apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-source/annotation-source.component.html rename to apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-details/annotation-details.component.html index 766e23aa6..01bdc134e 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-source/annotation-source.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-details/annotation-details.component.html @@ -1,15 +1,19 @@ +
+ +
+ -
+
diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-source/annotation-source.component.scss b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-details/annotation-details.component.scss similarity index 85% rename from apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-source/annotation-source.component.scss rename to apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-details/annotation-details.component.scss index c731a1878..d8356a43f 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-source/annotation-source.component.scss +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-details/annotation-details.component.scss @@ -1,5 +1,12 @@ @use '../../../../../../../assets/styles/variables'; +:host { + display: flex; + position: absolute; + top: 6px; + right: 8px; +} + .popover { width: 260px; padding: 10px; @@ -44,6 +51,10 @@ margin-right: 8px; } } + + &:not(:last-child) { + margin-right: 2px; + } } mat-icon { diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-details/annotation-details.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-details/annotation-details.component.ts new file mode 100644 index 000000000..745b6212a --- /dev/null +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-details/annotation-details.component.ts @@ -0,0 +1,89 @@ +import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { AnnotationWrapper } from '@models/file/annotation.wrapper'; +import { TranslateService } from '@ngx-translate/core'; +import { annotationChangesTranslations } from '../../../../../../translations/annotation-changes-translations'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; + +interface Engine { + readonly icon: string; + readonly description: string; + readonly show: boolean; +} + +const Engines = { + DICTIONARY: 'DICTIONARY', + NER: 'NER', + RULE: 'RULE', +} as const; + +type EngineName = keyof typeof Engines; + +@Component({ + selector: 'redaction-annotation-details', + templateUrl: './annotation-details.component.html', + styleUrls: ['./annotation-details.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AnnotationDetailsComponent implements OnChanges { + @Input() annotation: AnnotationWrapper; + + isPopoverOpen = false; + hasEnginesToShow: boolean; + engines: readonly Engine[]; + + hasChangesToShow: boolean; + changesTooltip: string; + + constructor(private readonly _translateService: TranslateService) {} + + ngOnChanges(changes: SimpleChanges) { + if (changes.annotation) { + this._updateChanges(); + this._updateEngines(); + } + } + + private _updateChanges(): void { + const changesProperties = [ + 'hasBeenResized', + 'hasBeenRecategorized', + 'hasLegalBasisChanged', + 'hasBeenForced', + 'hasBeenRemovedByManualOverride', + ]; + const changes = changesProperties.filter(key => this.annotation[key]); + const header = this._translateService.instant(_('annotation-changes.header')); + const details = changes + .map(change => this._translateService.instant(annotationChangesTranslations[change])) + .map(change => `• ${change}`); + this.changesTooltip = [header, ...details].join('\n'); + + this.hasChangesToShow = changes.length > 0; + } + + private _updateEngines(): void { + this.engines = [ + { + icon: 'red:dictionary', + description: this._translateService.instant('annotation-engines.dictionary', { isHint: this.annotation.hint }), + show: this._isBasedOn(Engines.DICTIONARY), + }, + { + icon: 'red:ai', + description: this._translateService.instant('annotation-engines.ner'), + show: this._isBasedOn(Engines.NER), + }, + { + icon: 'red:rule', + description: this._translateService.instant('annotation-engines.rule', { rule: this.annotation.legalBasisValue }), + show: this._isBasedOn(Engines.RULE), + }, + ]; + + this.hasEnginesToShow = this.engines.length && this.engines.some(source => source.show); + } + + private _isBasedOn(engineName: EngineName) { + return !!this.annotation.engines?.includes(engineName); + } +} diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-source/annotation-source.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-source/annotation-source.component.ts deleted file mode 100644 index 434b1dd03..000000000 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-source/annotation-source.component.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; -import { AnnotationWrapper } from '@models/file/annotation.wrapper'; -import { OnChange } from '@iqser/common-ui'; -import { TranslateService } from '@ngx-translate/core'; - -interface Engine { - readonly icon: string; - readonly description: string; - readonly show: boolean; -} - -const Engines = { - DICTIONARY: 'DICTIONARY', - NER: 'NER', - RULE: 'RULE', -} as const; - -type EngineName = keyof typeof Engines; - -@Component({ - selector: 'redaction-annotation-source', - templateUrl: './annotation-source.component.html', - styleUrls: ['./annotation-source.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class AnnotationSourceComponent { - @Input() - @OnChange('updateEngines') - annotation: AnnotationWrapper; - - isPopoverOpen = false; - engines: readonly Engine[]; - - constructor(private readonly _translateService: TranslateService) {} - - get hasEnginesToShow(): boolean { - return this.engines.length && this.engines.some(source => source.show); - } - - updateEngines(): void { - this.engines = [ - { - icon: 'red:dictionary', - description: this._translateService.instant('annotation-engines.dictionary', { isHint: this.annotation.hint }), - show: this._isBasedOn(Engines.DICTIONARY), - }, - { - icon: 'red:ai', - description: this._translateService.instant('annotation-engines.ner'), - show: this._isBasedOn(Engines.NER), - }, - { - icon: 'red:rule', - description: this._translateService.instant('annotation-engines.rule', { rule: this.annotation.legalBasisValue }), - show: this._isBasedOn(Engines.RULE), - }, - ]; - } - - private _isBasedOn(engineName: EngineName) { - return !!this.annotation.engines?.includes(engineName); - } -} diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotations-list/annotations-list.component.html b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotations-list/annotations-list.component.html index b4a0acb70..368df6874 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotations-list/annotations-list.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotations-list/annotations-list.component.html @@ -4,8 +4,8 @@ [attr.annotation-id]="annotation.id" [attr.annotation-page]="activeViewerPage" [class.active]="isSelected(annotation.annotationId)" - [class.multi-select-active]="multiSelectService.active$ | async" [class.help-mode]="helpModeService.isHelpModeActive$ | async" + [class.multi-select-active]="multiSelectService.active$ | async" class="annotation-wrapper" >
@@ -59,5 +59,5 @@
- +
diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotations-list/annotations-list.component.scss b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotations-list/annotations-list.component.scss index c9df84618..e159e24af 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotations-list/annotations-list.component.scss +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotations-list/annotations-list.component.scss @@ -90,9 +90,3 @@ } } } - -redaction-annotation-source { - position: absolute; - top: 6px; - right: 8px; -} diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview.module.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview.module.ts index 1943e4aae..6e9c902ae 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview.module.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview.module.ts @@ -7,7 +7,7 @@ import { SharedModule } from '@shared/shared.module'; import { SharedDossiersModule } from '../../shared/shared-dossiers.module'; import { FilePreviewScreenComponent } from './file-preview-screen.component'; import { FileWorkloadComponent } from './components/file-workload/file-workload.component'; -import { AnnotationSourceComponent } from './components/annotation-source/annotation-source.component'; +import { AnnotationDetailsComponent } from './components/annotation-details/annotation-details.component'; import { AnnotationsListComponent } from './components/annotations-list/annotations-list.component'; import { PageIndicatorComponent } from './components/page-indicator/page-indicator.component'; import { PageExclusionComponent } from './components/page-exclusion/page-exclusion.component'; @@ -33,7 +33,7 @@ const routes: Routes = [ declarations: [ FilePreviewScreenComponent, FileWorkloadComponent, - AnnotationSourceComponent, + AnnotationDetailsComponent, AnnotationsListComponent, PageIndicatorComponent, PageExclusionComponent, diff --git a/apps/red-ui/src/app/modules/dossier/services/annotation-processing.service.ts b/apps/red-ui/src/app/modules/dossier/services/annotation-processing.service.ts index 4c4ac1f28..a8c467bd8 100644 --- a/apps/red-ui/src/app/modules/dossier/services/annotation-processing.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/annotation-processing.service.ts @@ -19,12 +19,12 @@ export class AnnotationProcessingService { checker: (annotation: AnnotationWrapper) => annotation?.comments?.length > 0, }, { - id: 'with-reason-changes', - icon: 'red:reason', - label: _('filter-menu.with-reason-changes'), + id: 'redaction-changes', + icon: 'red:redaction-changes', + label: _('filter-menu.redaction-changes'), checked: false, topLevelFilter: true, - checker: (annotation: AnnotationWrapper) => annotation?.legalBasisChangeValue?.length > 0, + checker: (annotation: AnnotationWrapper) => annotation?.hasRedactionChanges, }, { id: 'unseen-pages', diff --git a/apps/red-ui/src/app/modules/icons/icons.module.ts b/apps/red-ui/src/app/modules/icons/icons.module.ts index 2448bfd6a..0945fd73e 100644 --- a/apps/red-ui/src/app/modules/icons/icons.module.ts +++ b/apps/red-ui/src/app/modules/icons/icons.module.ts @@ -50,6 +50,7 @@ export class IconsModule { 'ready-for-approval', 'reanalyse', 'reason', + 'redaction-changes', 'remove-from-dict', 'report', 'resize', diff --git a/apps/red-ui/src/app/translations/annotation-changes-translations.ts b/apps/red-ui/src/app/translations/annotation-changes-translations.ts new file mode 100644 index 000000000..7bd481fa1 --- /dev/null +++ b/apps/red-ui/src/app/translations/annotation-changes-translations.ts @@ -0,0 +1,11 @@ +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { AnnotationWrapper } from '../models/file/annotation.wrapper'; +import { KeysOf } from '@iqser/common-ui'; + +export const annotationChangesTranslations: { [key in KeysOf]?: string } = { + hasBeenResized: _('annotation-changes.resized'), + hasBeenRecategorized: _('annotation-changes.recategorized'), + hasLegalBasisChanged: _('annotation-changes.legal-basis'), + hasBeenForced: _('annotation-changes.forced'), + hasBeenRemovedByManualOverride: _('annotation-changes.removed-manual'), +} as const; diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index aeec13bf8..ad7d27030 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -261,6 +261,14 @@ "show": "Show", "undo": "Undo" }, + "annotation-changes": { + "forced": "Redaction forced", + "header": "Manual changes:", + "legal-basis": "Reason changed", + "recategorized": "Image category changed", + "removed-manual": "Redaction/Hint removed", + "resized": "Redaction area has been modified" + }, "annotation-engines": { "dictionary": "{isHint, select, true{Hint} other{Redaction}} based on dictionary", "ner": "Redaction based on AI", @@ -1111,9 +1119,9 @@ "filter-options": "Filter options", "filter-types": "Filter", "label": "Filter", + "redaction-changes": "Only annotations with redaction changes", "unseen-pages": "Only annotations on unseen pages", - "with-comments": "Only annotations with comments", - "with-reason-changes": "Only redactions with reason changes" + "with-comments": "Only annotations with comments" }, "filter": { "analysis": "Analysis pending", diff --git a/apps/red-ui/src/assets/icons/general/redaction-changes.svg b/apps/red-ui/src/assets/icons/general/redaction-changes.svg new file mode 100644 index 000000000..4e00eeffe --- /dev/null +++ b/apps/red-ui/src/assets/icons/general/redaction-changes.svg @@ -0,0 +1,10 @@ + + + + + + + +