From 0c0d72aef1c33dfde2239dcb7775518e6fc6dd7d Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 7 Jul 2023 12:08:19 +0300 Subject: [PATCH 1/3] RED-7054 fix not found http errors --- .../edit-dossier-general-info.component.ts | 22 ++++++---- .../services/entity-services/trash.service.ts | 10 +++-- .../src/app/services/license.service.ts | 41 +++++++++++-------- libs/common-ui | 2 +- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.ts b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.ts index 2d0f75243..c0b5cf9b0 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.ts +++ b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.ts @@ -144,15 +144,11 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti this._dialogService.openDialog('confirm', data, async () => { this._loadingService.start(); - await firstValueFrom(this._trashService.deleteDossier(this.dossier)); - this._editDossierDialogRef.close(); - await this._router.navigate([`/${this._tenantsService.activeTenantId}${this.dossier.dossiersListRouterLink}`]); + const successful = await this._trashService.deleteDossier(this.dossier); + if (successful) { + await this.#closeDialogAndRedirectToDossier(); + } this._loadingService.stop(); - this._toaster.success(_('edit-dossier-dialog.delete-successful'), { - params: { - dossierName: this.dossier.dossierName, - }, - }); }); } @@ -193,6 +189,16 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti return this._dossierStatesMapService.get(this.dossier.dossierTemplateId, stateId).color; } + async #closeDialogAndRedirectToDossier() { + this._editDossierDialogRef.close(); + await this._router.navigate([`/${this._tenantsService.activeTenantId}${this.dossier.dossiersListRouterLink}`]); + this._toaster.success(_('edit-dossier-dialog.delete-successful'), { + params: { + dossierName: this.dossier.dossierName, + }, + }); + } + #getForm(): UntypedFormGroup { const formFieldWithArchivedCheck = value => ({ value, disabled: !this.dossier.isActive }); return this._formBuilder.group({ diff --git a/apps/red-ui/src/app/services/entity-services/trash.service.ts b/apps/red-ui/src/app/services/entity-services/trash.service.ts index 921c40d9f..2b8365f93 100644 --- a/apps/red-ui/src/app/services/entity-services/trash.service.ts +++ b/apps/red-ui/src/app/services/entity-services/trash.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { EntitiesService, QueryParam, Toaster } from '@iqser/common-ui'; import { Dossier, File, IDossier, IFile, TrashDossier, TrashFile, TrashItem } from '@red/domain'; import { catchError, switchMap, take, tap } from 'rxjs/operators'; -import { forkJoin, map, Observable, of } from 'rxjs'; +import { firstValueFrom, forkJoin, map, Observable, of } from 'rxjs'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { PermissionsService } from '../permissions.service'; import { ActiveDossiersService } from '../dossiers/active-dossiers.service'; @@ -31,18 +31,20 @@ export class TrashService extends EntitiesService { super(); } - deleteDossier(dossier: Dossier): Observable { + deleteDossier(dossier: Dossier) { const showToast = () => { this._toaster.error(_('dossier-listing.delete.delete-failed'), { params: { dossierName: dossier.dossierName } }); - return of({}); + return of(undefined); }; const reloadDossiers$ = dossier.isActive ? this._activeDossiersService.loadAll() : this._archivedDossiersService.loadAll(); - return this.delete(dossier.id, 'dossier').pipe( + const request$ = this.delete(dossier.id, 'dossier').pipe( switchMap(() => reloadDossiers$), catchError(showToast), ); + + return firstValueFrom(request$); } restore(items: TrashItem[]): Observable { diff --git a/apps/red-ui/src/app/services/license.service.ts b/apps/red-ui/src/app/services/license.service.ts index 7c1dd0d14..8ababb1a5 100644 --- a/apps/red-ui/src/app/services/license.service.ts +++ b/apps/red-ui/src/app/services/license.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { inject, Injectable } from '@angular/core'; import { GenericService } from '@iqser/common-ui'; import { ILicense, ILicenseReport, ILicenseReportRequest, ILicenses } from '@red/domain'; import { BehaviorSubject, firstValueFrom, Observable, of } from 'rxjs'; @@ -39,6 +39,10 @@ const defaultOnError: ILicenses = { providedIn: 'root', }) export class LicenseService extends GenericService { + readonly #licenseData$ = new BehaviorSubject(undefined); + readonly #selectedLicense$ = new BehaviorSubject(undefined); + readonly #logger = inject(NGXLogger); + protected readonly _defaultModelPath = 'report'; readonly licenseData$: Observable; readonly selectedLicense$: Observable; activeLicenseId: string; @@ -48,9 +52,19 @@ export class LicenseService extends GenericService { unlicensedPages = 0; analyzedPagesInCurrentLicensingPeriod = 0; uploadedBytesCapacity = 0; - protected readonly _defaultModelPath = 'report'; - readonly #licenseData$ = new BehaviorSubject(undefined); - readonly #selectedLicense$ = new BehaviorSubject(undefined); + + constructor() { + super(); + this.selectedLicense$ = this.#selectedLicense$.pipe(filter(license => !!license)); + this.licenseData$ = this.#licenseData$.pipe( + filter(licenses => !!licenses), + tap(data => (this.activeLicenseId = data.activeLicense)), + tap(() => { + const uploadedBytesCapacity = this.activeLicense.features.find(f => f.name === 'uploadedBytesCapacity')?.value; + this.uploadedBytesCapacity = uploadedBytesCapacity ? parseInt(uploadedBytesCapacity, 10) : 0; + }), + ); + } get selectedLicense() { return this.#selectedLicense$.value; @@ -66,20 +80,13 @@ export class LicenseService extends GenericService { } get activeLicenseKey(): string { - return this.activeLicense.features.find(f => f.name === 'pdftron').value; - } + const activeLicense = this.activeLicense; + if (!activeLicense) { + this.#logger.error('[LICENSE] No active license found!'); + return ''; + } - constructor(private readonly _logger: NGXLogger) { - super(); - this.selectedLicense$ = this.#selectedLicense$.pipe(filter(license => !!license)); - this.licenseData$ = this.#licenseData$.pipe( - filter(licenses => !!licenses), - tap(data => (this.activeLicenseId = data.activeLicense)), - tap(() => { - const uploadedBytesCapacity = this.activeLicense.features.find(f => f.name === 'uploadedBytesCapacity')?.value; - this.uploadedBytesCapacity = uploadedBytesCapacity ? parseInt(uploadedBytesCapacity, 10) : 0; - }), - ); + return activeLicense.features.find(f => f.name === 'pdftron').value; } async loadLicenseData(license: ILicense = this.selectedLicense) { diff --git a/libs/common-ui b/libs/common-ui index f631395f6..30846478e 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit f631395f613e6cbeaf71826dac4dc8446be33520 +Subproject commit 30846478ed6a112813953b9217a69ef047ffa217 From e473db9c16c92dfe8bd62ddfc3b9d815b8fce907 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 7 Jul 2023 13:25:03 +0300 Subject: [PATCH 2/3] RED-3800 update config & common-ui --- apps/red-ui/src/assets/config/config.json | 4 ++-- libs/common-ui | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json index 311b38e1a..3e5de8134 100644 --- a/apps/red-ui/src/assets/config/config.json +++ b/apps/red-ui/src/assets/config/config.json @@ -1,7 +1,7 @@ { "ADMIN_CONTACT_NAME": null, "ADMIN_CONTACT_URL": null, - "API_URL": "https://dev-02.iqser.cloud", + "API_URL": "https://dev-04.iqser.cloud", "APP_NAME": "RedactManager", "AUTO_READ_TIME": 3, "BACKEND_APP_VERSION": "4.4.40", @@ -11,7 +11,7 @@ "MAX_RETRIES_ON_SERVER_ERROR": 3, "OAUTH_CLIENT_ID": "redaction", "OAUTH_IDP_HINT": null, - "OAUTH_URL": "https://dev-02.iqser.cloud/auth", + "OAUTH_URL": "https://dev-04.iqser.cloud/auth", "RECENT_PERIOD_IN_HOURS": 24, "SELECTION_MODE": "structural", "MANUAL_BASE_URL": "https://docs.redactmanager.com/preview", diff --git a/libs/common-ui b/libs/common-ui index 30846478e..da18c68a8 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit 30846478ed6a112813953b9217a69ef047ffa217 +Subproject commit da18c68a861a8d343dd3f63298e825543714f743 From 72130128dca630e19310e9c4da1ce09c931fae9c Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 7 Jul 2023 15:13:42 +0300 Subject: [PATCH 3/3] RED-6713 fix page refresh loop --- apps/red-ui/src/app/app-routing.module.ts | 28 ++++---- apps/red-ui/src/app/guards/dossiers.guard.ts | 72 +++++++++++-------- .../src/app/guards/if-logged-in.guard.ts | 2 +- .../watermark-screen.component.html | 14 ++-- .../file-preview-screen.component.ts | 6 +- .../pdf-viewer/pdf-viewer.component.html | 2 - .../pdf-viewer/pdf-viewer.component.scss | 12 ---- .../modules/pdf-viewer/pdf-viewer.module.ts | 2 - .../services/document-viewer.service.ts | 18 ++++- .../services/webviewer-loaded.guard.ts | 47 ++++++------ apps/red-ui/src/index.html | 1 + apps/red-ui/src/styles.scss | 8 +++ 12 files changed, 114 insertions(+), 98 deletions(-) diff --git a/apps/red-ui/src/app/app-routing.module.ts b/apps/red-ui/src/app/app-routing.module.ts index 01ba8ff2e..ccf478b4b 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -5,8 +5,8 @@ import { BaseScreenComponent } from '@components/base-screen/base-screen.compone import { RouteReuseStrategy, RouterModule } from '@angular/router'; import { NgModule } from '@angular/core'; import { DownloadsListScreenComponent } from '@components/downloads-list-screen/downloads-list-screen.component'; -import { DossiersGuard } from '@guards/dossiers.guard'; -import { ACTIVE_DOSSIERS_SERVICE, ARCHIVED_DOSSIERS_SERVICE } from './tokens'; +import { loadActiveDossiersGuard, loadAllDossiersGuard, loadArchivedDossiersGuard } from '@guards/dossiers.guard'; +import { ACTIVE_DOSSIERS_SERVICE } from './tokens'; import { FeaturesGuard } from '@guards/features-guard.service'; import { DossierTemplatesGuard } from '@guards/dossier-templates.guard'; import { templateExistsWhenEnteringDossierList } from '@guards/dossier-template-exists.guard'; @@ -14,7 +14,7 @@ import { DashboardGuard } from '@guards/dashboard-guard.service'; import { TrashGuard } from '@guards/trash.guard'; import { ARCHIVE_ROUTE, BreadcrumbTypes, DOSSIER_ID, DOSSIER_TEMPLATE_ID, DOSSIERS_ARCHIVE, DOSSIERS_ROUTE, FILE_ID } from '@red/domain'; import { DossierFilesGuard } from '@guards/dossier-files-guard'; -import { WebViewerLoadedGuard } from './modules/pdf-viewer/services/webviewer-loaded.guard'; +import { webViewerLoadedGuard } from './modules/pdf-viewer/services/webviewer-loaded.guard'; import { Roles } from '@users/roles'; import { mainResolver } from '@utils/main.resolver'; import { hasAnyRoleGuard, IqserAuthGuard } from '@iqser/common-ui/lib/users'; @@ -26,10 +26,8 @@ import { TenantSelectComponent } from '@iqser/common-ui/lib/tenants'; const dossierTemplateIdRoutes: IqserRoutes = [ { path: `${DOSSIERS_ROUTE}`, - canActivate: [CompositeRouteGuard, IqserPermissionsGuard], + canActivate: [loadActiveDossiersGuard(), IqserPermissionsGuard], data: { - routeGuards: [DossiersGuard], - dossiersService: ACTIVE_DOSSIERS_SERVICE, permissions: { allow: [Roles.files.readStatus], redirectTo: '/auth-error', @@ -53,9 +51,9 @@ const dossierTemplateIdRoutes: IqserRoutes = [ }, { path: `:${DOSSIER_ID}/file/:${FILE_ID}`, - canActivate: [CompositeRouteGuard, IqserPermissionsGuard], + canActivate: [CompositeRouteGuard, IqserPermissionsGuard, webViewerLoadedGuard()], data: { - routeGuards: [DossierFilesGuard, WebViewerLoadedGuard], + routeGuards: [DossierFilesGuard], breadcrumbs: [BreadcrumbTypes.dossierTemplate, BreadcrumbTypes.dossier, BreadcrumbTypes.file], dossiersService: ACTIVE_DOSSIERS_SERVICE, permissions: { @@ -78,10 +76,9 @@ const dossierTemplateIdRoutes: IqserRoutes = [ { path: `${ARCHIVE_ROUTE}`, loadChildren: () => import('./modules/archive/archive.module').then(m => m.ArchiveModule), - canActivate: [CompositeRouteGuard, WebViewerLoadedGuard], + canActivate: [CompositeRouteGuard, webViewerLoadedGuard(), loadArchivedDossiersGuard()], data: { - routeGuards: [FeaturesGuard, DossiersGuard], - dossiersService: ARCHIVED_DOSSIERS_SERVICE, + routeGuards: [FeaturesGuard], features: [DOSSIERS_ARCHIVE], }, }, @@ -150,9 +147,9 @@ const mainRoutes: IqserRoutes = [ { path: 'search', loadChildren: () => import('./modules/search/search.module').then(m => m.SearchModule), - canActivate: [CompositeRouteGuard, IqserPermissionsGuard], + canActivate: [CompositeRouteGuard, IqserPermissionsGuard, loadAllDossiersGuard()], data: { - routeGuards: [IqserAuthGuard, RedRoleGuard, DossiersGuard], + routeGuards: [IqserAuthGuard, RedRoleGuard], permissions: { allow: [Roles.search], redirectTo: '/auth-error', @@ -162,10 +159,9 @@ const mainRoutes: IqserRoutes = [ { path: 'trash', loadChildren: () => import('./modules/trash/trash.module').then(m => m.TrashModule), - canActivate: [CompositeRouteGuard, IqserPermissionsGuard], + canActivate: [CompositeRouteGuard, IqserPermissionsGuard, loadActiveDossiersGuard()], data: { - routeGuards: [IqserAuthGuard, RedRoleGuard, DossiersGuard, TrashGuard], - dossiersService: ACTIVE_DOSSIERS_SERVICE, + routeGuards: [IqserAuthGuard, RedRoleGuard, TrashGuard], permissions: { allow: [Roles.dossiers.read, Roles.files.readStatus], redirectTo: '/auth-error', diff --git a/apps/red-ui/src/app/guards/dossiers.guard.ts b/apps/red-ui/src/app/guards/dossiers.guard.ts index 35632190f..01be634ee 100644 --- a/apps/red-ui/src/app/guards/dossiers.guard.ts +++ b/apps/red-ui/src/app/guards/dossiers.guard.ts @@ -1,45 +1,57 @@ -import { Injectable, Injector, ProviderToken } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; -import { firstValueFrom, forkJoin } from 'rxjs'; -import { take } from 'rxjs/operators'; +import { inject } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivateFn, Router } from '@angular/router'; +import { firstValueFrom } from 'rxjs'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; import { ArchivedDossiersService } from '@services/dossiers/archived-dossiers.service'; -import { DossiersService } from '@services/dossiers/dossiers.service'; -import { ARCHIVE_ROUTE, DOSSIER_TEMPLATE_ID } from '@red/domain'; +import { DOSSIER_TEMPLATE_ID } from '@red/domain'; import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service'; import { TenantsService } from '@iqser/common-ui/lib/tenants'; +import { NGXLogger } from 'ngx-logger'; +import { ACTIVE_DOSSIERS_SERVICE, ARCHIVED_DOSSIERS_SERVICE } from '../tokens'; -@Injectable({ providedIn: 'root' }) -export class DossiersGuard implements CanActivate { - constructor( - private readonly _injector: Injector, - private readonly _router: Router, - private readonly _tenantsService: TenantsService, - private readonly _dashboardStatsService: DashboardStatsService, - private readonly _activeDossiersService: ActiveDossiersService, - private readonly _archivedDossiersService: ArchivedDossiersService, - ) {} +export function loadAllDossiersGuard(): CanActivateFn { + return async () => { + const logger = inject(NGXLogger); + logger.info('[GUARDS] loadAllDossiersGuard start'); - async canActivate(route: ActivatedRouteSnapshot): Promise { - const token: ProviderToken = route.data.dossiersService; - if (!token) { - const services = [this._archivedDossiersService, this._activeDossiersService]; - const loading$ = forkJoin(services.map(service => service.loadAll().pipe(take(1)))); - await firstValueFrom(loading$); - return true; - } + const services = [inject(ArchivedDossiersService), inject(ActiveDossiersService)]; + const requests = services.map(service => firstValueFrom(service.loadAll())); + await Promise.all(requests); - const dossiersService: DossiersService = this._injector.get(token); - const isArchive = dossiersService.routerPath === ARCHIVE_ROUTE; + logger.info('[GUARDS] loadAllDossiersGuard end'); + return true; + }; +} + +export function loadActiveDossiersGuard(): CanActivateFn { + return async () => { + const logger = inject(NGXLogger); + logger.info('[GUARDS] loadDossiersGuard start'); + + await firstValueFrom(inject(ACTIVE_DOSSIERS_SERVICE).loadAll()); + + logger.info('[GUARDS] loadDossiersGuard end'); + return true; + }; +} + +export function loadArchivedDossiersGuard(): CanActivateFn { + return async (route: ActivatedRouteSnapshot) => { + const logger = inject(NGXLogger); + logger.info('[GUARDS] loadArchivedDossiersGuard start'); + + const dossiersService = inject(ARCHIVED_DOSSIERS_SERVICE); const dossierTemplateId = route.paramMap.get(DOSSIER_TEMPLATE_ID); - const dossierTemplateStats = this._dashboardStatsService.find(dossierTemplateId); + const dossierTemplateStats = inject(DashboardStatsService).find(dossierTemplateId); - if (isArchive && dossierTemplateStats?.numberOfArchivedDossiers === 0) { - await this._router.navigate([this._tenantsService.activeTenantId, 'main', dossierTemplateId, 'dossiers']); + if (dossierTemplateStats?.numberOfArchivedDossiers === 0) { + logger.info('[GUARDS] loadArchivedDossiersGuard no archived dossiers, redirect to active dossiers page'); + await inject(Router).navigate([inject(TenantsService).activeTenantId, 'main', dossierTemplateId, 'dossiers']); return false; } await firstValueFrom(dossiersService.loadAll()); + logger.info('[GUARDS] loadArchivedDossiersGuard end'); return true; - } + }; } diff --git a/apps/red-ui/src/app/guards/if-logged-in.guard.ts b/apps/red-ui/src/app/guards/if-logged-in.guard.ts index dc2631dbd..91a51e440 100644 --- a/apps/red-ui/src/app/guards/if-logged-in.guard.ts +++ b/apps/red-ui/src/app/guards/if-logged-in.guard.ts @@ -9,7 +9,7 @@ import { LicenseService } from '@services/license.service'; export function ifLoggedIn(): CanActivateFn { return async (route: ActivatedRouteSnapshot) => { const logger = inject(NGXLogger); - logger.info('[ROUTES] Check if can activate main'); + logger.info('[ROUTES] Check if can activate route', route); const tenantsService = inject(TenantsService); const keycloakService = inject(KeycloakService); diff --git a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.html index c0a2d0a50..defe51978 100644 --- a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.html @@ -1,5 +1,5 @@
-
+
@@ -54,30 +54,30 @@
-
+
-
+
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 da2646e18..fb61214bb 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 @@ -11,7 +11,7 @@ import { TemplateRef, ViewChild, } from '@angular/core'; -import { ActivatedRoute, ActivatedRouteSnapshot, NavigationExtras, Router } from '@angular/router'; +import { ActivatedRouteSnapshot, NavigationExtras, Router } from '@angular/router'; import { CircleButtonTypes, ConfirmOption, @@ -20,6 +20,7 @@ import { ErrorService, HelpModeService, IConfirmationDialogData, + IqserDialog, LoadingService, Toaster, } from '@iqser/common-ui'; @@ -63,7 +64,6 @@ import { ConfigService } from '@services/config.service'; import { ReadableRedactionsService } from '../pdf-viewer/services/readable-redactions.service'; import { Roles } from '@users/roles'; import { SuggestionsService } from './services/suggestions.service'; -import { IqserDialog } from '../../../../../../libs/common-ui/src/lib/dialog/iqser-dialog.service'; import { RedactTextDialogComponent } from './dialogs/redact-text-dialog/redact-text-dialog.component'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { copyLocalStorageFiltersValues, FilterService, NestedFilter, processFilters } from '@iqser/common-ui/lib/filtering'; @@ -108,7 +108,6 @@ export class FilePreviewScreenComponent private readonly _annotationManager: REDAnnotationManager, private readonly _errorService: ErrorService, private readonly _filterService: FilterService, - private readonly _activatedRoute: ActivatedRoute, private readonly _loadingService: LoadingService, private readonly _filesMapService: FilesMapService, private readonly _dossiersService: DossiersService, @@ -161,6 +160,7 @@ export class FilePreviewScreenComponent effect(() => { const selectedText = this._documentViewer.selectedText(); + console.log('selectedText', selectedText); const canPerformActions = this.pdfProxyService.canPerformActions(); const isCurrentPageExcluded = this.state.file().isPageExcluded(this.pdf.currentPage()); diff --git a/apps/red-ui/src/app/modules/pdf-viewer/pdf-viewer.component.html b/apps/red-ui/src/app/modules/pdf-viewer/pdf-viewer.component.html index 0df39e49d..3fd4bcd55 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/pdf-viewer.component.html +++ b/apps/red-ui/src/app/modules/pdf-viewer/pdf-viewer.component.html @@ -1,5 +1,3 @@ -
- diff --git a/apps/red-ui/src/app/modules/pdf-viewer/pdf-viewer.component.scss b/apps/red-ui/src/app/modules/pdf-viewer/pdf-viewer.component.scss index 37792961d..e69de29bb 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/pdf-viewer.component.scss +++ b/apps/red-ui/src/app/modules/pdf-viewer/pdf-viewer.component.scss @@ -1,12 +0,0 @@ -:host { - --workload-width: 350px; - --header-height: calc(var(--iqser-top-bar-height) + 50px); -} - -div { - width: calc(100% - var(--workload-width)); - height: calc(100% - var(--header-height)); - bottom: 0; - left: 0; - position: absolute; -} diff --git a/apps/red-ui/src/app/modules/pdf-viewer/pdf-viewer.module.ts b/apps/red-ui/src/app/modules/pdf-viewer/pdf-viewer.module.ts index d49e497f6..7af623aba 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/pdf-viewer.module.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/pdf-viewer.module.ts @@ -11,7 +11,6 @@ import { PaginatorComponent } from './components/paginator/paginator.component'; import { MatIconModule } from '@angular/material/icon'; import { AnnotationDrawService } from './services/annotation-draw.service'; import { REDDocumentViewer } from './services/document-viewer.service'; -import { WebViewerLoadedGuard } from './services/webviewer-loaded.guard'; import { ReadableRedactionsService } from './services/readable-redactions.service'; @NgModule({ @@ -27,7 +26,6 @@ import { ReadableRedactionsService } from './services/readable-redactions.servic ReadableRedactionsService, ViewerHeaderService, AnnotationDrawService, - WebViewerLoadedGuard, ], }) export class PdfViewerModule {} diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts index 65724b262..7561fc1ce 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts @@ -1,4 +1,4 @@ -import { inject, Injectable, NgZone, Signal, signal } from '@angular/core'; +import { effect, inject, Injectable, Signal, signal } from '@angular/core'; import { Core } from '@pdftron/webviewer'; import { NGXLogger } from 'ngx-logger'; import { fromEvent, Observable } from 'rxjs'; @@ -25,7 +25,6 @@ export class REDDocumentViewer { readonly #userPreferenceService = inject(UserPreferenceService); readonly #pdf = inject(PdfViewer); readonly #activatedRoute = inject(ActivatedRoute); - readonly #ngZone = inject(NgZone); readonly loaded$: Observable; keyUp$: Observable; readonly selectedText: Signal; @@ -37,6 +36,21 @@ export class REDDocumentViewer { this.loaded$ = toObservable(this.#loaded); this.pageComplete = this.#pageComplete.asReadonly(); this.selectedText = this.#selectedText.asReadonly(); + + effect(() => { + const viewerElement = document.getElementById('viewer'); + if (!viewerElement) { + return; + } + + if (this.loaded()) { + this.#logger.info('[PDF] Show viewer'); + viewerElement.style.visibility = 'visible'; + } else { + this.#logger.info('[PDF] Hide viewer'); + viewerElement.style.visibility = 'hidden'; + } + }); } get PDFDoc() { diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/webviewer-loaded.guard.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/webviewer-loaded.guard.ts index 62feb6842..6278b91af 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/webviewer-loaded.guard.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/webviewer-loaded.guard.ts @@ -1,41 +1,42 @@ -import { Injectable } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { inject } from '@angular/core'; +import { CanActivateFn, ResolveFn, Router } from '@angular/router'; import { REDDocumentViewer } from './document-viewer.service'; import { PdfViewer } from './pdf-viewer.service'; import { REDAnnotationManager } from './annotation-manager.service'; import { ViewerHeaderService } from './viewer-header.service'; import { LoadingService } from '@iqser/common-ui'; import { WebViewerInstance } from '@pdftron/webviewer'; +import { NGXLogger } from 'ngx-logger'; +import { DOCUMENT } from '@angular/common'; -@Injectable() -export class WebViewerLoadedGuard implements CanActivate { - constructor( - private readonly _documentViewer: REDDocumentViewer, - private readonly _pdf: PdfViewer, - private readonly _router: Router, - private readonly _annotationManager: REDAnnotationManager, - private readonly _viewerHeaderService: ViewerHeaderService, - private readonly _loadingService: LoadingService, - ) {} +export function webViewerLoadedGuard(): CanActivateFn | ResolveFn { + return async (_, state) => { + const pdf = inject(PdfViewer); + const logger = inject(NGXLogger); - async canActivate(_, state) { - if (this._pdf.instance) { + if (pdf.instance) { + logger.info('[PDF] WebViewerGuard already loaded.'); return true; } - this._loadingService.start(); + inject(LoadingService).start(); + const router = inject(Router); + const annotationManager = inject(REDAnnotationManager); + const documentViewer = inject(REDDocumentViewer); + const viewerHeaderService = inject(ViewerHeaderService); let instance: WebViewerInstance | undefined; try { - instance = await this._pdf.init(document.getElementById('viewer')); - } catch { - return this._router.navigateByUrl(state.url); + instance = await pdf.init(inject(DOCUMENT).getElementById('viewer')); + } catch (e) { + logger.warn('[PDF] WebViewerGuard error: ', e, 'redirecting to', state.url); + return router.navigateByUrl(state.url); } - this._annotationManager.init(instance.Core.annotationManager); - this._documentViewer.init(instance.Core.documentViewer); - this._viewerHeaderService.init(); + annotationManager.init(instance.Core.annotationManager); + documentViewer.init(instance.Core.documentViewer); + viewerHeaderService.init(); - return !!this._pdf.instance; - } + return !!pdf.instance; + }; } diff --git a/apps/red-ui/src/index.html b/apps/red-ui/src/index.html index e54d15cff..52dbffae2 100644 --- a/apps/red-ui/src/index.html +++ b/apps/red-ui/src/index.html @@ -10,6 +10,7 @@ +
diff --git a/apps/red-ui/src/styles.scss b/apps/red-ui/src/styles.scss index c05edc9ac..716f736f0 100644 --- a/apps/red-ui/src/styles.scss +++ b/apps/red-ui/src/styles.scss @@ -143,3 +143,11 @@ $dark-accent-10: darken(vars.$accent, 10%); $iqser-app-name-font-size: 13px, $iqser-app-name-color: vars.$white ); + +#viewer { + width: calc(100% - 350px); + height: calc(100% - calc(var(--iqser-top-bar-height) + 50px)); + bottom: 0; + left: 0; + position: absolute; +}