From 2b3779a911f226de8517f37ad1596c6608142f0a Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Tue, 15 Mar 2022 19:09:07 +0200 Subject: [PATCH] RED-3623: skip reloading redactions multiple times --- .../annotation-references-list.component.ts | 16 +- .../file-workload.component.html | 4 +- .../file-workload/file-workload.component.ts | 2 + .../view-switch/view-switch.component.ts | 18 +- .../file-preview/file-preview-providers.ts | 2 + .../file-preview-screen.component.ts | 40 +-- .../services/file-data.service.ts | 259 ++++++++++++++++++ .../services/file-preview-state.service.ts | 15 +- .../entity-services/viewed-pages.service.ts | 2 +- package.json | 1 + yarn.lock | 5 + 11 files changed, 311 insertions(+), 53 deletions(-) create mode 100644 apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-references-list/annotation-references-list.component.ts b/apps/red-ui/src/app/modules/file-preview/components/annotation-references-list/annotation-references-list.component.ts index 05513e07e..5c12ce784 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-references-list/annotation-references-list.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-references-list/annotation-references-list.component.ts @@ -1,9 +1,9 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { AnnotationReferencesService } from '../../services/annotation-references.service'; -import { FilePreviewStateService } from '../../services/file-preview-state.service'; -import { combineLatest, Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { filter, map } from 'rxjs/operators'; +import { FileDataService } from '../../services/file-data.service'; @Component({ selector: 'redaction-annotation-references-list', @@ -16,16 +16,12 @@ export class AnnotationReferencesListComponent { @Output() readonly referenceClicked = new EventEmitter(); references$ = this._annotationReferences; - constructor( - readonly annotationReferencesService: AnnotationReferencesService, - private readonly _filePreviewStateService: FilePreviewStateService, - ) {} + constructor(readonly annotationReferencesService: AnnotationReferencesService, private readonly _fileDataService: FileDataService) {} private get _annotationReferences(): Observable { - const combination = combineLatest([this.annotationReferencesService.annotation$, this._filePreviewStateService.fileData$]); - return combination.pipe( - filter(([annotation]) => !!annotation), - map(([{ reference }, fileData]) => fileData.allAnnotations.filter(a => reference.includes(a.annotationId))), + return this.annotationReferencesService.annotation$.pipe( + filter(annotation => !!annotation), + map(({ reference }) => this._fileDataService.allAnnotations.filter(a => reference.includes(a.annotationId))), ); } diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html index 3be6766ec..1c2b9af72 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html @@ -91,7 +91,7 @@ -
+
diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts index 3ac5cc779..b5d9d31cd 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts @@ -34,6 +34,7 @@ import { SkippedService } from '../../services/skipped.service'; import { FilePreviewStateService } from '../../services/file-preview-state.service'; import { ViewModeService } from '../../services/view-mode.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { FileDataService } from '../../services/file-data.service'; const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape']; const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']; @@ -76,6 +77,7 @@ export class FileWorkloadComponent { readonly multiSelectService: MultiSelectService, readonly documentInfoService: DocumentInfoService, readonly excludedPagesService: ExcludedPagesService, + readonly fileDataService: FileDataService, private readonly _viewModeService: ViewModeService, private readonly _changeDetectorRef: ChangeDetectorRef, private readonly _annotationProcessingService: AnnotationProcessingService, diff --git a/apps/red-ui/src/app/modules/file-preview/components/view-switch/view-switch.component.ts b/apps/red-ui/src/app/modules/file-preview/components/view-switch/view-switch.component.ts index a3f33a436..d781c086c 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/view-switch/view-switch.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/view-switch/view-switch.component.ts @@ -3,7 +3,8 @@ import { ViewMode } from '@red/domain'; import { ViewModeService } from '../../services/view-mode.service'; import { FilePreviewStateService } from '../../services/file-preview-state.service'; import { combineLatest, Observable } from 'rxjs'; -import { filter, map, switchMap } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; +import { FileDataService } from '../../services/file-data.service'; @Component({ selector: 'redaction-view-switch', @@ -17,14 +18,13 @@ export class ViewSwitchComponent { readonly canSwitchToDeltaView$: Observable; readonly canSwitchToRedactedView$: Observable; - constructor(readonly viewModeService: ViewModeService, private readonly _stateService: FilePreviewStateService) { - this.canSwitchToDeltaView$ = _stateService.fileData$.pipe( - filter(fileData => !!fileData), - switchMap(fileData => - combineLatest([fileData.hasChangeLog$, _stateService.file$]).pipe( - map(([hasChangeLog, file]) => hasChangeLog && !file.isApproved), - ), - ), + constructor( + readonly viewModeService: ViewModeService, + private readonly _stateService: FilePreviewStateService, + private readonly _fileDataService: FileDataService, + ) { + this.canSwitchToDeltaView$ = combineLatest([_fileDataService.hasChangeLog$, _stateService.file$]).pipe( + map(([hasChangeLog, file]) => hasChangeLog && !file.isApproved), ); this.canSwitchToRedactedView$ = _stateService.file$.pipe(map(file => !file.analysisRequired && !file.excluded)); diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-providers.ts b/apps/red-ui/src/app/modules/file-preview/file-preview-providers.ts index d85d9a83f..2459dde14 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-providers.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-providers.ts @@ -14,6 +14,7 @@ import { AnnotationProcessingService } from '../dossier/services/annotation-proc import { dossiersServiceProvider } from '@services/entity-services/dossiers.service.provider'; import { PageRotationService } from './services/page-rotation.service'; import { PdfViewer } from './services/pdf-viewer.service'; +import { FileDataService } from './services/file-data.service'; export const filePreviewScreenProviders = [ FilterService, @@ -31,5 +32,6 @@ export const filePreviewScreenProviders = [ PageRotationService, PdfViewer, AnnotationProcessingService, + FileDataService, dossiersServiceProvider, ]; 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 0dfaa7628..e467f8aeb 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 @@ -42,7 +42,6 @@ import { ReanalysisService } from '@services/reanalysis.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { SkippedService } from './services/skipped.service'; import { FilePreviewStateService } from './services/file-preview-state.service'; -import { FileDataModel } from '@models/file/file-data.model'; import { filePreviewScreenProviders } from './file-preview-providers'; import { ManualAnnotationService } from '@services/manual-annotation.service'; import { DossiersService } from '@services/dossiers/dossiers.service'; @@ -50,6 +49,7 @@ import { PageRotationService } from './services/page-rotation.service'; import { ComponentCanDeactivate } from '../../guards/can-deactivate.guard'; import { PdfViewer } from './services/pdf-viewer.service'; import { FilePreviewDialogService } from './services/file-preview-dialog.service'; +import { FileDataService } from './services/file-data.service'; import Annotation = Core.Annotations.Annotation; import PDFNet = Core.PDFNet; @@ -106,6 +106,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni private readonly _errorService: ErrorService, private readonly _pageRotationService: PageRotationService, private readonly _skippedService: SkippedService, + private readonly _fileDataService: FileDataService, private readonly _pdf: PdfViewer, private readonly _manualAnnotationService: ManualAnnotationService, readonly excludedPagesService: ExcludedPagesService, @@ -128,15 +129,11 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } get visibleAnnotations(): AnnotationWrapper[] { - return this._fileData ? this._fileData.getVisibleAnnotations(this._viewModeService.viewMode) : []; + return this._fileDataService.getVisibleAnnotations(this._viewModeService.viewMode); } get allAnnotations(): AnnotationWrapper[] { - return this._fileData ? this._fileData.allAnnotations : []; - } - - private get _fileData(): FileDataModel { - return this.stateService.fileData; + return this._fileDataService.allAnnotations; } private get _canPerformAnnotationActions$() { @@ -157,14 +154,14 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni return; } - const textHighlightAnnotationIds = this._fileData.textHighlightAnnotations.map(a => a.id); + const textHighlightAnnotationIds = this._fileDataService.textHighlightAnnotations.map(a => a.id); const textHighlightAnnotations = this._pdf.getAnnotations((a: Core.Annotations.Annotation) => textHighlightAnnotationIds.includes(a.Id), ); this._pdf.deleteAnnotations(textHighlightAnnotations); - const ocrAnnotationIds = this._fileData.allAnnotations.filter(a => a.isOCR).map(a => a.id); + const ocrAnnotationIds = this.allAnnotations.filter(a => a.isOCR).map(a => a.id); const annotations = this._pdf.getAnnotations(a => a.getCustomData('redact-manager')); const redactions = annotations.filter(a => a.getCustomData('redaction')); @@ -201,8 +198,8 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni this._loadingService.start(); const textHighlights = await firstValueFrom(this._pdfViewerDataService.loadTextHighlightsFor(this.dossierId, this.fileId)); this._pdf.hideAnnotations(annotations); - this._fileData.textHighlights = textHighlights; - await this._annotationDrawService.drawAnnotations(this._fileData.textHighlightAnnotations); + this._fileDataService.textHighlights = textHighlights; + await this._annotationDrawService.drawAnnotations(this._fileDataService.textHighlightAnnotations); this._loadingService.stop(); } } @@ -266,7 +263,10 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni this._filterService.addFilterGroup({ slug: 'secondaryFilters', filterTemplate: this._filterTemplate, - filters: processFilters(secondaryFilters, AnnotationProcessingService.secondaryAnnotationFilters(this._fileData?.viewedPages)), + filters: processFilters( + secondaryFilters, + AnnotationProcessingService.secondaryAnnotationFilters(this._fileDataService.viewedPages), + ), }); console.log(`[REDACTION] Process time: ${new Date().getTime() - processStartTime} ms`); console.log(`[REDACTION] Filter rebuild time: ${new Date().getTime() - startTime}`); @@ -279,7 +279,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni if (this.selectedAnnotations.length > 1) { this.multiSelectService.activate(); } - this._workloadComponent.scrollToSelectedAnnotation(); + this._workloadComponent?.scrollToSelectedAnnotation(); this._changeDetectorRef.markForCheck(); } @@ -344,7 +344,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni handleArrowEvent($event: KeyboardEvent): void { if (['ArrowUp', 'ArrowDown'].includes($event.key)) { if (this.selectedAnnotations.length === 1) { - this._workloadComponent.navigateAnnotations($event); + this._workloadComponent?.navigateAnnotations($event); } } } @@ -585,7 +585,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni return; } - this.stateService.fileData = await firstValueFrom(this._pdfViewerDataService.loadDataFor(file)); + await this._fileDataService.load(file); } @Debounce(0) @@ -595,6 +595,10 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } private async _reloadAnnotations() { + if (!this._fileDataService.shouldUpdateAnnotations) { + console.log('skip reloading annotations'); + return; + } this._deleteAnnotations(); await this._cleanupAndRedrawAnnotations(); await this.updateViewMode(); @@ -609,7 +613,9 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } const currentPageAnnotations = this.visibleAnnotations.filter(a => a.pageNumber === page); - this._fileData.redactionLog = await firstValueFrom(this._pdfViewerDataService.loadRedactionLogFor(this.dossierId, this.fileId)); + await this._fileDataService.setRedactionLog( + await firstValueFrom(this._pdfViewerDataService.loadRedactionLogFor(this.dossierId, this.fileId)), + ); this._deleteAnnotations(currentPageAnnotations); await this._cleanupAndRedrawAnnotations(annotation => annotation.pageNumber === page); @@ -637,7 +643,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni this.rebuildFilters(); const startTime = new Date().getTime(); - const annotations = this._fileData.allAnnotations; + const annotations = this.allAnnotations; const newAnnotations = newAnnotationsFilter ? annotations.filter(newAnnotationsFilter) : annotations; if (currentFilters) { 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 new file mode 100644 index 000000000..e678980f1 --- /dev/null +++ b/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts @@ -0,0 +1,259 @@ +import { + ChangeType, + File, + IRedactionLog, + IRedactionLogEntry, + IViewedPage, + LogEntryStatus, + ManualRedactionType, + TextHighlightResponse, + ViewMode, +} from '@red/domain'; +import { AnnotationWrapper } from '../../../models/file/annotation.wrapper'; +import * as moment from 'moment'; +import { BehaviorSubject, firstValueFrom, of } from 'rxjs'; +import { RedactionLogEntry } from '../../../models/file/redaction-log.entry'; +import { Injectable } from '@angular/core'; +import { FilePreviewStateService } from './file-preview-state.service'; +import { ViewedPagesService } from '../../../services/entity-services/viewed-pages.service'; +import { UserPreferenceService } from '../../../services/user-preference.service'; +import { DictionariesMapService } from '../../../services/entity-services/dictionaries-map.service'; +import { catchError, tap } from 'rxjs/operators'; +import { PermissionsService } from '../../../services/permissions.service'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { Toaster } from '../../../../../../../libs/common-ui/src'; +import { RedactionLogService } from '../../dossier/services/redaction-log.service'; + +@Injectable() +export class FileDataService { + static readonly DELTA_VIEW_TIME = 10 * 60 * 1000; // 10 minutes; + viewedPages: IViewedPage[] = []; + allAnnotations: AnnotationWrapper[] = []; + readonly hasChangeLog$ = new BehaviorSubject(false); + missingTypes = new Set(); + textHighlightAnnotations: AnnotationWrapper[] = []; + shouldUpdateAnnotations = false; + #redactionLog: IRedactionLog; + #redactionLogHash = ''; + + constructor( + private readonly _state: FilePreviewStateService, + private readonly _viewedPagesService: ViewedPagesService, + private readonly _userPreferenceService: UserPreferenceService, + private readonly _dictionariesMapService: DictionariesMapService, + private readonly _permissionsService: PermissionsService, + private readonly _redactionLogService: RedactionLogService, + private readonly _toaster: Toaster, + ) {} + + set textHighlights(textHighlightResponse: TextHighlightResponse) { + const highlights = []; + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + for (const color of Object.keys(textHighlightResponse.redactionPerColor)) { + for (const entry of textHighlightResponse.redactionPerColor[color]) { + const annotation = AnnotationWrapper.fromHighlight(color, entry); + highlights.push(annotation); + } + } + this.textHighlightAnnotations = highlights; + } + + async setRedactionLog(redactionLog: IRedactionLog) { + this.#redactionLog = redactionLog; + const hash = require('object-hash'); + const newRedactionLogHash = hash(redactionLog.redactionLogEntry ?? []); + + if (newRedactionLogHash === this.#redactionLogHash) { + this.shouldUpdateAnnotations = false; + return; + } + + this.shouldUpdateAnnotations = true; + this.#redactionLogHash = newRedactionLogHash; + await this.#buildAllAnnotations(); + } + + async load(file: File) { + this.viewedPages = await firstValueFrom(this.getViewedPagesFor(file)); + await this.setRedactionLog(await firstValueFrom(this.loadRedactionLog())); + + if (this.missingTypes.size > 0) { + this._toaster.error(_('error.missing-types'), { + disableTimeOut: true, + params: { missingTypes: Array.from(this.missingTypes).join(', ') }, + }); + } + } + + getViewedPagesFor(file: File) { + if (this._permissionsService.canMarkPagesAsViewed(file)) { + return this._viewedPagesService.getViewedPages(file.dossierId, file.fileId); + } + return of([] as IViewedPage[]); + } + + loadRedactionLog() { + return this._redactionLogService.getRedactionLog(this._state.dossierId, this._state.fileId).pipe( + tap(redactionLog => redactionLog.redactionLogEntry.sort((a, b) => a.positions[0].page - b.positions[0].page)), + catchError(() => of({})), + ); + } + + getVisibleAnnotations(viewMode: ViewMode) { + if (viewMode === 'TEXT_HIGHLIGHTS') { + return this.textHighlightAnnotations; + } + + return this.allAnnotations.filter(annotation => { + if (viewMode === 'STANDARD') { + return !annotation.isChangeLogRemoved; + } else if (viewMode === 'DELTA') { + return annotation.isChangeLogEntry; + } else { + return annotation.previewAnnotation; + } + }); + } + + async #buildAllAnnotations() { + const file = await this._state.file; + const entries: RedactionLogEntry[] = this.#convertData(file); + + const previousAnnotations = [...this.allAnnotations]; + this.allAnnotations = entries + .map(entry => AnnotationWrapper.fromData(entry)) + .filter(ann => ann.manual || !file.excludedPages.includes(ann.pageNumber)); + + if (!this._userPreferenceService.areDevFeaturesEnabled) { + this.allAnnotations = this.allAnnotations.filter(annotation => !annotation.isFalsePositive); + } + + this._setHiddenPropertyToNewAnnotations(this.allAnnotations, previousAnnotations); + } + + private _setHiddenPropertyToNewAnnotations(newAnnotations: AnnotationWrapper[], oldAnnotations: AnnotationWrapper[]) { + newAnnotations.forEach(newAnnotation => { + const oldAnnotation = oldAnnotations.find(a => a.annotationId === newAnnotation.annotationId); + if (oldAnnotation) { + newAnnotation.hidden = oldAnnotation.hidden; + } + }); + } + + #convertData(file: File): RedactionLogEntry[] { + let result: RedactionLogEntry[] = []; + + const reasonAnnotationIds: { [key: string]: RedactionLogEntry[] } = {}; + const _dictionaryData = this._dictionariesMapService.get(this._state.dossierTemplateId); + this.#redactionLog.redactionLogEntry?.forEach(redactionLogEntry => { + // copy the redactionLog Entry + + const changeLogValues = this.#getChangeLogValues(redactionLogEntry, file); + const dictionaryData = _dictionaryData.find(dict => dict.type === redactionLogEntry.type); + if (!dictionaryData) { + this.missingTypes.add(redactionLogEntry.type); + return; + } + + const redactionLogEntryWrapper: RedactionLogEntry = new RedactionLogEntry( + redactionLogEntry, + changeLogValues.changeLogType, + changeLogValues.isChangeLogEntry, + changeLogValues.hidden, + this.#redactionLog.legalBasis, + !!dictionaryData?.hint, + ); + + if ( + redactionLogEntry.manualChanges?.find( + mc => + mc.manualRedactionType === ManualRedactionType.ADD_TO_DICTIONARY && + (mc.annotationStatus === LogEntryStatus.APPROVED || mc.annotationStatus === LogEntryStatus.REQUESTED), + ) + ) { + // for dictionary entries -> I.E accepted recommendations or false positives, + // check reason + if (!reasonAnnotationIds[redactionLogEntry.reason]) { + reasonAnnotationIds[redactionLogEntry.reason] = [redactionLogEntryWrapper]; + } else { + reasonAnnotationIds[redactionLogEntry.reason].push(redactionLogEntryWrapper); + } + } + + result.push(redactionLogEntryWrapper); + }); + + const reasonKeys = Object.keys(reasonAnnotationIds); + result = result.filter(r => { + const matched = reasonKeys.indexOf(r.id) >= 0; + if (matched) { + reasonAnnotationIds[r.id].forEach(value => { + value.reason = null; + }); + } + return !matched; + }); + + result = result.filter(r => !r.hidden); + + return result; + } + + #getChangeLogValues( + redactionLogEntry: IRedactionLogEntry, + file: File, + ): { + hidden: boolean; + changeLogType: ChangeType; + isChangeLogEntry: boolean; + } { + if (file.numberOfAnalyses > 1) { + const viableChanges = redactionLogEntry.changes.filter(c => c.analysisNumber > 1); + viableChanges.sort((a, b) => moment(a.dateTime).valueOf() - moment(b.dateTime).valueOf()); + + const lastChange = viableChanges.length >= 1 ? viableChanges[viableChanges.length - 1] : undefined; + const page = redactionLogEntry.positions?.[0].page; + + const viewedPage = this.viewedPages.filter(p => p.page === page).pop(); + + // page has been seen -> let's see if it's a change + if (viewedPage) { + const viewTime = moment(viewedPage.viewedTime).valueOf() - FileDataService.DELTA_VIEW_TIME; + // these are all unseen changes + const relevantChanges = viableChanges.filter(change => moment(change.dateTime).valueOf() > viewTime); + // at least one unseen change + if (relevantChanges.length > 0) { + // at least 1 relevant change + viewedPage.showAsUnseen = moment(viewedPage.viewedTime).valueOf() < moment(lastChange.dateTime).valueOf(); + this.hasChangeLog$.next(true); + return { + changeLogType: relevantChanges[relevantChanges.length - 1].type, + isChangeLogEntry: true, + hidden: false, + }; + } else { + // no relevant changes - hide removed anyway + return { + changeLogType: null, + isChangeLogEntry: false, + hidden: lastChange && lastChange.type === 'REMOVED', + }; + } + } else { + // Page doesn't have a view-time + return { + changeLogType: null, + isChangeLogEntry: false, + hidden: lastChange && lastChange.type === 'REMOVED', + }; + } + } else { + return { + changeLogType: null, + isChangeLogEntry: false, + hidden: false, + }; + } + // console.log(wrapper.changeLogType, wrapper.hidden, wrapper.isChangeLogEntry, wrapper.value, lastChange); + } +} 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 53719a8a5..9a26097b9 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 @@ -1,6 +1,5 @@ import { Injectable, Injector } from '@angular/core'; -import { BehaviorSubject, firstValueFrom, from, Observable, pairwise, switchMap } from 'rxjs'; -import { FileDataModel } from '@models/file/file-data.model'; +import { firstValueFrom, from, Observable, pairwise, switchMap } from 'rxjs'; import { Dossier, File } from '@red/domain'; import { ActivatedRoute } from '@angular/router'; import { FilesMapService } from '@services/entity-services/files-map.service'; @@ -20,14 +19,11 @@ export class FilePreviewStateService { readonly dossier$: Observable; readonly isReadonly$: Observable; readonly isWritable$: Observable; - readonly fileData$: Observable; readonly dossierId: string; readonly dossierTemplateId: string; readonly fileId: string; - readonly #fileData$ = new BehaviorSubject(undefined); - constructor( private readonly _fileManagementService: FileManagementService, private readonly _injector: Injector, @@ -43,18 +39,9 @@ export class FilePreviewStateService { this.file$ = _filesMapService.watch$(this.dossierId, this.fileId); [this.isReadonly$, this.isWritable$] = boolFactory(this.file$, file => !_permissionsService.canPerformAnnotationActions(file)); - this.fileData$ = this.#fileData$.asObservable().pipe(filter(value => !!value)); this.blob$ = this.#blob$; } - get fileData(): FileDataModel { - return this.#fileData$.value; - } - - set fileData(fileDataModel: FileDataModel) { - this.#fileData$.next(fileDataModel); - } - get file(): Promise { return firstValueFrom(this.file$); } diff --git a/apps/red-ui/src/app/services/entity-services/viewed-pages.service.ts b/apps/red-ui/src/app/services/entity-services/viewed-pages.service.ts index ac3b571aa..9d8462112 100644 --- a/apps/red-ui/src/app/services/entity-services/viewed-pages.service.ts +++ b/apps/red-ui/src/app/services/entity-services/viewed-pages.service.ts @@ -26,7 +26,7 @@ export class ViewedPagesService extends GenericService { getViewedPages(@RequiredParam() dossierId: string, @RequiredParam() fileId: string) { return this._getOne<{ pages?: IViewedPage[] }>([dossierId, fileId]).pipe( map(res => res.pages), - catchError(() => of([])), + catchError(() => of([] as IViewedPage[])), ); } } diff --git a/package.json b/package.json index b12c939a4..a0163714e 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "ngx-color-picker": "^12.0.1", "ngx-toastr": "^14.1.3", "ngx-translate-messageformat-compiler": "^5.0.1", + "object-hash": "^3.0.0", "papaparse": "^5.3.1", "rxjs": "~7.5.2", "sass": "^1.49.0", diff --git a/yarn.lock b/yarn.lock index 5962da5f4..e02dc288c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9183,6 +9183,11 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== + object-inspect@^1.11.0, object-inspect@^1.9.0: version "1.12.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0"