use reactive annotations
This commit is contained in:
parent
ee6f8dab02
commit
c8a2e0b580
@ -1,8 +1,9 @@
|
|||||||
import { Injectable, Injector } from '@angular/core';
|
import { Injectable, Injector } from '@angular/core';
|
||||||
import { GenericService, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
|
import { GenericService, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
|
||||||
import { TextHighlightOperation, TextHighlightRequest, TextHighlightResponse } from '@red/domain';
|
import { ImportedRedaction, TextHighlightOperation, TextHighlightRequest, TextHighlightResponse } from '@red/domain';
|
||||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||||
import { tap } from 'rxjs/operators';
|
import { catchError, map, tap } from 'rxjs/operators';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
@ -20,7 +21,10 @@ export class TextHighlightService extends GenericService<TextHighlightResponse>
|
|||||||
operation: TextHighlightOperation.INFO,
|
operation: TextHighlightOperation.INFO,
|
||||||
};
|
};
|
||||||
|
|
||||||
return this._post(request);
|
return this._post(request).pipe(
|
||||||
|
map(response => response.redactionPerColor),
|
||||||
|
catchError(() => of({} as Record<string, ImportedRedaction[]>)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Validate()
|
@Validate()
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { MultiSelectService } from '../../services/multi-select.service';
|
|||||||
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
||||||
import { HelpModeService, ScrollableParentView, ScrollableParentViews } from '@iqser/common-ui';
|
import { HelpModeService, ScrollableParentView, ScrollableParentViews } from '@iqser/common-ui';
|
||||||
import { PdfViewer } from '../../services/pdf-viewer.service';
|
import { PdfViewer } from '../../services/pdf-viewer.service';
|
||||||
|
import { FileDataService } from '../../services/file-data.service';
|
||||||
|
|
||||||
export const AnnotationButtonTypes = {
|
export const AnnotationButtonTypes = {
|
||||||
dark: 'dark',
|
dark: 'dark',
|
||||||
@ -39,6 +40,7 @@ export class AnnotationActionsComponent implements OnChanges {
|
|||||||
private readonly _pdf: PdfViewer,
|
private readonly _pdf: PdfViewer,
|
||||||
private readonly _state: FilePreviewStateService,
|
private readonly _state: FilePreviewStateService,
|
||||||
private readonly _permissionsService: PermissionsService,
|
private readonly _permissionsService: PermissionsService,
|
||||||
|
private readonly _fileDataService: FileDataService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
private _annotations: AnnotationWrapper[];
|
private _annotations: AnnotationWrapper[];
|
||||||
@ -101,14 +103,14 @@ export class AnnotationActionsComponent implements OnChanges {
|
|||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
this._pdf.annotationManager.hideAnnotations(this.viewerAnnotations);
|
this._pdf.annotationManager.hideAnnotations(this.viewerAnnotations);
|
||||||
this._pdf.annotationManager.deselectAllAnnotations();
|
this._pdf.annotationManager.deselectAllAnnotations();
|
||||||
this.annotationActionsService.updateHiddenAnnotation(this.annotations, this.viewerAnnotations, true);
|
this._fileDataService.updateHiddenAnnotations(this.viewerAnnotations, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
showAnnotation($event: MouseEvent) {
|
showAnnotation($event: MouseEvent) {
|
||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
this._pdf.annotationManager.showAnnotations(this.viewerAnnotations);
|
this._pdf.annotationManager.showAnnotations(this.viewerAnnotations);
|
||||||
this._pdf.annotationManager.deselectAllAnnotations();
|
this._pdf.annotationManager.deselectAllAnnotations();
|
||||||
this.annotationActionsService.updateHiddenAnnotation(this.annotations, this.viewerAnnotations, false);
|
this._fileDataService.updateHiddenAnnotations(this.viewerAnnotations, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
resize($event: MouseEvent) {
|
resize($event: MouseEvent) {
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||||
import { AnnotationReferencesService } from '../../services/annotation-references.service';
|
import { AnnotationReferencesService } from '../../services/annotation-references.service';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable, switchMap } from 'rxjs';
|
||||||
import { filter, map } from 'rxjs/operators';
|
import { filter } from 'rxjs/operators';
|
||||||
import { FileDataService } from '../../services/file-data.service';
|
import { FileDataService } from '../../services/file-data.service';
|
||||||
|
import { filterEach } from '../../../../../../../../libs/common-ui/src';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-annotation-references-list',
|
selector: 'redaction-annotation-references-list',
|
||||||
@ -21,7 +22,7 @@ export class AnnotationReferencesListComponent {
|
|||||||
private get _annotationReferences(): Observable<AnnotationWrapper[]> {
|
private get _annotationReferences(): Observable<AnnotationWrapper[]> {
|
||||||
return this.annotationReferencesService.annotation$.pipe(
|
return this.annotationReferencesService.annotation$.pipe(
|
||||||
filter(annotation => !!annotation),
|
filter(annotation => !!annotation),
|
||||||
map(({ reference }) => this._fileDataService.allAnnotations.filter(a => reference.includes(a.annotationId))),
|
switchMap(({ reference }) => this._fileDataService.annotations$.pipe(filterEach(a => reference.includes(a.annotationId)))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import {
|
|||||||
shareDistinctLast,
|
shareDistinctLast,
|
||||||
shareLast,
|
shareLast,
|
||||||
} from '@iqser/common-ui';
|
} from '@iqser/common-ui';
|
||||||
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
|
import { combineLatest, Observable } from 'rxjs';
|
||||||
import { map, tap } from 'rxjs/operators';
|
import { map, tap } from 'rxjs/operators';
|
||||||
import { File } from '@red/domain';
|
import { File } from '@red/domain';
|
||||||
import { ExcludedPagesService } from '../../services/excluded-pages.service';
|
import { ExcludedPagesService } from '../../services/excluded-pages.service';
|
||||||
@ -66,7 +66,6 @@ export class FileWorkloadComponent {
|
|||||||
readonly showExcludedPages$: Observable<boolean>;
|
readonly showExcludedPages$: Observable<boolean>;
|
||||||
readonly title$: Observable<string>;
|
readonly title$: Observable<string>;
|
||||||
readonly isHighlights$: Observable<boolean>;
|
readonly isHighlights$: Observable<boolean>;
|
||||||
private _annotations$ = new BehaviorSubject<AnnotationWrapper[]>([]);
|
|
||||||
@ViewChild('annotationsElement') private readonly _annotationsElement: ElementRef;
|
@ViewChild('annotationsElement') private readonly _annotationsElement: ElementRef;
|
||||||
@ViewChild('quickNavigation') private readonly _quickNavigationElement: ElementRef;
|
@ViewChild('quickNavigation') private readonly _quickNavigationElement: ElementRef;
|
||||||
|
|
||||||
@ -89,11 +88,6 @@ export class FileWorkloadComponent {
|
|||||||
this.title$ = this._title$;
|
this.title$ = this._title$;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input()
|
|
||||||
set annotations(value: AnnotationWrapper[]) {
|
|
||||||
this._annotations$.next(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
get activeAnnotations(): AnnotationWrapper[] | undefined {
|
get activeAnnotations(): AnnotationWrapper[] | undefined {
|
||||||
return this.displayedAnnotations.get(this.activeViewerPage);
|
return this.displayedAnnotations.get(this.activeViewerPage);
|
||||||
}
|
}
|
||||||
@ -142,7 +136,7 @@ export class FileWorkloadComponent {
|
|||||||
const primary$ = this.filterService.getFilterModels$('primaryFilters');
|
const primary$ = this.filterService.getFilterModels$('primaryFilters');
|
||||||
const secondary$ = this.filterService.getFilterModels$('secondaryFilters');
|
const secondary$ = this.filterService.getFilterModels$('secondaryFilters');
|
||||||
|
|
||||||
return combineLatest([this._annotations$.asObservable(), primary$, secondary$]).pipe(
|
return combineLatest([this.fileDataService.visibleAnnotations$, primary$, secondary$]).pipe(
|
||||||
map(([annotations, primary, secondary]) => this._filterAnnotations(annotations, primary, secondary)),
|
map(([annotations, primary, secondary]) => this._filterAnnotations(annotations, primary, secondary)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,6 +41,7 @@ import { PageRotationService } from '../../services/page-rotation.service';
|
|||||||
import { ALLOWED_KEYBOARD_SHORTCUTS, HeaderElements, TextPopups } from '../../shared/constants';
|
import { ALLOWED_KEYBOARD_SHORTCUTS, HeaderElements, TextPopups } from '../../shared/constants';
|
||||||
import { FilePreviewDialogService } from '../../services/file-preview-dialog.service';
|
import { FilePreviewDialogService } from '../../services/file-preview-dialog.service';
|
||||||
import { loadCompareDocumentWrapper } from '../../../dossier/utils/compare-mode.utils';
|
import { loadCompareDocumentWrapper } from '../../../dossier/utils/compare-mode.utils';
|
||||||
|
import { FileDataService } from '../../services/file-data.service';
|
||||||
import Tools = Core.Tools;
|
import Tools = Core.Tools;
|
||||||
import TextTool = Tools.TextTool;
|
import TextTool = Tools.TextTool;
|
||||||
import Annotation = Core.Annotations.Annotation;
|
import Annotation = Core.Annotations.Annotation;
|
||||||
@ -60,7 +61,6 @@ function getDivider(hiddenOn?: readonly ('desktop' | 'mobile' | 'tablet')[]) {
|
|||||||
export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnChanges {
|
export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnChanges {
|
||||||
@Input() dossier: Dossier;
|
@Input() dossier: Dossier;
|
||||||
@Input() canPerformActions = false;
|
@Input() canPerformActions = false;
|
||||||
@Input() annotations: AnnotationWrapper[];
|
|
||||||
@Output() readonly fileReady = new EventEmitter();
|
@Output() readonly fileReady = new EventEmitter();
|
||||||
@Output() readonly annotationSelected = new EventEmitter<string[]>();
|
@Output() readonly annotationSelected = new EventEmitter<string[]>();
|
||||||
@Output() readonly manualAnnotationRequested = new EventEmitter<ManualRedactionEntryWrapper>();
|
@Output() readonly manualAnnotationRequested = new EventEmitter<ManualRedactionEntryWrapper>();
|
||||||
@ -89,6 +89,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
|
|||||||
private readonly _loadingService: LoadingService,
|
private readonly _loadingService: LoadingService,
|
||||||
private readonly _fileManagementService: FileManagementService,
|
private readonly _fileManagementService: FileManagementService,
|
||||||
private readonly _pageRotationService: PageRotationService,
|
private readonly _pageRotationService: PageRotationService,
|
||||||
|
private readonly _fileDataService: FileDataService,
|
||||||
readonly stateService: FilePreviewStateService,
|
readonly stateService: FilePreviewStateService,
|
||||||
readonly viewModeService: ViewModeService,
|
readonly viewModeService: ViewModeService,
|
||||||
readonly multiSelectService: MultiSelectService,
|
readonly multiSelectService: MultiSelectService,
|
||||||
@ -226,18 +227,19 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
|
|||||||
this.pdf.disableHotkeys();
|
this.pdf.disableHotkeys();
|
||||||
await this._configureTextPopup();
|
await this._configureTextPopup();
|
||||||
|
|
||||||
this.annotationManager.addEventListener('annotationSelected', (annotations: Annotation[], action) => {
|
this.annotationManager.addEventListener('annotationSelected', async (annotations: Annotation[], action) => {
|
||||||
const nextAnnotations = this.multiSelectService.isEnabled ? this.annotationManager.getSelectedAnnotations() : annotations;
|
const nextAnnotations = this.multiSelectService.isEnabled ? this.annotationManager.getSelectedAnnotations() : annotations;
|
||||||
this.annotationSelected.emit(nextAnnotations.map(ann => ann.Id));
|
this.annotationSelected.emit(nextAnnotations.map(ann => ann.Id));
|
||||||
if (action === 'deselected') {
|
if (action === 'deselected') {
|
||||||
this._toggleRectangleAnnotationAction(true);
|
return this._toggleRectangleAnnotationAction(true);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
if (!this.multiSelectService.isEnabled) {
|
if (!this.multiSelectService.isEnabled) {
|
||||||
this.pdf.deselectAnnotations(this.annotations.filter(wrapper => !nextAnnotations.find(ann => ann.Id === wrapper.id)));
|
const visibleAnnotations = await this._fileDataService.visibleAnnotations;
|
||||||
|
this.pdf.deselectAnnotations(visibleAnnotations.filter(wrapper => !nextAnnotations.find(ann => ann.Id === wrapper.id)));
|
||||||
}
|
}
|
||||||
this._configureAnnotationSpecificActions(annotations);
|
this.#configureAnnotationSpecificActions(annotations);
|
||||||
this._toggleRectangleAnnotationAction(annotations.length === 1 && annotations[0].ReadOnly);
|
this._toggleRectangleAnnotationAction(annotations.length === 1 && annotations[0].ReadOnly);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.annotationManager.addEventListener('annotationChanged', (annotations: Annotation[]) => {
|
this.annotationManager.addEventListener('annotationChanged', (annotations: Annotation[]) => {
|
||||||
@ -480,12 +482,13 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _configureAnnotationSpecificActions(viewerAnnotations: Annotation[]) {
|
async #configureAnnotationSpecificActions(viewerAnnotations: Annotation[]) {
|
||||||
if (!this.canPerformActions) {
|
if (!this.canPerformActions) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const annotationWrappers = viewerAnnotations.map(va => this.annotations.find(a => a.id === va.Id)).filter(va => !!va);
|
const visibleAnnotations = await this._fileDataService.visibleAnnotations;
|
||||||
|
const annotationWrappers = viewerAnnotations.map(va => visibleAnnotations.find(a => a.id === va.Id)).filter(va => !!va);
|
||||||
this.instance.UI.annotationPopup.update([]);
|
this.instance.UI.annotationPopup.update([]);
|
||||||
|
|
||||||
if (annotationWrappers.length === 0) {
|
if (annotationWrappers.length === 0) {
|
||||||
@ -513,7 +516,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
|
|||||||
this.annotationManager.showAnnotations(viewerAnnotations);
|
this.annotationManager.showAnnotations(viewerAnnotations);
|
||||||
}
|
}
|
||||||
this.annotationManager.deselectAllAnnotations();
|
this.annotationManager.deselectAllAnnotations();
|
||||||
this._annotationActionsService.updateHiddenAnnotation(this.annotations, viewerAnnotations, allAreVisible);
|
this._fileDataService.updateHiddenAnnotations(viewerAnnotations, allAreVisible);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -69,7 +69,6 @@
|
|||||||
(pageChanged)="viewerPageChanged($event)"
|
(pageChanged)="viewerPageChanged($event)"
|
||||||
(viewerReady)="viewerReady()"
|
(viewerReady)="viewerReady()"
|
||||||
*ngIf="displayPdfViewer"
|
*ngIf="displayPdfViewer"
|
||||||
[annotations]="visibleAnnotations"
|
|
||||||
[canPerformActions]="canPerformAnnotationActions$ | async"
|
[canPerformActions]="canPerformAnnotationActions$ | async"
|
||||||
[class.hidden]="!ready"
|
[class.hidden]="!ready"
|
||||||
[dossier]="dossier"
|
[dossier]="dossier"
|
||||||
@ -95,7 +94,6 @@
|
|||||||
*ngIf="!file.excluded"
|
*ngIf="!file.excluded"
|
||||||
[activeViewerPage]="activeViewerPage"
|
[activeViewerPage]="activeViewerPage"
|
||||||
[annotationActionsTemplate]="annotationActionsTemplate"
|
[annotationActionsTemplate]="annotationActionsTemplate"
|
||||||
[annotations]="visibleAnnotations"
|
|
||||||
[dialogRef]="dialogRef"
|
[dialogRef]="dialogRef"
|
||||||
[file]="file"
|
[file]="file"
|
||||||
[selectedAnnotations]="selectedAnnotations"
|
[selectedAnnotations]="selectedAnnotations"
|
||||||
|
|||||||
@ -125,14 +125,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
|||||||
return this._pageRotationService.hasRotations();
|
return this._pageRotationService.hasRotations();
|
||||||
}
|
}
|
||||||
|
|
||||||
get visibleAnnotations(): AnnotationWrapper[] {
|
|
||||||
return this._fileDataService.getVisibleAnnotations(this._viewModeService.viewMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
get allAnnotations(): AnnotationWrapper[] {
|
|
||||||
return this._fileDataService.allAnnotations;
|
|
||||||
}
|
|
||||||
|
|
||||||
private get _canPerformAnnotationActions$() {
|
private get _canPerformAnnotationActions$() {
|
||||||
const viewMode$ = this._viewModeService.viewMode$.pipe(tap(() => this.#deactivateMultiSelect()));
|
const viewMode$ = this._viewModeService.viewMode$.pipe(tap(() => this.#deactivateMultiSelect()));
|
||||||
|
|
||||||
@ -154,15 +146,17 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._pdf.deleteAnnotations(this._fileDataService.textHighlightAnnotations.map(a => a.id));
|
this._pdf.deleteAnnotations(this._fileDataService.textHighlights.map(a => a.id));
|
||||||
|
|
||||||
const ocrAnnotationIds = this.allAnnotations.filter(a => a.isOCR).map(a => a.id);
|
|
||||||
const annotations = this._pdf.getAnnotations(a => a.getCustomData('redact-manager'));
|
const annotations = this._pdf.getAnnotations(a => a.getCustomData('redact-manager'));
|
||||||
const redactions = annotations.filter(a => a.getCustomData('redaction'));
|
const redactions = annotations.filter(a => a.getCustomData('redaction'));
|
||||||
|
|
||||||
switch (this._viewModeService.viewMode) {
|
switch (this._viewModeService.viewMode) {
|
||||||
case 'STANDARD': {
|
case 'STANDARD': {
|
||||||
this._setAnnotationsColor(redactions, 'annotationColor');
|
this._setAnnotationsColor(redactions, 'annotationColor');
|
||||||
|
const wrappers = await this._fileDataService.annotations;
|
||||||
|
const ocrAnnotationIds = wrappers.filter(a => a.isOCR).map(a => a.id);
|
||||||
|
|
||||||
const standardEntries = annotations
|
const standardEntries = annotations
|
||||||
.filter(a => a.getCustomData('changeLogRemoved') === 'false')
|
.filter(a => a.getCustomData('changeLogRemoved') === 'false')
|
||||||
.filter(a => !ocrAnnotationIds.includes(a.Id));
|
.filter(a => !ocrAnnotationIds.includes(a.Id));
|
||||||
@ -192,14 +186,14 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
|||||||
case 'TEXT_HIGHLIGHTS': {
|
case 'TEXT_HIGHLIGHTS': {
|
||||||
this._loadingService.start();
|
this._loadingService.start();
|
||||||
this._pdf.hideAnnotations(annotations);
|
this._pdf.hideAnnotations(annotations);
|
||||||
await this._fileDataService.loadTextHighlights();
|
const highlights = await this._fileDataService.loadTextHighlights();
|
||||||
await this._annotationDrawService.drawAnnotations(this._fileDataService.textHighlightAnnotations);
|
await this._annotationDrawService.drawAnnotations(highlights);
|
||||||
this._loadingService.stop();
|
this._loadingService.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this._stampPDF();
|
await this._stampPDF();
|
||||||
this.rebuildFilters();
|
await this.rebuildFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDetach(): void {
|
ngOnDetach(): void {
|
||||||
@ -237,7 +231,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
|||||||
this.displayPdfViewer = true;
|
this.displayPdfViewer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rebuildFilters(deletePreviousAnnotations = false): void {
|
async rebuildFilters(deletePreviousAnnotations = false) {
|
||||||
const startTime = new Date().getTime();
|
const startTime = new Date().getTime();
|
||||||
if (deletePreviousAnnotations) {
|
if (deletePreviousAnnotations) {
|
||||||
this._pdf.deleteAnnotations();
|
this._pdf.deleteAnnotations();
|
||||||
@ -246,7 +240,8 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
|||||||
}
|
}
|
||||||
const processStartTime = new Date().getTime();
|
const processStartTime = new Date().getTime();
|
||||||
|
|
||||||
const annotationFilters = this._annotationProcessingService.getAnnotationFilter(this.visibleAnnotations);
|
const visibleAnnotations = await this._fileDataService.visibleAnnotations;
|
||||||
|
const annotationFilters = this._annotationProcessingService.getAnnotationFilter(visibleAnnotations);
|
||||||
const primaryFilters = this._filterService.getGroup('primaryFilters')?.filters;
|
const primaryFilters = this._filterService.getGroup('primaryFilters')?.filters;
|
||||||
this._filterService.addFilterGroup({
|
this._filterService.addFilterGroup({
|
||||||
slug: 'primaryFilters',
|
slug: 'primaryFilters',
|
||||||
@ -266,9 +261,10 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
|||||||
console.log(`[REDACTION] Filter rebuild time: ${new Date().getTime() - startTime}`);
|
console.log(`[REDACTION] Filter rebuild time: ${new Date().getTime() - startTime}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAnnotationSelected(annotationIds: string[]) {
|
async handleAnnotationSelected(annotationIds: string[]) {
|
||||||
|
const visibleAnnotations = await this._fileDataService.visibleAnnotations;
|
||||||
this.selectedAnnotations = annotationIds
|
this.selectedAnnotations = annotationIds
|
||||||
.map(id => this.visibleAnnotations.find(annotationWrapper => annotationWrapper.id === id))
|
.map(id => visibleAnnotations.find(annotation => annotation.id === id))
|
||||||
.filter(ann => ann !== undefined);
|
.filter(ann => ann !== undefined);
|
||||||
if (this.selectedAnnotations.length > 1) {
|
if (this.selectedAnnotations.length > 1) {
|
||||||
this.multiSelectService.activate();
|
this.multiSelectService.activate();
|
||||||
@ -447,10 +443,10 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
|||||||
download(await firstValueFrom(originalFile), file.filename);
|
download(await firstValueFrom(originalFile), file.filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
#deactivateMultiSelect(): void {
|
async #deactivateMultiSelect() {
|
||||||
this.multiSelectService.deactivate();
|
this.multiSelectService.deactivate();
|
||||||
this._pdf.deselectAllAnnotations();
|
this._pdf.deselectAllAnnotations();
|
||||||
this.handleAnnotationSelected([]);
|
await this.handleAnnotationSelected([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _setExcludedPageStyles() {
|
private _setExcludedPageStyles() {
|
||||||
@ -498,7 +494,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _stampPreview(document: PDFNet.PDFDoc, dossierTemplateId: string) {
|
private async _stampPreview(document: PDFNet.PDFDoc, dossierTemplateId: string) {
|
||||||
const watermark = await this._watermarkService.getWatermark(dossierTemplateId).toPromise();
|
const watermark = await firstValueFrom(this._watermarkService.getWatermark(dossierTemplateId));
|
||||||
await stampPDFPage(
|
await stampPDFPage(
|
||||||
document,
|
document,
|
||||||
this._pdf.PDFNet,
|
this._pdf.PDFNet,
|
||||||
@ -605,7 +601,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentPageAnnotations = this.visibleAnnotations.filter(a => a.pageNumber === page);
|
const currentPageAnnotations = (await this._fileDataService.visibleAnnotations).filter(a => a.pageNumber === page);
|
||||||
await this._fileDataService.loadRedactionLog();
|
await this._fileDataService.loadRedactionLog();
|
||||||
|
|
||||||
this._pdf.deleteAnnotations(currentPageAnnotations.map(a => a.id));
|
this._pdf.deleteAnnotations(currentPageAnnotations.map(a => a.id));
|
||||||
@ -618,14 +614,15 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
|||||||
}
|
}
|
||||||
|
|
||||||
const currentFilters = this._filterService.getGroup('primaryFilters')?.filters || [];
|
const currentFilters = this._filterService.getGroup('primaryFilters')?.filters || [];
|
||||||
this.rebuildFilters();
|
await this.rebuildFilters();
|
||||||
|
|
||||||
const startTime = new Date().getTime();
|
const startTime = new Date().getTime();
|
||||||
const annotations = this.allAnnotations;
|
const annotations = await this._fileDataService.annotations;
|
||||||
const newAnnotations = newAnnotationsFilter ? annotations.filter(newAnnotationsFilter) : annotations;
|
const newAnnotations = newAnnotationsFilter ? annotations.filter(newAnnotationsFilter) : annotations;
|
||||||
|
|
||||||
if (currentFilters) {
|
if (currentFilters) {
|
||||||
this._handleDeltaAnnotationFilters(currentFilters, this.visibleAnnotations);
|
const visibleAnnotations = await this._fileDataService.visibleAnnotations;
|
||||||
|
this._handleDeltaAnnotationFilters(currentFilters, visibleAnnotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this._annotationDrawService.drawAnnotations(newAnnotations);
|
await this._annotationDrawService.drawAnnotations(newAnnotations);
|
||||||
|
|||||||
@ -24,7 +24,6 @@ import { MatDialog } from '@angular/material/dialog';
|
|||||||
import { FilePreviewStateService } from './file-preview-state.service';
|
import { FilePreviewStateService } from './file-preview-state.service';
|
||||||
import { PdfViewer } from './pdf-viewer.service';
|
import { PdfViewer } from './pdf-viewer.service';
|
||||||
import { FilePreviewDialogService } from './file-preview-dialog.service';
|
import { FilePreviewDialogService } from './file-preview-dialog.service';
|
||||||
import Annotation = Core.Annotations.Annotation;
|
|
||||||
import Quad = Core.Math.Quad;
|
import Quad = Core.Math.Quad;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -414,12 +413,6 @@ export class AnnotationActionsService {
|
|||||||
return availableActions;
|
return availableActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHiddenAnnotation(annotations: AnnotationWrapper[], viewerAnnotations: Annotation[], hidden: boolean) {
|
|
||||||
const annotationId = viewerAnnotations[0].Id;
|
|
||||||
const annotationToBeUpdated = annotations.find((a: AnnotationWrapper) => a.annotationId === annotationId);
|
|
||||||
annotationToBeUpdated.hidden = hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
resize($event: MouseEvent, annotationWrapper: AnnotationWrapper) {
|
resize($event: MouseEvent, annotationWrapper: AnnotationWrapper) {
|
||||||
$event?.stopPropagation();
|
$event?.stopPropagation();
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { DossiersService } from '@services/dossiers/dossiers.service';
|
|||||||
import { PdfViewer } from './pdf-viewer.service';
|
import { PdfViewer } from './pdf-viewer.service';
|
||||||
import { FilePreviewStateService } from './file-preview-state.service';
|
import { FilePreviewStateService } from './file-preview-state.service';
|
||||||
import { ViewModeService } from './view-mode.service';
|
import { ViewModeService } from './view-mode.service';
|
||||||
|
import { FileDataService } from './file-data.service';
|
||||||
import Annotation = Core.Annotations.Annotation;
|
import Annotation = Core.Annotations.Annotation;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -31,6 +32,7 @@ export class AnnotationDrawService {
|
|||||||
private readonly _pdf: PdfViewer,
|
private readonly _pdf: PdfViewer,
|
||||||
private readonly _state: FilePreviewStateService,
|
private readonly _state: FilePreviewStateService,
|
||||||
private readonly _viewModeService: ViewModeService,
|
private readonly _viewModeService: ViewModeService,
|
||||||
|
private readonly _fileDataService: FileDataService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
drawAnnotations(annotationWrappers: AnnotationWrapper[]) {
|
drawAnnotations(annotationWrappers: AnnotationWrapper[]) {
|
||||||
@ -200,7 +202,7 @@ export class AnnotationDrawService {
|
|||||||
annotationWrapper.isChangeLogRemoved ||
|
annotationWrapper.isChangeLogRemoved ||
|
||||||
(this._skippedService.hideSkipped && annotationWrapper.isSkipped) ||
|
(this._skippedService.hideSkipped && annotationWrapper.isSkipped) ||
|
||||||
annotationWrapper.isOCR ||
|
annotationWrapper.isOCR ||
|
||||||
annotationWrapper.hidden;
|
this._fileDataService.isHidden(annotationWrapper.annotationId);
|
||||||
annotation.setCustomData('redact-manager', 'true');
|
annotation.setCustomData('redact-manager', 'true');
|
||||||
annotation.setCustomData('redaction', String(annotationWrapper.previewAnnotation));
|
annotation.setCustomData('redaction', String(annotationWrapper.previewAnnotation));
|
||||||
annotation.setCustomData('skipped', String(annotationWrapper.isSkipped));
|
annotation.setCustomData('skipped', String(annotationWrapper.isSkipped));
|
||||||
|
|||||||
@ -1,66 +1,100 @@
|
|||||||
import {
|
import {
|
||||||
ChangeType,
|
ChangeType,
|
||||||
File,
|
File,
|
||||||
|
ImportedRedaction,
|
||||||
IRedactionLog,
|
IRedactionLog,
|
||||||
IRedactionLogEntry,
|
IRedactionLogEntry,
|
||||||
IViewedPage,
|
IViewedPage,
|
||||||
LogEntryStatus,
|
LogEntryStatus,
|
||||||
ManualRedactionType,
|
ManualRedactionType,
|
||||||
TextHighlightResponse,
|
|
||||||
ViewMode,
|
ViewMode,
|
||||||
|
ViewModes,
|
||||||
} from '@red/domain';
|
} from '@red/domain';
|
||||||
import { AnnotationWrapper } from '../../../models/file/annotation.wrapper';
|
import { AnnotationWrapper } from '../../../models/file/annotation.wrapper';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import { BehaviorSubject, firstValueFrom, of } from 'rxjs';
|
import { BehaviorSubject, firstValueFrom, iif, Observable, of } from 'rxjs';
|
||||||
import { RedactionLogEntry } from '../../../models/file/redaction-log.entry';
|
import { RedactionLogEntry } from '../../../models/file/redaction-log.entry';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { FilePreviewStateService } from './file-preview-state.service';
|
import { FilePreviewStateService } from './file-preview-state.service';
|
||||||
import { ViewedPagesService } from '../../../services/entity-services/viewed-pages.service';
|
import { ViewedPagesService } from '../../../services/entity-services/viewed-pages.service';
|
||||||
import { UserPreferenceService } from '../../../services/user-preference.service';
|
import { UserPreferenceService } from '../../../services/user-preference.service';
|
||||||
import { DictionariesMapService } from '../../../services/entity-services/dictionaries-map.service';
|
import { DictionariesMapService } from '../../../services/entity-services/dictionaries-map.service';
|
||||||
import { catchError, tap } from 'rxjs/operators';
|
import { catchError, map, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||||
import { PermissionsService } from '../../../services/permissions.service';
|
import { PermissionsService } from '../../../services/permissions.service';
|
||||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||||
import { Toaster } from '../../../../../../../libs/common-ui/src';
|
import { log, shareLast, Toaster } from '../../../../../../../libs/common-ui/src';
|
||||||
import { RedactionLogService } from '../../dossier/services/redaction-log.service';
|
import { RedactionLogService } from '../../dossier/services/redaction-log.service';
|
||||||
import { TextHighlightService } from '../../dossier/services/text-highlight.service';
|
import { TextHighlightService } from '../../dossier/services/text-highlight.service';
|
||||||
|
import { ViewModeService } from './view-mode.service';
|
||||||
|
import { Core } from '@pdftron/webviewer';
|
||||||
|
import Annotation = Core.Annotations.Annotation;
|
||||||
|
|
||||||
|
const DELTA_VIEW_TIME = 10 * 60 * 1000; // 10 minutes;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FileDataService {
|
export class FileDataService {
|
||||||
static readonly DELTA_VIEW_TIME = 10 * 60 * 1000; // 10 minutes;
|
|
||||||
viewedPages: IViewedPage[] = [];
|
viewedPages: IViewedPage[] = [];
|
||||||
allAnnotations: AnnotationWrapper[] = [];
|
|
||||||
readonly hasChangeLog$ = new BehaviorSubject<boolean>(false);
|
readonly hasChangeLog$ = new BehaviorSubject<boolean>(false);
|
||||||
missingTypes = new Set<string>();
|
missingTypes = new Set<string>();
|
||||||
textHighlightAnnotations: AnnotationWrapper[] = [];
|
|
||||||
shouldUpdateAnnotations = false;
|
shouldUpdateAnnotations = false;
|
||||||
|
readonly annotations$: Observable<AnnotationWrapper[]>;
|
||||||
|
readonly visibleAnnotations$: Observable<AnnotationWrapper[]>;
|
||||||
|
readonly hiddenAnnotations = new Set<string>();
|
||||||
|
|
||||||
#redactionLog: IRedactionLog;
|
#redactionLog: IRedactionLog;
|
||||||
#redactionLogHash = '';
|
#redactionLogHash = '';
|
||||||
|
readonly #redactionLog$ = new BehaviorSubject<IRedactionLog>({});
|
||||||
|
readonly #textHighlights$ = new BehaviorSubject<AnnotationWrapper[]>([]);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _state: FilePreviewStateService,
|
private readonly _state: FilePreviewStateService,
|
||||||
private readonly _viewedPagesService: ViewedPagesService,
|
private readonly _viewedPagesService: ViewedPagesService,
|
||||||
|
private readonly _viewModeService: ViewModeService,
|
||||||
private readonly _userPreferenceService: UserPreferenceService,
|
private readonly _userPreferenceService: UserPreferenceService,
|
||||||
private readonly _dictionariesMapService: DictionariesMapService,
|
private readonly _dictionariesMapService: DictionariesMapService,
|
||||||
private readonly _permissionsService: PermissionsService,
|
private readonly _permissionsService: PermissionsService,
|
||||||
private readonly _redactionLogService: RedactionLogService,
|
private readonly _redactionLogService: RedactionLogService,
|
||||||
private readonly _textHighlightsService: TextHighlightService,
|
private readonly _textHighlightsService: TextHighlightService,
|
||||||
private readonly _toaster: Toaster,
|
private readonly _toaster: Toaster,
|
||||||
) {}
|
) {
|
||||||
|
this.annotations$ = this.#annotations$;
|
||||||
set textHighlights(textHighlightResponse: TextHighlightResponse) {
|
this.visibleAnnotations$ = this._viewModeService.viewMode$.pipe(
|
||||||
const highlights = [];
|
switchMap(viewMode =>
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
iif(
|
||||||
for (const color of Object.keys(textHighlightResponse.redactionPerColor)) {
|
() => viewMode === ViewModes.TEXT_HIGHLIGHTS,
|
||||||
for (const entry of textHighlightResponse.redactionPerColor[color]) {
|
this.#textHighlights$,
|
||||||
const annotation = AnnotationWrapper.fromHighlight(color, entry);
|
this.annotations$.pipe(map(annotations => this.getVisibleAnnotations(annotations, viewMode))),
|
||||||
highlights.push(annotation);
|
),
|
||||||
}
|
),
|
||||||
}
|
log('visible annotations: '),
|
||||||
this.textHighlightAnnotations = highlights;
|
shareLast(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setRedactionLog(redactionLog: IRedactionLog) {
|
get visibleAnnotations() {
|
||||||
|
return firstValueFrom(this.visibleAnnotations$);
|
||||||
|
}
|
||||||
|
|
||||||
|
get annotations() {
|
||||||
|
return firstValueFrom(this.annotations$);
|
||||||
|
}
|
||||||
|
|
||||||
|
get textHighlights() {
|
||||||
|
return this.#textHighlights$.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get #annotations$() {
|
||||||
|
return this.#redactionLog$.pipe(
|
||||||
|
withLatestFrom(this._state.file$),
|
||||||
|
map(([redactionLog, file]) => this.#buildAnnotations(redactionLog, file)),
|
||||||
|
map(annotations =>
|
||||||
|
this._userPreferenceService.areDevFeaturesEnabled ? annotations : annotations.filter(a => !a.isFalsePositive),
|
||||||
|
),
|
||||||
|
shareLast(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setRedactionLog(redactionLog: IRedactionLog) {
|
||||||
this.#redactionLog = redactionLog;
|
this.#redactionLog = redactionLog;
|
||||||
const hash = require('object-hash');
|
const hash = require('object-hash');
|
||||||
const newRedactionLogHash = hash(redactionLog.redactionLogEntry ?? []);
|
const newRedactionLogHash = hash(redactionLog.redactionLogEntry ?? []);
|
||||||
@ -73,7 +107,6 @@ export class FileDataService {
|
|||||||
this.shouldUpdateAnnotations = true;
|
this.shouldUpdateAnnotations = true;
|
||||||
this.#redactionLogHash = newRedactionLogHash;
|
this.#redactionLogHash = newRedactionLogHash;
|
||||||
this.missingTypes.clear();
|
this.missingTypes.clear();
|
||||||
await this.#buildAllAnnotations();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async load(file: File) {
|
async load(file: File) {
|
||||||
@ -90,8 +123,11 @@ export class FileDataService {
|
|||||||
|
|
||||||
async loadTextHighlights() {
|
async loadTextHighlights() {
|
||||||
const { dossierId, fileId } = this._state;
|
const { dossierId, fileId } = this._state;
|
||||||
const highlights = this._textHighlightsService.getTextHighlights(dossierId, fileId).pipe(catchError(() => of({})));
|
const redactionPerColor = await firstValueFrom(this._textHighlightsService.getTextHighlights(dossierId, fileId));
|
||||||
this.textHighlights = await firstValueFrom(highlights);
|
const textHighlights = this.#buildTextHighlights(redactionPerColor);
|
||||||
|
this.#textHighlights$.next(textHighlights);
|
||||||
|
|
||||||
|
return textHighlights;
|
||||||
}
|
}
|
||||||
|
|
||||||
getViewedPagesFor(file: File) {
|
getViewedPagesFor(file: File) {
|
||||||
@ -105,60 +141,61 @@ export class FileDataService {
|
|||||||
const redactionLog$ = this._redactionLogService.getRedactionLog(this._state.dossierId, this._state.fileId).pipe(
|
const redactionLog$ = this._redactionLogService.getRedactionLog(this._state.dossierId, this._state.fileId).pipe(
|
||||||
tap(redactionLog => redactionLog.redactionLogEntry.sort((a, b) => a.positions[0].page - b.positions[0].page)),
|
tap(redactionLog => redactionLog.redactionLogEntry.sort((a, b) => a.positions[0].page - b.positions[0].page)),
|
||||||
catchError(() => of({})),
|
catchError(() => of({})),
|
||||||
|
tap(redactionLog => this.#redactionLog$.next(redactionLog)),
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.setRedactionLog(await firstValueFrom(redactionLog$));
|
this.setRedactionLog(await firstValueFrom(redactionLog$));
|
||||||
}
|
}
|
||||||
|
|
||||||
getVisibleAnnotations(viewMode: ViewMode) {
|
getVisibleAnnotations(annotations: AnnotationWrapper[], viewMode: ViewMode) {
|
||||||
if (viewMode === 'TEXT_HIGHLIGHTS') {
|
return annotations.filter(annotation => {
|
||||||
return this.textHighlightAnnotations;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.allAnnotations.filter(annotation => {
|
|
||||||
if (viewMode === 'STANDARD') {
|
if (viewMode === 'STANDARD') {
|
||||||
return !annotation.isChangeLogRemoved;
|
return !annotation.isChangeLogRemoved;
|
||||||
} else if (viewMode === 'DELTA') {
|
}
|
||||||
|
|
||||||
|
if (viewMode === 'DELTA') {
|
||||||
return annotation.isChangeLogEntry;
|
return annotation.isChangeLogEntry;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return annotation.previewAnnotation;
|
return annotation.previewAnnotation;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async #buildAllAnnotations() {
|
updateHiddenAnnotations(viewerAnnotations: Annotation[], hidden: boolean) {
|
||||||
const file = await this._state.file;
|
const annotationId = viewerAnnotations[0].Id;
|
||||||
const entries: RedactionLogEntry[] = this.#convertData(file);
|
if (hidden) {
|
||||||
|
this.hiddenAnnotations.add(annotationId);
|
||||||
const previousAnnotations = [...this.allAnnotations];
|
} else {
|
||||||
this.allAnnotations = entries
|
this.hiddenAnnotations.delete(annotationId);
|
||||||
.map(entry => AnnotationWrapper.fromData(entry))
|
}
|
||||||
.filter(ann => ann.manual || !file.excludedPages.includes(ann.pageNumber));
|
|
||||||
|
|
||||||
if (!this._userPreferenceService.areDevFeaturesEnabled) {
|
|
||||||
this.allAnnotations = this.allAnnotations.filter(annotation => !annotation.isFalsePositive);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._setHiddenPropertyToNewAnnotations(this.allAnnotations, previousAnnotations);
|
isHidden(annotationId: string) {
|
||||||
|
return this.hiddenAnnotations.has(annotationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _setHiddenPropertyToNewAnnotations(newAnnotations: AnnotationWrapper[], oldAnnotations: AnnotationWrapper[]) {
|
#buildTextHighlights(redactionPerColor: Record<string, ImportedRedaction[]>): AnnotationWrapper[] {
|
||||||
newAnnotations.forEach(newAnnotation => {
|
if (!redactionPerColor) {
|
||||||
const oldAnnotation = oldAnnotations.find(a => a.annotationId === newAnnotation.annotationId);
|
return [];
|
||||||
if (oldAnnotation) {
|
|
||||||
newAnnotation.hidden = oldAnnotation.hidden;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#convertData(file: File): RedactionLogEntry[] {
|
const highlights = Object.entries(redactionPerColor);
|
||||||
|
return highlights.flatMap(([color, entries]) => entries.map(entry => AnnotationWrapper.fromHighlight(color, entry)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#buildAnnotations(redactionLog: IRedactionLog, file: File) {
|
||||||
|
const entries: RedactionLogEntry[] = this.#convertData(redactionLog, file);
|
||||||
|
const annotations = entries.map(entry => AnnotationWrapper.fromData(entry));
|
||||||
|
|
||||||
|
return annotations.filter(ann => ann.manual || !file.excludedPages.includes(ann.pageNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
#convertData(redactionLog: IRedactionLog, file: File): RedactionLogEntry[] {
|
||||||
let result: RedactionLogEntry[] = [];
|
let result: RedactionLogEntry[] = [];
|
||||||
|
|
||||||
const reasonAnnotationIds: { [key: string]: RedactionLogEntry[] } = {};
|
const reasonAnnotationIds: { [key: string]: RedactionLogEntry[] } = {};
|
||||||
const _dictionaryData = this._dictionariesMapService.get(this._state.dossierTemplateId);
|
const _dictionaryData = this._dictionariesMapService.get(this._state.dossierTemplateId);
|
||||||
this.#redactionLog.redactionLogEntry?.forEach(redactionLogEntry => {
|
|
||||||
// copy the redactionLog Entry
|
|
||||||
|
|
||||||
|
redactionLog.redactionLogEntry?.forEach(redactionLogEntry => {
|
||||||
const changeLogValues = this.#getChangeLogValues(redactionLogEntry, file);
|
const changeLogValues = this.#getChangeLogValues(redactionLogEntry, file);
|
||||||
const dictionaryData = _dictionaryData.find(dict => dict.type === redactionLogEntry.type);
|
const dictionaryData = _dictionaryData.find(dict => dict.type === redactionLogEntry.type);
|
||||||
if (!dictionaryData) {
|
if (!dictionaryData) {
|
||||||
@ -171,7 +208,7 @@ export class FileDataService {
|
|||||||
changeLogValues.changeLogType,
|
changeLogValues.changeLogType,
|
||||||
changeLogValues.isChangeLogEntry,
|
changeLogValues.isChangeLogEntry,
|
||||||
changeLogValues.hidden,
|
changeLogValues.hidden,
|
||||||
this.#redactionLog.legalBasis,
|
redactionLog.legalBasis,
|
||||||
!!dictionaryData?.hint,
|
!!dictionaryData?.hint,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -229,7 +266,7 @@ export class FileDataService {
|
|||||||
|
|
||||||
// page has been seen -> let's see if it's a change
|
// page has been seen -> let's see if it's a change
|
||||||
if (viewedPage) {
|
if (viewedPage) {
|
||||||
const viewTime = moment(viewedPage.viewedTime).valueOf() - FileDataService.DELTA_VIEW_TIME;
|
const viewTime = moment(viewedPage.viewedTime).valueOf() - DELTA_VIEW_TIME;
|
||||||
// these are all unseen changes
|
// these are all unseen changes
|
||||||
const relevantChanges = viableChanges.filter(change => moment(change.dateTime).valueOf() > viewTime);
|
const relevantChanges = viableChanges.filter(change => moment(change.dateTime).valueOf() > viewTime);
|
||||||
// at least one unseen change
|
// at least one unseen change
|
||||||
|
|||||||
@ -1 +1,8 @@
|
|||||||
export type ViewMode = 'STANDARD' | 'DELTA' | 'REDACTED' | 'TEXT_HIGHLIGHTS';
|
export const ViewModes = {
|
||||||
|
STANDARD: 'STANDARD',
|
||||||
|
DELTA: 'DELTA',
|
||||||
|
REDACTED: 'REDACTED',
|
||||||
|
TEXT_HIGHLIGHTS: 'TEXT_HIGHLIGHTS',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type ViewMode = keyof typeof ViewModes;
|
||||||
|
|||||||
@ -5,5 +5,5 @@ export interface TextHighlightResponse {
|
|||||||
dossierId?: string;
|
dossierId?: string;
|
||||||
fileId?: string;
|
fileId?: string;
|
||||||
operation?: TextHighlightOperation;
|
operation?: TextHighlightOperation;
|
||||||
redactionPerColor?: { [key: string]: ImportedRedaction[] };
|
redactionPerColor?: Record<string, ImportedRedaction[]>;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user