fix RED-3519: show imported redactions after converting highlights

This commit is contained in:
Dan Percic 2022-03-22 18:36:52 +02:00
parent 3a19bf7b07
commit b016254bac
7 changed files with 82 additions and 83 deletions

View File

@ -111,7 +111,7 @@ const components = [AppComponent, AuthErrorComponent, NotificationsComponent, Sp
useValue: {
level: environment.production ? NgxLoggerLevel.ERROR : NgxLoggerLevel.DEBUG,
enableSourceMaps: true,
timestampFormat: 'hh:mm:ss SSS',
timestampFormat: 'mm:ss:SSS',
disableFileDetails: true,
features: {
ANNOTATIONS: {
@ -119,6 +119,9 @@ const components = [AppComponent, AuthErrorComponent, NotificationsComponent, Sp
enabled: true,
level: NgxLoggerLevel.DEBUG,
},
FILTERS: {
enabled: true,
},
},
} as ILoggerConfig,
},

View File

@ -24,7 +24,6 @@ export class AnnotationPermissions {
const summedPermissions: AnnotationPermissions = new AnnotationPermissions();
for (const annotation of annotations) {
console.log(annotation.pending);
const permissions: AnnotationPermissions = new AnnotationPermissions();
permissions.canUndo = (!isApprover && annotation.isSuggestion) || annotation.pending;

View File

@ -35,17 +35,17 @@ import { toPosition } from '../../../dossier/utils/pdf-calculation.utils';
import { ViewModeService } from '../../services/view-mode.service';
import { MultiSelectService } from '../../services/multi-select.service';
import { FilePreviewStateService } from '../../services/file-preview-state.service';
import { tap, withLatestFrom } from 'rxjs/operators';
import { map, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import { FileManagementService } from '@services/entity-services/file-management.service';
import { PageRotationService } from '../../services/page-rotation.service';
import { ALLOWED_KEYBOARD_SHORTCUTS, HeaderElements, TextPopups } from '../../shared/constants';
import { FilePreviewDialogService } from '../../services/file-preview-dialog.service';
import { loadCompareDocumentWrapper } from '../../../dossier/utils/compare-mode.utils';
import { fromEvent } from 'rxjs';
import { from, fromEvent } from 'rxjs';
import { FileDataService } from '../../services/file-data.service';
import Tools = Core.Tools;
import TextTool = Tools.TextTool;
import Annotation = Core.Annotations.Annotation;
import { FileDataService } from '../../services/file-data.service';
function getDivider(hiddenOn?: readonly ('desktop' | 'mobile' | 'tablet')[]) {
return {
@ -117,8 +117,8 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
this.addActiveScreenSubscription = this.stateService.blob$
.pipe(
switchMap(blob => from(this.pdf.lockDocument()).pipe(map(() => blob))),
withLatestFrom(this.stateService.file$),
tap(() => (this.pdf.ready = false)),
tap(([blob, file]) => this._loadDocument(blob, file)),
)
.subscribe();
@ -155,7 +155,6 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
const loadCompareDocument = async () => {
this._loadingService.start();
this.pdf.ready = false;
const mergedDocument = await pdfNet.PDFDoc.create();
const file = await this.stateService.file;
await loadCompareDocumentWrapper(
@ -690,16 +689,14 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
return entry;
}
private async _loadDocument(blob: Blob, file: File) {
const document = await this.instance.Core.documentViewer.getDocument()?.getPDFDoc();
await document?.lock();
private _loadDocument(blob: Blob, file: File) {
this.instance.UI.loadDocument(blob, { filename: file?.filename ?? 'document.pdf' });
this._pageRotationService.clearRotationsHideActions();
}
private _setReadyAndInitialState(): void {
private _setReadyAndInitialState() {
this._ngZone.run(() => {
this.pdf.documentLoaded$.next(true);
this.pdf.emitDocumentLoaded();
const routePageNumber: number = this._activatedRoute.snapshot.queryParams.page;
this.pageChanged.emit(routePageNumber || 1);
this._setInitialDisplayMode();

View File

@ -9,7 +9,6 @@ import {
ErrorService,
FilterService,
LoadingService,
log,
NestedFilter,
OnAttach,
OnDetach,
@ -143,11 +142,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
async updateViewMode(): Promise<void> {
if (!this.pdf.ready) {
return;
}
this.pdf.deleteAnnotations(this._fileDataService.textHighlights.map(a => a.id));
this._logger.debug(`[PDF] Update ${this._viewModeService.viewMode} view mode`);
const annotations = this.pdf.getAnnotations(a => a.getCustomData('redact-manager'));
const redactions = annotations.filter(a => a.getCustomData('redaction'));
@ -233,14 +228,8 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
this.displayPdfViewer = true;
}
async rebuildFilters(deletePreviousAnnotations = false) {
async rebuildFilters() {
const startTime = new Date().getTime();
if (deletePreviousAnnotations) {
this.pdf.deleteAnnotations();
console.log(`[REDACTION] Delete previous annotations time: ${new Date().getTime() - startTime} ms`);
}
const processStartTime = new Date().getTime();
const visibleAnnotations = await this._fileDataService.visibleAnnotations;
const annotationFilters = this._annotationProcessingService.getAnnotationFilter(visibleAnnotations);
@ -260,8 +249,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
),
});
this._logger.debug(`[REDACTION] Process time: ${new Date().getTime() - processStartTime} ms`);
this._logger.debug(`[REDACTION] Filter rebuild time: ${new Date().getTime() - startTime}`);
this._logger.debug(`[FILTERS] Rebuild time: ${new Date().getTime() - startTime} ms`);
}
async handleAnnotationSelected(annotationIds: string[]) {
@ -370,8 +358,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
viewerReady() {
this.ready = true;
this.pdf.ready = true;
this._setExcludedPageStyles();
this.pdf.documentViewer.addEventListener('pageComplete', () => {
@ -426,7 +412,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
let start;
return combineLatest([documentLoaded$, this._fileDataService.annotations$]).pipe(
debounceTime(300),
log(),
tap(() => (start = new Date().getTime())),
map(([, annotations]) => annotations),
startWith({} as Record<string, AnnotationWrapper>),
@ -451,7 +436,10 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
drawChangedAnnotations(oldAnnotations: Record<string, AnnotationWrapper>, newAnnotations: Record<string, AnnotationWrapper>) {
let annotationsToDraw: readonly AnnotationWrapper[];
if (this.pdf.hasAnnotations) {
const ann = this.pdf.annotationManager.getAnnotationsList().map(a => oldAnnotations[a.Id]);
const hasAnnotations = ann.filter(a => !!a).length > 0;
if (hasAnnotations) {
annotationsToDraw = this.#getAnnotationsToDraw(newAnnotations, oldAnnotations);
} else {
annotationsToDraw = Object.values(newAnnotations);
@ -511,18 +499,18 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
private async _stampPDF() {
const pdfDoc = await this.pdf.documentViewer.getDocument().getPDFDoc();
const file = await this.stateService.file;
const allPages = [...Array(file.numberOfPages).keys()].map(page => page + 1);
if (!pdfDoc || !this.pdf.ready) {
const pdfDoc = await this.pdf.documentViewer.getDocument()?.getPDFDoc();
if (!pdfDoc) {
return;
}
const file = await this.stateService.file;
const allPages = [...Array(file.numberOfPages).keys()].map(page => page + 1);
try {
await clearStamps(pdfDoc, this.pdf.PDFNet, allPages);
} catch (e) {
this._logger.debug('Error clearing stamps: ', e);
this._logger.error('Error clearing stamps: ', e);
return;
}
@ -616,10 +604,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
private async _cleanupAndRedrawAnnotations(newAnnotations: readonly AnnotationWrapper[]) {
if (!this.pdf.ready) {
return;
}
const currentFilters = this._filterService.getGroup('primaryFilters')?.filters || [];
await this.rebuildFilters();

View File

@ -37,10 +37,6 @@ export class AnnotationDrawService {
) {}
drawAnnotations(annotationWrappers: readonly AnnotationWrapper[]) {
if (!this._pdf.instance || !this._pdf.ready) {
return;
}
const licenceKey = environment.licenseKey ? atob(environment.licenseKey) : null;
return this._pdf.PDFNet.runWithCleanup(() => this._drawAnnotations(annotationWrappers), licenceKey);
}
@ -89,13 +85,6 @@ export class AnnotationDrawService {
}
private async _drawAnnotations(annotationWrappers: readonly AnnotationWrapper[]) {
const document = await this._pdf.documentViewer.getDocument()?.getPDFDoc();
if (!this._pdf.ready || !document) {
return;
}
await document.lock();
const annotations = annotationWrappers.map(annotation => this._computeAnnotation(annotation)).filter(a => !!a);
this._pdf.annotationManager.addAnnotations(annotations, { imported: true });
await this._pdf.annotationManager.drawAnnotationsFromList(annotations);

View File

@ -21,7 +21,7 @@ import { DictionariesMapService } from '../../../services/entity-services/dictio
import { map, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import { PermissionsService } from '../../../services/permissions.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { log, shareDistinctLast, shareLast, Toaster } from '../../../../../../../libs/common-ui/src';
import { shareDistinctLast, shareLast, Toaster } from '../../../../../../../libs/common-ui/src';
import { RedactionLogService } from '../../dossier/services/redaction-log.service';
import { TextHighlightService } from '../../dossier/services/text-highlight.service';
import { ViewModeService } from './view-mode.service';
@ -66,7 +66,6 @@ export class FileDataService {
this.annotations$.pipe(map(annotations => this.getVisibleAnnotations(Object.values(annotations), viewMode))),
),
),
log('Visible annotations: '),
shareDistinctLast(),
);
}

View File

@ -7,20 +7,37 @@ import { Inject, Injectable } from '@angular/core';
import { BASE_HREF } from '../../../tokens';
import { environment } from '@environments/environment';
import { DISABLED_HOTKEYS } from '../shared/constants';
import { Subject } from 'rxjs';
import { Observable, Subject } from 'rxjs';
import { NGXLogger } from 'ngx-logger';
import { tap } from 'rxjs/operators';
import { shareLast } from '../../../../../../../libs/common-ui/src';
import Annotation = Core.Annotations.Annotation;
import DocumentViewer = Core.DocumentViewer;
import AnnotationManager = Core.AnnotationManager;
@Injectable()
export class PdfViewer {
ready = false;
instance: WebViewerInstance;
documentViewer: DocumentViewer;
annotationManager: AnnotationManager;
readonly documentLoaded$ = new Subject();
instance?: WebViewerInstance;
constructor(@Inject(BASE_HREF) private readonly _baseHref: string, readonly viewModeService: ViewModeService) {}
readonly documentLoaded$: Observable<boolean>;
readonly #documentLoaded$ = new Subject<boolean>();
constructor(
@Inject(BASE_HREF) private readonly _baseHref: string,
private readonly _viewModeService: ViewModeService,
private readonly _logger: NGXLogger,
) {
this.documentLoaded$ = this.#documentLoaded$.asObservable().pipe(
tap(() => this._logger.debug('[PDF] Loaded')),
shareLast(),
);
}
get documentViewer() {
return this.instance?.Core.documentViewer;
}
get annotationManager() {
return this.instance?.Core.annotationManager;
}
get UI() {
return this.instance.UI;
@ -39,19 +56,15 @@ export class PdfViewer {
}
get paginationOffset() {
return this.viewModeService.isCompare ? 2 : 1;
return this._viewModeService.isCompare ? 2 : 1;
}
get currentPage() {
return this.viewModeService.isCompare ? Math.ceil(this._currentInternalPage / 2) : this._currentInternalPage;
return this._viewModeService.isCompare ? Math.ceil(this._currentInternalPage / 2) : this._currentInternalPage;
}
get totalPages() {
if (!this.ready) {
return null;
}
return this.viewModeService.isCompare ? Math.ceil(this._totalInternalPages / 2) : this._totalInternalPages;
return this._viewModeService.isCompare ? Math.ceil(this._totalInternalPages / 2) : this._totalInternalPages;
}
private get _currentInternalPage() {
@ -67,6 +80,28 @@ export class PdfViewer {
}
}
async lockDocument() {
const document = await this.documentViewer.getDocument()?.getPDFDoc();
if (!document) {
return false;
}
await document.lock();
this._logger.debug('[PDF] Locked');
return true;
}
async unlockDocument() {
const document = await this.documentViewer.getDocument()?.getPDFDoc();
if (!document) {
return false;
}
await document.unlock();
this._logger.debug('[PDF] Unlocked');
return true;
}
hideAnnotations(annotations: Annotation[]): void {
this.annotationManager.hideAnnotations(annotations);
}
@ -88,6 +123,11 @@ export class PdfViewer {
return [];
}
emitDocumentLoaded() {
this.deleteAnnotations();
this.#documentLoaded$.next(true);
}
async loadViewer(htmlElement: HTMLElement) {
this.instance = await WebViewer(
{
@ -100,9 +140,6 @@ export class PdfViewer {
htmlElement,
);
this.documentViewer = this.instance.Core.documentViewer;
this.annotationManager = this.instance.Core.annotationManager;
return this.instance;
}
@ -138,11 +175,7 @@ export class PdfViewer {
}
deselectAllAnnotations() {
if (!this.ready) {
return;
}
this.annotationManager.deselectAllAnnotations();
this.annotationManager?.deselectAllAnnotations();
}
selectAnnotations(annotations: AnnotationWrapper[], multiSelectActive: boolean = false) {
@ -167,10 +200,6 @@ export class PdfViewer {
}
deleteAnnotations(annotationsIds?: readonly string[]) {
if (!this.ready) {
return;
}
let annotations: Annotation[];
if (!annotationsIds) {
annotations = this.getAnnotations();
@ -180,7 +209,6 @@ export class PdfViewer {
try {
this.annotationManager.deleteAnnotations(annotations, {
imported: true,
force: true,
});
} catch (error) {