RED-6892 deselect text when redaction added

This commit is contained in:
Dan Percic 2023-07-07 19:23:25 +03:00
parent d72d865ad8
commit a93527e963
8 changed files with 73 additions and 70 deletions

View File

@ -141,10 +141,10 @@ export const appModuleFactory = (config: AppConfig) => {
enabled: true,
},
FILE: {
enabled: false,
enabled: true,
},
CHANGES: {
enabled: false,
enabled: true,
},
STATS: {
enabled: false,

View File

@ -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 =>

View File

@ -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<Blob>): event is HttpProgressEvent {
@Injectable()
export class FilePreviewStateService {
readonly #reloadBlob$ = new Subject();
readonly #dossierFileChange: Signal<boolean>;
readonly file$: Observable<File>;
readonly file: Signal<File>;
readonly dossier: Signal<Dossier>;
@ -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) {

View File

@ -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)),
);
}

View File

@ -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<string>());
#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<AnnotationWrapper>): Annotation[];
get(predicate?: (value: Annotation) => boolean): Annotation[];
get(argument?: AnnotationPredicate | List<AnnotationWrapper> | 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<AnnotationWrapper>);
deselect(annotation: string | AnnotationWrapper): void;
deselect(annotations?: List | List<AnnotationWrapper>): void;
deselect(argument?: string | AnnotationWrapper | List | List<AnnotationWrapper>) {
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

View File

@ -35,7 +35,7 @@ export class DossiersChangesService extends GenericService<Dossier> 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)),
),

View File

@ -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';

View File

@ -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;