From a93527e963d601190a5d32eaf148742000b7b7a5 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 7 Jul 2023 19:23:25 +0300 Subject: [PATCH] RED-6892 deselect text when redaction added --- apps/red-ui/src/app/app.module.ts | 4 +- .../file-preview-screen.component.ts | 57 +++++++++---------- .../services/file-preview-state.service.ts | 35 +++++------- .../services/pdf-proxy.service.ts | 4 +- .../services/annotation-manager.service.ts | 34 ++++++----- .../dossiers/dossier-changes.service.ts | 2 +- .../app/services/dossiers/dossiers.service.ts | 1 - apps/red-ui/src/styles.scss | 6 +- 8 files changed, 73 insertions(+), 70 deletions(-) diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index fc52f4819..944d621cd 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -141,10 +141,10 @@ export const appModuleFactory = (config: AppConfig) => { enabled: true, }, FILE: { - enabled: false, + enabled: true, }, CHANGES: { - enabled: false, + enabled: true, }, STATS: { enabled: false, 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 f5dce87ef..f4cb8f203 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 @@ -308,7 +308,7 @@ export class FilePreviewScreenComponent this._loadingService.start(); this.userPreferenceService.saveLastOpenedFileForDossier(this.dossierId, this.fileId).then(); - this._subscribeToFileUpdates(); + this.#subscribeToFileUpdates(); if (file?.analysisRequired && !file.excludedFromAutomaticAnalysis) { await this._reanalysisService.reanalyzeFilesForDossier([file], this.dossierId, { force: true }); @@ -354,34 +354,33 @@ export class FilePreviewScreenComponent async openRedactTextDialog(manualRedactionEntryWrapper: ManualRedactionEntryWrapper) { const file = this.state.file(); const dossierTemplate = this._dossierTemplatesService.find(this.state.dossierTemplateId); - const result = await this._iqserDialog - .openDefault(RedactTextDialogComponent, { - data: { - manualRedactionEntryWrapper, - dossierId: this.dossierId, - file, - applyToAllDossiers: dossierTemplate.applyDictionaryUpdatesToAllDossiersByDefault, - }, - }) - .result(); + const ref = this._iqserDialog.openDefault(RedactTextDialogComponent, { + data: { + manualRedactionEntryWrapper, + dossierId: this.dossierId, + file, + applyToAllDossiers: dossierTemplate.applyDictionaryUpdatesToAllDossiersByDefault, + }, + }); - if (result) { - const add$ = this._manualRedactionService.addAnnotation( - [result.redaction], - this.dossierId, - this.fileId, - result.dictionary?.label, - ); - - if (result.applyToAllDossiers !== null) { - const { ...body } = dossierTemplate; - body.applyDictionaryUpdatesToAllDossiersByDefault = result.applyToAllDossiers; - await this._dossierTemplatesService.createOrUpdate(body); - } - - const addAndReload$ = add$.pipe(switchMap(() => this._filesService.reload(this.dossierId, file))); - return firstValueFrom(addAndReload$.pipe(catchError(() => of(undefined)))); + const result = await ref.result(); + if (!result) { + return; } + + const add$ = this._manualRedactionService.addAnnotation([result.redaction], this.dossierId, this.fileId, result.dictionary?.label); + + if (result.applyToAllDossiers !== null) { + const { ...body } = dossierTemplate; + body.applyDictionaryUpdatesToAllDossiersByDefault = result.applyToAllDossiers; + await this._dossierTemplatesService.createOrUpdate(body); + } + + const addAndReload$ = add$.pipe( + tap(() => this._documentViewer.clearSelection()), + switchMap(() => this._filesService.reload(this.dossierId, file)), + ); + return firstValueFrom(addAndReload$.pipe(catchError(() => of(undefined)))); } toggleFullScreen() { @@ -610,7 +609,7 @@ export class FilePreviewScreenComponent }, 100); } - private _subscribeToFileUpdates(): void { + #subscribeToFileUpdates(): void { this.addActiveScreenSubscription = this.loadAnnotations().subscribe(); this.addActiveScreenSubscription = this._dossiersService @@ -642,7 +641,7 @@ export class FilePreviewScreenComponent }); this.addActiveScreenSubscription = this.pdfProxyService.redactTextRequested$.subscribe($event => { - this.openRedactTextDialog($event); + this.openRedactTextDialog($event).then(); }); this.addActiveScreenSubscription = this.pdfProxyService.pageChanged$.subscribe(page => diff --git a/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts b/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts index 7acc03014..1d4c7daf0 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts @@ -13,9 +13,10 @@ import { HttpEvent, HttpEventType, HttpProgressEvent, HttpResponse } from '@angu import { TranslateService } from '@ngx-translate/core'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import { DossierDictionariesMapService } from '@services/entity-services/dossier-dictionaries-map.service'; -import { toSignal } from '@angular/core/rxjs-interop'; +import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; import { ViewModeService } from './view-mode.service'; import { getParam } from '@iqser/common-ui/lib/utils'; +import { NGXLogger } from 'ngx-logger'; const ONE_MEGABYTE = 1024 * 1024; @@ -33,7 +34,6 @@ function isDownload(event: HttpEvent): event is HttpProgressEvent { @Injectable() export class FilePreviewStateService { readonly #reloadBlob$ = new Subject(); - readonly #dossierFileChange: Signal; readonly file$: Observable; readonly file: Signal; readonly dossier: Signal; @@ -45,12 +45,6 @@ export class FilePreviewStateService { readonly dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); readonly fileId = getParam(FILE_ID); - // readonly #routeKey = getReusableRouteKey(inject(ActivatedRoute).snapshot); - // readonly isAttached = inject(CustomRouteReuseStrategy).attached$.pipe( - // map(route => getReusableRouteKey(route) === this.#routeKey), - // startWith(true), - // ); - constructor( private readonly _permissionsService: PermissionsService, private readonly _filesService: FilesService, @@ -60,28 +54,27 @@ export class FilePreviewStateService { private readonly _translateService: TranslateService, private readonly _loadingService: LoadingService, private readonly _viewModeService: ViewModeService, + private readonly _logger: NGXLogger, ) { this.dossier = toSignal(dossiersServiceResolver().getEntityChanged$(this.dossierId)); this.file$ = inject(FilesMapService).watch$(this.dossierId, this.fileId); this.file = toSignal(this.file$); - // this.file$ = combineLatest([this.isAttached, file$]).pipe( - // filter(([isAttached]) => isAttached), - // map(([, file]) => file), - // log('file$'), - // shareDistinctLast(), - // ); - this.isWritable = computed(() => this._permissionsService.canPerformAnnotationActions(this.file(), this.dossier())); + this.isWritable = computed(() => { + const isWritable = this._permissionsService.canPerformAnnotationActions(this.file(), this.dossier()); + this._logger.info('[FILE] Is writeable:', isWritable); + return isWritable; + }); this.isReadonly = computed(() => !this.isWritable()); this.blob$ = this.#blob$; this.dossierDictionary = toSignal(inject(DossierDictionariesMapService).watch$(this.dossierId, 'dossier_redaction')); - this.#dossierFileChange = toSignal(this.#dossierFilesChange$); - effect(() => { - if (this.#dossierFileChange()) { - this._filesService.loadAll(this.dossierId); - } - }); + this.#dossierFilesChange$ + .pipe( + switchMap(() => this._filesService.loadAll(this.dossierId)), + takeUntilDestroyed(), + ) + .subscribe(); effect( () => { if (this._viewModeService.isEarmarks() && !this.file().hasHighlights) { diff --git a/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts b/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts index 6f0792a4b..b2058dd3e 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts @@ -101,8 +101,8 @@ export class PdfProxyService { get #annotationSelected$() { return this._annotationManager.annotationSelected$.pipe( - map(value => this._ngZone.run(() => this.#processSelectedAnnotations(...value))), - tap(annotations => this._ngZone.run(() => this.handleAnnotationSelected(annotations))), + map(value => this.#processSelectedAnnotations(...value)), + tap(annotations => this.handleAnnotationSelected(annotations)), ); } diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-manager.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-manager.service.ts index 3a02cb459..ad79534b7 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-manager.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-manager.service.ts @@ -1,13 +1,13 @@ -import { Injectable, signal } from '@angular/core'; +import { inject, Injectable, signal } from '@angular/core'; import { Core } from '@pdftron/webviewer'; import type { List } from '@iqser/common-ui/lib/utils'; import { AnnotationPredicate, DeleteAnnotationsOptions } from '../utils/types'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; -import { fromEvent, Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; +import { Subject } from 'rxjs'; import { asList, getId, isStringOrWrapper } from '../utils/functions'; import { getLast } from '@utils/functions'; import { AnnotationToolNames } from '../utils/constants'; +import { NGXLogger } from 'ngx-logger'; import AnnotationManager = Core.AnnotationManager; import Annotation = Core.Annotations.Annotation; @@ -15,7 +15,9 @@ import Annotation = Core.Annotations.Annotation; export class REDAnnotationManager { readonly #hidden = signal(new Set()); #manager: AnnotationManager; - annotationSelected$: Observable<[Annotation[], string]>; + readonly #logger = inject(NGXLogger); + readonly #annotationSelected$ = new Subject<[Annotation[], string]>(); + readonly annotationSelected$ = this.#annotationSelected$.asObservable(); resizingAnnotationId?: string = undefined; readonly hidden = this.#hidden.asReadonly(); @@ -27,11 +29,6 @@ export class REDAnnotationManager { return this.#get(); } - get #annotationSelected$() { - const onSelect$ = fromEvent<[Annotation[], string]>(this.#manager, 'annotationSelected'); - return onSelect$.pipe(tap(value => console.log('Annotation selected: ', value))); - } - addToHidden(value: string) { this.#hidden.mutate(set => set.add(value)); } @@ -42,7 +39,7 @@ export class REDAnnotationManager { init(annotationManager: AnnotationManager) { this.#manager = annotationManager; - this.annotationSelected$ = this.#annotationSelected$; + this.#listenForAnnotationSelected(); this.#autoSelectRectangleAfterCreation(); } @@ -60,8 +57,11 @@ export class REDAnnotationManager { } get(annotation: AnnotationWrapper | string): Annotation; + get(annotations: List | List): Annotation[]; + get(predicate?: (value: Annotation) => boolean): Annotation[]; + get(argument?: AnnotationPredicate | List | List | AnnotationWrapper | string): Annotation | Annotation[] { if (isStringOrWrapper(argument)) { return this.#getById(argument); @@ -71,8 +71,8 @@ export class REDAnnotationManager { return isList ? this.#getByIds(argument) : this.#get(argument); } - deselect(annotation: string | AnnotationWrapper); - deselect(annotations?: List | List); + deselect(annotation: string | AnnotationWrapper): void; + deselect(annotations?: List | List): void; deselect(argument?: string | AnnotationWrapper | List | List) { if (!argument) { return this.#manager.deselectAllAnnotations(); @@ -121,12 +121,20 @@ export class REDAnnotationManager { this.show(hidden); } + #listenForAnnotationSelected() { + this.#manager.addEventListener('annotationSelected', (annotations: Annotation[], action: string) => { + this.#logger.info('[PDF] Annotation selected: ', annotations, action); + this.#annotationSelected$.next([annotations, action]); + }); + } + #getById(annotation: AnnotationWrapper | string) { return this.#manager.getAnnotationById(getId(annotation)); } #autoSelectRectangleAfterCreation() { - this.#manager.addEventListener('annotationChanged', (annotations: Annotation[]) => { + this.#manager.addEventListener('annotationChanged', (annotations: Annotation[], action: string, options) => { + this.#logger.info('[PDF] Annotations changed: ', annotations, action, options); // when a rectangle is drawn, // it returns one annotation with tool name 'AnnotationCreateRectangle; // this will auto select rectangle after drawing diff --git a/apps/red-ui/src/app/services/dossiers/dossier-changes.service.ts b/apps/red-ui/src/app/services/dossiers/dossier-changes.service.ts index 59ff85819..f7db33bd6 100644 --- a/apps/red-ui/src/app/services/dossiers/dossier-changes.service.ts +++ b/apps/red-ui/src/app/services/dossiers/dossier-changes.service.ts @@ -35,7 +35,7 @@ export class DossiersChangesService extends GenericService implements O changes.map(change => this.#load(change.dossierId).pipe(removeIfNotFound(change.dossierId))); return this.hasChangesDetails$().pipe( - tap(changes => this.#logger.info('[CHANGES] ', changes)), + tap(changes => this.#logger.info('[CHANGES] Dossier changes', changes)), switchMap(dossierChanges => forkJoin([...load(dossierChanges), this.#dashboardStatsService.loadAll().pipe(take(1))]).pipe(map(() => dossierChanges)), ), diff --git a/apps/red-ui/src/app/services/dossiers/dossiers.service.ts b/apps/red-ui/src/app/services/dossiers/dossiers.service.ts index 23393b67c..d4873fef6 100644 --- a/apps/red-ui/src/app/services/dossiers/dossiers.service.ts +++ b/apps/red-ui/src/app/services/dossiers/dossiers.service.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/member-ordering */ import { EntitiesService, Toaster } from '@iqser/common-ui'; import { Dossier, DossierStats, IDossier, IDossierChanges, IDossierRequest } from '@red/domain'; import { Observable, of, Subject } from 'rxjs'; diff --git a/apps/red-ui/src/styles.scss b/apps/red-ui/src/styles.scss index 7ead7b9ab..862abfa29 100644 --- a/apps/red-ui/src/styles.scss +++ b/apps/red-ui/src/styles.scss @@ -144,9 +144,13 @@ $dark-accent-10: darken(vars.$accent, 10%); $iqser-app-name-color: vars.$white ); +body { + --workload-width: 350px; +} + #viewer { visibility: hidden; - width: calc(100% - 350px); + width: calc(100% - var(--workload-width)); height: calc(100% - calc(var(--iqser-top-bar-height) + 50px)); bottom: 0; left: 0;