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/components/file-workload/file-workload.component.html b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html
index 8a063381a..7111f4d66 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html
+++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html
@@ -19,6 +19,7 @@
iqserHelpMode="bulk-select-annotations"
translate="file-preview.tabs.annotations.select"
>
+
@@ -118,99 +119,103 @@
-
-
-
-
+
+
+
-
- {{ activeViewerPage }} -
- {{ activeAnnotations?.length || 0 }}
-
-
+
+ {{ activeViewerPage }} -
+ {{ activeAnnotations?.length || 0 }}
+
+
-
+
+
+
+
+
+ {{ 'file-preview.tabs.annotations.page-is' | translate }}
+ .
+
+
+
+
+
+
+ = displayedPages[displayedPages.length - 1]"
+ [label]="'file-preview.tabs.annotations.jump-to-next' | translate"
+ [type]="iconButtonTypes.dark"
+ class="mt-8"
+ icon="red:nav-next"
+ >
-
+
-
-
-
-
- {{ 'file-preview.tabs.annotations.page-is' | translate }}
- .
-
-
-
-
-
-
- = displayedPages[displayedPages.length - 1]"
- [label]="'file-preview.tabs.annotations.jump-to-next' | translate"
- [type]="iconButtonTypes.dark"
- class="mt-8"
- icon="red:nav-next"
- >
-
-
-
-
-
-
+
+
diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.scss b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.scss
index 64f58538a..78609b428 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.scss
+++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.scss
@@ -151,3 +151,7 @@
::ng-deep .page-separator iqser-circle-button mat-icon {
color: var(--iqser-primary);
}
+
+[hidden] {
+ display: none !important;
+}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.ts
index 999da819d..0607b4055 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.ts
@@ -21,7 +21,6 @@ import {
IconButtonTypes,
INestedFilter,
IqserEventTarget,
- Required,
shareDistinctLast,
shareLast,
} from '@iqser/common-ui';
@@ -38,7 +37,7 @@ const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'E
const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
@Component({
- selector: 'redaction-file-workload',
+ selector: 'redaction-file-workload [file]',
templateUrl: './file-workload.component.html',
styleUrls: ['./file-workload.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -53,7 +52,7 @@ export class FileWorkloadComponent {
@Input() shouldDeselectAnnotationsOnPageChange: boolean;
@Input() dialogRef: MatDialogRef;
@Input() viewedPages: IViewedPage[];
- @Input() @Required() file!: File;
+ @Input() file!: File;
@Input() hideSkipped: boolean;
@Input() annotationActionsTemplate: TemplateRef;
@Input() viewer: WebViewerInstance;
@@ -161,7 +160,7 @@ export class FileWorkloadComponent {
}
}
- hasOnlyManualRedactionsAndNotExcluded(pageNumber: number): boolean {
+ hasOnlyManualRedactionsAndIsExcluded(pageNumber: number): boolean {
const hasOnlyManualRedactions = this.displayedAnnotations.get(pageNumber).every(annotation => annotation.manual);
return hasOnlyManualRedactions && this.file.excludedPages.includes(pageNumber);
}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/page-exclusion/page-exclusion.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/page-exclusion/page-exclusion.component.ts
index 58dc2bc0c..ba2eb3b72 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/page-exclusion/page-exclusion.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/page-exclusion/page-exclusion.component.ts
@@ -67,7 +67,6 @@ export class PageExclusionComponent implements OnChanges {
)
.toPromise();
this._inputComponent.reset();
- this.excludedPagesService.toggle();
} catch (e) {
this._toaster.error(_('file-preview.tabs.exclude-pages.error'));
}
@@ -86,7 +85,6 @@ export class PageExclusionComponent implements OnChanges {
)
.toPromise();
this._inputComponent.reset();
- this.excludedPagesService.toggle();
this._loadingService.stop();
}
}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/page-indicator/page-indicator.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/page-indicator/page-indicator.component.ts
index 2ae2b8f06..dc417f73d 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/page-indicator/page-indicator.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/page-indicator/page-indicator.component.ts
@@ -14,12 +14,8 @@ import { FilesMapService } from '@services/entity-services/files-map.service';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PageIndicatorComponent extends AutoUnsubscribe implements OnDestroy, OnChanges {
- @Input()
- file: File;
-
- @Input()
- active = false;
-
+ @Input() file: File;
+ @Input() active = false;
@Input() showDottedIcon = false;
@Input() number: number;
@Input() viewedPages: IViewedPage[];
@@ -84,23 +80,6 @@ export class PageIndicatorComponent extends AutoUnsubscribe implements OnDestroy
}
}
- // @HostListener('window:keydown', ['$event'])
- // handleKeyDown(event: KeyboardEvent) {
- // if (this.canMarkPagesAsViewed) {
- // if (this.active && event.key === ' ') {
- // if (
- // document.activeElement &&
- // document.activeElement.className.indexOf('activePanel') >= 0
- // ) {
- // this.toggleReadState();
- // event.stopPropagation();
- // event.preventDefault();
- // return false;
- // }
- // }
- // }
- // }
-
private async _markPageRead() {
await this._viewedPagesService.addPage({ page: this.number }, this.file.dossierId, this.file.fileId).toPromise();
if (this.activePage) {
diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/pdf-viewer/pdf-viewer.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/pdf-viewer/pdf-viewer.component.ts
index daa248d77..059d44dc7 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/pdf-viewer/pdf-viewer.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/pdf-viewer/pdf-viewer.component.ts
@@ -284,7 +284,7 @@ export class PdfViewerComponent implements OnInit, OnChanges {
this._selectedText = selectedText;
const textActions = [dataElements.ADD_DICTIONARY, dataElements.ADD_FALSE_POSITIVE];
- if (selectedText.length > 2 && this.canPerformActions && !this.utils.isCurrentPageExcluded) {
+ if (selectedText.length > 2 && this.canPerformActions && !this.utils.isCurrentPageExcluded(this.file)) {
this.instance.UI.enableElements(textActions);
} else {
this.instance.UI.disableElements(textActions);
@@ -588,7 +588,7 @@ export class PdfViewerComponent implements OnInit, OnChanges {
ANNOTATION_POPUP,
];
- if (this.canPerformActions && !this.utils.isCurrentPageExcluded) {
+ if (this.canPerformActions && !this.utils.isCurrentPageExcluded(this.file)) {
try {
this.instance.UI.enableTools(['AnnotationCreateRectangle']);
} catch (e) {
@@ -605,7 +605,7 @@ export class PdfViewerComponent implements OnInit, OnChanges {
let elementsToDisable = [...elements, ADD_RECTANGLE];
- if (this.utils.isCurrentPageExcluded) {
+ if (this.utils.isCurrentPageExcluded(this.file)) {
const allowedActionsWhenPageExcluded: string[] = [ANNOTATION_POPUP, ADD_RECTANGLE, ADD_REDACTION, SHAPE_TOOL_GROUP_BUTTON];
elementsToDisable = elementsToDisable.filter(element => !allowedActionsWhenPageExcluded.includes(element));
} else {
diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts
index ec3849327..16976197e 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts
@@ -330,7 +330,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
.map(p => p.page)
.filter((item, pos, self) => self.indexOf(item) === pos);
for (const page of distinctPages) {
- await this._cleanupAndRedrawManualAnnotationsForEntirePage(page);
+ await this._reloadAnnotationsForPage(page);
}
}
},
@@ -398,7 +398,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
this._instance = $event;
this.ready = true;
await this._stampPDF();
- await this._cleanupAndRedrawManualAnnotations();
+ await this._reloadAnnotations();
this._setExcludedPageStyles();
this._instance.Core.documentViewer.addEventListener('pageComplete', () => {
@@ -419,7 +419,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
async annotationsChangedByReviewAction(annotation: AnnotationWrapper) {
- await this._cleanupAndRedrawManualAnnotationsForEntirePage(annotation?.pageNumber || this.activeViewerPage);
+ await this._reloadAnnotationsForPage(annotation?.pageNumber || this.activeViewerPage);
}
ocredFile(): void {
@@ -548,27 +548,32 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
await this._loadFileData(file, !this._reloadFileOnReanalysis);
this._reloadFileOnReanalysis = false;
this._loadingService.stop();
- await this._cleanupAndRedrawManualAnnotations();
+ await this._reloadAnnotations();
});
}
- private async _loadFileData(file: File, performUpdate = false): Promise {
+ private async _loadFileData(file: File, performUpdate = false): Promise {
+ if (!file || file.isError) {
+ return this._router.navigate([this._dossiersService.find(this.dossierId).routerLink]);
+ }
+
const fileData = await this._fileDownloadService.loadDataFor(file).toPromise();
- if (!file?.isPending && !file?.isError) {
+ if (!file.isPending) {
+ let excludedOrIncludedPages = new Set();
+ let currentPageAnnotations: AnnotationWrapper[] = [];
+
if (performUpdate && !!this.fileData) {
this.fileData.redactionLog = fileData.redactionLog;
this.fileData.viewedPages = fileData.viewedPages;
+ excludedOrIncludedPages = new Set([...this.fileData.file.excludedPages, ...file.excludedPages]);
+ currentPageAnnotations = this.annotations.filter(a => excludedOrIncludedPages.has(a.pageNumber));
+ this.fileData.file = file;
} else {
this.fileData = fileData;
}
- this.rebuildFilters();
- return;
- }
-
- if (file.isError) {
- await this._router.navigate([this._dossiersService.find(this.dossierId).routerLink]);
+ return this._cleanupAndRedrawAnnotations(currentPageAnnotations, a => excludedOrIncludedPages.has(a.pageNumber));
}
}
@@ -578,36 +583,32 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
this._workloadComponent?.scrollAnnotations();
}
- private async _cleanupAndRedrawManualAnnotations() {
- const currentAnnotations = this.annotations;
+ private async _reloadAnnotations() {
this.fileData.redactionLog = await this._fileDownloadService.loadRedactionLogFor(this.dossierId, this.fileId).toPromise();
- this.rebuildFilters();
-
- if (this.viewModeService.viewMode === 'STANDARD') {
- currentAnnotations.forEach(annotation => {
- this._findAndDeleteAnnotation(annotation.id);
- });
- const newAnnotations = this.annotations;
- this._handleDeltaAnnotationFilters(currentAnnotations, newAnnotations);
- await this._redrawAnnotations(newAnnotations);
- }
+ await this._cleanupAndRedrawAnnotations(this.annotations);
}
- private async _cleanupAndRedrawManualAnnotationsForEntirePage(page: number) {
+ private async _reloadAnnotationsForPage(page: number) {
const currentPageAnnotations = this.annotations.filter(a => a.pageNumber === page);
- const currentPageAnnotationIds = currentPageAnnotations.map(a => a.id);
await this._filesService.reload(this.dossierId, this.fileId).toPromise();
this.fileData.redactionLog = await this._fileDownloadService.loadRedactionLogFor(this.dossierId, this.fileId).toPromise();
+ await this._cleanupAndRedrawAnnotations(currentPageAnnotations, annotation => annotation.pageNumber === page);
+ }
+
+ private async _cleanupAndRedrawAnnotations(
+ annotationsToDelete: AnnotationWrapper[],
+ newAnnotationsFilter?: (annotation: AnnotationWrapper) => boolean,
+ ) {
this.rebuildFilters();
if (this.viewModeService.viewMode === 'STANDARD') {
- currentPageAnnotationIds.forEach(id => {
- this._findAndDeleteAnnotation(id);
+ annotationsToDelete?.forEach(annotation => {
+ this._findAndDeleteAnnotation(annotation.id);
});
- const newPageAnnotations = this.annotations.filter(item => item.pageNumber === page);
- this._handleDeltaAnnotationFilters(currentPageAnnotations, newPageAnnotations);
+ const newPageAnnotations = newAnnotationsFilter ? this.annotations.filter(newAnnotationsFilter) : this.annotations;
+ this._handleDeltaAnnotationFilters(annotationsToDelete ?? [], newPageAnnotations);
await this._redrawAnnotations(newPageAnnotations);
}
}
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/dossier/utils/pdf-viewer.utils.ts b/apps/red-ui/src/app/modules/dossier/utils/pdf-viewer.utils.ts
index 42bcbf6d6..5b29b9c07 100644
--- a/apps/red-ui/src/app/modules/dossier/utils/pdf-viewer.utils.ts
+++ b/apps/red-ui/src/app/modules/dossier/utils/pdf-viewer.utils.ts
@@ -2,6 +2,7 @@ import { translateQuads } from '@utils/pdf-coordinates';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { Core, WebViewerInstance } from '@pdftron/webviewer';
import { ViewModeService } from '../screens/file-preview-screen/services/view-mode.service';
+import { File } from '@red/domain';
import Annotation = Core.Annotations.Annotation;
const DISABLED_HOTKEYS = [
@@ -39,7 +40,6 @@ const DISABLED_HOTKEYS = [
export class PdfViewerUtils {
ready = false;
- excludedPages: number[] = [];
constructor(readonly instance: WebViewerInstance, readonly viewModeService: ViewModeService) {}
@@ -47,11 +47,6 @@ export class PdfViewerUtils {
return this.viewModeService.isCompare ? 2 : 1;
}
- get isCurrentPageExcluded() {
- const currentPage = this.currentPage;
- return !!this.excludedPages?.includes(currentPage);
- }
-
get currentPage() {
try {
return this.viewModeService.isCompare ? Math.ceil(this._currentInternalPage / 2) : this._currentInternalPage;
@@ -88,6 +83,11 @@ export class PdfViewerUtils {
return this.instance?.Core.documentViewer?.getPageCount();
}
+ isCurrentPageExcluded(file: File) {
+ const currentPage = this.currentPage;
+ return !!file?.excludedPages?.includes(currentPage);
+ }
+
navigateToPage(pageNumber: string | number) {
const parsedNumber = typeof pageNumber === 'string' ? parseInt(pageNumber, 10) : pageNumber;
this._navigateToPage(this.paginationOffset === 2 ? parsedNumber * this.paginationOffset - 1 : parsedNumber);
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/services/entity-services/files.service.ts b/apps/red-ui/src/app/services/entity-services/files.service.ts
index 485854529..258c93870 100644
--- a/apps/red-ui/src/app/services/entity-services/files.service.ts
+++ b/apps/red-ui/src/app/services/entity-services/files.service.ts
@@ -42,9 +42,9 @@ export class FilesService extends EntitiesService {
}
@Validate()
- setUnderApprovalFor(@RequiredParam() fileIds: List, @RequiredParam() dossierId: string, asigneeId: string) {
+ setUnderApprovalFor(@RequiredParam() fileIds: List, @RequiredParam() dossierId: string, assigneeId: string) {
const url = `${this._defaultModelPath}/under-approval/${dossierId}/bulk`;
- return this._post(fileIds, url, [{ key: 'assigneeId', value: asigneeId }]).pipe(switchMap(() => this.loadAll(dossierId)));
+ return this._post(fileIds, url, [{ key: 'assigneeId', value: assigneeId }]).pipe(switchMap(() => this.loadAll(dossierId)));
}
/**
diff --git a/apps/red-ui/src/app/services/user-preference.service.ts b/apps/red-ui/src/app/services/user-preference.service.ts
index e2ac56f9e..ac318c13d 100644
--- a/apps/red-ui/src/app/services/user-preference.service.ts
+++ b/apps/red-ui/src/app/services/user-preference.service.ts
@@ -68,8 +68,8 @@ export class UserPreferenceService extends GenericService {
window.location.reload();
}
- reload(): void {
- this.getAll()
+ reload(): Promise {
+ return this.getAll()
.toPromise()
.then(attributes => {
this._userAttributes = attributes ?? {};
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/app/translations/notifications-translations.ts b/apps/red-ui/src/app/translations/notifications-translations.ts
index adf4ca5bb..aa36fcc86 100644
--- a/apps/red-ui/src/app/translations/notifications-translations.ts
+++ b/apps/red-ui/src/app/translations/notifications-translations.ts
@@ -13,4 +13,5 @@ export const notificationsTranslations: { [key in NotificationType]: string } =
[NotificationTypes.USER_DEGRADED_TO_REVIEWER]: _('notification.user-demoted-to-reviewer'),
[NotificationTypes.USER_PROMOTED_TO_APPROVER]: _('notification.user-promoted-to-approver'),
[NotificationTypes.USER_REMOVED_AS_DOSSIER_MEMBER]: _('notification.user-removed-as-dossier-member'),
+ [NotificationTypes.DOWNLOAD_READY]: _('notification.download-ready'),
} as const;
diff --git a/apps/red-ui/src/app/utils/configuration.initializer.ts b/apps/red-ui/src/app/utils/configuration.initializer.ts
index 7350337e9..2f31bef07 100644
--- a/apps/red-ui/src/app/utils/configuration.initializer.ts
+++ b/apps/red-ui/src/app/utils/configuration.initializer.ts
@@ -23,8 +23,7 @@ export function configurationInitializer(
switchMap(loggedIn => (!loggedIn ? throwError('Not Logged In') : of({}))),
mergeMapTo(generalSettingsService.getGeneralConfigurations()),
tap(configuration => configService.updateDisplayName(configuration.displayName)),
- tap(() => userPreferenceService.reload()),
- tap(() => languageService.chooseAndSetInitialLanguage()),
+ tap(() => userPreferenceService.reload().then(() => languageService.chooseAndSetInitialLanguage())),
catchError(() => {
title.setTitle('RedactManager');
return of({});
diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json
index 4b1931c00..771207a5f 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",
@@ -356,12 +364,12 @@
"save": "Save Changes"
},
"content": {
+ "classification": "Value / Classification",
"comment": "Comment",
"legalBasis": "Legal Basis",
"reason": "Select redaction reason",
- "section": "Paragraph / Location",
- "classification": "Value / Classification",
- "reason-placeholder": "Select a reason..."
+ "reason-placeholder": "Select a reason...",
+ "section": "Paragraph / Location"
},
"header": "Edit Redaction Reason"
},
@@ -1118,9 +1126,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",
@@ -1263,14 +1271,14 @@
"save": "Save"
},
"content": {
+ "classification": "Value / Classification",
"comment": "Comment",
"dictionary": "Dictionary",
"legalBasis": "Legal Basis",
"reason": "Reason",
- "section": "Paragraph / Location",
- "classification": "Value / Classification",
"reason-placeholder": "Select a reason ...",
"rectangle": "Custom Rectangle",
+ "section": "Paragraph / Location",
"text": "Selected text:"
},
"header": {
@@ -1305,6 +1313,7 @@
"dossier-deleted": "Dossier: {dossierName} has been deleted!",
"dossier-owner-removed": "{dossierName} owner removed!",
"dossier-owner-set": " {dossierName} owner changed to {user}!",
+ "download-ready": "Your download is ready!",
"no-data": "You currently have no notifications",
"unassigned-from-file": "You have been unassigned from {fileName} in the {dossierName}!",
"user-becomes-dossier-member": "{user} joined dossier: {dossierName}!",
@@ -1497,9 +1506,9 @@
},
"search-screen": {
"cols": {
+ "assignee": "Assignee",
"document": "Document",
"dossier": "Dossier",
- "assignee": "Assignee",
"pages": "Pages",
"status": "Status"
},
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 @@
+
+
diff --git a/libs/common-ui b/libs/common-ui
index caf4838be..0610684e8 160000
--- a/libs/common-ui
+++ b/libs/common-ui
@@ -1 +1 @@
-Subproject commit caf4838be63574740e5380c74ad96fe21f7a456b
+Subproject commit 0610684e8fb963fab1f7dd51fd850a7b47287fca
diff --git a/libs/red-domain/src/lib/notifications/types.ts b/libs/red-domain/src/lib/notifications/types.ts
index fb1465a6f..4e59d8bbb 100644
--- a/libs/red-domain/src/lib/notifications/types.ts
+++ b/libs/red-domain/src/lib/notifications/types.ts
@@ -10,6 +10,7 @@ export const NotificationTypes = {
USER_REMOVED_AS_DOSSIER_MEMBER: 'USER_REMOVED_AS_DOSSIER_MEMBER', // "You have been removed from a dossier"
USER_PROMOTED_TO_APPROVER: 'USER_PROMOTED_TO_APPROVER', // "You are promoted to approver"
USER_DEGRADED_TO_REVIEWER: 'USER_DEGRADED_TO_REVIEWER', // "You are denoted to reviewer"
+ DOWNLOAD_READY: 'DOWNLOAD_READY',
} as const;
export type NotificationType = keyof typeof NotificationTypes;
diff --git a/package.json b/package.json
index 287c958c5..91a9f08b4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "redaction",
- "version": "3.105.0",
+ "version": "3.111.0",
"private": true,
"license": "MIT",
"scripts": {
diff --git a/paligo-theme.tar.gz b/paligo-theme.tar.gz
index 646cc9b83..840317a80 100644
Binary files a/paligo-theme.tar.gz and b/paligo-theme.tar.gz differ
diff --git a/paligo-theme/paligo-styles/redacto-theme.css b/paligo-theme/paligo-styles/redacto-theme.css
index bdb03936c..5ceef3777 100644
--- a/paligo-theme/paligo-styles/redacto-theme.css
+++ b/paligo-theme/paligo-styles/redacto-theme.css
@@ -319,6 +319,7 @@ li.searchresultitem {
--iqser-grey-5: #d3d5da;
--iqser-grey-6: #f0f1f4;
--iqser-grey-7: #9398a0;
+ --iqser-grey-8: #f9fafb;
--iqser-green-1: #00ff00;
--iqser-green-2: #5ce594;
--iqser-yellow-1: #ffb83b;