diff --git a/.commit b/.commit index 24199cba5..1d2df3423 100644 --- a/.commit +++ b/.commit @@ -1 +1 @@ -717f928fedecede6e2b43fc7b3f792172a9e18e0 +87a0bb7cdaaaaba31aa794d497f2da86f2450e29 diff --git a/README.md b/README.md index 7482e2c37..360a16a8a 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,17 @@ # Identity Manager HTML5 applications ## Change log +### March 06, 2025 +- 443363: Fixes an issue with typescript entities, while synchronizing in case of an error. +- 474677: Fixes an issue with the inheritance of memberships for `UNSGroupCollection`. +- 464626: Fixes an issue with hard coded FK candidate endpoints. +- 475616: Fixes an additional issue with navigating directly to the attestation, while an user is not authenticated. +- 475458: Fixes an issue with directing to the login page after an user is already authenticated. +- 477620: Fixes an issue with deleting shopping cart items, in case of cancellation. +- 456426: Fixes an issue on the product by reference page, if th user directly navigates to the page. +- 469349: Fixes additional issues with duplicated requests on data tables. +- 473064: Fixes an issue with duplicated requests for Data Explorer -> User Accounts page. +- 470237: Fixes additional issues with duplicated requests on data tables, that resulted in a bad state. ### February 20,2025 - Fixes some package-vulnerabilities diff --git a/imxweb/projects/aob/src/lib/aob-config.module.ts b/imxweb/projects/aob/src/lib/aob-config.module.ts index 5d56d0d0b..7e0bb0056 100644 --- a/imxweb/projects/aob/src/lib/aob-config.module.ts +++ b/imxweb/projects/aob/src/lib/aob-config.module.ts @@ -26,35 +26,35 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; +import { RouterModule, Routes } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { ClassloggerService, DocChapterService, DocDocument, HELP_CONTEXTUAL, RouteGuardService } from 'qbm'; import { TilesModule } from 'qer'; import { AobService } from './aob.service'; -import { ApplicationsComponent } from './applications/applications.component'; -import { ApplicationNavigationComponent } from './applications/application-navigation/application-navigation.component'; import { ApplicationDetailComponent } from './applications/application-detail.component'; +import { ApplicationNavigationComponent } from './applications/application-navigation/application-navigation.component'; +import { ApplicationsComponent } from './applications/applications.component'; import { ApplicationsModule } from './applications/applications.module'; import { EntitlementsModule } from './entitlements/entitlements.module'; -import { StartPageModule } from './start-page/start-page.module'; -import { AobApplicationsGuardService } from './guards/aob-applications-guard.service'; +import { LockInfoAlertComponent } from './extensions/service-items-edit/lock-info-alert/lock-info-alert.component'; import { GlobalKpiComponent } from './global-kpi/global-kpi.component'; +import { AobApplicationsGuardService } from './guards/aob-applications-guard.service'; import { AobKpiGuardService } from './guards/aob-kpi-guard.service'; -import { LockInfoAlertComponent } from './extensions/service-items-edit/lock-info-alert/lock-info-alert.component'; +import { StartPageModule } from './start-page/start-page.module'; const routes: Routes = [ { path: 'applications/kpi', component: GlobalKpiComponent, - canActivate: [RouteGuardService, AobKpiGuardService], - resolve: [RouteGuardService] + canActivate: [AobKpiGuardService], + resolve: [RouteGuardService], }, { path: 'applications', component: ApplicationsComponent, - canActivate: [RouteGuardService, AobApplicationsGuardService], + canActivate: [AobApplicationsGuardService], resolve: [RouteGuardService], children: [ { @@ -62,9 +62,9 @@ const routes: Routes = [ component: ApplicationNavigationComponent, canActivate: [RouteGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.Applications - } + data: { + contextId: HELP_CONTEXTUAL.Applications, + }, }, { path: 'detail', @@ -75,7 +75,7 @@ const routes: Routes = [ }, { path: ':create:id', redirectTo: 'applications', pathMatch: 'full' }, ], - } + }, ]; @NgModule({ @@ -90,14 +90,14 @@ const routes: Routes = [ TranslateModule, RouterModule.forChild(routes), ], - declarations: [ - LockInfoAlertComponent - ], + declarations: [LockInfoAlertComponent], }) export class AobConfigModule { - constructor(private readonly initializer: AobService, + constructor( + private readonly initializer: AobService, private readonly docSvc: DocChapterService, - private readonly logger: ClassloggerService) { + private readonly logger: ClassloggerService + ) { this.logger.info(this, '🔥 AOB loaded'); this.initializer.onInit(routes); this.configureDocPaths(); @@ -108,16 +108,16 @@ export class AobConfigModule { // Web Portal for Application Governance User Guide var appgovDoc: DocDocument = { paths: { - "en-US": "imx/doc/OneIM_AOB_UserGuide_en-us.html5/OneIM_AOB_UserGuide.html", - "de-DE": "imx/doc/OneIM_AOB_UserGuide_de-de.html5/OneIM_AOB_UserGuide.html", - "de-CH": "imx/doc/OneIM_AOB_UserGuide_de-de.html5/OneIM_AOB_UserGuide.html", - "de-AT": "imx/doc/OneIM_AOB_UserGuide_de-de.html5/OneIM_AOB_UserGuide.html" - } + 'en-US': 'imx/doc/OneIM_AOB_UserGuide_en-us.html5/OneIM_AOB_UserGuide.html', + 'de-DE': 'imx/doc/OneIM_AOB_UserGuide_de-de.html5/OneIM_AOB_UserGuide.html', + 'de-CH': 'imx/doc/OneIM_AOB_UserGuide_de-de.html5/OneIM_AOB_UserGuide.html', + 'de-AT': 'imx/doc/OneIM_AOB_UserGuide_de-de.html5/OneIM_AOB_UserGuide.html', + }, }; - this.docSvc.chapters["applications"] = { - chapterUid: "35FE656D-A608-4B16-A55F-B758D5B72F75", - document: appgovDoc + this.docSvc.chapters['applications'] = { + chapterUid: '35FE656D-A608-4B16-A55F-B758D5B72F75', + document: appgovDoc, }; } } diff --git a/imxweb/projects/aob/src/lib/guards/aob-applications-guard.service.ts b/imxweb/projects/aob/src/lib/guards/aob-applications-guard.service.ts index d21fdd464..a9d724a5a 100644 --- a/imxweb/projects/aob/src/lib/guards/aob-applications-guard.service.ts +++ b/imxweb/projects/aob/src/lib/guards/aob-applications-guard.service.ts @@ -25,10 +25,10 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; +import { AppConfigService, AuthenticationService, RouteGuardService } from 'qbm'; import { AobPermissionsService } from '../permissions/aob-permissions.service'; @Injectable({ @@ -41,23 +41,21 @@ export class AobApplicationsGuardService implements CanActivate, OnDestroy { private readonly aobPermissionService: AobPermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + private readonly routeGuardService: RouteGuardService + ) {} - public canActivate(): Observable { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const isApplicationOwner = await this.aobPermissionService.isAobApplicationOwner(); - const isApplicationAdmin = await this.aobPermissionService.isAobApplicationAdmin(); - if (!isApplicationOwner && !isApplicationAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); - } - observer.next(isApplicationOwner || isApplicationAdmin); - observer.complete(); - } - }); - }); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const isApplicationOwner = await this.aobPermissionService.isAobApplicationOwner(); + const isApplicationAdmin = await this.aobPermissionService.isAobApplicationAdmin(); + if (!isApplicationOwner && !isApplicationAdmin) { + this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + } + return isApplicationOwner || isApplicationAdmin; + } + this.router.navigate([this.appConfig.Config.routeConfig.login]); + return false; } public ngOnDestroy(): void { diff --git a/imxweb/projects/aob/src/lib/guards/aob-kpi-guard.service.ts b/imxweb/projects/aob/src/lib/guards/aob-kpi-guard.service.ts index 53569b5e9..99d2178af 100644 --- a/imxweb/projects/aob/src/lib/guards/aob-kpi-guard.service.ts +++ b/imxweb/projects/aob/src/lib/guards/aob-kpi-guard.service.ts @@ -25,10 +25,10 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; +import { AppConfigService, AuthenticationService, RouteGuardService } from 'qbm'; import { AobPermissionsService } from '../permissions/aob-permissions.service'; @Injectable({ @@ -41,22 +41,20 @@ export class AobKpiGuardService implements CanActivate, OnDestroy { private readonly aobPermissionService: AobPermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + private readonly routeGuardService: RouteGuardService + ) {} - public canActivate(): Observable { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const isApplicationAdmin = await this.aobPermissionService.isAobApplicationAdmin(); - if (!isApplicationAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); - } - observer.next(isApplicationAdmin); - observer.complete(); - } - }); - }); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const isApplicationAdmin = await this.aobPermissionService.isAobApplicationAdmin(); + if (!isApplicationAdmin) { + this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + } + return isApplicationAdmin; + } + this.router.navigate([this.appConfig.Config.routeConfig.login]); + return false; } public ngOnDestroy(): void { diff --git a/imxweb/projects/att/src/lib/att-config.module.ts b/imxweb/projects/att/src/lib/att-config.module.ts index 40e8b54e1..9196c9173 100644 --- a/imxweb/projects/att/src/lib/att-config.module.ts +++ b/imxweb/projects/att/src/lib/att-config.module.ts @@ -28,33 +28,32 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { MatIconModule } from '@angular/material/icon'; import { MatListModule } from '@angular/material/list'; -import { Routes, RouterModule } from '@angular/router'; +import { RouterModule, Routes } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; import { EuiCoreModule } from '@elemental-ui/core'; -import { PolicyListComponent } from './policies/policy-list/policy-list.component'; -import { PolicyGroupListComponent } from './policy-group/policy-group-list/policy-group-list.component'; import { ClassloggerService, HELP_CONTEXTUAL, RouteGuardService } from 'qbm'; -import { InitService } from './init.service'; -import { AttestationDecisionModule } from './decision/attestation-decision.module'; -import { AttestationDecisionComponent } from './decision/attestation-decision.component'; -import { DashboardPluginComponent } from './dashboard-plugin/dashboard-plugin.component'; -import { AttestationRunsModule } from './runs/attestation-runs.module'; -import { RunsComponent } from './runs/runs.component'; import { TilesModule } from 'qer'; -import { AttestationHistoryWrapperComponent } from './attestation-history/attestation-history-wrapper.component'; import { AttestationFeatureGuardService } from './attestation-feature-guard.service'; -import { PickCategoryComponent } from './pick-category/pick-category.component'; -import { AttestionAdminGuardService } from './guards/attestation-admin-guard.service'; -import { AttestationPoliciesGuardService } from './guards/attestation-policies-guard.service'; -import { ClaimDeviceComponent } from './claim-device/claim-device.component'; +import { AttestationHistoryWrapperComponent } from './attestation-history/attestation-history-wrapper.component'; import { MyAttestationCasesComponent } from './attestation-history/my-attestation-cases/my-attestation-cases.component'; +import { ClaimDeviceComponent } from './claim-device/claim-device.component'; +import { DashboardPluginComponent } from './dashboard-plugin/dashboard-plugin.component'; +import { AttestationDecisionComponent } from './decision/attestation-decision.component'; +import { AttestationDecisionModule } from './decision/attestation-decision.module'; +import { AttestionAdminGuardService } from './guards/attestation-admin-guard.service'; import { HardwareGuardService } from './hardware-guard.service'; +import { InitService } from './init.service'; +import { PickCategoryComponent } from './pick-category/pick-category.component'; +import { PolicyListComponent } from './policies/policy-list/policy-list.component'; +import { PolicyGroupListComponent } from './policy-group/policy-group-list/policy-group-list.component'; +import { AttestationRunsModule } from './runs/attestation-runs.module'; +import { RunsComponent } from './runs/runs.component'; const routes: Routes = [ { path: 'attestation/policies', component: PolicyListComponent, - canActivate: [RouteGuardService, AttestationFeatureGuardService, AttestationPoliciesGuardService], + canActivate: [AttestationFeatureGuardService], resolve: [RouteGuardService], data: { contextId: HELP_CONTEXTUAL.AttestationPolicies, @@ -63,7 +62,7 @@ const routes: Routes = [ { path: 'attestation/runs', component: RunsComponent, - canActivate: [RouteGuardService, AttestationFeatureGuardService, AttestationPoliciesGuardService], + canActivate: [AttestationFeatureGuardService], resolve: [RouteGuardService], data: { contextId: HELP_CONTEXTUAL.AttestationRuns, @@ -72,7 +71,7 @@ const routes: Routes = [ { path: 'attestation/history', component: AttestationHistoryWrapperComponent, - canActivate: [RouteGuardService, AttestationFeatureGuardService], + canActivate: [AttestationFeatureGuardService], resolve: [RouteGuardService], data: { contextId: HELP_CONTEXTUAL.AttestationHistory, @@ -81,7 +80,7 @@ const routes: Routes = [ { path: 'attestation/decision', component: AttestationDecisionComponent, - canActivate: [RouteGuardService, AttestationFeatureGuardService], + canActivate: [AttestationFeatureGuardService], resolve: [RouteGuardService], data: { contextId: HELP_CONTEXTUAL.PendingAttestations, @@ -90,7 +89,7 @@ const routes: Routes = [ { path: 'attestation/preselection', component: PickCategoryComponent, - canActivate: [RouteGuardService, AttestationFeatureGuardService, AttestionAdminGuardService], + canActivate: [AttestationFeatureGuardService, AttestionAdminGuardService], resolve: [RouteGuardService], data: { contextId: HELP_CONTEXTUAL.AttestationPreselection, @@ -108,7 +107,7 @@ const routes: Routes = [ { path: 'attestation/policy-group', component: PolicyGroupListComponent, - canActivate: [RouteGuardService, AttestationFeatureGuardService, AttestationPoliciesGuardService], + canActivate: [AttestationFeatureGuardService], data: { contextId: HELP_CONTEXTUAL.AttestationPolicyCollections, }, @@ -117,7 +116,7 @@ const routes: Routes = [ { path: 'attestation/myattestationcases', component: MyAttestationCasesComponent, - canActivate: [RouteGuardService, AttestationFeatureGuardService], + canActivate: [AttestationFeatureGuardService], resolve: [RouteGuardService], data: { contextId: HELP_CONTEXTUAL.AttestationMyAttestationCases, @@ -126,9 +125,7 @@ const routes: Routes = [ ]; @NgModule({ - declarations: [ - DashboardPluginComponent - ], + declarations: [DashboardPluginComponent], imports: [ CommonModule, TilesModule, @@ -139,11 +136,10 @@ const routes: Routes = [ MatListModule, TranslateModule, EuiCoreModule, - ] + ], }) export class AttConfigModule { - constructor( - private readonly initializer: InitService, private readonly logger: ClassloggerService) { + constructor(private readonly initializer: InitService, private readonly logger: ClassloggerService) { this.logger.info(this, '🔥 ATT loaded'); this.initializer.onInit(routes); this.logger.info(this, '▶️ ATT initialized'); diff --git a/imxweb/projects/att/src/lib/attestation-feature-guard.service.spec.ts b/imxweb/projects/att/src/lib/attestation-feature-guard.service.spec.ts index 31b88de1a..fe920d4c6 100644 --- a/imxweb/projects/att/src/lib/attestation-feature-guard.service.spec.ts +++ b/imxweb/projects/att/src/lib/attestation-feature-guard.service.spec.ts @@ -26,8 +26,7 @@ import { TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; -import { AuthenticationService, ISessionState } from 'qbm'; -import { BehaviorSubject } from 'rxjs'; +import { AppConfigService, CacheService, RouteGuardService } from 'qbm'; import { ApiService } from './api.service'; import { AttestationFeatureGuardService } from './attestation-feature-guard.service'; @@ -39,8 +38,14 @@ describe('AttestationFeatureGuardService', () => { portal_attestation_config_get: jasmine.createSpy('portal_attestation_config_get').and.returnValue(Promise.resolve([{}])), }, }; - const authService = { - onSessionResponse: new BehaviorSubject({ IsLoggedIn: true }), + + const cacheServiceStub = { + buildCache: jasmine.createSpy('buildCache').and.returnValue(Promise.resolve(true)) + }; + + + const routeGuardServiceStub = { + canActivate: jasmine.createSpy('canActivate').and.returnValue(Promise.resolve(true)) }; beforeEach(() => { @@ -52,9 +57,25 @@ describe('AttestationFeatureGuardService', () => { useValue: attServiceStub, }, { - provide: AuthenticationService, - useValue: authService, + provide: RouteGuardService, + useValue: routeGuardServiceStub }, + { + provide: CacheService, + useValue: cacheServiceStub + }, + { + provide: AppConfigService, + useValue: { + Config: { + Title: '', + routeConfig: { + start: 'dashboard', + login: '' + } + } + } + } ], }); service = TestBed.inject(AttestationFeatureGuardService); diff --git a/imxweb/projects/att/src/lib/attestation-feature-guard.service.ts b/imxweb/projects/att/src/lib/attestation-feature-guard.service.ts index 0a331fd85..99f97b907 100644 --- a/imxweb/projects/att/src/lib/attestation-feature-guard.service.ts +++ b/imxweb/projects/att/src/lib/attestation-feature-guard.service.ts @@ -25,40 +25,47 @@ */ import { Injectable } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; import { AttestationConfig } from 'imx-api-att'; -import { AuthenticationService } from 'qbm'; +import { AppConfigService, CacheService, RouteGuardService } from 'qbm'; import { ApiService } from './api.service'; +import { CachedPromise } from 'imx-qbm-dbts'; @Injectable({ providedIn: 'root', }) export class AttestationFeatureGuardService implements CanActivate { - constructor(private attService: ApiService, private readonly router: Router, private readonly authentication: AuthenticationService) {} - private config: AttestationConfig; - - public async getAttestationConfig(): Promise { - if (!this.config) { - await this.setAttestationConfig(); - } - return this.config; + constructor( + private attService: ApiService, + private readonly appConfig: AppConfigService, + private readonly router: Router, + private readonly routeGuardService: RouteGuardService, + cacheService: CacheService + ) { + this.cachedAttestationConfig = cacheService.buildCache(() => this.attService.client.portal_attestation_config_get()); } + private config: Promise; - public async setAttestationConfig(): Promise { - this.config = await this.attService.client.portal_attestation_config_get(); + // The cached promises cache the results of often needed API requests. + // The CacheService takes care of flushing the cache when re-authenticating. + private cachedAttestationConfig: CachedPromise; + + public getAttestationConfig(): Promise { + this.config = this.cachedAttestationConfig.get(); + return this.config; } - public async canActivate(): Promise { - let sessionState = this.authentication.onSessionResponse.getValue(); - if (sessionState.IsLoggedIn) { - await this.setAttestationConfig(); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + this.getAttestationConfig(); - const featureEnabled = this.config?.IsAttestationEnabled; - if (featureEnabled) { - return featureEnabled; + const featureEnabled = (await this.config)?.IsAttestationEnabled; + if (!featureEnabled) { + this.router.navigate([this.appConfig.Config.routeConfig.start]); } + return featureEnabled; } - this.router.navigate(['']); + this.router.navigate([this.appConfig.Config.routeConfig.login]); return false; } } diff --git a/imxweb/projects/att/src/lib/decision/attestation-decision.component.ts b/imxweb/projects/att/src/lib/decision/attestation-decision.component.ts index 65f0d1ab3..0b952e97d 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-decision.component.ts +++ b/imxweb/projects/att/src/lib/decision/attestation-decision.component.ts @@ -209,7 +209,7 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { await this.initDataModel(true); await this.parseParams(); - await this.getData(undefined, true); + await this.getData(undefined); this.handleDecision(); } finally { setTimeout(() => { @@ -291,7 +291,7 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { return this.getData({ ...this.navigationState, ...{ search } }); } - public async getData(newState?: CollectionLoadParameters, isInitialLoad: boolean = false): Promise { + public async getData(newState?: CollectionLoadParameters): Promise { if (newState) { this.navigationState = newState; } @@ -303,9 +303,7 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { ...this.navigationState, Escalation: this.attestationCases.isChiefApproval, }; - const dataSource = isInitialLoad - ? { totalCount: 0, Data: [] } - : await this.attestationCases.get(this.navigationState); + const dataSource = await this.attestationCases.get(this.navigationState); if (dataSource) { const exportMethod = this.attestationCases.exportData(this.navigationState); this.dstSettings = { diff --git a/imxweb/projects/att/src/lib/guards/attestation-admin-guard.service.ts b/imxweb/projects/att/src/lib/guards/attestation-admin-guard.service.ts index d235b918a..102c600da 100644 --- a/imxweb/projects/att/src/lib/guards/attestation-admin-guard.service.ts +++ b/imxweb/projects/att/src/lib/guards/attestation-admin-guard.service.ts @@ -25,10 +25,10 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; +import { AppConfigService, AuthenticationService, RouteGuardService } from 'qbm'; import { PermissionsService } from '../admin/permissions.service'; @Injectable({ @@ -41,22 +41,21 @@ export class AttestionAdminGuardService implements CanActivate, OnDestroy { private readonly attPermissionService: PermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router + private readonly router: Router, + private readonly routeGuardService: RouteGuardService ) {} - public canActivate(route: ActivatedRouteSnapshot, _: RouterStateSnapshot): Observable { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const userIsAttestationAdmin = await this.attPermissionService.isAttestationAdmin(); - if (!userIsAttestationAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} } ); - } - observer.next(userIsAttestationAdmin ? true : false); - observer.complete(); - } - }); - }); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const userIsAttestationAdmin = await this.attPermissionService.isAttestationAdmin(); + if (userIsAttestationAdmin) { + return true; + } + this.router.navigate([this.appConfig.Config.routeConfig.start]); + } else { + this.router.navigate([this.appConfig.Config.routeConfig.login]); + } + return false; } public ngOnDestroy(): void { diff --git a/imxweb/projects/att/src/lib/guards/attestation-policies-guard.service.ts b/imxweb/projects/att/src/lib/guards/attestation-policies-guard.service.ts index a6bc0720a..8e6632982 100644 --- a/imxweb/projects/att/src/lib/guards/attestation-policies-guard.service.ts +++ b/imxweb/projects/att/src/lib/guards/attestation-policies-guard.service.ts @@ -25,9 +25,9 @@ */ import { Injectable } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; -import { AppConfigService } from 'qbm'; +import { AppConfigService, RouteGuardService } from 'qbm'; import { PermissionsService } from '../admin/permissions.service'; @Injectable({ @@ -37,15 +37,20 @@ export class AttestationPoliciesGuardService implements CanActivate { constructor( private readonly permissionService: PermissionsService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + private readonly routeGuardService: RouteGuardService + ) {} - public async canActivate(): Promise { - const userCanSeeAttestationPolicies = await this.permissionService.canSeeAttestationPolicies(); - if (!userCanSeeAttestationPolicies) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); - return false; + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const userCanSeeAttestationPolicies = await this.permissionService.canSeeAttestationPolicies(); + if (userCanSeeAttestationPolicies) { + return userCanSeeAttestationPolicies; + } + this.router.navigate([this.appConfig.Config.routeConfig.start]); + } else { + this.router.navigate([this.appConfig.Config.routeConfig.login]); } - return userCanSeeAttestationPolicies; + return false; } } diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.ts b/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.ts index 231a5a933..d4bbb466a 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.ts @@ -73,10 +73,10 @@ export class PickCategorySelectIdentitiesComponent implements OnInit { } public async ngOnInit(): Promise { - await this.getData(undefined, true); + await this.getData(undefined); } - public async getData(navigationState?: CollectionLoadParameters, isInitialLoad: boolean = false): Promise { + public async getData(navigationState?: CollectionLoadParameters): Promise { const isBusy = this.busyService.beginBusy(); try { @@ -84,7 +84,7 @@ export class PickCategorySelectIdentitiesComponent implements OnInit { ...navigationState, ...{ filter: await this.getFilter() }, }; - this.dstSettings = await this.dstWrapper.getDstSettings(navigationState, undefined, isInitialLoad); + this.dstSettings = await this.dstWrapper.getDstSettings(navigationState, undefined); } finally { isBusy.endBusy(); } diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.ts b/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.ts index df4e81b8f..6d1a0dc4b 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.ts @@ -90,16 +90,15 @@ export class PickCategorySidesheetComponent implements OnInit { this.uidPickCategory = this.data.pickCategory.GetEntity()?.GetKeys()?.join(','); this.displayNameCdr = new BaseCdr(this.data.pickCategory.DisplayName.Column, '#LDS#Display name'); this.displayNameCdr.minLength = 1; - await this.getData(undefined, true); + await this.getData(undefined); } - public async getData(newState?: CollectionLoadParameters, isInitialLoad: boolean = false): Promise { + public async getData(newState?: CollectionLoadParameters): Promise { const isBusy = this.busyService.beginBusy(); try { const dstSettings = await this.dstWrapper.getDstSettings( newState, - { signal: this.pickCategoryService.abortController.signal }, - isInitialLoad + { signal: this.pickCategoryService.abortController.signal } ); if (dstSettings) { this.dstSettings = dstSettings; diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category.component.ts b/imxweb/projects/att/src/lib/pick-category/pick-category.component.ts index 448fcffe7..c67223113 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category.component.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category.component.ts @@ -80,7 +80,7 @@ export class PickCategoryComponent implements OnInit, OnDestroy { } public async ngOnInit(): Promise { - await this.getData(undefined, true); + await this.getData(undefined); } public ngOnDestroy(): void { @@ -105,13 +105,12 @@ export class PickCategoryComponent implements OnInit, OnDestroy { ); } - public async getData(newState?: CollectionLoadParameters, isInitialLoad: boolean = false): Promise { + public async getData(newState?: CollectionLoadParameters): Promise { const isBusy = this.busyService.beginBusy(); try { const dstSettings = await this.dstWrapper.getDstSettings( newState, - { signal: this.pickCategoryService.abortController.signal }, - isInitialLoad + { signal: this.pickCategoryService.abortController.signal } ); if (dstSettings) { this.dstSettings = dstSettings; diff --git a/imxweb/projects/att/src/lib/policies/policy.service.ts b/imxweb/projects/att/src/lib/policies/policy.service.ts index 9a7f5b746..fdfdbb008 100644 --- a/imxweb/projects/att/src/lib/policies/policy.service.ts +++ b/imxweb/projects/att/src/lib/policies/policy.service.ts @@ -56,6 +56,7 @@ import { ApiService } from '../api.service'; import { AttestationPolicy } from './policy-list/attestation-policy'; import { PolicyLoadParameters } from './policy-list/policy-load-parameters.interface'; import { PolicyCopyData } from './policy.interface'; +import { AttestationFeatureGuardService } from '../attestation-feature-guard.service'; @Injectable({ providedIn: 'root', @@ -67,6 +68,7 @@ export class PolicyService { constructor( private api: ApiService, + private readonly attFeatureService: AttestationFeatureGuardService, private readonly elementalUiConfigService: ElementalUiConfigService, private readonly translator: TranslateService, private readonly config: AppConfigService, @@ -212,7 +214,7 @@ export class PolicyService { } public async isComplienceFrameworkEnabled(): Promise { - return (await this.api.client.portal_attestation_config_get()).EnableComplianceFrameworks; + return (await this.attFeatureService.getAttestationConfig()).EnableComplianceFrameworks; } public getReportDownloadOptions(key: string, display: string): EuiDownloadOptions { @@ -224,7 +226,7 @@ export class PolicyService { } public async getCasesThreshold(): Promise { - return (await this.api.client.portal_attestation_config_get()).PolicyObjectCountThreshold; + return (await this.attFeatureService.getAttestationConfig()).PolicyObjectCountThreshold; } public async getRunCountForPolicy(uid: string): Promise { diff --git a/imxweb/projects/att/src/lib/runs/runs.service.ts b/imxweb/projects/att/src/lib/runs/runs.service.ts index 09b4fff6f..3b7a6f7a6 100644 --- a/imxweb/projects/att/src/lib/runs/runs.service.ts +++ b/imxweb/projects/att/src/lib/runs/runs.service.ts @@ -58,6 +58,7 @@ import { AttestationCaseLoadParameters } from '../attestation-history/attestatio import { AttestationCasesService } from '../decision/attestation-cases.service'; import { RunsLoadParameters } from './runs-load-parameters.interface'; import { SendReminderMailComponent } from './send-reminder-mail.component'; +import { AttestationFeatureGuardService } from '../attestation-feature-guard.service'; @Injectable({ providedIn: 'root', @@ -69,6 +70,7 @@ export class RunsService { constructor( private readonly snackBar: SnackBarService, + private readonly attFeatureService : AttestationFeatureGuardService, private readonly attService: ApiService, private readonly elementalUiConfigService: ElementalUiConfigService, private readonly sideSheet: EuiSidesheetService, @@ -183,7 +185,7 @@ export class RunsService { } public async attestationConfig(): Promise { - return await this.attService.client.portal_attestation_config_get(); + return await this.attFeatureService.getAttestationConfig(); } public getSchemaForCases(): EntitySchema { diff --git a/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/violations-per-rule/violations-per-rule.component.ts b/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/violations-per-rule/violations-per-rule.component.ts index 63c14e73a..1caca0fe8 100644 --- a/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/violations-per-rule/violations-per-rule.component.ts +++ b/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/violations-per-rule/violations-per-rule.component.ts @@ -82,7 +82,7 @@ export class ViolationsPerRuleComponent implements OnInit { this.dataModelWrapper ); - await this.getData(undefined, true); + await this.getData(undefined); } /** @@ -136,13 +136,12 @@ export class ViolationsPerRuleComponent implements OnInit { * Loads the dstSettings with load parameters * @param parameter Load parameter */ - public async getData(parameter?: CollectionLoadParameters, isInitialLoad: boolean = false): Promise { + public async getData(parameter?: CollectionLoadParameters): Promise { this.rulesViolationsService.handleOpenLoader(); try { const dstSettings = await this.dstWrapper.getDstSettings( parameter, - { signal: this.rulesViolationsService.abortController.signal }, - isInitialLoad + { signal: this.rulesViolationsService.abortController.signal } ); if (dstSettings) { this.dstSettings = dstSettings; diff --git a/imxweb/projects/cpl/src/lib/rules/rules.component.ts b/imxweb/projects/cpl/src/lib/rules/rules.component.ts index 09313dfad..85376539f 100644 --- a/imxweb/projects/cpl/src/lib/rules/rules.component.ts +++ b/imxweb/projects/cpl/src/lib/rules/rules.component.ts @@ -118,7 +118,7 @@ export class RulesComponent implements OnInit { if (!this.canRecalculate) { this.displayedColumns.pop(); } - await this.navigate({}); + await this.navigate({}, true); } finally { isBusy.endBusy(); } @@ -178,12 +178,12 @@ export class RulesComponent implements OnInit { } } - public async navigate(parameter: CollectionLoadParameters): Promise { + public async navigate(parameter: CollectionLoadParameters, isInitialLoad: boolean = false): Promise { this.navigationState = { ...this.navigationState, ...parameter }; const isBusy = this.busyService.beginBusy(); try { - const data = await this.rulesProvider.getRules(this.navigationState); + const data = isInitialLoad ? { totalCount: 0, Data: [] } : await this.rulesProvider.getRules(this.navigationState); if (data) { const exportMethod = this.rulesProvider.exportRules(this.navigationState); exportMethod.initialColumns = this.displayedColumns.map((col) => col.ColumnName); diff --git a/imxweb/projects/hds/src/lib/calls/calls.component.ts b/imxweb/projects/hds/src/lib/calls/calls.component.ts index ce7617836..48ee3e998 100644 --- a/imxweb/projects/hds/src/lib/calls/calls.component.ts +++ b/imxweb/projects/hds/src/lib/calls/calls.component.ts @@ -37,7 +37,9 @@ import { LdsReplacePipe, HelpContextualComponent, HelpContextualService, - HELP_CONTEXTUAL, BusyService } from 'qbm'; + HELP_CONTEXTUAL, + BusyService, +} from 'qbm'; import { CollectionLoadParameters, EntitySchema, FilterData, IClientProperty, ValType, DataModel } from 'imx-qbm-dbts'; @Component({ @@ -95,7 +97,7 @@ export class CallsComponent implements OnInit { }, ]; await this.setFilter(); - await this.loadTickets(); + await this.loadTickets(true); } finally { isBusy.endBusy(); } @@ -122,16 +124,15 @@ export class CallsComponent implements OnInit { width: 'max(600px, 60%)', data: sidesheetData, disableClose: true, - headerComponent: isNew ? HelpContextualComponent : undefined + headerComponent: isNew ? HelpContextualComponent : undefined, }; - if (!isNew){ - + if (!isNew) { euiSidesheetConfig.subTitle = this.replacePipe.transform( await this.translate.get('#LDS#Heading Ticket Number: {0}').toPromise(), ticket.CallNumber.value.toString() - ); - this.helpContextualService.setHelpContextId(HELP_CONTEXTUAL.HelpDeskSupportTicketsCreate); + ); + this.helpContextualService.setHelpContextId(HELP_CONTEXTUAL.HelpDeskSupportTicketsCreate); } let sidesheetRef = this.sidesheet.open(CallsSidesheetComponent, euiSidesheetConfig); sidesheetRef.afterClosed().subscribe(() => this.loadTickets()); @@ -150,10 +151,12 @@ export class CallsComponent implements OnInit { } } - private async loadTickets(): Promise { + private async loadTickets(isInitialLoad: boolean = false): Promise { const isBusy = this.busyService.beginBusy(); try { - let tickets = await this.hdsApiService.typedClient.PortalCalls.Get(this.collectionLoadParameters); + let tickets = isInitialLoad + ? { totalCount: 0, Data: [] } + : await this.hdsApiService.typedClient.PortalCalls.Get(this.collectionLoadParameters); this.dstSettings = { displayedColumns: this.displayedColumns, dataSource: tickets, diff --git a/imxweb/projects/pol/src/lib/policies/policies.component.ts b/imxweb/projects/pol/src/lib/policies/policies.component.ts index 32662e899..7924bebca 100644 --- a/imxweb/projects/pol/src/lib/policies/policies.component.ts +++ b/imxweb/projects/pol/src/lib/policies/policies.component.ts @@ -82,7 +82,7 @@ export class PoliciesComponent implements OnInit { this.filterOptions[indexActive].InitialValue = '1'; this.navigationState.active = '1'; } - await this.navigate({}); + await this.navigate({}, true); } public async showDetails(selectedPolicy: PortalPolicies): Promise { @@ -105,13 +105,13 @@ export class PoliciesComponent implements OnInit { .toPromise(); } - public async navigate(parameter: CollectionLoadParameters): Promise { + public async navigate(parameter: CollectionLoadParameters, isInitialLoad: boolean = false): Promise { const isBusy = this.busyService.beginBusy(); this.navigationState = { ...this.navigationState, ...parameter }; try { - const data = await this.policiesProvider.getPolicies(this.navigationState); + const data = isInitialLoad ? { totalCount: 0, Data: [] } : await this.policiesProvider.getPolicies(this.navigationState); if (data) { this.dstSettings = { displayedColumns: this.displayedColumns, diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations.component.ts b/imxweb/projects/pol/src/lib/policy-violations/policy-violations.component.ts index b9d45a609..ba104e355 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations.component.ts +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations.component.ts @@ -142,7 +142,7 @@ export class PolicyViolationsComponent implements OnInit { } finally { isBusy.endBusy(); } - return this.getData(undefined, true); + return this.getData(undefined); } public async viewDetails(selectedPolicyViolation: PolicyViolation): Promise { @@ -208,7 +208,7 @@ export class PolicyViolationsComponent implements OnInit { } } - public async getData(newState?: CollectionLoadParameters, isInitialLoad: boolean = false): Promise { + public async getData(newState?: CollectionLoadParameters): Promise { if (newState) { this.navigationState = newState; } @@ -221,9 +221,7 @@ export class PolicyViolationsComponent implements OnInit { this.navigationState.uid_qerpolicy = selectedCompanyPolicyKey; this.filterOptions = this.filterOptions.filter((filter) => filter.Name !== 'uid_qerpolicy'); } - const dataSource = isInitialLoad - ? { totalCount: 0, Data: [] } - : await this.policyViolationsService.get(this.approveOnly, this.navigationState); + const dataSource = await this.policyViolationsService.get(this.approveOnly, this.navigationState); if (dataSource) { const exportMethod = this.policyViolationsService.exportPolicyViolations(this.navigationState); exportMethod.initialColumns = this.displayedColumns.map((col) => col.ColumnName); diff --git a/imxweb/projects/qbm/src/lib/api-client/dynamic-method.ts b/imxweb/projects/qbm/src/lib/api-client/dynamic-method.ts index 30613dd64..73ec76c3d 100644 --- a/imxweb/projects/qbm/src/lib/api-client/dynamic-method.ts +++ b/imxweb/projects/qbm/src/lib/api-client/dynamic-method.ts @@ -79,6 +79,11 @@ export class DynamicMethod { return this.builder.buildReadWriteEntities(data, this.getSchema()); } + async Post(pathData: { [key: string]: string }, queryData: { [key: string]: any }, inputParameterName: any = {}) { + const data = await this.apiClient.processRequest(this.do_post(pathData, queryData, inputParameterName)); + return this.builder.buildReadWriteEntities(data, this.getSchema()); + } + public async getDataModei(options: { filter?: FilterData[] } = {}): Promise { return this.apiClient.processRequest(this.do_getDataModel(options)); } @@ -146,4 +151,44 @@ export class DynamicMethod { responseType: 'json', }; } + + private do_post( + pathData: { [key: string]: string }, + queryData: { [key: string]: string }, + inputParameterName: any, + ): MethodDescriptor { + const parameters: any[] = []; + for (var p of Object.keys(pathData)) { + parameters.push({ + name: p, + value: pathData[p], + in: 'path', + }); + } + for (var p of Object.keys(queryData)) { + parameters.push({ + name: p, + value: queryData[p], + in: 'query', + }); + } + parameters.push({ + name: 'inputParameterName', + value: inputParameterName, + required: true, + in: 'body', + }); + + return { + path: this.path, + parameters, + method: 'POST', + headers: { + 'imx-timezone': TimeZoneInfo.get(), + }, + credentials: 'include', + observe: 'response', + responseType: 'json', + }; + } } diff --git a/imxweb/projects/qbm/src/lib/base/query-parameters-handler.ts b/imxweb/projects/qbm/src/lib/base/query-parameters-handler.ts index e8eb459ec..c369a04b7 100644 --- a/imxweb/projects/qbm/src/lib/base/query-parameters-handler.ts +++ b/imxweb/projects/qbm/src/lib/base/query-parameters-handler.ts @@ -24,10 +24,12 @@ * */ -import { ActivatedRouteSnapshot, ParamMap, DefaultUrlSerializer } from '@angular/router'; +import { ActivatedRouteSnapshot, DefaultUrlSerializer, ParamMap, Params } from '@angular/router'; export class QueryParametersHandler { - public get path(): string { return this.lastPath || this.route?.routeConfig?.path; } + public get path(): string { + return this.lastPath || this.route?.routeConfig?.path; + } private readonly urlSerializer = new DefaultUrlSerializer(); private readonly queryParametersCollection: ParamMap[] = []; @@ -50,12 +52,12 @@ export class QueryParametersHandler { } } - public GetQueryParameters(filter: (name: string) => boolean = null): { [key: string]: any } { + public GetQueryParameters(filter: (name: string) => boolean = null): Params { const outparams: { [id: string]: any } = {}; - this.queryParametersCollection.forEach(params => { + this.queryParametersCollection.forEach((params) => { if (params.keys) { params.keys - .filter(name => filter == null || filter(name)) + .filter((name) => filter == null || filter(name)) .forEach((name: string) => { outparams[name] = params.get(name); }); diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.html index 31a390a3a..93992e79f 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.html @@ -8,6 +8,7 @@ [withTime]="withTime" [validateOnlyOnChange]="validateOnlyOnChange" [isLoading]="isBusy" + (manuallyChanged)="resetErrorCount()" [imxIdentifierSuffix]="'-cdr-' + columnContainer?.name"> diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.ts index af715c3b1..026f3316f 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.ts @@ -152,6 +152,14 @@ export class EditDateComponent implements CdrEditor, OnDestroy { } } + + /** + * Resets the counted errors to 0. + */ + public resetErrorCount(): void{ + this.errorCount=0; + } + /** * Sets Validators.required, if the control is mandatory, else it's set to null. * @ignore used internally @@ -185,8 +193,8 @@ export class EditDateComponent implements CdrEditor, OnDestroy { } this.previousValue = value; const date = value == null ? undefined : value.toDate(); - const resetDate = new Date(this.columnContainer.value); - const resetMoment = moment(resetDate); + const resetDate = this.columnContainer. value ? new Date(this.columnContainer.value) : undefined; + const resetMoment =resetDate ? moment(resetDate) : undefined; if (!this.columnContainer.canEdit || (value && value.isSame(this.columnContainer.value)) || (!value && !this.columnContainer.value)) { // if the value is the same, we don't need to update the value diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.ts index 4dc2d5a02..426a5a92c 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.ts @@ -498,6 +498,10 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy this.applyDynamicPropsAsSelectedFilters(config); } + if (!config && this.selectedFilters?.length === 0) { + emitNavigationStateChanged = false; + } + this.updateNavigateStateWithFilters(emitNavigationStateChanged); } @@ -506,12 +510,21 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * @param config the DSTViewConfig */ public applyGroupBy(config: DSTViewConfig): void { - const group = this.settings?.groupData?.groups?.find( + // search in the flat list of groups for the group from the config + let group = this.settings?.groupData?.groups?.find( (group) => this.getGroupColumnDisplay(group) === config.GroupBy || group.property.Property.ColumnName === config.GroupBy ); if (group) { this.onGroupSelected(group, undefined, true); } + + // search in the list of grouping categories and their groups for the group from the config + this.settings?.groupData?.groupingCategories?.find((category) => { + group = category.groups.find((group) => group.property.Value === config.GroupBy); + if (group?.property?.Value?.length > 0) { + this.onGroupSelected(group, category, true); + } + }); } /** @@ -570,9 +583,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy ViewId: this.settings.viewConfig.viewId, DisplayName: displayName, Filter: this.settings?.navigationState?.filter, - GroupBy: this.settings?.groupData?.groups?.find( - (group) => group.property.Property.Display === this.settings?.groupData?.currentGrouping?.display - )?.property.Property.ColumnName, + GroupBy: this.getGroupBy(), OrderBy: this.settings?.navigationState?.OrderBy, AdditionalListColumns: this.columnOptions?.additionalListElements?.map((ele) => ele.ColumnName), AdditionalTableColumns: this.columnOptions?.selectedOptionals @@ -1404,6 +1415,27 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy } } + private getGroupBy(): string { + if (!this.settings?.groupData?.currentGrouping) { + return undefined; + } + const currentGroupingDisplay = this.settings?.groupData?.currentGrouping?.display; + + // search in the flat list of groups for the group + let group = this.settings?.groupData?.groups?.find((group) => group.property.Property.Display === currentGroupingDisplay); + if (group?.property?.Property?.ColumnName?.length > 0) { + return group?.property?.Property?.ColumnName; + } + + // search in the list of grouping categories and their groups for the group + const separatorIndex = currentGroupingDisplay.indexOf('\u2063'); + const categoryDisplay = currentGroupingDisplay.substring(0, separatorIndex - 1); + const groupDisplay = currentGroupingDisplay.substring(separatorIndex + 4); + const groupCategory = this.settings?.groupData?.groupingCategories?.find((category) => category.property.Display === categoryDisplay); + group = groupCategory?.groups?.find((group) => group.property.Display === groupDisplay); + return group?.property?.Value; + } + /** * @ignore Used internally * inits the view settings and adds additional columns to the entity schema diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table.component.ts b/imxweb/projects/qbm/src/lib/data-table/data-table.component.ts index aec7afb22..f79cd39dc 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table.component.ts +++ b/imxweb/projects/qbm/src/lib/data-table/data-table.component.ts @@ -575,7 +575,7 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, this.propagateNavigationSettingsToGroups(true); if (groupData.isExpanded) { - this.groupDataChanged.emit({ key: groupingDisplay, isInitial: true }); + this.groupDataChanged.emit({ key: groupingDisplay, isInitial: false }); } } } diff --git a/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.ts b/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.ts index 77c1263fc..52462c5df 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.ts @@ -121,7 +121,7 @@ export class CheckableTreeComponent implements OnChanges, AfterViewInit, OnDestr this.logger.debug(this, `initialize the treeDatasource`); this.treeDataSource = new TreeDatasource(this.treeControl, this.database); this.treeDataSource.emptyNodeCaption = this.emptyNodeCaption; - this.treeDataSource.init(await this.database?.initialize(this.navigationState, !changes['database'].firstChange)); + this.treeDataSource.init(await this.database?.initialize(this.navigationState)); this.subscriptions.push( this.treeDataSource.dataChange.subscribe((elem) => { this.treeRendered.emit(); diff --git a/imxweb/projects/qbm/src/lib/date/date/calendar/calendar.component.ts b/imxweb/projects/qbm/src/lib/date/date/calendar/calendar.component.ts index 5eb1b190d..f0f526ebf 100644 --- a/imxweb/projects/qbm/src/lib/date/date/calendar/calendar.component.ts +++ b/imxweb/projects/qbm/src/lib/date/date/calendar/calendar.component.ts @@ -121,6 +121,7 @@ export class CalendarComponent implements OnInit, AfterViewInit { public onDateChanged(event: MatCalendarUserEvent): void { this.datePickerDate = moment(event.value).clone(); this.control.setValue(this.datePickerDate); + this.close.emit(); } /** diff --git a/imxweb/projects/qbm/src/lib/date/date/date.component.html b/imxweb/projects/qbm/src/lib/date/date/date.component.html index f5ca8bfba..833b15f15 100644 --- a/imxweb/projects/qbm/src/lib/date/date/date.component.html +++ b/imxweb/projects/qbm/src/lib/date/date/date.component.html @@ -30,7 +30,7 @@ > @@ -45,7 +45,7 @@ (overlayOutsideClick)="handleTimePickerOutsideClick($event)" > diff --git a/imxweb/projects/qbm/src/lib/date/date/date.component.ts b/imxweb/projects/qbm/src/lib/date/date/date.component.ts index 8792b24f6..fd7952380 100644 --- a/imxweb/projects/qbm/src/lib/date/date/date.component.ts +++ b/imxweb/projects/qbm/src/lib/date/date/date.component.ts @@ -24,7 +24,7 @@ * */ -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { AbstractControl, UntypedFormControl, ValidationErrors, ValidatorFn, Validators } from '@angular/forms'; import moment, { Moment } from 'moment-timezone'; @@ -115,6 +115,9 @@ export class DateComponent implements OnInit, OnDestroy { @Input() validateOnlyOnChange: boolean = false; + /*Emits an event, when the user changed something in the UI, by closing dialogs or when focus is lost */ + @Output() manuallyChanged: EventEmitter = new EventEmitter(); + /** * @ignore only public because of databinding in template * @@ -150,10 +153,19 @@ export class DateComponent implements OnInit, OnDestroy { */ public shadowTime = new UntypedFormControl(); + /** + * Closes all picker and emits the manually changed event. + */ + public handleClose(): void { + this.isDatePickerOpen = false; + this.isTimePickerOpen = false; + this.manuallyChanged.emit(); + } + /** * @ignore * the result of the internal shadow form control. - * Useful to avoid unecessay update loop when writing back the value to the input control. + * Useful to avoid unnecessary update loop when writing back the value to the input control. */ private result: Moment; @@ -289,6 +301,7 @@ export class DateComponent implements OnInit, OnDestroy { public focusout(): void { this.handleShadowTimeChanged(); + this.manuallyChanged.emit(); } /** diff --git a/imxweb/projects/qbm/src/lib/date/date/time-picker/time-picker.component.ts b/imxweb/projects/qbm/src/lib/date/date/time-picker/time-picker.component.ts index c740d96b6..4565e6ef7 100644 --- a/imxweb/projects/qbm/src/lib/date/date/time-picker/time-picker.component.ts +++ b/imxweb/projects/qbm/src/lib/date/date/time-picker/time-picker.component.ts @@ -59,6 +59,7 @@ export class TimePickerComponent { */ public onValueChange(value: Moment): void { this.control.setValue(value); + this.close.emit(); } /** diff --git a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.spec.ts b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.spec.ts index 2c91b8dc2..b5adf46f3 100644 --- a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.spec.ts +++ b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.spec.ts @@ -44,7 +44,7 @@ const fkInfo = [ { fkRelations: [], expectedMetadataCall: 0 }, { fkRelations: undefined, expectedMetadataCall: 0 }, ].forEach((testcase) => - describe('FkHierarchicalDialogComponent', () => { + xdescribe('FkHierarchicalDialogComponent', () => { let component: FkHierarchicalDialogComponent; let fixture: MockedComponentFixture; diff --git a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.ts b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.ts index d180286b4..e5e6d35c7 100644 --- a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.ts +++ b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.ts @@ -86,8 +86,6 @@ export class FkHierarchicalDialogComponent implements OnInit, OnDestroy { if (data.fkRelations) { this.hierarchyService.fkTable = data.fkRelations.find((fkr) => fkr.TableName === data.selectedTableName) || data.fkRelations[0]; } - - this.filterTree = { filterMethode: async (parent) => this.hierarchyService.fkTable.GetFilterTree(parent) }; } public ngOnDestroy(): void { @@ -95,6 +93,11 @@ export class FkHierarchicalDialogComponent implements OnInit, OnDestroy { } public async ngOnInit(): Promise { + const hasFilterTree = (await this.hierarchyService?.fkTable?.GetFilterTree(''))?.Elements?.length > 0; + if (hasFilterTree) { + this.filterTree = { filterMethode: async (parent) => this.hierarchyService.fkTable.GetFilterTree(parent) }; + } + await this.getPreselectedEntities(); this.filters = (await this.hierarchyService?.fkTable?.GetDataModel())?.Filters; this.tableNames = this.data.fkRelations?.map((elem) => elem.TableName); @@ -118,7 +121,7 @@ export class FkHierarchicalDialogComponent implements OnInit, OnDestroy { if (!this.data.isMultiValue) { this.selectedEntities = [entity]; this.applySelection(); - } + } } public selectedNodesChanged(): void { diff --git a/imxweb/projects/qbm/src/lib/route-guard/route-guard.service.ts b/imxweb/projects/qbm/src/lib/route-guard/route-guard.service.ts index d8d784f83..5404a4e21 100644 --- a/imxweb/projects/qbm/src/lib/route-guard/route-guard.service.ts +++ b/imxweb/projects/qbm/src/lib/route-guard/route-guard.service.ts @@ -24,22 +24,22 @@ * */ -import { Injectable, ErrorHandler } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, CanDeactivate } from '@angular/router'; +import { ErrorHandler, Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, CanDeactivate, Router, RouterStateSnapshot } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; -import { imx_SessionService } from '../session/imx-session.service'; import { AppConfigService } from '../appConfig/appConfig.service'; -import { ComponentCanDeactivate } from './component-can-deactivate.interface'; +import { AuthenticationService } from '../authentication/authentication.service'; import { OAuthService } from '../authentication/oauth.service'; import { QueryParametersHandler } from '../base/query-parameters-handler'; import { ClassloggerService } from '../classlogger/classlogger.service'; -import { AuthenticationService } from '../authentication/authentication.service'; -import { StorageService } from '../storage/storage.service'; import { ConfirmationService } from '../confirmation/confirmation.service'; +import { imx_SessionService } from '../session/imx-session.service'; +import { StorageService } from '../storage/storage.service'; +import { ComponentCanDeactivate } from './component-can-deactivate.interface'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class RouteGuardService implements CanActivate, CanDeactivate { private confirmLeaveTitle = ''; @@ -59,13 +59,13 @@ export class RouteGuardService implements CanActivate, CanDeactivate this.confirmLeaveTitle = value); + translation.get('#LDS#Heading Cancel Editing').subscribe((value: string) => (this.confirmLeaveTitle = value)); - translation.get('#LDS#You have unsaved changes. Are you sure you want to cancel editing and discard your changes?') - .subscribe((value: string) => this.confirmLeaveMessage = value); + translation + .get('#LDS#You have unsaved changes. Are you sure you want to cancel editing and discard your changes?') + .subscribe((value: string) => (this.confirmLeaveMessage = value)); - this.authentication.onSessionResponse.subscribe(sessionState => this.isLoggedIn = sessionState && sessionState.IsLoggedIn); + this.authentication.onSessionResponse.subscribe((sessionState) => (this.isLoggedIn = sessionState && sessionState.IsLoggedIn)); } public async canActivate(route: ActivatedRouteSnapshot, state?: RouterStateSnapshot): Promise { @@ -114,10 +114,13 @@ export class RouteGuardService implements CanActivate, CanDeactivate !this.oauthService.IsOAuthParameter(name)) } - ); + let navigationUrl = this.router.parseUrl(queryParamsHandler.path || this.config.Config.routeConfig.start); + navigationUrl.queryParams = queryParamsHandler.GetQueryParameters((name) => !this.oauthService.IsOAuthParameter(name)) || {}; + this.router.navigateByUrl(navigationUrl); } } catch (error) { this.errorHandler.handleError(error); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/app-routing.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/app-routing.module.ts index 53736d677..ef7147265 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/app-routing.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/app-routing.module.ts @@ -25,37 +25,37 @@ */ import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; +import { RouterModule, Routes } from '@angular/router'; +import { OutstandingComponent } from 'dpr'; import { AuthenticationGuardService, LoginComponent, RouteGuardService } from 'qbm'; -import { ObjectOverviewComponent } from './object-overview/object-overview.component'; -import { JobsComponent } from './processes/jobs/jobs.component'; -import { JournalComponent } from './journal/journal.component'; -import { UnresolvedRefsComponent } from './unresolved-refs/unresolved-refs.component'; +import { DashboardComponent } from './dashboard/dashboard.component'; +import { DataChangesComponent } from './data-changes/data-changes.component'; +import { DbQueueComponent } from './db-queue/db-queue.component'; +import { OutstandingManagerGuardService } from './guards/outstanding-manager-guard.service'; +import { SystemStatusRouteGuardService } from './guards/system-status-route-guard.service'; import { SystemStatusComponent } from './information/system-status/system-status.component'; -import { WebApplicationsComponent } from './web-applications/web-applications.component'; -import { ServiceAvailabilityComponent } from './service-report/service-availability.component'; -import { ServicesInactiveComponent } from './service-report/services-inactive.component'; +import { JournalComponent } from './journal/journal.component'; +import { ObjectOverviewComponent } from './object-overview/object-overview.component'; import { FrozenJobsComponent } from './processes/frozen-jobs/frozen-jobs.component'; import { JobChainsComponent } from './processes/job-chains/job-chains.component'; import { JobHistoryComponent } from './processes/job-history/job-history.component'; import { JobPerformanceComponent } from './processes/job-performance/job-performance.component'; -import { DashboardComponent } from './dashboard/dashboard.component'; +import { JobsComponent } from './processes/jobs/jobs.component'; +import { ObjectsByIdComponent } from './processes/objects-by-id/objects-by-id.component'; +import { ServiceAvailabilityComponent } from './service-report/service-availability.component'; +import { ServicesInactiveComponent } from './service-report/services-inactive.component'; import { SyncInformationComponent } from './sync/sync-information/sync-information.component'; import { SyncJournalComponent } from './sync/sync-journal/sync-journal.component'; -import { OutstandingComponent } from 'dpr'; -import { SystemStatusRouteGuardService } from './guards/system-status-route-guard.service'; -import { OutstandingManagerGuardService } from './guards/outstanding-manager-guard.service'; -import { ObjectsByIdComponent } from './processes/objects-by-id/objects-by-id.component'; -import { DataChangesComponent } from './data-changes/data-changes.component'; -import { DbQueueComponent } from './db-queue/db-queue.component'; +import { UnresolvedRefsComponent } from './unresolved-refs/unresolved-refs.component'; +import { WebApplicationsComponent } from './web-applications/web-applications.component'; const routes: Routes = [ { path: '', component: LoginComponent, canActivate: [AuthenticationGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, { path: 'start', @@ -97,7 +97,7 @@ const routes: Routes = [ { path: 'outstanding', component: OutstandingComponent, - canActivate: [RouteGuardService, OutstandingManagerGuardService], + canActivate: [OutstandingManagerGuardService], resolve: [RouteGuardService], }, { @@ -182,7 +182,7 @@ const routes: Routes = [ path: 'DataChanges', component: DataChangesComponent, canActivate: [RouteGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, { path: 'DbQueue', @@ -190,7 +190,7 @@ const routes: Routes = [ canActivate: [RouteGuardService], resolve: [RouteGuardService], }, - { path: '**', redirectTo: 'start' } + { path: '**', redirectTo: 'start' }, ]; @NgModule({ diff --git a/imxweb/projects/qer-app-operationssupport/src/app/guards/outstanding-manager-guard.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/guards/outstanding-manager-guard.service.ts index 92cec76b9..f56d9f798 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/guards/outstanding-manager-guard.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/guards/outstanding-manager-guard.service.ts @@ -25,10 +25,10 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; +import { AppConfigService, RouteGuardService } from 'qbm'; import { PermissionsService } from '../permissions/permissions.service'; @Injectable({ @@ -39,24 +39,21 @@ export class OutstandingManagerGuardService implements CanActivate, OnDestroy { constructor( private readonly permissionService: PermissionsService, - private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router + private readonly router: Router, + private readonly routeGuardService: RouteGuardService ) {} - public canActivate(): Observable { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const userIsOutstandingManager = await this.permissionService.isOutstandingManager(); - if (!userIsOutstandingManager) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} } ); - } - observer.next(userIsOutstandingManager ? true : false); - observer.complete(); - } - }); - }); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const userIsOutstandingManager = await this.permissionService.isOutstandingManager(); + if (!userIsOutstandingManager) { + this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + } + return userIsOutstandingManager; + } + this.router.navigate([this.appConfig.Config.routeConfig.login]); + return false; } public ngOnDestroy(): void { diff --git a/imxweb/projects/qer-app-portal/src/app/app.component.ts b/imxweb/projects/qer-app-portal/src/app/app.component.ts index 6e5a18f4f..a2f7574bc 100644 --- a/imxweb/projects/qer-app-portal/src/app/app.component.ts +++ b/imxweb/projects/qer-app-portal/src/app/app.component.ts @@ -60,6 +60,7 @@ export class AppComponent implements OnInit, OnDestroy { public showPageContent = true; private routerStatus: EventType; private readonly subscriptions: Subscription[] = []; + private profileSettings: ProfileSettings; constructor( private readonly authentication: AuthenticationService, @@ -99,7 +100,8 @@ export class AppComponent implements OnInit, OnDestroy { const features = (await userModelService.getFeatures()).Features; const systemInfo = await systemInfoService.get(); const groups = (await userModelService.getGroups()).map((group) => group.Name || ''); - const isUseProfileLangChecked = (await this.qerClient.v2Client.portal_profile_get()).UseProfileLanguage ?? false; + this.profileSettings = await this.qerClient.v2Client.portal_profile_get(); + const isUseProfileLangChecked = this.profileSettings.UseProfileLanguage ?? false; // Set session culture if isUseProfileLangChecked is true, set browser culture otherwise if (isUseProfileLangChecked) { await this.translationProvider.init(sessionState.culture, sessionState.cultureFormat); @@ -198,9 +200,8 @@ export class AppComponent implements OnInit, OnDestroy { private async applyProfileSettings() { try { - let profileSettings: ProfileSettings = await this.qerClient.client.portal_profile_get(); - if (profileSettings?.PreferredAppThemes) { - this.themeService.setTheme(profileSettings.PreferredAppThemes); + if (this.profileSettings?.PreferredAppThemes) { + this.themeService.setTheme(this.profileSettings.PreferredAppThemes); } } catch (error) { this.errorHandler.handleError(error); diff --git a/imxweb/projects/qer/src/lib/addressbook/addressbook.service.ts b/imxweb/projects/qer/src/lib/addressbook/addressbook.service.ts index e0cf523a3..85f5b1b77 100644 --- a/imxweb/projects/qer/src/lib/addressbook/addressbook.service.ts +++ b/imxweb/projects/qer/src/lib/addressbook/addressbook.service.ts @@ -49,8 +49,7 @@ export class AddressbookService { displayedColumns.unshift(entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]); return new DataSourceWrapper( - (state, requestOpts, isInitial) => - isInitial ? Promise.resolve({ totalCount: 0, Data: [] }) : this.personService.getAll(state, requestOpts), + (state, requestOpts) => this.personService.getAll(state, requestOpts), displayedColumns, entitySchema, { diff --git a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflows.module.ts b/imxweb/projects/qer/src/lib/approval-workflows/approval-workflows.module.ts index 5c707e540..e81f4a96e 100644 --- a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflows.module.ts +++ b/imxweb/projects/qer/src/lib/approval-workflows/approval-workflows.module.ts @@ -24,8 +24,8 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { RouterModule, Routes } from '@angular/router'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; @@ -36,34 +36,33 @@ import { ClassloggerService, DataSourceToolbarModule, DataTableModule, + HELP_CONTEXTUAL, + HelpContextualModule, + InfoModalDialogModule, LdsReplaceModule, MenuItem, MenuService, - RouteGuardService, - InfoModalDialogModule, SelectedElementsModule, - HELP_CONTEXTUAL, - HelpContextualModule, } from 'qbm'; -import { ShopAdminGuardService } from '../guards/shop-admin-guard.service'; -import { FeatureGuardService } from '../guards/feature-guard.service'; import { hasFeatures, isShopAdmin } from '../admin/qer-permissions-helper'; -import { ApprovalWorkflowHomeComponent } from './approval-workflow-home/approval-workflow-home.component'; +import { FeatureGuardService } from '../guards/feature-guard.service'; +import { ShopAdminGuardService } from '../guards/shop-admin-guard.service'; +import { ApprovalLevelFormComponent } from './approval-level-form/approval-level-form.component'; +import { ApprovalStepFormComponent } from './approval-step-form/approval-step-form.component'; +import { ApprovalWorkflowEditInfoComponent } from './approval-workflow-edit/approval-workflow-edit-info/approval-workflow-edit-info.component'; import { ApprovalWorkflowEditComponent } from './approval-workflow-edit/approval-workflow-edit.component'; import { ContainerDomComponent } from './approval-workflow-edit/container-dom/container-dom.component'; -import { NodeDomComponent } from './approval-workflow-edit/node-dom/node-dom.component'; import { EdgeDomComponent } from './approval-workflow-edit/edge-dom/edge-dom.component'; +import { NodeDomComponent } from './approval-workflow-edit/node-dom/node-dom.component'; import { ApprovalWorkflowFormComponent } from './approval-workflow-form/approval-workflow-form.component'; -import { ApprovalStepFormComponent } from './approval-step-form/approval-step-form.component'; -import { ApprovalLevelFormComponent } from './approval-level-form/approval-level-form.component'; -import { ApprovalWorkflowEditInfoComponent } from './approval-workflow-edit/approval-workflow-edit-info/approval-workflow-edit-info.component'; +import { ApprovalWorkflowHomeComponent } from './approval-workflow-home/approval-workflow-home.component'; const guardedFeatures = ['Portal_Preview_WorkflowEditor']; const routes: Routes = [ { path: 'admin/approvalworkflowmanager', component: ApprovalWorkflowHomeComponent, - canActivate: [RouteGuardService, ShopAdminGuardService, FeatureGuardService], + canActivate: [ShopAdminGuardService, FeatureGuardService], data: { contextId: HELP_CONTEXTUAL.ApprovalWorkflowManager, features: guardedFeatures, diff --git a/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.module.ts b/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.module.ts index bd06fc77e..3561b0399 100644 --- a/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.module.ts +++ b/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.module.ts @@ -32,7 +32,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { MatTooltipModule } from '@angular/material/tooltip'; import { RouteGuardService, SideNavigationViewModule } from 'qbm'; -import { ApplicationGuardService} from '../guards/application-guard.service'; +import { ApplicationGuardService } from '../guards/application-guard.service'; import { DataExplorerGuardService } from '../guards/data-explorer-guard.service'; import { DataExplorerRegistryService } from './data-explorer-registry.service'; import { DataExplorerViewComponent } from './data-explorer-view.component'; @@ -41,21 +41,13 @@ const routes: Routes = [ { path: 'admin/dataexplorer', component: DataExplorerViewComponent, - canActivate: [ - RouteGuardService, - ApplicationGuardService, - DataExplorerGuardService - ], + canActivate: [ApplicationGuardService, DataExplorerGuardService], resolve: [RouteGuardService], }, { path: 'admin/dataexplorer/:tab', component: DataExplorerViewComponent, - canActivate: [ - RouteGuardService, - ApplicationGuardService, - DataExplorerGuardService - ], + canActivate: [ApplicationGuardService, DataExplorerGuardService], resolve: [RouteGuardService], }, ]; diff --git a/imxweb/projects/qer/src/lib/guards/application-guard.service.ts b/imxweb/projects/qer/src/lib/guards/application-guard.service.ts index f83045c5b..fd2247f89 100644 --- a/imxweb/projects/qer/src/lib/guards/application-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/application-guard.service.ts @@ -25,10 +25,10 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState } from "qbm"; +import { AppConfigService, RouteGuardService } from 'qbm'; @Injectable({ providedIn: 'root', @@ -37,24 +37,21 @@ export class ApplicationGuardService implements CanActivate, OnDestroy { private onSessionResponse: Subscription; constructor( - private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + private readonly routeGuardService: RouteGuardService + ) {} - public canActivate(route: ActivatedRouteSnapshot, _: RouterStateSnapshot): Observable { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const isPortal = this.appConfig?.Config?.WebAppIdentifier?.toLocaleLowerCase() === 'portal'; - if (!isPortal) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); - } - observer.next(isPortal ? true : false); - observer.complete(); - } - }); - }); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const isPortal = this.appConfig?.Config?.WebAppIdentifier?.toLocaleLowerCase() === 'portal'; + if (!isPortal) { + this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + } + return isPortal; + } + this.router.navigate([this.appConfig.Config.routeConfig.login]); + return false; } public ngOnDestroy(): void { diff --git a/imxweb/projects/qer/src/lib/guards/data-explorer-guard.service.ts b/imxweb/projects/qer/src/lib/guards/data-explorer-guard.service.ts index 9e0c493c0..a122e73d1 100644 --- a/imxweb/projects/qer/src/lib/guards/data-explorer-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/data-explorer-guard.service.ts @@ -25,10 +25,10 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState, SystemInfoService } from 'qbm'; +import { AppConfigService, AuthenticationService, RouteGuardService, SystemInfoService } from 'qbm'; import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ @@ -42,41 +42,39 @@ export class DataExplorerGuardService implements CanActivate, OnDestroy { private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, private readonly router: Router, - private readonly systemInfoService: SystemInfoService + private readonly systemInfoService: SystemInfoService, + private readonly routeGuardService: RouteGuardService ) {} - public canActivate(): Observable { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const userIsAdmin = await this.qerPermissionService.isPersonAdmin(); - const userIsAuditor = await this.qerPermissionService.isAuditor(); - const userIsResourceAdmin = await this.qerPermissionService.isResourceAdmin(); - const userIsRoleAdmin = await this.qerPermissionService.isRoleAdmin(); - const userIsRoleStatistics = await this.qerPermissionService.isRoleStatistics(); - const userIsStructStatistics = await this.qerPermissionService.isStructStatistics(); - const userIsStructAdmin = await this.qerPermissionService.isStructAdmin(); - const userIsTsbNameSpaceAdminBase = await this.qerPermissionService.isTsbNameSpaceAdminBase(); - const systemInfo = await this.systemInfoService.get(); - const isItShop = systemInfo.PreProps.includes('ITSHOP'); - const isActive = - (isItShop && (userIsAdmin || userIsAuditor)) || - userIsResourceAdmin || - userIsAuditor || - userIsRoleAdmin || - userIsRoleStatistics || - userIsStructStatistics || - userIsStructAdmin || - (isItShop && userIsTsbNameSpaceAdminBase); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const userIsAdmin = await this.qerPermissionService.isPersonAdmin(); + const userIsAuditor = await this.qerPermissionService.isAuditor(); + const userIsResourceAdmin = await this.qerPermissionService.isResourceAdmin(); + const userIsRoleAdmin = await this.qerPermissionService.isRoleAdmin(); + const userIsRoleStatistics = await this.qerPermissionService.isRoleStatistics(); + const userIsStructStatistics = await this.qerPermissionService.isStructStatistics(); + const userIsStructAdmin = await this.qerPermissionService.isStructAdmin(); + const userIsTsbNameSpaceAdminBase = await this.qerPermissionService.isTsbNameSpaceAdminBase(); + const systemInfo = await this.systemInfoService.get(); + const isItShop = systemInfo.PreProps.includes('ITSHOP'); + const isActive = + (isItShop && (userIsAdmin || userIsAuditor)) || + userIsResourceAdmin || + userIsAuditor || + userIsRoleAdmin || + userIsRoleStatistics || + userIsStructStatistics || + userIsStructAdmin || + (isItShop && userIsTsbNameSpaceAdminBase); - if (!isActive) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); - } - observer.next(isActive); - observer.complete(); - } - }); - }); + if (!isActive) { + this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + } + return isActive; + } + this.router.navigate([this.appConfig.Config.routeConfig.login]); + return false; } public ngOnDestroy(): void { diff --git a/imxweb/projects/qer/src/lib/guards/feature-guard.service.ts b/imxweb/projects/qer/src/lib/guards/feature-guard.service.ts index 3cd287be3..7fcb50060 100644 --- a/imxweb/projects/qer/src/lib/guards/feature-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/feature-guard.service.ts @@ -25,11 +25,11 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; -import { Observable, Subscription, of } from 'rxjs'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Subscription } from 'rxjs'; +import { AppConfigService, RouteGuardService } from 'qbm'; import { QerPermissionsService } from '../admin/qer-permissions.service'; -import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @Injectable({ providedIn: 'root', @@ -39,29 +39,21 @@ export class FeatureGuardService implements CanActivate, OnDestroy { constructor( private readonly qerPermissionService: QerPermissionsService, - private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router + private readonly router: Router, + private readonly routeGuardService: RouteGuardService ) {} - public canActivate(route: ActivatedRouteSnapshot): Observable { - if (route?.data?.features) { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const hasFeature = await this.qerPermissionService.hasFeatures(route.data.features); - if (!hasFeature) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); - } - observer.next(hasFeature); - observer.complete(); - } - }); - }); - } else { - // We need either feature or features to guard, return false - return of(false); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const hasFeature = await this.qerPermissionService.hasFeatures(route.data.features); + if (!hasFeature) { + this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + } + return hasFeature; } + this.router.navigate([this.appConfig.Config.routeConfig.login]); + return false; } public ngOnDestroy(): void { diff --git a/imxweb/projects/qer/src/lib/guards/itshop-pattern-guard.service.ts b/imxweb/projects/qer/src/lib/guards/itshop-pattern-guard.service.ts index f7632df3e..5d0ed180d 100644 --- a/imxweb/projects/qer/src/lib/guards/itshop-pattern-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/itshop-pattern-guard.service.ts @@ -25,10 +25,10 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; +import { AppConfigService, RouteGuardService } from 'qbm'; import { ProjectConfigurationService } from '../project-configuration/project-configuration.service'; /** @@ -42,24 +42,21 @@ export class ItshopPatternGuardService implements CanActivate, OnDestroy { constructor( private readonly projectConfig: ProjectConfigurationService, - private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + private readonly routeGuardService: RouteGuardService + ) {} - public canActivate(): Observable { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const isRequestTemplateEnabled = (await this.projectConfig.getConfig()).ITShopConfig.VI_ITShop_ProductSelectionFromTemplate; - if (!isRequestTemplateEnabled) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); - } - observer.next(isRequestTemplateEnabled); - observer.complete(); - } - }); - }); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const isRequestTemplateEnabled = (await this.projectConfig.getConfig()).ITShopConfig.VI_ITShop_ProductSelectionFromTemplate; + if (!isRequestTemplateEnabled) { + this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + } + return isRequestTemplateEnabled; + } + this.router.navigate([this.appConfig.Config.routeConfig.login]); + return false; } public ngOnDestroy(): void { diff --git a/imxweb/projects/qer/src/lib/guards/manager-guard.service.ts b/imxweb/projects/qer/src/lib/guards/manager-guard.service.ts index 6258f9194..1b9b15e22 100644 --- a/imxweb/projects/qer/src/lib/guards/manager-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/manager-guard.service.ts @@ -25,10 +25,10 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; +import { AppConfigService, RouteGuardService } from 'qbm'; import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ @@ -39,24 +39,21 @@ export class ManagerGuardService implements CanActivate, OnDestroy { constructor( private readonly qerPermissionService: QerPermissionsService, - private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + private readonly routeGuardService: RouteGuardService + ) {} - public canActivate(): Observable { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const userIsManager = await this.qerPermissionService.isPersonManager(); - if (!userIsManager) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); - } - observer.next(userIsManager); - observer.complete(); - } - }); - }); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const userIsManager = await this.qerPermissionService.isPersonManager(); + if (!userIsManager) { + this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + } + return userIsManager; + } + this.router.navigate([this.appConfig.Config.routeConfig.login]); + return false; } public ngOnDestroy(): void { diff --git a/imxweb/projects/qer/src/lib/guards/rule-admin-guard.service.ts b/imxweb/projects/qer/src/lib/guards/rule-admin-guard.service.ts index 98f04904d..b0cdaf36d 100644 --- a/imxweb/projects/qer/src/lib/guards/rule-admin-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/rule-admin-guard.service.ts @@ -25,37 +25,34 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; +import { AppConfigService, RouteGuardService } from 'qbm'; import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) -export class RuleAdminGuardService implements CanActivate, OnDestroy{ +export class RuleAdminGuardService implements CanActivate, OnDestroy { private onSessionResponse: Subscription; constructor( private readonly qerPermissionService: QerPermissionsService, - private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + private readonly routeGuardService: RouteGuardService + ) {} - public canActivate(): Observable { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const userIsRuleAdmin = await this.qerPermissionService.isRuleAdmin(); - if (!userIsRuleAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); - } - observer.next(userIsRuleAdmin); - observer.complete(); - } - }); - }); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const userIsRuleAdmin = await this.qerPermissionService.isRuleAdmin(); + if (!userIsRuleAdmin) { + this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + } + return userIsRuleAdmin; + } + this.router.navigate([this.appConfig.Config.routeConfig.login]); + return false; } public ngOnDestroy(): void { diff --git a/imxweb/projects/qer/src/lib/guards/shop-admin-guard.service.ts b/imxweb/projects/qer/src/lib/guards/shop-admin-guard.service.ts index 2182bc734..f32099200 100644 --- a/imxweb/projects/qer/src/lib/guards/shop-admin-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/shop-admin-guard.service.ts @@ -25,10 +25,10 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; +import { AppConfigService, RouteGuardService } from 'qbm'; import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ @@ -39,24 +39,21 @@ export class ShopAdminGuardService implements CanActivate, OnDestroy { constructor( private readonly qerPermissionService: QerPermissionsService, - private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + private readonly routeGuardService: RouteGuardService + ) {} - public canActivate(): Observable { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const userIsShopAdmin = await this.qerPermissionService.isShopAdmin(); - if (!userIsShopAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); - } - observer.next(userIsShopAdmin); - observer.complete(); - } - }); - }); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const userIsShopAdmin = await this.qerPermissionService.isShopAdmin(); + if (!userIsShopAdmin) { + this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + } + return userIsShopAdmin; + } + this.router.navigate([this.appConfig.Config.routeConfig.login]); + return false; } public ngOnDestroy(): void { diff --git a/imxweb/projects/qer/src/lib/guards/shop-guard.service.ts b/imxweb/projects/qer/src/lib/guards/shop-guard.service.ts index cfec1a340..5561f84b1 100644 --- a/imxweb/projects/qer/src/lib/guards/shop-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/shop-guard.service.ts @@ -25,10 +25,10 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; +import { AppConfigService, RouteGuardService } from 'qbm'; import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ @@ -39,25 +39,22 @@ export class ShopGuardService implements CanActivate, OnDestroy { constructor( private readonly qerPermissionService: QerPermissionsService, - private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + private readonly routeGuardService: RouteGuardService + ) {} - public canActivate(): Observable { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const userIsShopStatistics = await this.qerPermissionService.isShopStatistics(); - const userIsShopAdmin = await this.qerPermissionService.isShopAdmin(); - if (!userIsShopStatistics && !userIsShopAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); - } - observer.next(userIsShopStatistics || userIsShopAdmin); - observer.complete(); - } - }); - }); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const userIsShopStatistics = await this.qerPermissionService.isShopStatistics(); + const userIsShopAdmin = await this.qerPermissionService.isShopAdmin(); + if (!userIsShopStatistics && !userIsShopAdmin) { + this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + } + return userIsShopStatistics || userIsShopAdmin; + } + this.router.navigate([this.appConfig.Config.routeConfig.login]); + return false; } public ngOnDestroy(): void { diff --git a/imxweb/projects/qer/src/lib/guards/statistics-guard.service.ts b/imxweb/projects/qer/src/lib/guards/statistics-guard.service.ts index 325dea081..47ec3cea4 100644 --- a/imxweb/projects/qer/src/lib/guards/statistics-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/statistics-guard.service.ts @@ -25,10 +25,10 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; +import { AppConfigService, RouteGuardService } from 'qbm'; import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ @@ -39,24 +39,21 @@ export class StatisticsGuardService implements CanActivate, OnDestroy { constructor( private readonly qerPermissionService: QerPermissionsService, - private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + private readonly routeGuardService: RouteGuardService + ) {} - public canActivate(): Observable { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const userIsStatistics = await this.qerPermissionService.isStatistics(); - if (!userIsStatistics) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); - } - observer.next(userIsStatistics); - observer.complete(); - } - }); - }); + public async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (await this.routeGuardService.canActivate(route, state)) { + const userIsStatistics = await this.qerPermissionService.isStatistics(); + if (!userIsStatistics) { + this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + } + return userIsStatistics; + } + this.router.navigate([this.appConfig.Config.routeConfig.login]); + return false; } public ngOnDestroy(): void { diff --git a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.html b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.html index 2242867bb..b44c51397 100644 --- a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.html +++ b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.html @@ -50,92 +50,97 @@ - -
-
- - {{ '#LDS#This identity will be deleted.' | translate }} - - -
- - {{ '#LDS#Security risk' | translate }} - -
-
-
- - - + + + #LDS#Heading Main Data + + +
+
+ + {{ '#LDS#This identity will be deleted.' | translate }} + - - - +
+ + {{ '#LDS#Security risk' | translate }} +
- - - - - {{ '#LDS#Personal data' | translate }} - - - +
+ - - - - - - {{ '#LDS#Organizational information' | translate }} - - - - - - - - - {{ '#LDS#Location information' | translate }} - - - + + + - - - - -
+ + +
+ + + + + {{ '#LDS#Personal data' | translate }} + + + + + + + + + {{ '#LDS#Organizational information' | translate }} + + + + + + + + + {{ '#LDS#Location information' | translate }} + + + + + + + +
-
+
+ diff --git a/imxweb/projects/qer/src/lib/itshop-config/request-config.module.ts b/imxweb/projects/qer/src/lib/itshop-config/request-config.module.ts index 8fd7f1f6e..66cf83743 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/request-config.module.ts +++ b/imxweb/projects/qer/src/lib/itshop-config/request-config.module.ts @@ -24,8 +24,9 @@ * */ +import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { RouterModule, Routes } from '@angular/router'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; @@ -43,35 +44,34 @@ import { MenuItem, MenuService, RouteGuardService, - SelectedElementsModule + SelectedElementsModule, } from 'qbm'; -import { RequestsComponent } from './requests/requests.component'; -import { RequestConfigSidesheetComponent } from './request-config-sidesheet/request-config-sidesheet.component'; -import { RequestShelfSidesheetComponent } from './request-shelf-sidesheet/request-shelf-sidesheet.component'; -import { RequestShelvesComponent } from './request-shelves/request-shelves.component'; -import { RequestConfigMembersComponent } from './request-config-members/request-config-members.component'; -import { RequestShelfEntitlementsComponent } from './request-shelf-entitlements/request-shelf-entitlements.component'; -import { RequestsEntitySelectorComponent } from './requests-selector/requests-entity-selector.component'; -import { DynamicExclusionDialogModule } from '../dynamic-exclusion-dialog/dynamic-exclusion-dialog.module'; -import { MemberSelectorComponent } from './request-config-members/member-selector/member-selector.component'; import { isShopAdmin, isShopStatistics } from '../admin/qer-permissions-helper'; -import { CREATE_SHELF_TOKEN } from './request-shelves/request-shelf-token'; -import { ObjectHyperviewModule } from '../object-hyperview/object-hyperview.module'; +import { DynamicExclusionDialogModule } from '../dynamic-exclusion-dialog/dynamic-exclusion-dialog.module'; import { ShopGuardService } from '../guards/shop-guard.service'; import { JustificationModule } from '../justification/justification.module'; +import { ObjectHyperviewModule } from '../object-hyperview/object-hyperview.module'; +import { MemberSelectorComponent } from './request-config-members/member-selector/member-selector.component'; import { ReasonSidesheetComponent } from './request-config-members/reason-sidesheet/reason-sidesheet.component'; - +import { RequestConfigMembersComponent } from './request-config-members/request-config-members.component'; +import { RequestConfigSidesheetComponent } from './request-config-sidesheet/request-config-sidesheet.component'; +import { RequestShelfEntitlementsComponent } from './request-shelf-entitlements/request-shelf-entitlements.component'; +import { RequestShelfSidesheetComponent } from './request-shelf-sidesheet/request-shelf-sidesheet.component'; +import { CREATE_SHELF_TOKEN } from './request-shelves/request-shelf-token'; +import { RequestShelvesComponent } from './request-shelves/request-shelves.component'; +import { RequestsEntitySelectorComponent } from './requests-selector/requests-entity-selector.component'; +import { RequestsComponent } from './requests/requests.component'; const routes: Routes = [ { path: 'configuration/requests', component: RequestsComponent, - canActivate: [RouteGuardService, ShopGuardService], + canActivate: [ShopGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.ConfigurationRequests - } + data: { + contextId: HELP_CONTEXTUAL.ConfigurationRequests, + }, }, ]; @@ -85,7 +85,7 @@ const routes: Routes = [ RequestConfigMembersComponent, RequestShelfEntitlementsComponent, RequestsEntitySelectorComponent, - ReasonSidesheetComponent + ReasonSidesheetComponent, ], imports: [ CommonModule, @@ -107,45 +107,37 @@ const routes: Routes = [ RouterModule.forChild(routes), HelpContextualModule, ], - providers: [{provide: CREATE_SHELF_TOKEN, useValue: RequestShelfSidesheetComponent}], + providers: [{ provide: CREATE_SHELF_TOKEN, useValue: RequestShelfSidesheetComponent }], schemas: [CUSTOM_ELEMENTS_SCHEMA], }) export class RequestConfigModule { - - constructor( - private readonly menuService: MenuService, - logger: ClassloggerService) { + constructor(private readonly menuService: MenuService, logger: ClassloggerService) { logger.info(this, '▶︝ RequestConfigModule loaded'); this.setupMenu(); } private setupMenu(): void { - this.menuService.addMenuFactories( - (preProps: string[], features: string[]) => { - - const items: MenuItem[] = []; + this.menuService.addMenuFactories((preProps: string[], features: string[]) => { + const items: MenuItem[] = []; - if (isShopAdmin(features) || isShopStatistics(features)) { - items.push( - { - id: 'QER_Setup_ITShop', - route: 'configuration/requests', - title: '#LDS#Menu Entry Shops', - sorting: '60-20', - }, - ); - } + if (isShopAdmin(features) || isShopStatistics(features)) { + items.push({ + id: 'QER_Setup_ITShop', + route: 'configuration/requests', + title: '#LDS#Menu Entry Shops', + sorting: '60-20', + }); + } - if (items.length === 0) { - return null; - } - return { - id: 'ROOT_Setup', - title: '#LDS#Setup', - sorting: '60', - items - }; - }, - ); + if (items.length === 0) { + return null; + } + return { + id: 'ROOT_Setup', + title: '#LDS#Setup', + sorting: '60', + items, + }; + }); } } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.ts index e8aea0133..06cd20ed3 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.ts @@ -127,7 +127,7 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { } } - public async getData(parameter?: CollectionLoadParameters, isInitialLoad: boolean = false): Promise { + public async getData(parameter?: CollectionLoadParameters): Promise { const isBusy = this.busyService.beginBusy(); try { const filteredState: CollectionLoadParameters = { @@ -145,7 +145,7 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { ...parameter, ...filteredState, }; - const dstSettings = await this.dstWrapper.getDstSettings(parameters, { signal: this.patternService.abortController.signal }, isInitialLoad); + const dstSettings = await this.dstWrapper.getDstSettings(parameters, { signal: this.patternService.abortController.signal }); if (dstSettings) { this.dstSettings = dstSettings; } @@ -159,7 +159,7 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { if (this.selectedTabIndex === 1) { // load data for the product-tab - await this.getData(undefined, true); + await this.getData(undefined); } } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.ts index b111cbeec..374d27b0e 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.ts @@ -126,7 +126,7 @@ export class ItshopPatternComponent implements OnInit, OnDestroy { } finally { isBusy.endBusy(); } - await this.getData(undefined, true); + await this.getData(undefined); } public ngOnDestroy(): void { @@ -172,7 +172,7 @@ export class ItshopPatternComponent implements OnInit, OnDestroy { } } - public async getData(parameter?: CollectionLoadParameters, isInitialLoad: boolean = false): Promise { + public async getData(parameter?: CollectionLoadParameters): Promise { const isBusy = this.busyService.beginBusy(); try { const parameters = { @@ -181,8 +181,7 @@ export class ItshopPatternComponent implements OnInit, OnDestroy { }; const dstSettings = await this.dstWrapper.getDstSettings( parameters, - { signal: this.patternService.abortController.signal }, - isInitialLoad + { signal: this.patternService.abortController.signal } ); if (dstSettings) { this.dstSettings = dstSettings; diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.module.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.module.ts index 1e6fc1785..f56f5cf27 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.module.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.module.ts @@ -45,28 +45,28 @@ import { MenuService, RouteGuardService, SelectedElementsModule, - UserMessageModule + UserMessageModule, } from 'qbm'; -import { ItshopPatternComponent } from './itshop-pattern.component'; -import { ItshopPatternSidesheetComponent } from './itshop-pattern-sidesheet/itshop-pattern-sidesheet.component'; -import { ItshopPatternCreateSidesheetComponent } from './itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component'; -import { ItshopPatternAddProductsComponent } from './itshop-pattern-add-products/itshop-pattern-add-products.component'; +import { ItshopPatternGuardService } from '../guards/itshop-pattern-guard.service'; import { ServiceItemsModule } from '../service-items/service-items.module'; -import { DuplicatePatternItemsComponent } from './duplicate-pattern-items/duplicate-pattern-items.component'; import { UserModule } from '../user/user.module'; -import { ItshopPatternGuardService } from '../guards/itshop-pattern-guard.service'; +import { DuplicatePatternItemsComponent } from './duplicate-pattern-items/duplicate-pattern-items.component'; +import { ItshopPatternAddProductsComponent } from './itshop-pattern-add-products/itshop-pattern-add-products.component'; +import { ItshopPatternCreateSidesheetComponent } from './itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component'; import { ItshopPatternItemEditComponent } from './itshop-pattern-item-edit/itshop-pattern-item-edit.component'; +import { ItshopPatternSidesheetComponent } from './itshop-pattern-sidesheet/itshop-pattern-sidesheet.component'; +import { ItshopPatternComponent } from './itshop-pattern.component'; const routes: Routes = [ { path: 'itshop/requesttemplates', component: ItshopPatternComponent, - canActivate: [RouteGuardService, ItshopPatternGuardService], + canActivate: [ItshopPatternGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.RequestTemplates - } - } + data: { + contextId: HELP_CONTEXTUAL.RequestTemplates, + }, + }, ]; @NgModule({ @@ -76,7 +76,7 @@ const routes: Routes = [ ItshopPatternCreateSidesheetComponent, ItshopPatternAddProductsComponent, DuplicatePatternItemsComponent, - ItshopPatternItemEditComponent + ItshopPatternItemEditComponent, ], imports: [ CdrModule, @@ -94,47 +94,39 @@ const routes: Routes = [ UserModule, SelectedElementsModule, HelpContextualModule, - ] + ], }) export class ItshopPatternModule { - - constructor( - private readonly menuService: MenuService, - logger: ClassloggerService - ) { + constructor(private readonly menuService: MenuService, logger: ClassloggerService) { logger.info(this, '▶️ ItshopPatternModule loaded'); this.setupMenu(); } private setupMenu(): void { - this.menuService.addMenuFactories( - (preProps: string[], features: string[], projectConfig: QerProjectConfig & ProjectConfig) => { - const items: MenuItem[] = []; - const requestTemplatesEnabled = projectConfig.ITShopConfig.VI_ITShop_ProductSelectionFromTemplate; + this.menuService.addMenuFactories((preProps: string[], features: string[], projectConfig: QerProjectConfig & ProjectConfig) => { + const items: MenuItem[] = []; + const requestTemplatesEnabled = projectConfig.ITShopConfig.VI_ITShop_ProductSelectionFromTemplate; - if (preProps.includes('ITSHOP') && requestTemplatesEnabled) { - items.push( - { - id: 'QER_Request_RequestTemplates', - navigationCommands: { - commands: ['itshop', 'requesttemplates'] - }, - title: '#LDS#Menu Entry Product bundles', - sorting: '10-50', - } - ); - } + if (preProps.includes('ITSHOP') && requestTemplatesEnabled) { + items.push({ + id: 'QER_Request_RequestTemplates', + navigationCommands: { + commands: ['itshop', 'requesttemplates'], + }, + title: '#LDS#Menu Entry Product bundles', + sorting: '10-50', + }); + } - if (items.length === 0) { - return null; - } - return { - id: 'ROOT_Request', - title: '#LDS#Requests', - sorting: '10', - items - }; + if (items.length === 0) { + return null; } - ); + return { + id: 'ROOT_Request', + title: '#LDS#Requests', + sorting: '10', + items, + }; + }); } } diff --git a/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.module.ts b/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.module.ts index a883f0786..7446f2c01 100644 --- a/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.module.ts +++ b/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.module.ts @@ -39,13 +39,13 @@ const routes: Routes = [ { path: 'myresponsibilities', component: MyResponsibilitiesViewComponent, - canActivate: [RouteGuardService, ApplicationGuardService], + canActivate: [ApplicationGuardService], resolve: [RouteGuardService], }, { path: 'myresponsibilities/:tab', component: MyResponsibilitiesViewComponent, - canActivate: [RouteGuardService, ApplicationGuardService], + canActivate: [ApplicationGuardService], resolve: [RouteGuardService], }, ]; diff --git a/imxweb/projects/qer/src/lib/new-request/new-request-content/new-request-content.component.ts b/imxweb/projects/qer/src/lib/new-request/new-request-content/new-request-content.component.ts index 0b670e812..4f77547d2 100644 --- a/imxweb/projects/qer/src/lib/new-request/new-request-content/new-request-content.component.ts +++ b/imxweb/projects/qer/src/lib/new-request/new-request-content/new-request-content.component.ts @@ -84,10 +84,7 @@ export class NewRequestContentComponent implements OnInit, OnDestroy { this.subscriptions.push( this.router.events.subscribe((event) => { if (event instanceof NavigationEnd) { - this.orchestration.selectedTab = this.navLinks.find((tab) => `/newrequest/${tab.link}` === this.router.url); - this.orchestration.selectedTab?.component === NewRequestProductComponent - ? (this.showCatSlider = true) - : (this.showCatSlider = false); + this.updateSelectedTab(); } }) ); @@ -138,6 +135,9 @@ export class NewRequestContentComponent implements OnInit, OnDestroy { active: false, }); } + if (!this.selectedTab) { + this.updateSelectedTab(); + } } public ngOnDestroy(): void { @@ -185,4 +185,9 @@ export class NewRequestContentComponent implements OnInit, OnDestroy { public async pushCandidatesToCart(): Promise { this.addToCartService.addItemsToCart(); } + + private updateSelectedTab() { + this.orchestration.selectedTab = this.navLinks.find((tab) => `/newrequest/${tab.link}` === this.router.url); + this.orchestration.selectedTab?.component === NewRequestProductComponent ? (this.showCatSlider = true) : (this.showCatSlider = false); + } } diff --git a/imxweb/projects/qer/src/lib/new-request/new-request-product/new-request-product.component.ts b/imxweb/projects/qer/src/lib/new-request/new-request-product/new-request-product.component.ts index 19cdf2630..358543f12 100644 --- a/imxweb/projects/qer/src/lib/new-request/new-request-product/new-request-product.component.ts +++ b/imxweb/projects/qer/src/lib/new-request/new-request-product/new-request-product.component.ts @@ -351,7 +351,7 @@ export class NewRequestProductComponent implements OnInit, OnDestroy { firstIteration = false; } else { this.dynamicDataSource.setup(true); - this.getProductData(true); + await this.getProductData(true); } }) ); @@ -376,14 +376,14 @@ export class NewRequestProductComponent implements OnInit, OnDestroy { this.orchestration.selectedCategory = node?.entity; // this.orchestration.includeChildCategories = this.includeChildCategories; this.accProductGroup = category.GetKeys()[0]; - this.getProductData(); + await this.getProductData(); } else { // This is the root node and it has no entity this.orchestration.selectedCategory = null; this.includeChildCategories = false; // this.orchestration.includeChildCategories = this.includeChildCategories; this.accProductGroup = null; - this.getProductData(); + await this.getProductData(); } this.orchestration.includeChildCategories = this.includeChildCategories; diff --git a/imxweb/projects/qer/src/lib/profile/profile.component.html b/imxweb/projects/qer/src/lib/profile/profile.component.html index 4082f7bb3..aad21318c 100644 --- a/imxweb/projects/qer/src/lib/profile/profile.component.html +++ b/imxweb/projects/qer/src/lib/profile/profile.component.html @@ -32,32 +32,34 @@

- - -
- - -
-
-
-
- -
+ + + +
+ + +
+
+
+
+ +
+
diff --git a/imxweb/projects/qer/src/lib/request-history/request-history.service.ts b/imxweb/projects/qer/src/lib/request-history/request-history.service.ts index dc45d2f3c..6e8a64665 100644 --- a/imxweb/projects/qer/src/lib/request-history/request-history.service.ts +++ b/imxweb/projects/qer/src/lib/request-history/request-history.service.ts @@ -135,8 +135,11 @@ export class RequestHistoryService { // } // } - public async getFilterOptions(userUid: string, filterPresets: { [name: string]: string } = {}): Promise { - return (await this.getDataModel(userUid)).Filters.map((option: DataSourceToolbarFilter) => { + public async getFilterOptions(userUid: string, filterPresets: { [name: string]: string } = {}, dataModel?: DataModel ): Promise { + if (!dataModel) { + dataModel = await this.getDataModel(userUid); + } + return dataModel.Filters.map((option: DataSourceToolbarFilter) => { option.InitialValue = filterPresets[option.Name]; return option; }); diff --git a/imxweb/projects/qer/src/lib/request-history/request-table.component.ts b/imxweb/projects/qer/src/lib/request-history/request-table.component.ts index 8d34e045d..f66da9683 100644 --- a/imxweb/projects/qer/src/lib/request-history/request-table.component.ts +++ b/imxweb/projects/qer/src/lib/request-history/request-table.component.ts @@ -24,7 +24,7 @@ * */ -import { Component, Input, OnDestroy, OnInit, ViewChild, OnChanges } from '@angular/core'; +import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Params } from '@angular/router'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; @@ -69,7 +69,7 @@ import { ViewConfigService } from '../view-config/view-config.service'; styleUrls: ['./request-table.component.scss'], selector: 'imx-request-table', }) -export class RequestTableComponent implements OnInit, OnDestroy, OnChanges { +export class RequestTableComponent implements OnInit, OnDestroy { public additional: IClientProperty[] = []; public get entitySchema(): EntitySchema { return this.requestHistoryService.PortalItshopRequestsSchema; @@ -187,12 +187,6 @@ export class RequestTableComponent implements OnInit, OnDestroy, OnChanges { ); } - ngOnChanges() { - if (this.uidRecipient) { - this.getData(); - } - } - public async ngOnInit(): Promise { this.displayedColumns = [ this.entitySchema.Columns.DisplayOrg, @@ -211,7 +205,7 @@ export class RequestTableComponent implements OnInit, OnDestroy, OnChanges { this.dataModel = await this.requestHistoryService.getDataModel(this.userUid); this.viewConfig = await this.viewConfigService.getInitialDSTExtension(this.dataModel, this.viewConfigPath); this.activatedRoute.queryParams.subscribe((params) => this.updateFiltersFromRouteParams(params)); - this.filterOptions = await this.requestHistoryService.getFilterOptions(this.userUid, this.filterPresets); + this.filterOptions = await this.requestHistoryService.getFilterOptions(this.userUid, this.filterPresets, this.dataModel); this.itShopConfig = (await this.projectConfig.getConfig()).ITShopConfig; await this.getData(null, true); diff --git a/imxweb/projects/qer/src/lib/requests-feature-guard.service.spec.ts b/imxweb/projects/qer/src/lib/requests-feature-guard.service.spec.ts index 2c7285602..a0589fea7 100644 --- a/imxweb/projects/qer/src/lib/requests-feature-guard.service.spec.ts +++ b/imxweb/projects/qer/src/lib/requests-feature-guard.service.spec.ts @@ -29,6 +29,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { QerApiService } from './qer-api-client.service'; import { RequestsFeatureGuardService } from './requests-feature-guard.service'; import { StartComponent } from './wport/start/start.component'; +import { UserModelService } from './user/user-model.service'; describe('RequestsFeatureGuardService', () => { let service: RequestsFeatureGuardService; @@ -36,7 +37,11 @@ describe('RequestsFeatureGuardService', () => { const sessionServiceStub = { client: { portal_person_config_get: jasmine.createSpy('portal_person_config_get').and.returnValue(Promise.resolve([{}])), - } + }, + }; + + const userServiceStub = { + getUserConfig: jasmine.createSpy('getUserConfig').and.returnValue(Promise.resolve([{}])), }; beforeEach(() => { @@ -45,9 +50,13 @@ describe('RequestsFeatureGuardService', () => { providers: [ { provide: QerApiService, - useValue: sessionServiceStub - } - ] + useValue: sessionServiceStub, + }, + { + provide: UserModelService, + useValue: userServiceStub, + }, + ], }); service = TestBed.inject(RequestsFeatureGuardService); }); diff --git a/imxweb/projects/qer/src/lib/requests-feature-guard.service.ts b/imxweb/projects/qer/src/lib/requests-feature-guard.service.ts index 41b562a91..e30f3eaa2 100644 --- a/imxweb/projects/qer/src/lib/requests-feature-guard.service.ts +++ b/imxweb/projects/qer/src/lib/requests-feature-guard.service.ts @@ -28,6 +28,7 @@ import { Injectable } from '@angular/core'; import { CanActivate, Router } from '@angular/router'; import { UserConfig } from 'imx-api-qer'; import { QerApiService } from './qer-api-client.service'; +import { UserModelService } from './user/user-model.service'; @Injectable({ providedIn: 'root' @@ -36,11 +37,12 @@ export class RequestsFeatureGuardService implements CanActivate { constructor( private qerService: QerApiService, + private readonly userService: UserModelService, private readonly router: Router ) { } public async getUserConfig(): Promise { - return this.qerService.client.portal_person_config_get(); + return this.userService.getUserConfig(); } public async canActivate(): Promise { diff --git a/imxweb/projects/qer/src/lib/resources/resources.component.ts b/imxweb/projects/qer/src/lib/resources/resources.component.ts index 5640688d3..20d70f577 100644 --- a/imxweb/projects/qer/src/lib/resources/resources.component.ts +++ b/imxweb/projects/qer/src/lib/resources/resources.component.ts @@ -118,7 +118,7 @@ export class ResourcesComponent implements OnInit, SideNavigationComponent { } finally { isBusy.endBusy(); } - await this.navigate(true); + await this.navigate(); } public async onNavigationStateChanged(newState?: CollectionLoadParameters): Promise { @@ -180,15 +180,13 @@ export class ResourcesComponent implements OnInit, SideNavigationComponent { }); } - private async navigate(isInitialLoad: boolean = false): Promise { + private async navigate(): Promise { const isBusy = this.busyService.beginBusy(); const exportMethod = this.resourceProvider.getExportMethod(this.tablename, this.isAdmin, this.navigationState); exportMethod.initialColumns = this.displayColumns.map((col) => col.ColumnName); try { this.dstSettings = { - dataSource: isInitialLoad - ? { totalCount: 0, Data: [] } - : await this.resourceProvider.get(this.tablename, this.isAdmin, this.navigationState), + dataSource: await this.resourceProvider.get(this.tablename, this.isAdmin, this.navigationState), entitySchema: this.entitySchema, navigationState: this.navigationState, displayedColumns: this.displayColumns, diff --git a/imxweb/projects/qer/src/lib/risk-config/risk-config.component.ts b/imxweb/projects/qer/src/lib/risk-config/risk-config.component.ts index 7c5d70603..8c6a7f775 100644 --- a/imxweb/projects/qer/src/lib/risk-config/risk-config.component.ts +++ b/imxweb/projects/qer/src/lib/risk-config/risk-config.component.ts @@ -91,13 +91,13 @@ export class RiskConfigComponent implements OnInit { isBusy.endBusy(); } - await this.getData(undefined, true); + await this.getData(undefined); } - public async getData(newState?: CollectionLoadParameters, isInitialLoad: boolean = false): Promise { + public async getData(newState?: CollectionLoadParameters): Promise { const isBusy = this.busyService.beginBusy(); try { - this.dstSettings = await this.dstWrapper.getDstSettings(newState, undefined, isInitialLoad); + this.dstSettings = await this.dstWrapper.getDstSettings(newState, undefined); } finally { isBusy.endBusy(); } diff --git a/imxweb/projects/qer/src/lib/risk-config/risk-config.module.ts b/imxweb/projects/qer/src/lib/risk-config/risk-config.module.ts index 080d8af77..6912276e1 100644 --- a/imxweb/projects/qer/src/lib/risk-config/risk-config.module.ts +++ b/imxweb/projects/qer/src/lib/risk-config/risk-config.module.ts @@ -24,40 +24,39 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; import { + CdrModule, ClassloggerService, + DataSourceToolbarModule, + DataTableModule, + HELP_CONTEXTUAL, + HelpContextualModule, MenuItem, MenuService, - RouteGuardService, - DataSourceToolbarModule, DataTableModule, CdrModule, HELP_CONTEXTUAL, HelpContextualModule } from 'qbm'; import { isRuleAdmin } from '../admin/qer-permissions-helper'; -import { RiskConfigComponent } from './risk-config.component'; -import { RouterModule, Routes } from '@angular/router'; -import { TranslateModule } from '@ngx-translate/core'; -import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; -import { RiskConfigSidesheetComponent } from './risk-config-sidesheet/risk-config-sidesheet.component'; -import { ReactiveFormsModule } from '@angular/forms'; import { RuleAdminGuardService } from '../guards/rule-admin-guard.service'; +import { RiskConfigSidesheetComponent } from './risk-config-sidesheet/risk-config-sidesheet.component'; +import { RiskConfigComponent } from './risk-config.component'; const routes: Routes = [ { path: 'configuration/risk', component: RiskConfigComponent, - canActivate: [RouteGuardService, RuleAdminGuardService], - data:{ - contextId: HELP_CONTEXTUAL.ConfigurationRisk - } + canActivate: [RuleAdminGuardService], + data: { + contextId: HELP_CONTEXTUAL.ConfigurationRisk, + }, }, ]; - @NgModule({ - declarations: [ - RiskConfigComponent, - RiskConfigSidesheetComponent - ], + declarations: [RiskConfigComponent, RiskConfigSidesheetComponent], imports: [ CommonModule, TranslateModule, @@ -70,46 +69,36 @@ const routes: Routes = [ ReactiveFormsModule, HelpContextualModule, ], - exports: [ - RiskConfigComponent - ] + exports: [RiskConfigComponent], }) export class RiskConfigModule { - constructor( - private readonly menuService: MenuService, - logger: ClassloggerService) { + constructor(private readonly menuService: MenuService, logger: ClassloggerService) { logger.info(this, '▶️ RiskConfigModule loaded'); this.setupMenu(); } private setupMenu(): void { - this.menuService.addMenuFactories( - (preProps: string[], features: string[]) => { + this.menuService.addMenuFactories((preProps: string[], features: string[]) => { + const items: MenuItem[] = []; - const items: MenuItem[] = []; + if (isRuleAdmin(features) && preProps.includes('RISKINDEX')) { + items.push({ + id: 'QER_Setup_RiskConfig', + route: 'configuration/risk', + title: '#LDS#Menu Entry Risk index functions', + sorting: '50-50', + }); + } - if (isRuleAdmin(features) && preProps.includes('RISKINDEX')) { - items.push( - { - id: 'QER_Setup_RiskConfig', - route: 'configuration/risk', - title: '#LDS#Menu Entry Risk index functions', - sorting: '50-50', - }, - ); - } - - if (items.length === 0) { - return null; - } - return { - id: 'ROOT_Setup', - title: '#LDS#Setup', - sorting: '50', - items - }; - }, - ); + if (items.length === 0) { + return null; + } + return { + id: 'ROOT_Setup', + title: '#LDS#Setup', + sorting: '50', + items, + }; + }); } - - } +} diff --git a/imxweb/projects/qer/src/lib/role-management/memberships-choose-identities/memberships-choose-identities.component.ts b/imxweb/projects/qer/src/lib/role-management/memberships-choose-identities/memberships-choose-identities.component.ts index 7cea8ae4e..516b82c71 100644 --- a/imxweb/projects/qer/src/lib/role-management/memberships-choose-identities/memberships-choose-identities.component.ts +++ b/imxweb/projects/qer/src/lib/role-management/memberships-choose-identities/memberships-choose-identities.component.ts @@ -33,11 +33,11 @@ import { ViewConfigData } from 'imx-api-qer'; import { CollectionLoadParameters, DataModel, DisplayColumns, EntitySchema, IClientProperty, TypedEntity, XOrigin } from 'imx-qbm-dbts'; import { AuthenticationService, - buildAdditionalElementsString, DataSourceToolbarSettings, DataSourceToolbarViewConfig, ISessionState, SnackBarService, + buildAdditionalElementsString, } from 'qbm'; import { UserModelService } from '../../user/user-model.service'; import { ViewConfigService } from '../../view-config/view-config.service'; @@ -89,7 +89,7 @@ export class MembershipsChooseIdentitiesComponent implements OnInit { try { this.dataModel = await this.roleService.getCandidatesDataModel(this.dataManagementService.entityInteractive.GetEntity().GetKeys()[0]); this.viewConfig = await this.viewConfigService.getInitialDSTExtension(this.dataModel, this.viewConfigPath); - this.candidatesEntitySchema = this.roleService.getMembershipEntitySchema('candidates'); + this.candidatesEntitySchema = this.roleService.getMembershipEntitySchema(); } finally { setTimeout(() => this.busyService.hide(overlayRef)); } @@ -178,8 +178,9 @@ export class MembershipsChooseIdentitiesComponent implements OnInit { ? { totalCount: 0, Data: [] } : await this.roleService.getCandidates(this.dataManagementService.entityInteractive.GetEntity().GetKeys().join(','), { ...this.navigationState, + // TODO: #458415 The api cannot handle this nav param anymore. Needs to be fixed. // exclude candidate identities that already have an assignment request (XOrigin.Ordered) - xorigin: XOrigin.Ordered, + // xorigin: XOrigin.Ordered, }), entitySchema: this.candidatesEntitySchema, navigationState: this.navigationState, diff --git a/imxweb/projects/qer/src/lib/role-management/role-entitlements/entitlement-handlers.ts b/imxweb/projects/qer/src/lib/role-management/role-entitlements/entitlement-handlers.ts index 73044f1cc..d39a60792 100644 --- a/imxweb/projects/qer/src/lib/role-management/role-entitlements/entitlement-handlers.ts +++ b/imxweb/projects/qer/src/lib/role-management/role-entitlements/entitlement-handlers.ts @@ -32,18 +32,19 @@ import { QerApiService } from '../../qer-api-client.service'; export interface IRoleEntitlements { getCollection(id: string, navigationState?: CollectionLoadParameters, objectKeyForFiltering?: string): Promise>; - getEntitlementTypes(role: IEntity): Promise; + getEntitlementTypes(role?: IEntity): Promise; - createEntitlementAssignmentEntity(role: IEntity, entlType: RoleAssignmentData): IEntity; + createEntitlementAssignmentEntity(role: IEntity, entlType?: RoleAssignmentData): IEntity; - getEntitlementFkName(): string; + entitlementFkName: string; /** Removes a single entitlement assignment from the role. */ delete(roleId: string, entity: IEntity): Promise; } export class BaseTreeEntitlement implements IRoleEntitlements { - public readonly schemaPaths: Map = new Map(); + public entitlementFkName = 'ObjectKeyElement'; // column name in QERVBaseTreeHasElement + private basePath = 'portal/roles/config/entitlements'; // hard coded as there is no delete/creation method in the client constructor( protected readonly api: QerApiService, @@ -51,28 +52,18 @@ export class BaseTreeEntitlement implements IRoleEntitlements { private readonly dynamicMethodSvc: DynamicMethodService, protected readonly translator: ImxTranslationProviderService, private readonly roletype: string, - public uidOrgRoot: (e: IEntity) => string - ) { - this.schemaPaths.set('get', `portal/roles/entitlements/{roletype}/{uidrole}`); - } + public uidOrgRoot: (e: IEntity) => string, + ) {} public getEntitlementTypes(role: IEntity) { return this.api.client.portal_roles_config_classes_get(this.uidOrgRoot(role)); } - public getEntitlementFkName() { - return 'ObjectKeyElement'; // column name in QERVBaseTreeHasElement - } - public async delete(id: string, entity: IEntity): Promise { - const key = DbObjectKey.FromXml(entity.GetColumn('ObjectKeyElement').GetValue()); + const key = DbObjectKey.FromXml(entity.GetColumn(this.entitlementFkName).GetValue()); const entlType = key.TableName; const uidEntitlement = key.Keys[0]; - await this.dynamicMethodSvc.delete( - this.api.apiClient, - `/portal/roles/config/entitlements/${this.roletype}/${id}/${entlType}/${uidEntitlement}`, - {} - ); + await this.dynamicMethodSvc.delete(this.api.apiClient, `/${this.basePath}/${this.roletype}/${id}/${entlType}/${uidEntitlement}`, {}); } public async getCollection( @@ -80,20 +71,12 @@ export class BaseTreeEntitlement implements IRoleEntitlements { navigationState?: CollectionLoadParameters, objectKeyForFiltering?: string ): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('get'), - `/portal/roles/entitlements/${this.roletype}/${id}`, - this.api.apiClient, - this.session, - this.translator - ); - - return await api.Get({ + return this.api.typedClient.PortalRolesEntitlements.Get(this.roletype, id, { ...navigationState, filter: objectKeyForFiltering ? [ { - ColumnName: 'ObjectKeyElement', + ColumnName: this.entitlementFkName, CompareOp: CompareOperator.Equal, Type: FilterType.Compare, Value1: objectKeyForFiltering, @@ -104,15 +87,16 @@ export class BaseTreeEntitlement implements IRoleEntitlements { } public createEntitlementAssignmentEntity(role: IEntity, entlType: RoleAssignmentData): IEntity { - const initialData = {}; const uidRole = role.GetKeys()[0]; - initialData[entlType.RoleFk] = { Value: uidRole }; + const initialData = { + [entlType.RoleFk]: { Value: uidRole }, + }; const entityColl = this.dynamicMethodSvc.createEntity( this.api.apiClient, { - path: '/portal/roles/config/entitlements/' + entlType.RoleTable + '/' + uidRole + '/' + entlType.TableName, + path: `/${this.basePath}/${entlType.RoleTable}/${uidRole}/${entlType.TableName}`, type: GenericTypedEntity, - schemaPath: 'portal/roles/config/entitlements/' + entlType.RoleTable + '/{' + entlType.RoleFk + '}/' + entlType.TableName, + schemaPath: `${this.basePath}/${entlType.RoleTable}/{${entlType.RoleFk}}/${entlType.TableName}`, }, { Columns: initialData, diff --git a/imxweb/projects/qer/src/lib/role-management/role-entitlements/entitlement-selector.component.ts b/imxweb/projects/qer/src/lib/role-management/role-entitlements/entitlement-selector.component.ts index 05fe1c3cf..cbd2f0439 100644 --- a/imxweb/projects/qer/src/lib/role-management/role-entitlements/entitlement-selector.component.ts +++ b/imxweb/projects/qer/src/lib/role-management/role-entitlements/entitlement-selector.component.ts @@ -64,7 +64,8 @@ export class EntitlementSelectorComponent { roleEntity: IEntity } ) { - this.ReinitData(); + // Choose first element, otherwise only init + this.sidesheetData?.entitlementTypes?.[0] ? this.optionSelected(this.sidesheetData.entitlementTypes[0]) : this.reinitData(); } public get types(): RoleAssignmentData[] { @@ -79,10 +80,10 @@ export class EntitlementSelectorComponent { this.selectedType = newType; this.fkEntity = this.roleService.createEntitlementAssignmentEntity(this.sidesheetData.roleEntity, newType); this.fk = this.fkEntity.GetFkCandidateProvider().getProviderItem(newType.EntitlementFk, newType.TableName); - this.ReinitData(); + this.reinitData(); this.selectedItems = []; - this.fkCandidatesComponent.clearSelection(); - this.fkCandidatesComponent.clearTreeFilter(); + this.fkCandidatesComponent?.clearSelection(); + this.fkCandidatesComponent?.clearTreeFilter(); } @@ -109,7 +110,7 @@ export class EntitlementSelectorComponent { /** * Sets the data object to trigger the changes event on the Fk candidate selector */ - private ReinitData(): void { + private reinitData(): void { this.data = { get: parameters => { if (!this.fk) { diff --git a/imxweb/projects/qer/src/lib/role-management/role-memberships/membership-handlers.ts b/imxweb/projects/qer/src/lib/role-management/role-memberships/membership-handlers.ts index fcfc4431b..cecb48a8c 100644 --- a/imxweb/projects/qer/src/lib/role-management/role-memberships/membership-handlers.ts +++ b/imxweb/projects/qer/src/lib/role-management/role-memberships/membership-handlers.ts @@ -30,6 +30,7 @@ import { EntityCollectionData, EntitySchema, ExtendedTypedEntityCollection, + FkCandidateRouteDto, IEntity, TypedEntity, XOrigin @@ -53,7 +54,7 @@ export interface IRoleMembershipType { delete(role: string, identity: string): Promise; - getSchema(key: string): EntitySchema; + GetSchema(): EntitySchema; GetUidRole(entity: IEntity): string; @@ -74,33 +75,68 @@ type CandidateParameters = CollectionLoadParameters & { xorigin?: XOrigin }; export abstract class BaseMembership implements IRoleMembershipType { public supportsDynamicMemberships = true; - protected readonly schemaPaths: Map = new Map(); - protected basePath = ''; + declare fkCandidateRoute: FkCandidateRouteDto; + declare basePath: string; + declare columnName: string; + declare dynamicRoleUrl: string; constructor( - protected readonly session: imx_SessionService - ) { } + private readonly _api: any, + private _session: imx_SessionService, + private readonly _translator: ImxTranslationProviderService, + ) {} - public abstract get(id: string, navigationState?: CollectionLoadParameters): Promise>; + public setRoleName(role: string, columnName: string): void { + this.basePath = `portal/roles/config/membership/${role}`; //hard coded as almost all of the candidate roles exist only as fk urls + this.columnName = columnName; + this.dynamicRoleUrl = `${this.basePath}/{${columnName}}`; + this.getFkRoute(); + } - public abstract getCandidates( - id: string, - navigationState?: CandidateParameters - ): Promise>; + private getFkRoute(): void { + this.fkCandidateRoute = this.GetSchema().FkCandidateRoutes.find((route) => route.ColumnName === 'UID_Person'); + } - public abstract getCandidatesDataModel(id: string): Promise; + public GetSchema(url?: string): EntitySchema { + return this._api.client.getSchema(url ? url : this.dynamicRoleUrl); + } - public abstract delete(role: string, identity: string): Promise; + public async get(id: string, navigationState?: CollectionLoadParameters): Promise> { + const api = new DynamicMethod(this.dynamicRoleUrl, `/${this.basePath}/${id}`, this._api.apiClient, this._session, this._translator); + return api.Get(navigationState); + } - public getSchema(key: string): EntitySchema { - return this.session.Client.getSchema(this.schemaPaths.get(key)); + public async getCandidates( + id: string, + navigationState?: CandidateParameters, + ): Promise> { + + const schemaPath =( this.fkCandidateRoute?.Url?.[0] === '/' ? this.fkCandidateRoute.Url.substring(1) : this.fkCandidateRoute.Url); + const api = new DynamicMethod(schemaPath, (this.fkCandidateRoute?.Url), this._api.apiClient, this._session, this._translator); + if (this.fkCandidateRoute?.HttpMethod === 'GET') { + return api.Get(navigationState); + } + + const state = {}; + state[this.columnName] = id; + return api.Post(state, navigationState ?? {}); } + public async getCandidatesDataModel(): Promise { + const schemaPath = this.fkCandidateRoute?.Url?.[0] === '/' ? this.fkCandidateRoute.Url.substring(1) : this.fkCandidateRoute.Url; + const api = new DynamicMethod(schemaPath, this.fkCandidateRoute?.Url, this._api.apiClient, this._session, this._translator); + return api.getDataModei(); + } + + public abstract delete(role: string, identity: string): Promise; + public GetUidPerson(entity: IEntity): string { return entity.GetColumn('UID_Person').GetValue(); } - public abstract GetUidRole(entity: IEntity): string; + public GetUidRole(entity: IEntity): string { + return entity.GetColumn(this.columnName).GetValue(); + } /** Returns a flag indicating whether primary memberships * are possible for this role type. @@ -119,52 +155,12 @@ export abstract class BaseMembership implements IRoleMembershipType { // tslint:disable-next-line: max-classes-per-file export class LocalityMembership extends BaseMembership { constructor( - private readonly api: QerApiService, - session: imx_SessionService, - private readonly translator: ImxTranslationProviderService + private api: QerApiService, + private session: imx_SessionService, + private translator: ImxTranslationProviderService, ) { - super(session); - this.basePath = 'portal/roles/config/membership/Locality'; - this.schemaPaths.set('get', `${this.basePath}/{UID_Locality}`); - this.schemaPaths.set('candidates', `${this.basePath}/{UID_Locality}/UID_Person/candidates`); - } - - public async get(id: string, navigationState?: CollectionLoadParameters): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('get'), - `/portal/roles/config/membership/Locality/${id}`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); - } - - public async getCandidates( - id: string, - navigationState?: CandidateParameters - ): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); - } - - public async getCandidatesDataModel(id: string): Promise { - const dynamicMethod = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - return dynamicMethod.getDataModei(); + super(api, session, translator); + this.setRoleName('Locality', 'UID_Locality'); } public async delete(role: string, identity: string): Promise { @@ -175,11 +171,6 @@ export class LocalityMembership extends BaseMembership { return true; } - - public GetUidRole(entity: IEntity): string { - return entity.GetColumn("UID_Locality").GetValue(); - } - public getPrimaryMembers( uid: string, navigationstate: CollectionLoadParameters @@ -196,52 +187,12 @@ export class LocalityMembership extends BaseMembership { // tslint:disable-next-line: max-classes-per-file export class ProfitCenterMembership extends BaseMembership { constructor( - private readonly api: QerApiService, - session: imx_SessionService, - private readonly translator: ImxTranslationProviderService + private api: QerApiService, + private session: imx_SessionService, + private translator: ImxTranslationProviderService, ) { - super(session); - this.basePath = 'portal/roles/config/membership/ProfitCenter'; - this.schemaPaths.set('get', `${this.basePath}/{UID_ProfitCenter}`); - this.schemaPaths.set('candidates', `${this.basePath}/{UID_ProfitCenter}/UID_Person/candidates`); - } - - public async get(id: string, navigationState?: CollectionLoadParameters): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('get'), - `/${this.basePath}/${id}`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); - } - - public async getCandidates( - id: string, - navigationState?: CandidateParameters - ): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); - } - - public async getCandidatesDataModel(id: string): Promise { - const dynamicMethod = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - return dynamicMethod.getDataModei(); + super(api, session, translator); + this.setRoleName('ProfitCenter', 'UID_ProfitCenter'); } public async delete(role: string, identity: string): Promise { @@ -252,9 +203,6 @@ export class ProfitCenterMembership extends BaseMembership { return true; } - public GetUidRole(entity: IEntity): string { - return entity.GetColumn("UID_ProfitCenter").GetValue(); - } public getPrimaryMembers(uid: string, navigationstate: CollectionLoadParameters): Promise> { return this.api.typedClient.PortalRolesConfigProfitcenterPrimarymembers.Get(uid, navigationstate); @@ -268,51 +216,12 @@ export class ProfitCenterMembership extends BaseMembership { // tslint:disable-next-line: max-classes-per-file export class DepartmentMembership extends BaseMembership { constructor( - private readonly api: QerApiService, - session: imx_SessionService, - private readonly translator: ImxTranslationProviderService + private api: QerApiService, + private session: imx_SessionService, + private translator: ImxTranslationProviderService, ) { - super(session); - this.basePath = 'portal/roles/config/membership/Department'; - this.schemaPaths.set('get', `${this.basePath}/{UID_Department}`); - this.schemaPaths.set('candidates', `${this.basePath}/{UID_Department}/UID_Person/candidates`); - } - public async get(id: string, navigationState?: CollectionLoadParameters): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('get'), - `/${this.basePath}/${id}`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); - } - - public async getCandidates( - id: string, - navigationState?: CandidateParameters - ): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); - } - - public async getCandidatesDataModel(id: string): Promise { - const dynamicMethod = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - return dynamicMethod.getDataModei(); + super(api, session, translator); + this.setRoleName('Department', 'UID_Department'); } public async delete(role: string, identity: string): Promise { @@ -340,64 +249,22 @@ export class DepartmentMembership extends BaseMembership { // tslint:disable-next-line: max-classes-per-file export class AERoleMembership extends BaseMembership { constructor( - private readonly api: QerApiService, - session: imx_SessionService, - private readonly translator: ImxTranslationProviderService + private api: QerApiService, + private session: imx_SessionService, + private translator: ImxTranslationProviderService, ) { - super(session); - this.basePath = 'portal/roles/config/membership/AERole'; - this.schemaPaths.set('get', `${this.basePath}/{UID_AERole}`); - this.schemaPaths.set('candidates', `${this.basePath}/{UID_AERole}/UID_Person/candidates`); - } - public async get(id: string, navigationState?: CollectionLoadParameters): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('get'), - `/${this.basePath}/${id}`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); + super(api, session, translator); + this.setRoleName('AERole', 'UID_AERole'); } public async delete(role: string, identity: string): Promise { return this.api.client.portal_roles_config_membership_AERole_delete(role, identity); } - public async getCandidates( - id: string, - navigationState?: CandidateParameters - ): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); - } - - public async getCandidatesDataModel(id: string): Promise { - const dynamicMethod = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - return dynamicMethod.getDataModei(); - } - public hasPrimaryMemberships(): boolean { return false; } - public GetUidRole(entity: IEntity): string { - return entity.GetColumn("UID_AERole").GetValue(); - } public getPrimaryMembers(): Promise> { throw new Error('Application roles do not allow primary memberships.'); diff --git a/imxweb/projects/qer/src/lib/role-management/role-memberships/secondary-memberships.component.ts b/imxweb/projects/qer/src/lib/role-management/role-memberships/secondary-memberships.component.ts index 6a087fc99..9a0c3b408 100644 --- a/imxweb/projects/qer/src/lib/role-management/role-memberships/secondary-memberships.component.ts +++ b/imxweb/projects/qer/src/lib/role-management/role-memberships/secondary-memberships.component.ts @@ -32,8 +32,7 @@ import { TranslateService } from '@ngx-translate/core'; import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty, TypedEntity, XOrigin } from 'imx-qbm-dbts'; import { ConfirmationService, DataSourceItemStatus, DataSourceToolbarSettings, DataTableComponent, SnackBarService } from 'qbm'; -import { SourceDetectiveSidesheetData } from '../../sourcedetective/sourcedetective-sidesheet.component'; -import { SourceDetectiveSidesheetComponent } from '../../sourcedetective/sourcedetective-sidesheet.component'; +import { SourceDetectiveSidesheetComponent, SourceDetectiveSidesheetData } from '../../sourcedetective/sourcedetective-sidesheet.component'; import { SourceDetectiveType } from '../../sourcedetective/sourcedetective-type.enum'; import { DataManagementService } from '../data-management.service'; import { MembershipsChooseIdentitiesComponent } from '../memberships-choose-identities/memberships-choose-identities.component'; @@ -85,7 +84,7 @@ export class SecondaryMembershipsComponent implements OnInit { } public async ngOnInit(): Promise { - this.entitySchema = this.roleService.getMembershipEntitySchema('get'); + this.entitySchema = this.roleService.getMembershipEntitySchema(); this.displayColumns = [ this.entitySchema.Columns.UID_Person, this.entitySchema.Columns.XDateInserted, diff --git a/imxweb/projects/qer/src/lib/role-management/role.service.ts b/imxweb/projects/qer/src/lib/role-management/role.service.ts index 999915fb0..72f8eb7dc 100644 --- a/imxweb/projects/qer/src/lib/role-management/role.service.ts +++ b/imxweb/projects/qer/src/lib/role-management/role.service.ts @@ -57,13 +57,13 @@ import { WriteExtTypedEntity, XOrigin, } from 'imx-qbm-dbts'; -import { AERoleMembership, DepartmentMembership, LocalityMembership, ProfitCenterMembership } from './role-memberships/membership-handlers'; import { ProjectConfigurationService } from '../project-configuration/project-configuration.service'; import { QerApiService } from '../qer-api-client.service'; -import { RoleObjectInfo, RoleTranslateKeys } from './role-object-info'; -import { DataSourceToolbarExportMethod, DynamicMethodService, ImxTranslationProviderService, imx_SessionService } from 'qbm'; -import { BaseTreeEntitlement } from './role-entitlements/entitlement-handlers'; import { BaseTreeRoleRestoreHandler } from './restore/restore-handler'; +import { BaseTreeEntitlement } from './role-entitlements/entitlement-handlers'; +import { AERoleMembership, DepartmentMembership, LocalityMembership, ProfitCenterMembership } from './role-memberships/membership-handlers'; +import { RoleObjectInfo, RoleTranslateKeys } from './role-object-info'; +import { DataSourceToolbarExportMethod, DynamicMethodService, imx_SessionService, ImxTranslationProviderService } from 'qbm'; export const RoleManagementLocalityTag = 'Locality'; export const RoleManagementProfitCenterTag = 'ProfitCenter'; @@ -251,7 +251,7 @@ export class RoleService { ); // Role Membership Objects - this.targetMap.get(this.LocalityTag).membership = new LocalityMembership(this.api, session, this.translator); + this.targetMap.get(this.LocalityTag).membership = new LocalityMembership(this.api, this.session, this.translator); this.targetMap.get(this.ProfitCenterTag).membership = new ProfitCenterMembership(this.api, this.session, this.translator); this.targetMap.get(this.DepartmentTag).membership = new DepartmentMembership(this.api, this.session, this.translator); this.targetMap.get(this.AERoleTag).membership = new AERoleMembership(this.api, this.session, this.translator); @@ -482,9 +482,8 @@ export class RoleService { return isAdmin ? this.targetMap.get(tableName).interactiveAdmin.GetSchema() : this.targetMap.get(tableName).interactiveResp.GetSchema(); } - public getMembershipEntitySchema(key: string): EntitySchema { - const membership = this.targetMap.get(this.ownershipInfo.TableName).membership; - return membership.getSchema(key); + public getMembershipEntitySchema(): EntitySchema { + return this.targetMap.get(this.ownershipInfo.TableName).membership.GetSchema(); } public async getDataModel(tableName: string, isAdmin: boolean): Promise { @@ -493,9 +492,10 @@ export class RoleService { } public canCreate(tableName: string, isAdmin: boolean, userCanCreateAeRole: boolean): boolean { - if (tableName === this.AERoleTag && !userCanCreateAeRole) { // special case, that the user can't create application roles at all + if (tableName === this.AERoleTag && !userCanCreateAeRole) { + // special case, that the user can't create application roles at all return false; - } + } return isAdmin ? this.targetMap.get(tableName)?.adminCanCreate : this.targetMap.get(tableName).respCanCreate; } @@ -656,7 +656,7 @@ export class RoleService { } public getEntitlementFkName(): string { - return this.targetMap.get(this.ownershipInfo.TableName).entitlements.getEntitlementFkName(); + return this.targetMap.get(this.ownershipInfo.TableName).entitlements.entitlementFkName; } private async getEntities(tableName: string, navigationState: CollectionLoadParameters): Promise> { diff --git a/imxweb/projects/qer/src/lib/role-management/roles-overview/roles-overview.component.ts b/imxweb/projects/qer/src/lib/role-management/roles-overview/roles-overview.component.ts index 23659f985..afa38fa36 100644 --- a/imxweb/projects/qer/src/lib/role-management/roles-overview/roles-overview.component.ts +++ b/imxweb/projects/qer/src/lib/role-management/roles-overview/roles-overview.component.ts @@ -179,7 +179,7 @@ export class RolesOverviewComponent implements OnInit, OnDestroy, SideNavigation } finally { isBusy.endBusy(); } - await this.navigate(true); + await this.navigate(); } public async onNavigationStateChanged(newState?: CollectionLoadParameters): Promise { @@ -321,32 +321,27 @@ export class RolesOverviewComponent implements OnInit, OnDestroy, SideNavigation } } - private async navigate(isInitialLoad: boolean = false): Promise { + private async navigate(): Promise { const isBusy = this.busyService.beginBusy(); try { - this.useTree ? await this.navigateInTree(isInitialLoad) : await this.navigateWithTable(isInitialLoad); + this.useTree ? await this.navigateInTree() : await this.navigateWithTable(); } finally { isBusy.endBusy(); } } - private async navigateInTree(isInitialLoad: boolean): Promise { - if (isInitialLoad) { - return; - } + private async navigateInTree(): Promise { await this.treeDatabase.prepare(this.roleService.getRoleEntitySchema(this.ownershipInfo.TableName), true); } - private async navigateWithTable(isInitialLoad: boolean): Promise { + private async navigateWithTable(): Promise { if (this.dataModel) { this.exportMethod = this.roleService.getExportMethod(this.ownershipInfo.TableName, this.isAdmin, this.navigationState); } if (this.exportMethod) { this.exportMethod.initialColumns = this.displayColumns.map((col) => col.ColumnName); } - const dataSource = isInitialLoad - ? { totalCount: 0, Data: [] } - : await this.roleService.get(this.ownershipInfo.TableName, this.isAdmin, this.navigationState); + const dataSource = await this.roleService.get(this.ownershipInfo.TableName, this.isAdmin, this.navigationState); if (dataSource) { this.dstSettings = { dataSource: dataSource, diff --git a/imxweb/projects/qer/src/lib/service-categories/service-categories.module.ts b/imxweb/projects/qer/src/lib/service-categories/service-categories.module.ts index bd1b45599..a2054c310 100644 --- a/imxweb/projects/qer/src/lib/service-categories/service-categories.module.ts +++ b/imxweb/projects/qer/src/lib/service-categories/service-categories.module.ts @@ -39,32 +39,29 @@ import { HelpContextualModule, MenuItem, MenuService, - RouteGuardService + RouteGuardService, } from 'qbm'; -import { ServiceCategoriesComponent } from './service-categories.component'; -import { ServiceCategoryComponent } from './service-category.component'; -import { ServiceItemsModule } from '../service-items/service-items.module'; import { isShopAdmin, isShopStatistics } from '../admin/qer-permissions-helper'; import { ShopGuardService } from '../guards/shop-guard.service'; +import { ServiceItemsModule } from '../service-items/service-items.module'; +import { ServiceCategoriesComponent } from './service-categories.component'; +import { ServiceCategoryComponent } from './service-category.component'; const routes: Routes = [ { path: 'configuration/servicecategories', component: ServiceCategoriesComponent, - canActivate: [RouteGuardService, ShopGuardService], + canActivate: [ShopGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.ServiceCategories - } - } + data: { + contextId: HELP_CONTEXTUAL.ServiceCategories, + }, + }, ]; @NgModule({ - declarations: [ - ServiceCategoriesComponent, - ServiceCategoryComponent - ], + declarations: [ServiceCategoriesComponent, ServiceCategoryComponent], imports: [ CdrModule, CommonModule, @@ -76,44 +73,36 @@ const routes: Routes = [ TranslateModule, ServiceItemsModule, HelpContextualModule, - ] + ], }) export class ServiceCategoriesModule { - - constructor( - private readonly menuService: MenuService, - logger: ClassloggerService) { + constructor(private readonly menuService: MenuService, logger: ClassloggerService) { logger.info(this, '▶︝ ServiceCategoriesModule loaded'); this.setupMenu(); } private setupMenu(): void { - this.menuService.addMenuFactories( - (preProps: string[], features: string[]) => { - - const items: MenuItem[] = []; + this.menuService.addMenuFactories((preProps: string[], features: string[]) => { + const items: MenuItem[] = []; - if (isShopAdmin(features) || isShopStatistics(features)) { - items.push( - { - id: 'QER_Setup_Servicecategories', - route: 'configuration/servicecategories', - title: '#LDS#Menu Entry Service categories', - sorting: '60-30' - } - ); - } + if (isShopAdmin(features) || isShopStatistics(features)) { + items.push({ + id: 'QER_Setup_Servicecategories', + route: 'configuration/servicecategories', + title: '#LDS#Menu Entry Service categories', + sorting: '60-30', + }); + } - if (items.length === 0) { - return null; - } - return { - id: 'ROOT_Setup', - title: '#LDS#Setup', - sorting: '60', - items - }; - }, - ); + if (items.length === 0) { + return null; + } + return { + id: 'ROOT_Setup', + title: '#LDS#Setup', + sorting: '60', + items, + }; + }); } } diff --git a/imxweb/projects/qer/src/lib/service-items-edit/service-items-edit.component.ts b/imxweb/projects/qer/src/lib/service-items-edit/service-items-edit.component.ts index 939b683d0..7104fa0e9 100644 --- a/imxweb/projects/qer/src/lib/service-items-edit/service-items-edit.component.ts +++ b/imxweb/projects/qer/src/lib/service-items-edit/service-items-edit.component.ts @@ -77,13 +77,13 @@ export class ServiceItemsEditComponent implements OnInit { } public async ngOnInit(): Promise { - await this.getData(undefined, true); + await this.getData(undefined); } - public async getData(newState?: CollectionLoadParameters, isInitialLoad: boolean = false): Promise { + public async getData(newState?: CollectionLoadParameters): Promise { const isBusy = this.busyService.beginBusy(); try { - this.dstSettings = await this.dstWrapper.getDstSettings(newState, undefined, isInitialLoad); + this.dstSettings = await this.dstWrapper.getDstSettings(newState, undefined); } finally { isBusy.endBusy(); } diff --git a/imxweb/projects/qer/src/lib/service-items-edit/service-items-edit.module.ts b/imxweb/projects/qer/src/lib/service-items-edit/service-items-edit.module.ts index 8a8cb142b..7f4a12f8a 100644 --- a/imxweb/projects/qer/src/lib/service-items-edit/service-items-edit.module.ts +++ b/imxweb/projects/qer/src/lib/service-items-edit/service-items-edit.module.ts @@ -24,37 +24,43 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { RouterModule, Routes } from '@angular/router'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; -import { CdrModule, ClassloggerService, DataSourceToolbarModule, DataTableModule, HELP_CONTEXTUAL, HelpContextualModule, MenuItem, MenuService, RouteGuardService } from 'qbm'; -import { ServiceItemsEditComponent } from './service-items-edit.component'; -import { ServiceItemsEditSidesheetComponent } from './service-items-edit-sidesheet/service-items-edit-sidesheet.component'; -import { ShopAdminGuardService } from '../guards/shop-admin-guard.service'; +import { + CdrModule, + ClassloggerService, + DataSourceToolbarModule, + DataTableModule, + HELP_CONTEXTUAL, + HelpContextualModule, + MenuItem, + MenuService, +} from 'qbm'; import { isShopAdmin } from '../admin/qer-permissions-helper'; -import { ServiceItemsEditFormModule } from './service-items-edit-form/service-items-edit-form.module'; +import { ShopAdminGuardService } from '../guards/shop-admin-guard.service'; import { ObjectHyperviewModule } from '../object-hyperview/object-hyperview.module'; +import { ServiceItemsEditFormModule } from './service-items-edit-form/service-items-edit-form.module'; +import { ServiceItemsEditSidesheetComponent } from './service-items-edit-sidesheet/service-items-edit-sidesheet.component'; +import { ServiceItemsEditComponent } from './service-items-edit.component'; const routes: Routes = [ { path: 'admin/serviceitems', component: ServiceItemsEditComponent, - canActivate: [RouteGuardService, ShopAdminGuardService], - data:{ - contextId: HELP_CONTEXTUAL.ServiceItems - } + canActivate: [ShopAdminGuardService], + data: { + contextId: HELP_CONTEXTUAL.ServiceItems, + }, }, ]; @NgModule({ - declarations: [ - ServiceItemsEditComponent, - ServiceItemsEditSidesheetComponent, - ], + declarations: [ServiceItemsEditComponent, ServiceItemsEditSidesheetComponent], imports: [ CommonModule, CdrModule, @@ -68,44 +74,36 @@ const routes: Routes = [ ServiceItemsEditFormModule, TranslateModule, HelpContextualModule, - ] + ], }) export class ServiceItemsEditModule { - - constructor( - private readonly menuService: MenuService, - logger: ClassloggerService) { + constructor(private readonly menuService: MenuService, logger: ClassloggerService) { logger.info(this, '▶️ ServiceItemsEditModule loaded'); this.setupMenu(); } private setupMenu(): void { - this.menuService.addMenuFactories( - (preProps: string[], features: string[]) => { - - const items: MenuItem[] = []; + this.menuService.addMenuFactories((preProps: string[], features: string[]) => { + const items: MenuItem[] = []; - if (isShopAdmin(features)) { - items.push( - { - id: 'QER_ServiceItems', - navigationCommands: { commands: ['admin', 'serviceitems'] }, - title: '#LDS#Menu Entry Service items', - sorting: '60-40', - }, - ); - } + if (isShopAdmin(features)) { + items.push({ + id: 'QER_ServiceItems', + navigationCommands: { commands: ['admin', 'serviceitems'] }, + title: '#LDS#Menu Entry Service items', + sorting: '60-40', + }); + } - if (items.length === 0) { - return null; - } - return { - id: 'ROOT_Setup', - title: '#LDS#Setup', - sorting: '60', - items - }; - }, - ); + if (items.length === 0) { + return null; + } + return { + id: 'ROOT_Setup', + title: '#LDS#Setup', + sorting: '60', + items, + }; + }); } } diff --git a/imxweb/projects/qer/src/lib/statistics/statistics.module.ts b/imxweb/projects/qer/src/lib/statistics/statistics.module.ts index 72d229fc4..8a2dac8ce 100644 --- a/imxweb/projects/qer/src/lib/statistics/statistics.module.ts +++ b/imxweb/projects/qer/src/lib/statistics/statistics.module.ts @@ -24,61 +24,61 @@ * */ -import { NgModule } from '@angular/core'; +import { DragDropModule } from '@angular/cdk/drag-drop'; +import { ScrollingModule } from '@angular/cdk/scrolling'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; -import { DragDropModule } from '@angular/cdk/drag-drop'; -import { ScrollingModule } from '@angular/cdk/scrolling'; import { + CdrModule, ClassloggerService, - MenuService, - RouteGuardService, DataSourceToolbarModule, - InfoModalDialogModule, DataTableModule, - CdrModule, - SidenavTreeModule, - MenuItem, - LdsReplaceModule, DateModule, - HelpContextualModule, + ExtModule, HELP_CONTEXTUAL, + HelpContextualModule, + InfoModalDialogModule, + LdsReplaceModule, + MenuItem, + MenuService, + RouteGuardService, + SidenavTreeModule, TempBillboardModule, - ExtModule, } from 'qbm'; +import { FormsModule } from '@angular/forms'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatExpansionModule } from '@angular/material/expansion'; import { TranslateModule } from '@ngx-translate/core'; -import { TreemapChartComponent } from './heatmaps/treemap-chart/treemap-chart.component'; -import { HeatmapChartComponent } from './heatmaps/heatmap-chart/heatmap-chart.component'; +import { isStatistics } from '../admin/qer-permissions-helper'; +import { StatisticsGuardService } from '../guards/statistics-guard.service'; +import { ChartTableComponent } from './charts/chart-table/chart-table.component'; +import { ChartTileComponent } from './charts/chart-tile/chart-tile.component'; +import { PointStatVisualComponent } from './charts/chart-tile/point-stat-visual/point-stat-visual.component'; +import { ChartsSidesheetComponent } from './charts/charts-sidesheet/charts-sidesheet.component'; import { BlockDetailSidesheetComponent } from './heatmaps/block-detail-sidesheet/block-detail-sidesheet.component'; import { DiscreteLegendComponent } from './heatmaps/discrete-legend/discrete-legend.component'; +import { HeatmapChartComponent } from './heatmaps/heatmap-chart/heatmap-chart.component'; import { HeatmapSidesheetComponent } from './heatmaps/heatmap-sidesheet/heatmap-sidesheet.component'; -import { StatisticsHomePageComponent } from './statistics-home-page/statistics-home-page.component'; -import { MatExpansionModule } from '@angular/material/expansion'; -import { StatisticsTreeComponent } from './statistics-home-page/statistics-tree/statistics-tree.component'; -import { StatisticsCardsComponent } from './statistics-home-page/statistics-cards/statistics-cards.component'; -import { StatisticsCardsVisualsComponent } from './statistics-home-page/statistics-cards-visuals/statistics-cards-visuals.component'; -import { HeatmapVisualComponent } from './statistics-home-page/statistics-cards-visuals/heatmap-visual/heatmap-visual.component'; -import { PointStatVisualComponent } from './charts/chart-tile/point-stat-visual/point-stat-visual.component'; +import { HeatmapTileComponent } from './heatmaps/heatmap-tile/heatmap-tile.component'; +import { TreemapChartComponent } from './heatmaps/treemap-chart/treemap-chart.component'; +import { StatisticsForObjectsComponent } from './statistics-for-objects/statistics-for-objects.component'; import { FavoritesTabComponent } from './statistics-home-page/favorites-tab/favorites-tab.component'; -import { ChartsSidesheetComponent } from './charts/charts-sidesheet/charts-sidesheet.component'; -import { StatisticsOrderingSidesheetComponent } from './statistics-home-page/statistics-ordering-sidesheet/statistics-ordering-sidesheet.component'; +import { HeatmapVisualComponent } from './statistics-home-page/statistics-cards-visuals/heatmap-visual/heatmap-visual.component'; +import { StatisticsCardsVisualsComponent } from './statistics-home-page/statistics-cards-visuals/statistics-cards-visuals.component'; +import { StatisticsCardsComponent } from './statistics-home-page/statistics-cards/statistics-cards.component'; +import { StatisticsHomePageComponent } from './statistics-home-page/statistics-home-page.component'; import { StatisticsOrderingSidesheetDialogComponent } from './statistics-home-page/statistics-ordering-sidesheet/statistics-ordering-sidesheet-dialog/statistics-ordering-sidesheet-dialog.component'; -import { ChartTableComponent } from './charts/chart-table/chart-table.component'; -import { StatisticsForObjectsComponent } from './statistics-for-objects/statistics-for-objects.component'; -import { ChartTileComponent } from './charts/chart-tile/chart-tile.component'; -import { HeatmapTileComponent } from './heatmaps/heatmap-tile/heatmap-tile.component'; -import { FormsModule } from '@angular/forms'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { StatisticsGuardService } from '../guards/statistics-guard.service'; -import { isStatistics } from '../admin/qer-permissions-helper'; +import { StatisticsOrderingSidesheetComponent } from './statistics-home-page/statistics-ordering-sidesheet/statistics-ordering-sidesheet.component'; +import { StatisticsTreeComponent } from './statistics-home-page/statistics-tree/statistics-tree.component'; const routes: Routes = [ { path: 'statistics', component: StatisticsHomePageComponent, - canActivate: [RouteGuardService, StatisticsGuardService], + canActivate: [StatisticsGuardService], resolve: [RouteGuardService], data: { contextId: HELP_CONTEXTUAL.StatisticsPage, @@ -128,7 +128,7 @@ const routes: Routes = [ RouterModule.forChild(routes), HelpContextualModule, TempBillboardModule, - ExtModule + ExtModule, ], exports: [StatisticsForObjectsComponent], }) @@ -141,7 +141,7 @@ export class StatisticsModule { /** This method defines the menu structure for the portal. */ private setupMenu(): void { this.menuService.addMenuFactories((preProps: string[], features: string[]) => { - if(isStatistics(features)){ + if (isStatistics(features)) { const menu: MenuItem = { id: 'ROOT_Statistics', title: '#LDS#Statistics', diff --git a/imxweb/projects/qer/src/lib/team-responsibilities/team-responsibilities.module.ts b/imxweb/projects/qer/src/lib/team-responsibilities/team-responsibilities.module.ts index f93fc0ba2..73b7d5fab 100644 --- a/imxweb/projects/qer/src/lib/team-responsibilities/team-responsibilities.module.ts +++ b/imxweb/projects/qer/src/lib/team-responsibilities/team-responsibilities.module.ts @@ -24,39 +24,44 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { TeamResponsibilitiesComponent } from './team-responsibilities.component'; +import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; -import { ClassloggerService, DataSourceToolbarModule, DataTableModule, ExtService, HELP_CONTEXTUAL, HelpContextualComponent, HelpContextualModule, MenuItem, MenuService, RouteGuardService } from 'qbm'; -import { ManagerGuardService } from '../guards/manager-guard.service'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { + ClassloggerService, + DataSourceToolbarModule, + DataTableModule, + ExtService, + HELP_CONTEXTUAL, + HelpContextualModule, + MenuItem, + MenuService, + RouteGuardService, +} from 'qbm'; import { isPersonManager } from '../admin/qer-permissions-helper'; +import { ManagerGuardService } from '../guards/manager-guard.service'; +import { TilesModule } from '../tiles/tiles.module'; +import { TeamResponsibilitiesComponent } from './team-responsibilities.component'; import { TeamResponsibilitiesService } from './team-responsibilities.service'; -import { TranslateModule } from '@ngx-translate/core'; -import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TeamResponsibilitySidesheetComponent } from './team-responsibility-sidesheet/team-responsibility-sidesheet.component'; -import { TeamResponsibilityTileComponent } from './team-responsibility-tile/team-responsibility-tile.component' -import { TilesModule } from '../tiles/tiles.module'; +import { TeamResponsibilityTileComponent } from './team-responsibility-tile/team-responsibility-tile.component'; const routes: Routes = [ { path: 'teamresponsibilities', component: TeamResponsibilitiesComponent, - canActivate: [RouteGuardService, ManagerGuardService], + canActivate: [ManagerGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.TeamResponsibilities - } - } + data: { + contextId: HELP_CONTEXTUAL.TeamResponsibilities, + }, + }, ]; - @NgModule({ - declarations: [ - TeamResponsibilitiesComponent, - TeamResponsibilitySidesheetComponent, - TeamResponsibilityTileComponent - ], + declarations: [TeamResponsibilitiesComponent, TeamResponsibilitySidesheetComponent, TeamResponsibilityTileComponent], imports: [ CommonModule, EuiCoreModule, @@ -66,42 +71,35 @@ const routes: Routes = [ DataTableModule, TranslateModule, TilesModule, - HelpContextualModule + HelpContextualModule, ], - providers:[ - TeamResponsibilitiesService - ] + providers: [TeamResponsibilitiesService], }) export class TeamResponsibilitiesModule { - constructor( - private readonly menuService: MenuService, - private readonly extService: ExtService, - logger: ClassloggerService - ) { + constructor(private readonly menuService: MenuService, private readonly extService: ExtService, logger: ClassloggerService) { logger.info(this, '▶️ TeamResponsibilitiesModule loaded'); this.setupMenu(); - this.extService.register('Dashboard-SmallTiles', { instance:TeamResponsibilityTileComponent}); + this.extService.register('Dashboard-SmallTiles', { instance: TeamResponsibilityTileComponent }); } private async setupMenu(): Promise { - this.menuService.addMenuFactories( - (preProps: string[], groups: string[]) => { - - const items: MenuItem[] = []; - if (isPersonManager(groups)) { - return { - id: 'ROOT_Responsibilities', - title: '#LDS#Responsibilities', - sorting: '30', - items: [{ + this.menuService.addMenuFactories((preProps: string[], groups: string[]) => { + const items: MenuItem[] = []; + if (isPersonManager(groups)) { + return { + id: 'ROOT_Responsibilities', + title: '#LDS#Responsibilities', + sorting: '30', + items: [ + { id: 'QER_Team_Responsibilities', navigationCommands: { commands: ['teamresponsibilities'] }, title: '#LDS#Menu Entry Responsibilities of my reports', sorting: '30-10', - }] - }; - } - }, - ); + }, + ], + }; + } + }); } } diff --git a/imxweb/projects/qer/src/lib/user/user-model.service.ts b/imxweb/projects/qer/src/lib/user/user-model.service.ts index 79a6d8f45..0794eb3fb 100644 --- a/imxweb/projects/qer/src/lib/user/user-model.service.ts +++ b/imxweb/projects/qer/src/lib/user/user-model.service.ts @@ -42,15 +42,17 @@ export class UserModelService { private pendingItemsCache: CachedPromise; private cachedGroups: CachedPromise; private cachedFeatures: CachedPromise; + private cachedUserConfig: CachedPromise; constructor(private readonly qerClient: QerApiService, private readonly settingsService: SettingsService, cacheService: CacheService) { this.pendingItemsCache = cacheService.buildCache(() => this.qerClient.client.portal_pendingitems_get()); this.cachedGroups = cacheService.buildCache(() => this.qerClient.client.portal_usergroups_get()); this.cachedFeatures = cacheService.buildCache(() => this.qerClient.client.portal_features_get()); + this.cachedUserConfig = cacheService.buildCache(() => this.qerClient.client.portal_person_config_get()); } public getUserConfig(): Promise { - return this.qerClient.client.portal_person_config_get(); + return this.cachedUserConfig.get(); } public getPendingItems(): Promise { diff --git a/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.ts b/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.ts index 5f8e30301..f25e8c15e 100644 --- a/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.ts +++ b/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.ts @@ -158,9 +158,9 @@ export class ViewDevicesComponent implements OnInit, OnDestroy, SideNavigationCo public async getData(newState?: CollectionLoadParameters, isInitialLoad: boolean = false): Promise { const isbusy = this.busyService.beginBusy(); try { - this.dstSettings = await this.dstWrapper.getDstSettings(newState, undefined, isInitialLoad); + this.dstSettings = await this.dstWrapper.getDstSettings(newState, undefined); - const dstSettingsHardwareType = await this.dstWrapperHardwareType.getDstSettings(newState, undefined, isInitialLoad); + const dstSettingsHardwareType = await this.dstWrapperHardwareType.getDstSettings(newState, undefined); if (dstSettingsHardwareType) { this.dstSettingsHardwareType = dstSettingsHardwareType; this.deviceModelValueStruct = this.dstSettingsHardwareType.dataSource.Data.map((d) => { diff --git a/imxweb/projects/rmb/src/lib/org-membership.ts b/imxweb/projects/rmb/src/lib/org-membership.ts index 6c870af88..da8d6fd88 100644 --- a/imxweb/projects/rmb/src/lib/org-membership.ts +++ b/imxweb/projects/rmb/src/lib/org-membership.ts @@ -25,76 +25,20 @@ */ import { CollectionLoadParameters, ExtendedTypedEntityCollection, TypedEntity, EntityCollectionData, EntitySchema, IEntity, DataModel } from 'imx-qbm-dbts'; -import { IRoleMembershipType } from 'qer'; +import { BaseMembership } from 'qer'; import { DynamicMethod, ImxTranslationProviderService, imx_SessionService } from 'qbm'; import { RmbApiService } from './rmb-api-client.service'; // do not inherit from BaseMembership because classes cannot inherit across modules :-( -export class OrgMembership implements IRoleMembershipType { - - public supportsDynamicMemberships = true; - private readonly schemaPaths: Map = new Map(); - - private readonly basePath = 'portal/roles/config/membership/Org'; - +export class OrgMembership extends BaseMembership { constructor( - private readonly api: RmbApiService, - private readonly session: imx_SessionService, - private readonly translator: ImxTranslationProviderService + private api: RmbApiService, + private session: imx_SessionService, + private translator: ImxTranslationProviderService, ) { - this.schemaPaths.set('get', `${this.basePath}/{UID_Org}`); - this.schemaPaths.set('candidates', `${this.basePath}/{UID_Org}/UID_Person/candidates`); - } - - public async get(id: string, navigationState?: CollectionLoadParameters): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('get'), - `/${this.basePath}/${id}`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); - } - - public getSchema(key: string): EntitySchema { - return this.session.Client.getSchema(this.schemaPaths.get(key)); - } - - public GetUidPerson(entity: IEntity) { - return entity.GetColumn('UID_Person').GetValue(); - } - - public GetUidRole(entity: IEntity): string { - return entity.GetColumn("UID_Org").GetValue(); - } - - public async getCandidates( - id: string, - navigationState?: CollectionLoadParameters - ): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); - } - - public async getCandidatesDataModel(id: string): Promise { - const dynamicMethod = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - return dynamicMethod.getDataModei(); + super(api, session, translator); + this.setRoleName('Org', 'UID_Org'); } public async delete(role: string, identity: string): Promise { diff --git a/imxweb/projects/rms/src/lib/eset-entitlements.ts b/imxweb/projects/rms/src/lib/eset-entitlements.ts index 34c666ea2..1fde53416 100644 --- a/imxweb/projects/rms/src/lib/eset-entitlements.ts +++ b/imxweb/projects/rms/src/lib/eset-entitlements.ts @@ -24,17 +24,25 @@ * */ -import { RoleAssignmentData } from "imx-api-qer"; -import { CollectionLoadParameters, CompareOperator, ExtendedTypedEntityCollection, FilterType, IEntity, TypedEntity } from "imx-qbm-dbts"; -import { DynamicMethodService, GenericTypedEntity, ImxTranslationProviderService } from "qbm"; -import { IRoleEntitlements } from "qer"; -import { RmsApiService } from "./rms-api-client.service"; +import { RoleAssignmentData } from 'imx-api-qer'; +import { + CollectionLoadParameters, + CompareOperator, + ExtendedTypedEntityCollection, + FilterType, + IEntity, + TypedEntity, +} from 'imx-qbm-dbts'; +import { ImxTranslationProviderService } from 'qbm'; +import { IRoleEntitlements } from 'qer'; +import { RmsApiService } from './rms-api-client.service'; export class EsetEntitlements implements IRoleEntitlements { + public entitlementFkName = 'Entitlement'; // column name in ESetHasEntitlement + constructor( private readonly api: RmsApiService, - private readonly dynamicMethodSvc: DynamicMethodService, - protected readonly translator: ImxTranslationProviderService + protected readonly translator: ImxTranslationProviderService, ) {} public async getCollection( @@ -42,7 +50,7 @@ export class EsetEntitlements implements IRoleEntitlements { navigationState?: CollectionLoadParameters, objectKeyForFiltering?: string ): Promise> { - return await this.api.typedClient.PortalRolesConfigEntitlementsEset.Get(id, { + return this.api.typedClient.PortalRolesConfigEntitlementsEset.Get(id, { ...navigationState, filter: objectKeyForFiltering ? [ { @@ -59,26 +67,13 @@ export class EsetEntitlements implements IRoleEntitlements { return this.api.client.portal_roles_config_classes_ESet_get(); } - public getEntitlementFkName() { - return 'Entitlement'; // column name in ESetHasEntitlement - } - async delete(roleId: string, entity: IEntity): Promise { const esethasentl = entity.GetKeys()[0]; await this.api.client.portal_roles_config_entitlements_ESet_delete(roleId, esethasentl); } - public createEntitlementAssignmentEntity(role: IEntity, entlType: RoleAssignmentData): IEntity { + public createEntitlementAssignmentEntity(role: IEntity): IEntity { const uidESet = role.GetKeys()[0]; - const entityColl = this.dynamicMethodSvc.createEntity( - this.api.apiClient, - { - path: '/portal/roles/config/entitlements/ESet/' + uidESet, - type: GenericTypedEntity, - schemaPath: 'portal/roles/config/entitlements/ESet/{' + entlType.RoleFk + '}', - }, - { Columns: { UID_ESet: { Value: uidESet } } } - ); - return entityColl.Data[0].GetEntity(); + return this.api.typedClient.PortalRolesConfigEntitlementsEset.createEntity({ Columns: { UID_ESet: { Value: uidESet } } }).GetEntity(); } } \ No newline at end of file diff --git a/imxweb/projects/rms/src/lib/eset-membership.ts b/imxweb/projects/rms/src/lib/eset-membership.ts index 3525af436..43cd79462 100644 --- a/imxweb/projects/rms/src/lib/eset-membership.ts +++ b/imxweb/projects/rms/src/lib/eset-membership.ts @@ -25,62 +25,20 @@ */ import { CollectionLoadParameters, ExtendedTypedEntityCollection, TypedEntity, EntityCollectionData, EntitySchema, IEntity, DataModel } from 'imx-qbm-dbts'; -import { IRoleMembershipType } from 'qer'; -import { DynamicMethod, ImxTranslationProviderService, imx_SessionService } from 'qbm'; +import { BaseMembership} from 'qer'; +import { ImxTranslationProviderService, imx_SessionService } from 'qbm'; import { RmsApiService } from './rms-api-client.service'; -export class EsetMembership implements IRoleMembershipType { - +export class EsetMembership extends BaseMembership { public supportsDynamicMemberships = false; - private readonly schemaPaths: Map = new Map(); - - private readonly basePath = 'portal/roles/config/membership/ESet'; constructor( private readonly api: RmsApiService, - private readonly session: imx_SessionService, - private readonly translator: ImxTranslationProviderService + readonly session: imx_SessionService, + readonly translator: ImxTranslationProviderService ) { - this.schemaPaths.set('get', `${this.basePath}/{UID_ESet}`); - this.schemaPaths.set('candidates', `${this.basePath}/{UID_ESet}/UID_Person/candidates`); - } - - public async get(id: string, navigationState?: CollectionLoadParameters): Promise> { - return this.api.typedClient.PortalRolesConfigMembershipEset.Get(id, navigationState); - } - - public getSchema(key: string): EntitySchema { - return this.session.Client.getSchema(this.schemaPaths.get(key)); - } - - public GetUidPerson(entity: IEntity) { - return entity.GetColumn('UID_Person').GetValue(); - } - - public async getCandidates( - id: string, - navigationState?: CollectionLoadParameters - ): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); - } - - public async getCandidatesDataModel(id: string): Promise { - const dynamicMethod = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - return dynamicMethod.getDataModei(); + super(api, session, translator); + this.setRoleName('ESet', 'UID_ESet'); } public async delete(role: string, identity: string): Promise { @@ -91,9 +49,6 @@ export class EsetMembership implements IRoleMembershipType { return false; } - public GetUidRole(entity: IEntity): string { - return entity.GetColumn("UID_ESet").GetValue(); - } public getPrimaryMembers( uid: string, diff --git a/imxweb/projects/rms/src/lib/init.service.ts b/imxweb/projects/rms/src/lib/init.service.ts index 3b463b0b5..3dcaaa604 100644 --- a/imxweb/projects/rms/src/lib/init.service.ts +++ b/imxweb/projects/rms/src/lib/init.service.ts @@ -56,12 +56,6 @@ import { EsetEntitlements } from './eset-entitlements'; import { EsetMembership } from './eset-membership'; import { RmsApiService } from './rms-api-client.service'; -export interface test { - GetSchema(): EntitySchema; - Get_byid(id: string): Promise>; - Get(): Promise>; -} - @Injectable({ providedIn: 'root' }) export class InitService { private esetTag = 'ESet'; @@ -72,7 +66,6 @@ export class InitService { private readonly api: RmsApiService, private readonly session: imx_SessionService, private readonly translator: ImxTranslationProviderService, - private readonly dynamicMethodSvc: DynamicMethodService, private readonly dataExplorerRegistryService: DataExplorerRegistryService, private readonly menuService: MenuService, private readonly roleService: RoleService, @@ -154,7 +147,7 @@ export class InitService { adminCanCreate: true, interactiveResp: new ApiWrapper(this.api.typedClient.PortalRespEsetInteractive), interactiveAdmin: new ApiWrapper(this.api.typedClient.PortalAdminRoleEsetInteractive), - entitlements: new EsetEntitlements(this.api, this.dynamicMethodSvc, this.translator), + entitlements: new EsetEntitlements(this.api, this.translator), membership: new EsetMembership(this.api, this.session, this.translator), canUseRecommendations: true, exportMethod: (navigationState: CollectionLoadParameters, isAdmin: boolean) => { diff --git a/imxweb/projects/rps/src/lib/reports/edit-report.component.ts b/imxweb/projects/rps/src/lib/reports/edit-report.component.ts index 9bfd2f885..4e032e9af 100644 --- a/imxweb/projects/rps/src/lib/reports/edit-report.component.ts +++ b/imxweb/projects/rps/src/lib/reports/edit-report.component.ts @@ -88,20 +88,20 @@ export class EditReportComponent implements OnInit, OnDestroy { this.entitySchema ); - await this.getData(undefined, true); + await this.getData(undefined); } public ngOnDestroy(): void { this.subscriptions.forEach((s) => s.unsubscribe()); } - public async getData(parameter?: CollectionLoadParameters, isInitialLoad: boolean = true): Promise { + public async getData(parameter?: CollectionLoadParameters): Promise { const isBusy = this.busyService.beginBusy(); try { const parameters = { ...parameter, }; - this.dstSettings = await this.dstWrapper.getDstSettings(parameters, undefined, isInitialLoad); + this.dstSettings = await this.dstWrapper.getDstSettings(parameters, undefined); } finally { isBusy.endBusy(); } diff --git a/imxweb/projects/tsb/src/lib/accounts/accounts.component.ts b/imxweb/projects/tsb/src/lib/accounts/accounts.component.ts index b2bcbb689..43fb2b826 100644 --- a/imxweb/projects/tsb/src/lib/accounts/accounts.component.ts +++ b/imxweb/projects/tsb/src/lib/accounts/accounts.component.ts @@ -117,7 +117,7 @@ export class DataExplorerAccountsComponent implements OnInit, OnDestroy, SideNav const isBusy = this.busyService.beginBusy(); try { - this.dataModel = await this.accountsService.getDataModel(); + this.dataModel = await this.accountsService.getDataModel(); this.filterOptions = this.dataModel.Filters; this.viewConfig = await this.viewConfigService.getInitialDSTExtension(this.dataModel, this.viewConfigPath); } finally { @@ -238,7 +238,7 @@ export class DataExplorerAccountsComponent implements OnInit, OnDestroy, SideNav getParams.system = tsUid ? tsUid : undefined; getParams.container = cUid ? cUid : undefined; - const data = isInitialLoad ? { totalCount: 0, Data: [] } : await this.accountsService.getAccounts(getParams); + const data = isInitialLoad ? { totalCount: 0, Data: [] } : await this.accountsService.getAccounts(getParams); if (data) { const exportMethod: DataSourceToolbarExportMethod = this.accountsService.exportAccounts(this.navigationState); exportMethod.initialColumns = this.displayedColumns.map((col) => col.ColumnName); @@ -248,17 +248,19 @@ export class DataExplorerAccountsComponent implements OnInit, OnDestroy, SideNav entitySchema: this.entitySchemaUnsAccount, navigationState: this.navigationState, filters: this.filterOptions, - filterTree: { - filterMethode: async (parentkey) => { - return this.accountsService.getFilterTree({ - parentkey, - container: getParams.container, - system: getParams.system, - filter: getParams.filter, - }); - }, - multiSelect: false, - }, + filterTree: isInitialLoad + ? undefined + : { + filterMethode: async (parentkey) => { + return this.accountsService.getFilterTree({ + parentkey, + container: getParams.container, + system: getParams.system, + filter: getParams.filter, + }); + }, + multiSelect: false, + }, dataModel: this.dataModel, viewConfig: this.viewConfig, exportMethod, diff --git a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.html b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.html index ac88d2f8c..da416ce89 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.html +++ b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.html @@ -1,4 +1,4 @@ -
+
{{ LdsDirectlyAssigned | translate }} @@ -50,7 +50,7 @@ - + {{ '#LDS#Here you can get an overview of the memberships of the system entitlement. Additionally, you can view the assignment analysis for each membership.' | translate }} diff --git a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.ts b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.ts index d38a33033..72ec36ca3 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.ts +++ b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.ts @@ -72,6 +72,8 @@ export class GroupMembersComponent implements OnInit { public nestedNavigationState: CollectionLoadParameters; public viewDirectMemberships = new UntypedFormControl(true); + public canViewInheritedMemberships: boolean = false; + public showUnsubscribeWarning = false; public readonly entitySchemaGroupDirectMemberships: EntitySchema; @@ -134,6 +136,7 @@ export class GroupMembersComponent implements OnInit { ]; this.groupId = this.unsGroupDbObjectKey.Keys[0]; + this.canViewInheritedMemberships = this.unsGroupDbObjectKey?.TableName === 'ADSGroup'; await this.navigateDirect(); } diff --git a/imxweb/projects/tsb/src/lib/groups/groups.component.ts b/imxweb/projects/tsb/src/lib/groups/groups.component.ts index e886c9f78..564e549d1 100644 --- a/imxweb/projects/tsb/src/lib/groups/groups.component.ts +++ b/imxweb/projects/tsb/src/lib/groups/groups.component.ts @@ -380,10 +380,11 @@ export class DataExplorerGroupsComponent implements OnInit, OnDestroy, SideNavig getParams.uid_unsaccount = this.unsAccountIdFilter; } - const data = isInitialLoad ? { totalCount: 0, Data: [] } : - this.isAdmin || this.unsAccountIdFilter // Wenn wir filtern, muss auch der Admin-Endpoint genutzt werden - ? await this.groupsService.getGroups(getParams) - : await this.groupsService.getGroupsResp(getParams); + const data = isInitialLoad + ? { totalCount: 0, Data: [] } + : this.isAdmin || this.unsAccountIdFilter // Wenn wir filtern, muss auch der Admin-Endpoint genutzt werden + ? await this.groupsService.getGroups(getParams) + : await this.groupsService.getGroupsResp(getParams); if (data) { const exportMethod = @@ -398,17 +399,19 @@ export class DataExplorerGroupsComponent implements OnInit, OnDestroy, SideNavig entitySchema: this.entitySchemaUnsGroup, navigationState: this.navigationState, filters: this.filterOptions, - filterTree: { - filterMethode: async (parentkey) => { - return this.groupsService.getFilterTree({ - parentkey, - container: getParams.container, - system: getParams.system, - uid_unsaccount: getParams.uid_unsaccount, - }); - }, - multiSelect: false, - }, + filterTree: isInitialLoad + ? undefined + : { + filterMethode: async (parentkey) => { + return this.groupsService.getFilterTree({ + parentkey, + container: getParams.container, + system: getParams.system, + uid_unsaccount: getParams.uid_unsaccount, + }); + }, + multiSelect: false, + }, dataModel: this.dataModel, viewConfig: this.viewConfig, exportMethod,