This commit is contained in:
Adina Țeudan 2021-12-13 10:33:17 +02:00
parent c78fd32268
commit 396b24dbb4
14 changed files with 174 additions and 82 deletions

View File

@ -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);

View File

@ -46,4 +46,10 @@ export interface RedactionLogEntryWrapper {
recategorizationType?: string;
legalBasisChangeValue?: string;
engines?: string[];
hasBeenResized?: boolean;
hasBeenRecategorized?: boolean;
hasLegalBasisChanged?: boolean;
hasBeenForced?: boolean;
hasBeenRemovedByManualOverride?: boolean;
}

View File

@ -1,15 +1,19 @@
<div *ngIf="hasChangesToShow" [matTooltip]="changesTooltip" class="chip" matTooltipClass="multiline" matTooltipPosition="above">
<mat-icon [svgIcon]="'red:redaction-changes'"></mat-icon>
</div>
<ng-container *ngIf="hasEnginesToShow">
<div cdkOverlayOrigin #trigger="cdkOverlayOrigin" class="chip" (mouseover)="isPopoverOpen = true" (mouseout)="isPopoverOpen = false">
<div #trigger="cdkOverlayOrigin" (mouseout)="isPopoverOpen = false" (mouseover)="isPopoverOpen = true" cdkOverlayOrigin class="chip">
<ng-container *ngFor="let engine of engines">
<mat-icon *ngIf="engine.show" [svgIcon]="engine.icon"></mat-icon>
</ng-container>
</div>
<ng-template
cdkConnectedOverlay
[cdkConnectedOverlayOffsetY]="-8"
[cdkConnectedOverlayOrigin]="trigger"
[cdkConnectedOverlayOpen]="isPopoverOpen"
[cdkConnectedOverlayOrigin]="trigger"
cdkConnectedOverlay
>
<div class="popover">
<ng-container *ngFor="let engine of engines">

View File

@ -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 {

View File

@ -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);
}
}

View File

@ -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<AnnotationWrapper, AnnotationSourceComponent>('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);
}
}

View File

@ -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"
>
<div class="active-bar-marker"></div>
@ -59,5 +59,5 @@
<redaction-comments #comments [annotation]="annotation"></redaction-comments>
</div>
<redaction-annotation-source [annotation]="annotation"></redaction-annotation-source>
<redaction-annotation-details [annotation]="annotation"></redaction-annotation-details>
</div>

View File

@ -90,9 +90,3 @@
}
}
}
redaction-annotation-source {
position: absolute;
top: 6px;
right: 8px;
}

View File

@ -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,

View File

@ -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',

View File

@ -50,6 +50,7 @@ export class IconsModule {
'ready-for-approval',
'reanalyse',
'reason',
'redaction-changes',
'remove-from-dict',
'report',
'resize',

View File

@ -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<AnnotationWrapper>]?: 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;

View File

@ -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",

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="100px" version="1.1" viewBox="0 0 100 100" width="100px" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd" id="Icons" stroke="none" stroke-width="1">
<g fill="currentColor" fill-rule="nonzero" id="Artboard" transform="translate(-6380.000000, -1180.000000)">
<path
d="M6414.42833,1180 C6421.86698,1180 6427.92216,1185.94892 6428.09365,1193.34652 L6428.09739,1193.66905 L6428.09692,1204.73467 L6428.39731,1204.65313 C6432.38041,1203.61868 6436.64509,1204.46415 6439.93905,1206.96769 L6440.24497,1207.20725 L6440.38329,1207.32149 L6440.66953,1207.09245 C6442.84231,1205.40126 6445.48514,1204.40388 6448.25226,1204.24615 L6448.64837,1204.22935 L6449.02864,1204.22405 C6451.94377,1204.22405 6454.7601,1205.15732 6457.07869,1206.85626 L6457.39174,1207.09266 L6457.68137,1207.32461 L6457.97347,1207.09245 C6460.14238,1205.40606 6462.77812,1204.40855 6465.53638,1204.24694 L6465.951,1204.22899 L6466.33095,1204.22364 C6469.95696,1204.22364 6473.43422,1205.66203 6475.99687,1208.22468 C6478.46861,1210.70084 6479.89572,1214.01929 6479.9945,1217.50113 L6480,1217.88864 L6480,1274.98143 C6480,1276.31414 6479.4715,1277.59035 6478.53022,1278.53162 C6477.6517,1279.41015 6476.48143,1279.9291 6475.24574,1279.99438 L6474.98003,1280.0014 L6402.31648,1280.0014 C6400.98704,1280.0014 6399.71106,1279.47235 6398.77034,1278.53162 C6397.89181,1277.65309 6397.37286,1276.48282 6397.30757,1275.24713 L6397.30056,1274.98143 L6397.30004,1273.59895 L6384.33924,1260.63765 C6379.09823,1255.40109 6378.55938,1247.13261 6382.97046,1241.26818 L6383.19515,1240.97699 L6383.42426,1240.69455 C6387.63316,1235.64107 6394.55368,1234.05714 6400.41661,1236.46331 L6400.75882,1236.60905 L6400.75928,1193.66905 C6400.75928,1186.33821 6406.53702,1180.35103 6413.78509,1180.01488 L6414.1058,1180.00373 L6414.42833,1180 Z M6414.42848,1190.03614 C6412.48854,1190.03614 6410.90415,1191.55587 6410.80068,1193.46995 L6410.7953,1193.66932 L6410.7953,1247.30332 C6410.7953,1249.33232 6409.57215,1251.16122 6407.69666,1251.9373 C6405.8965,1252.68221 6403.83604,1252.31645 6402.40481,1251.01672 L6402.22925,1250.84941 L6398.15459,1246.77422 C6397.26689,1245.84672 6396.04433,1245.31641 6394.76009,1245.30417 C6393.47774,1245.28893 6392.24283,1245.79262 6391.33595,1246.6995 C6390.42851,1247.61 6389.92466,1248.84355 6389.93641,1250.12304 C6389.9511,1251.32381 6390.41345,1252.46902 6391.24707,1253.3557 L6405.86649,1267.9768 C6406.36822,1268.47853 6406.75284,1269.07561 6407.00255,1269.7253 L6407.08678,1269.96577 L6469.96398,1269.96577 L6469.96398,1217.88912 C6469.96398,1215.94918 6468.44425,1214.36479 6466.53017,1214.26132 L6466.3308,1214.25594 C6464.39086,1214.25594 6462.80647,1215.77567 6462.703,1217.68975 L6462.69763,1217.88912 L6462.69763,1233.45988 C6462.69763,1236.23277 6460.45243,1238.47979 6457.68177,1238.47979 C6454.9829,1238.47979 6452.78365,1236.35352 6452.66675,1233.6836 L6452.66186,1233.45988 L6452.66186,1217.88912 C6452.66186,1215.88228 6451.03551,1214.25594 6449.02868,1214.25594 C6447.08874,1214.25594 6445.50435,1215.77567 6445.40088,1217.68975 L6445.3955,1217.88912 L6445.3955,1233.45988 C6445.3955,1236.23277 6443.1503,1238.47979 6440.37964,1238.47979 C6437.68383,1238.47979 6435.48553,1236.35266 6435.36867,1233.68353 L6435.36378,1233.45988 L6435.36378,1217.88912 C6435.36378,1215.88228 6433.73744,1214.25594 6431.7306,1214.25594 C6429.79066,1214.25594 6428.20627,1215.77567 6428.1028,1217.68975 L6428.09743,1217.88912 L6428.09743,1233.45988 C6428.09743,1236.23371 6425.8514,1238.47979 6423.07752,1238.47979 C6420.38171,1238.47979 6418.1834,1236.35266 6418.06654,1233.68353 L6418.06166,1233.45988 L6418.06166,1193.66932 C6418.06166,1191.66249 6416.43532,1190.03614 6414.42848,1190.03614 Z"
id="Fill-1"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB