remove file from fileData

This commit is contained in:
Dan Percic 2022-01-31 20:42:32 +02:00
parent 7acaa9f965
commit 440063c3b3
7 changed files with 174 additions and 183 deletions

View File

@ -19,7 +19,6 @@ export class FileDataModel {
allAnnotations: AnnotationWrapper[];
readonly hasChangeLog$ = new BehaviorSubject<boolean>(false);
readonly blob$ = new BehaviorSubject<Blob>(undefined);
readonly file$ = new BehaviorSubject<File>(undefined);
constructor(
private readonly _file: File,
@ -29,19 +28,10 @@ export class FileDataModel {
private _dictionaryData?: { [p: string]: Dictionary },
private _areDevFeaturesEnabled?: boolean,
) {
this.file$.next(_file);
this.blob$.next(_blob);
this._buildAllAnnotations();
}
get file(): File {
return this.file$.value;
}
set file(file: File) {
this.file$.next(file);
}
get redactionLog(): IRedactionLog {
return this._redactionLog;
}

View File

@ -11,7 +11,7 @@ import {
SimpleChanges,
ViewChild,
} from '@angular/core';
import { Dossier, IManualRedactionEntry } from '@red/domain';
import { Dossier, File, IManualRedactionEntry } from '@red/domain';
import WebViewer, { Core, WebViewerInstance } from '@pdftron/webviewer';
import { TranslateService } from '@ngx-translate/core';
import {
@ -37,7 +37,7 @@ import { toPosition } from '../../../../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 { filter, switchMap, tap } from 'rxjs/operators';
import { filter, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import Tools = Core.Tools;
import TextTool = Tools.TextTool;
import Annotation = Core.Annotations.Annotation;
@ -126,18 +126,19 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
switchMap(fileData => fileData.blob$),
// Skip document reload if file content hasn't changed
shareDistinctLast(),
tap(() => this._loadDocument()),
withLatestFrom(this.stateService.file$),
tap(([blob, file]) => this._loadDocument(blob, file)),
)
.subscribe();
}
ngOnChanges(changes: SimpleChanges): void {
async ngOnChanges(changes: SimpleChanges): Promise<void> {
if (!this.instance) {
return;
}
if (changes.canPerformActions) {
this._handleCustomActions();
await this._handleCustomActions();
}
}
@ -163,12 +164,13 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
this._loadingService.start();
this.utils.ready = false;
const mergedDocument = await pdfNet.PDFDoc.create();
const file = await this.stateService.file;
await loadCompareDocumentWrapper(
currentDocument,
compareDocument,
mergedDocument,
this.instance,
this.stateService.fileData.file,
file,
() => {
this.viewModeService.compareMode = true;
},
@ -211,9 +213,10 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
const pdfNet = this.instance.Core.PDFNet;
await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await this.stateService.fileData.blob$.value.arrayBuffer());
this.instance.UI.loadDocument(currentDocument, {
filename: this.stateService.fileData?.file?.filename ?? 'document.pdf',
});
const filename = (await this.stateService.file).filename ?? 'document.pdf';
this.instance.UI.loadDocument(currentDocument, { filename });
this.instance.UI.disableElements([dataElements.CLOSE_COMPARE_BUTTON]);
this.instance.UI.enableElements([dataElements.COMPARE_BUTTON]);
this.utils.navigateToPage(1);
@ -238,7 +241,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
this._setSelectionMode();
this._configureElements();
this.utils.disableHotkeys();
this._configureTextPopup();
await this._configureTextPopup();
this.annotationManager.addEventListener('annotationSelected', (annotations: Annotation[], action) => {
this.annotationSelected.emit(this.annotationManager.getSelectedAnnotations().map(ann => ann.Id));
@ -265,7 +268,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
this.utils.deselectAllAnnotations();
}
this._ngZone.run(() => this.pageChanged.emit(pageNumber));
this._handleCustomActions();
return this._handleCustomActions();
});
this.documentViewer.addEventListener('documentLoaded', this._setReadyAndInitialState);
@ -288,11 +291,12 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
}
});
this.documentViewer.addEventListener('textSelected', (quads, selectedText) => {
this.documentViewer.addEventListener('textSelected', async (quads, selectedText) => {
this._selectedText = selectedText;
const textActions = [dataElements.ADD_DICTIONARY, dataElements.ADD_FALSE_POSITIVE];
if (selectedText.length > 2 && this.canPerformActions && !this.utils.isCurrentPageExcluded(this.stateService.fileData.file)) {
const file = await this.stateService.file;
if (selectedText.length > 2 && this.canPerformActions && !this.utils.isCurrentPageExcluded(file)) {
this.instance.UI.enableElements(textActions);
} else {
this.instance.UI.disableElements(textActions);
@ -479,14 +483,13 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
]);
}
this.instance.UI.annotationPopup.add(
this._annotationActionsService.getViewerAvailableActions(
this.instance,
this.stateService.fileData.file,
annotationWrappers,
this.annotationsChanged,
),
const actions = this._annotationActionsService.getViewerAvailableActions(
this.instance,
this.dossier,
annotationWrappers,
this.annotationsChanged,
);
this.instance.UI.annotationPopup.add(actions);
}
private _configureRectangleAnnotationPopup() {
@ -576,7 +579,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
},
]);
this._handleCustomActions();
return this._handleCustomActions();
}
private _addManualRedactionOfType(type: ManualRedactionEntryType) {
@ -586,7 +589,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
this.manualAnnotationRequested.emit(new ManualRedactionEntryWrapper(selectedQuads, manualRedaction, type));
}
private _handleCustomActions() {
private async _handleCustomActions() {
this.instance.UI.setToolMode('AnnotationEdit');
const { ANNOTATION_POPUP, ADD_RECTANGLE, ADD_REDACTION, SHAPE_TOOL_GROUP_BUTTON } = dataElements;
const elements = [
@ -598,7 +601,9 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
ANNOTATION_POPUP,
];
if (this.canPerformActions && !this.utils.isCurrentPageExcluded(this.stateService.fileData.file)) {
const isCurrentPageExcluded = this.utils.isCurrentPageExcluded(await this.stateService.file);
if (this.canPerformActions && !isCurrentPageExcluded) {
try {
this.instance.UI.enableTools(['AnnotationCreateRectangle']);
} catch (e) {
@ -615,7 +620,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
let elementsToDisable = [...elements, ADD_RECTANGLE];
if (this.utils.isCurrentPageExcluded(this.stateService.fileData.file)) {
if (isCurrentPageExcluded) {
const allowedActionsWhenPageExcluded: string[] = [ANNOTATION_POPUP, ADD_RECTANGLE, ADD_REDACTION, SHAPE_TOOL_GROUP_BUTTON];
elementsToDisable = elementsToDisable.filter(element => !allowedActionsWhenPageExcluded.includes(element));
} else {
@ -645,9 +650,10 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
return entry;
}
private _loadDocument() {
this.instance.UI.loadDocument(this.stateService.fileData.blob$.value, {
filename: this.stateService.fileData?.file?.filename ?? 'document.pdf',
private _loadDocument(blob: Blob, file: File) {
console.log(blob, file);
this.instance.UI.loadDocument(blob, {
filename: file?.filename ?? 'document.pdf',
});
}

View File

@ -1,4 +1,4 @@
<ng-container *ngIf="dossier$ | async as dossier">
<ng-container *ngIf="stateService.dossier$ | async as dossier">
<ng-container *ngIf="stateService.file$ | async as file">
<section [class.fullscreen]="fullScreen">
<div class="page-header">

View File

@ -22,9 +22,9 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { ManualAnnotationResponse } from '@models/file/manual-annotation-response';
import { AnnotationDrawService } from './services/annotation-draw.service';
import { AnnotationProcessingService } from '../../services/annotation-processing.service';
import { Dossier, File, ViewMode } from '@red/domain';
import { File, ViewMode } from '@red/domain';
import { PermissionsService } from '@services/permissions.service';
import { combineLatest, Observable, timer } from 'rxjs';
import { combineLatest, firstValueFrom, Observable, timer } from 'rxjs';
import { UserPreferenceService } from '@services/user-preference.service';
import { PdfViewerDataService } from '../../services/pdf-viewer-data.service';
import { download } from '@utils/file-download-utils';
@ -36,7 +36,7 @@ import { handleFilterDelta } from '@utils/filter-utils';
import { FilesService } from '@services/entity-services/files.service';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { FileManagementService } from '@services/entity-services/file-management.service';
import { map, switchMap, tap } from 'rxjs/operators';
import { filter, map, switchMap, tap } from 'rxjs/operators';
import { FilesMapService } from '@services/entity-services/files-map.service';
import { WatermarkService } from '@shared/services/watermark.service';
import { ExcludedPagesService } from './services/excluded-pages.service';
@ -45,12 +45,10 @@ import { MultiSelectService } from './services/multi-select.service';
import { DocumentInfoService } from './services/document-info.service';
import { ReanalysisService } from '../../../../services/reanalysis.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { CommentingService } from './services/commenting.service';
import { SkippedService } from './services/skipped.service';
import { AnnotationActionsService } from './services/annotation-actions.service';
import { FilePreviewStateService } from './services/file-preview-state.service';
import { FileDataModel } from '../../../../models/file/file-data.model';
import { AnnotationReferencesService } from './services/annotation-references.service';
import { filePreviewScreenProviders } from './utils';
import Annotation = Core.Annotations.Annotation;
import PDFNet = Core.PDFNet;
@ -59,20 +57,7 @@ const ALL_HOTKEY_ARRAY = ['Escape', 'F', 'f', 'ArrowUp', 'ArrowDown'];
@Component({
templateUrl: './file-preview-screen.component.html',
styleUrls: ['./file-preview-screen.component.scss'],
providers: [
FilterService,
ExcludedPagesService,
ViewModeService,
MultiSelectService,
DocumentInfoService,
CommentingService,
SkippedService,
AnnotationDrawService,
AnnotationActionsService,
FilePreviewStateService,
PdfViewerDataService,
AnnotationReferencesService,
],
providers: filePreviewScreenProviders,
})
export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnInit, OnDestroy, OnAttach, OnDetach {
readonly circleButtonTypes = CircleButtonTypes;
@ -84,10 +69,9 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
displayPdfViewer = false;
activeViewerPage: number = null;
@ViewChild(PdfViewerComponent) readonly viewerComponent: PdfViewerComponent;
readonly dossierId: string;
readonly canPerformAnnotationActions$: Observable<boolean>;
readonly dossier$: Observable<Dossier>;
readonly fileId: string;
readonly fileId = this.stateService.fileId;
readonly dossierId = this.stateService.dossierId;
ready = false;
private _instance: WebViewerInstance;
private _lastPage: string;
@ -128,9 +112,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
readonly documentInfoService: DocumentInfoService,
) {
super();
this.dossierId = _activatedRoute.snapshot.paramMap.get('dossierId');
this.dossier$ = _dossiersService.getEntityChanged$(this.dossierId);
this.fileId = _activatedRoute.snapshot.paramMap.get('fileId');
this.canPerformAnnotationActions$ = this._canPerformAnnotationActions$;
document.documentElement.addEventListener('fullscreenchange', () => {
@ -466,19 +447,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}, 100);
}
private async _reloadFile(file: File): Promise<void> {
const previousFile = this._fileData?.file;
await this._loadFileData(file);
// file already loaded at least once
if (previousFile) {
// If it has been OCRd, we need to wait for it to load into the viewer
if (previousFile.lastOCRTime !== this._fileData?.file?.lastOCRTime) {
return;
}
}
}
private async _stampPDF() {
if (!this._instance?.Core.documentViewer.getDocument()) {
return;
@ -534,23 +502,22 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
}
private async _fileUpdated(file: File): Promise<File> {
if (!this._fileData || file.lastProcessed === this._fileData.file.lastProcessed) {
await this._reloadFile(file);
} else {
// File reanalysed
const previousAnnotations = this.visibleAnnotations;
await this._loadFileData(file);
await this._reloadAnnotations(previousAnnotations);
}
private async _fileUpdated(file: File): Promise<void> {
const hasBeenProcessed = await firstValueFrom(this.stateService.hasBeenProcessed$);
await this._loadFileData(file);
return file;
if (hasBeenProcessed) {
await this._reloadAnnotations();
}
}
private _subscribeToFileUpdates(): void {
this.addActiveScreenSubscription = this._filesMapService
.watch$(this.dossierId, this.fileId)
.pipe(switchMap(file => this._fileUpdated(file)))
.pipe(
filter(f => !!f),
switchMap(file => this._fileUpdated(file)),
)
.subscribe();
this.addActiveScreenSubscription = timer(0, 5000)
@ -589,13 +556,11 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
return this._router.navigate([this._dossiersService.find(this.dossierId).routerLink]);
}
const fileData = await this._pdfViewerDataService.loadDataFor(file).toPromise();
if (file.isPending) {
return;
}
this.stateService.fileData = fileData;
this.stateService.fileData = await firstValueFrom(this._pdfViewerDataService.loadDataFor(file));
}
@Debounce(0)
@ -604,25 +569,24 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
this._workloadComponent?.scrollAnnotations();
}
private async _reloadAnnotations(previousAnnotations?: AnnotationWrapper[]) {
private async _reloadAnnotations() {
this._deleteAnnotations();
await this._cleanupAndRedrawAnnotations(previousAnnotations);
await this._cleanupAndRedrawAnnotations();
}
private async _reloadAnnotationsForPage(page: number) {
this._fileData.file = await this._filesService.reload(this.dossierId, this.fileId).toPromise();
const file = await firstValueFrom(this._filesService.reload(this.dossierId, this.fileId));
// if this action triggered a re-processing,
// we don't want to redraw for this page since they will get redrawn as soon as processing ends;
if (this._fileData.file.isProcessing) {
if (file.isProcessing) {
return;
}
const currentPageAnnotations = this.visibleAnnotations.filter(a => a.pageNumber === page);
this._fileData.redactionLog = await this._pdfViewerDataService.loadRedactionLogFor(this.dossierId, this.fileId).toPromise();
this._fileData.redactionLog = await firstValueFrom(this._pdfViewerDataService.loadRedactionLogFor(this.dossierId, this.fileId));
this._deleteAnnotations(currentPageAnnotations);
await this._cleanupAndRedrawAnnotations(currentPageAnnotations, annotation => annotation.pageNumber === page);
await this._cleanupAndRedrawAnnotations(annotation => annotation.pageNumber === page);
}
private _deleteAnnotations(annotationsToDelete?: AnnotationWrapper[]) {
@ -641,10 +605,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
});
}
private async _cleanupAndRedrawAnnotations(
currentAnnotations?: AnnotationWrapper[],
newAnnotationsFilter?: (annotation: AnnotationWrapper) => boolean,
) {
private async _cleanupAndRedrawAnnotations(newAnnotationsFilter?: (annotation: AnnotationWrapper) => boolean) {
if (!this._instance?.Core.documentViewer.getDocument()) {
return;
}
@ -652,17 +613,18 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
const currentFilters = this._filterService.getGroup('primaryFilters')?.filters || [];
this.rebuildFilters();
if (this.viewModeService.viewMode === 'STANDARD') {
const startTime = new Date().getTime();
const newAnnotations = newAnnotationsFilter ? this.visibleAnnotations.filter(newAnnotationsFilter) : this.visibleAnnotations;
if (currentFilters) {
this._handleDeltaAnnotationFilters(currentFilters, this.visibleAnnotations);
}
await this._redrawAnnotations(newAnnotations);
console.log(
`[REDACTION] Annotations redraw time: ${new Date().getTime() - startTime} ms for ${newAnnotations.length} annotations`,
);
if (!this.viewModeService.isStandard) {
return;
}
const startTime = new Date().getTime();
const newAnnotations = newAnnotationsFilter ? this.visibleAnnotations.filter(newAnnotationsFilter) : this.visibleAnnotations;
if (currentFilters) {
this._handleDeltaAnnotationFilters(currentFilters, this.visibleAnnotations);
}
await this._redrawAnnotations(newAnnotations);
console.log(`[REDACTION] Annotations redraw time: ${new Date().getTime() - startTime} ms for ${newAnnotations.length} annotations`);
}
private _redrawAnnotations(annotations = this.allAnnotations) {

View File

@ -23,6 +23,7 @@ import {
import { defaultDialogConfig } from '@iqser/common-ui';
import { filter } from 'rxjs/operators';
import { MatDialog } from '@angular/material/dialog';
import { FilePreviewStateService } from './file-preview-state.service';
import Annotation = Core.Annotations.Annotation;
@Injectable()
@ -38,6 +39,7 @@ export class AnnotationActionsService {
private readonly _dialog: MatDialog,
private readonly _annotationDrawService: AnnotationDrawService,
private readonly _dossiersService: DossiersService,
private readonly _screenStateService: FilePreviewStateService,
) {}
acceptSuggestion(
@ -215,13 +217,11 @@ export class AnnotationActionsService {
getViewerAvailableActions(
viewer: WebViewerInstance,
file: File,
dossier: Dossier,
annotations: AnnotationWrapper[],
annotationsChanged: EventEmitter<AnnotationWrapper>,
): Record<string, unknown>[] {
const availableActions = [];
const dossier = this._dossier(file);
const annotationPermissions = annotations.map(annotation => ({
annotation,
permissions: AnnotationPermissions.forUser(
@ -241,21 +241,19 @@ export class AnnotationActionsService {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/check.svg'),
title: this._translateService.instant('annotation-actions.resize-accept.label'),
onClick: () => {
this._ngZone.run(() => {
onClick: () =>
this._runForCurrentFile(file => {
this.acceptResize(null, viewer, file, firstAnnotation, annotationsChanged);
});
},
}),
});
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/close.svg'),
title: this._translateService.instant('annotation-actions.resize-cancel.label'),
onClick: () => {
onClick: () =>
this._ngZone.run(() => {
this.cancelResize(null, viewer, firstAnnotation, annotationsChanged);
});
},
}),
});
return availableActions;
}
@ -264,11 +262,7 @@ export class AnnotationActionsService {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/resize.svg'),
title: this._translateService.instant('annotation-actions.resize.label'),
onClick: () => {
this._ngZone.run(() => {
this.resize(null, viewer, annotations[0]);
});
},
onClick: () => this._ngZone.run(() => this.resize(null, viewer, annotations[0])),
});
}
@ -278,11 +272,10 @@ export class AnnotationActionsService {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/edit.svg'),
title: this._translateService.instant('annotation-actions.edit-reason.label'),
onClick: () => {
this._ngZone.run(() => {
onClick: () =>
this._runForCurrentFile(file => {
this.changeLegalBasis(null, annotations, file, annotationsChanged);
});
},
}),
});
}
@ -292,11 +285,10 @@ export class AnnotationActionsService {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/thumb-down.svg'),
title: this._translateService.instant('annotation-actions.recategorize-image'),
onClick: () => {
this._ngZone.run(() => {
onClick: () =>
this._runForCurrentFile(file => {
this.recategorizeImages(null, annotations, file, annotationsChanged);
});
},
}),
});
}
@ -309,11 +301,10 @@ export class AnnotationActionsService {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/remove-from-dict.svg'),
title: this._translateService.instant('annotation-actions.remove-annotation.remove-from-dict'),
onClick: () => {
this._ngZone.run(() => {
onClick: () =>
this._runForCurrentFile(file => {
this.removeOrSuggestRemoveAnnotation(null, annotations, file, true, annotationsChanged);
});
},
}),
});
}
@ -323,11 +314,10 @@ export class AnnotationActionsService {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/check.svg'),
title: this._translateService.instant('annotation-actions.accept-recommendation.label'),
onClick: () => {
this._ngZone.run(() => {
onClick: () =>
this._runForCurrentFile(file => {
this.convertRecommendationToAnnotation(null, annotations, file, annotationsChanged);
});
},
}),
});
}
@ -337,11 +327,10 @@ export class AnnotationActionsService {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/check.svg'),
title: this._translateService.instant('annotation-actions.accept-suggestion.label'),
onClick: () => {
this._ngZone.run(() => {
onClick: () =>
this._runForCurrentFile(file => {
this.acceptSuggestion(null, annotations, file, annotationsChanged);
});
},
}),
});
}
@ -351,11 +340,10 @@ export class AnnotationActionsService {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/undo.svg'),
title: this._translateService.instant('annotation-actions.undo'),
onClick: () => {
this._ngZone.run(() => {
onClick: () =>
this._runForCurrentFile(file => {
this.undoDirectAction(null, annotations, file, annotationsChanged);
});
},
}),
});
}
@ -365,11 +353,10 @@ export class AnnotationActionsService {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/thumb-down.svg'),
title: this._translateService.instant('annotation-actions.remove-annotation.false-positive'),
onClick: () => {
this._ngZone.run(() => {
onClick: () =>
this._runForCurrentFile(file => {
this.markAsFalsePositive(null, annotations, file, annotationsChanged);
});
},
}),
});
}
@ -379,11 +366,10 @@ export class AnnotationActionsService {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/thumb-up.svg'),
title: this._translateService.instant('annotation-actions.force-redaction.label'),
onClick: () => {
this._ngZone.run(() => {
onClick: () =>
this._runForCurrentFile(file => {
this.forceAnnotation(null, annotations, file, annotationsChanged);
});
},
}),
});
}
@ -393,11 +379,10 @@ export class AnnotationActionsService {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/thumb-up.svg'),
title: this._translateService.instant('annotation-actions.force-hint.label'),
onClick: () => {
this._ngZone.run(() => {
onClick: () =>
this._runForCurrentFile(file => {
this.forceAnnotation(null, annotations, file, annotationsChanged, true);
});
},
}),
});
}
@ -407,11 +392,10 @@ export class AnnotationActionsService {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/close.svg'),
title: this._translateService.instant('annotation-actions.reject-suggestion'),
onClick: () => {
this._ngZone.run(() => {
onClick: () =>
this._runForCurrentFile(file => {
this.rejectSuggestion(null, annotations, file, annotationsChanged);
});
},
}),
});
}
@ -424,11 +408,10 @@ export class AnnotationActionsService {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/trash.svg'),
title: this._translateService.instant('annotation-actions.remove-annotation.only-here'),
onClick: () => {
this._ngZone.run(() => {
onClick: () =>
this._runForCurrentFile(file => {
this.removeOrSuggestRemoveAnnotation(null, annotations, file, false, annotationsChanged);
});
},
}),
});
}
@ -503,6 +486,13 @@ export class AnnotationActionsService {
annotationsChanged.emit(annotationWrapper);
}
private async _runForCurrentFile(func: (file: File) => unknown): Promise<void> {
const file = await this._screenStateService.file;
this._ngZone.run(() => {
func(file);
});
}
private _dossier(file: File): Dossier {
return this._dossiersService.find(file.dossierId);
}

View File

@ -1,28 +1,40 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, switchMap } from 'rxjs';
import { BehaviorSubject, firstValueFrom, Observable } from 'rxjs';
import { FileDataModel } from '@models/file/file-data.model';
import { Dossier, File } from '@red/domain';
import { filter } from 'rxjs/operators';
import { DossiersService } from '../../../../../services/entity-services/dossiers.service';
import { shareLast } from '../../../../../../../../../libs/common-ui/src';
import { ActivatedRoute } from '@angular/router';
import { FilesMapService } from '../../../../../services/entity-services/files-map.service';
import { map } from 'rxjs/operators';
@Injectable()
export class FilePreviewStateService {
readonly fileData$: Observable<FileDataModel>;
readonly file$: Observable<File>;
readonly dossier$: Observable<Dossier>;
readonly dossierId: string;
readonly fileId: string;
readonly hasBeenProcessed$: Observable<boolean>;
private readonly _fileData$ = new BehaviorSubject<FileDataModel>(undefined);
private _lastProcessed = '';
constructor(
private readonly _dossiersService: DossiersService,
private readonly _filesMapService: FilesMapService,
activatedRoute: ActivatedRoute,
) {
this.dossierId = activatedRoute.snapshot.paramMap.get('dossierId');
this.dossier$ = _dossiersService.getEntityChanged$(this.dossierId);
this.fileId = activatedRoute.snapshot.paramMap.get('fileId');
constructor(private readonly _dossiersService: DossiersService) {
this.fileData$ = this._fileData$.asObservable();
this.file$ = this.fileData$.pipe(
filter(fileData => !!fileData),
switchMap(fileData => fileData.file$),
shareLast(),
);
this.dossier$ = this.file$.pipe(
switchMap(file => this._dossiersService.getEntityChanged$(file.dossierId)),
shareLast(),
this.file$ = _filesMapService.watch$(this.dossierId, this.fileId);
this.hasBeenProcessed$ = this.file$.pipe(
map(file => {
const hasBeenProcessed = file.lastProcessed !== this._lastProcessed;
this._lastProcessed = file.lastProcessed;
return hasBeenProcessed;
}),
);
}
@ -33,4 +45,8 @@ export class FilePreviewStateService {
set fileData(fileDataModel: FileDataModel) {
this._fileData$.next(fileDataModel);
}
get file(): Promise<File> {
return firstValueFrom(this.file$);
}
}

View File

@ -0,0 +1,27 @@
import { ExcludedPagesService } from './services/excluded-pages.service';
import { ViewModeService } from './services/view-mode.service';
import { MultiSelectService } from './services/multi-select.service';
import { DocumentInfoService } from './services/document-info.service';
import { CommentingService } from './services/commenting.service';
import { SkippedService } from './services/skipped.service';
import { AnnotationDrawService } from './services/annotation-draw.service';
import { AnnotationActionsService } from './services/annotation-actions.service';
import { FilePreviewStateService } from './services/file-preview-state.service';
import { PdfViewerDataService } from '../../services/pdf-viewer-data.service';
import { AnnotationReferencesService } from './services/annotation-references.service';
import { FilterService } from '../../../../../../../../libs/common-ui/src';
export const filePreviewScreenProviders = [
FilterService,
ExcludedPagesService,
ViewModeService,
MultiSelectService,
DocumentInfoService,
CommentingService,
SkippedService,
AnnotationDrawService,
AnnotationActionsService,
FilePreviewStateService,
PdfViewerDataService,
AnnotationReferencesService,
];