diff --git a/apps/red-ui/src/app/app-routing.module.ts b/apps/red-ui/src/app/app-routing.module.ts index a42c3cb55..b6820fa72 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -6,6 +6,7 @@ import { IqserAuthGuard, IqserPermissionsGuard, IqserRoutes, + TenantResolveComponent, } from '@iqser/common-ui'; import { RedRoleGuard } from '@users/red-role.guard'; import { BaseScreenComponent } from '@components/base-screen/base-screen.component'; @@ -96,11 +97,14 @@ const dossierTemplateIdRoutes: IqserRoutes = [ const routes: IqserRoutes = [ { path: '', - redirectTo: 'main', - pathMatch: 'full', + component: TenantResolveComponent, }, { - path: 'main', + path: ':tenant', + component: TenantResolveComponent, + }, + { + path: ':tenant/main', component: BaseScreenComponent, children: [ { @@ -212,7 +216,7 @@ const routes: IqserRoutes = [ ], }, { - path: 'auth-error', + path: ':tenant/auth-error', component: AuthErrorComponent, canActivate: [IqserAuthGuard], }, diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index 4da89584c..d296b2e47 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -12,6 +12,7 @@ import { CommonUiModule, EmptyStateComponent, HiddenActionDirective, + IconButtonComponent, InputWithActionComponent, IqserAllowDirective, IqserDenyDirective, @@ -21,6 +22,7 @@ import { IqserPermissionsService, IqserTranslateModule, IqserUsersModule, + KeycloakStatusService, LanguageService, LogoComponent, MAX_RETRIES_ON_SERVER_ERROR, @@ -29,6 +31,8 @@ import { ServerErrorInterceptor, SkeletonComponent, StopPropagationDirective, + TenantPipe, + TenantsModule, ToastComponent, } from '@iqser/common-ui'; import { ToastrModule } from 'ngx-toastr'; @@ -66,13 +70,11 @@ import { AppConfig, ILoggerConfig } from '@red/domain'; import { SystemPreferencesService } from '@services/system-preferences.service'; import { PdfViewerModule } from './modules/pdf-viewer/pdf-viewer.module'; import { LicenseService } from '@services/license.service'; -import { TenantIdInterceptor } from '@utils/tenant-id-interceptor'; import { UI_CACHES } from '@utils/constants'; import { RedRoleGuard } from '@users/red-role.guard'; import { SkeletonTopBarComponent } from '@components/skeleton/skeleton-top-bar/skeleton-top-bar.component'; import { DossierSkeletonComponent } from '@components/skeleton/dossier-skeleton/dossier-skeleton.component'; import { SkeletonStatsComponent } from '@components/skeleton/skeleton-stats/skeleton-stats.component'; -import { TenantIdResponseInterceptor } from '@utils/tenant-id-response-interceptor'; const screens = [BaseScreenComponent, DownloadsListScreenComponent]; @@ -119,6 +121,7 @@ export const appModuleFactory = (config: AppConfig) => { preventDuplicates: true, resetTimeoutOnDuplicate: true, }), + TenantsModule.forRoot(), IqserTranslateModule.forRoot({ pathPrefix: config.BASE_TRANSLATIONS_DIRECTORY || '/assets/i18n/redact/' }), IqserLoadingModule.forRoot(), ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }), @@ -170,6 +173,8 @@ export const appModuleFactory = (config: AppConfig) => { IqserAllowDirective, IqserDenyDirective, IqserListingModule, + IconButtonComponent, + TenantPipe, ], providers: [ { @@ -181,22 +186,13 @@ export const appModuleFactory = (config: AppConfig) => { provide: ErrorHandler, useClass: GlobalErrorHandler, }, - { - provide: HTTP_INTERCEPTORS, - multi: true, - useClass: TenantIdInterceptor, - }, - { - provide: HTTP_INTERCEPTORS, - multi: true, - useClass: TenantIdResponseInterceptor, - }, { provide: APP_INITIALIZER, multi: true, useFactory: configurationInitializer, deps: [ BASE_HREF, + KeycloakStatusService, KeycloakService, ConfigService, SystemPreferencesService, diff --git a/apps/red-ui/src/app/components/base-screen/base-screen.component.html b/apps/red-ui/src/app/components/base-screen/base-screen.component.html index f9f73cfb2..932500312 100644 --- a/apps/red-ui/src/app/components/base-screen/base-screen.component.html +++ b/apps/red-ui/src/app/components/base-screen/base-screen.component.html @@ -38,11 +38,15 @@
- + {{ item.name | translate }} + + -
+
-
+
-
+
+
@@ -25,6 +26,7 @@
+ @@ -47,7 +49,6 @@ [icon]="fullScreen ? 'red:exit-fullscreen' : 'red:fullscreen'" [tooltip]="'file-preview.fullscreen' | translate" class="ml-2" - tooltipPosition="below" > @@ -58,19 +59,16 @@ [type]="circleButtonTypes.primary" class="ml-8" icon="iqser:download" - tooltipPosition="below" >
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 aae181cf1..9d77ff5f4 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,6 +31,7 @@ import { OnDetach, processFilters, shareDistinctLast, + TenantContextHolder, Toaster, } from '@iqser/common-ui'; import { MatDialog } from '@angular/material/dialog'; @@ -125,6 +126,7 @@ export class FilePreviewScreenComponent private readonly _viewModeService: ViewModeService, private readonly _documentViewer: REDDocumentViewer, private readonly _changeRef: ChangeDetectorRef, + private readonly _tenantContextHolder: TenantContextHolder, private readonly _dialogService: FilePreviewDialogService, private readonly _pageRotationService: PageRotationService, private readonly _viewerHeaderService: ViewerHeaderService, @@ -772,7 +774,7 @@ export class FilePreviewScreenComponent private _navigateToDossier() { this._logger.info('Navigating to ', this.state.dossier.dossierName); - return this._router.navigate([this.state.dossier.routerLink]); + return this._router.navigate([`/${this._tenantContextHolder.currentTenant}${this.state.dossier.routerLink}`]); } #highlightSelectedAnnotations(newAnnotations: AnnotationWrapper[]) { diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts b/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts index ab604c7af..91386b77f 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts @@ -21,6 +21,7 @@ import { RoundCheckboxComponent, StatusBarComponent, StopPropagationDirective, + TenantPipe, } from '@iqser/common-ui'; import { TranslateModule } from '@ngx-translate/core'; import { RouterModule } from '@angular/router'; @@ -139,6 +140,7 @@ const components = [ RoundCheckboxComponent, IqserAllowDirective, IqserDenyDirective, + TenantPipe, ], providers: [FilePreviewDialogService, ManualRedactionService, DocumentUnloadedGuard, SuggestionsService], }) diff --git a/apps/red-ui/src/app/modules/search/search-item-template/search-item-template.component.html b/apps/red-ui/src/app/modules/search/search-item-template/search-item-template.component.html index 5901dc0b4..e6a250561 100644 --- a/apps/red-ui/src/app/modules/search/search-item-template/search-item-template.component.html +++ b/apps/red-ui/src/app/modules/search/search-item-template/search-item-template.component.html @@ -50,7 +50,7 @@ diff --git a/apps/red-ui/src/app/modules/search/search.module.ts b/apps/red-ui/src/app/modules/search/search.module.ts index 160d2a5bb..1a6943185 100644 --- a/apps/red-ui/src/app/modules/search/search.module.ts +++ b/apps/red-ui/src/app/modules/search/search.module.ts @@ -2,7 +2,7 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SearchScreenComponent } from './search-screen/search-screen.component'; import { RouterModule } from '@angular/router'; -import { IqserListingModule, IqserUsersModule, StatusBarComponent, StopPropagationDirective } from '@iqser/common-ui'; +import { IqserListingModule, IqserUsersModule, StatusBarComponent, StopPropagationDirective, TenantPipe } from '@iqser/common-ui'; import { SharedModule } from '@shared/shared.module'; import { TranslateModule } from '@ngx-translate/core'; import { SearchItemTemplateComponent } from './search-item-template/search-item-template.component'; @@ -20,6 +20,7 @@ const routes = [{ path: '', component: SearchScreenComponent }]; IqserListingModule, StatusBarComponent, StopPropagationDirective, + TenantPipe, ], }) export class SearchModule {} 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 287b6a518..893ec3c36 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 @@ -8,11 +8,12 @@ import { getCurrentUser, IConfirmationDialogData, IqserPermissionsService, - IqserTooltipPosition, + IqserTooltipPositions, LoadingService, OverlappingElements, ScrollableParentView, ScrollableParentViews, + TenantContextHolder, Toaster, } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @@ -76,7 +77,7 @@ export class FileActionsComponent implements OnChanges { isDossierOverviewList = false; isDossierOverviewWorkflow = false; isFilePreview = false; - tooltipPosition: IqserTooltipPosition; + tooltipPosition = IqserTooltipPositions.above; buttons: Action[]; scrollableParentView: ScrollableParentView; @@ -90,6 +91,7 @@ export class FileActionsComponent implements OnChanges { private readonly _changeRef: ChangeDetectorRef, private readonly _loadingService: LoadingService, private readonly _dialogService: DossiersDialogService, + private readonly _tenantContextHolder: TenantContextHolder, private readonly _fileAssignService: FileAssignService, private readonly _reanalysisService: ReanalysisService, private readonly _permissionsService: PermissionsService, @@ -343,7 +345,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([dossier.routerLink]); + await this._injector.get(Router).navigate([`/${this._tenantContextHolder.currentTenant}${dossier.routerLink}`]); } catch (error) { this._injector.get(Toaster).error(_('error.http.generic'), { params: error }); } @@ -416,8 +418,6 @@ export class FileActionsComponent implements OnChanges { this.isDossierOverview = this.type.startsWith('dossier-overview'); this.isFilePreview = this.type === 'file-preview'; - this.tooltipPosition = this.isFilePreview ? 'below' : 'above'; - this.assignTooltip = this.file.isUnderApproval ? _('dossier-overview.assign-approver') : _('dossier-overview.assign-reviewer'); this.buttonType = this.isFilePreview ? CircleButtonTypes.default : CircleButtonTypes.dark; this.showAssign = 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 a3fb03445..f3962714f 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 @@ -7,7 +7,15 @@ import { PermissionsService } from '@services/permissions.service'; import { Router } from '@angular/router'; import { MatDialogRef } from '@angular/material/dialog'; import { EditDossierDialogComponent } from '../edit-dossier-dialog.component'; -import { ConfirmOptions, IconButtonTypes, IConfirmationDialogData, LoadingService, TitleColors, Toaster } from '@iqser/common-ui'; +import { + ConfirmOptions, + IconButtonTypes, + IConfirmationDialogData, + LoadingService, + TenantContextHolder, + TitleColors, + Toaster, +} from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { DossierStatsService } from '@services/dossiers/dossier-stats.service'; @@ -47,6 +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 _editDossierDialogRef: MatDialogRef, private readonly _toaster: Toaster, private readonly _loadingService: LoadingService, @@ -144,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.dossier.dossiersListRouterLink]); + await this._router.navigate([`/${this._tenantContextHolder.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/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 fb048bf13..57b6a02bd 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 } from '@iqser/common-ui'; +import { BaseDialogComponent, IconButtonTypes, IqserPermissionsService, SaveOptions, TenantContextHolder } 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,6 +42,7 @@ export class AddDossierDialogComponent extends BaseDialogComponent implements On constructor( readonly permissionsService: IqserPermissionsService, + private readonly _tenantContextHolder: TenantContextHolder, private readonly _activeDossiersService: ActiveDossiersService, private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _reportTemplateController: ReportTemplateService, @@ -82,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([savedDossier.routerLink]); + await this._router.navigate([`/${this._tenantContextHolder.currentTenant}${savedDossier.routerLink}`]); if (options?.addMembers) { this._dialogService.openDialog('editDossier', { dossierId: savedDossier.id, diff --git a/apps/red-ui/src/app/modules/trash/trash-screen/trash-table-item/trash-table-item.component.html b/apps/red-ui/src/app/modules/trash/trash-screen/trash-table-item/trash-table-item.component.html index c328c4ca3..c7d6ebb58 100644 --- a/apps/red-ui/src/app/modules/trash/trash-screen/trash-table-item/trash-table-item.component.html +++ b/apps/red-ui/src/app/modules/trash/trash-screen/trash-table-item/trash-table-item.component.html @@ -20,7 +20,11 @@
- + {{ fileDossier.dossierName }} diff --git a/apps/red-ui/src/app/modules/trash/trash.module.ts b/apps/red-ui/src/app/modules/trash/trash.module.ts index a86df8312..aa1cfe00e 100644 --- a/apps/red-ui/src/app/modules/trash/trash.module.ts +++ b/apps/red-ui/src/app/modules/trash/trash.module.ts @@ -2,7 +2,7 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { TrashScreenComponent } from './trash-screen/trash-screen.component'; -import { CircleButtonComponent, IqserListingModule, IqserUsersModule } from '@iqser/common-ui'; +import { CircleButtonComponent, IqserListingModule, IqserUsersModule, TenantPipe } from '@iqser/common-ui'; import { TrashTableItemComponent } from './trash-screen/trash-table-item/trash-table-item.component'; import { SharedModule } from '@shared/shared.module'; import { TrashDialogService } from './services/trash-dialog.service'; @@ -20,6 +20,7 @@ const routes = [{ path: '', component: TrashScreenComponent }]; TranslateModule, IqserListingModule, CircleButtonComponent, + TenantPipe, ], providers: [TrashDialogService], }) 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 7307ec389..5531ac4d0 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,15 +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, RequiredParam, Validate } from '@iqser/common-ui'; +import { EntitiesService, mapEach, RequiredParam, TenantContextHolder, Validate } from '@iqser/common-ui'; import { NGXLogger } from 'ngx-logger'; -import { TenantContext } from '@utils/tenant-context'; @Injectable() export class FileDownloadService extends EntitiesService { protected readonly _defaultModelPath = 'async/download'; protected readonly _entityClass = DownloadStatus; - protected readonly _tenantContext = inject(TenantContext); + protected readonly _tenantContext = inject(TenantContextHolder); constructor(private readonly _configService: ConfigService, private readonly _logger: NGXLogger) { super(); @@ -37,7 +36,7 @@ export class FileDownloadService extends EntitiesService { @@ -40,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([route]); + await this.#router.navigate([`/${this.#tenantContextHolder.currentTenant}${route}`]); }), catchError(showArchiveFailedToast), ); 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 a7a976343..fc2a0d39a 100644 --- a/apps/red-ui/src/app/services/router-history.service.ts +++ b/apps/red-ui/src/app/services/router-history.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@angular/core'; import { NavigationEnd, Router } from '@angular/router'; import { filter } from 'rxjs/operators'; +import { TenantContextHolder } from '@iqser/common-ui'; const LAST_DOSSIERS_SCREEN = 'routerHistory_lastDossiersScreen'; @@ -10,7 +11,8 @@ const LAST_DOSSIERS_SCREEN = 'routerHistory_lastDossiersScreen'; export class RouterHistoryService { private _lastDossiersScreen = localStorage.getItem(LAST_DOSSIERS_SCREEN); - constructor(private readonly _router: Router) { + constructor(private readonly _router: Router, private readonly _tenantContextHolder: TenantContextHolder) { + // 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')) { this._lastDossiersScreen = event.url; @@ -21,9 +23,10 @@ export class RouterHistoryService { navigateToLastDossiersScreen(): void { if (this._router.url === decodeURI(this._lastDossiersScreen)) { - this._router.navigate(['/']); + this._router.navigate(['/' + this._tenantContextHolder.currentTenant]); } else { const url = decodeURI(this._lastDossiersScreen).split('?')[0]; + // todo links this._router.navigate([url]); } } 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 7a5b156ec..91e238537 100644 --- a/apps/red-ui/src/app/users/red-role.guard.ts +++ b/apps/red-ui/src/app/users/red-role.guard.ts @@ -1,7 +1,7 @@ import { inject, Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { UserService } from './user.service'; -import { IqserPermissionsService, IqserRoleGuard } from '@iqser/common-ui'; +import { IqserPermissionsService, IqserRoleGuard, TenantContextHolder } from '@iqser/common-ui'; @Injectable({ providedIn: 'root', @@ -9,19 +9,20 @@ import { IqserPermissionsService, IqserRoleGuard } from '@iqser/common-ui'; 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(['/auth-error']); + await this._router.navigate([`/${this._tenantContextHolder.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(['/main/admin/users']); + await this._router.navigate([`/${this._tenantContextHolder.currentTenant}/main/admin/users`]); return false; } @@ -29,9 +30,9 @@ export class RedRoleGuard extends IqserRoleGuard { currentUser.isUserAdmin && !currentUser.isAdmin && !currentUser.isUser && - !(state.url.startsWith('/main/admin/users') || state.url.startsWith('/main/account')) + !(state.url.includes('/main/admin/users') || state.url.includes('/main/account')) ) { - await this._router.navigate(['/main/admin/users']); + await this._router.navigate([`/${this._tenantContextHolder.currentTenant}/main/admin/users`]); return false; } @@ -40,9 +41,9 @@ export class RedRoleGuard extends IqserRoleGuard { return true; } if (!currentUser.isUser) { - await this._router.navigate(['/main/admin']); + await this._router.navigate([`/${this._tenantContextHolder.currentTenant}/main/admin`]); } else { - await this._router.navigate(['/']); + await this._router.navigate([`/${this._tenantContextHolder.currentTenant}`]); } return false; } diff --git a/apps/red-ui/src/app/utils/configuration.initializer.ts b/apps/red-ui/src/app/utils/configuration.initializer.ts index 7a2f34965..2472b86cc 100644 --- a/apps/red-ui/src/app/utils/configuration.initializer.ts +++ b/apps/red-ui/src/app/utils/configuration.initializer.ts @@ -1,9 +1,9 @@ import { catchError, filter, switchMap, tap } from 'rxjs/operators'; import { ConfigService } from '@services/config.service'; import { firstValueFrom, map, of, throwError } from 'rxjs'; -import { KeycloakEventType, KeycloakService } from 'keycloak-angular'; +import { KeycloakService } from 'keycloak-angular'; import { GeneralSettingsService } from '@services/general-settings.service'; -import { IqserPermissionsService, LanguageService } from '@iqser/common-ui'; +import { IqserPermissionsService, KeycloakStatus, KeycloakStatusService, LanguageService } from '@iqser/common-ui'; import { UserPreferenceService } from '@users/user-preference.service'; import { UserService } from '@users/user.service'; import { FeaturesService } from '@services/features.service'; @@ -21,6 +21,7 @@ function lastDossierTemplateRedirect(baseHref: string, userPreferenceService: Us export function configurationInitializer( baseHref: string, + keycloakStatusService: KeycloakStatusService, keycloakService: KeycloakService, configService: ConfigService, systemPreferencesService: SystemPreferencesService, @@ -32,8 +33,9 @@ export function configurationInitializer( licenseService: LicenseService, permissionsService: IqserPermissionsService, ) { - const setup = keycloakService.keycloakEvents$.pipe( - filter(event => event.type === KeycloakEventType.OnReady), + console.log('BASE HREF: ', baseHref); + const setup = keycloakStatusService.keycloakStatus$.pipe( + filter(event => event === KeycloakStatus.READY || event === KeycloakStatus.NOT_ACTIVE), map(() => featuresService.loadConfig()), switchMap(() => keycloakService.isLoggedIn()), switchMap(loggedIn => (!loggedIn ? throwError(() => 'Not Logged In') : of({}))), @@ -43,8 +45,12 @@ export function configurationInitializer( tap(configuration => configService.updateDisplayName(configuration.displayName)), switchMap(() => systemPreferencesService.loadPreferences()), switchMap(() => userPreferenceService.reload()), - catchError(e => { + catchError((e: unknown) => { console.log('[Redaction] Initialization error:', e); + if (keycloakStatusService.keycloakStatus$.value === KeycloakStatus.READY) { + return of(userService.redirectToLogin()); + } + return of({}); }), tap(() => { diff --git a/apps/red-ui/src/app/utils/tenant-context.ts b/apps/red-ui/src/app/utils/tenant-context.ts deleted file mode 100644 index e4efbcb85..000000000 --- a/apps/red-ui/src/app/utils/tenant-context.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ providedIn: 'root' }) -export class TenantContext { - getTenant(): string { - return 'redaction'; - } -} diff --git a/apps/red-ui/src/app/utils/tenant-id-interceptor.ts b/apps/red-ui/src/app/utils/tenant-id-interceptor.ts deleted file mode 100644 index 4deddeca1..000000000 --- a/apps/red-ui/src/app/utils/tenant-id-interceptor.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; -import { inject, Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { TenantContext } from '@utils/tenant-context'; - -@Injectable() -export class TenantIdInterceptor implements HttpInterceptor { - protected readonly _tenantContext = inject(TenantContext); - - intercept(req: HttpRequest, next: HttpHandler): Observable> { - const updatedRequest = req.clone({ - setHeaders: { 'X-TENANT-ID': this._tenantContext.getTenant() }, - }); - return next.handle(updatedRequest); - } -} diff --git a/apps/red-ui/src/app/utils/tenant-id-response-interceptor.ts b/apps/red-ui/src/app/utils/tenant-id-response-interceptor.ts deleted file mode 100644 index 25449f010..000000000 --- a/apps/red-ui/src/app/utils/tenant-id-response-interceptor.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; - -const VALID_TENANT_IDS = ['redaction']; - -@Injectable() -export class TenantIdResponseInterceptor implements HttpInterceptor { - intercept(req: HttpRequest, next: HttpHandler): Observable> { - return next.handle(req).pipe( - tap(event => { - if (event instanceof HttpResponse) { - const xTenantId = event.headers.get('X-TENANT-ID'); - if (VALID_TENANT_IDS.includes(xTenantId)) { - //TODO add logic to deny the response when backend will send the header - } - } - }), - ); - } -} diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json index c81f4bc32..7ff543187 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-08.iqser.cloud/redaction-gateway-v1", + "API_URL": "https://dom1.iqser.cloud/redaction-gateway-v1", "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-08.iqser.cloud/auth/realms/redaction", + "OAUTH_URL": "https://dom1.iqser.cloud/auth", "RECENT_PERIOD_IN_HOURS": 24, "SELECTION_MODE": "structural", "MANUAL_BASE_URL": "https://docs.redactmanager.com/preview", diff --git a/apps/red-ui/src/assets/i18n/redact/de.json b/apps/red-ui/src/assets/i18n/redact/de.json index ba2c6f114..f282d792a 100644 --- a/apps/red-ui/src/assets/i18n/redact/de.json +++ b/apps/red-ui/src/assets/i18n/redact/de.json @@ -1764,6 +1764,7 @@ "title": "Benachrichtigungseinstellungen" }, "notifications": { + "button-text": "", "deleted-dossier": "", "label": "Benachrichtigungen", "mark-all-as-read": "Alle als gelesen markieren", @@ -1815,11 +1816,6 @@ "previous": "Vorherige" }, "pdf-viewer": { - "text-popup": { - "actions": { - "search": "Nach Auswahl suchen" - } - }, "toggle-readable-redactions": "", "toggle-tooltips": "{active, select, true{Disable} false{Enable} other{}} Kurzinfos für Anmerkungen" }, @@ -2051,6 +2047,15 @@ }, "title": "Authentifizierung aktivieren" }, + "tenant-resolve": { + "actions": { + "save": "Proceed" + }, + "form": { + "tenant-placeholder": "Select a tenant ..." + }, + "header": "Select your Tenant" + }, "time": { "days": "{days} {days, plural, one{Tag} other{Tage}}", "hours": "{hours} {hours, plural, one{Stunde} other{Stunden}}", @@ -2078,6 +2083,7 @@ "label": "Sprache" }, "logout": "Abmelden", + "select-tenant": "Select Tenant", "trash": "Papierkorb" } } @@ -2180,6 +2186,9 @@ } }, "user-management": "Benutzerverwaltung", + "user-menu": { + "button-text": "" + }, "user-profile": "Mein Profil", "user-profile-screen": { "actions": { diff --git a/apps/red-ui/src/assets/i18n/redact/en.json b/apps/red-ui/src/assets/i18n/redact/en.json index a6950c81d..da4fa4495 100644 --- a/apps/red-ui/src/assets/i18n/redact/en.json +++ b/apps/red-ui/src/assets/i18n/redact/en.json @@ -1764,6 +1764,7 @@ "title": "Notifications Preferences" }, "notifications": { + "button-text": "Notifications", "deleted-dossier": "Deleted Dossier", "label": "Notifications", "mark-all-as-read": "Mark all as read", @@ -1815,11 +1816,6 @@ "previous": "Prev" }, "pdf-viewer": { - "text-popup": { - "actions": { - "search": "Search for selection" - } - }, "toggle-readable-redactions": "Show redactions {active, select, true{as in final document} false{in preview color} other{}}", "toggle-tooltips": "{active, select, true{Disable} false{Enable} other{}} annotation tooltips" }, @@ -2051,6 +2047,15 @@ }, "title": "Enable Authentication" }, + "tenant-resolve": { + "actions": { + "save": "Proceed" + }, + "form": { + "tenant-placeholder": "Select a tenant ..." + }, + "header": "Select your Tenant" + }, "time": { "days": "{days} {days, plural, one{day} other{days}}", "hours": "{hours} {hours, plural, one{hour} other{hours}}", @@ -2078,6 +2083,7 @@ "label": "Language" }, "logout": "Logout", + "select-tenant": "Select Tenant", "trash": "Trash" } } @@ -2180,6 +2186,9 @@ } }, "user-management": "User Management", + "user-menu": { + "button-text": "User menu" + }, "user-profile": "My Profile", "user-profile-screen": { "actions": { diff --git a/apps/red-ui/src/assets/i18n/scm/de.json b/apps/red-ui/src/assets/i18n/scm/de.json index d6c71b494..a70ccebdd 100644 --- a/apps/red-ui/src/assets/i18n/scm/de.json +++ b/apps/red-ui/src/assets/i18n/scm/de.json @@ -1764,6 +1764,7 @@ "title": "Benachrichtigungseinstellungen" }, "notifications": { + "button-text": "", "deleted-dossier": "", "label": "Benachrichtigungen", "mark-all-as-read": "Alle als gelesen markieren", @@ -1815,11 +1816,6 @@ "previous": "Vorherige" }, "pdf-viewer": { - "text-popup": { - "actions": { - "search": "Nach Auswahl suchen" - } - }, "toggle-readable-redactions": "", "toggle-tooltips": "{active, select, true{Disable} false{Enable} other{}} Kurzinfos für Anmerkungen" }, @@ -2051,6 +2047,15 @@ }, "title": "Authentifizierung aktivieren" }, + "tenant-resolve": { + "actions": { + "save": "Proceed" + }, + "form": { + "tenant-placeholder": "Select a tenant ..." + }, + "header": "Select your Tenant" + }, "time": { "days": "{days} {days, plural, one{Tag} other{Tage}}", "hours": "{hours} {hours, plural, one{Stunde} other{Stunden}}", @@ -2078,6 +2083,7 @@ "label": "Sprache" }, "logout": "Abmelden", + "select-tenant": "Select Tenant", "trash": "Papierkorb" } } @@ -2180,6 +2186,9 @@ } }, "user-management": "Benutzerverwaltung", + "user-menu": { + "button-text": "" + }, "user-profile": "Mein Profil", "user-profile-screen": { "actions": { diff --git a/apps/red-ui/src/assets/i18n/scm/en.json b/apps/red-ui/src/assets/i18n/scm/en.json index 59f92efd4..ea9c964eb 100644 --- a/apps/red-ui/src/assets/i18n/scm/en.json +++ b/apps/red-ui/src/assets/i18n/scm/en.json @@ -1764,6 +1764,7 @@ "title": "Notifications Preferences" }, "notifications": { + "button-text": "", "deleted-dossier": "Deleted Dossier", "label": "Notifications", "mark-all-as-read": "Mark all as read", @@ -1815,11 +1816,6 @@ "previous": "Prev" }, "pdf-viewer": { - "text-popup": { - "actions": { - "search": "Search for selection" - } - }, "toggle-readable-redactions": "Show components {active, select, true{as in final document} false{in preview color} other{}}", "toggle-tooltips": "{active, select, true{Disable} false{Enable} other{}} annotation tooltips" }, @@ -2051,6 +2047,15 @@ }, "title": "Enable Authentication" }, + "tenant-resolve": { + "actions": { + "save": "Proceed" + }, + "form": { + "tenant-placeholder": "Select a tenant ..." + }, + "header": "Select your Tenant" + }, "time": { "days": "{days} {days, plural, one{day} other{days}}", "hours": "{hours} {hours, plural, one{hour} other{hours}}", @@ -2078,6 +2083,7 @@ "label": "Language" }, "logout": "Logout", + "select-tenant": "Select Tenant", "trash": "Trash" } } @@ -2180,6 +2186,9 @@ } }, "user-management": "User Management", + "user-menu": { + "button-text": "" + }, "user-profile": "My Profile", "user-profile-screen": { "actions": { diff --git a/libs/common-ui b/libs/common-ui index ba21886e2..9bb761990 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit ba21886e27187490c526816c4692c541384e1f5f +Subproject commit 9bb7619907b3965da28a3477addcb3a3082d4b3b diff --git a/package.json b/package.json index c1a034e50..077cd9ca0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redaction", - "version": "4.31.0", + "version": "4.39.0", "private": true, "license": "MIT", "scripts": { diff --git a/paligo-theme.tar.gz b/paligo-theme.tar.gz index 752aacd0c..dc6137107 100644 Binary files a/paligo-theme.tar.gz and b/paligo-theme.tar.gz differ