From b016254baca1aa404b0bb0c4fccc4e9fb6096226 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Tue, 22 Mar 2022 18:36:52 +0200 Subject: [PATCH] fix RED-3519: show imported redactions after converting highlights --- apps/red-ui/src/app/app.module.ts | 5 +- .../app/models/file/annotation.permissions.ts | 1 - .../pdf-viewer/pdf-viewer.component.ts | 17 ++-- .../file-preview-screen.component.ts | 42 +++------ .../services/annotation-draw.service.ts | 11 --- .../services/file-data.service.ts | 3 +- .../services/pdf-viewer.service.ts | 86 ++++++++++++------- 7 files changed, 82 insertions(+), 83 deletions(-) diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index aeb4391d0..7d728eaa8 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -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, }, diff --git a/apps/red-ui/src/app/models/file/annotation.permissions.ts b/apps/red-ui/src/app/models/file/annotation.permissions.ts index 21643b353..751ec622a 100644 --- a/apps/red-ui/src/app/models/file/annotation.permissions.ts +++ b/apps/red-ui/src/app/models/file/annotation.permissions.ts @@ -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; diff --git a/apps/red-ui/src/app/modules/file-preview/components/pdf-viewer/pdf-viewer.component.ts b/apps/red-ui/src/app/modules/file-preview/components/pdf-viewer/pdf-viewer.component.ts index d0f5c8d5f..757c15cdb 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/pdf-viewer/pdf-viewer.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/pdf-viewer/pdf-viewer.component.ts @@ -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(); diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts index 1c6b41821..0b17ec4d7 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts @@ -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 { - 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), @@ -451,7 +436,10 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni drawChangedAnnotations(oldAnnotations: Record, newAnnotations: Record) { 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(); diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotation-draw.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotation-draw.service.ts index a8bb428e3..37a7dc010 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/annotation-draw.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/annotation-draw.service.ts @@ -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); diff --git a/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts b/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts index bbf5382e5..224c950b4 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts @@ -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(), ); } diff --git a/apps/red-ui/src/app/modules/file-preview/services/pdf-viewer.service.ts b/apps/red-ui/src/app/modules/file-preview/services/pdf-viewer.service.ts index db545fa8c..f961db56e 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/pdf-viewer.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/pdf-viewer.service.ts @@ -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; + readonly #documentLoaded$ = new Subject(); + + 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) {