@acorex-platform/module-auth-client 0.0.18 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/{acorex-platform-module-auth-client-acorex-platform-module-auth-client-mW7tx8C0.mjs → acorex-platform-module-auth-client-acorex-platform-module-auth-client-CYmUn-lw.mjs} +940 -608
- package/fesm2022/acorex-platform-module-auth-client-acorex-platform-module-auth-client-CYmUn-lw.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-auth-client-app-chooser.component-BVbu-f8h.mjs +75 -0
- package/fesm2022/acorex-platform-module-auth-client-app-chooser.component-BVbu-f8h.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-blank.layout-BRGgntib.mjs → acorex-platform-module-auth-client-blank.layout-BCXNPgrp.mjs} +6 -6
- package/fesm2022/acorex-platform-module-auth-client-blank.layout-BCXNPgrp.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-change-password.command-O8Mgxoqj.mjs → acorex-platform-module-auth-client-change-password.command-DIM_d7RO.mjs} +51 -41
- package/fesm2022/acorex-platform-module-auth-client-change-password.command-DIM_d7RO.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-auth-client-change-photo.command-CYGqrJV0.mjs +257 -0
- package/fesm2022/acorex-platform-module-auth-client-change-photo.command-CYGqrJV0.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-auth-client-contracts.mjs +46 -10
- package/fesm2022/acorex-platform-module-auth-client-contracts.mjs.map +1 -1
- package/fesm2022/{acorex-platform-module-auth-client-edit-account-info.command-B-mVlXxg.mjs → acorex-platform-module-auth-client-edit-account-info.command-CD9IrimO.mjs} +5 -5
- package/fesm2022/acorex-platform-module-auth-client-edit-account-info.command-CD9IrimO.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-edit-signature.command-CcTJJwAX.mjs → acorex-platform-module-auth-client-edit-signature.command-TjOLhvKL.mjs} +5 -5
- package/fesm2022/acorex-platform-module-auth-client-edit-signature.command-TjOLhvKL.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-auth-client-get-user-activity.query-BTpibxe9.mjs +80 -0
- package/fesm2022/acorex-platform-module-auth-client-get-user-activity.query-BTpibxe9.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-lock-screen.command-PMoJJxe7.mjs → acorex-platform-module-auth-client-lock-screen.command-Br9O4b5c.mjs} +6 -6
- package/fesm2022/acorex-platform-module-auth-client-lock-screen.command-Br9O4b5c.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-login.module-C4S0RjM7.mjs → acorex-platform-module-auth-client-login.module-DJVL3bAF.mjs} +8 -21
- package/fesm2022/acorex-platform-module-auth-client-login.module-DJVL3bAF.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-auth-client-master.layout-DZUYm22p.mjs +39 -0
- package/fesm2022/acorex-platform-module-auth-client-master.layout-DZUYm22p.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-oauth-callback.component-CEMvfjj4.mjs → acorex-platform-module-auth-client-oauth-callback.component-DnQzPUxF.mjs} +11 -15
- package/fesm2022/acorex-platform-module-auth-client-oauth-callback.component-DnQzPUxF.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-auth-client-open-sessions.command-LZKM9fgo.mjs +200 -0
- package/fesm2022/acorex-platform-module-auth-client-open-sessions.command-LZKM9fgo.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-password.component-CIr6IBG6.mjs → acorex-platform-module-auth-client-password.component-CNKRWfuG.mjs} +86 -45
- package/fesm2022/acorex-platform-module-auth-client-password.component-CNKRWfuG.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-auth-client-password.component-CW0t9fEn.mjs +87 -0
- package/fesm2022/acorex-platform-module-auth-client-password.component-CW0t9fEn.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-auth-client-platform-settings-unavailable.component-BEVkQ3jh.mjs +47 -0
- package/fesm2022/acorex-platform-module-auth-client-platform-settings-unavailable.component-BEVkQ3jh.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-profile-activity-chart.component-DTY1eEI_.mjs → acorex-platform-module-auth-client-profile-activity-chart.component-CtSrYARX.mjs} +38 -46
- package/fesm2022/acorex-platform-module-auth-client-profile-activity-chart.component-CtSrYARX.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-profile-coming-soon.command-DBbFbzAx.mjs → acorex-platform-module-auth-client-profile-coming-soon.command-Crh2GsRA.mjs} +5 -5
- package/fesm2022/acorex-platform-module-auth-client-profile-coming-soon.command-Crh2GsRA.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-profile-delete-account-danger-zone.component-C6u3AB4N.mjs → acorex-platform-module-auth-client-profile-delete-account-danger-zone.component-D0QS8joQ.mjs} +18 -13
- package/fesm2022/{acorex-platform-module-auth-client-profile-delete-account-danger-zone.component-C6u3AB4N.mjs.map → acorex-platform-module-auth-client-profile-delete-account-danger-zone.component-D0QS8joQ.mjs.map} +1 -1
- package/fesm2022/{acorex-platform-module-auth-client-profile-page-component.provider-Dhmzo4ME.mjs → acorex-platform-module-auth-client-profile-page-component.provider-6lNx6bKI.mjs} +7 -7
- package/fesm2022/{acorex-platform-module-auth-client-profile-page-component.provider-Dhmzo4ME.mjs.map → acorex-platform-module-auth-client-profile-page-component.provider-6lNx6bKI.mjs.map} +1 -1
- package/fesm2022/acorex-platform-module-auth-client-profile-page.component-CdxseoJX.mjs +650 -0
- package/fesm2022/acorex-platform-module-auth-client-profile-page.component-CdxseoJX.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-register-password.component-ia6tdvTc.mjs → acorex-platform-module-auth-client-register-password.component-D-tBrCJv.mjs} +15 -14
- package/fesm2022/acorex-platform-module-auth-client-register-password.component-D-tBrCJv.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-register.module--DG9m8iC.mjs → acorex-platform-module-auth-client-register.module-BrXqva0B.mjs} +23 -23
- package/fesm2022/acorex-platform-module-auth-client-register.module-BrXqva0B.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-remove-pin-code.command-qtswigkv.mjs → acorex-platform-module-auth-client-remove-pin-code.command-uK04-h15.mjs} +7 -7
- package/fesm2022/acorex-platform-module-auth-client-remove-pin-code.command-uK04-h15.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-auth-client-reset-password.component-CcwDb6Wb.mjs +115 -0
- package/fesm2022/acorex-platform-module-auth-client-reset-password.component-CcwDb6Wb.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-result.component-DYJaB-FD.mjs → acorex-platform-module-auth-client-result.component-DWv1hmQR.mjs} +6 -6
- package/fesm2022/acorex-platform-module-auth-client-result.component-DWv1hmQR.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-routes-DVN2Y2Ps.mjs → acorex-platform-module-auth-client-routes-IX2qmeqU.mjs} +3 -3
- package/fesm2022/{acorex-platform-module-auth-client-routes-DVN2Y2Ps.mjs.map → acorex-platform-module-auth-client-routes-IX2qmeqU.mjs.map} +1 -1
- package/fesm2022/acorex-platform-module-auth-client-session-lock-overlay.component-BhsTAmVe.mjs +361 -0
- package/fesm2022/acorex-platform-module-auth-client-session-lock-overlay.component-BhsTAmVe.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-auth-client-set-pin-code.command-BJT7F-xz.mjs +116 -0
- package/fesm2022/acorex-platform-module-auth-client-set-pin-code.command-BJT7F-xz.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-set-pin-code.component-BHVqbYFv.mjs → acorex-platform-module-auth-client-set-pin-code.component-Cq4skm_3.mjs} +29 -20
- package/fesm2022/acorex-platform-module-auth-client-set-pin-code.component-Cq4skm_3.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-settings.provider-n1qbs6e1.mjs → acorex-platform-module-auth-client-settings.provider-Yaoz8yp3.mjs} +139 -11
- package/fesm2022/acorex-platform-module-auth-client-settings.provider-Yaoz8yp3.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-show-profile-command-CxMz1yy-.mjs → acorex-platform-module-auth-client-show-profile-command-BWoDxIdx.mjs} +5 -6
- package/fesm2022/acorex-platform-module-auth-client-show-profile-command-BWoDxIdx.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-signout-command-DqqrP5pk.mjs → acorex-platform-module-auth-client-signout-command-B7n_Fn4P.mjs} +5 -5
- package/fesm2022/acorex-platform-module-auth-client-signout-command-B7n_Fn4P.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-auth-client-tenant-chooser.component-CHmg7D5H.mjs +67 -0
- package/fesm2022/acorex-platform-module-auth-client-tenant-chooser.component-CHmg7D5H.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-auth-client-two-factor-code.component-nsB4v25Z.mjs +40 -0
- package/fesm2022/acorex-platform-module-auth-client-two-factor-code.component-nsB4v25Z.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-two-factor.module-FAqKbmBb.mjs → acorex-platform-module-auth-client-two-factor.module-_jYo6xXr.mjs} +8 -11
- package/fesm2022/acorex-platform-module-auth-client-two-factor.module-_jYo6xXr.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-auth-client-view-login-history.command-B42BHIAL.mjs → acorex-platform-module-auth-client-view-login-history.command-ovj5rdHL.mjs} +13 -11
- package/fesm2022/acorex-platform-module-auth-client-view-login-history.command-ovj5rdHL.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-auth-client.mjs +1 -1
- package/package.json +1 -1
- package/types/acorex-platform-module-auth-client-contracts.d.ts +43 -9
- package/types/acorex-platform-module-auth-client.d.ts +63 -56
- package/fesm2022/acorex-platform-module-auth-client-acorex-platform-module-auth-client-mW7tx8C0.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-app-chooser.component-IPLp1kVv.mjs +0 -67
- package/fesm2022/acorex-platform-module-auth-client-app-chooser.component-IPLp1kVv.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-blank.layout-BRGgntib.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-change-password.command-O8Mgxoqj.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-change-photo.command-BcNq9mTU.mjs +0 -192
- package/fesm2022/acorex-platform-module-auth-client-change-photo.command-BcNq9mTU.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-edit-account-info.command-B-mVlXxg.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-edit-signature.command-CcTJJwAX.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-lock-screen.command-PMoJJxe7.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-login.module-C4S0RjM7.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-master.layout-DXwb5VSr.mjs +0 -24
- package/fesm2022/acorex-platform-module-auth-client-master.layout-DXwb5VSr.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-oauth-callback.component-CEMvfjj4.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-open-sessions.command-BsS9b6Xk.mjs +0 -196
- package/fesm2022/acorex-platform-module-auth-client-open-sessions.command-BsS9b6Xk.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-password.component-CIr6IBG6.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-password.component-DnFItGdA.mjs +0 -88
- package/fesm2022/acorex-platform-module-auth-client-password.component-DnFItGdA.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-profile-activity-chart.component-DTY1eEI_.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-profile-coming-soon.command-DBbFbzAx.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-profile-page.component-CJ9AA3ZN.mjs +0 -446
- package/fesm2022/acorex-platform-module-auth-client-profile-page.component-CJ9AA3ZN.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-register-password.component-ia6tdvTc.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-register.module--DG9m8iC.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-remove-pin-code.command-qtswigkv.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-reset-password.component-CTlrt_18.mjs +0 -115
- package/fesm2022/acorex-platform-module-auth-client-reset-password.component-CTlrt_18.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-result.component-DYJaB-FD.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-session-lock-overlay.component-CN1JqPBW.mjs +0 -346
- package/fesm2022/acorex-platform-module-auth-client-session-lock-overlay.component-CN1JqPBW.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-set-pin-code.command-mBEdso1T.mjs +0 -33
- package/fesm2022/acorex-platform-module-auth-client-set-pin-code.command-mBEdso1T.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-set-pin-code.component-BHVqbYFv.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-settings.provider-n1qbs6e1.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-show-profile-command-CxMz1yy-.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-signout-command-DqqrP5pk.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-tenant-chooser.component-B_9s4F36.mjs +0 -59
- package/fesm2022/acorex-platform-module-auth-client-tenant-chooser.component-B_9s4F36.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-two-factor-code.component-DAxlYlhM.mjs +0 -40
- package/fesm2022/acorex-platform-module-auth-client-two-factor-code.component-DAxlYlhM.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-two-factor.module-FAqKbmBb.mjs.map +0 -1
- package/fesm2022/acorex-platform-module-auth-client-view-login-history.command-B42BHIAL.mjs.map +0 -1
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
import * as i1$
|
|
2
|
-
import { AXPFileStorageService,
|
|
3
|
-
import { AXPSessionService,
|
|
1
|
+
import * as i1$5 from '@acorex-platform/framework-client/common';
|
|
2
|
+
import { AXPFileStorageService, AXPHomePageService, AXPPlatformSettingsLoadState, AXPSettingsService, AXPDataProvider, AXPCommonSettings, AXP_PROTECTED_ROUTE_GUARDS, AXPCommonModule, AXPPlatformSettingsOfflineBootstrapService, AXP_MENU_PROVIDER, AXP_SETTING_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/common';
|
|
3
|
+
import { AXPSessionService, AXPUnauthorizedError, AXPUnauthenticatedError, AXPAuthStrategyRegistryService, traceAuthGuard, AXPAuthGuard, AXPSessionStatus } from '@acorex-platform/framework-client/auth';
|
|
4
4
|
import { AXPUserAvatarService, AXPUserAvatarComponent, AXP_PAGE_COMPONENT_PROVIDER } from '@acorex-platform/framework-client/layout/components';
|
|
5
|
-
import { AXPFileStorageStatus,
|
|
6
|
-
import { RootConfig } from '@acorex-platform/module-
|
|
7
|
-
import { RootConfig as RootConfig$1 } from '@acorex-platform/module-security-management-client/contracts';
|
|
5
|
+
import { AXPFileStorageStatus, coerceUnknownToTrimmedString, AXPPlatformScope, AXPKeyboardShortcutPriority, verifyPassword } from '@acorex-platform/framework-shared/core';
|
|
6
|
+
import { RootConfig } from '@acorex-platform/module-security-management-client/contracts';
|
|
8
7
|
import { AXPEntityService, AXP_ENTITY_STORAGE_MIDDLEWARE } from '@acorex-platform/framework-client/layout/entity';
|
|
9
8
|
import * as i0 from '@angular/core';
|
|
10
|
-
import { inject, Injectable, isDevMode, InjectionToken, NgModule, input, output, viewChild, viewChildren, signal, computed, effect, ChangeDetectionStrategy, Component, DestroyRef, ViewEncapsulation, ViewChild, Injector, afterNextRender,
|
|
11
|
-
import { first, isEmpty, isNil, isString, orderBy, get, defaultTo } from 'lodash';
|
|
12
|
-
import { AXDataSource } from '@acorex/cdk/common';
|
|
13
|
-
import { AXMAuthDataSourceKeys, AXPAuthSettings, AXMAuthCommandKeys } from '@acorex-platform/module-auth-client/contracts';
|
|
9
|
+
import { inject, Injectable, isDevMode, InjectionToken, NgModule, input, output, viewChild, viewChildren, signal, computed, effect, ChangeDetectionStrategy, Component, DestroyRef, ViewEncapsulation, ViewChild, Injector, afterNextRender, ApplicationRef } from '@angular/core';
|
|
14
10
|
import { AXPLayoutThemeService, AXPMenuVerticalMode } from '@acorex-platform/framework-client/themes/shared';
|
|
15
11
|
import { HttpErrorResponse } from '@angular/common/http';
|
|
16
|
-
import * as i1$
|
|
17
|
-
import { Router, RouterModule, ROUTES } from '@angular/router';
|
|
12
|
+
import * as i1$6 from '@angular/router';
|
|
13
|
+
import { Router, RouterModule, ROUTES, NavigationStart } from '@angular/router';
|
|
14
|
+
import { AXPAuthCredentialTypeOptions, AXP_AUTH_SIGN_IN_PAGE_SLOGAN_DEFAULT, AXP_AUTH_SIGN_IN_PAGE_DESCRIPTION_DEFAULT, AXPAuthSettings, AXMAuthCommandKeys } from '@acorex-platform/module-auth-client/contracts';
|
|
18
15
|
import * as i1 from '@acorex/core/validation';
|
|
19
16
|
import { AXValidationModule } from '@acorex/core/validation';
|
|
20
|
-
import
|
|
21
|
-
import
|
|
22
|
-
import {
|
|
17
|
+
import { isNil, isString, orderBy, isEmpty, get, defaultTo } from 'lodash';
|
|
18
|
+
import * as i1$4 from '@acorex-platform/framework-client/core';
|
|
19
|
+
import { axpApplicationLogoKey, AXPEntityLogoRegistrationService, AXPLogoComponent, axpTenantLogoKey, AXPHookService, AXPKeyboardShortcutRegistry, chordToKbdItemKeys, getPrimaryKeyboardShortcutChord, normalizeKeyboardShortcuts, AXPDeviceService, AXPComponentSlotModule, AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER, provideAppStartUpTask, AXP_APP_STARTUP_PRIORITY, provideLazyProvider, AXPComponentSlotDirective } from '@acorex-platform/framework-client/core';
|
|
20
|
+
import { AXPCommandService, provideQuerySetups, provideCommandSetups } from '@acorex-platform/framework-client/runtime';
|
|
23
21
|
import { AXPRootLayoutComponent } from '@acorex-platform/framework-client/themes/default';
|
|
24
|
-
import * as
|
|
25
|
-
import { CommonModule, AsyncPipe } from '@angular/common';
|
|
26
|
-
import { first
|
|
22
|
+
import * as i3 from '@angular/common';
|
|
23
|
+
import { CommonModule, AsyncPipe, Location } from '@angular/common';
|
|
24
|
+
import { first, filter, firstValueFrom, take, combineLatest, distinctUntilChanged, switchMap, EMPTY, from, timeout } from 'rxjs';
|
|
27
25
|
import * as i1$1 from '@acorex/components/button';
|
|
28
26
|
import { AXButtonModule } from '@acorex/components/button';
|
|
29
27
|
import * as i3$1 from '@acorex/components/decorators';
|
|
30
28
|
import { AXDecoratorModule } from '@acorex/components/decorators';
|
|
31
29
|
import * as i2$1 from '@acorex/components/popover';
|
|
32
30
|
import { AXPopoverModule } from '@acorex/components/popover';
|
|
33
|
-
import { RootConfig as RootConfig$
|
|
34
|
-
import * as
|
|
31
|
+
import { RootConfig as RootConfig$1 } from '@acorex-platform/module-application-management-client/contracts';
|
|
32
|
+
import * as i6 from '@acorex/cdk/list-navigation';
|
|
35
33
|
import { AXListNavigationDirective, AXListNavigationItemDirective, AXListNavigationModule } from '@acorex/cdk/list-navigation';
|
|
36
|
-
import * as
|
|
34
|
+
import * as i5 from '@acorex/components/search-box';
|
|
37
35
|
import { AXSearchBoxModule } from '@acorex/components/search-box';
|
|
38
|
-
import * as
|
|
36
|
+
import * as i4 from '@acorex/components/select-box';
|
|
39
37
|
import { AXSelectBoxModule } from '@acorex/components/select-box';
|
|
40
|
-
import * as i2 from '@acorex/components/
|
|
38
|
+
import * as i2 from '@acorex/components/loading';
|
|
39
|
+
import { AXLoadingModule } from '@acorex/components/loading';
|
|
40
|
+
import * as i1$2 from '@acorex/components/skeleton';
|
|
41
41
|
import { AXSkeletonModule } from '@acorex/components/skeleton';
|
|
42
|
-
import * as
|
|
43
|
-
import { AXTranslationModule, AXTranslationService } from '@acorex/core/translation';
|
|
42
|
+
import * as i5$1 from '@acorex/core/translation';
|
|
43
|
+
import { AXTranslationModule, AXTranslationService, resolveMultiLanguageString } from '@acorex/core/translation';
|
|
44
44
|
import { AXAvatarModule } from '@acorex/components/avatar';
|
|
45
45
|
import { AXImageModule } from '@acorex/components/image';
|
|
46
|
-
import { AXLoadingModule } from '@acorex/components/loading';
|
|
47
46
|
import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
48
|
-
import * as i1$
|
|
47
|
+
import * as i1$3 from '@angular/forms';
|
|
49
48
|
import { FormsModule } from '@angular/forms';
|
|
50
49
|
import { AXToastService } from '@acorex/components/toast';
|
|
51
50
|
import { AXMDeviceSessionsService } from '@acorex-platform/module-security-management-client';
|
|
52
51
|
import { AXOverlayService } from '@acorex/cdk/overlay';
|
|
53
52
|
import { AXPlatform } from '@acorex/core/platform';
|
|
53
|
+
import { PRESENCE_SET_AVAILABILITY } from '@acorex-platform/framework-shared/runtime';
|
|
54
54
|
|
|
55
55
|
//#region ---- Hook keys ----
|
|
56
56
|
const PROFILE_PAGE_GROUPS_HOOK = 'profile-page.groups';
|
|
@@ -69,6 +69,10 @@ function resolveUserProfileSectionContent(section) {
|
|
|
69
69
|
function isUserProfileGroupComponent(group) {
|
|
70
70
|
return group.content?.mode === 'component';
|
|
71
71
|
}
|
|
72
|
+
/** True when section hooks should run for `groupId` (all groups when the payload omits it). */
|
|
73
|
+
function isUserProfileSectionsGroupRequested(payload, groupId) {
|
|
74
|
+
return payload.groupId == null || payload.groupId === groupId;
|
|
75
|
+
}
|
|
72
76
|
/** Visible actions on a section card. */
|
|
73
77
|
function visibleUserProfileSectionActions(actions) {
|
|
74
78
|
return actions.filter((action) => action.visible !== false);
|
|
@@ -84,7 +88,6 @@ function resolveDefaultUserProfileSectionAction(actions) {
|
|
|
84
88
|
//#endregion
|
|
85
89
|
|
|
86
90
|
//#region ---- Avatar storage constants ----
|
|
87
|
-
const AXP_PROFILE_PHOTO_REF_TYPE = 'PersonCore.Person';
|
|
88
91
|
const AXP_PROFILE_PHOTO_USER_REF_TYPE = 'SecurityManagement.User';
|
|
89
92
|
const AXP_PROFILE_PHOTO_CATEGORY = 'profile-photo';
|
|
90
93
|
const FILE_STORAGE_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
@@ -134,11 +137,11 @@ function dataUrlToBlob(dataUrl) {
|
|
|
134
137
|
}
|
|
135
138
|
//#endregion
|
|
136
139
|
|
|
137
|
-
//#endregion
|
|
138
140
|
//#region ---- User avatar sync service (client) ----
|
|
139
141
|
/**
|
|
140
142
|
* Client-side profile photo operations for self-service flows.
|
|
141
|
-
*
|
|
143
|
+
* Canonical store is SecurityManagement.User.avatar; Person.image is mirrored
|
|
144
|
+
* on the server by HCM avatar sync middleware.
|
|
142
145
|
*/
|
|
143
146
|
class AXPUserAvatarSyncService {
|
|
144
147
|
constructor() {
|
|
@@ -146,30 +149,14 @@ class AXPUserAvatarSyncService {
|
|
|
146
149
|
this.entityService = inject(AXPEntityService);
|
|
147
150
|
this.fileStorage = inject(AXPFileStorageService);
|
|
148
151
|
this.sessionService = inject(AXPSessionService);
|
|
149
|
-
this.identityService = inject(AXPUserProfileIdentityService);
|
|
150
152
|
this.userAvatarService = inject(AXPUserAvatarService);
|
|
151
153
|
}
|
|
152
154
|
//#endregion
|
|
153
155
|
//#region ---- Public API ----
|
|
154
|
-
async resolveStorageTarget(userId) {
|
|
155
|
-
const person = await this.findPersonByUserId(userId);
|
|
156
|
-
if (person?.id) {
|
|
157
|
-
return { kind: 'person', personId: person.id, userId };
|
|
158
|
-
}
|
|
159
|
-
return { kind: 'user', userId };
|
|
160
|
-
}
|
|
161
156
|
async getCurrentAvatarRef(userId) {
|
|
162
157
|
const sessionUser = this.sessionService.user;
|
|
163
|
-
if (sessionUser?.id === userId) {
|
|
164
|
-
|
|
165
|
-
if (sessionRef) {
|
|
166
|
-
return sessionRef;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
const target = await this.resolveStorageTarget(userId);
|
|
170
|
-
if (target.kind === 'person') {
|
|
171
|
-
const person = await this.personData().byKey(target.personId);
|
|
172
|
-
return normalizeAvatarRef(person?.image);
|
|
158
|
+
if (sessionUser?.id === userId && sessionUser.avatar !== undefined) {
|
|
159
|
+
return normalizeAvatarRef(sessionUser.avatar);
|
|
173
160
|
}
|
|
174
161
|
const user = await this.userData().byKey(userId);
|
|
175
162
|
return normalizeAvatarRef(user?.avatar);
|
|
@@ -187,20 +174,23 @@ class AXPUserAvatarSyncService {
|
|
|
187
174
|
return response.blob();
|
|
188
175
|
}
|
|
189
176
|
if (isFileStorageId(ref)) {
|
|
190
|
-
|
|
177
|
+
try {
|
|
178
|
+
return await this.fileStorage.download(ref);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
191
183
|
}
|
|
192
184
|
return null;
|
|
193
185
|
}
|
|
194
186
|
async uploadAndSetAvatar(userId, file) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const refId = target.kind === 'person' ? target.personId : userId;
|
|
198
|
-
const refType = target.kind === 'person' ? AXP_PROFILE_PHOTO_REF_TYPE : AXP_PROFILE_PHOTO_USER_REF_TYPE;
|
|
187
|
+
// Save as Temporary; HCM UserAvatarSyncMiddleware commits on attach and
|
|
188
|
+
// removes the previous avatar file server-side (no client File:Remove).
|
|
199
189
|
const info = await this.fileStorage.save({
|
|
200
190
|
file,
|
|
201
191
|
name: file.name || 'profile-photo.png',
|
|
202
|
-
refId,
|
|
203
|
-
refType,
|
|
192
|
+
refId: userId,
|
|
193
|
+
refType: AXP_PROFILE_PHOTO_USER_REF_TYPE,
|
|
204
194
|
category: AXP_PROFILE_PHOTO_CATEGORY,
|
|
205
195
|
status: AXPFileStorageStatus.Temporary,
|
|
206
196
|
});
|
|
@@ -208,32 +198,14 @@ class AXPUserAvatarSyncService {
|
|
|
208
198
|
if (!fileId) {
|
|
209
199
|
throw new Error('File storage did not return a fileId.');
|
|
210
200
|
}
|
|
211
|
-
await this.
|
|
212
|
-
if (target.kind === 'person') {
|
|
213
|
-
await this.personData().update(target.personId, { image: fileId });
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
await this.userData().update(userId, { avatar: fileId });
|
|
217
|
-
}
|
|
201
|
+
await this.userData().update(userId, { avatar: fileId });
|
|
218
202
|
await this.notifyAvatarChanged(userId, fileId);
|
|
219
|
-
if (previousRef && isFileStorageId(previousRef) && previousRef !== fileId) {
|
|
220
|
-
await this.safeRemoveFile(previousRef);
|
|
221
|
-
}
|
|
222
203
|
return fileId;
|
|
223
204
|
}
|
|
224
205
|
async removeAvatar(userId) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if (target.kind === 'person') {
|
|
228
|
-
await this.personData().update(target.personId, { image: undefined });
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
231
|
-
await this.userData().update(userId, { avatar: null });
|
|
232
|
-
}
|
|
206
|
+
// Previous file cleanup runs in HCM avatar middleware when avatar is cleared.
|
|
207
|
+
await this.userData().update(userId, { avatar: null });
|
|
233
208
|
await this.notifyAvatarChanged(userId, null);
|
|
234
|
-
if (previousRef && isFileStorageId(previousRef)) {
|
|
235
|
-
await this.safeRemoveFile(previousRef);
|
|
236
|
-
}
|
|
237
209
|
}
|
|
238
210
|
/** Keeps session, avatar cache, and shell avatars in sync after any avatar change. */
|
|
239
211
|
async notifyAvatarChanged(userId, avatar) {
|
|
@@ -242,50 +214,49 @@ class AXPUserAvatarSyncService {
|
|
|
242
214
|
//#endregion
|
|
243
215
|
//#region ---- Private helpers ----
|
|
244
216
|
async refreshClientDisplay(userId, avatar) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
217
|
+
try {
|
|
218
|
+
const isCurrentUser = this.sessionService.user?.id === userId;
|
|
219
|
+
const session = isCurrentUser ? this.sessionService.getSessionData() : null;
|
|
220
|
+
if (avatar === null && session?.user?.avatar) {
|
|
221
|
+
this.userAvatarService.invalidateDisplayUrl(session.user.avatar);
|
|
222
|
+
}
|
|
223
|
+
if (isCurrentUser && session?.user) {
|
|
224
|
+
this.sessionService.setSession({
|
|
225
|
+
...session,
|
|
226
|
+
user: {
|
|
227
|
+
...session.user,
|
|
228
|
+
avatar,
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
const sessionUser = isCurrentUser ? this.sessionService.user : null;
|
|
233
|
+
const displayName = sessionUser?.title || sessionUser?.name || '';
|
|
234
|
+
const parts = displayName.trim().split(/\s+/).filter(Boolean);
|
|
235
|
+
const patch = {
|
|
236
|
+
id: userId,
|
|
237
|
+
status: 'offline',
|
|
238
|
+
username: sessionUser?.name || '',
|
|
239
|
+
firstName: parts[0] ?? '',
|
|
240
|
+
lastName: parts.slice(1).join(' '),
|
|
241
|
+
};
|
|
242
|
+
if (avatar) {
|
|
243
|
+
patch.avatarUrl = avatar;
|
|
244
|
+
}
|
|
245
|
+
this.userAvatarService.patchCachedUser(userId, patch);
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
console.warn('Avatar display refresh failed after profile photo change', error);
|
|
250
249
|
}
|
|
251
|
-
this.userAvatarService.clearCache(userId);
|
|
252
|
-
await this.userAvatarService.refreshUserInfo(userId);
|
|
253
|
-
}
|
|
254
|
-
personData() {
|
|
255
|
-
return this.entityService
|
|
256
|
-
.withEntity(RootConfig.module.name, RootConfig.entities.person.name)
|
|
257
|
-
.data();
|
|
258
250
|
}
|
|
259
251
|
userData() {
|
|
260
252
|
return this.entityService
|
|
261
|
-
.withEntity(RootConfig
|
|
253
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.users.name)
|
|
262
254
|
.data();
|
|
263
255
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
filter: { field: 'userId', operator: { type: 'equal' }, value: userId },
|
|
267
|
-
take: 1,
|
|
268
|
-
skip: 0,
|
|
269
|
-
});
|
|
270
|
-
return first(result.items) ?? null;
|
|
271
|
-
}
|
|
272
|
-
async safeRemoveFile(fileId) {
|
|
273
|
-
try {
|
|
274
|
-
await this.fileStorage.remove(fileId);
|
|
275
|
-
}
|
|
276
|
-
catch {
|
|
277
|
-
try {
|
|
278
|
-
await this.fileStorage.markForDeletion(fileId);
|
|
279
|
-
}
|
|
280
|
-
catch {
|
|
281
|
-
/* ignore cleanup failures */
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPUserAvatarSyncService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
286
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPUserAvatarSyncService, providedIn: 'root' }); }
|
|
256
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPUserAvatarSyncService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
257
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPUserAvatarSyncService, providedIn: 'root' }); }
|
|
287
258
|
}
|
|
288
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
259
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPUserAvatarSyncService, decorators: [{
|
|
289
260
|
type: Injectable,
|
|
290
261
|
args: [{ providedIn: 'root' }]
|
|
291
262
|
}] });
|
|
@@ -508,144 +479,6 @@ function extractUserActivityEndDate(filter) {
|
|
|
508
479
|
}
|
|
509
480
|
//#endregion
|
|
510
481
|
|
|
511
|
-
//#region ---- User activity data source ----
|
|
512
|
-
function resolveLoadParams(request) {
|
|
513
|
-
const userId = extractUserActivityUserId(request?.filter);
|
|
514
|
-
if (isEmpty(userId)) {
|
|
515
|
-
return null;
|
|
516
|
-
}
|
|
517
|
-
const defaultRange = resolveDefaultUserActivityDateRange();
|
|
518
|
-
const startDate = extractUserActivityStartDate(request?.filter) ?? defaultRange.startDate;
|
|
519
|
-
const endDate = extractUserActivityEndDate(request?.filter) ?? defaultRange.endDate;
|
|
520
|
-
return {
|
|
521
|
-
userId: userId,
|
|
522
|
-
startDate,
|
|
523
|
-
endDate,
|
|
524
|
-
};
|
|
525
|
-
}
|
|
526
|
-
/** Contribution-style user activity heatmap derived from device session sign-in dates. */
|
|
527
|
-
class AXMUserActivityDataSourceDefinition {
|
|
528
|
-
constructor() {
|
|
529
|
-
//#region ---- Services & Dependencies ----
|
|
530
|
-
this.entityService = inject(AXPEntityService);
|
|
531
|
-
//#endregion
|
|
532
|
-
}
|
|
533
|
-
//#endregion
|
|
534
|
-
//#region ---- Public API ----
|
|
535
|
-
items() {
|
|
536
|
-
const sampleParams = resolveDefaultUserActivityDateRange();
|
|
537
|
-
const sampleItem = buildUserActivityDataSourceItem({ userId: 'sample-user', ...sampleParams }, []);
|
|
538
|
-
return Promise.resolve([
|
|
539
|
-
{
|
|
540
|
-
name: AXMAuthDataSourceKeys.UserActivity,
|
|
541
|
-
title: 'User Activity',
|
|
542
|
-
columns: [
|
|
543
|
-
{
|
|
544
|
-
name: 'id',
|
|
545
|
-
title: 'ID',
|
|
546
|
-
datatype: 'string',
|
|
547
|
-
type: AXPWidgetsCatalog.text,
|
|
548
|
-
},
|
|
549
|
-
{
|
|
550
|
-
name: 'userId',
|
|
551
|
-
title: 'User ID',
|
|
552
|
-
datatype: 'string',
|
|
553
|
-
type: AXPWidgetsCatalog.text,
|
|
554
|
-
},
|
|
555
|
-
{
|
|
556
|
-
name: 'startDate',
|
|
557
|
-
title: 'Start Date',
|
|
558
|
-
datatype: 'date',
|
|
559
|
-
type: AXPWidgetsCatalog.dateTime,
|
|
560
|
-
},
|
|
561
|
-
{
|
|
562
|
-
name: 'endDate',
|
|
563
|
-
title: 'End Date',
|
|
564
|
-
datatype: 'date',
|
|
565
|
-
type: AXPWidgetsCatalog.dateTime,
|
|
566
|
-
},
|
|
567
|
-
],
|
|
568
|
-
filters: [
|
|
569
|
-
{
|
|
570
|
-
field: 'userId',
|
|
571
|
-
title: 'User',
|
|
572
|
-
operator: { type: 'equal' },
|
|
573
|
-
widget: { type: AXPWidgetsCatalog.text },
|
|
574
|
-
filterType: { advance: true, inline: true },
|
|
575
|
-
},
|
|
576
|
-
{
|
|
577
|
-
field: 'startDate',
|
|
578
|
-
title: 'Start Date',
|
|
579
|
-
operator: { type: 'gte' },
|
|
580
|
-
widget: { type: AXPWidgetsCatalog.dateTime, options: { format: 'date' } },
|
|
581
|
-
filterType: { advance: true, inline: true },
|
|
582
|
-
},
|
|
583
|
-
{
|
|
584
|
-
field: 'endDate',
|
|
585
|
-
title: 'End Date',
|
|
586
|
-
operator: { type: 'lte' },
|
|
587
|
-
widget: { type: AXPWidgetsCatalog.dateTime, options: { format: 'date' } },
|
|
588
|
-
filterType: { advance: true, inline: true },
|
|
589
|
-
},
|
|
590
|
-
],
|
|
591
|
-
textField: { name: 'id', title: 'ID' },
|
|
592
|
-
valueField: { name: 'id', title: 'ID' },
|
|
593
|
-
samples: [sampleItem],
|
|
594
|
-
source: () => new AXDataSource({
|
|
595
|
-
key: 'id',
|
|
596
|
-
pageSize: 1,
|
|
597
|
-
load: async (request) => {
|
|
598
|
-
const params = resolveLoadParams(request);
|
|
599
|
-
if (!params) {
|
|
600
|
-
return { items: [], total: 0 };
|
|
601
|
-
}
|
|
602
|
-
const sessions = await this.loadUserSessions(params.userId);
|
|
603
|
-
const item = buildUserActivityDataSourceItem(params, sessions);
|
|
604
|
-
return { items: [item], total: 1 };
|
|
605
|
-
},
|
|
606
|
-
}),
|
|
607
|
-
},
|
|
608
|
-
]);
|
|
609
|
-
}
|
|
610
|
-
//#endregion
|
|
611
|
-
//#region ---- Private Methods ----
|
|
612
|
-
async loadUserSessions(userId) {
|
|
613
|
-
const response = await this.entityService
|
|
614
|
-
.withEntity(RootConfig$1.module.name, RootConfig$1.entities.deviceSessions.name)
|
|
615
|
-
.data()
|
|
616
|
-
.query({
|
|
617
|
-
skip: 0,
|
|
618
|
-
take: 1000,
|
|
619
|
-
filter: {
|
|
620
|
-
field: 'userId',
|
|
621
|
-
operator: { type: 'equal' },
|
|
622
|
-
value: userId,
|
|
623
|
-
},
|
|
624
|
-
});
|
|
625
|
-
return response.items ?? [];
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
//#endregion
|
|
629
|
-
|
|
630
|
-
//#region ---- Auth data source provider ----
|
|
631
|
-
/**
|
|
632
|
-
* Registers auth module data source definitions.
|
|
633
|
-
*/
|
|
634
|
-
class AXMAuthDataSourceProvider {
|
|
635
|
-
constructor() {
|
|
636
|
-
this.userActivity = new AXMUserActivityDataSourceDefinition();
|
|
637
|
-
}
|
|
638
|
-
async items() {
|
|
639
|
-
return [...(await this.userActivity.items())];
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
//#endregion
|
|
643
|
-
|
|
644
|
-
var datasource_provider = /*#__PURE__*/Object.freeze({
|
|
645
|
-
__proto__: null,
|
|
646
|
-
AXMAuthDataSourceProvider: AXMAuthDataSourceProvider
|
|
647
|
-
});
|
|
648
|
-
|
|
649
482
|
class AXMAuthErrorHandler {
|
|
650
483
|
constructor() {
|
|
651
484
|
this.router = inject(Router);
|
|
@@ -680,26 +513,46 @@ class AXMAuthErrorHandler {
|
|
|
680
513
|
}
|
|
681
514
|
this.layoutService.setNavigationLoading(false);
|
|
682
515
|
}
|
|
683
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
684
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
516
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthErrorHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
517
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthErrorHandler }); }
|
|
685
518
|
}
|
|
686
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
519
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthErrorHandler, decorators: [{
|
|
687
520
|
type: Injectable
|
|
688
521
|
}] });
|
|
689
522
|
|
|
523
|
+
//#region ----- Login page guard -----
|
|
690
524
|
/**
|
|
691
|
-
*
|
|
692
|
-
*
|
|
525
|
+
* Login page guard.
|
|
526
|
+
* If the user already has a cookie session but has not finished tenant/app binding,
|
|
527
|
+
* send them to the chooser — never destroy the session.
|
|
528
|
+
* If the session is fully bound, send them home (do not show login again).
|
|
693
529
|
*/
|
|
694
|
-
const canActivateLogin = async (
|
|
530
|
+
const canActivateLogin = async (_route, _state) => {
|
|
695
531
|
const sessionService = inject(AXPSessionService);
|
|
532
|
+
const homePageService = inject(AXPHomePageService);
|
|
533
|
+
const platformSettingsLoadState = inject(AXPPlatformSettingsLoadState);
|
|
534
|
+
const router = inject(Router);
|
|
535
|
+
if (platformSettingsLoadState.hasFailure()) {
|
|
536
|
+
return router.createUrlTree(['/auth/unavailable']);
|
|
537
|
+
}
|
|
696
538
|
const session = sessionService.getSessionData();
|
|
697
|
-
if (session?.user?.id &&
|
|
698
|
-
|
|
539
|
+
if (session?.user?.id && session.cookieSession) {
|
|
540
|
+
if (!session.tenant?.id) {
|
|
541
|
+
return router.createUrlTree(['/auth/account/tenant-chooser']);
|
|
542
|
+
}
|
|
543
|
+
if (!session.application?.id) {
|
|
544
|
+
return router.createUrlTree(['/auth/account/app-chooser']);
|
|
545
|
+
}
|
|
546
|
+
if (sessionService.isAuthorized && sessionService.application?.name) {
|
|
547
|
+
return homePageService.resolveAuthorizedHomeUrlTree();
|
|
548
|
+
}
|
|
549
|
+
return router.createUrlTree(['/auth/account/app-chooser']);
|
|
699
550
|
}
|
|
700
551
|
return true;
|
|
701
552
|
};
|
|
553
|
+
//#endregion
|
|
702
554
|
|
|
555
|
+
//#region ----- Authentication types -----
|
|
703
556
|
var AXMAuthenticationTypes;
|
|
704
557
|
(function (AXMAuthenticationTypes) {
|
|
705
558
|
AXMAuthenticationTypes[AXMAuthenticationTypes["UsernamePassword"] = 0] = "UsernamePassword";
|
|
@@ -709,21 +562,35 @@ var AXMAuthenticationTypes;
|
|
|
709
562
|
AXMAuthenticationTypes[AXMAuthenticationTypes["EmailCode"] = 4] = "EmailCode";
|
|
710
563
|
AXMAuthenticationTypes[AXMAuthenticationTypes["MobileCode"] = 5] = "MobileCode";
|
|
711
564
|
})(AXMAuthenticationTypes || (AXMAuthenticationTypes = {}));
|
|
565
|
+
/** Map persisted credential-type setting values to {@link AXMAuthenticationTypes}. */
|
|
566
|
+
function parseAuthCredentialType(value) {
|
|
567
|
+
const raw = typeof value === 'string' ? value.trim() : '';
|
|
568
|
+
switch (raw) {
|
|
569
|
+
case AXPAuthCredentialTypeOptions.UsernameEmailPassword:
|
|
570
|
+
return AXMAuthenticationTypes.UsernameEmailPassword;
|
|
571
|
+
case AXPAuthCredentialTypeOptions.EmailPassword:
|
|
572
|
+
return AXMAuthenticationTypes.EmailPassword;
|
|
573
|
+
case AXPAuthCredentialTypeOptions.MobilePassword:
|
|
574
|
+
return AXMAuthenticationTypes.MobilePassword;
|
|
575
|
+
case AXPAuthCredentialTypeOptions.EmailCode:
|
|
576
|
+
return AXMAuthenticationTypes.EmailCode;
|
|
577
|
+
case AXPAuthCredentialTypeOptions.MobileCode:
|
|
578
|
+
return AXMAuthenticationTypes.MobileCode;
|
|
579
|
+
case AXPAuthCredentialTypeOptions.UsernamePassword:
|
|
580
|
+
default:
|
|
581
|
+
return AXMAuthenticationTypes.UsernamePassword;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
712
584
|
const AXM_AUTH_CONFIG_TOKEN = new InjectionToken('app-module-auth-config', {
|
|
713
585
|
providedIn: 'root',
|
|
714
|
-
factory: () =>
|
|
715
|
-
return AXMDefaultAuthConfigs;
|
|
716
|
-
},
|
|
586
|
+
factory: () => AXMDefaultAuthConfigs,
|
|
717
587
|
});
|
|
718
|
-
const AXMDefaultAuthConfigs = {
|
|
719
|
-
type: AXMAuthenticationTypes.UsernamePassword,
|
|
720
|
-
// defaultStrategyName:'oidc',
|
|
721
|
-
// حذف authConfig از اینجا چون از environment خوانده میشود
|
|
722
|
-
defaultStrategyName: 'user-pass',
|
|
723
|
-
};
|
|
588
|
+
const AXMDefaultAuthConfigs = {};
|
|
724
589
|
function configAuthModule(config = AXMDefaultAuthConfigs) {
|
|
725
590
|
return { ...AXMDefaultAuthConfigs, ...config };
|
|
726
591
|
}
|
|
592
|
+
//#endregion
|
|
593
|
+
//#region ----- Login Guard Token -----
|
|
727
594
|
/**
|
|
728
595
|
* Injection token for login page guard.
|
|
729
596
|
* Apps can provide their own custom guard by providing this token.
|
|
@@ -735,6 +602,76 @@ const AXM_LOGIN_GUARD_TOKEN = new InjectionToken('AXM_LOGIN_GUARD_TOKEN', {
|
|
|
735
602
|
});
|
|
736
603
|
//#endregion
|
|
737
604
|
|
|
605
|
+
//#region ----- Constants -----
|
|
606
|
+
const DEFAULT_SLOGAN = AXP_AUTH_SIGN_IN_PAGE_SLOGAN_DEFAULT;
|
|
607
|
+
const DEFAULT_DESCRIPTION = AXP_AUTH_SIGN_IN_PAGE_DESCRIPTION_DEFAULT;
|
|
608
|
+
const DEFAULT_STRATEGY = 'user-pass';
|
|
609
|
+
const DEFAULT_SIGNUP_URL = '/auth/register';
|
|
610
|
+
//#endregion
|
|
611
|
+
//#region ----- Auth platform settings (P) -----
|
|
612
|
+
/**
|
|
613
|
+
* Reads public platform auth UI settings loaded during app startup.
|
|
614
|
+
* Slogan and description are multi-language strings.
|
|
615
|
+
*/
|
|
616
|
+
class AXMAuthPlatformSettingsService {
|
|
617
|
+
constructor() {
|
|
618
|
+
this.settings = inject(AXPSettingsService);
|
|
619
|
+
}
|
|
620
|
+
//#region ----- Sign-in page -----
|
|
621
|
+
slogan() {
|
|
622
|
+
return this.readMls(AXPAuthSettings.SignInPageSlogan, DEFAULT_SLOGAN);
|
|
623
|
+
}
|
|
624
|
+
description() {
|
|
625
|
+
return this.readMls(AXPAuthSettings.SignInPageDescription, DEFAULT_DESCRIPTION);
|
|
626
|
+
}
|
|
627
|
+
//#endregion
|
|
628
|
+
//#region ----- Sign-up -----
|
|
629
|
+
signupEnabled() {
|
|
630
|
+
const value = this.settings.peekCached(AXPAuthSettings.SignUpEnabled);
|
|
631
|
+
return value === true || value === 'true';
|
|
632
|
+
}
|
|
633
|
+
signupUrl() {
|
|
634
|
+
const value = this.settings.peekCached(AXPAuthSettings.SignUpUrl);
|
|
635
|
+
if (typeof value === 'string' && value.trim()) {
|
|
636
|
+
return value.trim();
|
|
637
|
+
}
|
|
638
|
+
return DEFAULT_SIGNUP_URL;
|
|
639
|
+
}
|
|
640
|
+
//#endregion
|
|
641
|
+
//#region ----- Sign-in -----
|
|
642
|
+
credentialType() {
|
|
643
|
+
return parseAuthCredentialType(this.settings.peekCached(AXPAuthSettings.SignInCredentialType));
|
|
644
|
+
}
|
|
645
|
+
defaultStrategyName() {
|
|
646
|
+
const value = this.settings.peekCached(AXPAuthSettings.SignInDefaultStrategy);
|
|
647
|
+
if (typeof value === 'string' && value.trim()) {
|
|
648
|
+
return value.trim();
|
|
649
|
+
}
|
|
650
|
+
return DEFAULT_STRATEGY;
|
|
651
|
+
}
|
|
652
|
+
//#endregion
|
|
653
|
+
//#region ----- Private -----
|
|
654
|
+
readMls(key, fallback) {
|
|
655
|
+
const value = this.settings.peekCached(key);
|
|
656
|
+
if (value == null || value === '') {
|
|
657
|
+
return fallback;
|
|
658
|
+
}
|
|
659
|
+
if (typeof value === 'string') {
|
|
660
|
+
return value;
|
|
661
|
+
}
|
|
662
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
663
|
+
return value;
|
|
664
|
+
}
|
|
665
|
+
return fallback;
|
|
666
|
+
}
|
|
667
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthPlatformSettingsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
668
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthPlatformSettingsService, providedIn: 'root' }); }
|
|
669
|
+
}
|
|
670
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthPlatformSettingsService, decorators: [{
|
|
671
|
+
type: Injectable,
|
|
672
|
+
args: [{ providedIn: 'root' }]
|
|
673
|
+
}] });
|
|
674
|
+
|
|
738
675
|
//#region ---- Types ----
|
|
739
676
|
const AXPAuthPasswordComplexityLevels = {
|
|
740
677
|
Low: 'Low',
|
|
@@ -852,10 +789,10 @@ class AXPAuthPasswordComplexityService {
|
|
|
852
789
|
const effectiveValue = await this.settingsService.get(AXPAuthSettings.PasswordComplexity);
|
|
853
790
|
return normalizePasswordComplexityLevel(effectiveValue);
|
|
854
791
|
}
|
|
855
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
856
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
792
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAuthPasswordComplexityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
793
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAuthPasswordComplexityService, providedIn: 'root' }); }
|
|
857
794
|
}
|
|
858
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
795
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAuthPasswordComplexityService, decorators: [{
|
|
859
796
|
type: Injectable,
|
|
860
797
|
args: [{ providedIn: 'root' }]
|
|
861
798
|
}] });
|
|
@@ -899,22 +836,22 @@ class PasswordComplexityValidationRule {
|
|
|
899
836
|
}
|
|
900
837
|
return this.passwordComplexityService.getLevel();
|
|
901
838
|
}
|
|
902
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
903
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
839
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PasswordComplexityValidationRule, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
840
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PasswordComplexityValidationRule }); }
|
|
904
841
|
}
|
|
905
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
842
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PasswordComplexityValidationRule, decorators: [{
|
|
906
843
|
type: Injectable
|
|
907
844
|
}] });
|
|
908
845
|
|
|
909
846
|
//#region ---- Auth Validation Rules Module ----
|
|
910
847
|
class AXMAuthValidationRulesModule {
|
|
911
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
912
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "
|
|
913
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "
|
|
848
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthValidationRulesModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
849
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthValidationRulesModule, imports: [i1.AXValidationModule] }); }
|
|
850
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthValidationRulesModule, imports: [AXValidationModule.forChild({
|
|
914
851
|
rules: [PasswordComplexityValidationRule],
|
|
915
852
|
})] }); }
|
|
916
853
|
}
|
|
917
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
854
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthValidationRulesModule, decorators: [{
|
|
918
855
|
type: NgModule,
|
|
919
856
|
args: [{
|
|
920
857
|
imports: [
|
|
@@ -934,34 +871,38 @@ const routes = [
|
|
|
934
871
|
pathMatch: 'full',
|
|
935
872
|
redirectTo: 'login',
|
|
936
873
|
},
|
|
874
|
+
{
|
|
875
|
+
path: 'unavailable',
|
|
876
|
+
loadComponent: () => import('./acorex-platform-module-auth-client-platform-settings-unavailable.component-BEVkQ3jh.mjs').then((c) => c.AXMPlatformSettingsUnavailableComponent),
|
|
877
|
+
},
|
|
937
878
|
{
|
|
938
879
|
path: '',
|
|
939
|
-
loadComponent: () => import('./acorex-platform-module-auth-client-master.layout-
|
|
940
|
-
loadChildren: () => import('./acorex-platform-module-auth-client-login.module-
|
|
880
|
+
loadComponent: () => import('./acorex-platform-module-auth-client-master.layout-DZUYm22p.mjs').then((c) => c.AXPAuthMasterLayoutComponent),
|
|
881
|
+
loadChildren: () => import('./acorex-platform-module-auth-client-login.module-DJVL3bAF.mjs').then((c) => c.AXPSignInModule),
|
|
941
882
|
},
|
|
942
883
|
{
|
|
943
884
|
path: '',
|
|
944
|
-
loadComponent: () => import('./acorex-platform-module-auth-client-master.layout-
|
|
945
|
-
loadChildren: () => import('./acorex-platform-module-auth-client-two-factor.module-
|
|
885
|
+
loadComponent: () => import('./acorex-platform-module-auth-client-master.layout-DZUYm22p.mjs').then((c) => c.AXPAuthMasterLayoutComponent),
|
|
886
|
+
loadChildren: () => import('./acorex-platform-module-auth-client-two-factor.module-_jYo6xXr.mjs').then((c) => c.AXPTwoFactorModule),
|
|
946
887
|
},
|
|
947
888
|
{
|
|
948
889
|
path: '',
|
|
949
|
-
loadComponent: () => import('./acorex-platform-module-auth-client-master.layout-
|
|
950
|
-
loadChildren: () => import('./acorex-platform-module-auth-client-routes-
|
|
890
|
+
loadComponent: () => import('./acorex-platform-module-auth-client-master.layout-DZUYm22p.mjs').then((c) => c.AXPAuthMasterLayoutComponent),
|
|
891
|
+
loadChildren: () => import('./acorex-platform-module-auth-client-routes-IX2qmeqU.mjs').then((c) => c),
|
|
951
892
|
},
|
|
952
893
|
{
|
|
953
|
-
path: '
|
|
954
|
-
loadComponent: () => import('./acorex-platform-module-auth-client-oauth-callback.component-
|
|
894
|
+
path: 'oauth-callback',
|
|
895
|
+
loadComponent: () => import('./acorex-platform-module-auth-client-oauth-callback.component-DnQzPUxF.mjs').then((c) => c.AXPOAuthCallbackComponent),
|
|
955
896
|
},
|
|
956
897
|
{
|
|
957
898
|
path: 'account',
|
|
958
|
-
loadComponent: () => import('./acorex-platform-module-auth-client-blank.layout-
|
|
899
|
+
loadComponent: () => import('./acorex-platform-module-auth-client-blank.layout-BCXNPgrp.mjs').then((c) => c.AXPAuthBlankLayoutComponent),
|
|
959
900
|
loadChildren: () => Promise.resolve().then(function () { return account_module; }).then((c) => c.AXPAccountModule),
|
|
960
901
|
},
|
|
961
902
|
{
|
|
962
903
|
path: '',
|
|
963
|
-
loadComponent: () => import('./acorex-platform-module-auth-client-master.layout-
|
|
964
|
-
loadChildren: () => import('./acorex-platform-module-auth-client-register.module
|
|
904
|
+
loadComponent: () => import('./acorex-platform-module-auth-client-master.layout-DZUYm22p.mjs').then((c) => c.AXPAuthMasterLayoutComponent),
|
|
905
|
+
loadChildren: () => import('./acorex-platform-module-auth-client-register.module-BrXqva0B.mjs').then((c) => c.AXPRegisterModule),
|
|
965
906
|
},
|
|
966
907
|
],
|
|
967
908
|
},
|
|
@@ -985,26 +926,43 @@ class AXPAppChooserListComponent {
|
|
|
985
926
|
this.homePageService = inject(AXPHomePageService);
|
|
986
927
|
this.authStrategyRegistry = inject(AXPAuthStrategyRegistryService);
|
|
987
928
|
this.logoRegistration = inject(AXPEntityLogoRegistrationService);
|
|
988
|
-
this.applicationService = this.entityService.withEntity(RootConfig$
|
|
929
|
+
this.applicationService = this.entityService.withEntity(RootConfig$1.module.name, RootConfig$1.entities.application.name).data();
|
|
989
930
|
this.strategyName = this.sessionService.getSessionData()?.strategy;
|
|
990
931
|
this.strategy = this.authStrategyRegistry.get(this.strategyName);
|
|
991
932
|
//#endregion
|
|
992
933
|
//#region ---- Inputs & Outputs ----
|
|
993
|
-
this.simple = input(false,
|
|
934
|
+
this.simple = input(false, /* @ts-ignore */
|
|
935
|
+
...(ngDevMode ? [{ debugName: "simple" }] : /* istanbul ignore next */ []));
|
|
994
936
|
this.applicationChosen = output();
|
|
937
|
+
this.loadingChange = output();
|
|
995
938
|
//#endregion
|
|
996
939
|
//#region ---- View References ----
|
|
997
|
-
this.listNav = viewChild(AXListNavigationDirective,
|
|
998
|
-
|
|
940
|
+
this.listNav = viewChild(AXListNavigationDirective, /* @ts-ignore */
|
|
941
|
+
...(ngDevMode ? [{ debugName: "listNav" }] : /* istanbul ignore next */ []));
|
|
942
|
+
this.listItems = viewChildren(AXListNavigationItemDirective, /* @ts-ignore */
|
|
943
|
+
...(ngDevMode ? [{ debugName: "listItems" }] : /* istanbul ignore next */ []));
|
|
999
944
|
//#endregion
|
|
1000
945
|
//#region ---- State ----
|
|
1001
|
-
this.isLoading = signal(true,
|
|
1002
|
-
|
|
1003
|
-
this.
|
|
1004
|
-
|
|
1005
|
-
this.
|
|
1006
|
-
|
|
946
|
+
this.isLoading = signal(true, /* @ts-ignore */
|
|
947
|
+
...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
|
|
948
|
+
this.isChoosing = signal(false, /* @ts-ignore */
|
|
949
|
+
...(ngDevMode ? [{ debugName: "isChoosing" }] : /* istanbul ignore next */ []));
|
|
950
|
+
this.choosingId = signal(null, /* @ts-ignore */
|
|
951
|
+
...(ngDevMode ? [{ debugName: "choosingId" }] : /* istanbul ignore next */ []));
|
|
952
|
+
this.allApplications = signal([], /* @ts-ignore */
|
|
953
|
+
...(ngDevMode ? [{ debugName: "allApplications" }] : /* istanbul ignore next */ []));
|
|
954
|
+
this.useSelectBox = computed(() => this.allApplications().length > 3, /* @ts-ignore */
|
|
955
|
+
...(ngDevMode ? [{ debugName: "useSelectBox" }] : /* istanbul ignore next */ []));
|
|
956
|
+
this.selectedApplication = signal(null, /* @ts-ignore */
|
|
957
|
+
...(ngDevMode ? [{ debugName: "selectedApplication" }] : /* istanbul ignore next */ []));
|
|
958
|
+
this.isSelectBoxOpen = signal(false, /* @ts-ignore */
|
|
959
|
+
...(ngDevMode ? [{ debugName: "isSelectBoxOpen" }] : /* istanbul ignore next */ []));
|
|
960
|
+
this.canApply = computed(() => !!this.selectedApplication(), /* @ts-ignore */
|
|
961
|
+
...(ngDevMode ? [{ debugName: "canApply" }] : /* istanbul ignore next */ []));
|
|
1007
962
|
this.skeletonItems = [1, 2, 3];
|
|
963
|
+
effect(() => {
|
|
964
|
+
this.loadingChange.emit(this.isLoading());
|
|
965
|
+
});
|
|
1008
966
|
effect(() => {
|
|
1009
967
|
if (!this.isLoading() && !this.useSelectBox() && this.allApplications().length > 0) {
|
|
1010
968
|
queueMicrotask(() => this.focusFirstListItem());
|
|
@@ -1014,7 +972,7 @@ class AXPAppChooserListComponent {
|
|
|
1014
972
|
//#endregion
|
|
1015
973
|
//#region ---- Lifecycle Methods ----
|
|
1016
974
|
ngOnInit() {
|
|
1017
|
-
this.sessionService.applications$.pipe(first
|
|
975
|
+
this.sessionService.applications$.pipe(first()).subscribe((applications) => {
|
|
1018
976
|
this.logoRegistration.registerApplications(applications);
|
|
1019
977
|
this.allApplications.set(applications);
|
|
1020
978
|
if (applications.length > 0) {
|
|
@@ -1054,43 +1012,64 @@ class AXPAppChooserListComponent {
|
|
|
1054
1012
|
}
|
|
1055
1013
|
}
|
|
1056
1014
|
applySelection() {
|
|
1015
|
+
if (this.isChoosing()) {
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1057
1018
|
const application = this.selectedApplication();
|
|
1058
1019
|
if (application) {
|
|
1059
1020
|
void this.chooseApplication(application);
|
|
1060
1021
|
}
|
|
1061
1022
|
}
|
|
1062
1023
|
async chooseApplication(item) {
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
throw new Error('Tenant ID is missing. Cannot choose application.');
|
|
1066
|
-
}
|
|
1067
|
-
const fullApplication = await this.applicationService.byKey(item.id);
|
|
1068
|
-
if (!fullApplication) {
|
|
1069
|
-
throw new Error(`Application not found: ${item.id}`);
|
|
1070
|
-
}
|
|
1071
|
-
let selectedEdition = item.edition;
|
|
1072
|
-
if (!selectedEdition && fullApplication.editions && fullApplication.editions.length > 0) {
|
|
1073
|
-
selectedEdition = {
|
|
1074
|
-
id: fullApplication.editions[0].id,
|
|
1075
|
-
title: fullApplication.editions[0].title,
|
|
1076
|
-
description: fullApplication.editions[0].description,
|
|
1077
|
-
};
|
|
1024
|
+
if (this.isChoosing()) {
|
|
1025
|
+
return;
|
|
1078
1026
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1027
|
+
this.isChoosing.set(true);
|
|
1028
|
+
this.choosingId.set(item.id);
|
|
1029
|
+
try {
|
|
1030
|
+
const tenantId = this.sessionService.tenant?.id || '';
|
|
1031
|
+
if (!tenantId) {
|
|
1032
|
+
throw new Error('Tenant ID is missing. Cannot choose application.');
|
|
1033
|
+
}
|
|
1034
|
+
let applicationWithEdition = { ...item };
|
|
1035
|
+
if (this.strategy && typeof this.strategy.updateToken === 'function') {
|
|
1036
|
+
await this.sessionService.updateToken({
|
|
1037
|
+
application: applicationWithEdition,
|
|
1038
|
+
user: this.sessionService.user,
|
|
1039
|
+
tenant: this.sessionService.tenant,
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
if (!applicationWithEdition.edition) {
|
|
1043
|
+
const fullApplication = await this.applicationService.byKey(item.id);
|
|
1044
|
+
if (!fullApplication) {
|
|
1045
|
+
throw new Error(`Application not found: ${item.id}`);
|
|
1046
|
+
}
|
|
1047
|
+
if (fullApplication.editions && fullApplication.editions.length > 0) {
|
|
1048
|
+
applicationWithEdition = {
|
|
1049
|
+
...applicationWithEdition,
|
|
1050
|
+
version: fullApplication.version || applicationWithEdition.version,
|
|
1051
|
+
edition: {
|
|
1052
|
+
id: fullApplication.editions[0].id,
|
|
1053
|
+
title: fullApplication.editions[0].title,
|
|
1054
|
+
description: fullApplication.editions[0].description,
|
|
1055
|
+
},
|
|
1056
|
+
};
|
|
1057
|
+
if (this.strategy && typeof this.strategy.updateToken === 'function') {
|
|
1058
|
+
await this.sessionService.updateToken({
|
|
1059
|
+
application: applicationWithEdition,
|
|
1060
|
+
user: this.sessionService.user,
|
|
1061
|
+
tenant: this.sessionService.tenant,
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
this.applicationChosen.emit();
|
|
1067
|
+
await this.homePageService.navigateTo();
|
|
1068
|
+
}
|
|
1069
|
+
finally {
|
|
1070
|
+
this.isChoosing.set(false);
|
|
1071
|
+
this.choosingId.set(null);
|
|
1091
1072
|
}
|
|
1092
|
-
this.applicationChosen.emit();
|
|
1093
|
-
await this.homePageService.navigateTo();
|
|
1094
1073
|
}
|
|
1095
1074
|
//#endregion
|
|
1096
1075
|
//#region ---- Utility Methods ----
|
|
@@ -1103,39 +1082,41 @@ class AXPAppChooserListComponent {
|
|
|
1103
1082
|
nav.navigateTo(items[currentIndex >= 0 ? currentIndex : 0]);
|
|
1104
1083
|
}
|
|
1105
1084
|
}
|
|
1106
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1107
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1085
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAppChooserListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1086
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPAppChooserListComponent, isStandalone: true, selector: "axp-app-chooser-list", inputs: { simple: { classPropertyName: "simple", publicName: "simple", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { applicationChosen: "applicationChosen", loadingChange: "loadingChange" }, viewQueries: [{ propertyName: "listNav", first: true, predicate: AXListNavigationDirective, descendants: true, isSignal: true }, { propertyName: "listItems", predicate: AXListNavigationItemDirective, descendants: true, isSignal: true }], ngImport: i0, template: "@if (isLoading()) {\n <div class=\"w-full flex flex-col gap-3\">\n @for (item of skeletonItems; track item) {\n <div class=\"flex gap-3 items-center p-2\">\n <ax-skeleton [animated]=\"true\" class=\"size-10 rounded-lg shrink-0\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"flex-1 h-5 rounded-md\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"w-16 h-4 rounded-md shrink-0\"></ax-skeleton>\n </div>\n }\n </div>\n} @else if (useSelectBox()) {\n <div\n class=\"w-full flex flex-col gap-4\"\n [class.pointer-events-none]=\"isChoosing()\"\n [class.opacity-60]=\"isChoosing()\"\n (keydown.capture)=\"handleSelectBoxKeyDown($event)\"\n >\n <ax-select-box\n class=\"w-full\"\n [dataSource]=\"allApplications()\"\n textField=\"title\"\n valueField=\"id\"\n [value]=\"selectedApplication()\"\n [itemHeight]=\"56\"\n [placeholder]=\"('@auth:application-chooser.select-placeholder' | translate | async) ?? ''\"\n [itemTemplate]=\"applicationItemTemplate\"\n (onOpened)=\"isSelectBoxOpen.set(true)\"\n (onClosed)=\"isSelectBoxOpen.set(false)\"\n (onValueChanged)=\"handleApplicationSelect($event)\"\n >\n <ax-search-box look=\"fill\"></ax-search-box>\n </ax-select-box>\n <ax-button\n class=\"w-full\"\n color=\"primary\"\n [disabled]=\"!canApply() || isChoosing()\"\n [text]=\"('@general:actions.apply.title' | translate | async) ?? ''\"\n (onClick)=\"applySelection()\"\n >\n @if (isChoosing()) {\n <ax-loading></ax-loading>\n }\n </ax-button>\n </div>\n} @else {\n <div\n axListNavigation\n #listNav=\"axListNavigation\"\n class=\"w-full overflow-auto max-h-[300px] flex flex-col divide-y divide-neutral-100 dark:divide-neutral-800\"\n role=\"listbox\"\n [class.pointer-events-none]=\"isChoosing()\"\n >\n @for (application of allApplications(); track application.id) {\n <div\n axListNavigationItem\n #navItem=\"axListNavigationItem\"\n tabindex=\"0\"\n role=\"option\"\n [attr.aria-selected]=\"isApplicationSelected(application)\"\n [attr.aria-busy]=\"choosingId() === application.id\"\n class=\"flex gap-2 items-center p-2 cursor-pointer rounded-md transition-colors outline-none hover:bg-primary-lightest hover:dark:bg-primary-dark focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary\"\n [class.bg-primary-lighter]=\"isApplicationSelected(application)\"\n [class.dark:bg-primary-darker]=\"isApplicationSelected(application)\"\n [class.text-primary-on-lighter]=\"isApplicationSelected(application)\"\n [class.dark:text-primary-on-darker]=\"isApplicationSelected(application)\"\n [class.opacity-50]=\"isChoosing() && choosingId() !== application.id\"\n [class.cursor-wait]=\"isChoosing()\"\n (click)=\"chooseApplication(application)\"\n (keydown)=\"handleListItemKeyDown($event, application)\"\n >\n <div class=\"flex flex-1 gap-3 items-center min-w-0\">\n <div class=\"shrink-0 size-12 overflow-hidden rounded-lg\">\n <axp-logo\n [logoKey]=\"applicationLogoKey(application)\"\n appearance=\"colored\"\n [size]=\"42\"\n [attr.alt]=\"(application.title | translate | async) ?? ''\"\n class=\"size-12 overflow-hidden rounded-lg\"\n ></axp-logo>\n </div>\n <span class=\"flex-1 min-w-0 text-start md:text-base text-sm break-words md:truncate\">{{\n application.title | translate | async\n }}</span>\n @if (application.edition?.title) {\n <span class=\"text-muted text-xs shrink-0\">{{\n application.edition?.title | translate | async\n }}</span>\n }\n </div>\n @if (choosingId() === application.id) {\n <ax-loading class=\"shrink-0\"></ax-loading>\n }\n </div>\n }\n </div>\n}\n\n<ng-template #applicationItemTemplate let-item>\n <div class=\"flex gap-3 items-center p-2\">\n <div class=\"size-12 overflow-hidden rounded-lg shrink-0\">\n <axp-logo\n [logoKey]=\"applicationLogoKey(item.data)\"\n appearance=\"colored\"\n [size]=\"42\"\n [attr.alt]=\"(item.data.title | translate | async) ?? ''\"\n class=\"size-12 overflow-hidden rounded-lg\"\n ></axp-logo>\n </div>\n <span class=\"flex-1 text-start md:text-base text-sm\">{{ item.data.title | translate | async }}</span>\n @if (item.data.edition?.title) {\n <span class=\"text-muted text-xs\">{{ item.data.edition.title | translate | async }}</span>\n }\n </div>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i2.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i1$2.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i4.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "itemHeight", "maxVisibleItems", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed", "onItemSelected", "onItemClick"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i5.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXListNavigationModule }, { kind: "directive", type: i6.AXListNavigationDirective, selector: "[axListNavigation]", inputs: ["orientation"], outputs: ["onNavigationChanged", "onKeypress"], exportAs: ["axListNavigation"] }, { kind: "directive", type: i6.AXListNavigationItemDirective, selector: "[axListNavigationItem]", outputs: ["onKeypress"], exportAs: ["axListNavigationItem"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPLogoComponent, selector: "axp-logo", inputs: ["logoKey", "appearance", "size", "format"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i5$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1108
1087
|
}
|
|
1109
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1088
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAppChooserListComponent, decorators: [{
|
|
1110
1089
|
type: Component,
|
|
1111
1090
|
args: [{ selector: 'axp-app-chooser-list', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
1112
1091
|
CommonModule,
|
|
1113
1092
|
AXButtonModule,
|
|
1114
1093
|
AXDecoratorModule,
|
|
1094
|
+
AXLoadingModule,
|
|
1115
1095
|
AXSkeletonModule,
|
|
1116
1096
|
AXSelectBoxModule,
|
|
1117
1097
|
AXSearchBoxModule,
|
|
1118
1098
|
AXListNavigationModule,
|
|
1119
1099
|
AXTranslationModule,
|
|
1120
1100
|
AXPLogoComponent,
|
|
1121
|
-
], template: "@if (isLoading()) {\n <div class=\"w-full flex flex-col gap-3\">\n @for (item of skeletonItems; track item) {\n <div class=\"flex gap-
|
|
1122
|
-
}], ctorParameters: () => [], propDecorators: { simple: [{ type: i0.Input, args: [{ isSignal: true, alias: "simple", required: false }] }], applicationChosen: [{ type: i0.Output, args: ["applicationChosen"] }], listNav: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXListNavigationDirective), { isSignal: true }] }], listItems: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => AXListNavigationItemDirective), { isSignal: true }] }] } });
|
|
1101
|
+
], template: "@if (isLoading()) {\n <div class=\"w-full flex flex-col gap-3\">\n @for (item of skeletonItems; track item) {\n <div class=\"flex gap-3 items-center p-2\">\n <ax-skeleton [animated]=\"true\" class=\"size-10 rounded-lg shrink-0\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"flex-1 h-5 rounded-md\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"w-16 h-4 rounded-md shrink-0\"></ax-skeleton>\n </div>\n }\n </div>\n} @else if (useSelectBox()) {\n <div\n class=\"w-full flex flex-col gap-4\"\n [class.pointer-events-none]=\"isChoosing()\"\n [class.opacity-60]=\"isChoosing()\"\n (keydown.capture)=\"handleSelectBoxKeyDown($event)\"\n >\n <ax-select-box\n class=\"w-full\"\n [dataSource]=\"allApplications()\"\n textField=\"title\"\n valueField=\"id\"\n [value]=\"selectedApplication()\"\n [itemHeight]=\"56\"\n [placeholder]=\"('@auth:application-chooser.select-placeholder' | translate | async) ?? ''\"\n [itemTemplate]=\"applicationItemTemplate\"\n (onOpened)=\"isSelectBoxOpen.set(true)\"\n (onClosed)=\"isSelectBoxOpen.set(false)\"\n (onValueChanged)=\"handleApplicationSelect($event)\"\n >\n <ax-search-box look=\"fill\"></ax-search-box>\n </ax-select-box>\n <ax-button\n class=\"w-full\"\n color=\"primary\"\n [disabled]=\"!canApply() || isChoosing()\"\n [text]=\"('@general:actions.apply.title' | translate | async) ?? ''\"\n (onClick)=\"applySelection()\"\n >\n @if (isChoosing()) {\n <ax-loading></ax-loading>\n }\n </ax-button>\n </div>\n} @else {\n <div\n axListNavigation\n #listNav=\"axListNavigation\"\n class=\"w-full overflow-auto max-h-[300px] flex flex-col divide-y divide-neutral-100 dark:divide-neutral-800\"\n role=\"listbox\"\n [class.pointer-events-none]=\"isChoosing()\"\n >\n @for (application of allApplications(); track application.id) {\n <div\n axListNavigationItem\n #navItem=\"axListNavigationItem\"\n tabindex=\"0\"\n role=\"option\"\n [attr.aria-selected]=\"isApplicationSelected(application)\"\n [attr.aria-busy]=\"choosingId() === application.id\"\n class=\"flex gap-2 items-center p-2 cursor-pointer rounded-md transition-colors outline-none hover:bg-primary-lightest hover:dark:bg-primary-dark focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary\"\n [class.bg-primary-lighter]=\"isApplicationSelected(application)\"\n [class.dark:bg-primary-darker]=\"isApplicationSelected(application)\"\n [class.text-primary-on-lighter]=\"isApplicationSelected(application)\"\n [class.dark:text-primary-on-darker]=\"isApplicationSelected(application)\"\n [class.opacity-50]=\"isChoosing() && choosingId() !== application.id\"\n [class.cursor-wait]=\"isChoosing()\"\n (click)=\"chooseApplication(application)\"\n (keydown)=\"handleListItemKeyDown($event, application)\"\n >\n <div class=\"flex flex-1 gap-3 items-center min-w-0\">\n <div class=\"shrink-0 size-12 overflow-hidden rounded-lg\">\n <axp-logo\n [logoKey]=\"applicationLogoKey(application)\"\n appearance=\"colored\"\n [size]=\"42\"\n [attr.alt]=\"(application.title | translate | async) ?? ''\"\n class=\"size-12 overflow-hidden rounded-lg\"\n ></axp-logo>\n </div>\n <span class=\"flex-1 min-w-0 text-start md:text-base text-sm break-words md:truncate\">{{\n application.title | translate | async\n }}</span>\n @if (application.edition?.title) {\n <span class=\"text-muted text-xs shrink-0\">{{\n application.edition?.title | translate | async\n }}</span>\n }\n </div>\n @if (choosingId() === application.id) {\n <ax-loading class=\"shrink-0\"></ax-loading>\n }\n </div>\n }\n </div>\n}\n\n<ng-template #applicationItemTemplate let-item>\n <div class=\"flex gap-3 items-center p-2\">\n <div class=\"size-12 overflow-hidden rounded-lg shrink-0\">\n <axp-logo\n [logoKey]=\"applicationLogoKey(item.data)\"\n appearance=\"colored\"\n [size]=\"42\"\n [attr.alt]=\"(item.data.title | translate | async) ?? ''\"\n class=\"size-12 overflow-hidden rounded-lg\"\n ></axp-logo>\n </div>\n <span class=\"flex-1 text-start md:text-base text-sm\">{{ item.data.title | translate | async }}</span>\n @if (item.data.edition?.title) {\n <span class=\"text-muted text-xs\">{{ item.data.edition.title | translate | async }}</span>\n }\n </div>\n</ng-template>\n" }]
|
|
1102
|
+
}], ctorParameters: () => [], propDecorators: { simple: [{ type: i0.Input, args: [{ isSignal: true, alias: "simple", required: false }] }], applicationChosen: [{ type: i0.Output, args: ["applicationChosen"] }], loadingChange: [{ type: i0.Output, args: ["loadingChange"] }], listNav: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXListNavigationDirective), { isSignal: true }] }], listItems: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => AXListNavigationItemDirective), { isSignal: true }] }] } });
|
|
1123
1103
|
|
|
1124
1104
|
class AXMAppChooserSlotComponent {
|
|
1125
1105
|
constructor() {
|
|
1126
1106
|
this.sessionService = inject(AXPSessionService);
|
|
1127
1107
|
this.applications$ = this.sessionService.applications$;
|
|
1128
|
-
this.appPopover = viewChild('appPopover',
|
|
1108
|
+
this.appPopover = viewChild('appPopover', /* @ts-ignore */
|
|
1109
|
+
...(ngDevMode ? [{ debugName: "appPopover" }] : /* istanbul ignore next */ []));
|
|
1129
1110
|
}
|
|
1130
1111
|
closePopover() {
|
|
1131
1112
|
this.appPopover()?.close();
|
|
1132
1113
|
}
|
|
1133
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1134
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1114
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAppChooserSlotComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1115
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXMAppChooserSlotComponent, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "appPopover", first: true, predicate: ["appPopover"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (applications$ | async; as applications) {\n @if (applications.length > 1) {\n <ax-button color=\"primary\" #appChooser>\n <ax-icon class=\"fa-regular fa-grid-2\"> </ax-icon>\n </ax-button>\n <ax-popover [target]=\"appChooser\" [openOn]=\"'toggle'\" [closeOn]=\"'clickOut'\" #appPopover>\n <div class=\"bg-lightest border overflow-hidden rounded-md shadow-md w-full min-w-64 p-1\">\n <axp-app-chooser-list [simple]=\"true\" (applicationChosen)=\"closePopover()\"></axp-app-chooser-list>\n </div>\n </ax-popover>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$1.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "visualContextScope", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "closeOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: AXPAppChooserListComponent, selector: "axp-app-chooser-list", inputs: ["simple"], outputs: ["applicationChosen", "loadingChange"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
|
|
1135
1116
|
}
|
|
1136
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1117
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAppChooserSlotComponent, decorators: [{
|
|
1137
1118
|
type: Component,
|
|
1138
|
-
args: [{ imports: [CommonModule, AXButtonModule, AXPopoverModule, AXDecoratorModule, AXPAppChooserListComponent], template: "@if (
|
|
1119
|
+
args: [{ changeDetection: ChangeDetectionStrategy.Eager, imports: [CommonModule, AXButtonModule, AXPopoverModule, AXDecoratorModule, AXPAppChooserListComponent], template: "@if (applications$ | async; as applications) {\n @if (applications.length > 1) {\n <ax-button color=\"primary\" #appChooser>\n <ax-icon class=\"fa-regular fa-grid-2\"> </ax-icon>\n </ax-button>\n <ax-popover [target]=\"appChooser\" [openOn]=\"'toggle'\" [closeOn]=\"'clickOut'\" #appPopover>\n <div class=\"bg-lightest border overflow-hidden rounded-md shadow-md w-full min-w-64 p-1\">\n <axp-app-chooser-list [simple]=\"true\" (applicationChosen)=\"closePopover()\"></axp-app-chooser-list>\n </div>\n </ax-popover>\n }\n}\n" }]
|
|
1139
1120
|
}], propDecorators: { appPopover: [{ type: i0.ViewChild, args: ['appPopover', { isSignal: true }] }] } });
|
|
1140
1121
|
|
|
1141
1122
|
class AXPTenantChooserListComponent {
|
|
@@ -1154,27 +1135,44 @@ class AXPTenantChooserListComponent {
|
|
|
1154
1135
|
this.sessionService = inject(AXPSessionService);
|
|
1155
1136
|
this.authStrategyRegistry = inject(AXPAuthStrategyRegistryService);
|
|
1156
1137
|
this.logoRegistration = inject(AXPEntityLogoRegistrationService);
|
|
1138
|
+
this.translationService = inject(AXTranslationService);
|
|
1157
1139
|
this.router = inject(Router);
|
|
1158
1140
|
this.strategyName = this.sessionService.getSessionData()?.strategy;
|
|
1159
1141
|
this.strategy = this.authStrategyRegistry.get(this.strategyName);
|
|
1160
1142
|
//#endregion
|
|
1161
1143
|
//#region ---- Inputs & Outputs ----
|
|
1162
|
-
this.simple = input(false,
|
|
1144
|
+
this.simple = input(false, /* @ts-ignore */
|
|
1145
|
+
...(ngDevMode ? [{ debugName: "simple" }] : /* istanbul ignore next */ []));
|
|
1163
1146
|
this.tenantChosen = output();
|
|
1147
|
+
this.loadingChange = output();
|
|
1164
1148
|
//#endregion
|
|
1165
1149
|
//#region ---- View References ----
|
|
1166
|
-
this.listNav = viewChild(AXListNavigationDirective,
|
|
1167
|
-
|
|
1150
|
+
this.listNav = viewChild(AXListNavigationDirective, /* @ts-ignore */
|
|
1151
|
+
...(ngDevMode ? [{ debugName: "listNav" }] : /* istanbul ignore next */ []));
|
|
1152
|
+
this.listItems = viewChildren(AXListNavigationItemDirective, /* @ts-ignore */
|
|
1153
|
+
...(ngDevMode ? [{ debugName: "listItems" }] : /* istanbul ignore next */ []));
|
|
1168
1154
|
//#endregion
|
|
1169
1155
|
//#region ---- State ----
|
|
1170
|
-
this.isLoading = signal(true,
|
|
1171
|
-
|
|
1172
|
-
this.
|
|
1173
|
-
|
|
1174
|
-
this.
|
|
1175
|
-
|
|
1176
|
-
this.
|
|
1177
|
-
|
|
1156
|
+
this.isLoading = signal(true, /* @ts-ignore */
|
|
1157
|
+
...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
|
|
1158
|
+
this.isChoosing = signal(false, /* @ts-ignore */
|
|
1159
|
+
...(ngDevMode ? [{ debugName: "isChoosing" }] : /* istanbul ignore next */ []));
|
|
1160
|
+
this.choosingId = signal(null, /* @ts-ignore */
|
|
1161
|
+
...(ngDevMode ? [{ debugName: "choosingId" }] : /* istanbul ignore next */ []));
|
|
1162
|
+
this.allTenants = signal([], /* @ts-ignore */
|
|
1163
|
+
...(ngDevMode ? [{ debugName: "allTenants" }] : /* istanbul ignore next */ []));
|
|
1164
|
+
this.searchValue = signal('', /* @ts-ignore */
|
|
1165
|
+
...(ngDevMode ? [{ debugName: "searchValue" }] : /* istanbul ignore next */ []));
|
|
1166
|
+
this.showAll = signal(false, /* @ts-ignore */
|
|
1167
|
+
...(ngDevMode ? [{ debugName: "showAll" }] : /* istanbul ignore next */ []));
|
|
1168
|
+
this.useSelectBox = computed(() => this.allTenants().length > 3, /* @ts-ignore */
|
|
1169
|
+
...(ngDevMode ? [{ debugName: "useSelectBox" }] : /* istanbul ignore next */ []));
|
|
1170
|
+
this.selectedTenant = signal(null, /* @ts-ignore */
|
|
1171
|
+
...(ngDevMode ? [{ debugName: "selectedTenant" }] : /* istanbul ignore next */ []));
|
|
1172
|
+
this.isSelectBoxOpen = signal(false, /* @ts-ignore */
|
|
1173
|
+
...(ngDevMode ? [{ debugName: "isSelectBoxOpen" }] : /* istanbul ignore next */ []));
|
|
1174
|
+
this.canApply = computed(() => !!this.selectedTenant(), /* @ts-ignore */
|
|
1175
|
+
...(ngDevMode ? [{ debugName: "canApply" }] : /* istanbul ignore next */ []));
|
|
1178
1176
|
this.skeletonItems = [1, 2, 3];
|
|
1179
1177
|
/** Tenants shown in the list (respects search and view-all toggle). */
|
|
1180
1178
|
this.displayedTenants = computed(() => {
|
|
@@ -1183,8 +1181,13 @@ class AXPTenantChooserListComponent {
|
|
|
1183
1181
|
return tenants;
|
|
1184
1182
|
}
|
|
1185
1183
|
return tenants.slice(0, 4);
|
|
1186
|
-
},
|
|
1187
|
-
|
|
1184
|
+
}, /* @ts-ignore */
|
|
1185
|
+
...(ngDevMode ? [{ debugName: "displayedTenants" }] : /* istanbul ignore next */ []));
|
|
1186
|
+
this.showSearchAndViewAll = computed(() => this.allTenants().length > 4, /* @ts-ignore */
|
|
1187
|
+
...(ngDevMode ? [{ debugName: "showSearchAndViewAll" }] : /* istanbul ignore next */ []));
|
|
1188
|
+
effect(() => {
|
|
1189
|
+
this.loadingChange.emit(this.isLoading());
|
|
1190
|
+
});
|
|
1188
1191
|
effect(() => {
|
|
1189
1192
|
if (!this.isLoading() && !this.useSelectBox() && !this.simple() && this.allTenants().length > 0) {
|
|
1190
1193
|
queueMicrotask(() => this.focusFirstListItem());
|
|
@@ -1194,7 +1197,7 @@ class AXPTenantChooserListComponent {
|
|
|
1194
1197
|
//#endregion
|
|
1195
1198
|
//#region ---- Lifecycle Methods ----
|
|
1196
1199
|
ngOnInit() {
|
|
1197
|
-
this.sessionService.tenants$.pipe(first
|
|
1200
|
+
this.sessionService.tenants$.pipe(first()).subscribe((tenants) => {
|
|
1198
1201
|
this.logoRegistration.registerTenants(tenants);
|
|
1199
1202
|
this.allTenants.set(tenants);
|
|
1200
1203
|
if (tenants.length > 0) {
|
|
@@ -1207,7 +1210,11 @@ class AXPTenantChooserListComponent {
|
|
|
1207
1210
|
//#region ---- UI Handlers ----
|
|
1208
1211
|
filterTenants(tenants) {
|
|
1209
1212
|
const query = this.searchValue().toLowerCase();
|
|
1210
|
-
|
|
1213
|
+
if (!query) {
|
|
1214
|
+
return tenants;
|
|
1215
|
+
}
|
|
1216
|
+
const locale = this.translationService.getActiveLang();
|
|
1217
|
+
return tenants.filter((tenant) => resolveMultiLanguageString(tenant.title, locale).toLowerCase().includes(query));
|
|
1211
1218
|
}
|
|
1212
1219
|
handleSearch(event) {
|
|
1213
1220
|
if (event !== undefined) {
|
|
@@ -1246,21 +1253,35 @@ class AXPTenantChooserListComponent {
|
|
|
1246
1253
|
}
|
|
1247
1254
|
}
|
|
1248
1255
|
applySelection() {
|
|
1256
|
+
if (this.isChoosing()) {
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1249
1259
|
const tenant = this.selectedTenant();
|
|
1250
1260
|
if (tenant) {
|
|
1251
1261
|
void this.chooseTenant(tenant);
|
|
1252
1262
|
}
|
|
1253
1263
|
}
|
|
1254
1264
|
async chooseTenant(item) {
|
|
1255
|
-
if (this.
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1265
|
+
if (this.isChoosing()) {
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
this.isChoosing.set(true);
|
|
1269
|
+
this.choosingId.set(item.id);
|
|
1270
|
+
try {
|
|
1271
|
+
if (this.strategy) {
|
|
1272
|
+
const updateContext = {
|
|
1273
|
+
tenant: item,
|
|
1274
|
+
user: this.sessionService.user,
|
|
1275
|
+
};
|
|
1276
|
+
await this.sessionService.updateToken(updateContext);
|
|
1277
|
+
}
|
|
1278
|
+
this.tenantChosen.emit();
|
|
1279
|
+
return this.router.navigate(['/auth/account/app-chooser']);
|
|
1280
|
+
}
|
|
1281
|
+
finally {
|
|
1282
|
+
this.isChoosing.set(false);
|
|
1283
|
+
this.choosingId.set(null);
|
|
1261
1284
|
}
|
|
1262
|
-
this.tenantChosen.emit();
|
|
1263
|
-
return this.router.navigate(['/auth/account/app-chooser']);
|
|
1264
1285
|
}
|
|
1265
1286
|
//#endregion
|
|
1266
1287
|
//#region ---- Utility Methods ----
|
|
@@ -1273,10 +1294,10 @@ class AXPTenantChooserListComponent {
|
|
|
1273
1294
|
nav.navigateTo(items[currentIndex >= 0 ? currentIndex : 0]);
|
|
1274
1295
|
}
|
|
1275
1296
|
}
|
|
1276
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1277
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPTenantChooserListComponent, isStandalone: true, selector: "axp-tenant-chooser-list", inputs: { simple: { classPropertyName: "simple", publicName: "simple", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { tenantChosen: "tenantChosen" }, viewQueries: [{ propertyName: "listNav", first: true, predicate: AXListNavigationDirective, descendants: true, isSignal: true }, { propertyName: "listItems", predicate: AXListNavigationItemDirective, descendants: true, isSignal: true }], ngImport: i0, template: "@if (isLoading()) {\n <div class=\"w-full flex flex-col gap-3\">\n @for (item of skeletonItems; track item) {\n <div class=\"flex gap-2 items-center p-2\">\n <ax-skeleton [animated]=\"true\" class=\"w-12 h-12 rounded-full shrink-0\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"flex-1 h-6 rounded-md\"></ax-skeleton>\n </div>\n }\n </div>\n} @else if (simple()) {\n <div class=\"w-full overflow-auto max-h-[300px] pe-2\">\n @for (tenant of allTenants(); track tenant.id) {\n <div\n class=\"flex gap-2 justify-between border-b last:border-b-0 py-3 items-start cursor-pointer\"\n (click)=\"chooseTenant(tenant)\"\n >\n <div class=\"flex flex-1 gap-2 items-center font-medium\">\n <div\n class=\"w-12 h-12 flex justify-center items-center rounded-full bg-neutral-100 m-auto\"\n >\n <axp-logo\n [logoKey]=\"tenantLogoKey(tenant)\"\n appearance=\"colored\"\n [size]=\"40\"\n [attr.alt]=\"tenant.title\"\n class=\"flex! items-center justify-center text-sm! mx-auto w-10 h-10 bg-neutral-200 rounded-full\"\n ></axp-logo>\n </div>\n <span class=\"flex-1 text-start md:text-base text-sm\">{{ tenant.title }}</span>\n </div>\n </div>\n }\n </div>\n} @else if (useSelectBox()) {\n <div class=\"w-full flex flex-col gap-4\" (keydown.capture)=\"handleSelectBoxKeyDown($event)\">\n <ax-select-box\n class=\"w-full\"\n [dataSource]=\"allTenants()\"\n textField=\"title\"\n valueField=\"id\"\n [value]=\"selectedTenant()\"\n [itemHeight]=\"56\"\n [placeholder]=\"('@auth:tenant-chooser.select-placeholder' | translate | async) ?? ''\"\n [itemTemplate]=\"tenantItemTemplate\"\n (onOpened)=\"isSelectBoxOpen.set(true)\"\n (onClosed)=\"isSelectBoxOpen.set(false)\"\n (onValueChanged)=\"handleTenantSelect($event)\"\n >\n <ax-search-box look=\"fill\"></ax-search-box>\n </ax-select-box>\n <ax-button\n class=\"w-full\"\n color=\"primary\"\n [disabled]=\"!canApply()\"\n [text]=\"('@general:actions.apply.title' | translate | async) ?? ''\"\n (onClick)=\"applySelection()\"\n ></ax-button>\n </div>\n} @else {\n @if (showSearchAndViewAll()) {\n <ax-search-box\n [placeholder]=\"'@general:search.title' | translate | async\"\n [ngModel]=\"searchValue()\"\n (ngModelChange)=\"handleSearch($event)\"\n class=\"w-full\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n }\n <div\n axListNavigation\n #listNav=\"axListNavigation\"\n class=\"w-full overflow-auto max-h-[300px] flex flex-col gap-1\"\n role=\"listbox\"\n >\n @for (tenant of displayedTenants(); track tenant.id) {\n <div\n axListNavigationItem\n #navItem=\"axListNavigationItem\"\n tabindex=\"0\"\n role=\"option\"\n [attr.aria-selected]=\"isTenantSelected(tenant)\"\n class=\"flex gap-2 items-center p-2 cursor-pointer rounded-md transition-colors outline-none hover:bg-primary-lightest hover:dark:bg-primary-dark\"\n [class.bg-primary-lighter]=\"isTenantSelected(tenant)\"\n [class.dark:bg-primary-darker]=\"isTenantSelected(tenant)\"\n [class.text-primary-on-lighter]=\"isTenantSelected(tenant)\"\n [class.dark:text-primary-on-darker]=\"isTenantSelected(tenant)\"\n [class.ring-2]=\"navItem.isActive()\"\n [class.ring-primary]=\"navItem.isActive()\"\n (click)=\"chooseTenant(tenant)\"\n (keydown)=\"handleListItemKeyDown($event, tenant)\"\n >\n <div class=\"flex flex-1 gap-2 items-center min-w-0\">\n <div\n class=\"shrink-0 flex justify-center items-center rounded-full bg-neutral-100\"\n [class.w-10]=\"simple()\"\n [class.h-10]=\"simple()\"\n [class.w-12]=\"!simple()\"\n [class.h-12]=\"!simple()\"\n >\n <axp-logo\n [logoKey]=\"tenantLogoKey(tenant)\"\n appearance=\"colored\"\n [size]=\"40\"\n [attr.alt]=\"tenant.title\"\n class=\"flex! items-center justify-center text-sm! bg-neutral-200 dark:bg-neutral-800 rounded-full\"\n [class.w-8]=\"simple()\"\n [class.h-8]=\"simple()\"\n [class.w-10]=\"!simple()\"\n [class.h-10]=\"!simple()\"\n ></axp-logo>\n </div>\n <span class=\"flex-1 truncate text-start md:text-base text-sm\">{{ tenant.title }}</span>\n </div>\n </div>\n }\n </div>\n @if (showSearchAndViewAll()) {\n <div class=\"mt-6 w-full flex justify-center\">\n <ax-button\n (onClick)=\"showAllTenants()\"\n class=\"w-full\"\n look=\"outline\"\n [text]=\"\n showAll()\n ? ('@general:actions.view-less.title' | translate | async)\n : ('@general:actions.view-all.title' | translate | async)\n \"\n ></ax-button>\n </div>\n }\n}\n\n<ng-template #tenantItemTemplate let-item>\n <div class=\"flex gap-2 items-center p-2\">\n <div\n class=\"w-10 h-10 flex justify-center items-center rounded-full bg-neutral-100 shrink-0\"\n >\n <axp-logo\n [logoKey]=\"tenantLogoKey(item.data)\"\n appearance=\"colored\"\n [size]=\"32\"\n [attr.alt]=\"item.data.title\"\n class=\"flex! items-center justify-center text-sm! w-8 h-8 bg-neutral-200 rounded-full\"\n ></axp-logo>\n </div>\n <span class=\"text-start md:text-base text-sm\">{{ item.data.title }}</span>\n </div>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i2.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i3.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "itemHeight", "maxVisibleItems", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed", "onItemSelected", "onItemClick"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i4.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXListNavigationModule }, { kind: "directive", type: i5.AXListNavigationDirective, selector: "[axListNavigation]", inputs: ["orientation"], outputs: ["onNavigationChanged", "onKeypress"], exportAs: ["axListNavigation"] }, { kind: "directive", type: i5.AXListNavigationItemDirective, selector: "[axListNavigationItem]", outputs: ["onKeypress"], exportAs: ["axListNavigationItem"] }, { kind: "component", type: AXPLogoComponent, selector: "axp-logo", inputs: ["logoKey", "appearance", "size", "format"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i7.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1297
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPTenantChooserListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1298
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPTenantChooserListComponent, isStandalone: true, selector: "axp-tenant-chooser-list", inputs: { simple: { classPropertyName: "simple", publicName: "simple", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { tenantChosen: "tenantChosen", loadingChange: "loadingChange" }, viewQueries: [{ propertyName: "listNav", first: true, predicate: AXListNavigationDirective, descendants: true, isSignal: true }, { propertyName: "listItems", predicate: AXListNavigationItemDirective, descendants: true, isSignal: true }], ngImport: i0, template: "@if (isLoading()) {\n <div class=\"w-full flex flex-col gap-3\">\n @for (item of skeletonItems; track item) {\n <div class=\"flex gap-3 items-center p-2\">\n <ax-skeleton [animated]=\"true\" class=\"size-12 rounded-lg shrink-0\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"flex-1 h-5 rounded-md\"></ax-skeleton>\n </div>\n }\n </div>\n} @else if (simple()) {\n <div\n class=\"w-full overflow-auto max-h-[300px] pe-2 flex flex-col divide-y divide-neutral-100 dark:divide-neutral-800\"\n [class.pointer-events-none]=\"isChoosing()\"\n >\n @for (tenant of allTenants(); track tenant.id) {\n <div\n class=\"flex gap-2 justify-between py-3 items-center cursor-pointer rounded-md transition-colors hover:bg-primary-lightest hover:dark:bg-primary-dark\"\n [class.opacity-50]=\"isChoosing() && choosingId() !== tenant.id\"\n [class.cursor-wait]=\"isChoosing()\"\n [attr.aria-busy]=\"choosingId() === tenant.id\"\n (click)=\"chooseTenant(tenant)\"\n >\n <div class=\"flex flex-1 gap-3 items-center font-medium min-w-0\">\n <div class=\"shrink-0 size-12 overflow-hidden rounded-lg\">\n <axp-logo\n [logoKey]=\"tenantLogoKey(tenant)\"\n appearance=\"colored\"\n [size]=\"42\"\n [attr.alt]=\"(tenant.title | translate | async) ?? ''\"\n class=\"size-12 overflow-hidden rounded-lg\"\n ></axp-logo>\n </div>\n <span class=\"flex-1 truncate text-start md:text-base text-sm\">{{\n tenant.title | translate | async\n }}</span>\n </div>\n @if (choosingId() === tenant.id) {\n <ax-loading class=\"shrink-0\"></ax-loading>\n }\n </div>\n }\n </div>\n} @else if (useSelectBox()) {\n <div\n class=\"w-full flex flex-col gap-4\"\n [class.pointer-events-none]=\"isChoosing()\"\n [class.opacity-60]=\"isChoosing()\"\n (keydown.capture)=\"handleSelectBoxKeyDown($event)\"\n >\n <ax-select-box\n class=\"w-full\"\n [dataSource]=\"allTenants()\"\n textField=\"title\"\n valueField=\"id\"\n [value]=\"selectedTenant()\"\n [itemHeight]=\"56\"\n [placeholder]=\"('@auth:tenant-chooser.select-placeholder' | translate | async) ?? ''\"\n [itemTemplate]=\"tenantItemTemplate\"\n (onOpened)=\"isSelectBoxOpen.set(true)\"\n (onClosed)=\"isSelectBoxOpen.set(false)\"\n (onValueChanged)=\"handleTenantSelect($event)\"\n >\n <ax-search-box look=\"fill\"></ax-search-box>\n </ax-select-box>\n <ax-button\n class=\"w-full\"\n color=\"primary\"\n [disabled]=\"!canApply() || isChoosing()\"\n [text]=\"('@general:actions.apply.title' | translate | async) ?? ''\"\n (onClick)=\"applySelection()\"\n >\n @if (isChoosing()) {\n <ax-loading></ax-loading>\n }\n </ax-button>\n </div>\n} @else {\n @if (showSearchAndViewAll()) {\n <ax-search-box\n [placeholder]=\"'@general:search.title' | translate | async\"\n [ngModel]=\"searchValue()\"\n (ngModelChange)=\"handleSearch($event)\"\n class=\"w-full\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n }\n <div\n axListNavigation\n #listNav=\"axListNavigation\"\n class=\"w-full overflow-auto max-h-[300px] flex flex-col divide-y divide-neutral-100 dark:divide-neutral-800\"\n role=\"listbox\"\n [class.pointer-events-none]=\"isChoosing()\"\n >\n @for (tenant of displayedTenants(); track tenant.id) {\n <div\n axListNavigationItem\n #navItem=\"axListNavigationItem\"\n tabindex=\"0\"\n role=\"option\"\n [attr.aria-selected]=\"isTenantSelected(tenant)\"\n [attr.aria-busy]=\"choosingId() === tenant.id\"\n class=\"flex gap-2 items-center p-2 cursor-pointer rounded-md transition-colors outline-none hover:bg-primary-lightest hover:dark:bg-primary-dark focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary\"\n [class.bg-primary-lighter]=\"isTenantSelected(tenant)\"\n [class.dark:bg-primary-darker]=\"isTenantSelected(tenant)\"\n [class.text-primary-on-lighter]=\"isTenantSelected(tenant)\"\n [class.dark:text-primary-on-darker]=\"isTenantSelected(tenant)\"\n [class.opacity-50]=\"isChoosing() && choosingId() !== tenant.id\"\n [class.cursor-wait]=\"isChoosing()\"\n (click)=\"chooseTenant(tenant)\"\n (keydown)=\"handleListItemKeyDown($event, tenant)\"\n >\n <div class=\"flex flex-1 gap-3 items-center min-w-0\">\n <div class=\"shrink-0 size-12 overflow-hidden rounded-lg\">\n <axp-logo\n [logoKey]=\"tenantLogoKey(tenant)\"\n appearance=\"colored\"\n [size]=\"42\"\n [attr.alt]=\"(tenant.title | translate | async) ?? ''\"\n class=\"size-12 overflow-hidden rounded-lg\"\n ></axp-logo>\n </div>\n <span class=\"flex-1 truncate text-start md:text-base text-sm\">{{\n tenant.title | translate | async\n }}</span>\n </div>\n @if (choosingId() === tenant.id) {\n <ax-loading class=\"shrink-0\"></ax-loading>\n }\n </div>\n }\n </div>\n @if (showSearchAndViewAll()) {\n <div class=\"mt-6 w-full flex justify-center\">\n <ax-button\n (onClick)=\"showAllTenants()\"\n class=\"w-full\"\n look=\"outline\"\n [disabled]=\"isChoosing()\"\n [text]=\"\n showAll()\n ? ('@general:actions.view-less.title' | translate | async)\n : ('@general:actions.view-all.title' | translate | async)\n \"\n ></ax-button>\n </div>\n }\n}\n\n<ng-template #tenantItemTemplate let-item>\n <div class=\"flex gap-3 items-center p-2\">\n <div class=\"size-12 overflow-hidden rounded-lg shrink-0\">\n <axp-logo\n [logoKey]=\"tenantLogoKey(item.data)\"\n appearance=\"colored\"\n [size]=\"42\"\n [attr.alt]=\"(item.data.title | translate | async) ?? ''\"\n class=\"size-12 overflow-hidden rounded-lg\"\n ></axp-logo>\n </div>\n <span class=\"text-start md:text-base text-sm\">{{ item.data.title | translate | async }}</span>\n </div>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i2.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i1$2.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i4.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "itemHeight", "maxVisibleItems", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed", "onItemSelected", "onItemClick"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i5.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXListNavigationModule }, { kind: "directive", type: i6.AXListNavigationDirective, selector: "[axListNavigation]", inputs: ["orientation"], outputs: ["onNavigationChanged", "onKeypress"], exportAs: ["axListNavigation"] }, { kind: "directive", type: i6.AXListNavigationItemDirective, selector: "[axListNavigationItem]", outputs: ["onKeypress"], exportAs: ["axListNavigationItem"] }, { kind: "component", type: AXPLogoComponent, selector: "axp-logo", inputs: ["logoKey", "appearance", "size", "format"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i5$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1278
1299
|
}
|
|
1279
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1300
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPTenantChooserListComponent, decorators: [{
|
|
1280
1301
|
type: Component,
|
|
1281
1302
|
args: [{ selector: 'axp-tenant-chooser-list', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
1282
1303
|
CommonModule,
|
|
@@ -1284,30 +1305,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1284
1305
|
AXTranslationModule,
|
|
1285
1306
|
AXButtonModule,
|
|
1286
1307
|
AXDecoratorModule,
|
|
1308
|
+
AXLoadingModule,
|
|
1287
1309
|
AXSkeletonModule,
|
|
1288
1310
|
AXSelectBoxModule,
|
|
1289
1311
|
AXSearchBoxModule,
|
|
1290
1312
|
AXListNavigationModule,
|
|
1291
1313
|
AXPLogoComponent,
|
|
1292
|
-
], template: "@if (isLoading()) {\n <div class=\"w-full flex flex-col gap-3\">\n @for (item of skeletonItems; track item) {\n <div class=\"flex gap-
|
|
1293
|
-
}], ctorParameters: () => [], propDecorators: { simple: [{ type: i0.Input, args: [{ isSignal: true, alias: "simple", required: false }] }], tenantChosen: [{ type: i0.Output, args: ["tenantChosen"] }], listNav: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXListNavigationDirective), { isSignal: true }] }], listItems: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => AXListNavigationItemDirective), { isSignal: true }] }] } });
|
|
1314
|
+
], template: "@if (isLoading()) {\n <div class=\"w-full flex flex-col gap-3\">\n @for (item of skeletonItems; track item) {\n <div class=\"flex gap-3 items-center p-2\">\n <ax-skeleton [animated]=\"true\" class=\"size-12 rounded-lg shrink-0\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"flex-1 h-5 rounded-md\"></ax-skeleton>\n </div>\n }\n </div>\n} @else if (simple()) {\n <div\n class=\"w-full overflow-auto max-h-[300px] pe-2 flex flex-col divide-y divide-neutral-100 dark:divide-neutral-800\"\n [class.pointer-events-none]=\"isChoosing()\"\n >\n @for (tenant of allTenants(); track tenant.id) {\n <div\n class=\"flex gap-2 justify-between py-3 items-center cursor-pointer rounded-md transition-colors hover:bg-primary-lightest hover:dark:bg-primary-dark\"\n [class.opacity-50]=\"isChoosing() && choosingId() !== tenant.id\"\n [class.cursor-wait]=\"isChoosing()\"\n [attr.aria-busy]=\"choosingId() === tenant.id\"\n (click)=\"chooseTenant(tenant)\"\n >\n <div class=\"flex flex-1 gap-3 items-center font-medium min-w-0\">\n <div class=\"shrink-0 size-12 overflow-hidden rounded-lg\">\n <axp-logo\n [logoKey]=\"tenantLogoKey(tenant)\"\n appearance=\"colored\"\n [size]=\"42\"\n [attr.alt]=\"(tenant.title | translate | async) ?? ''\"\n class=\"size-12 overflow-hidden rounded-lg\"\n ></axp-logo>\n </div>\n <span class=\"flex-1 truncate text-start md:text-base text-sm\">{{\n tenant.title | translate | async\n }}</span>\n </div>\n @if (choosingId() === tenant.id) {\n <ax-loading class=\"shrink-0\"></ax-loading>\n }\n </div>\n }\n </div>\n} @else if (useSelectBox()) {\n <div\n class=\"w-full flex flex-col gap-4\"\n [class.pointer-events-none]=\"isChoosing()\"\n [class.opacity-60]=\"isChoosing()\"\n (keydown.capture)=\"handleSelectBoxKeyDown($event)\"\n >\n <ax-select-box\n class=\"w-full\"\n [dataSource]=\"allTenants()\"\n textField=\"title\"\n valueField=\"id\"\n [value]=\"selectedTenant()\"\n [itemHeight]=\"56\"\n [placeholder]=\"('@auth:tenant-chooser.select-placeholder' | translate | async) ?? ''\"\n [itemTemplate]=\"tenantItemTemplate\"\n (onOpened)=\"isSelectBoxOpen.set(true)\"\n (onClosed)=\"isSelectBoxOpen.set(false)\"\n (onValueChanged)=\"handleTenantSelect($event)\"\n >\n <ax-search-box look=\"fill\"></ax-search-box>\n </ax-select-box>\n <ax-button\n class=\"w-full\"\n color=\"primary\"\n [disabled]=\"!canApply() || isChoosing()\"\n [text]=\"('@general:actions.apply.title' | translate | async) ?? ''\"\n (onClick)=\"applySelection()\"\n >\n @if (isChoosing()) {\n <ax-loading></ax-loading>\n }\n </ax-button>\n </div>\n} @else {\n @if (showSearchAndViewAll()) {\n <ax-search-box\n [placeholder]=\"'@general:search.title' | translate | async\"\n [ngModel]=\"searchValue()\"\n (ngModelChange)=\"handleSearch($event)\"\n class=\"w-full\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n }\n <div\n axListNavigation\n #listNav=\"axListNavigation\"\n class=\"w-full overflow-auto max-h-[300px] flex flex-col divide-y divide-neutral-100 dark:divide-neutral-800\"\n role=\"listbox\"\n [class.pointer-events-none]=\"isChoosing()\"\n >\n @for (tenant of displayedTenants(); track tenant.id) {\n <div\n axListNavigationItem\n #navItem=\"axListNavigationItem\"\n tabindex=\"0\"\n role=\"option\"\n [attr.aria-selected]=\"isTenantSelected(tenant)\"\n [attr.aria-busy]=\"choosingId() === tenant.id\"\n class=\"flex gap-2 items-center p-2 cursor-pointer rounded-md transition-colors outline-none hover:bg-primary-lightest hover:dark:bg-primary-dark focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary\"\n [class.bg-primary-lighter]=\"isTenantSelected(tenant)\"\n [class.dark:bg-primary-darker]=\"isTenantSelected(tenant)\"\n [class.text-primary-on-lighter]=\"isTenantSelected(tenant)\"\n [class.dark:text-primary-on-darker]=\"isTenantSelected(tenant)\"\n [class.opacity-50]=\"isChoosing() && choosingId() !== tenant.id\"\n [class.cursor-wait]=\"isChoosing()\"\n (click)=\"chooseTenant(tenant)\"\n (keydown)=\"handleListItemKeyDown($event, tenant)\"\n >\n <div class=\"flex flex-1 gap-3 items-center min-w-0\">\n <div class=\"shrink-0 size-12 overflow-hidden rounded-lg\">\n <axp-logo\n [logoKey]=\"tenantLogoKey(tenant)\"\n appearance=\"colored\"\n [size]=\"42\"\n [attr.alt]=\"(tenant.title | translate | async) ?? ''\"\n class=\"size-12 overflow-hidden rounded-lg\"\n ></axp-logo>\n </div>\n <span class=\"flex-1 truncate text-start md:text-base text-sm\">{{\n tenant.title | translate | async\n }}</span>\n </div>\n @if (choosingId() === tenant.id) {\n <ax-loading class=\"shrink-0\"></ax-loading>\n }\n </div>\n }\n </div>\n @if (showSearchAndViewAll()) {\n <div class=\"mt-6 w-full flex justify-center\">\n <ax-button\n (onClick)=\"showAllTenants()\"\n class=\"w-full\"\n look=\"outline\"\n [disabled]=\"isChoosing()\"\n [text]=\"\n showAll()\n ? ('@general:actions.view-less.title' | translate | async)\n : ('@general:actions.view-all.title' | translate | async)\n \"\n ></ax-button>\n </div>\n }\n}\n\n<ng-template #tenantItemTemplate let-item>\n <div class=\"flex gap-3 items-center p-2\">\n <div class=\"size-12 overflow-hidden rounded-lg shrink-0\">\n <axp-logo\n [logoKey]=\"tenantLogoKey(item.data)\"\n appearance=\"colored\"\n [size]=\"42\"\n [attr.alt]=\"(item.data.title | translate | async) ?? ''\"\n class=\"size-12 overflow-hidden rounded-lg\"\n ></axp-logo>\n </div>\n <span class=\"text-start md:text-base text-sm\">{{ item.data.title | translate | async }}</span>\n </div>\n</ng-template>\n" }]
|
|
1315
|
+
}], ctorParameters: () => [], propDecorators: { simple: [{ type: i0.Input, args: [{ isSignal: true, alias: "simple", required: false }] }], tenantChosen: [{ type: i0.Output, args: ["tenantChosen"] }], loadingChange: [{ type: i0.Output, args: ["loadingChange"] }], listNav: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXListNavigationDirective), { isSignal: true }] }], listItems: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => AXListNavigationItemDirective), { isSignal: true }] }] } });
|
|
1294
1316
|
|
|
1295
1317
|
class AXPTenantChooserDropdownComponent {
|
|
1296
1318
|
constructor() {
|
|
1319
|
+
//#region ----- Services & Dependencies -----
|
|
1297
1320
|
this.sessionService = inject(AXPSessionService);
|
|
1321
|
+
//#endregion
|
|
1322
|
+
//#region ----- State Signals -----
|
|
1298
1323
|
this.tenants$ = this.sessionService.tenants$;
|
|
1299
|
-
this.tenant = this.sessionService.tenant
|
|
1300
|
-
this.
|
|
1324
|
+
this.tenant$ = this.sessionService.tenant$;
|
|
1325
|
+
this.tenantsLoading = signal(true, /* @ts-ignore */
|
|
1326
|
+
...(ngDevMode ? [{ debugName: "tenantsLoading" }] : /* istanbul ignore next */ []));
|
|
1327
|
+
this.tenantPopover = viewChild('tenantPopover', /* @ts-ignore */
|
|
1328
|
+
...(ngDevMode ? [{ debugName: "tenantPopover" }] : /* istanbul ignore next */ []));
|
|
1301
1329
|
}
|
|
1330
|
+
//#endregion
|
|
1331
|
+
//#region ----- Lifecycle -----
|
|
1332
|
+
ngOnInit() {
|
|
1333
|
+
this.tenants$.pipe(first()).subscribe(() => {
|
|
1334
|
+
this.tenantsLoading.set(false);
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
//#endregion
|
|
1338
|
+
//#region ----- Event Handlers -----
|
|
1302
1339
|
closePopover() {
|
|
1303
1340
|
this.tenantPopover()?.close();
|
|
1304
1341
|
}
|
|
1305
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1306
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1342
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPTenantChooserDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1343
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPTenantChooserDropdownComponent, isStandalone: true, selector: "axp-tenant-chooser-dropdown", viewQueries: [{ propertyName: "tenantPopover", first: true, predicate: ["tenantPopover"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (tenantsLoading()) {\n <ax-skeleton [animated]=\"true\" class=\"h-5 w-32 max-w-full\"></ax-skeleton>\n} @else if (tenants$ | async; as tenants) {\n @if (tenants.length > 1) {\n <ax-button\n [text]=\"((tenant$ | async)?.title | translate | async) ?? ''\"\n class=\"ax-sm\"\n look=\"blank\"\n #tenantChooser\n >\n <ax-suffix>\n <ax-icon class=\"fa-solid fa-caret-down\"></ax-icon>\n </ax-suffix>\n </ax-button>\n <ax-popover\n [target]=\"tenantChooser\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n [adaptivityEnabled]=\"true\"\n #tenantPopover\n >\n <div\n class=\"bg-lightest border overflow-hidden rounded-md shadow-md w-full min-w-64 p-1\"\n >\n <axp-tenant-chooser-list\n [simple]=\"true\"\n (tenantChosen)=\"closePopover()\"\n ></axp-tenant-chooser-list>\n </div>\n </ax-popover>\n } @else {\n <ax-button\n [text]=\"((tenant$ | async)?.title | translate | async) ?? ''\"\n class=\"ax-sm\"\n look=\"blank\"\n ></ax-button>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$1.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "visualContextScope", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "closeOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i1$2.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "component", type: AXPTenantChooserListComponent, selector: "axp-tenant-chooser-list", inputs: ["simple"], outputs: ["tenantChosen", "loadingChange"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i5$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
|
|
1307
1344
|
}
|
|
1308
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1345
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPTenantChooserDropdownComponent, decorators: [{
|
|
1309
1346
|
type: Component,
|
|
1310
|
-
args: [{ selector: 'axp-tenant-chooser-dropdown',
|
|
1347
|
+
args: [{ selector: 'axp-tenant-chooser-dropdown', changeDetection: ChangeDetectionStrategy.Eager, imports: [
|
|
1348
|
+
CommonModule,
|
|
1349
|
+
AXTranslationModule,
|
|
1350
|
+
AXButtonModule,
|
|
1351
|
+
AXPopoverModule,
|
|
1352
|
+
AXDecoratorModule,
|
|
1353
|
+
AXSkeletonModule,
|
|
1354
|
+
AXPTenantChooserListComponent,
|
|
1355
|
+
], template: "@if (tenantsLoading()) {\n <ax-skeleton [animated]=\"true\" class=\"h-5 w-32 max-w-full\"></ax-skeleton>\n} @else if (tenants$ | async; as tenants) {\n @if (tenants.length > 1) {\n <ax-button\n [text]=\"((tenant$ | async)?.title | translate | async) ?? ''\"\n class=\"ax-sm\"\n look=\"blank\"\n #tenantChooser\n >\n <ax-suffix>\n <ax-icon class=\"fa-solid fa-caret-down\"></ax-icon>\n </ax-suffix>\n </ax-button>\n <ax-popover\n [target]=\"tenantChooser\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n [adaptivityEnabled]=\"true\"\n #tenantPopover\n >\n <div\n class=\"bg-lightest border overflow-hidden rounded-md shadow-md w-full min-w-64 p-1\"\n >\n <axp-tenant-chooser-list\n [simple]=\"true\"\n (tenantChosen)=\"closePopover()\"\n ></axp-tenant-chooser-list>\n </div>\n </ax-popover>\n } @else {\n <ax-button\n [text]=\"((tenant$ | async)?.title | translate | async) ?? ''\"\n class=\"ax-sm\"\n look=\"blank\"\n ></ax-button>\n }\n}\n" }]
|
|
1311
1356
|
}], propDecorators: { tenantPopover: [{ type: i0.ViewChild, args: ['tenantPopover', { isSignal: true }] }] } });
|
|
1312
1357
|
|
|
1313
1358
|
//#region ---- Profile slot menu hook ----
|
|
@@ -1338,7 +1383,8 @@ class AXMAuthProfileSlotComponent {
|
|
|
1338
1383
|
this.tenant$ = this.sessionService.tenant$;
|
|
1339
1384
|
this.isAuthenticated$ = this.sessionService.isAuthenticated$;
|
|
1340
1385
|
this.isAuthenticated = toSignal(this.sessionService.isAuthenticated$, { initialValue: false });
|
|
1341
|
-
this.menuItems = signal([],
|
|
1386
|
+
this.menuItems = signal([], /* @ts-ignore */
|
|
1387
|
+
...(ngDevMode ? [{ debugName: "menuItems" }] : /* istanbul ignore next */ []));
|
|
1342
1388
|
//#endregion
|
|
1343
1389
|
//#region ---- UI Handlers ----
|
|
1344
1390
|
this.appName = () => this.sessionService.application?.name;
|
|
@@ -1432,17 +1478,17 @@ class AXMAuthProfileSlotComponent {
|
|
|
1432
1478
|
await this.commandService.execute(command.name, command.options ?? {});
|
|
1433
1479
|
}
|
|
1434
1480
|
}
|
|
1435
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1436
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1481
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthProfileSlotComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1482
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXMAuthProfileSlotComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: "@if (isAuthenticated$ | async) {\n <div class=\"size-fit\">\n <div #avatar>\n <axp-user-avatar\n [size]=\"36\"\n [userId]=\"$safeNavigationMigration((user$ | async)?.id)!\"\n [showPresence]=\"true\"\n ></axp-user-avatar>\n </div>\n\n <ax-popover\n [target]=\"avatar\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n [adaptivityEnabled]=\"false\"\n #p\n >\n <div\n class=\"bg-lightest border border-lightest rounded-md shadow-md w-full min-w-64\"\n >\n <div class=\"flex flex-col items-center p-4 border-b\">\n <axp-user-avatar\n [size]=\"64\"\n [userId]=\"$safeNavigationMigration((user$ | async)?.id)!\"\n [showPresence]=\"false\"\n ></axp-user-avatar>\n\n <div class=\"flex flex-col items-center justify-center mt-2\">\n <div class=\"text-base font-bold\">{{ (user$ | async)?.title }}</div>\n <axp-tenant-chooser-dropdown></axp-tenant-chooser-dropdown>\n </div>\n </div>\n <div class=\"axp-profile-slot-menus\">\n <ul>\n @for (item of menuItems(); track item.name ?? item.title) {\n @if (item.visible != false) {\n @if (hasProfileSlotMenuBreakBefore(item.break)) {\n <li class=\"axp-profile-slot-menu-break\" role=\"separator\"></li>\n }\n <li [class]=\"menuItemClass(item)\">\n <a (click)=\"handleMenuItemClick(item, p)\">\n <i [class]=\"item.icon\"></i>\n <span class=\"flex-1\">{{\n item.title | translate | async\n }}</span>\n </a>\n </li>\n @if (hasProfileSlotMenuBreakAfter(item.break)) {\n <li class=\"axp-profile-slot-menu-break\" role=\"separator\"></li>\n }\n }\n }\n </ul>\n </div>\n </div>\n </ax-popover>\n </div>\n} @else {\n <ax-button\n color=\"default\"\n look=\"blank\"\n text=\"Sign Up / Sign In\"\n (click)=\"handleSignIn()\"\n >\n <ax-icon>\n <i class=\"fa-solid fa-user text-slate-400 dark:text-slate-200\"></i>\n </ax-icon>\n </ax-button>\n}\n", styles: ["@layer properties;.axp-profile-slot-menus ul{margin-top:calc(var(--spacing, .25rem) * 2);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-border-default);padding-inline:calc(var(--spacing, .25rem) * 2)}.axp-profile-slot-menus ul:last-child{border-style:var(--tw-border-style);border-width:0px}.axp-profile-slot-menus ul li{display:flex;cursor:pointer;border-radius:var(--radius-md, .375rem)}.axp-profile-slot-menus ul li:last-child{margin-bottom:calc(var(--spacing, .25rem) * 2)}.axp-profile-slot-menus ul li:hover{background-color:rgba(var(--ax-sys-color-dark-surface))}.axp-profile-slot-menus ul li.axp-profile-slot-menu-break{pointer-events:none;margin-inline:calc(var(--spacing, .25rem) * 2);margin-block:var(--spacing, .25rem);height:0px;min-height:0px;cursor:default;border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-border-default);padding:0}.axp-profile-slot-menus ul li.axp-profile-slot-menu-break:hover{background-color:transparent}.axp-profile-slot-menus ul li i{margin-inline-end:calc(var(--spacing, .25rem) * 3);display:grid;height:calc(var(--spacing, .25rem) * 6);width:calc(var(--spacing, .25rem) * 6);place-items:center;font-size:var(--text-xl, 1.25rem);line-height:var(--tw-leading, var(--text-xl--line-height, calc(1.75 / 1.25)))}.axp-profile-slot-menus ul li a{display:flex;height:100%;width:100%;align-items:center;gap:calc(var(--spacing, .25rem) * 2);padding:calc(var(--spacing, .25rem) * 2)}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type:
|
|
1437
1483
|
//
|
|
1438
|
-
AXImageModule }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$1.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "closeOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type:
|
|
1484
|
+
AXImageModule }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$1.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "visualContextScope", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "closeOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type:
|
|
1439
1485
|
// AXKBDComponent,
|
|
1440
1486
|
// AXKBDItemComponent,
|
|
1441
|
-
AXLoadingModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPUserAvatarComponent, selector: "axp-user-avatar", inputs: ["size", "userId"] }, { kind: "component", type:
|
|
1487
|
+
AXLoadingModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPUserAvatarComponent, selector: "axp-user-avatar", inputs: ["size", "userId", "showPresence", "displayName", "displayAvatar"] }, { kind: "component", type:
|
|
1442
1488
|
//
|
|
1443
|
-
AXPTenantChooserDropdownComponent, selector: "axp-tenant-chooser-dropdown" }, { kind: "pipe", type:
|
|
1489
|
+
AXPTenantChooserDropdownComponent, selector: "axp-tenant-chooser-dropdown" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i5$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
1444
1490
|
}
|
|
1445
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1491
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthProfileSlotComponent, decorators: [{
|
|
1446
1492
|
type: Component,
|
|
1447
1493
|
args: [{ imports: [
|
|
1448
1494
|
CommonModule,
|
|
@@ -1460,7 +1506,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1460
1506
|
AXPUserAvatarComponent,
|
|
1461
1507
|
//
|
|
1462
1508
|
AXPTenantChooserDropdownComponent,
|
|
1463
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@if (isAuthenticated$ | async) {\n <div class=\"size-fit\">\n <div #avatar>\n <axp-user-avatar\n [size]=\"36\"\n [userId]=\"(user$ | async)?.id!\"\n ></axp-user-avatar>\n </div>\n\n <ax-popover
|
|
1509
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@if (isAuthenticated$ | async) {\n <div class=\"size-fit\">\n <div #avatar>\n <axp-user-avatar\n [size]=\"36\"\n [userId]=\"$safeNavigationMigration((user$ | async)?.id)!\"\n [showPresence]=\"true\"\n ></axp-user-avatar>\n </div>\n\n <ax-popover\n [target]=\"avatar\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n [adaptivityEnabled]=\"false\"\n #p\n >\n <div\n class=\"bg-lightest border border-lightest rounded-md shadow-md w-full min-w-64\"\n >\n <div class=\"flex flex-col items-center p-4 border-b\">\n <axp-user-avatar\n [size]=\"64\"\n [userId]=\"$safeNavigationMigration((user$ | async)?.id)!\"\n [showPresence]=\"false\"\n ></axp-user-avatar>\n\n <div class=\"flex flex-col items-center justify-center mt-2\">\n <div class=\"text-base font-bold\">{{ (user$ | async)?.title }}</div>\n <axp-tenant-chooser-dropdown></axp-tenant-chooser-dropdown>\n </div>\n </div>\n <div class=\"axp-profile-slot-menus\">\n <ul>\n @for (item of menuItems(); track item.name ?? item.title) {\n @if (item.visible != false) {\n @if (hasProfileSlotMenuBreakBefore(item.break)) {\n <li class=\"axp-profile-slot-menu-break\" role=\"separator\"></li>\n }\n <li [class]=\"menuItemClass(item)\">\n <a (click)=\"handleMenuItemClick(item, p)\">\n <i [class]=\"item.icon\"></i>\n <span class=\"flex-1\">{{\n item.title | translate | async\n }}</span>\n </a>\n </li>\n @if (hasProfileSlotMenuBreakAfter(item.break)) {\n <li class=\"axp-profile-slot-menu-break\" role=\"separator\"></li>\n }\n }\n }\n </ul>\n </div>\n </div>\n </ax-popover>\n </div>\n} @else {\n <ax-button\n color=\"default\"\n look=\"blank\"\n text=\"Sign Up / Sign In\"\n (click)=\"handleSignIn()\"\n >\n <ax-icon>\n <i class=\"fa-solid fa-user text-slate-400 dark:text-slate-200\"></i>\n </ax-icon>\n </ax-button>\n}\n", styles: ["@layer properties;.axp-profile-slot-menus ul{margin-top:calc(var(--spacing, .25rem) * 2);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-border-default);padding-inline:calc(var(--spacing, .25rem) * 2)}.axp-profile-slot-menus ul:last-child{border-style:var(--tw-border-style);border-width:0px}.axp-profile-slot-menus ul li{display:flex;cursor:pointer;border-radius:var(--radius-md, .375rem)}.axp-profile-slot-menus ul li:last-child{margin-bottom:calc(var(--spacing, .25rem) * 2)}.axp-profile-slot-menus ul li:hover{background-color:rgba(var(--ax-sys-color-dark-surface))}.axp-profile-slot-menus ul li.axp-profile-slot-menu-break{pointer-events:none;margin-inline:calc(var(--spacing, .25rem) * 2);margin-block:var(--spacing, .25rem);height:0px;min-height:0px;cursor:default;border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-border-default);padding:0}.axp-profile-slot-menus ul li.axp-profile-slot-menu-break:hover{background-color:transparent}.axp-profile-slot-menus ul li i{margin-inline-end:calc(var(--spacing, .25rem) * 3);display:grid;height:calc(var(--spacing, .25rem) * 6);width:calc(var(--spacing, .25rem) * 6);place-items:center;font-size:var(--text-xl, 1.25rem);line-height:var(--tw-leading, var(--text-xl--line-height, calc(1.75 / 1.25)))}.axp-profile-slot-menus ul li a{display:flex;height:100%;width:100%;align-items:center;gap:calc(var(--spacing, .25rem) * 2);padding:calc(var(--spacing, .25rem) * 2)}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
|
|
1464
1510
|
}] });
|
|
1465
1511
|
|
|
1466
1512
|
class AXMUserProfileCardSlotComponent {
|
|
@@ -1473,15 +1519,18 @@ class AXMUserProfileCardSlotComponent {
|
|
|
1473
1519
|
this.isCompactMode = computed(() => {
|
|
1474
1520
|
this.deviceService.screenSize();
|
|
1475
1521
|
return this.themeStore.effectiveMenuVerticalMode() === AXPMenuVerticalMode.Compact;
|
|
1476
|
-
},
|
|
1477
|
-
|
|
1478
|
-
this.
|
|
1522
|
+
}, /* @ts-ignore */
|
|
1523
|
+
...(ngDevMode ? [{ debugName: "isCompactMode" }] : /* istanbul ignore next */ []));
|
|
1524
|
+
this.hasPicture = signal(true, /* @ts-ignore */
|
|
1525
|
+
...(ngDevMode ? [{ debugName: "hasPicture" }] : /* istanbul ignore next */ []));
|
|
1526
|
+
this.avatarText = signal('', /* @ts-ignore */
|
|
1527
|
+
...(ngDevMode ? [{ debugName: "avatarText" }] : /* istanbul ignore next */ []));
|
|
1479
1528
|
this.user$ = this.sessionService.user$;
|
|
1480
1529
|
this.tenant$ = this.sessionService.tenant$;
|
|
1481
1530
|
this.isAuthenticated$ = this.sessionService.isAuthenticated$;
|
|
1482
1531
|
this.appName = () => this.sessionService.application?.name;
|
|
1483
1532
|
this.getAvatarText = () => {
|
|
1484
|
-
this.user$.pipe(first
|
|
1533
|
+
this.user$.pipe(first()).subscribe((user) => {
|
|
1485
1534
|
const names = user?.title.split(' ');
|
|
1486
1535
|
if (names?.length && names?.length > 1) {
|
|
1487
1536
|
this.avatarText.set(`${names[0][0].toUpperCase()}${names[names.length - 1][0].toUpperCase()}`);
|
|
@@ -1528,16 +1577,16 @@ class AXMUserProfileCardSlotComponent {
|
|
|
1528
1577
|
this.src = '';
|
|
1529
1578
|
}
|
|
1530
1579
|
}
|
|
1531
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1532
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1580
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMUserProfileCardSlotComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1581
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXMUserProfileCardSlotComponent, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "profilePopover", first: true, predicate: ["profilePopover"], descendants: true }], ngImport: i0, template: "@if((isAuthenticated$ | async)) {\n<div class=\"p-3 flex items-center gap-1 border-b border-border-lighter\" [class.justify-center]=\"isCompactMode()\">\n <div #avatar>\n <axp-user-avatar\n [size]=\"48\"\n [userId]=\"$safeNavigationMigration((user$ | async)?.id)!\"\n [showPresence]=\"false\"\n ></axp-user-avatar>\n </div>\n @if (!isCompactMode()) {\n <div class=\"flex flex-col\">\n <ax-title class=\"text-sm font-medium px-3\">{{ (user$ | async)?.title }}</ax-title>\n <axp-tenant-chooser-dropdown />\n </div>\n }\n</div>\n}\n", dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type:
|
|
1533
1582
|
//
|
|
1534
1583
|
AXImageModule }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type:
|
|
1535
1584
|
//
|
|
1536
|
-
AXPTenantChooserDropdownComponent, selector: "axp-tenant-chooser-dropdown" }, { kind: "component", type: AXPUserAvatarComponent, selector: "axp-user-avatar", inputs: ["size", "userId"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
|
|
1585
|
+
AXPTenantChooserDropdownComponent, selector: "axp-tenant-chooser-dropdown" }, { kind: "component", type: AXPUserAvatarComponent, selector: "axp-user-avatar", inputs: ["size", "userId", "showPresence", "displayName", "displayAvatar"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
|
|
1537
1586
|
}
|
|
1538
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1587
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMUserProfileCardSlotComponent, decorators: [{
|
|
1539
1588
|
type: Component,
|
|
1540
|
-
args: [{ imports: [
|
|
1589
|
+
args: [{ changeDetection: ChangeDetectionStrategy.Eager, imports: [
|
|
1541
1590
|
RouterModule,
|
|
1542
1591
|
//
|
|
1543
1592
|
AXImageModule,
|
|
@@ -1551,7 +1600,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1551
1600
|
AXPTenantChooserDropdownComponent,
|
|
1552
1601
|
AsyncPipe,
|
|
1553
1602
|
AXPUserAvatarComponent,
|
|
1554
|
-
], template: "@if((isAuthenticated$ | async)) {\n<div class=\"p-3 flex items-center gap-1 border-b border-border-lighter\" [class.justify-center]=\"isCompactMode()\">\n <div #avatar>\n <axp-user-avatar
|
|
1603
|
+
], template: "@if((isAuthenticated$ | async)) {\n<div class=\"p-3 flex items-center gap-1 border-b border-border-lighter\" [class.justify-center]=\"isCompactMode()\">\n <div #avatar>\n <axp-user-avatar\n [size]=\"48\"\n [userId]=\"$safeNavigationMigration((user$ | async)?.id)!\"\n [showPresence]=\"false\"\n ></axp-user-avatar>\n </div>\n @if (!isCompactMode()) {\n <div class=\"flex flex-col\">\n <ax-title class=\"text-sm font-medium px-3\">{{ (user$ | async)?.title }}</ax-title>\n <axp-tenant-chooser-dropdown />\n </div>\n }\n</div>\n}\n" }]
|
|
1555
1604
|
}], ctorParameters: () => [], propDecorators: { profilePopover: [{
|
|
1556
1605
|
type: ViewChild,
|
|
1557
1606
|
args: ['profilePopover']
|
|
@@ -1566,7 +1615,7 @@ class AXMUserDeviceSessionsServiceImp extends AXMUserDeviceSessionsService {
|
|
|
1566
1615
|
this.sessionService = inject(AXPSessionService);
|
|
1567
1616
|
this.entityService = inject(AXPEntityService);
|
|
1568
1617
|
this.deviceSessionsDataAccessor = this.entityService
|
|
1569
|
-
.withEntity(RootConfig
|
|
1618
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.deviceSessions.name)
|
|
1570
1619
|
.data();
|
|
1571
1620
|
this.deviceSessionsService = inject(AXMDeviceSessionsService);
|
|
1572
1621
|
this.settingsService = inject(AXPSettingsService);
|
|
@@ -1602,7 +1651,11 @@ class AXMUserDeviceSessionsServiceImp extends AXMUserDeviceSessionsService {
|
|
|
1602
1651
|
return mostRecentSession;
|
|
1603
1652
|
}
|
|
1604
1653
|
async terminateSession(sessionId) {
|
|
1605
|
-
await this.deviceSessionsDataAccessor.update(sessionId, {
|
|
1654
|
+
await this.deviceSessionsDataAccessor.update(sessionId, {
|
|
1655
|
+
status: 'revoked',
|
|
1656
|
+
loggedOutAt: new Date(),
|
|
1657
|
+
isActiveSession: false,
|
|
1658
|
+
});
|
|
1606
1659
|
await this.showTerminateSuccessToast();
|
|
1607
1660
|
}
|
|
1608
1661
|
async terminateAllSession() {
|
|
@@ -1628,53 +1681,73 @@ class AXMUserDeviceSessionsServiceImp extends AXMUserDeviceSessionsService {
|
|
|
1628
1681
|
timeOutProgress: true,
|
|
1629
1682
|
});
|
|
1630
1683
|
}
|
|
1631
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1632
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
1684
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMUserDeviceSessionsServiceImp, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1685
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMUserDeviceSessionsServiceImp }); }
|
|
1633
1686
|
}
|
|
1634
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1687
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMUserDeviceSessionsServiceImp, decorators: [{
|
|
1635
1688
|
type: Injectable
|
|
1636
1689
|
}] });
|
|
1637
1690
|
|
|
1638
|
-
|
|
1691
|
+
//#region ----- Tenant chooser guard -----
|
|
1692
|
+
const canActivateTenantChooser = async (_route, _state) => {
|
|
1639
1693
|
const sessionService = inject(AXPSessionService);
|
|
1640
1694
|
const authStrategyRegistry = inject(AXPAuthStrategyRegistryService);
|
|
1641
1695
|
const router = inject(Router);
|
|
1642
1696
|
const strategyName = sessionService.getSessionData()?.strategy;
|
|
1643
1697
|
const strategy = authStrategyRegistry.get(strategyName);
|
|
1644
1698
|
if (!sessionService.user?.id) {
|
|
1699
|
+
traceAuthGuard('Tenant chooser → login (no user)');
|
|
1700
|
+
return router.createUrlTree(['/auth/login']);
|
|
1701
|
+
}
|
|
1702
|
+
if (!sessionService.hasSessionCredentials()) {
|
|
1703
|
+
traceAuthGuard('Tenant chooser → login (no credentials)');
|
|
1645
1704
|
return router.createUrlTree(['/auth/login']);
|
|
1646
1705
|
}
|
|
1647
|
-
|
|
1706
|
+
// Shared session cache — same ListTenants as tenants$ / chooser list.
|
|
1707
|
+
const tenants = await sessionService.getTenantsList();
|
|
1708
|
+
traceAuthGuard('Tenant chooser catalog', () => ({ count: tenants.length }));
|
|
1648
1709
|
if (tenants.length === 0) {
|
|
1649
|
-
await sessionService.signout();
|
|
1650
1710
|
window.alert('You do not have any tenant assigned to your account and cannot use the site. Please contact your administrator.');
|
|
1651
|
-
return
|
|
1711
|
+
// Stay on chooser rather than return false (cancels nav and sticks on prior login URL).
|
|
1712
|
+
return true;
|
|
1652
1713
|
}
|
|
1653
1714
|
if (tenants.length === 1) {
|
|
1654
1715
|
if (strategy && typeof strategy.updateToken === 'function') {
|
|
1655
|
-
|
|
1716
|
+
await sessionService.updateToken({
|
|
1656
1717
|
user: sessionService.user,
|
|
1657
1718
|
tenant: tenants[0],
|
|
1658
|
-
};
|
|
1659
|
-
|
|
1719
|
+
});
|
|
1720
|
+
traceAuthGuard('Tenant chooser auto-bound single tenant → app chooser');
|
|
1660
1721
|
return router.createUrlTree(['/auth/account/app-chooser']);
|
|
1661
1722
|
}
|
|
1662
|
-
return
|
|
1723
|
+
return true;
|
|
1663
1724
|
}
|
|
1664
1725
|
return true;
|
|
1665
1726
|
};
|
|
1727
|
+
//#endregion
|
|
1666
1728
|
|
|
1667
|
-
|
|
1729
|
+
//#region ----- App chooser guard -----
|
|
1730
|
+
const canActivateAppChooser = async (_route, _state) => {
|
|
1668
1731
|
const sessionService = inject(AXPSessionService);
|
|
1669
1732
|
const authStrategyRegistry = inject(AXPAuthStrategyRegistryService);
|
|
1670
1733
|
const homePageService = inject(AXPHomePageService);
|
|
1671
1734
|
const router = inject(Router);
|
|
1672
1735
|
const strategyName = sessionService.getSessionData()?.strategy;
|
|
1673
1736
|
const strategy = authStrategyRegistry.get(strategyName);
|
|
1674
|
-
|
|
1737
|
+
if (!sessionService.tenant?.id) {
|
|
1738
|
+
traceAuthGuard('App chooser → tenant chooser (no tenant)');
|
|
1739
|
+
return router.createUrlTree(['/auth/account/tenant-chooser']);
|
|
1740
|
+
}
|
|
1741
|
+
if (!sessionService.hasSessionCredentials()) {
|
|
1742
|
+
traceAuthGuard('App chooser → login (no credentials)');
|
|
1743
|
+
return router.createUrlTree(['/auth/login']);
|
|
1744
|
+
}
|
|
1745
|
+
// Shared session cache — same ListApplications as applications$ / chooser list.
|
|
1746
|
+
const apps = await sessionService.getApplicationsList();
|
|
1747
|
+
traceAuthGuard('App chooser catalog', () => ({ count: apps.length }));
|
|
1675
1748
|
if (apps.length === 0) {
|
|
1676
|
-
|
|
1677
|
-
return
|
|
1749
|
+
// Show the chooser empty state instead of cancelling navigation (return false sticks on login).
|
|
1750
|
+
return true;
|
|
1678
1751
|
}
|
|
1679
1752
|
if (apps.length === 1) {
|
|
1680
1753
|
const tenantId = sessionService.tenant?.id;
|
|
@@ -1682,39 +1755,44 @@ const canActivateAppChooser = async (route, state) => {
|
|
|
1682
1755
|
throw new Error('Tenant ID is missing. Please contact support.');
|
|
1683
1756
|
}
|
|
1684
1757
|
if (strategy && typeof strategy.updateToken === 'function') {
|
|
1685
|
-
|
|
1758
|
+
await sessionService.updateToken({
|
|
1686
1759
|
user: sessionService.user,
|
|
1687
1760
|
tenant: sessionService.tenant,
|
|
1688
1761
|
application: apps[0],
|
|
1689
|
-
};
|
|
1690
|
-
await
|
|
1691
|
-
|
|
1762
|
+
});
|
|
1763
|
+
// Return UrlTree — never await router.navigate inside canActivate (deadlocks).
|
|
1764
|
+
traceAuthGuard('App chooser auto-bound single app → home');
|
|
1765
|
+
return homePageService.resolveAuthorizedHomeUrlTree();
|
|
1692
1766
|
}
|
|
1693
|
-
return
|
|
1767
|
+
return true;
|
|
1694
1768
|
}
|
|
1769
|
+
// Stale application from a prior session must not mark the user Authorized on this screen.
|
|
1770
|
+
sessionService.clearApplicationSelection();
|
|
1771
|
+
traceAuthGuard('App chooser showing multi-app UI');
|
|
1695
1772
|
return true;
|
|
1696
1773
|
};
|
|
1774
|
+
//#endregion
|
|
1697
1775
|
|
|
1698
1776
|
function routesFacory() {
|
|
1699
1777
|
let routes = [];
|
|
1700
1778
|
routes = [
|
|
1701
1779
|
{
|
|
1702
1780
|
path: 'tenant-chooser',
|
|
1703
|
-
loadComponent: () => import('./acorex-platform-module-auth-client-tenant-chooser.component-
|
|
1781
|
+
loadComponent: () => import('./acorex-platform-module-auth-client-tenant-chooser.component-CHmg7D5H.mjs').then((c) => c.AXPAuthTenantChooserComponent),
|
|
1704
1782
|
canActivate: [AXPAuthGuard, canActivateTenantChooser],
|
|
1705
1783
|
},
|
|
1706
1784
|
{
|
|
1707
1785
|
path: 'app-chooser',
|
|
1708
|
-
loadComponent: () => import('./acorex-platform-module-auth-client-app-chooser.component-
|
|
1786
|
+
loadComponent: () => import('./acorex-platform-module-auth-client-app-chooser.component-BVbu-f8h.mjs').then((c) => c.AXPAuthAppChooserComponent),
|
|
1709
1787
|
canActivate: [AXPAuthGuard, canActivateAppChooser],
|
|
1710
1788
|
},
|
|
1711
1789
|
];
|
|
1712
1790
|
return routes;
|
|
1713
1791
|
}
|
|
1714
1792
|
class AXPAccountModule {
|
|
1715
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1716
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "
|
|
1717
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "
|
|
1793
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAccountModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1794
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXPAccountModule, imports: [RouterModule, i1$4.AXPComponentSlotModule] }); }
|
|
1795
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAccountModule, providers: [
|
|
1718
1796
|
{
|
|
1719
1797
|
provide: ROUTES,
|
|
1720
1798
|
multi: true,
|
|
@@ -1748,7 +1826,7 @@ class AXPAccountModule {
|
|
|
1748
1826
|
],
|
|
1749
1827
|
})] }); }
|
|
1750
1828
|
}
|
|
1751
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1829
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAccountModule, decorators: [{
|
|
1752
1830
|
type: NgModule,
|
|
1753
1831
|
args: [{
|
|
1754
1832
|
declarations: [],
|
|
@@ -1814,18 +1892,23 @@ class AXPIdleLockService {
|
|
|
1814
1892
|
//#region ---- Constructor ----
|
|
1815
1893
|
constructor() {
|
|
1816
1894
|
//#region ---- State ----
|
|
1817
|
-
this.locked = signal(false,
|
|
1818
|
-
|
|
1819
|
-
this.
|
|
1895
|
+
this.locked = signal(false, /* @ts-ignore */
|
|
1896
|
+
...(ngDevMode ? [{ debugName: "locked" }] : /* istanbul ignore next */ []));
|
|
1897
|
+
this.idleTimeoutMs = signal(DEFAULT_LOCK_WHEN_IDLE_MINUTES * 60_000, /* @ts-ignore */
|
|
1898
|
+
...(ngDevMode ? [{ debugName: "idleTimeoutMs" }] : /* istanbul ignore next */ []));
|
|
1899
|
+
this.enabled = signal(false, /* @ts-ignore */
|
|
1900
|
+
...(ngDevMode ? [{ debugName: "enabled" }] : /* istanbul ignore next */ []));
|
|
1820
1901
|
/** Whether manual or idle lock is available (Lock When Idle setting is enabled). */
|
|
1821
1902
|
this.canLock = this.enabled.asReadonly();
|
|
1822
|
-
this.storedPinCode = signal('',
|
|
1903
|
+
this.storedPinCode = signal('', /* @ts-ignore */
|
|
1904
|
+
...(ngDevMode ? [{ debugName: "storedPinCode" }] : /* istanbul ignore next */ []));
|
|
1823
1905
|
this.lastActivityAt = Date.now();
|
|
1824
1906
|
this.lastMouseMoveAt = 0;
|
|
1825
1907
|
this.idleCheckTimerId = null;
|
|
1826
1908
|
this.overlayRef = null;
|
|
1827
1909
|
this.overlayOpening = false;
|
|
1828
1910
|
this.enableTask = Promise.resolve();
|
|
1911
|
+
this.pendingLockScreenOffer = false;
|
|
1829
1912
|
//#endregion
|
|
1830
1913
|
//#region ---- Services & Dependencies ----
|
|
1831
1914
|
this.sessionService = inject(AXPSessionService);
|
|
@@ -1848,20 +1931,18 @@ class AXPIdleLockService {
|
|
|
1848
1931
|
this.recordActivity();
|
|
1849
1932
|
};
|
|
1850
1933
|
this.sessionService.status$
|
|
1851
|
-
.pipe(filter((status) => status === AXPSessionStatus.
|
|
1852
|
-
status === AXPSessionStatus.Authorized ||
|
|
1934
|
+
.pipe(filter((status) => status === AXPSessionStatus.Authorized ||
|
|
1853
1935
|
status === AXPSessionStatus.SignedOut ||
|
|
1854
1936
|
status === AXPSessionStatus.Expired), takeUntilDestroyed(this.destroyRef))
|
|
1855
1937
|
.subscribe((status) => {
|
|
1856
|
-
|
|
1857
|
-
if (isActiveSession) {
|
|
1938
|
+
if (status === AXPSessionStatus.Authorized) {
|
|
1858
1939
|
void this.scheduleEnable();
|
|
1859
1940
|
return;
|
|
1860
1941
|
}
|
|
1861
1942
|
void this.handleInactiveSession(status);
|
|
1862
1943
|
});
|
|
1863
1944
|
afterNextRender(() => {
|
|
1864
|
-
if (this.sessionService.isLocked()) {
|
|
1945
|
+
if (this.sessionService.isLocked() && this.sessionService.isAuthorized) {
|
|
1865
1946
|
void this.scheduleEnable();
|
|
1866
1947
|
}
|
|
1867
1948
|
}, { injector: this.injector });
|
|
@@ -1883,7 +1964,7 @@ class AXPIdleLockService {
|
|
|
1883
1964
|
}
|
|
1884
1965
|
async verifyPassword(password) {
|
|
1885
1966
|
const userId = this.sessionService.user?.id;
|
|
1886
|
-
if (isNil(userId) || isEmpty(password)) {
|
|
1967
|
+
if (isNil(userId) || isEmpty(password) || !this.canLoadUserSecurityFields()) {
|
|
1887
1968
|
return false;
|
|
1888
1969
|
}
|
|
1889
1970
|
try {
|
|
@@ -1908,11 +1989,25 @@ class AXPIdleLockService {
|
|
|
1908
1989
|
lockScreen() {
|
|
1909
1990
|
this.lock();
|
|
1910
1991
|
}
|
|
1992
|
+
/** Marks that PIN setup succeeded so the caller can offer lock-screen activation. */
|
|
1993
|
+
requestLockScreenOffer() {
|
|
1994
|
+
this.pendingLockScreenOffer = true;
|
|
1995
|
+
}
|
|
1996
|
+
/** Returns whether PIN setup requested a lock-screen offer, then clears the flag. */
|
|
1997
|
+
consumeLockScreenOffer() {
|
|
1998
|
+
const pending = this.pendingLockScreenOffer;
|
|
1999
|
+
this.pendingLockScreenOffer = false;
|
|
2000
|
+
return pending;
|
|
2001
|
+
}
|
|
1911
2002
|
async refreshPinState() {
|
|
1912
2003
|
if (!this.isOperational()) {
|
|
1913
2004
|
this.storedPinCode.set('');
|
|
1914
2005
|
return;
|
|
1915
2006
|
}
|
|
2007
|
+
if (!this.canLoadUserSecurityFields()) {
|
|
2008
|
+
this.storedPinCode.set('');
|
|
2009
|
+
return;
|
|
2010
|
+
}
|
|
1916
2011
|
const userId = this.sessionService.user?.id;
|
|
1917
2012
|
if (isNil(userId)) {
|
|
1918
2013
|
this.storedPinCode.set('');
|
|
@@ -1931,13 +2026,17 @@ class AXPIdleLockService {
|
|
|
1931
2026
|
this.storedPinCode.set('');
|
|
1932
2027
|
}
|
|
1933
2028
|
}
|
|
2029
|
+
/** Refreshes lock-when-idle settings only (no User entity fetch). Used by profile menu hooks. */
|
|
2030
|
+
async refreshLockMenuState() {
|
|
2031
|
+
await this.refreshConfiguration();
|
|
2032
|
+
}
|
|
1934
2033
|
/** Refreshes lock settings and PIN state for menu/commands. */
|
|
1935
2034
|
async refreshLockState() {
|
|
1936
2035
|
await this.refreshConfiguration();
|
|
1937
2036
|
if (!this.isOperational()) {
|
|
1938
2037
|
return;
|
|
1939
2038
|
}
|
|
1940
|
-
await this.
|
|
2039
|
+
await this.ensurePinStateLoaded();
|
|
1941
2040
|
}
|
|
1942
2041
|
/** Restores the lock overlay when the persisted session is locked. */
|
|
1943
2042
|
restoreFromPersistedSession() {
|
|
@@ -1953,13 +2052,26 @@ class AXPIdleLockService {
|
|
|
1953
2052
|
return;
|
|
1954
2053
|
}
|
|
1955
2054
|
const status = await firstValueFrom(this.sessionService.status$);
|
|
1956
|
-
|
|
1957
|
-
if (isActiveSession) {
|
|
2055
|
+
if (status === AXPSessionStatus.Authorized) {
|
|
1958
2056
|
await this.scheduleEnable();
|
|
1959
2057
|
}
|
|
1960
2058
|
}
|
|
1961
2059
|
//#endregion
|
|
1962
2060
|
//#region ---- Private Methods ----
|
|
2061
|
+
/** PIN/password entity reads require a fully authorized app context, except when restoring a lock overlay. */
|
|
2062
|
+
canLoadUserSecurityFields() {
|
|
2063
|
+
return this.sessionService.isReadyForAppScopedApi || this.sessionService.isLocked();
|
|
2064
|
+
}
|
|
2065
|
+
async ensurePinStateLoaded() {
|
|
2066
|
+
if (!this.isOperational()) {
|
|
2067
|
+
this.storedPinCode.set('');
|
|
2068
|
+
return;
|
|
2069
|
+
}
|
|
2070
|
+
if (!this.canLoadUserSecurityFields()) {
|
|
2071
|
+
await firstValueFrom(this.sessionService.isReadyForAppScopedApi$.pipe(filter((ready) => ready), take(1)));
|
|
2072
|
+
}
|
|
2073
|
+
await this.refreshPinState();
|
|
2074
|
+
}
|
|
1963
2075
|
scheduleEnable() {
|
|
1964
2076
|
this.enableTask = this.enableTask.then(() => this.runEnable());
|
|
1965
2077
|
return this.enableTask;
|
|
@@ -1967,7 +2079,7 @@ class AXPIdleLockService {
|
|
|
1967
2079
|
async runEnable() {
|
|
1968
2080
|
await this.refreshConfiguration();
|
|
1969
2081
|
if (this.sessionService.isLocked()) {
|
|
1970
|
-
await this.
|
|
2082
|
+
await this.ensurePinStateLoaded();
|
|
1971
2083
|
this.restoreLockedSession();
|
|
1972
2084
|
return;
|
|
1973
2085
|
}
|
|
@@ -1975,7 +2087,7 @@ class AXPIdleLockService {
|
|
|
1975
2087
|
this.disable(false);
|
|
1976
2088
|
return;
|
|
1977
2089
|
}
|
|
1978
|
-
await this.
|
|
2090
|
+
await this.ensurePinStateLoaded();
|
|
1979
2091
|
this.resetUnlockedRuntimeState();
|
|
1980
2092
|
this.attachActivityListeners();
|
|
1981
2093
|
this.startIdleCheck();
|
|
@@ -2026,8 +2138,7 @@ class AXPIdleLockService {
|
|
|
2026
2138
|
}
|
|
2027
2139
|
async applyLockWhenIdleSettingChange() {
|
|
2028
2140
|
const status = await firstValueFrom(this.sessionService.status$);
|
|
2029
|
-
|
|
2030
|
-
if (!isActiveSession) {
|
|
2141
|
+
if (status !== AXPSessionStatus.Authorized) {
|
|
2031
2142
|
return;
|
|
2032
2143
|
}
|
|
2033
2144
|
await this.scheduleEnable();
|
|
@@ -2064,7 +2175,7 @@ class AXPIdleLockService {
|
|
|
2064
2175
|
this.overlayOpening = true;
|
|
2065
2176
|
this.locked.set(true);
|
|
2066
2177
|
try {
|
|
2067
|
-
const { AXMSessionLockOverlayComponent: overlayComponent } = await import('./acorex-platform-module-auth-client-session-lock-overlay.component-
|
|
2178
|
+
const { AXMSessionLockOverlayComponent: overlayComponent } = await import('./acorex-platform-module-auth-client-session-lock-overlay.component-BhsTAmVe.mjs');
|
|
2068
2179
|
const panelClasses = ['axm-session-lock-overlay-shell'];
|
|
2069
2180
|
if (this.platform.isDark()) {
|
|
2070
2181
|
panelClasses.push('ax-dark');
|
|
@@ -2138,10 +2249,10 @@ class AXPIdleLockService {
|
|
|
2138
2249
|
events.forEach((eventName) => document.removeEventListener(eventName, this.onActivity, true));
|
|
2139
2250
|
document.removeEventListener('mousemove', this.onMouseMove, true);
|
|
2140
2251
|
}
|
|
2141
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2142
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2252
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPIdleLockService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2253
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPIdleLockService, providedIn: 'root' }); }
|
|
2143
2254
|
}
|
|
2144
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2255
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPIdleLockService, decorators: [{
|
|
2145
2256
|
type: Injectable,
|
|
2146
2257
|
args: [{ providedIn: 'root' }]
|
|
2147
2258
|
}], ctorParameters: () => [] });
|
|
@@ -2152,12 +2263,27 @@ class AXPLogoEntitySyncService {
|
|
|
2152
2263
|
constructor() {
|
|
2153
2264
|
this.session = inject(AXPSessionService);
|
|
2154
2265
|
this.logoRegistration = inject(AXPEntityLogoRegistrationService);
|
|
2266
|
+
this.destroyRef = inject(DestroyRef);
|
|
2267
|
+
this.syncGeneration = 0;
|
|
2155
2268
|
combineLatest([this.session.isAuthorized$, this.session.tenant$])
|
|
2156
|
-
.pipe(
|
|
2269
|
+
.pipe(distinctUntilChanged(([authorized, tenant], [previousAuthorized, previousTenant]) => authorized === previousAuthorized && tenant?.id === previousTenant?.id), switchMap(([authorized, tenant]) => {
|
|
2270
|
+
if (!authorized || !tenant?.id || !this.session.getToken()) {
|
|
2271
|
+
this.syncGeneration++;
|
|
2272
|
+
return EMPTY;
|
|
2273
|
+
}
|
|
2274
|
+
const generation = this.syncGeneration;
|
|
2275
|
+
return from(this.syncEntityLogos(generation));
|
|
2276
|
+
}), takeUntilDestroyed(this.destroyRef))
|
|
2157
2277
|
.subscribe();
|
|
2158
2278
|
}
|
|
2159
|
-
async syncEntityLogos() {
|
|
2279
|
+
async syncEntityLogos(generation) {
|
|
2280
|
+
if (!this.canSyncLogos() || generation !== this.syncGeneration) {
|
|
2281
|
+
return;
|
|
2282
|
+
}
|
|
2160
2283
|
const tenants = await firstValueFrom(this.session.tenants$);
|
|
2284
|
+
if (generation !== this.syncGeneration || !this.canSyncLogos()) {
|
|
2285
|
+
return;
|
|
2286
|
+
}
|
|
2161
2287
|
this.logoRegistration.registerTenants(tenants.map((tenant) => ({
|
|
2162
2288
|
id: tenant.id,
|
|
2163
2289
|
title: tenant.title,
|
|
@@ -2167,16 +2293,22 @@ class AXPLogoEntitySyncService {
|
|
|
2167
2293
|
return;
|
|
2168
2294
|
}
|
|
2169
2295
|
const applications = await firstValueFrom(this.session.applications$);
|
|
2296
|
+
if (generation !== this.syncGeneration || !this.canSyncLogos()) {
|
|
2297
|
+
return;
|
|
2298
|
+
}
|
|
2170
2299
|
this.logoRegistration.registerApplications(applications.map((application) => ({
|
|
2171
2300
|
id: application.id,
|
|
2172
2301
|
title: application.title,
|
|
2173
2302
|
logoUrl: application.logoUrl,
|
|
2174
2303
|
})));
|
|
2175
2304
|
}
|
|
2176
|
-
|
|
2177
|
-
|
|
2305
|
+
canSyncLogos() {
|
|
2306
|
+
return this.session.isAuthorized && !!this.session.getToken() && !!this.session.tenant?.id;
|
|
2307
|
+
}
|
|
2308
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPLogoEntitySyncService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2309
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPLogoEntitySyncService, providedIn: 'root' }); }
|
|
2178
2310
|
}
|
|
2179
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2311
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPLogoEntitySyncService, decorators: [{
|
|
2180
2312
|
type: Injectable,
|
|
2181
2313
|
args: [{ providedIn: 'root' }]
|
|
2182
2314
|
}], ctorParameters: () => [] });
|
|
@@ -2240,10 +2372,8 @@ const CoreProfileGroupsHookProvider = {
|
|
|
2240
2372
|
const CoreProfileSectionsHookProvider = {
|
|
2241
2373
|
key: PROFILE_PAGE_SECTIONS_HOOK,
|
|
2242
2374
|
priority: 0,
|
|
2243
|
-
execute: (payload) =>
|
|
2244
|
-
|
|
2245
|
-
sections: [
|
|
2246
|
-
...payload.sections,
|
|
2375
|
+
execute: (payload) => {
|
|
2376
|
+
const contributed = [
|
|
2247
2377
|
{
|
|
2248
2378
|
id: 'basic-info',
|
|
2249
2379
|
groupId: 'account',
|
|
@@ -2274,7 +2404,7 @@ const CoreProfileSectionsHookProvider = {
|
|
|
2274
2404
|
name: 'change-profile-photo',
|
|
2275
2405
|
title: '@auth:profile-page.sections.profile-photo.actions.manage',
|
|
2276
2406
|
icon: 'far fa-pen',
|
|
2277
|
-
command: { name: AXMAuthCommandKeys.Profile.ChangePhoto
|
|
2407
|
+
command: { name: AXMAuthCommandKeys.Profile.ChangePhoto },
|
|
2278
2408
|
},
|
|
2279
2409
|
],
|
|
2280
2410
|
},
|
|
@@ -2365,23 +2495,33 @@ const CoreProfileSectionsHookProvider = {
|
|
|
2365
2495
|
},
|
|
2366
2496
|
layout: { colSpan: 12 },
|
|
2367
2497
|
},
|
|
2368
|
-
]
|
|
2369
|
-
|
|
2498
|
+
];
|
|
2499
|
+
const matching = payload.groupId
|
|
2500
|
+
? contributed.filter((section) => section.groupId === payload.groupId)
|
|
2501
|
+
: contributed;
|
|
2502
|
+
return {
|
|
2503
|
+
...payload,
|
|
2504
|
+
sections: [...payload.sections, ...matching],
|
|
2505
|
+
};
|
|
2506
|
+
},
|
|
2370
2507
|
};
|
|
2371
2508
|
//#endregion
|
|
2372
2509
|
|
|
2373
2510
|
//#region ---- Security PIN section hook ----
|
|
2374
|
-
const SECURITY_PIN_SECTION_ID = 'security-pin';
|
|
2511
|
+
const SECURITY_PIN_SECTION_ID$1 = 'security-pin';
|
|
2375
2512
|
/** Enriches the security PIN section with change/remove actions when a PIN exists. */
|
|
2376
2513
|
const SecurityPinSectionHookProvider = {
|
|
2377
2514
|
key: PROFILE_PAGE_SECTIONS_HOOK,
|
|
2378
2515
|
priority: 10,
|
|
2379
2516
|
execute: async (payload) => {
|
|
2517
|
+
if (!isUserProfileSectionsGroupRequested(payload, 'security')) {
|
|
2518
|
+
return payload;
|
|
2519
|
+
}
|
|
2380
2520
|
const hasPinCode = await loadHasPinCode();
|
|
2381
2521
|
return {
|
|
2382
2522
|
...payload,
|
|
2383
2523
|
sections: payload.sections.map((section) => {
|
|
2384
|
-
if (section.id !== SECURITY_PIN_SECTION_ID) {
|
|
2524
|
+
if (section.id !== SECURITY_PIN_SECTION_ID$1) {
|
|
2385
2525
|
return section;
|
|
2386
2526
|
}
|
|
2387
2527
|
return {
|
|
@@ -2422,7 +2562,7 @@ async function loadHasPinCode() {
|
|
|
2422
2562
|
}
|
|
2423
2563
|
try {
|
|
2424
2564
|
const user = await entityService
|
|
2425
|
-
.withEntity(RootConfig
|
|
2565
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.users.name)
|
|
2426
2566
|
.data()
|
|
2427
2567
|
.byKey(userId);
|
|
2428
2568
|
return !isEmpty(defaultTo(get(user, 'pinCode'), ''));
|
|
@@ -2468,16 +2608,34 @@ class AXPAuthPasswordChangeTrackingService {
|
|
|
2468
2608
|
buildStorageKey(userId) {
|
|
2469
2609
|
return `${STORAGE_KEY_PREFIX}${userId}`;
|
|
2470
2610
|
}
|
|
2471
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2472
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2611
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAuthPasswordChangeTrackingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2612
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAuthPasswordChangeTrackingService, providedIn: 'root' }); }
|
|
2473
2613
|
}
|
|
2474
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2614
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAuthPasswordChangeTrackingService, decorators: [{
|
|
2475
2615
|
type: Injectable,
|
|
2476
2616
|
args: [{ providedIn: 'root' }]
|
|
2477
2617
|
}] });
|
|
2478
2618
|
|
|
2479
|
-
//#region
|
|
2619
|
+
//#region ----- Constants -----
|
|
2480
2620
|
const CHANGE_PASSWORD_SECTION_ID = 'change-password';
|
|
2621
|
+
const PROFILE_SECTION_INSIGHTS_PATCH_METADATA_KEY = 'profileSectionInsightsPatch';
|
|
2622
|
+
//#endregion
|
|
2623
|
+
//#region ----- Password insight -----
|
|
2624
|
+
/** Builds the last-changed insight shown on the Change Password profile card. */
|
|
2625
|
+
function buildPasswordLastChangedInsights(lastChangedAt) {
|
|
2626
|
+
return [
|
|
2627
|
+
{
|
|
2628
|
+
id: 'last-password-change',
|
|
2629
|
+
icon: 'fa-light fa-fw fa-clock',
|
|
2630
|
+
date: lastChangedAt,
|
|
2631
|
+
datePrefix: '@auth:profile-page.sections.change-password.insights.last-changed',
|
|
2632
|
+
},
|
|
2633
|
+
];
|
|
2634
|
+
}
|
|
2635
|
+
//#endregion
|
|
2636
|
+
|
|
2637
|
+
//#region ---- Section ids ----
|
|
2638
|
+
const SECURITY_PIN_SECTION_ID = 'security-pin';
|
|
2481
2639
|
const ACTIVE_SESSIONS_SECTION_ID = 'active-sessions';
|
|
2482
2640
|
const LOGIN_HISTORY_SECTION_ID = 'login-history';
|
|
2483
2641
|
//#endregion
|
|
@@ -2498,12 +2656,19 @@ class AXPUserProfileSecurityInsightsService {
|
|
|
2498
2656
|
if (!userId) {
|
|
2499
2657
|
return {};
|
|
2500
2658
|
}
|
|
2501
|
-
const sessions = await
|
|
2659
|
+
const [sessions, user] = await Promise.all([
|
|
2660
|
+
this.loadUserSessions(userId),
|
|
2661
|
+
this.loadCurrentUser(userId),
|
|
2662
|
+
]);
|
|
2502
2663
|
const insightsBySectionId = {};
|
|
2503
|
-
const passwordInsights = this.buildPasswordInsights(userId);
|
|
2664
|
+
const passwordInsights = this.buildPasswordInsights(userId, user);
|
|
2504
2665
|
if (!isEmpty(passwordInsights)) {
|
|
2505
2666
|
insightsBySectionId[CHANGE_PASSWORD_SECTION_ID] = passwordInsights;
|
|
2506
2667
|
}
|
|
2668
|
+
const pinInsights = this.buildPinInsights(user);
|
|
2669
|
+
if (!isEmpty(pinInsights)) {
|
|
2670
|
+
insightsBySectionId[SECURITY_PIN_SECTION_ID] = pinInsights;
|
|
2671
|
+
}
|
|
2507
2672
|
const activeSessionInsights = await this.buildActiveSessionInsights(sessions);
|
|
2508
2673
|
if (!isEmpty(activeSessionInsights)) {
|
|
2509
2674
|
insightsBySectionId[ACTIVE_SESSIONS_SECTION_ID] = activeSessionInsights;
|
|
@@ -2516,17 +2681,40 @@ class AXPUserProfileSecurityInsightsService {
|
|
|
2516
2681
|
}
|
|
2517
2682
|
//#endregion
|
|
2518
2683
|
//#region ---- Insight builders ----
|
|
2519
|
-
buildPasswordInsights(userId) {
|
|
2520
|
-
const lastChangedAt = this.
|
|
2521
|
-
|
|
2522
|
-
|
|
2684
|
+
buildPasswordInsights(userId, user) {
|
|
2685
|
+
const lastChangedAt = this.parseValidDate(user?.passwordChangedAt) ??
|
|
2686
|
+
this.passwordChangeTrackingService.getLastChangedAt(userId);
|
|
2687
|
+
if (lastChangedAt) {
|
|
2688
|
+
return buildPasswordLastChangedInsights(lastChangedAt);
|
|
2523
2689
|
}
|
|
2524
2690
|
return [
|
|
2525
2691
|
{
|
|
2526
2692
|
id: 'last-password-change',
|
|
2527
2693
|
icon: 'fa-light fa-fw fa-clock',
|
|
2528
|
-
|
|
2529
|
-
|
|
2694
|
+
text: '@auth:profile-page.sections.change-password.insights.never-changed',
|
|
2695
|
+
},
|
|
2696
|
+
];
|
|
2697
|
+
}
|
|
2698
|
+
buildPinInsights(user) {
|
|
2699
|
+
const lastChangedAt = this.parseValidDate(user?.pinChangedAt);
|
|
2700
|
+
if (lastChangedAt) {
|
|
2701
|
+
return [
|
|
2702
|
+
{
|
|
2703
|
+
id: 'last-pin-change',
|
|
2704
|
+
icon: 'fa-light fa-fw fa-clock',
|
|
2705
|
+
date: lastChangedAt,
|
|
2706
|
+
datePrefix: '@auth:profile-page.sections.security-pin.insights.last-changed',
|
|
2707
|
+
},
|
|
2708
|
+
];
|
|
2709
|
+
}
|
|
2710
|
+
const hasPin = !isEmpty(defaultTo(get(user, 'pinCode'), ''));
|
|
2711
|
+
return [
|
|
2712
|
+
{
|
|
2713
|
+
id: 'last-pin-change',
|
|
2714
|
+
icon: 'fa-light fa-fw fa-clock',
|
|
2715
|
+
text: hasPin
|
|
2716
|
+
? '@auth:profile-page.sections.security-pin.insights.never-changed'
|
|
2717
|
+
: '@auth:profile-page.sections.security-pin.insights.not-set',
|
|
2530
2718
|
},
|
|
2531
2719
|
];
|
|
2532
2720
|
}
|
|
@@ -2585,9 +2773,21 @@ class AXPUserProfileSecurityInsightsService {
|
|
|
2585
2773
|
}
|
|
2586
2774
|
//#endregion
|
|
2587
2775
|
//#region ---- Data loading ----
|
|
2776
|
+
async loadCurrentUser(userId) {
|
|
2777
|
+
try {
|
|
2778
|
+
return await this.entityService
|
|
2779
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.users.name)
|
|
2780
|
+
.data()
|
|
2781
|
+
.byKey(userId);
|
|
2782
|
+
}
|
|
2783
|
+
catch (error) {
|
|
2784
|
+
console.error('Failed to load user for profile security insights', error);
|
|
2785
|
+
return null;
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2588
2788
|
async loadUserSessions(userId) {
|
|
2589
2789
|
const response = await this.entityService
|
|
2590
|
-
.withEntity(RootConfig
|
|
2790
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.deviceSessions.name)
|
|
2591
2791
|
.data()
|
|
2592
2792
|
.query({ skip: 0, take: 1000 });
|
|
2593
2793
|
return (response.items ?? []).filter((item) => item.userId === userId);
|
|
@@ -2616,20 +2816,23 @@ class AXPUserProfileSecurityInsightsService {
|
|
|
2616
2816
|
.filter(Boolean);
|
|
2617
2817
|
return parts.join(' · ');
|
|
2618
2818
|
}
|
|
2619
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2620
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2819
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPUserProfileSecurityInsightsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2820
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPUserProfileSecurityInsightsService, providedIn: 'root' }); }
|
|
2621
2821
|
}
|
|
2622
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2822
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPUserProfileSecurityInsightsService, decorators: [{
|
|
2623
2823
|
type: Injectable,
|
|
2624
2824
|
args: [{ providedIn: 'root' }]
|
|
2625
2825
|
}] });
|
|
2626
2826
|
|
|
2627
2827
|
//#region ---- Security sections insights hook ----
|
|
2628
|
-
/** Adds live security context (sessions, login, password) to profile section cards. */
|
|
2828
|
+
/** Adds live security context (sessions, login, password, PIN) to profile section cards. */
|
|
2629
2829
|
const SecuritySectionsInsightsHookProvider = {
|
|
2630
2830
|
key: PROFILE_PAGE_SECTIONS_HOOK,
|
|
2631
2831
|
priority: 15,
|
|
2632
2832
|
execute: async (payload) => {
|
|
2833
|
+
if (!isUserProfileSectionsGroupRequested(payload, 'security')) {
|
|
2834
|
+
return payload;
|
|
2835
|
+
}
|
|
2633
2836
|
const insightsService = inject(AXPUserProfileSecurityInsightsService);
|
|
2634
2837
|
const insightsBySectionId = await insightsService.loadBySectionId();
|
|
2635
2838
|
return {
|
|
@@ -2694,7 +2897,7 @@ const ProfileSlotMyProfileMenuHookProvider = {
|
|
|
2694
2897
|
command: {
|
|
2695
2898
|
name: 'navigate',
|
|
2696
2899
|
options: {
|
|
2697
|
-
path: `/${appName}/profile
|
|
2900
|
+
path: `/${appName}/profile`,
|
|
2698
2901
|
},
|
|
2699
2902
|
},
|
|
2700
2903
|
},
|
|
@@ -2711,7 +2914,7 @@ const ProfileSlotLockMenuHookProvider = {
|
|
|
2711
2914
|
priority: 50,
|
|
2712
2915
|
execute: async (payload) => {
|
|
2713
2916
|
const idleLockService = inject(AXPIdleLockService);
|
|
2714
|
-
await idleLockService.
|
|
2917
|
+
await idleLockService.refreshLockMenuState();
|
|
2715
2918
|
if (!idleLockService.canLock()) {
|
|
2716
2919
|
return payload;
|
|
2717
2920
|
}
|
|
@@ -2733,69 +2936,42 @@ const ProfileSlotLockMenuHookProvider = {
|
|
|
2733
2936
|
};
|
|
2734
2937
|
//#endregion
|
|
2735
2938
|
|
|
2736
|
-
//#region ----
|
|
2737
|
-
|
|
2738
|
-
const
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
}
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
imageByUserId.set(String(userId), image);
|
|
2768
|
-
}
|
|
2769
|
-
}
|
|
2770
|
-
}
|
|
2771
|
-
catch {
|
|
2772
|
-
/* ignore hydration failures */
|
|
2773
|
-
}
|
|
2774
|
-
return imageByUserId;
|
|
2775
|
-
}
|
|
2776
|
-
/** Hydrates User.avatar from linked Person.image on read. */
|
|
2777
|
-
const userAvatarHydrateMiddleware = {
|
|
2778
|
-
target: { ops: ['getOne', 'getAll', 'query'], order: 13 },
|
|
2779
|
-
execute: async (ctx, next) => {
|
|
2780
|
-
await next();
|
|
2781
|
-
if (ctx.entityName !== USER_ENTITY) {
|
|
2782
|
-
return;
|
|
2783
|
-
}
|
|
2784
|
-
const rows = collectUserRows(ctx.result);
|
|
2785
|
-
const userIds = Array.from(new Set(rows.map((row) => get(row, 'id')).filter((id) => id != null).map(String)));
|
|
2786
|
-
const imageByUserId = await loadPersonImagesByUserIds(ctx, userIds);
|
|
2787
|
-
for (const row of rows) {
|
|
2788
|
-
const userId = get(row, 'id');
|
|
2789
|
-
if (userId == null) {
|
|
2790
|
-
continue;
|
|
2791
|
-
}
|
|
2792
|
-
const personImage = imageByUserId.get(String(userId));
|
|
2793
|
-
if (personImage) {
|
|
2794
|
-
row['avatar'] = personImage;
|
|
2795
|
-
}
|
|
2796
|
-
}
|
|
2797
|
-
},
|
|
2939
|
+
//#region ---- Profile slot presence menu hook ----
|
|
2940
|
+
/** Registers Available / Away / Busy entries in the profile dropdown. */
|
|
2941
|
+
const ProfileSlotPresenceMenuHookProvider = {
|
|
2942
|
+
key: PROFILE_SLOT_MENU_ITEMS_HOOK,
|
|
2943
|
+
priority: 40,
|
|
2944
|
+
execute: (payload) => ({
|
|
2945
|
+
...payload,
|
|
2946
|
+
items: [
|
|
2947
|
+
...payload.items,
|
|
2948
|
+
{
|
|
2949
|
+
name: 'presence-available',
|
|
2950
|
+
title: '@auth:profile.presence-available',
|
|
2951
|
+
icon: 'fa-solid fa-circle text-success',
|
|
2952
|
+
break: { before: true },
|
|
2953
|
+
command: { name: PRESENCE_SET_AVAILABILITY, options: { status: 'online' } },
|
|
2954
|
+
},
|
|
2955
|
+
{
|
|
2956
|
+
name: 'presence-away',
|
|
2957
|
+
title: '@auth:profile.presence-away',
|
|
2958
|
+
icon: 'fa-solid fa-circle text-warning',
|
|
2959
|
+
command: { name: PRESENCE_SET_AVAILABILITY, options: { status: 'away' } },
|
|
2960
|
+
},
|
|
2961
|
+
{
|
|
2962
|
+
name: 'presence-busy',
|
|
2963
|
+
title: '@auth:profile.presence-busy',
|
|
2964
|
+
icon: 'fa-solid fa-circle text-danger',
|
|
2965
|
+
break: { after: true },
|
|
2966
|
+
command: { name: PRESENCE_SET_AVAILABILITY, options: { status: 'busy' } },
|
|
2967
|
+
},
|
|
2968
|
+
],
|
|
2969
|
+
}),
|
|
2798
2970
|
};
|
|
2971
|
+
//#endregion
|
|
2972
|
+
|
|
2973
|
+
//#region ---- User avatar client middleware ----
|
|
2974
|
+
const USER_ENTITY = `${RootConfig.module.name}.${RootConfig.entities.users.name}`;
|
|
2799
2975
|
/** Refreshes avatar cache/session after user detail saves avatar. */
|
|
2800
2976
|
const userAvatarCacheRefreshMiddleware = {
|
|
2801
2977
|
target: { ops: ['update'], order: 95 },
|
|
@@ -2822,6 +2998,7 @@ const userAvatarCacheRefreshMiddleware = {
|
|
|
2822
2998
|
//#endregion
|
|
2823
2999
|
|
|
2824
3000
|
function profileRoutesFactory() {
|
|
3001
|
+
const loadProfilePage = () => import('./acorex-platform-module-auth-client-profile-page.component-CdxseoJX.mjs').then((c) => c.AXMUserProfilePageComponent);
|
|
2825
3002
|
return [
|
|
2826
3003
|
{
|
|
2827
3004
|
path: ':app/profile',
|
|
@@ -2831,12 +3008,12 @@ function profileRoutesFactory() {
|
|
|
2831
3008
|
children: [
|
|
2832
3009
|
{
|
|
2833
3010
|
path: '',
|
|
2834
|
-
|
|
2835
|
-
|
|
3011
|
+
loadComponent: loadProfilePage,
|
|
3012
|
+
data: { reuse: true },
|
|
2836
3013
|
},
|
|
2837
3014
|
{
|
|
2838
3015
|
path: ':groupId',
|
|
2839
|
-
loadComponent:
|
|
3016
|
+
loadComponent: loadProfilePage,
|
|
2840
3017
|
data: { reuse: true },
|
|
2841
3018
|
},
|
|
2842
3019
|
],
|
|
@@ -2848,35 +3025,107 @@ class AXMAuthModule {
|
|
|
2848
3025
|
inject(AXPIdleLockService);
|
|
2849
3026
|
inject(AXPLogoEntitySyncService);
|
|
2850
3027
|
}
|
|
2851
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2852
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "
|
|
3028
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
3029
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthModule, imports: [CommonModule, i1$5.AXPCommonModule, i1$6.RouterModule, AXPAccountModule,
|
|
2853
3030
|
AXMAuthValidationRulesModule] }); }
|
|
2854
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "
|
|
2855
|
-
|
|
3031
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthModule, providers: [
|
|
3032
|
+
provideAppStartUpTask(() => {
|
|
2856
3033
|
const sessionService = inject(AXPSessionService);
|
|
2857
3034
|
const idleLockService = inject(AXPIdleLockService);
|
|
2858
|
-
return
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
3035
|
+
return {
|
|
3036
|
+
name: 'idle-lock-restore',
|
|
3037
|
+
priority: AXP_APP_STARTUP_PRIORITY.idleLockRestore,
|
|
3038
|
+
run: async () => {
|
|
3039
|
+
await firstValueFrom(sessionService.isLoading$.pipe(filter((loading) => !loading)));
|
|
3040
|
+
if (sessionService.isLocked() && sessionService.isAuthorized) {
|
|
3041
|
+
await idleLockService.restoreFromPersistedSession();
|
|
3042
|
+
}
|
|
3043
|
+
},
|
|
3044
|
+
};
|
|
3045
|
+
}),
|
|
3046
|
+
provideAppStartUpTask(() => {
|
|
3047
|
+
const loadState = inject(AXPPlatformSettingsLoadState);
|
|
3048
|
+
const offlineBootstrap = inject(AXPPlatformSettingsOfflineBootstrapService);
|
|
3049
|
+
const router = inject(Router);
|
|
3050
|
+
const location = inject(Location);
|
|
3051
|
+
const appRef = inject(ApplicationRef);
|
|
3052
|
+
return {
|
|
3053
|
+
name: 'platform-settings-failure-redirect',
|
|
3054
|
+
priority: AXP_APP_STARTUP_PRIORITY.platformSettingsFailureRedirect,
|
|
3055
|
+
run: async () => {
|
|
3056
|
+
if (!loadState.hasFailure() && !loadState.hasPendingOfflineContinue()) {
|
|
3057
|
+
return;
|
|
3058
|
+
}
|
|
3059
|
+
const goUnavailable = () => {
|
|
3060
|
+
if (!loadState.hasFailure()) {
|
|
3061
|
+
return;
|
|
3062
|
+
}
|
|
3063
|
+
if (router.url.startsWith('/auth/unavailable')) {
|
|
3064
|
+
return;
|
|
3065
|
+
}
|
|
3066
|
+
void router.navigateByUrl('/auth/unavailable', { replaceUrl: true });
|
|
3067
|
+
};
|
|
3068
|
+
const whenStable = () => firstValueFrom(appRef.isStable.pipe(filter((stable) => stable), take(1), timeout({ first: 10_000 }))).catch(() => undefined);
|
|
3069
|
+
// Never await router.navigate during APP_INITIALIZER — it does not resolve and freezes splash.
|
|
3070
|
+
if (loadState.hasFailure()) {
|
|
3071
|
+
location.replaceState('/auth/unavailable');
|
|
3072
|
+
const navGuard = router.events
|
|
3073
|
+
.pipe(filter((event) => event instanceof NavigationStart))
|
|
3074
|
+
.subscribe((event) => {
|
|
3075
|
+
if (!loadState.hasFailure()) {
|
|
3076
|
+
navGuard.unsubscribe();
|
|
3077
|
+
return;
|
|
3078
|
+
}
|
|
3079
|
+
if (!event.url.startsWith('/auth/unavailable')) {
|
|
3080
|
+
goUnavailable();
|
|
3081
|
+
}
|
|
3082
|
+
});
|
|
3083
|
+
queueMicrotask(goUnavailable);
|
|
3084
|
+
void whenStable().then(() => {
|
|
3085
|
+
navGuard.unsubscribe();
|
|
3086
|
+
goUnavailable();
|
|
3087
|
+
});
|
|
3088
|
+
return;
|
|
3089
|
+
}
|
|
3090
|
+
// Offline confirm needs the root ViewContainerRef — confirmAndContinueOffline waits for that
|
|
3091
|
+
// (not full isStable, which delays the dialog while the zone stays busy).
|
|
3092
|
+
queueMicrotask(() => {
|
|
3093
|
+
void (async () => {
|
|
3094
|
+
if (!loadState.hasPendingOfflineContinue()) {
|
|
3095
|
+
return;
|
|
3096
|
+
}
|
|
3097
|
+
let continued = false;
|
|
3098
|
+
try {
|
|
3099
|
+
continued = await offlineBootstrap.confirmAndContinueOffline();
|
|
3100
|
+
}
|
|
3101
|
+
catch (error) {
|
|
3102
|
+
console.error('Offline continue confirm failed', error);
|
|
3103
|
+
}
|
|
3104
|
+
if (!continued) {
|
|
3105
|
+
loadState.setFailure(loadState.consumePendingBootstrapError() ?? 'Platform settings unavailable');
|
|
3106
|
+
location.replaceState('/auth/unavailable');
|
|
3107
|
+
goUnavailable();
|
|
3108
|
+
}
|
|
3109
|
+
})();
|
|
3110
|
+
});
|
|
3111
|
+
},
|
|
3112
|
+
};
|
|
2864
3113
|
}),
|
|
2865
3114
|
AXMAuthErrorHandler,
|
|
2866
3115
|
provideLazyProvider(AXP_MENU_PROVIDER, () => import('./acorex-platform-module-auth-client-menu.provider-Bz-kRip4.mjs').then(m => m.AXMSecurityManagementModuleMenuProvider)),
|
|
2867
|
-
provideLazyProvider(AXP_SETTING_DEFINITION_PROVIDER, () => import('./acorex-platform-module-auth-client-settings.provider-
|
|
2868
|
-
provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-platform-module-auth-client-profile-page-component.provider-
|
|
2869
|
-
|
|
3116
|
+
provideLazyProvider(AXP_SETTING_DEFINITION_PROVIDER, () => import('./acorex-platform-module-auth-client-settings.provider-Yaoz8yp3.mjs').then(m => m.AXMSettingProvider)),
|
|
3117
|
+
provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-platform-module-auth-client-profile-page-component.provider-6lNx6bKI.mjs').then((module) => module.AXMProfilePageComponentProvider)),
|
|
3118
|
+
provideQuerySetups([
|
|
3119
|
+
{
|
|
3120
|
+
key: 'Auth:GetUserActivity',
|
|
3121
|
+
loader: () => import('./acorex-platform-module-auth-client-get-user-activity.query-BTpibxe9.mjs').then((c) => c.AXMGetUserActivityQuery),
|
|
3122
|
+
},
|
|
3123
|
+
]),
|
|
2870
3124
|
{
|
|
2871
3125
|
provide: ROUTES,
|
|
2872
3126
|
multi: true,
|
|
2873
3127
|
useFactory: profileRoutesFactory,
|
|
2874
3128
|
},
|
|
2875
|
-
{
|
|
2876
|
-
provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
|
|
2877
|
-
multi: true,
|
|
2878
|
-
useValue: userAvatarHydrateMiddleware,
|
|
2879
|
-
},
|
|
2880
3129
|
{
|
|
2881
3130
|
provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
|
|
2882
3131
|
multi: true,
|
|
@@ -2885,51 +3134,51 @@ class AXMAuthModule {
|
|
|
2885
3134
|
provideCommandSetups([
|
|
2886
3135
|
{
|
|
2887
3136
|
key: AXMAuthCommandKeys.Profile.Show,
|
|
2888
|
-
command: () => import('./acorex-platform-module-auth-client-show-profile-command-
|
|
3137
|
+
command: () => import('./acorex-platform-module-auth-client-show-profile-command-BWoDxIdx.mjs').then((c) => c.AXPShowProfileCommand),
|
|
2889
3138
|
},
|
|
2890
3139
|
{
|
|
2891
3140
|
key: AXMAuthCommandKeys.Session.Signout,
|
|
2892
|
-
command: () => import('./acorex-platform-module-auth-client-signout-command-
|
|
3141
|
+
command: () => import('./acorex-platform-module-auth-client-signout-command-B7n_Fn4P.mjs').then((c) => c.AXPSignoutCommand),
|
|
2893
3142
|
},
|
|
2894
3143
|
{
|
|
2895
3144
|
key: AXMAuthCommandKeys.Session.OpenSessions,
|
|
2896
|
-
command: () => import('./acorex-platform-module-auth-client-open-sessions.command-
|
|
3145
|
+
command: () => import('./acorex-platform-module-auth-client-open-sessions.command-LZKM9fgo.mjs').then((c) => c.AXPOpenSessionsCommand),
|
|
2897
3146
|
},
|
|
2898
3147
|
{
|
|
2899
3148
|
key: AXMAuthCommandKeys.Session.LockScreen,
|
|
2900
|
-
command: () => import('./acorex-platform-module-auth-client-lock-screen.command-
|
|
3149
|
+
command: () => import('./acorex-platform-module-auth-client-lock-screen.command-Br9O4b5c.mjs').then((c) => c.AXPLockScreenCommand),
|
|
2901
3150
|
},
|
|
2902
3151
|
{
|
|
2903
3152
|
key: AXMAuthCommandKeys.Profile.ChangePhoto,
|
|
2904
|
-
command: () => import('./acorex-platform-module-auth-client-change-photo.command-
|
|
3153
|
+
command: () => import('./acorex-platform-module-auth-client-change-photo.command-CYGqrJV0.mjs').then((c) => c.AXPChangePhotoCommand),
|
|
2905
3154
|
},
|
|
2906
3155
|
{
|
|
2907
3156
|
key: AXMAuthCommandKeys.Profile.EditAccountInfo,
|
|
2908
|
-
command: () => import('./acorex-platform-module-auth-client-edit-account-info.command-
|
|
3157
|
+
command: () => import('./acorex-platform-module-auth-client-edit-account-info.command-CD9IrimO.mjs').then((c) => c.AXPEditAccountInfoCommand),
|
|
2909
3158
|
},
|
|
2910
3159
|
{
|
|
2911
3160
|
key: AXMAuthCommandKeys.Security.ChangePassword,
|
|
2912
|
-
command: () => import('./acorex-platform-module-auth-client-change-password.command-
|
|
3161
|
+
command: () => import('./acorex-platform-module-auth-client-change-password.command-DIM_d7RO.mjs').then((c) => c.AXPChangePasswordCommand),
|
|
2913
3162
|
},
|
|
2914
3163
|
{
|
|
2915
3164
|
key: AXMAuthCommandKeys.Security.SetPinCode,
|
|
2916
|
-
command: () => import('./acorex-platform-module-auth-client-set-pin-code.command-
|
|
3165
|
+
command: () => import('./acorex-platform-module-auth-client-set-pin-code.command-BJT7F-xz.mjs').then((c) => c.AXPSetPinCodeCommand),
|
|
2917
3166
|
},
|
|
2918
3167
|
{
|
|
2919
3168
|
key: AXMAuthCommandKeys.Security.RemovePinCode,
|
|
2920
|
-
command: () => import('./acorex-platform-module-auth-client-remove-pin-code.command-
|
|
3169
|
+
command: () => import('./acorex-platform-module-auth-client-remove-pin-code.command-uK04-h15.mjs').then((c) => c.AXPRemovePinCodeCommand),
|
|
2921
3170
|
},
|
|
2922
3171
|
{
|
|
2923
3172
|
key: AXMAuthCommandKeys.Security.ViewLoginHistory,
|
|
2924
|
-
command: () => import('./acorex-platform-module-auth-client-view-login-history.command-
|
|
3173
|
+
command: () => import('./acorex-platform-module-auth-client-view-login-history.command-ovj5rdHL.mjs').then((c) => c.AXPViewLoginHistoryCommand),
|
|
2925
3174
|
},
|
|
2926
3175
|
{
|
|
2927
3176
|
key: AXMAuthCommandKeys.Security.EditSignature,
|
|
2928
|
-
command: () => import('./acorex-platform-module-auth-client-edit-signature.command-
|
|
3177
|
+
command: () => import('./acorex-platform-module-auth-client-edit-signature.command-TjOLhvKL.mjs').then((c) => c.AXPEditSignatureCommand),
|
|
2929
3178
|
},
|
|
2930
3179
|
{
|
|
2931
3180
|
key: AXMAuthCommandKeys.Profile.ComingSoon,
|
|
2932
|
-
command: () => import('./acorex-platform-module-auth-client-profile-coming-soon.command-
|
|
3181
|
+
command: () => import('./acorex-platform-module-auth-client-profile-coming-soon.command-Crh2GsRA.mjs').then((c) => c.AXPProfileComingSoonCommand),
|
|
2933
3182
|
},
|
|
2934
3183
|
]),
|
|
2935
3184
|
{
|
|
@@ -2947,6 +3196,11 @@ class AXMAuthModule {
|
|
|
2947
3196
|
useValue: ProfileSlotLockMenuHookProvider,
|
|
2948
3197
|
multi: true,
|
|
2949
3198
|
},
|
|
3199
|
+
{
|
|
3200
|
+
provide: AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER,
|
|
3201
|
+
useValue: ProfileSlotPresenceMenuHookProvider,
|
|
3202
|
+
multi: true,
|
|
3203
|
+
},
|
|
2950
3204
|
{
|
|
2951
3205
|
provide: AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER,
|
|
2952
3206
|
useValue: CoreProfileGroupsHookProvider,
|
|
@@ -2973,7 +3227,7 @@ class AXMAuthModule {
|
|
|
2973
3227
|
AXPAccountModule,
|
|
2974
3228
|
AXMAuthValidationRulesModule] }); }
|
|
2975
3229
|
}
|
|
2976
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3230
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMAuthModule, decorators: [{
|
|
2977
3231
|
type: NgModule,
|
|
2978
3232
|
args: [{
|
|
2979
3233
|
imports: [
|
|
@@ -2984,31 +3238,103 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
2984
3238
|
AXMAuthValidationRulesModule,
|
|
2985
3239
|
],
|
|
2986
3240
|
providers: [
|
|
2987
|
-
|
|
3241
|
+
provideAppStartUpTask(() => {
|
|
2988
3242
|
const sessionService = inject(AXPSessionService);
|
|
2989
3243
|
const idleLockService = inject(AXPIdleLockService);
|
|
2990
|
-
return
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
3244
|
+
return {
|
|
3245
|
+
name: 'idle-lock-restore',
|
|
3246
|
+
priority: AXP_APP_STARTUP_PRIORITY.idleLockRestore,
|
|
3247
|
+
run: async () => {
|
|
3248
|
+
await firstValueFrom(sessionService.isLoading$.pipe(filter((loading) => !loading)));
|
|
3249
|
+
if (sessionService.isLocked() && sessionService.isAuthorized) {
|
|
3250
|
+
await idleLockService.restoreFromPersistedSession();
|
|
3251
|
+
}
|
|
3252
|
+
},
|
|
3253
|
+
};
|
|
3254
|
+
}),
|
|
3255
|
+
provideAppStartUpTask(() => {
|
|
3256
|
+
const loadState = inject(AXPPlatformSettingsLoadState);
|
|
3257
|
+
const offlineBootstrap = inject(AXPPlatformSettingsOfflineBootstrapService);
|
|
3258
|
+
const router = inject(Router);
|
|
3259
|
+
const location = inject(Location);
|
|
3260
|
+
const appRef = inject(ApplicationRef);
|
|
3261
|
+
return {
|
|
3262
|
+
name: 'platform-settings-failure-redirect',
|
|
3263
|
+
priority: AXP_APP_STARTUP_PRIORITY.platformSettingsFailureRedirect,
|
|
3264
|
+
run: async () => {
|
|
3265
|
+
if (!loadState.hasFailure() && !loadState.hasPendingOfflineContinue()) {
|
|
3266
|
+
return;
|
|
3267
|
+
}
|
|
3268
|
+
const goUnavailable = () => {
|
|
3269
|
+
if (!loadState.hasFailure()) {
|
|
3270
|
+
return;
|
|
3271
|
+
}
|
|
3272
|
+
if (router.url.startsWith('/auth/unavailable')) {
|
|
3273
|
+
return;
|
|
3274
|
+
}
|
|
3275
|
+
void router.navigateByUrl('/auth/unavailable', { replaceUrl: true });
|
|
3276
|
+
};
|
|
3277
|
+
const whenStable = () => firstValueFrom(appRef.isStable.pipe(filter((stable) => stable), take(1), timeout({ first: 10_000 }))).catch(() => undefined);
|
|
3278
|
+
// Never await router.navigate during APP_INITIALIZER — it does not resolve and freezes splash.
|
|
3279
|
+
if (loadState.hasFailure()) {
|
|
3280
|
+
location.replaceState('/auth/unavailable');
|
|
3281
|
+
const navGuard = router.events
|
|
3282
|
+
.pipe(filter((event) => event instanceof NavigationStart))
|
|
3283
|
+
.subscribe((event) => {
|
|
3284
|
+
if (!loadState.hasFailure()) {
|
|
3285
|
+
navGuard.unsubscribe();
|
|
3286
|
+
return;
|
|
3287
|
+
}
|
|
3288
|
+
if (!event.url.startsWith('/auth/unavailable')) {
|
|
3289
|
+
goUnavailable();
|
|
3290
|
+
}
|
|
3291
|
+
});
|
|
3292
|
+
queueMicrotask(goUnavailable);
|
|
3293
|
+
void whenStable().then(() => {
|
|
3294
|
+
navGuard.unsubscribe();
|
|
3295
|
+
goUnavailable();
|
|
3296
|
+
});
|
|
3297
|
+
return;
|
|
3298
|
+
}
|
|
3299
|
+
// Offline confirm needs the root ViewContainerRef — confirmAndContinueOffline waits for that
|
|
3300
|
+
// (not full isStable, which delays the dialog while the zone stays busy).
|
|
3301
|
+
queueMicrotask(() => {
|
|
3302
|
+
void (async () => {
|
|
3303
|
+
if (!loadState.hasPendingOfflineContinue()) {
|
|
3304
|
+
return;
|
|
3305
|
+
}
|
|
3306
|
+
let continued = false;
|
|
3307
|
+
try {
|
|
3308
|
+
continued = await offlineBootstrap.confirmAndContinueOffline();
|
|
3309
|
+
}
|
|
3310
|
+
catch (error) {
|
|
3311
|
+
console.error('Offline continue confirm failed', error);
|
|
3312
|
+
}
|
|
3313
|
+
if (!continued) {
|
|
3314
|
+
loadState.setFailure(loadState.consumePendingBootstrapError() ?? 'Platform settings unavailable');
|
|
3315
|
+
location.replaceState('/auth/unavailable');
|
|
3316
|
+
goUnavailable();
|
|
3317
|
+
}
|
|
3318
|
+
})();
|
|
3319
|
+
});
|
|
3320
|
+
},
|
|
3321
|
+
};
|
|
2996
3322
|
}),
|
|
2997
3323
|
AXMAuthErrorHandler,
|
|
2998
3324
|
provideLazyProvider(AXP_MENU_PROVIDER, () => import('./acorex-platform-module-auth-client-menu.provider-Bz-kRip4.mjs').then(m => m.AXMSecurityManagementModuleMenuProvider)),
|
|
2999
|
-
provideLazyProvider(AXP_SETTING_DEFINITION_PROVIDER, () => import('./acorex-platform-module-auth-client-settings.provider-
|
|
3000
|
-
provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-platform-module-auth-client-profile-page-component.provider-
|
|
3001
|
-
|
|
3325
|
+
provideLazyProvider(AXP_SETTING_DEFINITION_PROVIDER, () => import('./acorex-platform-module-auth-client-settings.provider-Yaoz8yp3.mjs').then(m => m.AXMSettingProvider)),
|
|
3326
|
+
provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-platform-module-auth-client-profile-page-component.provider-6lNx6bKI.mjs').then((module) => module.AXMProfilePageComponentProvider)),
|
|
3327
|
+
provideQuerySetups([
|
|
3328
|
+
{
|
|
3329
|
+
key: 'Auth:GetUserActivity',
|
|
3330
|
+
loader: () => import('./acorex-platform-module-auth-client-get-user-activity.query-BTpibxe9.mjs').then((c) => c.AXMGetUserActivityQuery),
|
|
3331
|
+
},
|
|
3332
|
+
]),
|
|
3002
3333
|
{
|
|
3003
3334
|
provide: ROUTES,
|
|
3004
3335
|
multi: true,
|
|
3005
3336
|
useFactory: profileRoutesFactory,
|
|
3006
3337
|
},
|
|
3007
|
-
{
|
|
3008
|
-
provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
|
|
3009
|
-
multi: true,
|
|
3010
|
-
useValue: userAvatarHydrateMiddleware,
|
|
3011
|
-
},
|
|
3012
3338
|
{
|
|
3013
3339
|
provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
|
|
3014
3340
|
multi: true,
|
|
@@ -3017,51 +3343,51 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
3017
3343
|
provideCommandSetups([
|
|
3018
3344
|
{
|
|
3019
3345
|
key: AXMAuthCommandKeys.Profile.Show,
|
|
3020
|
-
command: () => import('./acorex-platform-module-auth-client-show-profile-command-
|
|
3346
|
+
command: () => import('./acorex-platform-module-auth-client-show-profile-command-BWoDxIdx.mjs').then((c) => c.AXPShowProfileCommand),
|
|
3021
3347
|
},
|
|
3022
3348
|
{
|
|
3023
3349
|
key: AXMAuthCommandKeys.Session.Signout,
|
|
3024
|
-
command: () => import('./acorex-platform-module-auth-client-signout-command-
|
|
3350
|
+
command: () => import('./acorex-platform-module-auth-client-signout-command-B7n_Fn4P.mjs').then((c) => c.AXPSignoutCommand),
|
|
3025
3351
|
},
|
|
3026
3352
|
{
|
|
3027
3353
|
key: AXMAuthCommandKeys.Session.OpenSessions,
|
|
3028
|
-
command: () => import('./acorex-platform-module-auth-client-open-sessions.command-
|
|
3354
|
+
command: () => import('./acorex-platform-module-auth-client-open-sessions.command-LZKM9fgo.mjs').then((c) => c.AXPOpenSessionsCommand),
|
|
3029
3355
|
},
|
|
3030
3356
|
{
|
|
3031
3357
|
key: AXMAuthCommandKeys.Session.LockScreen,
|
|
3032
|
-
command: () => import('./acorex-platform-module-auth-client-lock-screen.command-
|
|
3358
|
+
command: () => import('./acorex-platform-module-auth-client-lock-screen.command-Br9O4b5c.mjs').then((c) => c.AXPLockScreenCommand),
|
|
3033
3359
|
},
|
|
3034
3360
|
{
|
|
3035
3361
|
key: AXMAuthCommandKeys.Profile.ChangePhoto,
|
|
3036
|
-
command: () => import('./acorex-platform-module-auth-client-change-photo.command-
|
|
3362
|
+
command: () => import('./acorex-platform-module-auth-client-change-photo.command-CYGqrJV0.mjs').then((c) => c.AXPChangePhotoCommand),
|
|
3037
3363
|
},
|
|
3038
3364
|
{
|
|
3039
3365
|
key: AXMAuthCommandKeys.Profile.EditAccountInfo,
|
|
3040
|
-
command: () => import('./acorex-platform-module-auth-client-edit-account-info.command-
|
|
3366
|
+
command: () => import('./acorex-platform-module-auth-client-edit-account-info.command-CD9IrimO.mjs').then((c) => c.AXPEditAccountInfoCommand),
|
|
3041
3367
|
},
|
|
3042
3368
|
{
|
|
3043
3369
|
key: AXMAuthCommandKeys.Security.ChangePassword,
|
|
3044
|
-
command: () => import('./acorex-platform-module-auth-client-change-password.command-
|
|
3370
|
+
command: () => import('./acorex-platform-module-auth-client-change-password.command-DIM_d7RO.mjs').then((c) => c.AXPChangePasswordCommand),
|
|
3045
3371
|
},
|
|
3046
3372
|
{
|
|
3047
3373
|
key: AXMAuthCommandKeys.Security.SetPinCode,
|
|
3048
|
-
command: () => import('./acorex-platform-module-auth-client-set-pin-code.command-
|
|
3374
|
+
command: () => import('./acorex-platform-module-auth-client-set-pin-code.command-BJT7F-xz.mjs').then((c) => c.AXPSetPinCodeCommand),
|
|
3049
3375
|
},
|
|
3050
3376
|
{
|
|
3051
3377
|
key: AXMAuthCommandKeys.Security.RemovePinCode,
|
|
3052
|
-
command: () => import('./acorex-platform-module-auth-client-remove-pin-code.command-
|
|
3378
|
+
command: () => import('./acorex-platform-module-auth-client-remove-pin-code.command-uK04-h15.mjs').then((c) => c.AXPRemovePinCodeCommand),
|
|
3053
3379
|
},
|
|
3054
3380
|
{
|
|
3055
3381
|
key: AXMAuthCommandKeys.Security.ViewLoginHistory,
|
|
3056
|
-
command: () => import('./acorex-platform-module-auth-client-view-login-history.command-
|
|
3382
|
+
command: () => import('./acorex-platform-module-auth-client-view-login-history.command-ovj5rdHL.mjs').then((c) => c.AXPViewLoginHistoryCommand),
|
|
3057
3383
|
},
|
|
3058
3384
|
{
|
|
3059
3385
|
key: AXMAuthCommandKeys.Security.EditSignature,
|
|
3060
|
-
command: () => import('./acorex-platform-module-auth-client-edit-signature.command-
|
|
3386
|
+
command: () => import('./acorex-platform-module-auth-client-edit-signature.command-TjOLhvKL.mjs').then((c) => c.AXPEditSignatureCommand),
|
|
3061
3387
|
},
|
|
3062
3388
|
{
|
|
3063
3389
|
key: AXMAuthCommandKeys.Profile.ComingSoon,
|
|
3064
|
-
command: () => import('./acorex-platform-module-auth-client-profile-coming-soon.command-
|
|
3390
|
+
command: () => import('./acorex-platform-module-auth-client-profile-coming-soon.command-Crh2GsRA.mjs').then((c) => c.AXPProfileComingSoonCommand),
|
|
3065
3391
|
},
|
|
3066
3392
|
]),
|
|
3067
3393
|
{
|
|
@@ -3079,6 +3405,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
3079
3405
|
useValue: ProfileSlotLockMenuHookProvider,
|
|
3080
3406
|
multi: true,
|
|
3081
3407
|
},
|
|
3408
|
+
{
|
|
3409
|
+
provide: AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER,
|
|
3410
|
+
useValue: ProfileSlotPresenceMenuHookProvider,
|
|
3411
|
+
multi: true,
|
|
3412
|
+
},
|
|
3082
3413
|
{
|
|
3083
3414
|
provide: AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER,
|
|
3084
3415
|
useValue: CoreProfileGroupsHookProvider,
|
|
@@ -3111,18 +3442,19 @@ const AUTH_LOGIN_EXTERNAL_PROVIDERS_SLOT = 'auth-login-external-providers';
|
|
|
3111
3442
|
class AXPLoginExternalProvidersComponent {
|
|
3112
3443
|
constructor() {
|
|
3113
3444
|
this.slotName = AUTH_LOGIN_EXTERNAL_PROVIDERS_SLOT;
|
|
3114
|
-
this.slot = viewChild(AXPComponentSlotDirective,
|
|
3445
|
+
this.slot = viewChild(AXPComponentSlotDirective, /* @ts-ignore */
|
|
3446
|
+
...(ngDevMode ? [{ debugName: "slot" }] : /* istanbul ignore next */ []));
|
|
3115
3447
|
}
|
|
3116
3448
|
hasContent() {
|
|
3117
3449
|
const slot = this.slot();
|
|
3118
3450
|
return !!slot && !slot.isEmpty();
|
|
3119
3451
|
}
|
|
3120
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3121
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "
|
|
3452
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPLoginExternalProvidersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3453
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.0.8", type: AXPLoginExternalProvidersComponent, isStandalone: true, selector: "axm-login-external-providers", viewQueries: [{ propertyName: "slot", first: true, predicate: AXPComponentSlotDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<axp-component-slot\n class=\"flex flex-col gap-2 w-full mt-0 lg:mt-2\"\n #slot=\"slot\"\n [name]=\"slotName\"\n [host]=\"this\"\n></axp-component-slot>\n", dependencies: [{ kind: "ngmodule", type: AXPComponentSlotModule }, { kind: "directive", type: i1$4.AXPComponentSlotDirective, selector: "axp-component-slot", inputs: ["name", "host", "context"], exportAs: ["slot"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
|
|
3122
3454
|
}
|
|
3123
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3455
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPLoginExternalProvidersComponent, decorators: [{
|
|
3124
3456
|
type: Component,
|
|
3125
|
-
args: [{ selector: 'axm-login-external-providers', imports: [AXPComponentSlotModule], template: "<axp-component-slot\n class=\"flex flex-col gap-2 w-full mt-
|
|
3457
|
+
args: [{ selector: 'axm-login-external-providers', changeDetection: ChangeDetectionStrategy.Eager, imports: [AXPComponentSlotModule], template: "<axp-component-slot\n class=\"flex flex-col gap-2 w-full mt-0 lg:mt-2\"\n #slot=\"slot\"\n [name]=\"slotName\"\n [host]=\"this\"\n></axp-component-slot>\n" }]
|
|
3126
3458
|
}], propDecorators: { slot: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPComponentSlotDirective), { isSignal: true }] }] } });
|
|
3127
3459
|
|
|
3128
3460
|
//#endregion
|
|
@@ -3142,7 +3474,7 @@ class AXPLoginHistoryService {
|
|
|
3142
3474
|
return [];
|
|
3143
3475
|
}
|
|
3144
3476
|
const response = await this.entityService
|
|
3145
|
-
.withEntity(RootConfig
|
|
3477
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.deviceSessions.name)
|
|
3146
3478
|
.data()
|
|
3147
3479
|
.query({ skip: 0, take: 1000 });
|
|
3148
3480
|
const items = response.items ?? [];
|
|
@@ -3158,10 +3490,10 @@ class AXPLoginHistoryService {
|
|
|
3158
3490
|
lastLoginDate: item.lastLoginDate,
|
|
3159
3491
|
})), [(entry) => new Date(entry.lastLoginDate).getTime()], ['desc']);
|
|
3160
3492
|
}
|
|
3161
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3162
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
3493
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPLoginHistoryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3494
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPLoginHistoryService, providedIn: 'root' }); }
|
|
3163
3495
|
}
|
|
3164
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3496
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPLoginHistoryService, decorators: [{
|
|
3165
3497
|
type: Injectable,
|
|
3166
3498
|
args: [{ providedIn: 'root' }]
|
|
3167
3499
|
}] });
|
|
@@ -3170,5 +3502,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
3170
3502
|
* Generated bundle index. Do not edit.
|
|
3171
3503
|
*/
|
|
3172
3504
|
|
|
3173
|
-
export { AXMUserDeviceSessionsService as A,
|
|
3174
|
-
//# sourceMappingURL=acorex-platform-module-auth-client-acorex-platform-module-auth-client-
|
|
3505
|
+
export { AXMUserDeviceSessionsService as A, AXMAuthenticationTypes as B, CHANGE_PASSWORD_SECTION_ID as C, AUTH_LOGIN_EXTERNAL_PROVIDERS_SLOT as D, AUTH_USER_ACTIVITY_DEFAULT_WEEKS as E, AXMAuthErrorHandler as F, AXMAuthModule as G, AXMDefaultAuthConfigs as H, AXM_AUTH_CONFIG_TOKEN as I, aggregateDailySessionCounts as J, buildUserActivityWeeks as K, canActivateLogin as L, computeUserActivityStats as M, configAuthModule as N, countToActivityLevel as O, PROFILE_PAGE_GROUPS_HOOK as P, extractUserActivityEndDate as Q, extractUserActivityStartDate as R, extractUserActivityUserId as S, isUserProfileGroupComponent as T, isUserProfileSectionsGroupRequested as U, parseAuthCredentialType as V, PROFILE_PAGE_SECTIONS_HOOK as a, PROFILE_PAGE_HEADER_META_HOOK as b, resolveUserProfileSectionContent as c, PROFILE_SECTION_INSIGHTS_PATCH_METADATA_KEY as d, PROFILE_ACTIVITY_CHART_COMPONENT_KEY as e, PROFILE_DELETE_ACCOUNT_DANGER_ZONE_COMPONENT_KEY as f, resolveDefaultUserActivityDateRange as g, buildUserActivityDataSourceItem as h, AXPIdleLockService as i, AXPUserAvatarSyncService as j, AXPAuthPasswordComplexityService as k, AXPAuthPasswordChangeTrackingService as l, getPasswordComplexityHintKey as m, getPasswordComplexityValidationMessageKey as n, validatePasswordAgainstComplexity as o, buildPasswordLastChangedInsights as p, AXPLoginHistoryService as q, resolveDefaultUserProfileSectionAction as r, AXMAuthPlatformSettingsService as s, AXM_LOGIN_GUARD_TOKEN as t, AXPTenantChooserListComponent as u, visibleUserProfileSectionActions as v, AXPTenantChooserDropdownComponent as w, AXPAppChooserListComponent as x, formatCompactActivityCount as y, AXPLoginExternalProvidersComponent as z };
|
|
3506
|
+
//# sourceMappingURL=acorex-platform-module-auth-client-acorex-platform-module-auth-client-CYmUn-lw.mjs.map
|