diff --git a/apps/red-ui/src/app/app-routing.module.ts b/apps/red-ui/src/app/app-routing.module.ts index 5eb70338e..ccf478b4b 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -1,22 +1,12 @@ import { AuthErrorComponent } from '@components/auth-error/auth-error.component'; -import { - CompositeRouteGuard, - CustomRouteReuseStrategy, - DEFAULT_REDIRECT_KEY, - ifLoggedIn, - ifNotLoggedIn, - IqserAuthGuard, - IqserPermissionsGuard, - IqserRoutes, - TenantSelectComponent, -} from '@iqser/common-ui'; +import { CompositeRouteGuard, DEFAULT_REDIRECT_KEY, IqserPermissionsGuard, IqserRoutes } from '@iqser/common-ui'; import { RedRoleGuard } from '@users/red-role.guard'; import { BaseScreenComponent } from '@components/base-screen/base-screen.component'; import { RouteReuseStrategy, RouterModule } from '@angular/router'; import { NgModule } from '@angular/core'; import { DownloadsListScreenComponent } from '@components/downloads-list-screen/downloads-list-screen.component'; -import { DossiersGuard } from '@guards/dossiers.guard'; -import { ACTIVE_DOSSIERS_SERVICE, ARCHIVED_DOSSIERS_SERVICE } from './tokens'; +import { loadActiveDossiersGuard, loadAllDossiersGuard, loadArchivedDossiersGuard } from '@guards/dossiers.guard'; +import { ACTIVE_DOSSIERS_SERVICE } from './tokens'; import { FeaturesGuard } from '@guards/features-guard.service'; import { DossierTemplatesGuard } from '@guards/dossier-templates.guard'; import { templateExistsWhenEnteringDossierList } from '@guards/dossier-template-exists.guard'; @@ -24,17 +14,20 @@ import { DashboardGuard } from '@guards/dashboard-guard.service'; import { TrashGuard } from '@guards/trash.guard'; import { ARCHIVE_ROUTE, BreadcrumbTypes, DOSSIER_ID, DOSSIER_TEMPLATE_ID, DOSSIERS_ARCHIVE, DOSSIERS_ROUTE, FILE_ID } from '@red/domain'; import { DossierFilesGuard } from '@guards/dossier-files-guard'; -import { WebViewerLoadedGuard } from './modules/pdf-viewer/services/webviewer-loaded.guard'; +import { webViewerLoadedGuard } from './modules/pdf-viewer/services/webviewer-loaded.guard'; import { Roles } from '@users/roles'; import { mainResolver } from '@utils/main.resolver'; +import { hasAnyRoleGuard, IqserAuthGuard } from '@iqser/common-ui/lib/users'; +import { CustomRouteReuseStrategy } from '@iqser/common-ui/lib/utils'; +import { ifLoggedIn } from '@guards/if-logged-in.guard'; +import { ifNotLoggedIn } from '@guards/if-not-logged-in.guard'; +import { TenantSelectComponent } from '@iqser/common-ui/lib/tenants'; const dossierTemplateIdRoutes: IqserRoutes = [ { path: `${DOSSIERS_ROUTE}`, - canActivate: [CompositeRouteGuard, IqserPermissionsGuard], + canActivate: [loadActiveDossiersGuard(), IqserPermissionsGuard], data: { - routeGuards: [DossiersGuard], - dossiersService: ACTIVE_DOSSIERS_SERVICE, permissions: { allow: [Roles.files.readStatus], redirectTo: '/auth-error', @@ -58,9 +51,9 @@ const dossierTemplateIdRoutes: IqserRoutes = [ }, { path: `:${DOSSIER_ID}/file/:${FILE_ID}`, - canActivate: [CompositeRouteGuard, IqserPermissionsGuard], + canActivate: [CompositeRouteGuard, IqserPermissionsGuard, webViewerLoadedGuard()], data: { - routeGuards: [DossierFilesGuard, WebViewerLoadedGuard], + routeGuards: [DossierFilesGuard], breadcrumbs: [BreadcrumbTypes.dossierTemplate, BreadcrumbTypes.dossier, BreadcrumbTypes.file], dossiersService: ACTIVE_DOSSIERS_SERVICE, permissions: { @@ -83,10 +76,9 @@ const dossierTemplateIdRoutes: IqserRoutes = [ { path: `${ARCHIVE_ROUTE}`, loadChildren: () => import('./modules/archive/archive.module').then(m => m.ArchiveModule), - canActivate: [CompositeRouteGuard, WebViewerLoadedGuard], + canActivate: [CompositeRouteGuard, webViewerLoadedGuard(), loadArchivedDossiersGuard()], data: { - routeGuards: [FeaturesGuard, DossiersGuard], - dossiersService: ARCHIVED_DOSSIERS_SERVICE, + routeGuards: [FeaturesGuard], features: [DOSSIERS_ARCHIVE], }, }, @@ -155,9 +147,9 @@ const mainRoutes: IqserRoutes = [ { path: 'search', loadChildren: () => import('./modules/search/search.module').then(m => m.SearchModule), - canActivate: [CompositeRouteGuard, IqserPermissionsGuard], + canActivate: [CompositeRouteGuard, IqserPermissionsGuard, loadAllDossiersGuard()], data: { - routeGuards: [IqserAuthGuard, RedRoleGuard, DossiersGuard], + routeGuards: [IqserAuthGuard, RedRoleGuard], permissions: { allow: [Roles.search], redirectTo: '/auth-error', @@ -167,10 +159,9 @@ const mainRoutes: IqserRoutes = [ { path: 'trash', loadChildren: () => import('./modules/trash/trash.module').then(m => m.TrashModule), - canActivate: [CompositeRouteGuard, IqserPermissionsGuard], + canActivate: [CompositeRouteGuard, IqserPermissionsGuard, loadActiveDossiersGuard()], data: { - routeGuards: [IqserAuthGuard, RedRoleGuard, DossiersGuard, TrashGuard], - dossiersService: ACTIVE_DOSSIERS_SERVICE, + routeGuards: [IqserAuthGuard, RedRoleGuard, TrashGuard], permissions: { allow: [Roles.dossiers.read, Roles.files.readStatus], redirectTo: '/auth-error', @@ -182,7 +173,7 @@ const mainRoutes: IqserRoutes = [ children: dossierTemplateIdRoutes, canActivate: [CompositeRouteGuard, IqserPermissionsGuard, templateExistsWhenEnteringDossierList()], data: { - routeGuards: [IqserAuthGuard, RedRoleGuard, DossierTemplatesGuard, DashboardGuard], + routeGuards: [IqserAuthGuard, RedRoleGuard], permissions: { allow: [ Roles.any, @@ -210,7 +201,7 @@ const routes: IqserRoutes = [ { path: '', pathMatch: 'full', - canActivate: [ifNotLoggedIn], + canActivate: [ifNotLoggedIn()], component: TenantSelectComponent, }, { @@ -220,7 +211,7 @@ const routes: IqserRoutes = [ }, { path: ':tenant/main', - canActivate: [ifLoggedIn], + canActivate: [ifLoggedIn()], component: BaseScreenComponent, resolve: { whateverThisMainRouteNeeds: mainResolver, @@ -230,7 +221,7 @@ const routes: IqserRoutes = [ { path: ':tenant/auth-error', component: AuthErrorComponent, - canActivate: [IqserAuthGuard], + canActivate: [hasAnyRoleGuard()], }, { path: '**', diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index e4d0d0f72..944d621cd 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -9,7 +9,6 @@ import { CachingModule, ChevronButtonComponent, CircleButtonComponent, - CommonUiModule, EmptyStateComponent, HelpModeKey, HiddenActionDirective, @@ -21,18 +20,12 @@ import { IqserListingModule, IqserLoadingModule, IqserTranslateModule, - IqserUsersModule, LanguageService, - LogoComponent, MAX_RETRIES_ON_SERVER_ERROR, RoundCheckboxComponent, SERVER_ERROR_SKIP_PATHS, ServerErrorInterceptor, - SkeletonComponent, StopPropagationDirective, - TenantPipe, - TenantsModule, - ToastComponent, } from '@iqser/common-ui'; import { ToastrModule } from 'ngx-toastr'; import { ServiceWorkerModule } from '@angular/service-worker'; @@ -71,6 +64,10 @@ import { SkeletonStatsComponent } from '@components/skeleton/skeleton-stats/skel import { UserMenuComponent } from '@components/user-menu/user-menu.component'; import { TenantsMenuComponent } from '@components/tenants-menu/tenants-menu.component'; import { MatDividerModule } from '@angular/material/divider'; +import { IqserUsersModule } from '@iqser/common-ui/lib/users'; +import { CommonUiModule } from '@iqser/common-ui/lib/common-ui.module'; +import { LogoComponent, SkeletonComponent, ToastComponent } from '@iqser/common-ui/lib/shared'; +import { TenantPipe, TenantsModule } from '@iqser/common-ui/lib/tenants'; export const appModuleFactory = (config: AppConfig) => { @NgModule({ @@ -144,10 +141,10 @@ export const appModuleFactory = (config: AppConfig) => { enabled: true, }, FILE: { - enabled: false, + enabled: true, }, CHANGES: { - enabled: false, + enabled: true, }, STATS: { enabled: false, 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 3961f1bb6..f37002b13 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 @@ -6,15 +6,17 @@ import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; import { SpotlightSearchAction } from '@components/spotlight-search/spotlight-search-action'; import { filter, map, startWith } from 'rxjs/operators'; -import { IqserPermissionsService, List, shareDistinctLast, TenantsService } from '@iqser/common-ui'; +import { IqserPermissionsService } 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'; import { Roles } from '@users/roles'; import { REDDocumentViewer } from '../../modules/pdf-viewer/services/document-viewer.service'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { List, shareDistinctLast } from '@iqser/common-ui/lib/utils'; +import { TenantsService } from '@iqser/common-ui/lib/tenants'; -const isNavigationStart = event => event instanceof NavigationStart; +const isNavigationStart = (event: unknown): event is NavigationStart => event instanceof NavigationStart; const isSearchScreen: (url: string) => boolean = url => url.includes('/search'); @Component({ @@ -22,6 +24,12 @@ const isSearchScreen: (url: string) => boolean = url => url.includes('/search'); styleUrls: ['./base-screen.component.scss'], }) export class BaseScreenComponent { + readonly #navigationStart$ = this._router.events.pipe( + filter(isNavigationStart), + map(event => event.url), + startWith(this._router.url), + shareDistinctLast(), + ); readonly roles = Roles; readonly documentViewer = inject(REDDocumentViewer); readonly currentUser = this.userService.currentUser; @@ -44,12 +52,6 @@ export class BaseScreenComponent { action: (query): void => this.#search(query, []), }, ]; - 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)); constructor( diff --git a/apps/red-ui/src/app/components/notifications/notifications.component.html b/apps/red-ui/src/app/components/notifications/notifications.component.html index 8b65174a4..5f2b7e66b 100644 --- a/apps/red-ui/src/app/components/notifications/notifications.component.html +++ b/apps/red-ui/src/app/components/notifications/notifications.component.html @@ -1,8 +1,8 @@ @@ -25,7 +25,7 @@ *ngIf="(hasUnreadNotifications$ | async) && first" class="view-all" id="notifications-mark-all-as-read-btn" - stopPropagation + iqserStopPropagation > {{ 'notifications.mark-all-as-read' | translate }} @@ -37,8 +37,8 @@ [class.unread]="!notification.readDate" [id]="'notifications-mark-as-read-' + notification.id + '-btn'" class="notification" + iqserStopPropagation mat-menu-item - stopPropagation > @@ -51,9 +51,9 @@ (click)="markRead([notification], !notification.readDate)" [id]="'notifications-mark-' + notification.id" class="dot" + iqserStopPropagation matTooltip="{{ 'notifications.mark-as' | translate : { type: notification.readDate ? 'unread' : 'read' } }}" matTooltipPosition="before" - stopPropagation > diff --git a/apps/red-ui/src/app/components/notifications/notifications.component.ts b/apps/red-ui/src/app/components/notifications/notifications.component.ts index 5d9a56c96..743dcda00 100644 --- a/apps/red-ui/src/app/components/notifications/notifications.component.ts +++ b/apps/red-ui/src/app/components/notifications/notifications.component.ts @@ -4,7 +4,7 @@ import { NotificationsService } from '@services/notifications.service'; import { Notification } from '@red/domain'; import { distinctUntilChanged, map } from 'rxjs/operators'; import { Observable } from 'rxjs'; -import { isToday, shareLast, trackByFactory } from '@iqser/common-ui'; +import { isToday, shareLast, trackByFactory } from '@iqser/common-ui/lib/utils'; import dayjs, { Dayjs } from 'dayjs'; import { TranslateService } from '@ngx-translate/core'; diff --git a/apps/red-ui/src/app/components/tenants-menu/tenants-menu.component.html b/apps/red-ui/src/app/components/tenants-menu/tenants-menu.component.html index 66bf2b5f3..96ee8315f 100644 --- a/apps/red-ui/src/app/components/tenants-menu/tenants-menu.component.html +++ b/apps/red-ui/src/app/components/tenants-menu/tenants-menu.component.html @@ -1,11 +1,11 @@
- +
{{ item.key }}
{{ stored.email }} diff --git a/apps/red-ui/src/app/components/tenants-menu/tenants-menu.component.ts b/apps/red-ui/src/app/components/tenants-menu/tenants-menu.component.ts index c2cd0fc77..01054e7ea 100644 --- a/apps/red-ui/src/app/components/tenants-menu/tenants-menu.component.ts +++ b/apps/red-ui/src/app/components/tenants-menu/tenants-menu.component.ts @@ -1,8 +1,10 @@ import { Component, inject } from '@angular/core'; -import { BASE_HREF, getConfig, getCurrentUser, IStoredTenant, KeycloakStatusService, TenantsService } from '@iqser/common-ui'; +import { getConfig } from '@iqser/common-ui'; import { User } from '@red/domain'; -import { KeyValue } from '@angular/common'; import { KeycloakService } from 'keycloak-angular'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { BASE_HREF } from '@iqser/common-ui/lib/utils'; +import { getKeycloakOptions, IStoredTenantId, KeycloakStatusService, TenantsService } from '@iqser/common-ui/lib/tenants'; @Component({ selector: 'app-tenants-menu', @@ -10,48 +12,49 @@ import { KeycloakService } from 'keycloak-angular'; styleUrls: ['./tenants-menu.component.scss'], }) export class TenantsMenuComponent { - readonly tenantsService = inject(TenantsService); - readonly storedTenants: Map; readonly #baseHref = inject(BASE_HREF); readonly #keycloakService = inject(KeycloakService); readonly #keycloakStatusService = inject(KeycloakStatusService); readonly #currentUser = getCurrentUser(); readonly #config = getConfig(); + readonly tenantsService = inject(TenantsService); + readonly storedTenants: { key: string; value: IStoredTenantId[] }[]; constructor() { this.storedTenants = this.#getStoredTenants(); } - trackBy(_index: number, item: KeyValue) { + trackBy(_index: number, item: { key: string; value: IStoredTenantId[] }) { return item.key; } + // TODO: this should be moved to the keycloak status service async selectTenant(tenantId?: string, email?: string) { - let tenantUrl = tenantId ? '/' + tenantId : '/'; - if (email) { - tenantUrl += '?username=' + email; + if (tenantId && tenantId !== this.tenantsService.activeTenantId) { + await this.#keycloakService.init(getKeycloakOptions(this.#baseHref, this.#config, tenantId)); } - if (tenantId === this.tenantsService.activeTenantId) { + if (tenantId) { const url = this.#keycloakService.getKeycloakInstance().createLoginUrl({ - redirectUri: this.#keycloakStatusService.createLoginUrl(), + redirectUri: this.#keycloakStatusService.createLoginUrl(tenantId), idpHint: this.#config.OAUTH_IDP_HINT, loginHint: email ?? undefined, }); return this.#keycloakService.logout(url); } - window.open(window.location.origin + this.#baseHref + tenantUrl, '_blank'); + return this.#keycloakService.logout(window.location.origin + this.#baseHref); } - #getStoredTenants(): Map { + #getStoredTenants() { const storedTenants = this.tenantsService.getStoredTenants(); const otherTenant = storedTenants.filter(t => { - const isCurrentTenant = t.tenant.tenantId === this.tenantsService.activeTenantId; + const isCurrentTenant = t.tenantId === this.tenantsService.activeTenantId; const isCurrentUser = t.email === this.#currentUser.email || t.email === this.#currentUser.username; return !(isCurrentTenant && isCurrentUser); }); - return otherTenant.groupBy(t => t.tenant.displayName); + const grouped = otherTenant.groupBy(t => t.tenantId); + return [...grouped.keys()].sort((a, b) => a.localeCompare(b)).map(key => ({ key, value: grouped.get(key) })); } } diff --git a/apps/red-ui/src/app/components/user-menu/user-menu.component.html b/apps/red-ui/src/app/components/user-menu/user-menu.component.html index 5bdf0637e..5cc6b5e25 100644 --- a/apps/red-ui/src/app/components/user-menu/user-menu.component.html +++ b/apps/red-ui/src/app/components/user-menu/user-menu.component.html @@ -5,7 +5,7 @@
- + {{ 'top-bar.navigation-items.my-account.children.select-tenant' | translate }} diff --git a/apps/red-ui/src/app/components/user-menu/user-menu.component.ts b/apps/red-ui/src/app/components/user-menu/user-menu.component.ts index 49690a0ce..3ff2442e5 100644 --- a/apps/red-ui/src/app/components/user-menu/user-menu.component.ts +++ b/apps/red-ui/src/app/components/user-menu/user-menu.component.ts @@ -1,9 +1,12 @@ import { Component, inject } from '@angular/core'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { Roles } from '@users/roles'; -import { getCurrentUser, IqserPermissionsService, List, TenantsService } from '@iqser/common-ui'; +import { IqserPermissionsService } from '@iqser/common-ui'; import { User } from '@red/domain'; import { UserService } from '@users/user.service'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { List } from '@iqser/common-ui/lib/utils'; +import { TenantsService } from '@iqser/common-ui/lib/tenants'; interface MenuItem { readonly id: string; @@ -20,10 +23,10 @@ interface MenuItem { styleUrls: ['./user-menu.component.scss'], }) export class UserMenuComponent { + readonly #permissionsService = inject(IqserPermissionsService); readonly currentUser = getCurrentUser(); readonly tenantsService = inject(TenantsService); readonly userService = inject(UserService); - readonly #permissionsService = inject(IqserPermissionsService); readonly userMenuItems: List = [ { id: 'account', 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 11c6914f4..45ece236d 100644 --- a/apps/red-ui/src/app/guards/dossier-files-guard.ts +++ b/apps/red-ui/src/app/guards/dossier-files-guard.ts @@ -7,7 +7,7 @@ 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 { TenantsService } from '@iqser/common-ui'; +import { TenantsService } from '@iqser/common-ui/lib/tenants'; @Injectable({ providedIn: 'root' }) export class DossierFilesGuard implements CanActivate { 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 ebd2b36f6..840b5c94e 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 @@ -2,7 +2,10 @@ 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 { TenantsService } from '@iqser/common-ui'; +import { TenantsService } from '@iqser/common-ui/lib/tenants'; +import { NGXLogger } from 'ngx-logger'; +import { firstValueFrom } from 'rxjs'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; export function templateExistsWhenEnteringAdmin(): CanActivateFn { return async function (route: ActivatedRouteSnapshot): Promise { @@ -20,10 +23,18 @@ export function templateExistsWhenEnteringAdmin(): CanActivateFn { export function templateExistsWhenEnteringDossierList(): CanActivateFn { return async function (route: ActivatedRouteSnapshot) { const dossierTemplateId: string = route.paramMap.get(DOSSIER_TEMPLATE_ID); + const dashboardStatsService = inject(DashboardStatsService); + const dossierTemplatesService = inject(DossierTemplatesService); + const logger = inject(NGXLogger); + const router = inject(Router); + const tenantsService = inject(TenantsService); - const dossierTemplateStats = inject(DashboardStatsService).find(dossierTemplateId); + await firstValueFrom(dashboardStatsService.loadAll()); + await firstValueFrom(dossierTemplatesService.loadAll()); + const dossierTemplateStats = dashboardStatsService.find(dossierTemplateId); if (!dossierTemplateStats || dossierTemplateStats.isEmpty) { - await inject(Router).navigate([inject(TenantsService).activeTenantId, 'main']); + logger.warn('[ROUTES] Dossier template not found, redirecting to main'); + await router.navigate([tenantsService.activeTenantId, '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 880b45b02..01be634ee 100644 --- a/apps/red-ui/src/app/guards/dossiers.guard.ts +++ b/apps/red-ui/src/app/guards/dossiers.guard.ts @@ -1,45 +1,57 @@ -import { Injectable, Injector, ProviderToken } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; -import { firstValueFrom, forkJoin } from 'rxjs'; -import { take } from 'rxjs/operators'; +import { inject } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivateFn, Router } from '@angular/router'; +import { firstValueFrom } from 'rxjs'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; import { ArchivedDossiersService } from '@services/dossiers/archived-dossiers.service'; -import { DossiersService } from '@services/dossiers/dossiers.service'; -import { ARCHIVE_ROUTE, DOSSIER_TEMPLATE_ID } from '@red/domain'; +import { DOSSIER_TEMPLATE_ID } from '@red/domain'; import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service'; -import { TenantsService } from '@iqser/common-ui'; +import { TenantsService } from '@iqser/common-ui/lib/tenants'; +import { NGXLogger } from 'ngx-logger'; +import { ACTIVE_DOSSIERS_SERVICE, ARCHIVED_DOSSIERS_SERVICE } from '../tokens'; -@Injectable({ providedIn: 'root' }) -export class DossiersGuard implements CanActivate { - constructor( - private readonly _injector: Injector, - private readonly _router: Router, - private readonly _tenantsService: TenantsService, - private readonly _dashboardStatsService: DashboardStatsService, - private readonly _activeDossiersService: ActiveDossiersService, - private readonly _archivedDossiersService: ArchivedDossiersService, - ) {} +export function loadAllDossiersGuard(): CanActivateFn { + return async () => { + const logger = inject(NGXLogger); + logger.info('[GUARDS] loadAllDossiersGuard start'); - async canActivate(route: ActivatedRouteSnapshot): Promise { - const token: ProviderToken = route.data.dossiersService; - if (!token) { - const services = [this._archivedDossiersService, this._activeDossiersService]; - const loading$ = forkJoin(services.map(service => service.loadAll().pipe(take(1)))); - await firstValueFrom(loading$); - return true; - } + const services = [inject(ArchivedDossiersService), inject(ActiveDossiersService)]; + const requests = services.map(service => firstValueFrom(service.loadAll())); + await Promise.all(requests); - const dossiersService: DossiersService = this._injector.get(token); - const isArchive = dossiersService.routerPath === ARCHIVE_ROUTE; + logger.info('[GUARDS] loadAllDossiersGuard end'); + return true; + }; +} + +export function loadActiveDossiersGuard(): CanActivateFn { + return async () => { + const logger = inject(NGXLogger); + logger.info('[GUARDS] loadDossiersGuard start'); + + await firstValueFrom(inject(ACTIVE_DOSSIERS_SERVICE).loadAll()); + + logger.info('[GUARDS] loadDossiersGuard end'); + return true; + }; +} + +export function loadArchivedDossiersGuard(): CanActivateFn { + return async (route: ActivatedRouteSnapshot) => { + const logger = inject(NGXLogger); + logger.info('[GUARDS] loadArchivedDossiersGuard start'); + + const dossiersService = inject(ARCHIVED_DOSSIERS_SERVICE); const dossierTemplateId = route.paramMap.get(DOSSIER_TEMPLATE_ID); - const dossierTemplateStats = this._dashboardStatsService.find(dossierTemplateId); + const dossierTemplateStats = inject(DashboardStatsService).find(dossierTemplateId); - if (isArchive && dossierTemplateStats?.numberOfArchivedDossiers === 0) { - await this._router.navigate([this._tenantsService.activeTenantId, 'main', dossierTemplateId, 'dossiers']); + if (dossierTemplateStats?.numberOfArchivedDossiers === 0) { + logger.info('[GUARDS] loadArchivedDossiersGuard no archived dossiers, redirect to active dossiers page'); + await inject(Router).navigate([inject(TenantsService).activeTenantId, 'main', dossierTemplateId, 'dossiers']); return false; } await firstValueFrom(dossiersService.loadAll()); + logger.info('[GUARDS] loadArchivedDossiersGuard end'); return true; - } + }; } diff --git a/apps/red-ui/src/app/guards/entity-exists-guard.service.ts b/apps/red-ui/src/app/guards/entity-exists-guard.service.ts index 285e1b806..6ade34350 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 @@ -3,7 +3,7 @@ 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 { TenantsService } from '@iqser/common-ui'; +import { TenantsService } from '@iqser/common-ui/lib/tenants'; export function entityExistsGuard(): CanActivateFn { return async function (route: ActivatedRouteSnapshot): Promise { diff --git a/apps/red-ui/src/app/guards/if-logged-in.guard.ts b/apps/red-ui/src/app/guards/if-logged-in.guard.ts new file mode 100644 index 000000000..91a51e440 --- /dev/null +++ b/apps/red-ui/src/app/guards/if-logged-in.guard.ts @@ -0,0 +1,50 @@ +import { ActivatedRouteSnapshot, CanActivateFn, Router } from '@angular/router'; +import { inject } from '@angular/core'; +import { NGXLogger } from 'ngx-logger'; +import { keycloakInitializer, KeycloakStatusService, TenantsService } from '@iqser/common-ui/lib/tenants'; +import { KeycloakService } from 'keycloak-angular'; +import { UserService } from '@users/user.service'; +import { LicenseService } from '@services/license.service'; + +export function ifLoggedIn(): CanActivateFn { + return async (route: ActivatedRouteSnapshot) => { + const logger = inject(NGXLogger); + logger.info('[ROUTES] Check if can activate route', route); + + const tenantsService = inject(TenantsService); + const keycloakService = inject(KeycloakService); + const usersService = inject(UserService); + const licenseService = inject(LicenseService); + const keycloakStatusService = inject(KeycloakStatusService); + + const keycloakInstance = keycloakService.getKeycloakInstance(); + const tenant = route.paramMap.get('tenant'); + const queryParams = new URLSearchParams(window.location.search); + const username = queryParams.get('username'); + + if (!keycloakInstance) { + if (!tenant) { + logger.error('[ROUTES] No tenant found, something is wrong...'); + return inject(Router).navigate(['/']); + } + + logger.info('[KEYCLOAK] Keycloak init...'); + await keycloakInitializer(tenant); + logger.info('[KEYCLOAK] Keycloak init done!'); + await tenantsService.selectTenant(tenant); + await usersService.initialize(); + await licenseService.loadLicenses(); + } + + const isLoggedIn = await keycloakService.isLoggedIn(); + + if (isLoggedIn) { + logger.info('[ROUTES] Is logged in, continuing'); + return true; + } + + logger.warn('[ROUTES] Redirect to login'); + keycloakStatusService.createLoginUrlAndExecute(username); + return false; + }; +} diff --git a/apps/red-ui/src/app/guards/if-not-logged-in.guard.ts b/apps/red-ui/src/app/guards/if-not-logged-in.guard.ts new file mode 100644 index 000000000..80b5beb85 --- /dev/null +++ b/apps/red-ui/src/app/guards/if-not-logged-in.guard.ts @@ -0,0 +1,29 @@ +import { ActivatedRouteSnapshot, CanActivateFn, Router } from '@angular/router'; +import { inject } from '@angular/core'; +import { NGXLogger } from 'ngx-logger'; +import { KeycloakService } from 'keycloak-angular'; + +export function ifNotLoggedIn(): CanActivateFn { + return async (route: ActivatedRouteSnapshot) => { + const logger = inject(NGXLogger); + const router = inject(Router); + const keycloakService = inject(KeycloakService); + + const isLoggedIn = await keycloakService.isLoggedIn(); + + if (!isLoggedIn) { + logger.info('[ROUTES] Not logged in, continuing to selected route'); + return true; + } + + const tenant = route.paramMap.get('tenant') || keycloakService.getKeycloakInstance().realm; + if (!tenant) { + logger.error('[ROUTES] Tenant not found in route or keycloak realm'); + return false; + } + + logger.warn('[ROUTES] Is logged in for ' + tenant + ', redirecting to /' + tenant); + await router.navigate([tenant]); + return false; + }; +} 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 02a3b19d9..c0312d7ee 100644 --- a/apps/red-ui/src/app/guards/watermark-exists.guard.ts +++ b/apps/red-ui/src/app/guards/watermark-exists.guard.ts @@ -2,7 +2,7 @@ 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 { TenantsService } from '@iqser/common-ui'; +import { TenantsService } from '@iqser/common-ui/lib/tenants'; export function watermarkExistsGuard(): CanActivateFn { return async function (route: ActivatedRouteSnapshot) { diff --git a/apps/red-ui/src/app/modules/account/account-routing.module.ts b/apps/red-ui/src/app/modules/account/account-routing.module.ts index 75e216243..086dd3c89 100644 --- a/apps/red-ui/src/app/modules/account/account-routing.module.ts +++ b/apps/red-ui/src/app/modules/account/account-routing.module.ts @@ -1,10 +1,11 @@ import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; -import { CompositeRouteGuard, IqserAuthGuard, IqserPermissionsGuard, IqserRoutes } from '@iqser/common-ui'; +import { CompositeRouteGuard, IqserPermissionsGuard, IqserRoutes } from '@iqser/common-ui'; import { RedRoleGuard } from '@users/red-role.guard'; import { BaseAccountScreenComponent } from './base-account-screen/base-account-screen-component'; import { PreferencesComponent } from './screens/preferences/preferences.component'; import { Roles } from '@users/roles'; +import { IqserAuthGuard } from '@iqser/common-ui/lib/users'; const routes: IqserRoutes = [ { path: '', redirectTo: 'user-profile', pathMatch: 'full' }, diff --git a/apps/red-ui/src/app/modules/account/account-side-nav/account-side-nav.component.ts b/apps/red-ui/src/app/modules/account/account-side-nav/account-side-nav.component.ts index d337c138c..c21b6346c 100644 --- a/apps/red-ui/src/app/modules/account/account-side-nav/account-side-nav.component.ts +++ b/apps/red-ui/src/app/modules/account/account-side-nav/account-side-nav.component.ts @@ -1,8 +1,9 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { getCurrentUser, IqserPermissionsService } from '@iqser/common-ui'; +import { IqserPermissionsService } from '@iqser/common-ui'; import { Roles } from '@users/roles'; import { User } from '@red/domain'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; interface NavItem { readonly label: string; diff --git a/apps/red-ui/src/app/modules/account/account.module.ts b/apps/red-ui/src/app/modules/account/account.module.ts index a8b2382fa..7f35e0d7a 100644 --- a/apps/red-ui/src/app/modules/account/account.module.ts +++ b/apps/red-ui/src/app/modules/account/account.module.ts @@ -6,8 +6,9 @@ import { AccountSideNavComponent } from './account-side-nav/account-side-nav.com import { BaseAccountScreenComponent } from './base-account-screen/base-account-screen-component'; import { NotificationPreferencesService } from './services/notification-preferences.service'; import { TranslateModule } from '@ngx-translate/core'; -import { IconButtonComponent, IqserHelpModeModule, SideNavComponent } from '@iqser/common-ui'; +import { IconButtonComponent, IqserHelpModeModule } from '@iqser/common-ui'; import { PreferencesComponent } from './screens/preferences/preferences.component'; +import { SideNavComponent } from '@iqser/common-ui/lib/shared'; @NgModule({ declarations: [AccountSideNavComponent, BaseAccountScreenComponent, PreferencesComponent], diff --git a/apps/red-ui/src/app/modules/account/screens/notifications/notifications-screen/notifications-screen.component.ts b/apps/red-ui/src/app/modules/account/screens/notifications/notifications-screen/notifications-screen.component.ts index f80144236..1e3a64e7a 100644 --- a/apps/red-ui/src/app/modules/account/screens/notifications/notifications-screen/notifications-screen.component.ts +++ b/apps/red-ui/src/app/modules/account/screens/notifications/notifications-screen/notifications-screen.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { NotificationPreferencesService } from '../../../services/notification-preferences.service'; -import { BaseFormComponent, getCurrentUser, LoadingService, Toaster } from '@iqser/common-ui'; +import { BaseFormComponent, LoadingService, Toaster } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { NotificationCategoriesValues, @@ -12,6 +12,7 @@ import { } from '@red/domain'; import { firstValueFrom } from 'rxjs'; import { notificationsSettingsTranslations } from '@translations/notifications-settings-translations'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; @Component({ templateUrl: './notifications-screen.component.html', @@ -24,6 +25,7 @@ export class NotificationsScreenComponent extends BaseFormComponent implements O readonly notificationGroupsValues = NotificationGroupsValues; readonly translations = notificationsSettingsTranslations; readonly currentUser = getCurrentUser(); + constructor( private readonly _toaster: Toaster, private readonly _formBuilder: UntypedFormBuilder, diff --git a/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.ts b/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.ts index 3ecb9c9cf..765aeeeec 100644 --- a/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.ts +++ b/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.ts @@ -2,8 +2,9 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/ import { PreferencesKeys, UserPreferenceService } from '@users/user-preference.service'; import { FormBuilder, FormGroup } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; -import { AsControl, BaseFormComponent, IqserPermissionsService } from '@iqser/common-ui'; +import { BaseFormComponent, IqserPermissionsService } from '@iqser/common-ui'; import { Roles } from '@users/roles'; +import { AsControl } from '@iqser/common-ui/lib/utils'; interface PreferencesForm { // preferences diff --git a/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.ts b/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.ts index 442b268ce..97ac2f444 100644 --- a/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.ts +++ b/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.ts @@ -2,15 +2,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnInit } import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { DomSanitizer } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; -import { - BaseFormComponent, - getConfig, - IqserPermissionsService, - LanguageService, - LoadingService, - TenantsService, - Toaster, -} from '@iqser/common-ui'; +import { BaseFormComponent, getConfig, IqserPermissionsService, LanguageService, LoadingService, Toaster } from '@iqser/common-ui'; import { AppConfig, IProfile } from '@red/domain'; import { languagesTranslations } from '@translations/languages-translations'; import { UserService } from '@users/user.service'; @@ -19,6 +11,7 @@ import { UserPreferenceService } from '@users/user-preference.service'; import { Roles } from '@users/roles'; import { UserProfileDialogService } from '../services/user-profile-dialog.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { TenantsService } from '@iqser/common-ui/lib/tenants'; @Component({ templateUrl: './user-profile-screen.component.html', @@ -26,12 +19,11 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class UserProfileScreenComponent extends BaseFormComponent implements OnInit { + #profileModel: IProfile; readonly translations = languagesTranslations; readonly devMode = this._userPreferenceService.areDevFeaturesEnabled; readonly changePasswordUrl: string; - #profileModel: IProfile; - constructor( domSanitizer: DomSanitizer, private readonly _userService: UserService, 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 4abb5739d..0f8631355 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 @@ -1,5 +1,5 @@ import { NgModule } from '@angular/core'; -import { CompositeRouteGuard, IqserAuthGuard, IqserPermissionsGuard, IqserRoutes } from '@iqser/common-ui'; +import { CompositeRouteGuard, IqserPermissionsGuard, IqserRoutes } from '@iqser/common-ui'; import { RedRoleGuard } from '@users/red-role.guard'; import { EntitiesListingScreenComponent } from './screens/entities-listing/entities-listing-screen.component'; import { PendingChangesGuard } from '@guards/can-deactivate.guard'; @@ -18,6 +18,7 @@ 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'; +import { IqserAuthGuard } from '@iqser/common-ui/lib/users'; const dossierTemplateIdRoutes: IqserRoutes = [ { diff --git a/apps/red-ui/src/app/modules/admin/admin.module.ts b/apps/red-ui/src/app/modules/admin/admin.module.ts index 8ce9a49ac..67eff6d7f 100644 --- a/apps/red-ui/src/app/modules/admin/admin.module.ts +++ b/apps/red-ui/src/app/modules/admin/admin.module.ts @@ -49,13 +49,13 @@ import { IqserHelpModeModule, IqserListingModule, IqserUploadFileModule, - IqserUsersModule, RoundCheckboxComponent, - TenantPipe, } from '@iqser/common-ui'; import { TranslateModule } from '@ngx-translate/core'; import { AuditInfoDialogComponent } from './dialogs/audit-info-dialog/audit-info-dialog.component'; import { DossierTemplateActionsComponent } from './shared/components/dossier-template-actions/dossier-template-actions.component'; +import { IqserUsersModule } from '@iqser/common-ui/lib/users'; +import { TenantPipe } from '@iqser/common-ui/lib/tenants'; const dialogs = [ AddEditCloneDossierTemplateDialogComponent, 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 75a70446f..635cd8392 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,21 +4,23 @@ 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, TenantsService } from '@iqser/common-ui'; +import { LoadingService } 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'; import { PermissionsService } from '@services/permissions.service'; +import { getParam } from '@iqser/common-ui/lib/utils'; +import { TenantsService } from '@iqser/common-ui/lib/tenants'; @Component({ templateUrl: './base-entity-screen.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) export class BaseEntityScreenComponent { - readonly disabledItems$: Observable; - readonly canDeleteEntity$: Observable; readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); readonly #entityType = getParam(ENTITY_TYPE); + readonly disabledItems$: Observable; + readonly canDeleteEntity$: Observable; constructor( private readonly _router: Router, diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts index 8950b2780..7222506d5 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts @@ -1,13 +1,14 @@ import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { AdminDialogService } from '../../../services/admin-dialog.service'; -import { BaseFormComponent, IProfileUpdateRequest, LoadingService, Toaster } from '@iqser/common-ui'; +import { BaseFormComponent, LoadingService, Toaster } from '@iqser/common-ui'; import { rolesTranslations } from '@translations/roles-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { User } from '@red/domain'; import { UserService } from '@users/user.service'; import { HttpStatusCode } from '@angular/common/http'; import { firstValueFrom } from 'rxjs'; +import { IProfileUpdateRequest } from '@iqser/common-ui/lib/users'; @Component({ selector: 'redaction-user-details', @@ -15,17 +16,15 @@ import { firstValueFrom } from 'rxjs'; styleUrls: ['./user-details.component.scss'], }) export class UserDetailsComponent extends BaseFormComponent implements OnChanges { + /** e.g. a RED_ADMIN is automatically a RED_USER_ADMIN => can't disable RED_USER_ADMIN as long as RED_ADMIN is checked */ + private readonly _ROLE_REQUIREMENTS = { RED_MANAGER: 'RED_USER', RED_ADMIN: 'RED_USER_ADMIN' }; @Input() user: User; @Output() readonly toggleResetPassword = new EventEmitter(); @Output() readonly closeDialog = new EventEmitter(); @Output() readonly cancel = new EventEmitter(); - readonly ROLES = ['RED_USER', 'RED_MANAGER', 'RED_USER_ADMIN', 'RED_ADMIN']; readonly translations = rolesTranslations; - /** e.g. a RED_ADMIN is automatically a RED_USER_ADMIN => can't disable RED_USER_ADMIN as long as RED_ADMIN is checked */ - private readonly _ROLE_REQUIREMENTS = { RED_MANAGER: 'RED_USER', RED_ADMIN: 'RED_USER_ADMIN' }; - constructor( private readonly _formBuilder: UntypedFormBuilder, private readonly _toaster: Toaster, diff --git a/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.ts index 37973b4da..14f21dce0 100644 --- a/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.ts @@ -3,7 +3,6 @@ import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { applyIntervalConstraints } from '@utils/date-inputs-utils'; import { CircleButtonTypes, - getCurrentUser, IqserPermissionsService, ListingComponent, listingProvidersFactory, @@ -19,6 +18,7 @@ import { Dayjs } from 'dayjs'; import { RouterHistoryService } from '@services/router-history.service'; import { Roles } from '@users/roles'; import { AdminDialogService } from '../../services/admin-dialog.service'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; const PAGE_SIZE = 50; @@ -28,6 +28,8 @@ const PAGE_SIZE = 50; providers: listingProvidersFactory(AuditScreenComponent), }) export class AuditScreenComponent extends ListingComponent implements OnInit, OnDestroy { + private _previousFrom: Dayjs; + private _previousTo: Dayjs; readonly circleButtonTypes = CircleButtonTypes; readonly ALL_CATEGORIES = 'allCategories'; readonly ALL_USERS = _('audit-screen.all-users'); @@ -37,11 +39,9 @@ export class AuditScreenComponent extends ListingComponent implements OnI readonly permissionsService = inject(IqserPermissionsService); readonly roles = Roles; readonly currentUser = getCurrentUser(); - categories: string[] = []; userIds: Set; logs: IAuditResponse; - readonly tableColumnConfigs: TableColumnConfig[] = [ { label: _('audit-screen.table-col-names.message') }, { label: _('audit-screen.table-col-names.date') }, @@ -49,8 +49,6 @@ export class AuditScreenComponent extends ListingComponent implements OnI { label: _('audit-screen.table-col-names.category') }, ]; readonly tableHeaderLabel = _('audit-screen.table-header.title'); - private _previousFrom: Dayjs; - private _previousTo: Dayjs; constructor( private readonly _formBuilder: UntypedFormBuilder, diff --git a/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.ts index f111beede..6070e9103 100644 --- a/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.ts @@ -1,21 +1,15 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { DefaultColorTypes, DOSSIER_TEMPLATE_ID, User } from '@red/domain'; import { AdminDialogService } from '../../services/admin-dialog.service'; -import { - CircleButtonTypes, - getCurrentUser, - getParam, - IListable, - ListingComponent, - listingProvidersFactory, - TableColumnConfig, -} from '@iqser/common-ui'; +import { CircleButtonTypes, IListable, ListingComponent, listingProvidersFactory, TableColumnConfig } from '@iqser/common-ui'; import { defaultColorsTranslations } from '@translations/default-colors-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { combineLatest } from 'rxjs'; import { map, tap } from 'rxjs/operators'; import { DefaultColorsService } from '@services/entity-services/default-colors.service'; import { Roles } from '@users/roles'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { getParam } from '@iqser/common-ui/lib/utils'; interface ListItem extends IListable { readonly key: string; @@ -29,6 +23,7 @@ interface ListItem extends IListable { providers: listingProvidersFactory(DefaultColorsScreenComponent), }) export class DefaultColorsScreenComponent extends ListingComponent { + readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = getCurrentUser(); readonly roles = Roles; @@ -39,7 +34,6 @@ export class DefaultColorsScreenComponent extends ListingComponent { { label: _('default-colors-screen.table-col-names.color'), class: 'flex-center' }, ]; readonly context$; - readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); constructor(private readonly _dialogService: AdminDialogService, private readonly _defaultColorsService: DefaultColorsService) { super(); diff --git a/apps/red-ui/src/app/modules/admin/screens/digital-signature/digital-signature-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/digital-signature/digital-signature-screen.component.ts index 9034f49ee..9f866c301 100644 --- a/apps/red-ui/src/app/modules/admin/screens/digital-signature/digital-signature-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/digital-signature/digital-signature-screen.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; -import { getCurrentUser, IconButtonTypes, IqserPermissionsService, LoadingService, Toaster } from '@iqser/common-ui'; +import { IconButtonTypes, IqserPermissionsService, LoadingService, Toaster } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { RouterHistoryService } from '@services/router-history.service'; import { DigitalSignatureService } from '../../services/digital-signature.service'; @@ -9,6 +9,7 @@ import { PkcsSignatureConfigurationComponent } from '../../dialogs/configure-dig import { KmsSignatureConfigurationComponent } from '../../dialogs/configure-digital-signature-dialog/form/kms-signature-configuration/kms-signature-configuration.component'; import { DigitalSignatureOptions, IKmsDigitalSignatureRequest, IPkcsDigitalSignatureRequest, User } from '@red/domain'; import { Roles } from '@users/roles'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; @Component({ selector: 'redaction-digital-signature-screen', diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts index 08396011c..6719b81c9 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts @@ -2,8 +2,6 @@ import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { CircleButtonTypes, defaultDialogConfig, - getCurrentUser, - getParam, IconButtonTypes, ListingComponent, listingProvidersFactory, @@ -21,6 +19,8 @@ import { AddEditDossierAttributeDialogComponent, AddEditDossierAttributeDialogData, } from './add-edit-dossier-attribute-dialog/add-edit-dossier-attribute-dialog.component'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { getParam } from '@iqser/common-ui/lib/utils'; @Component({ templateUrl: './dossier-attributes-listing-screen.component.html', @@ -31,6 +31,7 @@ import { }), }) export class DossierAttributesListingScreenComponent extends ListingComponent implements OnInit { + readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = getCurrentUser(); @@ -42,7 +43,6 @@ export class DossierAttributesListingScreenComponent extends ListingComponent; readonly canEditDossierAttributes = this.permissionsService.canEditGlobalDossierAttributes(); - readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); constructor( readonly permissionsService: PermissionsService, diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen/dossier-states-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen/dossier-states-listing-screen.component.ts index b830e8473..e4f3b1cda 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen/dossier-states-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen/dossier-states-listing-screen.component.ts @@ -1,13 +1,5 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { - defaultDialogConfig, - getParam, - IconButtonTypes, - ListingComponent, - listingProvidersFactory, - SortingOrders, - TableColumnConfig, -} from '@iqser/common-ui'; +import { defaultDialogConfig, IconButtonTypes, ListingComponent, listingProvidersFactory, TableColumnConfig } from '@iqser/common-ui'; import { type DonutChartConfig, DOSSIER_TEMPLATE_ID, type DossierState } from '@red/domain'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { firstValueFrom, Observable } from 'rxjs'; @@ -20,6 +12,8 @@ import { AddEditDossierStateDialogComponent, AddEditDossierStateDialogData, } from '../add-edit-dossier-state-dialog/add-edit-dossier-state-dialog.component'; +import { SortingOrders } from '@iqser/common-ui/lib/sorting'; +import { getParam } from '@iqser/common-ui/lib/utils'; @Component({ templateUrl: './dossier-states-listing-screen.component.html', @@ -27,6 +21,7 @@ import { providers: listingProvidersFactory(DossierStatesListingScreenComponent), }) export class DossierStatesListingScreenComponent extends ListingComponent implements OnInit, OnDestroy { + readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); readonly iconButtonTypes = IconButtonTypes; readonly tableHeaderLabel = _('dossier-states-listing.table-header.title'); readonly tableColumnConfigs: TableColumnConfig[] = [ @@ -35,7 +30,6 @@ export class DossierStatesListingScreenComponent extends ListingComponent; - readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); constructor( private readonly _dialog: MatDialog, diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts index 9ac11e170..1b43f9e0d 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts @@ -4,7 +4,6 @@ import { AdminDialogService } from '../../../services/admin-dialog.service'; import { DossierTemplate, User } from '@red/domain'; import { CircleButtonTypes, - getCurrentUser, IconButtonTypes, IqserPermissionsService, ListingComponent, @@ -17,6 +16,7 @@ import { RouterHistoryService } from '@services/router-history.service'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { firstValueFrom } from 'rxjs'; import { Roles } from '@users/roles'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; @Component({ templateUrl: './dossier-templates-listing-screen.component.html', diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing.module.ts b/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing.module.ts index 5334b90e3..b0dc3dc8f 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing.module.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing.module.ts @@ -12,10 +12,10 @@ import { IqserHelpModeModule, IqserListingModule, IqserRoutes, - IqserUsersModule, } from '@iqser/common-ui'; import { TranslateModule } from '@ngx-translate/core'; import { DossierTemplateActionsComponent } from '../../shared/components/dossier-template-actions/dossier-template-actions.component'; +import { IqserUsersModule } from '@iqser/common-ui/lib/users'; const routes: IqserRoutes = [{ path: '', component: DossierTemplatesListingScreenComponent }]; diff --git a/apps/red-ui/src/app/modules/admin/screens/entities-listing/entities-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/entities-listing/entities-listing-screen.component.ts index ddebcd371..d5c8537a2 100644 --- a/apps/red-ui/src/app/modules/admin/screens/entities-listing/entities-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/entities-listing/entities-listing-screen.component.ts @@ -1,7 +1,6 @@ import { Component } from '@angular/core'; import { CircleButtonTypes, - getParam, IconButtonTypes, ListingComponent, listingProvidersFactory, @@ -17,6 +16,7 @@ import { DossierTemplateStatsService } from '@services/entity-services/dossier-t import { tap } from 'rxjs/operators'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import { PermissionsService } from '@services/permissions.service'; +import { getParam } from '@iqser/common-ui/lib/utils'; @Component({ templateUrl: './entities-listing-screen.component.html', @@ -24,6 +24,7 @@ import { PermissionsService } from '@services/permissions.service'; providers: listingProvidersFactory(EntitiesListingScreenComponent), }) export class EntitiesListingScreenComponent extends ListingComponent { + readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; readonly tableHeaderLabel = _('entities-listing.table-header.title'); @@ -34,7 +35,6 @@ export class EntitiesListingScreenComponent extends ListingComponent { label: _('entities-listing.table-col-names.dictionary-entries') }, ]; readonly templateStats$: Observable; - readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); constructor( private readonly _loadingService: LoadingService, diff --git a/apps/red-ui/src/app/modules/admin/screens/entities/screens/dictionary/dictionary-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/entities/screens/dictionary/dictionary-screen.component.ts index fc7eda515..c7cbd599b 100644 --- a/apps/red-ui/src/app/modules/admin/screens/entities/screens/dictionary/dictionary-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/entities/screens/dictionary/dictionary-screen.component.ts @@ -2,12 +2,14 @@ import { ChangeDetectionStrategy, Component, OnInit, ViewChild } from '@angular/ import { ActivatedRoute } from '@angular/router'; import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component'; import { DictionaryService } from '@services/entity-services/dictionary.service'; -import { getCurrentUser, getParam, IqserPermissionsService, List, LoadingService } from '@iqser/common-ui'; +import { IqserPermissionsService, LoadingService } from '@iqser/common-ui'; import { BehaviorSubject } from 'rxjs'; import { DICTIONARY_TO_ENTRY_TYPE_MAP, DICTIONARY_TYPE_KEY_MAP, DictionaryType, DOSSIER_TEMPLATE_ID, ENTITY_TYPE, User } from '@red/domain'; import { PermissionsService } from '@services/permissions.service'; import { Roles } from '@users/roles'; import { NGXLogger } from 'ngx-logger'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { getParam, List } from '@iqser/common-ui/lib/utils'; @Component({ templateUrl: './dictionary-screen.component.html', @@ -15,15 +17,15 @@ import { NGXLogger } from 'ngx-logger'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class DictionaryScreenComponent implements OnInit { + readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); + @ViewChild('dictionaryManager', { static: false }) + private readonly _dictionaryManager: DictionaryManagerComponent; readonly currentUser = getCurrentUser(); readonly roles = Roles; readonly initialEntries$ = new BehaviorSubject([]); isLeavingPage = false; readonly type: DictionaryType; readonly entityType = getParam(ENTITY_TYPE); - readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); - @ViewChild('dictionaryManager', { static: false }) - private readonly _dictionaryManager: DictionaryManagerComponent; constructor( route: ActivatedRoute, diff --git a/apps/red-ui/src/app/modules/admin/screens/entities/screens/entity-info/entity-info.component.ts b/apps/red-ui/src/app/modules/admin/screens/entities/screens/entity-info/entity-info.component.ts index 8c123a20d..e992f7d9c 100644 --- a/apps/red-ui/src/app/modules/admin/screens/entities/screens/entity-info/entity-info.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/entities/screens/entity-info/entity-info.component.ts @@ -5,9 +5,10 @@ import { ActivatedRoute } from '@angular/router'; import { getCurrentUser } from '@users/user.service'; import { PermissionsService } from '@services/permissions.service'; import { AddEditEntityComponent } from '@shared/components/add-edit-entity/add-edit-entity.component'; -import { IconButtonTypes, IqserEventTarget } from '@iqser/common-ui'; +import { IconButtonTypes } from '@iqser/common-ui'; import { Observable } from 'rxjs'; import { Roles } from '@users/roles'; +import { IqserEventTarget } from '@iqser/common-ui/lib/utils'; @Component({ selector: 'redaction-entity-info', @@ -16,14 +17,13 @@ import { Roles } from '@users/roles'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class EntityInfoComponent { + @ViewChild(AddEditEntityComponent) private readonly _addEditEntityComponent: AddEditEntityComponent; readonly currentUser = getCurrentUser(); readonly entity$: Observable; readonly dossierTemplateId: string; readonly roles = Roles; readonly iconButtonTypes = IconButtonTypes; - @ViewChild(AddEditEntityComponent) private readonly _addEditEntityComponent: AddEditEntityComponent; - constructor(route: ActivatedRoute, dictionariesMapService: DictionariesMapService, readonly permissionsService: PermissionsService) { this.dossierTemplateId = route.parent.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID); const entityType = route.parent.snapshot.paramMap.get(ENTITY_TYPE); diff --git a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.ts b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.ts index 010bdaa8a..19abe8403 100644 --- a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.ts @@ -4,11 +4,12 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import * as Papa from 'papaparse'; import { firstValueFrom, Observable } from 'rxjs'; import { map, startWith } from 'rxjs/operators'; -import { IconButtonTypes, ListingComponent, listingProvidersFactory, TableColumnConfig, Toaster, trackByFactory } from '@iqser/common-ui'; +import { IconButtonTypes, ListingComponent, listingProvidersFactory, TableColumnConfig, Toaster } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { FileAttributeConfig, FileAttributeConfigTypes, FileAttributeEncodingTypes, IField, IFileAttributesConfig } from '@red/domain'; import { FileAttributesService } from '@services/entity-services/file-attributes.service'; import { fileAttributeEncodingTypesTranslations } from '@translations/file-attribute-encoding-types-translations'; +import { trackByFactory } from '@iqser/common-ui/lib/utils'; export interface IFileAttributesCSVImportData { readonly csv: File; diff --git a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.ts index cf2f27b83..32d704f4e 100644 --- a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.ts @@ -3,8 +3,6 @@ import { AdminDialogService } from '../../services/admin-dialog.service'; import { CircleButtonTypes, defaultDialogConfig, - getCurrentUser, - getParam, IconButtonTypes, largeDialogConfig, ListingComponent, @@ -32,6 +30,8 @@ import { IFileAttributesCSVImportData, } from './file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component'; import { FileAttributesConfigurationsDialogComponent } from './file-attributes-configurations-dialog/file-attributes-configurations-dialog.component'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { getParam } from '@iqser/common-ui/lib/utils'; @Component({ templateUrl: './file-attributes-listing-screen.component.html', @@ -39,6 +39,10 @@ import { FileAttributesConfigurationsDialogComponent } from './file-attributes-c providers: listingProvidersFactory(FileAttributesListingScreenComponent), }) export class FileAttributesListingScreenComponent extends ListingComponent implements OnInit, OnDestroy { + @ViewChild('impactedTemplates') private readonly _impactedTemplatesRef: TemplateRef; + #existingConfiguration: IFileAttributesConfig; + @ViewChild('fileInput') private _fileInput: ElementRef; + readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = getCurrentUser(); @@ -59,18 +63,6 @@ export class FileAttributesListingScreenComponent extends ListingComponent; - #existingConfiguration: IFileAttributesConfig; - @ViewChild('fileInput') private _fileInput: ElementRef; - readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); - - private get _numberOfDisplayedAttrs(): number { - return this.entitiesService.all.filter(attr => attr.displayedInFileList).length; - } - - private get _numberOfFilterableAttrs(): number { - return this.entitiesService.all.filter(attr => attr.filterable).length; - } constructor( readonly permissionsService: PermissionsService, @@ -84,6 +76,14 @@ export class FileAttributesListingScreenComponent extends ListingComponent attr.displayedInFileList).length; + } + + private get _numberOfFilterableAttrs(): number { + return this.entitiesService.all.filter(attr => attr.filterable).length; + } + async ngOnInit() { await this.#loadData(); } diff --git a/apps/red-ui/src/app/modules/admin/screens/general-config/system-preferences-form/system-preferences-form.component.ts b/apps/red-ui/src/app/modules/admin/screens/general-config/system-preferences-form/system-preferences-form.component.ts index 000ac9054..44f01f82a 100644 --- a/apps/red-ui/src/app/modules/admin/screens/general-config/system-preferences-form/system-preferences-form.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/general-config/system-preferences-form/system-preferences-form.component.ts @@ -1,10 +1,11 @@ import { Component } from '@angular/core'; -import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, Validators } from '@angular/forms'; import { SystemPreferences } from '@red/domain'; -import { BaseFormComponent, IqserPermissionsService, KeysOf, LoadingService } from '@iqser/common-ui'; +import { BaseFormComponent, IqserPermissionsService, LoadingService } from '@iqser/common-ui'; import { SystemPreferencesService } from '@services/system-preferences.service'; import { systemPreferencesTranslations } from '@translations/system-preferences-translations'; import { Roles } from '@users/roles'; +import { KeysOf } from '@iqser/common-ui/lib/utils'; export type ValueType = 'number' | 'string' | 'boolean'; @@ -13,24 +14,24 @@ export type ValueType = 'number' | 'string' | 'boolean'; templateUrl: './system-preferences-form.component.html', }) export class SystemPreferencesFormComponent extends BaseFormComponent { + #initialConfiguration: SystemPreferences; readonly translations = systemPreferencesTranslations; readonly keys: { name: KeysOf; type: ValueType }[] = [ { name: 'softDeleteCleanupTime', type: 'number' }, { name: 'downloadCleanupNotDownloadFilesHours', type: 'number' }, { name: 'downloadCleanupDownloadFilesHours', type: 'number' }, ]; - private _initialConfiguration: SystemPreferences; constructor( private readonly _loadingService: LoadingService, private readonly _systemPreferencesService: SystemPreferencesService, private readonly _formBuilder: UntypedFormBuilder, - private readonly _permissionsService: IqserPermissionsService, + permissionsService: IqserPermissionsService, ) { super(); - this.form = this._getForm(); - this._loadData(); - if (!_permissionsService.has(Roles.appConfiguration.write)) { + this.form = this.#getForm(); + this.#loadData(); + if (!permissionsService.has(Roles.appConfiguration.write)) { this.form.disable(); } } @@ -38,19 +39,21 @@ export class SystemPreferencesFormComponent extends BaseFormComponent { async save(): Promise { this._loadingService.start(); await this._systemPreferencesService.update(this.form.getRawValue()); - this._loadData(); + this.#loadData(); this._loadingService.stop(); } - private _getForm(): UntypedFormGroup { + #getForm() { const controlsConfig = {}; - this.keys.forEach(key => (controlsConfig[key.name] = [this._systemPreferencesService.values[key.name], Validators.required])); + this.keys.forEach(key => { + controlsConfig[key.name] = [this._systemPreferencesService.values[key.name], Validators.required]; + }); return this._formBuilder.group(controlsConfig); } - private _loadData() { - this._initialConfiguration = this._systemPreferencesService.values; - this.form.patchValue(this._initialConfiguration, { emitEvent: false }); + #loadData() { + this.#initialConfiguration = this._systemPreferencesService.values; + this.form.patchValue(this.#initialConfiguration, { emitEvent: false }); this.initialFormValue = this.form.getRawValue(); } } diff --git a/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info.module.ts b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info.module.ts index f4ad7c25d..6c2f49351 100644 --- a/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info.module.ts +++ b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info.module.ts @@ -3,8 +3,9 @@ import { CommonModule } from '@angular/common'; import { DossierTemplateInfoScreenComponent } from './info-screen/dossier-template-info-screen.component'; import { RouterModule } from '@angular/router'; import { SharedModule } from '@shared/shared.module'; -import { HasScrollbarDirective, IqserHelpModeModule, IqserUsersModule } from '@iqser/common-ui'; +import { HasScrollbarDirective, IqserHelpModeModule } from '@iqser/common-ui'; import { TranslateModule } from '@ngx-translate/core'; +import { IqserUsersModule } from '@iqser/common-ui/lib/users'; const routes = [{ path: '', component: DossierTemplateInfoScreenComponent }]; diff --git a/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts index e6d940119..e50143cbe 100644 --- a/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts @@ -3,7 +3,7 @@ import { DossierTemplatesService } from '@services/dossier-templates/dossier-tem import { DOSSIER_TEMPLATE_ID, type DossierTemplate, type DossierTemplateStats } from '@red/domain'; import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service'; import { dossierTemplateStatusTranslations } from '@translations/dossier-template-status-translations'; -import { ContextComponent, getParam } from '@iqser/common-ui'; +import { ContextComponent, getParam } from '@iqser/common-ui/lib/utils'; interface Context { readonly dossierTemplate: DossierTemplate; diff --git a/apps/red-ui/src/app/modules/admin/screens/justifications/justifications-screen/justifications-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/justifications/justifications-screen/justifications-screen.component.ts index 59e11f857..3206b2837 100644 --- a/apps/red-ui/src/app/modules/admin/screens/justifications/justifications-screen/justifications-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/justifications/justifications-screen/justifications-screen.component.ts @@ -2,12 +2,10 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { CircleButtonTypes, - getParam, IconButtonTypes, ListingComponent, listingProvidersFactory, LoadingService, - SortingOrders, TableColumnConfig, } from '@iqser/common-ui'; import { DOSSIER_TEMPLATE_ID, Justification } from '@red/domain'; @@ -16,6 +14,8 @@ import { JustificationsDialogService } from '../justifications-dialog.service'; import { UserPreferenceService } from '@users/user-preference.service'; import { firstValueFrom } from 'rxjs'; import { PermissionsService } from '@services/permissions.service'; +import { SortingOrders } from '@iqser/common-ui/lib/sorting'; +import { getParam } from '@iqser/common-ui/lib/utils'; @Component({ selector: 'redaction-justifications-screen', @@ -28,6 +28,7 @@ import { PermissionsService } from '@services/permissions.service'; }), }) export class JustificationsScreenComponent extends ListingComponent implements OnInit { + readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; readonly tableHeaderLabel = _('justifications-listing.table-header'); @@ -37,7 +38,6 @@ export class JustificationsScreenComponent extends ListingComponent ({ datasets: this.#getDatasets(license), - labels: getLabelsFromMonthlyData(license.monthlyData), + labels: getLabelsFromLicense(license), })), ); readonly size = size; diff --git a/apps/red-ui/src/app/modules/admin/screens/license/components/license-usage/license-usage.component.ts b/apps/red-ui/src/app/modules/admin/screens/license/components/license-usage/license-usage.component.ts index 8f1524d3c..0e423a730 100644 --- a/apps/red-ui/src/app/modules/admin/screens/license/components/license-usage/license-usage.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/license/components/license-usage/license-usage.component.ts @@ -5,7 +5,7 @@ import { map } from 'rxjs/operators'; import type { ILicenseReport } from '@red/domain'; import { ChartDataset } from 'chart.js'; import { ChartBlue, ChartGreen, ChartRed } from '../../utils/constants'; -import { getLabelsFromMonthlyData, getLineConfig } from '../../utils/functions'; +import { getLabelsFromLicense, getLineConfig } from '../../utils/functions'; @Component({ selector: 'red-license-usage', @@ -18,7 +18,7 @@ export class LicenseUsageComponent { map(() => this.licenseService.currentLicenseReport), map(license => ({ datasets: this.#getDatasets(license), - labels: getLabelsFromMonthlyData(license.monthlyData), + labels: getLabelsFromLicense(license), })), ); @@ -32,12 +32,14 @@ export class LicenseUsageComponent { #getDatasets(license: ILicenseReport): ChartDataset[] { const monthlyData = license.monthlyData; + return [ { data: monthlyData.flatMap(d => d.numberOfAnalyzedPages), label: 'Pages per Month', type: 'bar', backgroundColor: ChartBlue, + borderColor: ChartBlue, order: 2, }, { diff --git a/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.ts index c09292794..e2665814e 100644 --- a/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.ts @@ -1,12 +1,13 @@ import { Component } from '@angular/core'; import { ConfigService } from '@services/config.service'; import { TranslateService } from '@ngx-translate/core'; -import { ButtonConfig, getCurrentUser, IconButtonTypes, IqserPermissionsService } from '@iqser/common-ui'; +import { ButtonConfig, IconButtonTypes, IqserPermissionsService } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { RouterHistoryService } from '@services/router-history.service'; import { LicenseService } from '@services/license.service'; import { Roles } from '@users/roles'; import type { User } from '@red/domain'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; @Component({ templateUrl: './license-screen.component.html', diff --git a/apps/red-ui/src/app/modules/admin/screens/license/utils/functions.ts b/apps/red-ui/src/app/modules/admin/screens/license/utils/functions.ts index efbbea5d3..efa5d0aad 100644 --- a/apps/red-ui/src/app/modules/admin/screens/license/utils/functions.ts +++ b/apps/red-ui/src/app/modules/admin/screens/license/utils/functions.ts @@ -1,7 +1,7 @@ import dayjs, { Dayjs } from 'dayjs'; import { FillTarget } from 'chart.js'; import { hexToRgba } from '@utils/functions'; -import { ILicenseData } from '@red/domain'; +import { ILicenseData, ILicenseReport } from '@red/domain'; import { ComplexFillTarget } from 'chart.js/dist/types'; const monthNames = dayjs.monthsShort(); @@ -30,3 +30,17 @@ export const getLineConfig: ( }); export const getLabelsFromMonthlyData = (monthlyData: ILicenseData[]) => monthlyData.map(data => verboseDate(dayjs(data.startDate))); + +export const getLabelsFromLicense = (license: ILicenseReport) => { + let startMonth = dayjs(license.startDate); + const endMonth = dayjs(license.endDate); + + const result = []; + + while (startMonth.isBefore(endMonth)) { + result.push(verboseDate(startMonth)); + startMonth = startMonth.add(1, 'month'); + } + + return result; +}; diff --git a/apps/red-ui/src/app/modules/admin/screens/permissions/permissions-screen/permissions-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/permissions/permissions-screen/permissions-screen.component.ts index c4cc7cb84..309c09449 100644 --- a/apps/red-ui/src/app/modules/admin/screens/permissions/permissions-screen/permissions-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/permissions/permissions-screen/permissions-screen.component.ts @@ -1,13 +1,5 @@ import { Component, OnDestroy } from '@angular/core'; -import { - getCurrentUser, - IqserPermissionsService, - ListingComponent, - listingProvidersFactory, - LoadingService, - SortingOrders, - TableColumnConfig, -} from '@iqser/common-ui'; +import { IqserPermissionsService, ListingComponent, listingProvidersFactory, LoadingService, TableColumnConfig } from '@iqser/common-ui'; import { PermissionsMapping, User } from '@red/domain'; import { ConfigService } from '../config.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @@ -20,6 +12,8 @@ import { switchMap, tap } from 'rxjs/operators'; import { permissionsTranslations } from '@translations/permissions-translations'; import { RouterHistoryService } from '@services/router-history.service'; import { Roles } from '@users/roles'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { SortingOrders } from '@iqser/common-ui/lib/sorting'; @Component({ templateUrl: './permissions-screen.component.html', @@ -27,6 +21,7 @@ import { Roles } from '@users/roles'; providers: listingProvidersFactory(PermissionsScreenComponent), }) export class PermissionsScreenComponent extends ListingComponent implements OnDestroy { + readonly #subscription: Subscription = new Subscription(); readonly roles = Roles; readonly currentUser = getCurrentUser(); readonly translations = permissionsTranslations; @@ -34,7 +29,6 @@ export class PermissionsScreenComponent extends ListingComponent([]); readonly availableTemplates$ = new BehaviorSubject([]); readonly currentUser = getCurrentUser(); readonly roles = Roles; - @ViewChild('fileInput') private readonly _fileInput: ElementRef; - readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); constructor( private readonly _reportTemplateService: ReportTemplateService, diff --git a/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.ts index c819bdd82..ef81e18c5 100644 --- a/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; -import { Debounce, getParam, IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui'; +import { IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui'; import { saveAs } from 'file-saver'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { RulesService } from '../../../services/rules.service'; @@ -8,6 +8,7 @@ import { firstValueFrom } from 'rxjs'; import { DOSSIER_TEMPLATE_ID } from '@red/domain'; import { EditorThemeService } from '@services/editor-theme.service'; import { ComponentCanDeactivate } from '@guards/can-deactivate.guard'; +import { Debounce, getParam } from '@iqser/common-ui/lib/utils'; import ICodeEditor = monaco.editor.ICodeEditor; import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration; import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorConstructionOptions; @@ -18,6 +19,11 @@ import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorCon changeDetection: ChangeDetectionStrategy.OnPush, }) export class RulesScreenComponent implements OnInit, ComponentCanDeactivate { + @ViewChild('fileInput') + private _fileInput: ElementRef; + private _codeEditor: ICodeEditor; + private _decorations: string[] = []; + readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); readonly iconButtonTypes = IconButtonTypes; readonly editorOptions: IStandaloneEditorConstructionOptions = { theme: 'vs', @@ -25,19 +31,10 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate { automaticLayout: true, readOnly: !this.permissionsService.canEditRules(), }; - initialLines: string[] = []; currentLines: string[] = []; - isLeaving = false; - @ViewChild('fileInput') - private _fileInput: ElementRef; - - private _codeEditor: ICodeEditor; - private _decorations: string[] = []; - readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); - constructor( readonly permissionsService: PermissionsService, private readonly _rulesService: RulesService, diff --git a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts index 7ab70f3bf..c002cf300 100644 --- a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts @@ -11,7 +11,6 @@ import { ListingComponent, listingProvidersFactory, LoadingService, - NestedFilter, SearchPositions, TableColumnConfig, } from '@iqser/common-ui'; @@ -22,6 +21,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { userTypeChecker, userTypeFilters } from '../../../../utils'; import { RouterHistoryService } from '@services/router-history.service'; import { Roles } from '@users/roles'; +import { NestedFilter } from '@iqser/common-ui/lib/filtering'; function configToFilter({ key, label }: DonutChartConfig) { return new NestedFilter({ diff --git a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.html index c0a2d0a50..defe51978 100644 --- a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.html @@ -1,5 +1,5 @@
-
+
@@ -54,30 +54,30 @@
-
+
-
+
diff --git a/apps/red-ui/src/app/modules/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 4a2f7c1e3..f8fabc61f 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 @@ -2,20 +2,7 @@ import { ChangeDetectorRef, Component, ElementRef, inject, OnInit, ViewChild } f import WebViewer, { WebViewerInstance } from '@pdftron/webviewer'; import { HttpClient } from '@angular/common/http'; import { FormBuilder, FormGroup } from '@angular/forms'; -import { - AsControl, - BASE_HREF_FN, - Debounce, - getConfig, - getCurrentUser, - getParam, - IconButtonTypes, - IqserPermissionsService, - LoadingService, - TenantsService, - Toaster, - trackByFactory, -} from '@iqser/common-ui'; +import { getConfig, IconButtonTypes, IqserPermissionsService, LoadingService, Toaster } from '@iqser/common-ui'; import { AppConfig, DOSSIER_TEMPLATE_ID, @@ -42,6 +29,9 @@ import { Roles } from '@users/roles'; import { environment } from '@environments/environment'; import { tap } from 'rxjs/operators'; import { watermarkTranslations } from '@translations/watermark-translations'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { AsControl, BASE_HREF_FN, Debounce, getParam, trackByFactory } from '@iqser/common-ui/lib/utils'; +import { TenantsService } from '@iqser/common-ui/lib/tenants'; export const DEFAULT_WATERMARK: Partial = { text: 'Watermark', @@ -72,6 +62,13 @@ interface WatermarkForm { styleUrls: ['./watermark-screen.component.scss'], }) export class WatermarkScreenComponent implements OnInit { + @ViewChild('viewer', { static: true }) private readonly _viewer: ElementRef; + private readonly _convertPath = inject(BASE_HREF_FN); + readonly #loaded$ = new BehaviorSubject(false); + readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); + readonly #watermarkId = Number(getParam(WATERMARK_ID)); + readonly #config = getConfig(); + #watermark: Partial = {}; readonly iconButtonTypes = IconButtonTypes; readonly translations = watermarkTranslations; readonly trackBy = trackByFactory(); @@ -89,13 +86,6 @@ export class WatermarkScreenComponent implements OnInit { readonly watermarkHorizontalAlignments = Object.values(WATERMARK_HORIZONTAL_ALIGNMENTS); readonly watermarkVerticalAlignments = Object.values(WATERMARK_VERTICAL_ALIGNMENTS); currentAlignment: WatermarkAlignment; - @ViewChild('viewer', { static: true }) private readonly _viewer: ElementRef; - private readonly _convertPath = inject(BASE_HREF_FN); - readonly #loaded$ = new BehaviorSubject(false); - readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); - readonly #watermarkId = Number(getParam(WATERMARK_ID)); - readonly #config = getConfig(); - #watermark: Partial = {}; constructor( private readonly _http: HttpClient, 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 dc3eabe70..8fbfbb910 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 @@ -9,12 +9,9 @@ import { HasScrollbarDirective, IconButtonComponent, IqserAllowDirective, - IqserAuthGuard, IqserHelpModeModule, IqserListingModule, IqserRoutes, - IqserUsersModule, - TenantPipe, } from '@iqser/common-ui'; import { RedRoleGuard } from '@users/red-role.guard'; import { WATERMARK_ID } from '@red/domain'; @@ -27,6 +24,8 @@ import { MatSliderModule } from '@angular/material/slider'; import { ColorPickerModule } from 'ngx-color-picker'; import { MatTooltipModule } from '@angular/material/tooltip'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { IqserAuthGuard, IqserUsersModule } from '@iqser/common-ui/lib/users'; +import { TenantPipe } from '@iqser/common-ui/lib/tenants'; const routes: IqserRoutes = [ { diff --git a/apps/red-ui/src/app/modules/admin/screens/watermark/watermarks-listing/watermarks-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/watermark/watermarks-listing/watermarks-listing-screen.component.ts index b4590f6ea..8a5602b84 100644 --- a/apps/red-ui/src/app/modules/admin/screens/watermark/watermarks-listing/watermarks-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/watermark/watermarks-listing/watermarks-listing-screen.component.ts @@ -1,8 +1,6 @@ import { Component } from '@angular/core'; import { CircleButtonTypes, - getCurrentUser, - getParam, IconButtonTypes, IConfirmationDialogData, IqserPermissionsService, @@ -18,6 +16,8 @@ import { WatermarkService } from '@services/entity-services/watermark.service'; import { AdminDialogService } from '../../../services/admin-dialog.service'; import { WatermarksMapService } from '@services/entity-services/watermarks-map.service'; import { Roles } from '@users/roles'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { getParam } from '@iqser/common-ui/lib/utils'; @Component({ templateUrl: './watermarks-listing-screen.component.html', @@ -25,6 +25,7 @@ import { Roles } from '@users/roles'; providers: listingProvidersFactory(WatermarksListingScreenComponent), }) export class WatermarksListingScreenComponent extends ListingComponent { + readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = getCurrentUser(); @@ -37,7 +38,6 @@ export class WatermarksListingScreenComponent extends ListingComponent { 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 8a2fcccea..b78a3cf3d 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,9 +5,12 @@ 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, TenantPipe } from '@iqser/common-ui'; +import { IqserHelpModeModule, IqserPermissionsService } from '@iqser/common-ui'; import { TranslateModule } from '@ngx-translate/core'; import { NgForOf, NgIf } from '@angular/common'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { SideNavComponent } from '@iqser/common-ui/lib/shared'; +import { TenantPipe } from '@iqser/common-ui/lib/tenants'; interface NavItem { readonly label: string; 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 021c15f89..dec85ea38 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 @@ -1,19 +1,14 @@ import { Component, Input, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { AdminDialogService } from '../../../services/admin-dialog.service'; -import { - CircleButtonComponent, - CircleButtonTypes, - getCurrentUser, - IqserHelpModeModule, - LoadingService, - TenantsService, -} from '@iqser/common-ui'; +import { CircleButtonComponent, CircleButtonTypes, IqserHelpModeModule, LoadingService } from '@iqser/common-ui'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { firstValueFrom } from 'rxjs'; import { DOSSIER_TEMPLATE_ID, type User } from '@red/domain'; import { NgIf } from '@angular/common'; import { TranslateModule } from '@ngx-translate/core'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { TenantsService } from '@iqser/common-ui/lib/tenants'; @Component({ selector: 'redaction-dossier-template-actions', diff --git a/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component.ts b/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component.ts index 62e110ec2..a2eabf69d 100644 --- a/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component.ts +++ b/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component.ts @@ -8,7 +8,7 @@ import { DictionariesMapService } from '@services/entity-services/dictionaries-m import { AsyncPipe, NgIf } from '@angular/common'; import { MatIconModule } from '@angular/material/icon'; import { TranslateModule } from '@ngx-translate/core'; -import { TenantPipe } from '@iqser/common-ui'; +import { TenantPipe } from '@iqser/common-ui/lib/tenants'; @Component({ selector: 'redaction-dossier-template-breadcrumbs', diff --git a/apps/red-ui/src/app/modules/archive/archive.module.ts b/apps/red-ui/src/app/modules/archive/archive.module.ts index 32f4c7725..ec6dd7e41 100644 --- a/apps/red-ui/src/app/modules/archive/archive.module.ts +++ b/apps/red-ui/src/app/modules/archive/archive.module.ts @@ -4,10 +4,11 @@ import { ArchivedDossiersScreenComponent } from './screens/archived-dossiers-scr import { ArchiveRoutingModule } from './archive-routing.module'; import { TableItemComponent } from './components/table-item/table-item.component'; import { ConfigService } from './services/config.service'; -import { IqserHelpModeModule, IqserListingModule, IqserUsersModule } from '@iqser/common-ui'; +import { IqserHelpModeModule, IqserListingModule } from '@iqser/common-ui'; import { TranslateModule } from '@ngx-translate/core'; import { SharedModule } from '@shared/shared.module'; import { SharedDossiersModule } from '../shared-dossiers/shared-dossiers.module'; +import { IqserUsersModule } from '@iqser/common-ui/lib/users'; @NgModule({ declarations: [TableItemComponent, ArchivedDossiersScreenComponent], diff --git a/apps/red-ui/src/app/modules/archive/services/config.service.ts b/apps/red-ui/src/app/modules/archive/services/config.service.ts index d7b74694a..5655dbf0c 100644 --- a/apps/red-ui/src/app/modules/archive/services/config.service.ts +++ b/apps/red-ui/src/app/modules/archive/services/config.service.ts @@ -1,11 +1,12 @@ import { Injectable } from '@angular/core'; -import { IFilterGroup, keyChecker, NestedFilter, TableColumnConfig } from '@iqser/common-ui'; +import { TableColumnConfig } from '@iqser/common-ui'; import { Dossier, User } from '@red/domain'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { dossierMemberChecker, dossierMemberQuickChecker, dossierOwnerQuickChecker, dossierTemplateChecker } from '@utils/index'; import { UserService } from '@users/user.service'; import { TranslateService } from '@ngx-translate/core'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; +import { IFilterGroup, keyChecker, NestedFilter } from '@iqser/common-ui/lib/filtering'; @Injectable() export class ConfigService { diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts index 7ebd51e3c..69a16dcee 100644 --- a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts +++ b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts @@ -1,8 +1,9 @@ import { Component, inject, OnInit } from '@angular/core'; import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service'; import { UserPreferenceService } from '@users/user-preference.service'; -import { getCurrentUser, trackByFactory } from '@iqser/common-ui'; +import { trackByFactory } from '@iqser/common-ui/lib/utils'; import { User } from '@red/domain'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; @Component({ templateUrl: './dashboard-screen.component.html', diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts index 4b04618b6..eb401f1d0 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts @@ -13,16 +13,7 @@ import { } from '@red/domain'; import { TranslateChartService } from '@services/translate-chart.service'; import { UserService } from '@users/user.service'; -import { - ContextComponent, - FilterService, - getCurrentUser, - getParam, - INestedFilter, - ProgressBarConfigModel, - shareLast, - Toaster, -} from '@iqser/common-ui'; +import { ProgressBarConfigModel, Toaster } from '@iqser/common-ui'; import { workflowFileStatusTranslations } from '@translations/file-status-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { combineLatestWith, firstValueFrom } from 'rxjs'; @@ -31,6 +22,9 @@ import { map, tap } from 'rxjs/operators'; import { DossiersService } from '@services/dossiers/dossiers.service'; import { FilesMapService } from '@services/files/files-map.service'; import { Roles } from '@users/roles'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { FilterService, INestedFilter } from '@iqser/common-ui/lib/filtering'; +import { ContextComponent, getParam, shareLast } from '@iqser/common-ui/lib/utils'; interface DossierDetailsContext { needsWorkFilters: INestedFilter[] | undefined; @@ -45,17 +39,16 @@ interface DossierDetailsContext { styleUrls: ['./dossier-details.component.scss'], }) export class DossierDetailsComponent extends ContextComponent { + #currentChartSubtitleIndex = 0; + readonly #dossierId = getParam(DOSSIER_ID); @Input() dossierAttributes: DossierAttributeWithValue[]; @Output() readonly toggleCollapse = new EventEmitter(); - editingOwner = false; readonly roles = Roles; readonly currentUser = getCurrentUser(); readonly collapseTooltip = _('dossier-details.collapse'); readonly expandTooltip = _('dossier-details.expand'); chartConfig: DonutChartConfig[] = []; - #currentChartSubtitleIndex = 0; - readonly #dossierId = getParam(DOSSIER_ID); constructor( private readonly _toaster: Toaster, diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/file-attribute/file-attribute.component.html b/apps/red-ui/src/app/modules/dossier-overview/components/file-attribute/file-attribute.component.html index de7e1d214..b4c80aaa1 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/file-attribute/file-attribute.component.html +++ b/apps/red-ui/src/app/modules/dossier-overview/components/file-attribute/file-attribute.component.html @@ -1,8 +1,12 @@ -
-
+
+
{{ fileAttribute.label }}: - + {{ fileAttributeValue || '-' }} @@ -14,20 +18,20 @@
-
+
@@ -35,15 +39,15 @@
-
-
+
+ - +
diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/file-attribute/file-attribute.component.ts b/apps/red-ui/src/app/modules/dossier-overview/components/file-attribute/file-attribute.component.ts index be6de78e3..f9b20b80b 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/file-attribute/file-attribute.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/components/file-attribute/file-attribute.component.ts @@ -1,8 +1,8 @@ -import { Component, HostListener, Input, OnDestroy } from '@angular/core'; +import { Component, computed, effect, HostListener, Input, OnDestroy } from '@angular/core'; import { Dossier, File, FileAttributeConfigTypes, IFileAttributeConfig } from '@red/domain'; import { BaseFormComponent, HelpModeService, ListingService, Toaster } from '@iqser/common-ui'; import { PermissionsService } from '@services/permissions.service'; -import { FormBuilder, UntypedFormGroup } from '@angular/forms'; +import { FormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { FileAttributesService } from '@services/entity-services/file-attributes.service'; import { firstValueFrom, Subscription } from 'rxjs'; import { FilesService } from '@services/files/files.service'; @@ -25,6 +25,12 @@ export class FileAttributeComponent extends BaseFormComponent implements OnDestr isInEditMode = false; closedDatepicker = true; readonly #subscriptions = new Subscription(); + readonly #shouldClose = computed( + () => + this.fileAttributesService.isEditingFileAttribute() && + (this.fileAttribute.id !== this.fileAttributesService.openAttributeEdit() || + this.file.fileId !== this.fileAttributesService.fileEdit()), + ); constructor( router: Router, @@ -46,6 +52,15 @@ export class FileAttributeComponent extends BaseFormComponent implements OnDestr tap(() => this.close()), ); this.#subscriptions.add(sub2.subscribe()); + + effect( + () => { + if (this.#shouldClose()) { + this.close(); + } + }, + { allowSignalWrites: true }, + ); } get isDate(): boolean { @@ -56,6 +71,13 @@ export class FileAttributeComponent extends BaseFormComponent implements OnDestr return this.file.fileAttributes.attributeIdToValue[this.fileAttribute.id]; } + @HostListener('document:click') + clickOutside() { + if (this.isInEditMode && this.closedDatepicker) { + this.close(); + } + } + ngOnDestroy() { this.#subscriptions.unsubscribe(); } @@ -64,6 +86,8 @@ export class FileAttributeComponent extends BaseFormComponent implements OnDestr if (!this.file.isInitialProcessing && this.permissionsService.canEditFileAttributes(this.file, this.dossier)) { $event.stopPropagation(); this.#toggleEdit(); + this.fileAttributesService.setFileEdit(this.file.fileId); + this.fileAttributesService.setOpenAttributeEdit(this.fileAttribute.id); } } @@ -95,13 +119,6 @@ export class FileAttributeComponent extends BaseFormComponent implements OnDestr } } - @HostListener('document:click') - clickOutside() { - if (this.isInEditMode && this.closedDatepicker) { - this.close(); - } - } - #initFileAttributes() { const configs = this.fileAttributesService.getFileAttributeConfig(this.file.dossierTemplateId).fileAttributeConfigs; configs.forEach(config => { @@ -116,13 +133,16 @@ export class FileAttributeComponent extends BaseFormComponent implements OnDestr const fileAttributes = this.file.fileAttributes.attributeIdToValue; Object.keys(fileAttributes).forEach(key => { const attrValue = fileAttributes[key]; - config[key] = [dayjs(attrValue, 'YYYY-MM-DD', true).isValid() ? dayjs(attrValue).toDate() : attrValue]; + config[key] = [ + dayjs(attrValue, 'YYYY-MM-DD', true).isValid() ? dayjs(attrValue).toDate() : attrValue, + Validators.pattern(/^(\s+\S+\s*)*(?!\s).*$/), + ]; }); return this._formBuilder.group(config); } #formatAttributeValue(attrValue) { - return this.isDate ? attrValue && dayjs(attrValue).format('YYYY-MM-DD') : attrValue; + return this.isDate ? attrValue && dayjs(attrValue).format('YYYY-MM-DD') : attrValue.replaceAll(/\s\s+/g, ' '); } #toggleEdit(): void { @@ -133,7 +153,7 @@ export class FileAttributeComponent extends BaseFormComponent implements OnDestr } this.isInEditMode = !this.isInEditMode; - this.fileAttributesService.isEditingFileAttribute$.next(this.isInEditMode); + this.fileAttributesService.isEditingFileAttribute.set(this.isInEditMode); if (this.isInEditMode) { this.#focusOnEditInput(); 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 138bf667c..326f802fd 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 @@ -1,16 +1,5 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { - ActionConfig, - CircleButtonTypes, - EntitiesService, - List, - ListingService, - LoadingService, - some, - SortingService, - TenantsService, - Toaster, -} from '@iqser/common-ui'; +import { ActionConfig, CircleButtonTypes, EntitiesService, ListingService, LoadingService, Toaster } from '@iqser/common-ui'; import { Dossier, File, IFile } from '@red/domain'; import { PermissionsService } from '@services/permissions.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @@ -22,6 +11,9 @@ import { ConfigService } from '../../config.service'; import { PrimaryFileAttributeService } from '@services/primary-file-attribute.service'; import { Router } from '@angular/router'; import { Roles } from '@users/roles'; +import { SortingService } from '@iqser/common-ui/lib/sorting'; +import { List, some } from '@iqser/common-ui/lib/utils'; +import { TenantsService } from '@iqser/common-ui/lib/tenants'; @Component({ selector: 'redaction-dossier-overview-screen-header [dossier] [upload]', diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/workflow-item/workflow-item.component.html b/apps/red-ui/src/app/modules/dossier-overview/components/workflow-item/workflow-item.component.html index 40cd96b34..2c0632a24 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/workflow-item/workflow-item.component.html +++ b/apps/red-ui/src/app/modules/dossier-overview/components/workflow-item/workflow-item.component.html @@ -1,10 +1,10 @@ -
+
@@ -20,7 +20,7 @@
- +
@@ -31,10 +31,11 @@
diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/workflow-item/workflow-item.component.ts b/apps/red-ui/src/app/modules/dossier-overview/components/workflow-item/workflow-item.component.ts index 525ada944..6fe2cb184 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/workflow-item/workflow-item.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/components/workflow-item/workflow-item.component.ts @@ -1,6 +1,7 @@ import { ChangeDetectorRef, Component, ElementRef, Input, OnInit, Optional, ViewChild } from '@angular/core'; import { Dossier, File, IFileAttributeConfig } from '@red/domain'; -import { Debounce, HelpModeService } from '@iqser/common-ui'; +import { HelpModeService } from '@iqser/common-ui'; +import { Debounce } from '@iqser/common-ui/lib/utils'; @Component({ selector: 'redaction-workflow-item [file] [dossier] [displayedAttributes]', @@ -8,13 +9,12 @@ import { Debounce, HelpModeService } from '@iqser/common-ui'; styleUrls: ['./workflow-item.component.scss'], }) export class WorkflowItemComponent implements OnInit { + @ViewChild('actionsWrapper', { static: true }) private _actionsWrapper: ElementRef; @Input() file: File; @Input() dossier: Dossier; @Input() displayedAttributes: IFileAttributeConfig[]; width: number; - @ViewChild('actionsWrapper', { static: true }) private _actionsWrapper: ElementRef; - constructor(private readonly _changeRef: ChangeDetectorRef, @Optional() readonly helpModeService: HelpModeService) {} ngOnInit(): void { diff --git a/apps/red-ui/src/app/modules/dossier-overview/config.service.ts b/apps/red-ui/src/app/modules/dossier-overview/config.service.ts index 560b633f6..938b32f30 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/config.service.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/config.service.ts @@ -2,16 +2,9 @@ import { Injectable, TemplateRef } from '@angular/core'; import { ActionConfig, getConfig, - getCurrentUser, - getParam, - IFilterGroup, - INestedFilter, IqserPermissionsService, - keyChecker, - List, ListingMode, ListingModes, - NestedFilter, TableColumnConfig, WorkflowColumn, WorkflowConfig, @@ -46,6 +39,9 @@ import { DictionariesMapService } from '@services/entity-services/dictionaries-m import { UserPreferenceService } from '@users/user-preference.service'; import { DossiersService } from '@services/dossiers/dossiers.service'; import { Roles } from '@users/roles'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { IFilterGroup, INestedFilter, keyChecker, NestedFilter } from '@iqser/common-ui/lib/filtering'; +import { getParam, List } from '@iqser/common-ui/lib/utils'; @Injectable() export class ConfigService { diff --git a/apps/red-ui/src/app/modules/dossier-overview/dossier-overview.module.ts b/apps/red-ui/src/app/modules/dossier-overview/dossier-overview.module.ts index 230792a1c..972364348 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/dossier-overview.module.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/dossier-overview.module.ts @@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { CircleButtonComponent, + DisableStopPropagationDirective, DynamicInputComponent, HasScrollbarDirective, IqserAllowDirective, @@ -10,10 +11,7 @@ import { IqserListingModule, IqserLoadingModule, IqserRoutes, - IqserUsersModule, - StatusBarComponent, StopPropagationDirective, - TenantPipe, } from '@iqser/common-ui'; import { TranslateModule } from '@ngx-translate/core'; import { DossierOverviewScreenComponent } from './screen/dossier-overview-screen.component'; @@ -28,6 +26,9 @@ import { DossierOverviewScreenHeaderComponent } from './components/screen-header import { ViewModeSelectionComponent } from './components/view-mode-selection/view-mode-selection.component'; import { FileAttributeComponent } from './components/file-attribute/file-attribute.component'; import { SharedModule } from '@shared/shared.module'; +import { IqserUsersModule } from '@iqser/common-ui/lib/users'; +import { StatusBarComponent } from '@iqser/common-ui/lib/shared'; +import { TenantPipe } from '@iqser/common-ui/lib/tenants'; const routes: IqserRoutes = [ { @@ -70,6 +71,7 @@ const routes: IqserRoutes = [ DynamicInputComponent, IqserAllowDirective, TenantPipe, + DisableStopPropagationDirective, ], }) export class DossierOverviewModule {} diff --git a/apps/red-ui/src/app/modules/dossier-overview/screen/dossier-overview-screen.component.ts b/apps/red-ui/src/app/modules/dossier-overview/screen/dossier-overview-screen.component.ts index 4b75aebf2..9563a1cca 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/screen/dossier-overview-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/screen/dossier-overview-screen.component.ts @@ -19,16 +19,11 @@ import { CircleButtonTypes, CustomError, ErrorService, - getParam, IqserPermissionsService, ListingComponent, ListingModes, listingProvidersFactory, LoadingService, - NestedFilter, - OnAttach, - OnDetach, - shareLast, TableColumnConfig, TableComponent, WorkflowConfig, @@ -46,6 +41,8 @@ import { BulkActionsService } from '../services/bulk-actions.service'; import { DossiersService } from '@services/dossiers/dossiers.service'; import { dossiersServiceProvider } from '@services/entity-services/dossiers.service.provider'; import { Roles } from '@users/roles'; +import { NestedFilter } from '@iqser/common-ui/lib/filtering'; +import { getParam, OnAttach, OnDetach, shareLast } from '@iqser/common-ui/lib/utils'; @Component({ templateUrl: './dossier-overview-screen.component.html', diff --git a/apps/red-ui/src/app/modules/dossiers-listing/components/dossier-documents-status/dossier-documents-status.component.ts b/apps/red-ui/src/app/modules/dossiers-listing/components/dossier-documents-status/dossier-documents-status.component.ts index 6a4e855f7..37850cb8a 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/components/dossier-documents-status/dossier-documents-status.component.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/components/dossier-documents-status/dossier-documents-status.component.ts @@ -1,6 +1,7 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; import { DossierStats, StatusSorter } from '@red/domain'; -import { List, StatusBarConfig } from '@iqser/common-ui'; +import { List } from '@iqser/common-ui/lib/utils'; +import { StatusBarConfig } from '@iqser/common-ui/lib/shared'; @Component({ selector: 'redaction-dossier-documents-status', diff --git a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts index 283137f18..f5acb2e40 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts @@ -4,7 +4,7 @@ import { Observable } from 'rxjs'; import { TranslateChartService } from '@services/translate-chart.service'; import { map } from 'rxjs/operators'; import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service'; -import { getParam } from '@iqser/common-ui'; +import { getParam } from '@iqser/common-ui/lib/utils'; @Component({ selector: 'redaction-dossiers-listing-details', diff --git a/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts b/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts index a71840a67..277a5613f 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts @@ -1,13 +1,5 @@ import { Injectable, TemplateRef } from '@angular/core'; -import { - ButtonConfig, - IFilterGroup, - INestedFilter, - keyChecker, - NestedFilter, - OverlappingElements, - TableColumnConfig, -} from '@iqser/common-ui'; +import { ButtonConfig, TableColumnConfig } from '@iqser/common-ui'; import { annotationDefaultColorConfig, AnnotationShapeMap, @@ -35,6 +27,7 @@ import { DossierStatesMapService } from '@services/entity-services/dossier-state import { PermissionsService } from '@services/permissions.service'; import { SharedDialogService } from '@shared/services/dialog.service'; import { DefaultColorsService } from '@services/entity-services/default-colors.service'; +import { IFilterGroup, INestedFilter, keyChecker, NestedFilter } from '@iqser/common-ui/lib/filtering'; @Injectable() export class ConfigService { diff --git a/apps/red-ui/src/app/modules/dossiers-listing/dossiers-listing.module.ts b/apps/red-ui/src/app/modules/dossiers-listing/dossiers-listing.module.ts index 5033d8fe1..28b2f1109 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/dossiers-listing.module.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/dossiers-listing.module.ts @@ -1,14 +1,6 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { - CompositeRouteGuard, - HasScrollbarDirective, - IqserHelpModeModule, - IqserListingModule, - IqserRoutes, - IqserUsersModule, - StatusBarComponent, -} from '@iqser/common-ui'; +import { CompositeRouteGuard, HasScrollbarDirective, IqserHelpModeModule, IqserListingModule, IqserRoutes } from '@iqser/common-ui'; import { TranslateModule } from '@ngx-translate/core'; import { DossiersListingScreenComponent } from './screen/dossiers-listing-screen.component'; import { RouterModule } from '@angular/router'; @@ -21,6 +13,8 @@ import { DossierWorkloadColumnComponent } from './components/dossier-workload-co import { DossierDocumentsStatusComponent } from './components/dossier-documents-status/dossier-documents-status.component'; import { DossierFilesGuard } from '@guards/dossier-files-guard'; import { ACTIVE_DOSSIERS_SERVICE } from '../../tokens'; +import { IqserUsersModule } from '@iqser/common-ui/lib/users'; +import { StatusBarComponent } from '@iqser/common-ui/lib/shared'; const routes: IqserRoutes = [ { diff --git a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts index 1ca7f7ddf..32ad8ec0e 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { Dossier, DOSSIER_TEMPLATE_ID, DossierTemplate } from '@red/domain'; import { PermissionsService } from '@services/permissions.service'; -import { ButtonConfig, ListingComponent, listingProvidersFactory, OnAttach, TableComponent } from '@iqser/common-ui'; +import { ButtonConfig, ListingComponent, listingProvidersFactory, TableComponent } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { ConfigService } from '../config.service'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; @@ -10,6 +10,7 @@ import { Router } from '@angular/router'; import { UserPreferenceService } from '@users/user-preference.service'; import { SharedDialogService } from '@shared/services/dialog.service'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; +import { OnAttach } from '@iqser/common-ui/lib/utils'; @Component({ templateUrl: './dossiers-listing-screen.component.html', @@ -18,17 +19,17 @@ import { DossierTemplatesService } from '@services/dossier-templates/dossier-tem changeDetection: ChangeDetectionStrategy.OnPush, }) export class DossiersListingScreenComponent extends ListingComponent implements OnInit, OnAttach { - readonly tableColumnConfigs = this._configService.tableConfig; - readonly tableHeaderLabel = _('dossier-listing.table-header.title'); - readonly buttonConfigs: ButtonConfig[]; - readonly dossierTemplate: DossierTemplate; - readonly computeFilters$ = this._activeDossiersService.all$.pipe(tap(() => this._computeAllFilters())); @ViewChild('needsWorkFilterTemplate', { read: TemplateRef, static: true, }) private readonly _needsWorkFilterTemplate: TemplateRef; @ViewChild(TableComponent) private readonly _tableComponent: TableComponent; + readonly tableColumnConfigs = this._configService.tableConfig; + readonly tableHeaderLabel = _('dossier-listing.table-header.title'); + readonly buttonConfigs: ButtonConfig[]; + readonly dossierTemplate: DossierTemplate; + readonly computeFilters$ = this._activeDossiersService.all$.pipe(tap(() => this._computeAllFilters())); constructor( router: Router, diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-details/annotation-details.component.ts b/apps/red-ui/src/app/modules/file-preview/components/annotation-details/annotation-details.component.ts index d5266d823..4da630864 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-details/annotation-details.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-details/annotation-details.component.ts @@ -3,9 +3,9 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { TranslateService } from '@ngx-translate/core'; import { annotationChangesTranslations } from '@translations/annotation-changes-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { KeysOf } from '@iqser/common-ui'; import { ListItem } from '@models/file/list-item'; import { MultiSelectService } from '../../services/multi-select.service'; +import { KeysOf } from '@iqser/common-ui/lib/utils'; interface Engine { readonly icon: string; @@ -41,16 +41,14 @@ const changesProperties: KeysOf[] = [ styleUrls: ['./annotation-details.component.scss'], }) export class AnnotationDetailsComponent implements OnChanges { + private readonly _translateService = inject(TranslateService); + private readonly _multiSelectService = inject(MultiSelectService); @Input() annotation: ListItem; isPopoverOpen = false; - engines: Engine[]; changesTooltip: string; noSelection: boolean; - private readonly _translateService = inject(TranslateService); - private readonly _multiSelectService = inject(MultiSelectService); - getChangesTooltip(): string | undefined { const changes = changesProperties.filter(key => this.annotation.item[key]); diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-wrapper/annotation-wrapper.component.html b/apps/red-ui/src/app/modules/file-preview/components/annotation-wrapper/annotation-wrapper.component.html index dfd222f5e..7482014ca 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-wrapper/annotation-wrapper.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-wrapper/annotation-wrapper.component.html @@ -13,8 +13,8 @@ (click)="comments.toggleExpandComments()" [matTooltip]="'comments.comments' | translate : { count: annotation.item.comments?.length }" class="comments-counter" + iqserStopPropagation matTooltipPosition="above" - stopPropagation > {{ annotation.item.comments.length }} diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotations-list/annotations-list.component.ts b/apps/red-ui/src/app/modules/file-preview/components/annotations-list/annotations-list.component.ts index bd4a8a323..bf06d514a 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotations-list/annotations-list.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/annotations-list/annotations-list.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectorRef, Component, computed, ElementRef, EventEmitter, Input, OnChanges, Output } from '@angular/core'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; -import { FilterService, HasScrollbarDirective, IqserEventTarget } from '@iqser/common-ui'; +import { HasScrollbarDirective } from '@iqser/common-ui'; import { MultiSelectService } from '../../services/multi-select.service'; import { AnnotationReferencesService } from '../../services/annotation-references.service'; import { UserPreferenceService } from '@users/user-preference.service'; @@ -9,6 +9,8 @@ import { EarmarkGroup } from '@red/domain'; import { REDAnnotationManager } from '../../../pdf-viewer/services/annotation-manager.service'; import { AnnotationsListingService } from '../../services/annotations-listing.service'; import { ListItem } from '@models/file/list-item'; +import { FilterService } from '@iqser/common-ui/lib/filtering'; +import { IqserEventTarget } from '@iqser/common-ui/lib/utils'; @Component({ selector: 'redaction-annotations-list', @@ -16,15 +18,14 @@ import { ListItem } from '@models/file/list-item'; styleUrls: ['./annotations-list.component.scss'], }) export class AnnotationsListComponent extends HasScrollbarDirective implements OnChanges { - @Input() annotations: ListItem[]; - @Output() readonly pagesPanelActive = new EventEmitter(); - readonly #earmarkGroups = computed(() => { if (this._viewModeService.isEarmarks()) { return this.#getEarmarksGroups(); } return [] as EarmarkGroup[]; }); + @Input() annotations: ListItem[]; + @Output() readonly pagesPanelActive = new EventEmitter(); constructor( protected readonly _elementRef: ElementRef, diff --git a/apps/red-ui/src/app/modules/file-preview/components/comments/comments.component.html b/apps/red-ui/src/app/modules/file-preview/components/comments/comments.component.html index 8ddd05bf0..3b7c4a0a2 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/comments/comments.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/comments/comments.component.html @@ -33,7 +33,7 @@
diff --git a/apps/red-ui/src/app/modules/file-preview/components/comments/comments.component.ts b/apps/red-ui/src/app/modules/file-preview/components/comments/comments.component.ts index 617cdea00..578020003 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/comments/comments.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/comments/comments.component.ts @@ -2,12 +2,14 @@ import { ChangeDetectorRef, Component, HostBinding, Input, OnInit, ViewChild } f import type { IComment, User } from '@red/domain'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { PermissionsService } from '@services/permissions.service'; -import { ContextComponent, getCurrentUser, InputWithActionComponent, LoadingService, trackByFactory } from '@iqser/common-ui'; +import { InputWithActionComponent, LoadingService } from '@iqser/common-ui'; import { Observable } from 'rxjs'; import { CommentingService } from '../../services/commenting.service'; import { tap } from 'rxjs/operators'; import { FilePreviewStateService } from '../../services/file-preview-state.service'; import { ManualRedactionService } from '../../services/manual-redaction.service'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; +import { ContextComponent, trackByFactory } from '@iqser/common-ui/lib/utils'; interface CommentsContext { hiddenComments: boolean; @@ -19,12 +21,12 @@ interface CommentsContext { styleUrls: ['./comments.component.scss'], }) export class CommentsComponent extends ContextComponent implements OnInit { + @HostBinding('class.hidden') private _hidden = true; + @ViewChild(InputWithActionComponent) private readonly _input: InputWithActionComponent; @Input() annotation: AnnotationWrapper; readonly trackBy = trackByFactory(); readonly currentUser = getCurrentUser(); hiddenComments$: Observable; - @HostBinding('class.hidden') private _hidden = true; - @ViewChild(InputWithActionComponent) private readonly _input: InputWithActionComponent; constructor( readonly permissionsService: PermissionsService, diff --git a/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.ts b/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.ts index 1d9e5ee07..dbe150783 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.ts @@ -6,7 +6,7 @@ import { FilePreviewStateService } from '../../services/file-preview-state.servi import { type FileAttributeConfigType, FileAttributeConfigTypes } from '@red/domain'; import { FilePreviewDialogService } from '../../services/file-preview-dialog.service'; import { FileAttributesService } from '@services/entity-services/file-attributes.service'; -import { ContextComponent } from '@iqser/common-ui'; +import { ContextComponent } from '@iqser/common-ui/lib/utils'; import { toSignal } from '@angular/core/rxjs-interop'; interface FileAttribute { diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html index 56ed7fa4c..78c824d35 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html @@ -29,6 +29,7 @@ *ngIf="documentInfoService.hidden()" [actionsTemplate]="annotationFilterActionTemplate" [attr.help-mode-key]="'workload_in_editor'" + [fileId]="state.file()?.id" [primaryFiltersSlug]="'primaryFilters'" [secondaryFiltersSlug]="'secondaryFilters'" > @@ -216,6 +217,6 @@ *ngIf="filter.id === 'skipped'" [icon]="skippedService.hideSkipped() ? 'red:visibility-off' : 'red:visibility'" [type]="circleButtonTypes.dark" - preventDefault + iqserPreventDefault > diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts index 515b53474..8461382d1 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts @@ -1,18 +1,9 @@ -import { ChangeDetectorRef, Component, computed, effect, ElementRef, HostListener, OnDestroy, ViewChild } from '@angular/core'; +import { ChangeDetectorRef, Component, computed, effect, ElementRef, HostListener, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { AnnotationProcessingService } from '../../services/annotation-processing.service'; import { MatDialog } from '@angular/material/dialog'; import scrollIntoView from 'scroll-into-view-if-needed'; -import { - AutoUnsubscribe, - bool, - CircleButtonTypes, - Debounce, - FilterService, - IconButtonTypes, - INestedFilter, - IqserEventTarget, -} from '@iqser/common-ui'; +import { CircleButtonTypes, IconButtonTypes } from '@iqser/common-ui'; import { combineLatest, delay, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { ExcludedPagesService } from '../../services/excluded-pages.service'; @@ -30,6 +21,9 @@ import { REDDocumentViewer } from '../../../pdf-viewer/services/document-viewer. import { SuggestionsService } from '../../services/suggestions.service'; import { ListItem } from '@models/file/list-item'; import { PageRotationService } from '../../../pdf-viewer/services/page-rotation.service'; +import { getLocalStorageDataByFileId } from '@utils/local-storage'; +import { FilterService, INestedFilter } from '@iqser/common-ui/lib/filtering'; +import { AutoUnsubscribe, bool, Debounce, IqserEventTarget } from '@iqser/common-ui/lib/utils'; const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape']; const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']; @@ -39,10 +33,11 @@ const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']; templateUrl: './file-workload.component.html', styleUrls: ['./file-workload.component.scss'], }) -export class FileWorkloadComponent extends AutoUnsubscribe implements OnDestroy { +export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, OnDestroy { + @ViewChild('annotationsElement') private readonly _annotationsElement: ElementRef; + @ViewChild('quickNavigation') private readonly _quickNavigationElement: ElementRef; readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; - displayedAnnotations = new Map(); displayedPages: number[] = []; pagesPanelActive = true; @@ -51,8 +46,6 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnDestroy this.viewModeService.isEarmarks() ? _('file-preview.tabs.highlights.label') : _('file-preview.tabs.annotations.label'), ); readonly currentPageIsExcluded = computed(() => this.state.file().excludedPages.includes(this.pdf.currentPage())); - @ViewChild('annotationsElement') private readonly _annotationsElement: ElementRef; - @ViewChild('quickNavigation') private readonly _quickNavigationElement: ElementRef; constructor( readonly filterService: FilterService, @@ -155,6 +148,20 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnDestroy } } + ngOnInit(): void { + setTimeout(() => { + const showExcludePages = getLocalStorageDataByFileId(this.state.file()?.id, 'show-exclude-pages') ?? false; + if (showExcludePages) { + this.excludedPagesService.show(); + } + + const showDocumentInfo = getLocalStorageDataByFileId(this.state.file()?.id, 'show-document-info') ?? false; + if (showDocumentInfo) { + this.documentInfoService.show(); + } + }); + } + selectAllOnActivePage() { this.listingService.selectAnnotations(this.activeAnnotations); } diff --git a/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.ts b/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.ts index 4472986f9..262f9f979 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.ts @@ -3,12 +3,13 @@ import { PermissionsService } from '@services/permissions.service'; import { ViewedPagesService } from '@services/files/viewed-pages.service'; import { FilePreviewStateService } from '../../services/file-preview-state.service'; import { PageRotationService } from '../../../pdf-viewer/services/page-rotation.service'; -import { ContextComponent, getConfig } from '@iqser/common-ui'; +import { getConfig } from '@iqser/common-ui'; import { map, tap } from 'rxjs/operators'; import { AppConfig, ViewedPage } from '@red/domain'; import { ViewedPagesMapService } from '@services/files/viewed-pages-map.service'; import { pairwise } from 'rxjs'; import { PdfViewer } from '../../../pdf-viewer/services/pdf-viewer.service'; +import { ContextComponent } from '@iqser/common-ui/lib/utils'; interface PageIndicatorContext { isRotated: boolean; @@ -21,14 +22,13 @@ interface PageIndicatorContext { styleUrls: ['./page-indicator.component.scss'], }) export class PageIndicatorComponent extends ContextComponent implements OnChanges, OnInit { + readonly #config = getConfig(); @Input({ required: true }) number: number; @Input() showDottedIcon = false; @Input() activeSelection = false; @Input() read = false; @Output() readonly pageSelected = new EventEmitter(); - pageReadTimeout: number = null; - readonly #config = getConfig(); constructor( private readonly _viewedPagesService: ViewedPagesService, diff --git a/apps/red-ui/src/app/modules/file-preview/components/pages/pages.component.ts b/apps/red-ui/src/app/modules/file-preview/components/pages/pages.component.ts index 287c7db81..b268b15db 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/pages/pages.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/pages/pages.component.ts @@ -1,5 +1,5 @@ import { Component, inject, Input } from '@angular/core'; -import { List } from '@iqser/common-ui'; +import { List } from '@iqser/common-ui/lib/utils'; import { PdfViewer } from '../../../pdf-viewer/services/pdf-viewer.service'; import { MultiSelectService } from '../../services/multi-select.service'; import { AnnotationsListingService } from '../../services/annotations-listing.service'; @@ -14,13 +14,13 @@ import { ViewedPage } from '@red/domain'; styleUrls: ['./pages.component.scss'], }) export class PagesComponent { - @Input({ required: true }) pages: List; - @Input({ required: true }) displayedAnnotations: Map; - protected readonly _pdf = inject(PdfViewer); readonly #state = inject(FilePreviewStateService); - readonly viewedPages$ = inject(ViewedPagesMapService).get$(this.#state.fileId); readonly #multiSelectService = inject(MultiSelectService); readonly #listingService = inject(AnnotationsListingService); + protected readonly _pdf = inject(PdfViewer); + @Input({ required: true }) pages: List; + @Input({ required: true }) displayedAnnotations: Map; + readonly viewedPages$ = inject(ViewedPagesMapService).get$(this.#state.fileId); pageSelectedByClick($event: number): void { this._pdf.navigateTo($event); diff --git a/apps/red-ui/src/app/modules/file-preview/components/user-management/user-management.component.ts b/apps/red-ui/src/app/modules/file-preview/components/user-management/user-management.component.ts index b96e5df60..5c04bd120 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/user-management/user-management.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/user-management/user-management.component.ts @@ -1,6 +1,6 @@ import { Component, computed } from '@angular/core'; import { File, User } from '@red/domain'; -import { getCurrentUser, LoadingService, Toaster } from '@iqser/common-ui'; +import { LoadingService, Toaster } from '@iqser/common-ui'; import { PermissionsService } from '@services/permissions.service'; import { workflowFileStatusTranslations } from '@translations/file-status-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @@ -9,6 +9,7 @@ import { FilesService } from '@services/files/files.service'; import { FilePreviewStateService } from '../../services/file-preview-state.service'; import { FileAssignService } from '../../../shared-dossiers/services/file-assign.service'; import { moveElementInArray } from '@utils/functions'; +import { getCurrentUser } from '@iqser/common-ui/lib/users'; @Component({ selector: 'redaction-user-management', @@ -16,17 +17,6 @@ import { moveElementInArray } from '@utils/functions'; styleUrls: ['./user-management.component.scss'], }) export class UserManagementComponent { - readonly translations = workflowFileStatusTranslations; - readonly statusBarConfig = computed(() => [{ length: 1, color: this.state.file().workflowStatus }]); - readonly assignTooltip = computed(() => { - const file = this.state.file(); - return file.isUnderApproval - ? _('dossier-overview.assign-approver') - : file.assignee - ? _('file-preview.change-reviewer') - : _('file-preview.assign-reviewer'); - }); - editingReviewer = false; protected readonly _canAssignToSelf = computed(() => this.permissionsService.canAssignToSelf(this.state.file(), this.state.dossier())); protected readonly _canAssignUser = computed(() => this.permissionsService.canAssignUser(this.state.file(), this.state.dossier())); protected readonly _canUnassignUser = computed(() => this.permissionsService.canUnassignUser(this.state.file(), this.state.dossier())); @@ -45,6 +35,17 @@ export class UserManagementComponent { : this.#customSort([...dossier.memberIds, ...unassignUser]); }); protected readonly _currentUserId = getCurrentUser().id; + readonly translations = workflowFileStatusTranslations; + readonly statusBarConfig = computed(() => [{ length: 1, color: this.state.file().workflowStatus }]); + readonly assignTooltip = computed(() => { + const file = this.state.file(); + return file.isUnderApproval + ? _('dossier-overview.assign-approver') + : file.assignee + ? _('file-preview.change-reviewer') + : _('file-preview.assign-reviewer'); + }); + editingReviewer = false; constructor( readonly fileAssignService: FileAssignService, diff --git a/apps/red-ui/src/app/modules/file-preview/components/view-switch/view-switch.component.ts b/apps/red-ui/src/app/modules/file-preview/components/view-switch/view-switch.component.ts index a79ec3af4..3df651796 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/view-switch/view-switch.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/view-switch/view-switch.component.ts @@ -3,11 +3,12 @@ import { ViewMode, ViewModes } from '@red/domain'; import { ViewModeService } from '../../services/view-mode.service'; import { FilePreviewStateService } from '../../services/file-preview-state.service'; import { FileDataService } from '../../services/file-data.service'; -import { BASE_HREF, ConfirmOptions, IConfirmationDialogData, Toaster } from '@iqser/common-ui'; +import { ConfirmOptions, IConfirmationDialogData, Toaster } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { UserPreferenceService } from '@users/user-preference.service'; import { FilePreviewDialogService } from '../../services/file-preview-dialog.service'; import { Roles } from '@users/roles'; +import { BASE_HREF } from '@iqser/common-ui/lib/utils'; @Component({ selector: 'redaction-view-switch', diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.html index f0652bbb7..fec0d8467 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.html @@ -1,6 +1,6 @@
-
+
@@ -42,7 +42,7 @@ -
+
@@ -61,7 +61,7 @@
-
+