From 0db227c70fe9d63301a706634fd8bf0c88779dc8 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Thu, 18 May 2023 12:24:11 +0300 Subject: [PATCH] RED-6713: remove tenants context holder --- apps/red-ui/src/app/app-routing.module.ts | 12 +-- .../base-screen/base-screen.component.ts | 37 +++++---- .../src/app/guards/dossier-files-guard.ts | 10 +-- .../guards/dossier-template-exists.guard.ts | 52 ++++++------- apps/red-ui/src/app/guards/dossiers.guard.ts | 6 +- .../app/guards/entity-exists-guard.service.ts | 26 +++---- .../src/app/guards/watermark-exists.guard.ts | 25 +++--- .../app/modules/admin/admin-routing.module.ts | 11 ++- .../base-entity-screen.component.ts | 6 +- .../watermark-screen.component.ts | 6 +- .../screens/watermark/watermark.module.ts | 6 +- .../admin-side-nav.component.ts | 10 +-- .../dossier-template-actions.component.ts | 10 +-- ...sier-overview-screen-header.component.html | 8 +- ...ossier-overview-screen-header.component.ts | 4 +- .../services/bulk-actions.service.ts | 8 +- .../file-preview-screen.component.ts | 9 +-- .../file-actions/file-actions.component.ts | 76 +++++++++---------- .../edit-dossier-dictionary.component.ts | 10 +-- .../edit-dossier-general-info.component.ts | 10 +-- .../file-download-btn.component.ts | 6 +- .../expandable-file-actions.component.ts | 13 +--- .../add-dossier-dialog.component.ts | 6 +- .../services/file-download.service.ts | 6 +- .../dossiers/archived-dossiers.service.ts | 8 +- .../entity-services/dictionary.service.ts | 33 ++++---- .../src/app/services/notifications.service.ts | 8 +- .../src/app/services/reanalysis.service.ts | 17 +++-- .../app/services/router-history.service.ts | 6 +- apps/red-ui/src/app/users/red-role.guard.ts | 15 ++-- apps/red-ui/src/app/utils/main.resolver.ts | 6 +- libs/common-ui | 2 +- 32 files changed, 210 insertions(+), 258 deletions(-) diff --git a/apps/red-ui/src/app/app-routing.module.ts b/apps/red-ui/src/app/app-routing.module.ts index f39e3d8b4..d856101fd 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -8,7 +8,7 @@ import { IqserAuthGuard, IqserPermissionsGuard, IqserRoutes, - TenantResolveComponent, + TenantSelectComponent, } from '@iqser/common-ui'; import { RedRoleGuard } from '@users/red-role.guard'; import { BaseScreenComponent } from '@components/base-screen/base-screen.component'; @@ -19,7 +19,7 @@ import { DossiersGuard } from '@guards/dossiers.guard'; import { ACTIVE_DOSSIERS_SERVICE, ARCHIVED_DOSSIERS_SERVICE } from './tokens'; import { FeaturesGuard } from '@guards/features-guard.service'; import { DossierTemplatesGuard } from '@guards/dossier-templates.guard'; -import { DossierTemplateExistsGuard } from '@guards/dossier-template-exists.guard'; +import { templateExistsWhenEnteringDossierList } from '@guards/dossier-template-exists.guard'; 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'; @@ -180,9 +180,9 @@ const mainRoutes: IqserRoutes = [ { path: `:${DOSSIER_TEMPLATE_ID}`, children: dossierTemplateIdRoutes, - canActivate: [CompositeRouteGuard, IqserPermissionsGuard], + canActivate: [CompositeRouteGuard, IqserPermissionsGuard, templateExistsWhenEnteringDossierList()], data: { - routeGuards: [IqserAuthGuard, RedRoleGuard, DossierTemplatesGuard, DashboardGuard, DossierTemplateExistsGuard], + routeGuards: [IqserAuthGuard, RedRoleGuard, DossierTemplatesGuard, DashboardGuard], permissions: { allow: [ ROLES.any, @@ -211,7 +211,7 @@ const routes: IqserRoutes = [ path: '', pathMatch: 'full', canActivate: [ifNotLoggedIn], - component: TenantResolveComponent, + component: TenantSelectComponent, }, { path: ':tenant', @@ -240,7 +240,7 @@ const routes: IqserRoutes = [ ]; @NgModule({ - imports: [RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled' })], + imports: [RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled', bindToComponentInputs: true })], providers: [{ provide: RouteReuseStrategy, useExisting: CustomRouteReuseStrategy }], exports: [RouterModule], }) diff --git a/apps/red-ui/src/app/components/base-screen/base-screen.component.ts b/apps/red-ui/src/app/components/base-screen/base-screen.component.ts index 27a80eb9b..5b96bb85e 100644 --- a/apps/red-ui/src/app/components/base-screen/base-screen.component.ts +++ b/apps/red-ui/src/app/components/base-screen/base-screen.component.ts @@ -7,7 +7,7 @@ import { TranslateService } from '@ngx-translate/core'; import { SpotlightSearchAction } from '@components/spotlight-search/spotlight-search-action'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { filter, map, startWith } from 'rxjs/operators'; -import { BASE_HREF, IqserPermissionsService, shareDistinctLast, TenantContextHolder, TenantsService } from '@iqser/common-ui'; +import { BASE_HREF, IqserPermissionsService, List, shareDistinctLast, TenantsService } from '@iqser/common-ui'; import { BreadcrumbsService } from '@services/breadcrumbs.service'; import { FeaturesService } from '@services/features.service'; import { ARCHIVE_ROUTE, DOSSIERS_ARCHIVE, DOSSIERS_ROUTE } from '@red/domain'; @@ -32,7 +32,6 @@ const isSearchScreen: (url: string) => boolean = url => url.includes('/search'); }) export class BaseScreenComponent { readonly roles = ROLES; - readonly tenantContext = inject(TenantsService); readonly documentViewer = inject(REDDocumentViewer); readonly currentUser = this.userService.currentUser; readonly userMenuItems: readonly MenuItem[] = [ @@ -64,42 +63,42 @@ export class BaseScreenComponent { id: 'select-tenant', name: _('top-bar.navigation-items.my-account.children.select-tenant'), action: () => this.selectTenant(), - show: this.tenantContext.hasMultipleTenants, + show: this._tenantsService.hasMultiple(), }, ]; - readonly searchActions: readonly SpotlightSearchAction[] = [ + readonly searchActions: List = [ { text: this._translateService.instant('search.this-dossier'), icon: 'red:enter', - hide: (): boolean => this._hideSearchThisDossier, - action: (query): void => this._searchThisDossier(query), + hide: (): boolean => this.#hideSearchThisDossier, + action: (query): void => this.#searchThisDossier(query), }, { text: this._translateService.instant('search.active-dossiers'), icon: 'red:enter', hide: () => !this._featuresService.isEnabled(DOSSIERS_ARCHIVE), - action: (query): void => this._search(query, [], true), + action: (query): void => this.#search(query, [], true), }, { text: this._translateService.instant('search.all-dossiers'), icon: 'red:enter', - action: (query): void => this._search(query, []), + action: (query): void => this.#search(query, []), }, ]; - private readonly _baseHref = inject(BASE_HREF); - private readonly _navigationStart$ = this._router.events.pipe( + readonly #baseHref = inject(BASE_HREF); + readonly #navigationStart$ = this._router.events.pipe( filter(isNavigationStart), map((event: NavigationStart) => event.url), startWith(this._router.url), shareDistinctLast(), ); - readonly isSearchScreen$ = this._navigationStart$.pipe(map(isSearchScreen)); + readonly isSearchScreen$ = this.#navigationStart$.pipe(map(isSearchScreen)); constructor( private readonly _router: Router, private readonly _translateService: TranslateService, private readonly _featuresService: FeaturesService, - private readonly _tenantContextHolder: TenantContextHolder, + private readonly _tenantsService: TenantsService, readonly permissionsService: IqserPermissionsService, readonly userService: UserService, readonly userPreferenceService: UserPreferenceService, @@ -107,7 +106,7 @@ export class BaseScreenComponent { readonly breadcrumbsService: BreadcrumbsService, ) {} - private get _hideSearchThisDossier() { + get #hideSearchThisDossier() { const routerLink = this.breadcrumbsService.breadcrumbs[1]?.options?.routerLink; if (!routerLink) { return true; @@ -122,20 +121,20 @@ export class BaseScreenComponent { } selectTenant() { - window.open(window.location.origin + this._baseHref, '_blank'); + window.open(window.location.origin + this.#baseHref, '_blank'); } - private _search(query: string, dossierIds: string[], onlyActive = false) { + #search(query: string, dossierIds: string[], onlyActive = false) { const queryParams = { query, dossierIds: dossierIds.join(','), onlyActive }; - this._router.navigate([`/${this._tenantContextHolder.currentTenant}/main/search`], { queryParams }).then(); + this._router.navigate([`/${this._tenantsService.currentTenant}/main/search`], { queryParams }).then(); } - private _searchThisDossier(query: string) { + #searchThisDossier(query: string) { const routerLink = this.breadcrumbsService.breadcrumbs[1]?.options?.routerLink; if (!routerLink) { - return this._search(query, []); + return this.#search(query, []); } const dossierId = routerLink[2]; - return this._search(query, [dossierId]); + return this.#search(query, [dossierId]); } } diff --git a/apps/red-ui/src/app/guards/dossier-files-guard.ts b/apps/red-ui/src/app/guards/dossier-files-guard.ts index 26eb26a69..06acc0426 100644 --- a/apps/red-ui/src/app/guards/dossier-files-guard.ts +++ b/apps/red-ui/src/app/guards/dossier-files-guard.ts @@ -7,13 +7,13 @@ import { DOSSIER_ID, DOSSIER_TEMPLATE_ID } from '@red/domain'; import { DossiersService } from '@services/dossiers/dossiers.service'; import { DictionaryService } from '@services/entity-services/dictionary.service'; import { DossierDictionariesMapService } from '@services/entity-services/dossier-dictionaries-map.service'; -import { TenantContextHolder } from '@iqser/common-ui'; +import { TenantsService } from '@iqser/common-ui'; @Injectable({ providedIn: 'root' }) export class DossierFilesGuard implements CanActivate { constructor( private readonly _injector: Injector, - private readonly _tenantContextHolder: TenantContextHolder, + private readonly _tenantsService: TenantsService, private readonly _filesMapService: FilesMapService, private readonly _filesService: FilesService, private readonly _dictionaryService: DictionaryService, @@ -34,7 +34,7 @@ export class DossierFilesGuard implements CanActivate { } if (!dossiersService.has(dossierId)) { - await this._router.navigate([`/${this._tenantContextHolder.currentTenant}/main`, dossierTemplateId]); + await this._router.navigate([`/${this._tenantsService.currentTenant}/main`, dossierTemplateId]); return false; } @@ -46,8 +46,8 @@ export class DossierFilesGuard implements CanActivate { const promises = []; if (!this._dictionaryMapService.has(dossierId)) { - const dictionary$ = this._dictionaryService.loadDossierDictionary(dossierTemplateId, dossierId); - promises.push(firstValueFrom(dictionary$)); + const dictionaryPromise = this._dictionaryService.loadDossierDictionary(dossierTemplateId, dossierId); + promises.push(dictionaryPromise); } if (!this._filesMapService.has(dossierId)) { diff --git a/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts b/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts index c8c89856b..bc4c3a684 100644 --- a/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts +++ b/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts @@ -1,37 +1,31 @@ -import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; +import { inject } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivateFn, Router } from '@angular/router'; import { DOSSIER_TEMPLATE_ID } from '@red/domain'; import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service'; -import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; -import { TenantContextHolder } from '@iqser/common-ui'; +import { TenantsService } from '@iqser/common-ui'; -@Injectable({ providedIn: 'root' }) -export class DossierTemplateExistsGuard implements CanActivate { - constructor( - private readonly _dashboardStatsService: DashboardStatsService, - private readonly _tenantContextHolder: TenantContextHolder, - private readonly _dossierTemplatesService: DossierTemplatesService, - private readonly _router: Router, - ) {} - - async canActivate(route: ActivatedRouteSnapshot): Promise { +export function templateExistsWhenEnteringAdmin(): CanActivateFn { + return async function (route: ActivatedRouteSnapshot): Promise { const dossierTemplateId: string = route.paramMap.get(DOSSIER_TEMPLATE_ID); - const dossiersListView = !route.pathFromRoot.find(r => r.routeConfig?.path === 'admin'); - if (dossiersListView) { - const dossierTemplateStats = this._dashboardStatsService.find(dossierTemplateId); - if (!dossierTemplateStats || dossierTemplateStats.isEmpty) { - await this._router.navigate([`/${this._tenantContextHolder.currentTenant}/main`]); - return false; - } - } else { - const dossierTemplate = this._dossierTemplatesService.find(dossierTemplateId); - if (!dossierTemplate) { - await this._router.navigate([this._tenantContextHolder.currentTenant, 'main', 'admin', 'dossier-templates']); - return false; - } + const dossierTemplate = inject(DashboardStatsService).find(dossierTemplateId); + if (!dossierTemplate) { + await inject(Router).navigate([inject(TenantsService).currentTenant, 'main', 'admin', 'dossier-templates']); + return false; } - return true; - } + }; +} + +export function templateExistsWhenEnteringDossierList(): CanActivateFn { + return async function (route: ActivatedRouteSnapshot) { + const dossierTemplateId: string = route.paramMap.get(DOSSIER_TEMPLATE_ID); + + const dossierTemplateStats = inject(DashboardStatsService).find(dossierTemplateId); + if (!dossierTemplateStats || dossierTemplateStats.isEmpty) { + await inject(Router).navigate([inject(TenantsService).currentTenant, 'main']); + return false; + } + return true; + }; } diff --git a/apps/red-ui/src/app/guards/dossiers.guard.ts b/apps/red-ui/src/app/guards/dossiers.guard.ts index 9f634a252..ff8902584 100644 --- a/apps/red-ui/src/app/guards/dossiers.guard.ts +++ b/apps/red-ui/src/app/guards/dossiers.guard.ts @@ -7,14 +7,14 @@ import { ArchivedDossiersService } from '@services/dossiers/archived-dossiers.se import { DossiersService } from '@services/dossiers/dossiers.service'; import { ARCHIVE_ROUTE, DOSSIER_TEMPLATE_ID } from '@red/domain'; import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service'; -import { TenantContextHolder } from '@iqser/common-ui'; +import { TenantsService } from '@iqser/common-ui'; @Injectable({ providedIn: 'root' }) export class DossiersGuard implements CanActivate { constructor( private readonly _injector: Injector, private readonly _router: Router, - private readonly _tenantContextHolder: TenantContextHolder, + private readonly _tenantsService: TenantsService, private readonly _dashboardStatsService: DashboardStatsService, private readonly _activeDossiersService: ActiveDossiersService, private readonly _archivedDossiersService: ArchivedDossiersService, @@ -35,7 +35,7 @@ export class DossiersGuard implements CanActivate { const dossierTemplateStats = this._dashboardStatsService.find(dossierTemplateId); if (isArchive && dossierTemplateStats?.numberOfArchivedDossiers === 0) { - await this._router.navigate([this._tenantContextHolder.currentTenant, 'main', dossierTemplateId, 'dossiers']); + await this._router.navigate([this._tenantsService.currentTenant, 'main', dossierTemplateId, 'dossiers']); return false; } diff --git a/apps/red-ui/src/app/guards/entity-exists-guard.service.ts b/apps/red-ui/src/app/guards/entity-exists-guard.service.ts index 704230c3e..4d1e6c9ca 100644 --- a/apps/red-ui/src/app/guards/entity-exists-guard.service.ts +++ b/apps/red-ui/src/app/guards/entity-exists-guard.service.ts @@ -1,29 +1,21 @@ -import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; +import { inject } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivateFn, Router } from '@angular/router'; import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@red/domain'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; -import { TenantContextHolder } from '@iqser/common-ui'; +import { TenantsService } from '@iqser/common-ui'; -@Injectable({ providedIn: 'root' }) -export class EntityExistsGuard implements CanActivate { - constructor( - private readonly _dictionariesMapService: DictionariesMapService, - private readonly _router: Router, - private readonly _dossierTemplatesService: DossierTemplatesService, - private readonly _tenantContextHolder: TenantContextHolder, - ) {} - - async canActivate(route: ActivatedRouteSnapshot): Promise { +export function entityExistsGuard(): CanActivateFn { + return async function (route: ActivatedRouteSnapshot): Promise { const dossierTemplateId = route.paramMap.get(DOSSIER_TEMPLATE_ID); const type = route.paramMap.get(ENTITY_TYPE); - if (!this._dictionariesMapService.get(dossierTemplateId, type)) { - const dossierTemplate = this._dossierTemplatesService.find(dossierTemplateId); - await this._router.navigate([`/${this._tenantContextHolder.currentTenant}/${dossierTemplate.routerLink}/entities`]); + if (!inject(DictionariesMapService).get(dossierTemplateId, type)) { + const dossierTemplate = inject(DossierTemplatesService).find(dossierTemplateId); + await inject(Router).navigate([`/${inject(TenantsService).currentTenant}/${dossierTemplate.routerLink}/entities`]); return false; } return true; - } + }; } diff --git a/apps/red-ui/src/app/guards/watermark-exists.guard.ts b/apps/red-ui/src/app/guards/watermark-exists.guard.ts index 0e0e6c6e9..2813d803c 100644 --- a/apps/red-ui/src/app/guards/watermark-exists.guard.ts +++ b/apps/red-ui/src/app/guards/watermark-exists.guard.ts @@ -1,27 +1,20 @@ -import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; +import { inject } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivateFn, Router } from '@angular/router'; import { WatermarksMapService } from '@services/entity-services/watermarks-map.service'; import { DOSSIER_TEMPLATE_ID, WATERMARK_ID } from '@red/domain'; -import { TenantContextHolder } from '@iqser/common-ui'; +import { TenantsService } from '@iqser/common-ui'; -@Injectable({ providedIn: 'root' }) -export class WatermarkExistsGuard implements CanActivate { - constructor( - private readonly _watermarksMapService: WatermarksMapService, - private readonly _tenantContextHolder: TenantContextHolder, - private readonly _router: Router, - ) {} - - async canActivate(route: ActivatedRouteSnapshot): Promise { +export function watermarkExistsGuard(): CanActivateFn { + return async function (route: ActivatedRouteSnapshot) { const dossierTemplateId = route.parent.paramMap.get(DOSSIER_TEMPLATE_ID); const watermarkId = Number(route.paramMap.get(WATERMARK_ID)); - if (this._watermarksMapService.get(dossierTemplateId, watermarkId)) { + if (inject(WatermarksMapService).get(dossierTemplateId, watermarkId)) { return true; } - await this._router.navigate([ - this._tenantContextHolder.currentTenant, + await inject(Router).navigate([ + inject(TenantsService).currentTenant, 'main', 'admin', 'dossier-templates', @@ -29,5 +22,5 @@ export class WatermarkExistsGuard implements CanActivate { 'watermarks', ]); return false; - } + }; } diff --git a/apps/red-ui/src/app/modules/admin/admin-routing.module.ts b/apps/red-ui/src/app/modules/admin/admin-routing.module.ts index 7492cccfa..17b960c77 100644 --- a/apps/red-ui/src/app/modules/admin/admin-routing.module.ts +++ b/apps/red-ui/src/app/modules/admin/admin-routing.module.ts @@ -13,8 +13,8 @@ import { BaseAdminScreenComponent } from './base-admin-screen/base-admin-screen. import { BaseDossierTemplateScreenComponent } from './base-dossier-templates-screen/base-dossier-template-screen.component'; import { DossierTemplatesGuard } from '@guards/dossier-templates.guard'; import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@red/domain'; -import { DossierTemplateExistsGuard } from '@guards/dossier-template-exists.guard'; -import { EntityExistsGuard } from '@guards/entity-exists-guard.service'; +import { templateExistsWhenEnteringAdmin } from '@guards/dossier-template-exists.guard'; +import { entityExistsGuard } from '@guards/entity-exists-guard.service'; import { BaseEntityScreenComponent } from './base-entity-screen/base-entity-screen.component'; import { PermissionsGuard } from '@guards/permissions-guard'; import { ROLES } from '@users/roles'; @@ -39,10 +39,10 @@ const dossierTemplateIdRoutes: IqserRoutes = [ { path: `:${ENTITY_TYPE}`, component: BaseEntityScreenComponent, - canActivate: [CompositeRouteGuard], + canActivate: [CompositeRouteGuard, entityExistsGuard()], loadChildren: () => import('./screens/entities/entities.module').then(m => m.EntitiesModule), data: { - routeGuards: [IqserAuthGuard, RedRoleGuard, EntityExistsGuard], + routeGuards: [IqserAuthGuard, RedRoleGuard], }, }, ], @@ -141,8 +141,7 @@ const dossierTemplatesRoutes: IqserRoutes = [ { path: `:${DOSSIER_TEMPLATE_ID}`, children: dossierTemplateIdRoutes, - canActivate: [CompositeRouteGuard], - data: { routeGuards: [DossierTemplateExistsGuard] }, + canActivate: [templateExistsWhenEnteringAdmin()], }, ]; diff --git a/apps/red-ui/src/app/modules/admin/base-entity-screen/base-entity-screen.component.ts b/apps/red-ui/src/app/modules/admin/base-entity-screen/base-entity-screen.component.ts index 3292ce08e..429607f02 100644 --- a/apps/red-ui/src/app/modules/admin/base-entity-screen/base-entity-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/base-entity-screen/base-entity-screen.component.ts @@ -4,7 +4,7 @@ import { Router } from '@angular/router'; import { firstValueFrom, Observable } from 'rxjs'; import { AdminDialogService } from '../services/admin-dialog.service'; import { DictionaryService } from '@services/entity-services/dictionary.service'; -import { getParam, LoadingService, TenantContextHolder } from '@iqser/common-ui'; +import { getParam, LoadingService, TenantsService } from '@iqser/common-ui'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import { map } from 'rxjs/operators'; @@ -27,7 +27,7 @@ export class BaseEntityScreenComponent { private readonly _dialogService: AdminDialogService, private readonly _dictionaryService: DictionaryService, private readonly _permissionsService: PermissionsService, - private readonly _tenantContextHolder: TenantContextHolder, + private readonly _tenantsService: TenantsService, private readonly _dossierTemplatesService: DossierTemplatesService, ) { const entity$ = dictionaryMapService.watch$(this.#dossierTemplateId, this.#entityType); @@ -42,7 +42,7 @@ export class BaseEntityScreenComponent { this._loadingService.start(); const dossierTemplate = this._dossierTemplatesService.find(this.#dossierTemplateId); await firstValueFrom(this._dictionaryService.deleteDictionaries([this.#entityType], this.#dossierTemplateId)); - await this._router.navigate([`/${this._tenantContextHolder.currentTenant}/${dossierTemplate.routerLink}/entities`]); + await this._router.navigate([`/${this._tenantsService.currentTenant}/${dossierTemplate.routerLink}/entities`]); this._loadingService.stop(); }); } diff --git a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.ts index d89c12eb8..410a97223 100644 --- a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.ts @@ -11,7 +11,7 @@ import { IconButtonTypes, IqserPermissionsService, LoadingService, - TenantContextHolder, + TenantsService, Toaster, } from '@iqser/common-ui'; import { DOSSIER_TEMPLATE_ID, type IWatermark, type User, WATERMARK_ID, WatermarkOrientation, WatermarkOrientations } from '@red/domain'; @@ -77,7 +77,7 @@ export class WatermarkScreenComponent implements OnInit { private readonly _formBuilder: FormBuilder, readonly permissionsService: IqserPermissionsService, private readonly _loadingService: LoadingService, - private readonly _tenantContextHolder: TenantContextHolder, + private readonly _tenantsService: TenantsService, private readonly _licenseService: LicenseService, private readonly _watermarkService: WatermarkService, private readonly _userPreferenceService: UserPreferenceService, @@ -151,7 +151,7 @@ export class WatermarkScreenComponent implements OnInit { ); if (!watermark.id) { await this._router.navigate([ - `/${this._tenantContextHolder.currentTenant}/main/admin/dossier-templates/${this.#dossierTemplateId}/watermarks/${ + `/${this._tenantsService.currentTenant}/main/admin/dossier-templates/${this.#dossierTemplateId}/watermarks/${ updatedWatermark.id }`, ]); diff --git a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark.module.ts b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark.module.ts index e9a28af4f..02c8c9e28 100644 --- a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark.module.ts +++ b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark.module.ts @@ -18,7 +18,7 @@ import { } from '@iqser/common-ui'; import { RedRoleGuard } from '@users/red-role.guard'; import { WATERMARK_ID } from '@red/domain'; -import { WatermarkExistsGuard } from '@guards/watermark-exists.guard'; +import { watermarkExistsGuard } from '@guards/watermark-exists.guard'; import { TranslateModule } from '@ngx-translate/core'; import { PaginatorComponent } from './paginator/paginator.component'; import { MatIconModule } from '@angular/material/icon'; @@ -47,9 +47,9 @@ const routes: IqserRoutes = [ { path: `:${WATERMARK_ID}`, component: WatermarkScreenComponent, - canActivate: [CompositeRouteGuard], + canActivate: [CompositeRouteGuard, watermarkExistsGuard()], data: { - routeGuards: [IqserAuthGuard, RedRoleGuard, WatermarkExistsGuard], + routeGuards: [IqserAuthGuard, RedRoleGuard], }, }, ]; diff --git a/apps/red-ui/src/app/modules/admin/shared/components/admin-side-nav/admin-side-nav.component.ts b/apps/red-ui/src/app/modules/admin/shared/components/admin-side-nav/admin-side-nav.component.ts index fedf5832c..6a4fc5df1 100644 --- a/apps/red-ui/src/app/modules/admin/shared/components/admin-side-nav/admin-side-nav.component.ts +++ b/apps/red-ui/src/app/modules/admin/shared/components/admin-side-nav/admin-side-nav.component.ts @@ -5,14 +5,7 @@ import { adminSideNavTranslations } from '@translations/admin-side-nav-translati import { ActivatedRoute, RouterLink, RouterLinkActive } from '@angular/router'; import { AdminSideNavType, AdminSideNavTypes, DOSSIER_TEMPLATE_ID, ENTITY_TYPE, User, WATERMARK_ID } from '@red/domain'; import { ROLES } from '@users/roles'; -import { - getCurrentUser, - IqserHelpModeModule, - IqserPermissionsService, - SideNavComponent, - TenantContextHolder, - TenantPipe, -} from '@iqser/common-ui'; +import { getCurrentUser, IqserHelpModeModule, IqserPermissionsService, SideNavComponent, TenantPipe } from '@iqser/common-ui'; import { TranslateModule } from '@ngx-translate/core'; import { NgForOf, NgIf } from '@angular/common'; @@ -173,7 +166,6 @@ export class AdminSideNavComponent implements OnInit { constructor( private readonly _permissionsService: IqserPermissionsService, - private readonly _tenantContextHolder: TenantContextHolder, private readonly _route: ActivatedRoute, readonly userPreferenceService: UserPreferenceService, ) {} diff --git a/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.ts b/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.ts index 8afbefad7..9a4d4ffe9 100644 --- a/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.ts +++ b/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.ts @@ -7,7 +7,7 @@ import { getCurrentUser, IqserHelpModeModule, LoadingService, - TenantContextHolder, + TenantsService, } from '@iqser/common-ui'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { firstValueFrom } from 'rxjs'; @@ -23,17 +23,17 @@ import { TranslateModule } from '@ngx-translate/core'; imports: [NgIf, IqserHelpModeModule, CircleButtonComponent, TranslateModule], }) export class DossierTemplateActionsComponent implements OnInit { + @Input() dossierTemplateId: string; + readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = getCurrentUser(); - @Input() dossierTemplateId: string; - constructor( private readonly _router: Router, private readonly _route: ActivatedRoute, private readonly _loadingService: LoadingService, private readonly _dialogService: AdminDialogService, - private readonly _tenantContextHolder: TenantContextHolder, + private readonly _tenantsService: TenantsService, private readonly _dossierTemplatesService: DossierTemplatesService, ) {} @@ -51,7 +51,7 @@ export class DossierTemplateActionsComponent implements OnInit { const success = await firstValueFrom(this._dossierTemplatesService.delete([this.dossierTemplateId])); if (success) { - await this._router.navigate([this._tenantContextHolder.currentTenant, 'main', 'admin']); + await this._router.navigate([this._tenantsService.currentTenant, 'main', 'admin']); } this._loadingService.stop(); diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html index 619fcf3ef..78037fd8b 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html +++ b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html @@ -1,5 +1,5 @@ diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.ts b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.ts index f16299d9e..53935da38 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.ts @@ -8,7 +8,7 @@ import { LoadingService, some, SortingService, - TenantContextHolder, + TenantsService, Toaster, } from '@iqser/common-ui'; import { Dossier, File, IFile } from '@red/domain'; @@ -44,7 +44,7 @@ export class DossierOverviewScreenHeaderComponent implements OnInit { readonly sortingService: SortingService, readonly permissionsService: PermissionsService, readonly entitiesService: EntitiesService, - readonly tenantContextHolder: TenantContextHolder, + readonly tenantsService: TenantsService, private readonly _reanalysisService: ReanalysisService, private readonly _loadingService: LoadingService, private readonly _primaryFileAttributeService: PrimaryFileAttributeService, diff --git a/apps/red-ui/src/app/modules/dossier-overview/services/bulk-actions.service.ts b/apps/red-ui/src/app/modules/dossier-overview/services/bulk-actions.service.ts index c092aad30..5399a7ce9 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/services/bulk-actions.service.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/services/bulk-actions.service.ts @@ -40,7 +40,7 @@ export class BulkActionsService { async ocr(files: File[]) { this._loadingService.start(); - await firstValueFrom(this._reanalysisService.ocrFiles(files, files[0].dossierId)); + await this._reanalysisService.ocrFiles(files, files[0].dossierId); this._loadingService.stop(); } @@ -61,9 +61,7 @@ export class BulkActionsService { async reanalyse(files: File[]) { this._loadingService.start(); - await firstValueFrom( - this._reanalysisService.reanalyzeFilesForDossier(files, files[0].dossierId, { force: true, triggeredByUser: true }), - ); + await this._reanalysisService.reanalyzeFilesForDossier(files, files[0].dossierId, { force: true, triggeredByUser: true }); this._loadingService.stop(); } @@ -75,7 +73,7 @@ export class BulkActionsService { async toggleAnalysis(files: File[], excluded: boolean) { this._loadingService.start(); - await firstValueFrom(this._reanalysisService.toggleAnalysis(files[0].dossierId, files, excluded)); + await this._reanalysisService.toggleAnalysis(files[0].dossierId, files, excluded); this._loadingService.stop(); } 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 e8db1ca54..60361bf24 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 @@ -31,7 +31,7 @@ import { OnDetach, processFilters, shareDistinctLast, - TenantContextHolder, + TenantsService, Toaster, } from '@iqser/common-ui'; import { MatDialog } from '@angular/material/dialog'; @@ -126,7 +126,7 @@ export class FilePreviewScreenComponent private readonly _viewModeService: ViewModeService, private readonly _documentViewer: REDDocumentViewer, private readonly _changeRef: ChangeDetectorRef, - private readonly _tenantContextHolder: TenantContextHolder, + private readonly _tenantsService: TenantsService, private readonly _dialogService: FilePreviewDialogService, private readonly _pageRotationService: PageRotationService, private readonly _viewerHeaderService: ViewerHeaderService, @@ -310,8 +310,7 @@ export class FilePreviewScreenComponent this._subscribeToFileUpdates(); if (file?.analysisRequired && !file.excludedFromAutomaticAnalysis) { - const reanalyzeFiles = this._reanalysisService.reanalyzeFilesForDossier([file], this.dossierId, { force: true }); - await firstValueFrom(reanalyzeFiles); + await this._reanalysisService.reanalyzeFilesForDossier([file], this.dossierId, { force: true }); } this.pdfProxyService.configureElements(); @@ -772,7 +771,7 @@ export class FilePreviewScreenComponent private _navigateToDossier() { this._logger.info('Navigating to ', this.state.dossier.dossierName); - return this._router.navigate([`/${this._tenantContextHolder.currentTenant}${this.state.dossier.routerLink}`]); + return this._router.navigate([`/${this._tenantsService.currentTenant}${this.state.dossier.routerLink}`]); } #highlightSelectedAnnotations(newAnnotations: AnnotationWrapper[]) { diff --git a/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts b/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts index f49458d9c..210bee6d7 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts +++ b/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectorRef, Component, HostBinding, Injector, Input, OnChanges, Optional, SimpleChanges, ViewChild } from '@angular/core'; +import { ChangeDetectorRef, Component, HostBinding, Injector, Input, OnChanges, Optional, ViewChild } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; import { Action, ActionTypes, Dossier, File, ProcessingFileStatuses, User } from '@red/domain'; import { DossiersDialogService } from '../../services/dossiers-dialog.service'; @@ -10,8 +10,7 @@ import { IqserPermissionsService, IqserTooltipPositions, LoadingService, - ScrollableParentView, - TenantContextHolder, + TenantsService, Toaster, } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @@ -39,15 +38,16 @@ import { FileAttributesService } from '@services/entity-services/file-attributes styleUrls: ['./file-actions.component.scss'], }) export class FileActionsComponent implements OnChanges { - readonly circleButtonTypes = CircleButtonTypes; - readonly currentUser = getCurrentUser(); - @Input() file: File; @Input() dossier: Dossier; @Input() type: 'file-preview' | 'dossier-overview-list' | 'dossier-overview-workflow'; @Input() maxWidth: number; @Input() minWidth: number; @Input() fileActionsHelpModeKey: 'document_features_in_dossier' | 'editor_document_features' = 'document_features_in_dossier'; + + readonly circleButtonTypes = CircleButtonTypes; + readonly currentUser = getCurrentUser(); + toggleTooltip?: string; assignTooltip?: string; buttonType?: CircleButtonType; @@ -78,8 +78,6 @@ export class FileActionsComponent implements OnChanges { tooltipPosition = IqserTooltipPositions.above; buttons: Action[]; - scrollableParentView: ScrollableParentView; - @ViewChild(ExpandableFileActionsComponent) private readonly _expandableActionsComponent: ExpandableFileActionsComponent; @@ -89,7 +87,7 @@ export class FileActionsComponent implements OnChanges { private readonly _changeRef: ChangeDetectorRef, private readonly _loadingService: LoadingService, private readonly _dialogService: DossiersDialogService, - private readonly _tenantContextHolder: TenantContextHolder, + private readonly _tenantsService: TenantsService, private readonly _fileAssignService: FileAssignService, private readonly _reanalysisService: ReanalysisService, private readonly _permissionsService: PermissionsService, @@ -120,7 +118,7 @@ export class FileActionsComponent implements OnChanges { { id: 'delete-file-btn', type: ActionTypes.circleBtn, - action: () => this._openDeleteFileDialog(), + action: () => this.#openDeleteFileDialog(), tooltip: _('dossier-overview.delete.action'), icon: 'iqser:trash', show: this.showDelete, @@ -128,7 +126,7 @@ export class FileActionsComponent implements OnChanges { { id: 'assign-btn', type: ActionTypes.circleBtn, - action: () => this._assign(), + action: () => this.#assign(), tooltip: this.assignTooltip, icon: 'red:assign', show: this.showAssign, @@ -136,7 +134,7 @@ export class FileActionsComponent implements OnChanges { { id: 'assign-to-me-btn', type: ActionTypes.circleBtn, - action: () => this._assignToMe(), + action: () => this.#assignToMe(), tooltip: _('dossier-overview.assign-me'), icon: 'red:assign-me', show: this.showAssignToSelf, @@ -144,7 +142,7 @@ export class FileActionsComponent implements OnChanges { { id: 'open-import-redactions-dialog-btn', type: ActionTypes.circleBtn, - action: () => this._openImportRedactionsDialog(), + action: () => this.#openImportRedactionsDialog(), tooltip: _('dossier-overview.import-redactions'), icon: 'red:import_redactions', show: this.showImportRedactions && !this._iqserPermissionsService.has(ROLES.getRss), @@ -191,7 +189,7 @@ export class FileActionsComponent implements OnChanges { { id: 'set-file-under-approval-btn', type: ActionTypes.circleBtn, - action: () => this._setFileUnderApproval(), + action: () => this.#setFileUnderApproval(), tooltip: _('dossier-overview.under-approval'), icon: 'red:ready-for-approval', show: this.showUnderApproval, @@ -199,7 +197,7 @@ export class FileActionsComponent implements OnChanges { { id: 'set-file-under-review-btn', type: ActionTypes.circleBtn, - action: () => this._setFileUnderReview(), + action: () => this.#setFileUnderReview(), tooltip: _('dossier-overview.under-review'), icon: 'red:undo', show: this.showUnderReview, @@ -216,7 +214,7 @@ export class FileActionsComponent implements OnChanges { { id: 'toggle-automatic-analysis-btn', type: ActionTypes.circleBtn, - action: () => this._toggleAutomaticAnalysis(), + action: () => this.#toggleAutomaticAnalysis(), tooltip: _('dossier-overview.stop-auto-analysis'), icon: 'red:disable-analysis', show: this.canDisableAutoAnalysis, @@ -224,7 +222,7 @@ export class FileActionsComponent implements OnChanges { { id: 'reanalyse-file-preview-btn', type: ActionTypes.circleBtn, - action: () => this._reanalyseFile(), + action: () => this.#reanalyseFile(), tooltip: _('file-preview.reanalyse-notification'), tooltipClass: 'small', icon: 'iqser:refresh', @@ -234,7 +232,7 @@ export class FileActionsComponent implements OnChanges { { id: 'toggle-automatic-analysis-btn', type: ActionTypes.circleBtn, - action: () => this._toggleAutomaticAnalysis(), + action: () => this.#toggleAutomaticAnalysis(), tooltip: _('dossier-overview.start-auto-analysis'), buttonType: this.isFilePreview ? CircleButtonTypes.warn : CircleButtonTypes.default, icon: 'red:enable-analysis', @@ -243,7 +241,7 @@ export class FileActionsComponent implements OnChanges { { id: 'set-under-approval-btn', type: ActionTypes.circleBtn, - action: () => this._setFileUnderApproval(), + action: () => this.#setFileUnderApproval(), tooltip: _('dossier-overview.under-approval'), icon: 'red:undo', show: this.showUndoApproval, @@ -251,7 +249,7 @@ export class FileActionsComponent implements OnChanges { { id: 'ocr-file-btn', type: ActionTypes.circleBtn, - action: () => this._ocrFile(), + action: () => this.#ocrFile(), tooltip: _('dossier-overview.ocr-file'), icon: 'iqser:ocr', show: this.showOCR, @@ -259,7 +257,7 @@ export class FileActionsComponent implements OnChanges { { id: 'reanalyse-file-btn', type: ActionTypes.circleBtn, - action: () => this._reanalyseFile(), + action: () => this.#reanalyseFile(), tooltip: _('dossier-overview.reanalyse.action'), icon: 'iqser:refresh', show: this.showReanalyseDossierOverview, @@ -267,7 +265,7 @@ export class FileActionsComponent implements OnChanges { { id: 'toggle-analysis-btn', type: ActionTypes.toggle, - action: () => this._toggleAnalysis(), + action: () => this.#toggleAnalysis(), disabled: !this.canToggleAnalysis, tooltip: this.toggleTooltip, class: { 'mr-24': this.isDossierOverviewList }, @@ -280,7 +278,7 @@ export class FileActionsComponent implements OnChanges { } ngOnChanges() { - this._setup(); + this.#setup(); } async setFileApproved() { @@ -305,7 +303,7 @@ export class FileActionsComponent implements OnChanges { forceReanalysisAction($event: LongPressEvent) { this.analysisForced = !$event.touchEnd && this._userPreferenceService.areDevFeaturesEnabled; - this._setup(); + this.#setup(); } #showOCRConfirmationDialog(): Observable { @@ -319,11 +317,11 @@ export class FileActionsComponent implements OnChanges { return ref.afterClosed(); } - private _openImportRedactionsDialog() { + #openImportRedactionsDialog() { this._dialogService.openDialog('importRedactions', { dossierId: this.file.dossierId, fileId: this.file.fileId }); } - private _openDeleteFileDialog() { + #openDeleteFileDialog() { this._dialogService.openDialog( 'confirm', { @@ -335,7 +333,7 @@ export class FileActionsComponent implements OnChanges { try { const dossier = this._activeDossiersService.find(this.file.dossierId); await firstValueFrom(this._fileManagementService.delete([this.file], this.file.dossierId)); - await this._injector.get(Router).navigate([`/${this._tenantContextHolder.currentTenant}${dossier.routerLink}`]); + await this._injector.get(Router).navigate([`/${this._tenantsService.currentTenant}${dossier.routerLink}`]); } catch (error) { this._injector.get(Toaster).error(_('error.http.generic'), { params: error }); } @@ -344,7 +342,7 @@ export class FileActionsComponent implements OnChanges { ); } - private _assign() { + #assign() { const files = [this.file]; const targetStatus = this.file.workflowStatus; const withCurrentUserAsDefault = true; @@ -352,29 +350,29 @@ export class FileActionsComponent implements OnChanges { this._dialogService.openDialog('assignFile', { targetStatus, files, withCurrentUserAsDefault, withUnassignedOption }); } - private async _assignToMe() { + async #assignToMe() { await this._fileAssignService.assignToMe([this.file]); } - private async _reanalyseFile() { + async #reanalyseFile() { const params: ReanalyzeQueryParams = { force: true, triggeredByUser: true, }; - await firstValueFrom(this._reanalysisService.reanalyzeFilesForDossier([this.file], this.file.dossierId, params)); + await this._reanalysisService.reanalyzeFilesForDossier([this.file], this.file.dossierId, params); } - private async _toggleAutomaticAnalysis() { + async #toggleAutomaticAnalysis() { this._loadingService.start(); await firstValueFrom(this._reanalysisService.toggleAutomaticAnalysis(this.file.dossierId, [this.file])); this._loadingService.stop(); } - private async _setFileUnderApproval() { + async #setFileUnderApproval() { await this._fileAssignService.assignApprover(this.file, true); } - private async _ocrFile() { + async #ocrFile() { if (this.file.lastManualChangeDate) { const confirm = await firstValueFrom(this.#showOCRConfirmationDialog()); if (!confirm) { @@ -388,21 +386,21 @@ export class FileActionsComponent implements OnChanges { viewerHeaderService.disable(ROTATION_ACTION_BUTTONS); this._loadingService.start(); - await firstValueFrom(this._reanalysisService.ocrFiles([this.file], this.file.dossierId)); + await this._reanalysisService.ocrFiles([this.file], this.file.dossierId); this._loadingService.stop(); } - private async _setFileUnderReview() { + async #setFileUnderReview() { await this._fileAssignService.assignReviewer(this.file, true); } - private async _toggleAnalysis() { + async #toggleAnalysis() { this._loadingService.start(); - await firstValueFrom(this._reanalysisService.toggleAnalysis(this.file.dossierId, [this.file], !this.file.excluded)); + await this._reanalysisService.toggleAnalysis(this.file.dossierId, [this.file], !this.file.excluded); this._loadingService.stop(); } - private _setup() { + #setup() { this.isDossierOverviewList = this.type === 'dossier-overview-list'; this.isDossierOverviewWorkflow = this.type === 'dossier-overview-workflow'; this.isDossierOverview = this.type.startsWith('dossier-overview'); diff --git a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.ts b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.ts index 32660e26c..af47cfbd7 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.ts +++ b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.ts @@ -44,7 +44,7 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa async ngOnInit() { this._loadingService.start(); this.canEdit = this._permissionsService.canEditDossierDictionary(this.dossier); - await this._updateDossierDictionary(); + await this.#updateDossierDictionary(); this._loadingService.stop(); } @@ -61,7 +61,7 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa ), ); - await this._updateDossierDictionary(); + await this.#updateDossierDictionary(); return { success: true }; } catch (error) { return { success: false }; @@ -75,12 +75,12 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa openEditDetailsDialog(): void { const data = { dictionary: this.dossierDictionary, dossierId: this.dossier.id, readOnly: !this.canEdit }; this._dialogService.openDialog('editDictionaryDetails', data, async () => { - await this._updateDossierDictionary(); + await this.#updateDossierDictionary(); }); } - private async _updateDossierDictionary() { + async #updateDossierDictionary() { const { dossierId, dossierTemplateId } = this.dossier; - this.dossierDictionary = await firstValueFrom(this._dictionaryService.loadDossierDictionary(dossierTemplateId, dossierId)); + this.dossierDictionary = await this._dictionaryService.loadDossierDictionary(dossierTemplateId, dossierId); } } 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 f3962714f..13985fbf2 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 @@ -12,7 +12,7 @@ import { IconButtonTypes, IConfirmationDialogData, LoadingService, - TenantContextHolder, + TenantsService, TitleColors, Toaster, } from '@iqser/common-ui'; @@ -35,10 +35,10 @@ import { dateWithoutTime } from '@utils/functions'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSectionInterface { - readonly iconButtonTypes = IconButtonTypes; - @Input() dossier: Dossier; + readonly iconButtonTypes = IconButtonTypes; + form: UntypedFormGroup; statusPlaceholder: string; hasDueDate: boolean; @@ -55,7 +55,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti private readonly _formBuilder: UntypedFormBuilder, private readonly _dialogService: DossiersDialogService, private readonly _router: Router, - private readonly _tenantContextHolder: TenantContextHolder, + private readonly _tenantsService: TenantsService, private readonly _editDossierDialogRef: MatDialogRef, private readonly _toaster: Toaster, private readonly _loadingService: LoadingService, @@ -153,7 +153,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti this._loadingService.start(); await firstValueFrom(this._trashService.deleteDossier(this.dossier)); this._editDossierDialogRef.close(); - await this._router.navigate([`/${this._tenantContextHolder.currentTenant}${this.dossier.dossiersListRouterLink}`]); + await this._router.navigate([`/${this._tenantsService.currentTenant}${this.dossier.dossiersListRouterLink}`]); this._loadingService.stop(); this._toaster.success(_('edit-dossier-dialog.delete-successful'), { params: { diff --git a/apps/red-ui/src/app/modules/shared/components/buttons/file-download-btn/file-download-btn.component.ts b/apps/red-ui/src/app/modules/shared/components/buttons/file-download-btn/file-download-btn.component.ts index 6aa2bed8e..b946dc0b2 100644 --- a/apps/red-ui/src/app/modules/shared/components/buttons/file-download-btn/file-download-btn.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/buttons/file-download-btn/file-download-btn.component.ts @@ -2,7 +2,7 @@ import { Component, Input, OnChanges } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; import { Dossier, File, ProcessingFileStatuses } from '@red/domain'; import { FileDownloadService } from '@upload-download/services/file-download.service'; -import { CircleButtonType, CircleButtonTypes, defaultDialogConfig, TenantContextHolder, Toaster } from '@iqser/common-ui'; +import { CircleButtonType, CircleButtonTypes, defaultDialogConfig, TenantsService, Toaster } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { MatDialog } from '@angular/material/dialog'; import { @@ -31,7 +31,7 @@ export class FileDownloadBtnComponent implements OnChanges { constructor( private readonly _permissionsService: PermissionsService, - private readonly _tenantContextHolder: TenantContextHolder, + private readonly _tenantsService: TenantsService, private readonly _fileDownloadService: FileDownloadService, private readonly _dialog: MatDialog, private readonly _toaster: Toaster, @@ -62,7 +62,7 @@ export class FileDownloadBtnComponent implements OnChanges { await downloadRequest .then(() => this._toaster.info(_('download-status.queued'), { - params: { downloadHref: `/ui/${this._tenantContextHolder.currentTenant}/main/downloads` }, + params: { downloadHref: `/ui/${this._tenantsService.currentTenant}/main/downloads` }, }), ) .catch(() => this._toaster.error(_('download-status.error'))); diff --git a/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.ts b/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.ts index 3793837a7..c1221ef6c 100644 --- a/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.ts @@ -1,13 +1,6 @@ import { Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core'; import { Action, ActionTypes, Dossier, File } from '@red/domain'; -import { - CircleButtonType, - defaultDialogConfig, - IqserTooltipPosition, - TenantContextHolder, - Toaster, - trackByFactory, -} from '@iqser/common-ui'; +import { CircleButtonType, defaultDialogConfig, IqserTooltipPosition, TenantsService, Toaster, trackByFactory } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { FileDownloadService } from '@upload-download/services/file-download.service'; import { PermissionsService } from '@services/permissions.service'; @@ -41,7 +34,7 @@ export class ExpandableFileActionsComponent implements OnChanges { constructor( private readonly _fileDownloadService: FileDownloadService, - private readonly _tenantContextHolder: TenantContextHolder, + private readonly _tenantsService: TenantsService, private readonly _toaster: Toaster, private readonly _permissionsService: PermissionsService, private readonly _dialog: MatDialog, @@ -106,7 +99,7 @@ export class ExpandableFileActionsComponent implements OnChanges { ...result, }); this._toaster.info(_('download-status.queued'), { - params: { downloadHref: `/ui/${this._tenantContextHolder.currentTenant}/main/downloads` }, + params: { downloadHref: `/ui/${this._tenantsService.currentTenant}/main/downloads` }, }); } } diff --git a/apps/red-ui/src/app/modules/shared/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts b/apps/red-ui/src/app/modules/shared/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts index 2cd5e93f9..b608ad956 100644 --- a/apps/red-ui/src/app/modules/shared/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts +++ b/apps/red-ui/src/app/modules/shared/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts @@ -3,7 +3,7 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { DOSSIER_TEMPLATE_ID, DownloadFileType, IDossierRequest, IDossierTemplate, IReportTemplate } from '@red/domain'; import { UntypedFormGroup, Validators } from '@angular/forms'; import { downloadTypesTranslations } from '@translations/download-types-translations'; -import { BaseDialogComponent, IconButtonTypes, IqserPermissionsService, SaveOptions, TenantContextHolder } from '@iqser/common-ui'; +import { BaseDialogComponent, IconButtonTypes, IqserPermissionsService, SaveOptions, TenantsService } from '@iqser/common-ui'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { ReportTemplateService } from '@services/report-template.service'; @@ -42,7 +42,7 @@ export class AddDossierDialogComponent extends BaseDialogComponent implements On constructor( readonly permissionsService: IqserPermissionsService, - private readonly _tenantContextHolder: TenantContextHolder, + private readonly _tenantsService: TenantsService, private readonly _activeDossiersService: ActiveDossiersService, private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _reportTemplateController: ReportTemplateService, @@ -83,7 +83,7 @@ export class AddDossierDialogComponent extends BaseDialogComponent implements On this._loadingService.start(); const savedDossier = await firstValueFrom(this._activeDossiersService.createOrUpdate(this._formToObject())); if (savedDossier) { - await this._router.navigate([`/${this._tenantContextHolder.currentTenant}${savedDossier.routerLink}`]); + await this._router.navigate([`/${this._tenantsService.currentTenant}${savedDossier.routerLink}`]); if (options?.addMembers) { this._dialogService.openDialog('editDossier', { dossierId: savedDossier.id, diff --git a/apps/red-ui/src/app/modules/upload-download/services/file-download.service.ts b/apps/red-ui/src/app/modules/upload-download/services/file-download.service.ts index 2a3eab3fa..39672a4af 100644 --- a/apps/red-ui/src/app/modules/upload-download/services/file-download.service.ts +++ b/apps/red-ui/src/app/modules/upload-download/services/file-download.service.ts @@ -3,14 +3,14 @@ import { DownloadStatus, IDownloadStatus, IDownloadStatusResponse, IPrepareDownl import { firstValueFrom, Observable } from 'rxjs'; import { ConfigService } from '@services/config.service'; import { map, tap } from 'rxjs/operators'; -import { EntitiesService, mapEach, TenantContextHolder } from '@iqser/common-ui'; +import { EntitiesService, mapEach, TenantsService } from '@iqser/common-ui'; import { NGXLogger } from 'ngx-logger'; @Injectable() export class FileDownloadService extends EntitiesService { protected readonly _defaultModelPath = 'async/download'; protected readonly _entityClass = DownloadStatus; - protected readonly _tenantContext = inject(TenantContextHolder); + protected readonly _tenantsService = inject(TenantsService); constructor(private readonly _configService: ConfigService, private readonly _logger: NGXLogger) { super(); @@ -36,7 +36,7 @@ export class FileDownloadService extends EntitiesService { @@ -42,7 +42,7 @@ export class ArchivedDossiersService extends DossiersService { if (!this.#activeDossiersService.all.find(d => d.dossierTemplateId === dossierTemplateId)) { route = route.replace(DOSSIERS_ROUTE, ARCHIVE_ROUTE); } - await this.#router.navigate([`/${this.#tenantContextHolder.currentTenant}${route}`]); + await this.#router.navigate([`/${this.#tenantsService.currentTenant}${route}`]); }), catchError(showArchiveFailedToast), ); diff --git a/apps/red-ui/src/app/services/entity-services/dictionary.service.ts b/apps/red-ui/src/app/services/entity-services/dictionary.service.ts index b3302e860..158a4b176 100644 --- a/apps/red-ui/src/app/services/entity-services/dictionary.service.ts +++ b/apps/red-ui/src/app/services/entity-services/dictionary.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { forkJoin, Observable, of, throwError, zip } from 'rxjs'; +import { firstValueFrom, forkJoin, Observable, throwError, zip } from 'rxjs'; import { EntitiesService, List, QueryParam, Toaster } from '@iqser/common-ui'; import { Dictionary, DictionaryEntryType, DictionaryEntryTypes, IDictionary, IUpdateDictionary, SuperTypes } from '@red/domain'; import { catchError, map, switchMap, tap } from 'rxjs/operators'; @@ -170,23 +170,20 @@ export class DictionaryService extends EntitiesService return possibleDictionaries; } - loadDossierDictionary(dossierTemplateId: string, dossierId: string): Observable { - return this.getForType(dossierTemplateId, 'dossier_redaction', dossierId).pipe( - map( - dictionary => - new Dictionary({ - ...dictionary, - type: 'dossier_redaction', - }), - ), - tap(dictionary => { - this._dossierDictionariesMapService.set(dossierId, [dictionary]); - }), - catchError(() => { - this._dossierDictionariesMapService.set(dossierId, []); - return of(null); - }), - ); + async loadDossierDictionary(dossierTemplateId: string, dossierId: string): Promise { + const promise = firstValueFrom(this.getForType(dossierTemplateId, 'dossier_redaction', dossierId)); + const dict = await promise.catch(() => undefined); + if (dict) { + const dictionary = new Dictionary({ + ...dict, + type: 'dossier_redaction', + }); + this._dossierDictionariesMapService.set(dossierId, [dictionary]); + return dictionary; + } + + this._dossierDictionariesMapService.set(dossierId, []); + return undefined; } loadDictionaryData(dossierTemplatesIds: string[]): Observable { diff --git a/apps/red-ui/src/app/services/notifications.service.ts b/apps/red-ui/src/app/services/notifications.service.ts index b906a0b94..3cdc513ad 100644 --- a/apps/red-ui/src/app/services/notifications.service.ts +++ b/apps/red-ui/src/app/services/notifications.service.ts @@ -1,5 +1,5 @@ import { Inject, Injectable, OnDestroy } from '@angular/core'; -import { BASE_HREF, EntitiesService, getConfig, List, mapEach, QueryParam, TenantContextHolder } from '@iqser/common-ui'; +import { BASE_HREF, EntitiesService, getConfig, List, mapEach, QueryParam, TenantsService } from '@iqser/common-ui'; import { TranslateService } from '@ngx-translate/core'; import { EMPTY, firstValueFrom, iif, merge, Observable, of, Subscription, timer } from 'rxjs'; import { AppConfig, Dossier, INotification, Notification, NotificationTypes } from '@red/domain'; @@ -30,7 +30,7 @@ export class NotificationsService extends EntitiesService { return this._post(body, `include-pages/${dossierId}/${file.id}`).pipe(switchMap(() => this._filesService.reload(dossierId, file))); } - reanalyzeFilesForDossier(files: List, dossierId: string, params?: ReanalyzeQueryParams) { + async reanalyzeFilesForDossier(files: List, dossierId: string, params?: ReanalyzeQueryParams) { const fileIds = files.map(f => f.id); const queryParams: QueryParam[] = []; if (params?.force) { @@ -44,19 +44,19 @@ export class ReanalysisService extends GenericService { queryParams.push({ key: 'triggeredByUser', value: true }); } - return this._post(fileIds, `reanalyze/${dossierId}/bulk`, queryParams).pipe(switchMap(() => this._filesService.loadAll(dossierId))); + await firstValueFrom(this._post(fileIds, `reanalyze/${dossierId}/bulk`, queryParams)); + return firstValueFrom(this._filesService.loadAll(dossierId)); } - toggleAnalysis(dossierId: string, files: List, excluded?: boolean) { + async toggleAnalysis(dossierId: string, files: List, excluded?: boolean) { const fileIds = files.map(f => f.id); const queryParams: QueryParam[] = []; if (excluded) { queryParams.push({ key: 'excluded', value: excluded }); } - return this._post(fileIds, `toggle-analysis/${dossierId}/bulk`, queryParams).pipe( - switchMap(() => this._filesService.loadAll(dossierId)), - ); + await firstValueFrom(this._post(fileIds, `toggle-analysis/${dossierId}/bulk`, queryParams)); + return firstValueFrom(this._filesService.loadAll(dossierId)); } toggleAutomaticAnalysis(dossierId: string, files: File[]) { @@ -77,9 +77,10 @@ export class ReanalysisService extends GenericService { ); } - ocrFiles(files: List, dossierId: string) { + async ocrFiles(files: List, dossierId: string) { const fileIds = files.map(f => f.id); - return this._post(fileIds, `ocr/reanalyze/${dossierId}/bulk`).pipe(switchMap(() => this._filesService.loadAll(dossierId))); + await firstValueFrom(this._post(fileIds, `ocr/reanalyze/${dossierId}/bulk`)); + return firstValueFrom(this._filesService.loadAll(dossierId)); } async reanalyzeDossier(dossier: Dossier, force?: boolean) { diff --git a/apps/red-ui/src/app/services/router-history.service.ts b/apps/red-ui/src/app/services/router-history.service.ts index fc2a0d39a..7c965533e 100644 --- a/apps/red-ui/src/app/services/router-history.service.ts +++ b/apps/red-ui/src/app/services/router-history.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { NavigationEnd, Router } from '@angular/router'; import { filter } from 'rxjs/operators'; -import { TenantContextHolder } from '@iqser/common-ui'; +import { TenantsService } from '@iqser/common-ui'; const LAST_DOSSIERS_SCREEN = 'routerHistory_lastDossiersScreen'; @@ -11,7 +11,7 @@ const LAST_DOSSIERS_SCREEN = 'routerHistory_lastDossiersScreen'; export class RouterHistoryService { private _lastDossiersScreen = localStorage.getItem(LAST_DOSSIERS_SCREEN); - constructor(private readonly _router: Router, private readonly _tenantContextHolder: TenantContextHolder) { + constructor(private readonly _router: Router, private readonly _tenantsService: TenantsService) { // eslint-disable-next-line rxjs/no-ignored-subscription this._router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe((event: NavigationEnd) => { if (event.url.includes('/dossiers') || event.url.includes('/archive')) { @@ -23,7 +23,7 @@ export class RouterHistoryService { navigateToLastDossiersScreen(): void { if (this._router.url === decodeURI(this._lastDossiersScreen)) { - this._router.navigate(['/' + this._tenantContextHolder.currentTenant]); + this._router.navigate(['/' + this._tenantsService.currentTenant]); } else { const url = decodeURI(this._lastDossiersScreen).split('?')[0]; // todo links diff --git a/apps/red-ui/src/app/users/red-role.guard.ts b/apps/red-ui/src/app/users/red-role.guard.ts index 91e238537..37d87d66b 100644 --- a/apps/red-ui/src/app/users/red-role.guard.ts +++ b/apps/red-ui/src/app/users/red-role.guard.ts @@ -1,28 +1,25 @@ import { inject, Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; -import { UserService } from './user.service'; -import { IqserPermissionsService, IqserRoleGuard, TenantContextHolder } from '@iqser/common-ui'; +import { IqserPermissionsService, IqserRoleGuard } from '@iqser/common-ui'; @Injectable({ providedIn: 'root', }) export class RedRoleGuard extends IqserRoleGuard { - protected readonly _userService = inject(UserService); protected readonly _permissionsService = inject(IqserPermissionsService); - protected readonly _tenantContextHolder = inject(TenantContextHolder); async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { const currentUser = this._userService.currentUser; if (!currentUser?.hasAnyRole) { - await this._router.navigate([`/${this._tenantContextHolder.currentTenant}/auth-error`]); + await this._router.navigate([`/${this._tenantsService.currentTenant}/auth-error`]); this._loadingService.stop(); return false; } // we have at least 1 RED Role -> if it's not user he must be an admin if (currentUser.isUserAdmin && !currentUser.isAdmin && state.url.includes('admin') && !state.url.includes('users')) { - await this._router.navigate([`/${this._tenantContextHolder.currentTenant}/main/admin/users`]); + await this._router.navigate([`/${this._tenantsService.currentTenant}/main/admin/users`]); return false; } @@ -32,7 +29,7 @@ export class RedRoleGuard extends IqserRoleGuard { !currentUser.isUser && !(state.url.includes('/main/admin/users') || state.url.includes('/main/account')) ) { - await this._router.navigate([`/${this._tenantContextHolder.currentTenant}/main/admin/users`]); + await this._router.navigate([`/${this._tenantsService.currentTenant}/main/admin/users`]); return false; } @@ -41,9 +38,9 @@ export class RedRoleGuard extends IqserRoleGuard { return true; } if (!currentUser.isUser) { - await this._router.navigate([`/${this._tenantContextHolder.currentTenant}/main/admin`]); + await this._router.navigate([`/${this._tenantsService.currentTenant}/main/admin`]); } else { - await this._router.navigate([`/${this._tenantContextHolder.currentTenant}`]); + await this._router.navigate([`/${this._tenantsService.currentTenant}`]); } return false; } diff --git a/apps/red-ui/src/app/utils/main.resolver.ts b/apps/red-ui/src/app/utils/main.resolver.ts index 45902d090..b016ecf0a 100644 --- a/apps/red-ui/src/app/utils/main.resolver.ts +++ b/apps/red-ui/src/app/utils/main.resolver.ts @@ -5,7 +5,7 @@ import { UserService } from '@users/user.service'; import { SystemPreferencesService } from '@services/system-preferences.service'; import { UserPreferenceService } from '@users/user-preference.service'; import { LicenseService } from '@services/license.service'; -import { BASE_HREF, IqserPermissionsService, LoadingService, TenantContextHolder } from '@iqser/common-ui'; +import { BASE_HREF, IqserPermissionsService, LoadingService, TenantsService } from '@iqser/common-ui'; import { FeaturesService } from '@services/features.service'; import { GeneralSettingsService } from '@services/general-settings.service'; import { tap } from 'rxjs/operators'; @@ -32,7 +32,7 @@ export const mainResolver: ResolveFn = async () => { const systemPreferencesService = inject(SystemPreferencesService); const userPreferenceService = inject(UserPreferenceService); - const tenantContextHolder = inject(TenantContextHolder); + const tenantsService = inject(TenantsService); const licenseService = inject(LicenseService); const loadingService = inject(LoadingService); const configService = inject(ConfigService); @@ -53,7 +53,7 @@ export const mainResolver: ResolveFn = async () => { const lastDossierTemplate = userPreferenceService.getLastDossierTemplate(); if (lastDossierTemplate) { - redirectToLastDossierTemplate(baseHref, tenantContextHolder.currentTenant, lastDossierTemplate); + redirectToLastDossierTemplate(baseHref, tenantsService.currentTenant, lastDossierTemplate); } loadingService.stop(); diff --git a/libs/common-ui b/libs/common-ui index dbfde290c..d0551742e 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit dbfde290c877d41142bf9ea7430fd4359cf223b2 +Subproject commit d0551742ecfce6a473ab1431ce890372b1b1a40f