From bb5b0d03f5754e21e8a4484f5bb01f88278c9836 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 29 Apr 2022 17:59:02 +0300 Subject: [PATCH] RED-3772: handle document loading error --- .../pdf-viewer/pdf-viewer.component.ts | 13 +++++- .../services/file-preview-state.service.ts | 44 ++++++++++++------- apps/red-ui/src/assets/i18n/de.json | 4 ++ apps/red-ui/src/assets/i18n/en.json | 4 ++ libs/common-ui | 2 +- 5 files changed, 47 insertions(+), 20 deletions(-) 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 131f4c488..b7ef4fa83 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 @@ -26,7 +26,7 @@ import { AnnotationActionsService } from '../../services/annotation-actions.serv import { UserPreferenceService } from '@services/user-preference.service'; import { BASE_HREF } from '../../../../tokens'; import { ConfigService } from '@services/config.service'; -import { AutoUnsubscribe, ConfirmationDialogInput, LoadingService } from '@iqser/common-ui'; +import { AutoUnsubscribe, ConfirmationDialogInput, CustomError, ErrorService, LoadingService } from '@iqser/common-ui'; import { PdfViewer } from '../../services/pdf-viewer.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { toPosition } from '../../../dossier/utils/pdf-calculation.utils'; @@ -47,6 +47,8 @@ import Tools = Core.Tools; import TextTool = Tools.TextTool; import Annotation = Core.Annotations.Annotation; +const DocLoadingError = new CustomError(_('error.file-preview.label'), _('error.file-preview.action'), 'iqser:refresh'); + @Component({ selector: 'redaction-pdf-viewer', templateUrl: './pdf-viewer.component.html', @@ -81,6 +83,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha private readonly _fileDataService: FileDataService, private readonly _headerConfigService: ViewerHeaderConfigService, private readonly _tooltipsService: TooltipsService, + private readonly _errorService: ErrorService, readonly stateService: FilePreviewStateService, readonly viewModeService: ViewModeService, readonly multiSelectService: MultiSelectService, @@ -97,6 +100,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha .pipe( switchMap(blob => from(this.pdfViewer.lockDocument()).pipe(map(() => blob))), withLatestFrom(this.stateService.file$), + tap(() => this._errorService.clear()), tap(([blob, file]) => this._loadDocument(blob, file)), ) .subscribe(); @@ -550,7 +554,12 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha } private _loadDocument(blob: Blob, file: File) { - this.instance.UI.loadDocument(blob, { filename: file?.filename + '.pdf' ?? 'document.pdf' }); + const onError = () => { + this._loadingService.stop(); + this._errorService.set(DocLoadingError); + this.stateService.reloadBlob(); + }; + this.instance.UI.loadDocument(blob, { filename: file?.filename + '.pdf' ?? 'document.pdf', onError }); this._pageRotationService.clearRotationsHideActions(); } 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 10fc0c3f1..34e546838 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,11 +1,11 @@ import { Injectable, Injector } from '@angular/core'; -import { combineLatest, firstValueFrom, from, Observable, of, pairwise, switchMap } from 'rxjs'; +import { combineLatest, firstValueFrom, from, merge, Observable, of, pairwise, Subject, switchMap } from 'rxjs'; import { Dossier, File } from '@red/domain'; import { ActivatedRoute } from '@angular/router'; import { FilesMapService } from '@services/entity-services/files-map.service'; import { PermissionsService } from '@services/permissions.service'; import { boolFactory } from '@iqser/common-ui'; -import { filter, startWith, tap } from 'rxjs/operators'; +import { filter, map, startWith, tap, withLatestFrom } from 'rxjs/operators'; import { FileManagementService } from '@services/entity-services/file-management.service'; import { DOSSIER_ID, FILE_ID } from '@utils/constants'; import { dossiersServiceResolver } from '@services/entity-services/dossiers.service.provider'; @@ -29,26 +29,28 @@ export class FilePreviewStateService { dossier: Dossier; file: File; - constructor( - private readonly _fileManagementService: FileManagementService, - private readonly _injector: Injector, - private readonly _route: ActivatedRoute, - private readonly _filesMapService: FilesMapService, - private readonly _dossiersService: DossiersService, - private readonly _filesService: FilesService, - private readonly _permissionsService: PermissionsService, - ) { - const dossiersService = dossiersServiceResolver(this._injector); + readonly #reloadBlob$ = new Subject(); - this.fileId = _route.snapshot.paramMap.get(FILE_ID); - this.dossierId = _route.snapshot.paramMap.get(DOSSIER_ID); + constructor( + route: ActivatedRoute, + filesMapService: FilesMapService, + private readonly _injector: Injector, + permissionsService: PermissionsService, + private readonly _filesService: FilesService, + private readonly _dossiersService: DossiersService, + private readonly _fileManagementService: FileManagementService, + ) { + const dossiersService = dossiersServiceResolver(_injector); + + this.fileId = route.snapshot.paramMap.get(FILE_ID); + this.dossierId = route.snapshot.paramMap.get(DOSSIER_ID); this.dossierTemplateId = dossiersService.find(this.dossierId).dossierTemplateId; this.dossier$ = dossiersService.getEntityChanged$(this.dossierId).pipe(tap(dossier => (this.dossier = dossier))); - this.file$ = _filesMapService.watch$(this.dossierId, this.fileId).pipe(tap(file => (this.file = file))); + this.file$ = filesMapService.watch$(this.dossierId, this.fileId).pipe(tap(file => (this.file = file))); [this.isReadonly$, this.isWritable$] = boolFactory( combineLatest([this.file$, this.dossier$]), - ([file, dossier]) => !_permissionsService.canPerformAnnotationActions(file, dossier), + ([file, dossier]) => !permissionsService.canPerformAnnotationActions(file, dossier), ); this.blob$ = this.#blob$; @@ -60,7 +62,11 @@ export class FilePreviewStateService { } get #blob$() { - return this.file$.pipe( + const reloadBlob$ = this.#reloadBlob$.pipe( + withLatestFrom(this.file$), + map(([, file]) => file), + ); + return merge(this.file$, reloadBlob$).pipe( startWith(undefined), pairwise(), filter(([oldFile, newFile]) => oldFile?.cacheIdentifier !== newFile.cacheIdentifier), @@ -68,6 +74,10 @@ export class FilePreviewStateService { ); } + reloadBlob(): void { + this.#reloadBlob$.next(true); + } + #dossierFilesChange$() { return this._dossiersService.dossierFileChanges$.pipe( filter(dossierId => dossierId === this.dossierId), diff --git a/apps/red-ui/src/assets/i18n/de.json b/apps/red-ui/src/assets/i18n/de.json index 7df298f12..702feb6a6 100644 --- a/apps/red-ui/src/assets/i18n/de.json +++ b/apps/red-ui/src/assets/i18n/de.json @@ -1127,6 +1127,10 @@ "label": "Diese Datei wurde gelöscht!" } }, + "file-preview": { + "action": "", + "label": "" + }, "http": { "generic": "Aktion mit Code {status} fehlgeschlagen" }, diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 8ff44794d..e581a91ac 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -1127,6 +1127,10 @@ "label": "This file has been deleted!" } }, + "file-preview": { + "action": "Refresh", + "label": "An unknown error occurred. Please refresh the page" + }, "http": { "generic": "Action failed with code {status}" }, diff --git a/libs/common-ui b/libs/common-ui index fd9d62241..2998cb076 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit fd9d622413547de842439e8d91ee4316f2facff1 +Subproject commit 2998cb076f802a2bfb8694742c2c35a36ae687b8