@acorex/platform 21.0.0-next.2 → 21.0.0-next.5
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/auth/index.d.ts +97 -238
- package/common/index.d.ts +783 -213
- package/core/index.d.ts +311 -442
- package/fesm2022/acorex-platform-auth.mjs +156 -200
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/acorex-platform-common.mjs +1038 -127
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +602 -413
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-domain.mjs +54 -11
- package/fesm2022/acorex-platform-domain.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +412 -270
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +2100 -3141
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +7 -7
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +730 -652
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +4 -4
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +249 -205
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-widgets-file-list-popup.component-D0y-9nE5.mjs → acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs} +2 -2
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-m8rHZP8L.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs} +2 -2
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-widgets.mjs +3066 -1040
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-default-entity-master-create-view.component-mARj77Mr.mjs → acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs} +26 -5
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-entity-master-list-view.component-Cym8pq0v.mjs → acorex-platform-themes-default-entity-master-list-view.component-DyDa_hyd.mjs} +4 -5
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DyDa_hyd.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs +101 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-B_P0a5KW.mjs → acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs} +3 -3
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +166 -30
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-shared.mjs +27 -27
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/fesm2022/acorex-platform-workflow.mjs +474 -1527
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/layout/builder/index.d.ts +4 -1
- package/layout/components/index.d.ts +405 -327
- package/layout/designer/index.d.ts +3 -3
- package/layout/entity/index.d.ts +154 -108
- package/layout/widget-core/index.d.ts +39 -52
- package/layout/widgets/index.d.ts +368 -54
- package/package.json +9 -9
- package/themes/default/index.d.ts +15 -2
- package/themes/shared/index.d.ts +10 -10
- package/workflow/index.d.ts +182 -817
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-edit.component-fhhZOWul.mjs +0 -50
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-edit.component-fhhZOWul.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-view.component-C3Qbs0fz.mjs +0 -42
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-view.component-C3Qbs0fz.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-edit.component-CngQBUlN.mjs +0 -55
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-edit.component-CngQBUlN.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-view.component-DSNo9e4W.mjs +0 -50
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-view.component-DSNo9e4W.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-edit.component-CL0CwEHX.mjs +0 -48
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-edit.component-CL0CwEHX.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-view.component-B6Fi0xTw.mjs +0 -42
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-view.component-B6Fi0xTw.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-D0y-9nE5.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-m8rHZP8L.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-mARj77Mr.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-Cym8pq0v.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-BTA6h7Xd.mjs +0 -101
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-BTA6h7Xd.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-B_P0a5KW.mjs.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, Injector, Injectable, signal, inject, Input, Directive, provideAppInitializer, Optional, Inject, NgModule
|
|
3
|
-
import {
|
|
4
|
-
import { AXPBroadcastEventService } from '@acorex/platform/core';
|
|
2
|
+
import { InjectionToken, Injector, Injectable, signal, inject, Input, Directive, provideAppInitializer, Optional, Inject, NgModule } from '@angular/core';
|
|
3
|
+
import { AXPBroadcastEventService, AXP_SESSION_SERVICE } from '@acorex/platform/core';
|
|
5
4
|
import { isEmpty } from 'lodash-es';
|
|
5
|
+
import { map, BehaviorSubject, shareReplay, defaultIfEmpty, switchMap, filter, from, first } from 'rxjs';
|
|
6
6
|
|
|
7
7
|
const AXP_APPLICATION_LOADER = new InjectionToken('AXP_APPLICATION_LOADER', {
|
|
8
8
|
providedIn: 'root',
|
|
@@ -11,25 +11,29 @@ const AXP_APPLICATION_LOADER = new InjectionToken('AXP_APPLICATION_LOADER', {
|
|
|
11
11
|
},
|
|
12
12
|
});
|
|
13
13
|
class AXPApplicationDefaultLoader {
|
|
14
|
-
getList(context) {
|
|
15
|
-
return
|
|
14
|
+
async getList(context) {
|
|
15
|
+
return [
|
|
16
16
|
{
|
|
17
17
|
id: '1',
|
|
18
18
|
name: 'default-app',
|
|
19
19
|
title: 'Default Application',
|
|
20
20
|
version: '1.0.0',
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
edition: {
|
|
22
|
+
id: 'default-edition-1',
|
|
23
|
+
title: 'Standard',
|
|
24
|
+
},
|
|
23
25
|
},
|
|
24
26
|
{
|
|
25
27
|
id: '2',
|
|
26
28
|
name: 'default-app',
|
|
27
29
|
title: 'Default Application',
|
|
28
30
|
version: '1.0.0',
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
edition: {
|
|
32
|
+
id: 'default-edition-2',
|
|
33
|
+
title: 'Standard',
|
|
34
|
+
},
|
|
31
35
|
},
|
|
32
|
-
]
|
|
36
|
+
];
|
|
33
37
|
}
|
|
34
38
|
}
|
|
35
39
|
|
|
@@ -40,14 +44,14 @@ const AXP_TENANT_LOADER = new InjectionToken('AXP_TENANT_LOADER', {
|
|
|
40
44
|
},
|
|
41
45
|
});
|
|
42
46
|
class AXPTenantDefaultLoader {
|
|
43
|
-
getList(context) {
|
|
44
|
-
return
|
|
47
|
+
async getList(context) {
|
|
48
|
+
return [
|
|
45
49
|
{
|
|
46
50
|
id: '1',
|
|
47
51
|
name: 'default-tenant',
|
|
48
52
|
title: 'Default Tenant',
|
|
49
53
|
},
|
|
50
|
-
]
|
|
54
|
+
];
|
|
51
55
|
}
|
|
52
56
|
}
|
|
53
57
|
|
|
@@ -85,8 +89,8 @@ const AXP_FEATURE_LOADER = new InjectionToken('AXP_FEATURE_LOADER', {
|
|
|
85
89
|
},
|
|
86
90
|
});
|
|
87
91
|
class AXPFeatureDefaultLoader {
|
|
88
|
-
getList(context) {
|
|
89
|
-
return
|
|
92
|
+
async getList(context) {
|
|
93
|
+
return [];
|
|
90
94
|
}
|
|
91
95
|
}
|
|
92
96
|
|
|
@@ -173,6 +177,13 @@ const AXPFeatureGuard = (route, state) => {
|
|
|
173
177
|
}));
|
|
174
178
|
};
|
|
175
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Optional injection token for feature checker.
|
|
182
|
+
* If provided, the checker will be called to potentially override
|
|
183
|
+
* feature enablement results based on custom logic.
|
|
184
|
+
*/
|
|
185
|
+
const AXP_FEATURE_CHECKER = new InjectionToken('AXP_FEATURE_CHECKER');
|
|
186
|
+
|
|
176
187
|
const AXP_PERMISSION_LOADER = new InjectionToken('AXP_PERMISSION_LOADER', {
|
|
177
188
|
providedIn: 'root',
|
|
178
189
|
factory: () => {
|
|
@@ -180,11 +191,18 @@ const AXP_PERMISSION_LOADER = new InjectionToken('AXP_PERMISSION_LOADER', {
|
|
|
180
191
|
}
|
|
181
192
|
});
|
|
182
193
|
class AXPPermissionDefaultLoader {
|
|
183
|
-
getList(context) {
|
|
184
|
-
return
|
|
194
|
+
async getList(context) {
|
|
195
|
+
return [];
|
|
185
196
|
}
|
|
186
197
|
}
|
|
187
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Optional injection token for permission checker.
|
|
201
|
+
* If provided, the checker will be called to potentially override
|
|
202
|
+
* authorization results based on custom logic.
|
|
203
|
+
*/
|
|
204
|
+
const AXP_PERMISSION_CHECKER = new InjectionToken('AXP_PERMISSION_CHECKER');
|
|
205
|
+
|
|
188
206
|
class AXPSessionContext {
|
|
189
207
|
get user() {
|
|
190
208
|
return this._user;
|
|
@@ -218,10 +236,13 @@ class AXPSessionService {
|
|
|
218
236
|
constructor() {
|
|
219
237
|
this.eventService = inject(AXPBroadcastEventService);
|
|
220
238
|
this.authStrategyRegistry = inject(AXPAuthStrategyRegistryService);
|
|
239
|
+
this.injector = inject(Injector);
|
|
221
240
|
this.permissionLoader = inject(AXP_PERMISSION_LOADER);
|
|
222
241
|
this.featureLoader = inject(AXP_FEATURE_LOADER);
|
|
223
242
|
this.tenantLoader = inject(AXP_TENANT_LOADER);
|
|
224
243
|
this.applicationLoader = inject(AXP_APPLICATION_LOADER);
|
|
244
|
+
this.permissionChecker = inject(AXP_PERMISSION_CHECKER, { optional: true });
|
|
245
|
+
this.featureChecker = inject(AXP_FEATURE_CHECKER, { optional: true });
|
|
225
246
|
this.status = new BehaviorSubject(AXPSessionStatus.Unauthenticated);
|
|
226
247
|
this.status$ = this.status.asObservable().pipe(shareReplay(1));
|
|
227
248
|
// Add loading state to prevent premature redirects
|
|
@@ -244,8 +265,10 @@ class AXPSessionService {
|
|
|
244
265
|
// Add a new observable that considers loading state
|
|
245
266
|
this.isAuthenticatedWithLoading$ = this.isLoading$.pipe(switchMap((loading) => {
|
|
246
267
|
if (loading) {
|
|
268
|
+
// Wait for loading to complete, then return authentication status
|
|
247
269
|
return this.isLoading$.pipe(filter((isLoading) => !isLoading), switchMap(() => this.isAuthenticated$));
|
|
248
270
|
}
|
|
271
|
+
// If not loading, return current authentication status
|
|
249
272
|
return this.isAuthenticated$;
|
|
250
273
|
}), shareReplay(1));
|
|
251
274
|
this.isAuthorized$ = this.status$.pipe(map((status) => status === AXPSessionStatus.Authorized), shareReplay(1));
|
|
@@ -266,7 +289,7 @@ class AXPSessionService {
|
|
|
266
289
|
return this.currentTenantSubject.value;
|
|
267
290
|
}
|
|
268
291
|
get tenants$() {
|
|
269
|
-
return this.tenantLoader.getList(this.getContext());
|
|
292
|
+
return from(this.tenantLoader.getList(this.getContext()));
|
|
270
293
|
}
|
|
271
294
|
get application() {
|
|
272
295
|
const session = this.getSessionData();
|
|
@@ -276,7 +299,7 @@ class AXPSessionService {
|
|
|
276
299
|
return this.currentApplicationSubject.value;
|
|
277
300
|
}
|
|
278
301
|
get applications$() {
|
|
279
|
-
return this.applicationLoader.getList(this.getContext());
|
|
302
|
+
return from(this.applicationLoader.getList(this.getContext()));
|
|
280
303
|
}
|
|
281
304
|
get permissions() {
|
|
282
305
|
return this.permissionsSubject.value ?? [];
|
|
@@ -291,6 +314,13 @@ class AXPSessionService {
|
|
|
291
314
|
if (sessionData) {
|
|
292
315
|
if (sessionData.user) {
|
|
293
316
|
this.currentUserSubject.next(sessionData.user);
|
|
317
|
+
// Restore tenant and application from session data
|
|
318
|
+
if (sessionData.tenant) {
|
|
319
|
+
this.currentTenantSubject.next(sessionData.tenant);
|
|
320
|
+
}
|
|
321
|
+
if (sessionData.application) {
|
|
322
|
+
this.currentApplicationSubject.next(sessionData.application);
|
|
323
|
+
}
|
|
294
324
|
this.status.next(AXPSessionStatus.Authenticated);
|
|
295
325
|
await this.loadPermissions();
|
|
296
326
|
await this.loadFeatures();
|
|
@@ -457,7 +487,7 @@ class AXPSessionService {
|
|
|
457
487
|
}
|
|
458
488
|
async loadPermissions() {
|
|
459
489
|
try {
|
|
460
|
-
const permissions = await
|
|
490
|
+
const permissions = await this.permissionLoader.getList(this.getContext());
|
|
461
491
|
this.permissionsSubject.next(permissions ?? []);
|
|
462
492
|
}
|
|
463
493
|
catch (error) {
|
|
@@ -467,7 +497,7 @@ class AXPSessionService {
|
|
|
467
497
|
}
|
|
468
498
|
async loadFeatures() {
|
|
469
499
|
try {
|
|
470
|
-
const features = await
|
|
500
|
+
const features = await this.featureLoader.getList(this.getContext());
|
|
471
501
|
this.featuresSubject.next(features ?? []);
|
|
472
502
|
}
|
|
473
503
|
catch (error) {
|
|
@@ -547,26 +577,55 @@ class AXPSessionService {
|
|
|
547
577
|
localStorage.removeItem(AXPSessionService.SESSION_KEY);
|
|
548
578
|
}
|
|
549
579
|
authorize(...keys) {
|
|
550
|
-
|
|
580
|
+
// Calculate base result
|
|
581
|
+
const baseResult = keys.every((k) => {
|
|
582
|
+
if (isEmpty(k))
|
|
583
|
+
return true;
|
|
584
|
+
// Check if user has the permission
|
|
585
|
+
const hasPermission = this.permissions.indexOf(k) > -1;
|
|
586
|
+
if (!hasPermission)
|
|
587
|
+
return false;
|
|
588
|
+
// Check if permission has required features (if permission definition service is available)
|
|
589
|
+
// Note: This is a lightweight check. Full feature validation happens in permission definition service.
|
|
590
|
+
return true;
|
|
591
|
+
});
|
|
592
|
+
// If permission checker is provided, use it to potentially override the result
|
|
593
|
+
if (this.permissionChecker) {
|
|
594
|
+
const context = this.getContext();
|
|
595
|
+
return this.permissionChecker.check(keys, context, baseResult);
|
|
596
|
+
}
|
|
597
|
+
return baseResult;
|
|
551
598
|
}
|
|
552
599
|
isFeatureEnabled(...keys) {
|
|
553
|
-
|
|
600
|
+
// Calculate base result
|
|
601
|
+
const baseResult = keys.every((k) => isEmpty(k) || this.features.some((c) => c.name == k && c.value == true));
|
|
602
|
+
// If feature checker is provided, use it to potentially override the result
|
|
603
|
+
if (this.featureChecker) {
|
|
604
|
+
const context = this.getContext();
|
|
605
|
+
return this.featureChecker.check(keys, context, baseResult);
|
|
606
|
+
}
|
|
607
|
+
return baseResult;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Checks if a module is enabled for the current tenant/application.
|
|
611
|
+
* Module names are stored as features with value: true when enabled.
|
|
612
|
+
* Module names can be provided in PascalCase (e.g., 'SecurityManagement') or kebab-case (e.g., 'security-management').
|
|
613
|
+
*/
|
|
614
|
+
isModuleEnabled(moduleName) {
|
|
615
|
+
if (!moduleName) {
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
// Normalize module name: convert kebab-case to PascalCase if needed
|
|
619
|
+
const normalizedModuleName = moduleName.includes('-')
|
|
620
|
+
? moduleName.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join('')
|
|
621
|
+
: moduleName;
|
|
622
|
+
// Module names are stored as features with value: true when enabled
|
|
623
|
+
return this.features.some(f => f.name === normalizedModuleName && f.value === true);
|
|
554
624
|
}
|
|
555
625
|
getToken() {
|
|
556
626
|
const sessionData = this.getSessionData();
|
|
557
627
|
return sessionData?.accessToken;
|
|
558
628
|
}
|
|
559
|
-
checkTokenValidation() {
|
|
560
|
-
let sessionData = this.getSessionData();
|
|
561
|
-
if (sessionData && sessionData?.accessToken && sessionData.expiresIn) {
|
|
562
|
-
const expiresInDate = new Date(sessionData.expiresIn);
|
|
563
|
-
if (expiresInDate > new Date()) {
|
|
564
|
-
// Token is still valid
|
|
565
|
-
return true;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
return false;
|
|
569
|
-
}
|
|
570
629
|
getContext() {
|
|
571
630
|
return new AXPSessionContext({
|
|
572
631
|
user: this.user,
|
|
@@ -687,12 +746,13 @@ class AXPPermissionDefinitionGroupBuilder {
|
|
|
687
746
|
this.context = context;
|
|
688
747
|
this._group = group;
|
|
689
748
|
}
|
|
690
|
-
addPermission(name, title, description) {
|
|
749
|
+
addPermission(name, title, description, requiredFeatures) {
|
|
691
750
|
const permission = {
|
|
692
751
|
name,
|
|
693
752
|
title,
|
|
694
753
|
description,
|
|
695
|
-
children: []
|
|
754
|
+
children: [],
|
|
755
|
+
requiredFeatures
|
|
696
756
|
};
|
|
697
757
|
this._group.permissions.push(permission);
|
|
698
758
|
return new AXPPermissionDefinitionBuilder(this, permission);
|
|
@@ -712,16 +772,25 @@ class AXPPermissionDefinitionBuilder {
|
|
|
712
772
|
this.groupBuilder = groupBuilder;
|
|
713
773
|
this.permission = permission;
|
|
714
774
|
}
|
|
715
|
-
addChild(name, title, description) {
|
|
775
|
+
addChild(name, title, description, requiredFeatures) {
|
|
716
776
|
const permission = {
|
|
717
777
|
name,
|
|
718
778
|
title,
|
|
719
779
|
description,
|
|
720
|
-
children: []
|
|
780
|
+
children: [],
|
|
781
|
+
requiredFeatures
|
|
721
782
|
};
|
|
722
783
|
this.permission.children.push(permission);
|
|
723
784
|
return this;
|
|
724
785
|
}
|
|
786
|
+
/**
|
|
787
|
+
* Set required features for this permission.
|
|
788
|
+
* @param features - Array of feature names (e.g., ['PlatformManagement.menu-customization'])
|
|
789
|
+
*/
|
|
790
|
+
requireFeatures(...features) {
|
|
791
|
+
this.permission.requiredFeatures = features;
|
|
792
|
+
return this;
|
|
793
|
+
}
|
|
725
794
|
endPermission() {
|
|
726
795
|
return this.groupBuilder;
|
|
727
796
|
}
|
|
@@ -736,6 +805,7 @@ const AXP_PERMISSION_DEFINITION_PROVIDER = new InjectionToken('AXP_PERMISSION_DE
|
|
|
736
805
|
class AXPPermissionDefinitionService {
|
|
737
806
|
constructor() {
|
|
738
807
|
this.providers = inject(AXP_PERMISSION_DEFINITION_PROVIDER, { optional: true });
|
|
808
|
+
this.sessionService = inject(AXPSessionService);
|
|
739
809
|
this.cache = null;
|
|
740
810
|
}
|
|
741
811
|
async load() {
|
|
@@ -743,6 +813,7 @@ class AXPPermissionDefinitionService {
|
|
|
743
813
|
return;
|
|
744
814
|
}
|
|
745
815
|
const context = new AXPPermissionDefinitionProviderContext();
|
|
816
|
+
// Load providers from DI tokens
|
|
746
817
|
if (Array.isArray(this.providers)) {
|
|
747
818
|
for (const provider of this.providers) {
|
|
748
819
|
if (provider instanceof Promise) {
|
|
@@ -756,7 +827,44 @@ class AXPPermissionDefinitionService {
|
|
|
756
827
|
}
|
|
757
828
|
}
|
|
758
829
|
}
|
|
759
|
-
|
|
830
|
+
// Filter permissions based on required features
|
|
831
|
+
const allGroups = context.getGroupDefinitions();
|
|
832
|
+
this.cache = this.filterByFeatures(allGroups);
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Filter permissions based on required features.
|
|
836
|
+
* Removes permissions that have required features that are not enabled.
|
|
837
|
+
*/
|
|
838
|
+
filterByFeatures(groups) {
|
|
839
|
+
return groups.map(group => ({
|
|
840
|
+
...group,
|
|
841
|
+
permissions: this.filterPermissions(group.permissions)
|
|
842
|
+
})).filter(group => group.permissions.length > 0);
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Recursively filter permissions and their children based on required features.
|
|
846
|
+
*/
|
|
847
|
+
filterPermissions(permissions) {
|
|
848
|
+
return permissions
|
|
849
|
+
.filter(permission => {
|
|
850
|
+
// Check if required features are enabled
|
|
851
|
+
if (permission.requiredFeatures && permission.requiredFeatures.length > 0) {
|
|
852
|
+
const allFeaturesEnabled = permission.requiredFeatures.every(featureName => this.sessionService.isFeatureEnabled(featureName));
|
|
853
|
+
if (!allFeaturesEnabled) {
|
|
854
|
+
return false; // Filter out this permission
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
return true;
|
|
858
|
+
})
|
|
859
|
+
.map(permission => ({
|
|
860
|
+
...permission,
|
|
861
|
+
children: this.filterPermissions(permission.children)
|
|
862
|
+
}))
|
|
863
|
+
.filter(permission => {
|
|
864
|
+
// Remove permissions that have no children if they were only containers
|
|
865
|
+
// (This is optional - you might want to keep parent permissions even without children)
|
|
866
|
+
return true;
|
|
867
|
+
});
|
|
760
868
|
}
|
|
761
869
|
async reload() {
|
|
762
870
|
this.cache = null;
|
|
@@ -882,6 +990,10 @@ class AXPAuthModule {
|
|
|
882
990
|
const initializerFn = initializeAppState(inject(AXPSessionService));
|
|
883
991
|
return initializerFn();
|
|
884
992
|
}),
|
|
993
|
+
{
|
|
994
|
+
provide: AXP_SESSION_SERVICE,
|
|
995
|
+
useExisting: AXPSessionService,
|
|
996
|
+
},
|
|
885
997
|
] }); }
|
|
886
998
|
}
|
|
887
999
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPAuthModule, decorators: [{
|
|
@@ -895,6 +1007,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
895
1007
|
const initializerFn = initializeAppState(inject(AXPSessionService));
|
|
896
1008
|
return initializerFn();
|
|
897
1009
|
}),
|
|
1010
|
+
{
|
|
1011
|
+
provide: AXP_SESSION_SERVICE,
|
|
1012
|
+
useExisting: AXPSessionService,
|
|
1013
|
+
},
|
|
898
1014
|
],
|
|
899
1015
|
}]
|
|
900
1016
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
@@ -984,169 +1100,9 @@ class TimeUtil {
|
|
|
984
1100
|
}
|
|
985
1101
|
//#endregion
|
|
986
1102
|
|
|
987
|
-
//#region ---- Challenge Data Types ----
|
|
988
|
-
//#endregion
|
|
989
|
-
|
|
990
|
-
//#region ---- Abstract Challenge Provider ----
|
|
991
|
-
/**
|
|
992
|
-
* Abstract base class for login challenge providers
|
|
993
|
-
*
|
|
994
|
-
* Implement this class to create custom challenge mechanisms like:
|
|
995
|
-
* - Image CAPTCHA
|
|
996
|
-
* - reCAPTCHA
|
|
997
|
-
* - SMS verification
|
|
998
|
-
* - Email verification
|
|
999
|
-
*
|
|
1000
|
-
* @example
|
|
1001
|
-
* ```typescript
|
|
1002
|
-
* @Injectable()
|
|
1003
|
-
* export class MyImageCaptchaProvider extends AXPLoginChallengeProvider {
|
|
1004
|
-
* readonly name = 'image-captcha';
|
|
1005
|
-
*
|
|
1006
|
-
* checkResponse(error: unknown): AXPChallengeCheckResult | null {
|
|
1007
|
-
* if (error instanceof HttpErrorResponse) {
|
|
1008
|
-
* if (error.error?.requiresCaptcha) {
|
|
1009
|
-
* return { required: true };
|
|
1010
|
-
* }
|
|
1011
|
-
* }
|
|
1012
|
-
* return null;
|
|
1013
|
-
* }
|
|
1014
|
-
*
|
|
1015
|
-
* async getChallenge(): Promise<AXPLoginChallengeData> {
|
|
1016
|
-
* const response = await this.http.get('/api/captcha').toPromise();
|
|
1017
|
-
* return {
|
|
1018
|
-
* id: response.id,
|
|
1019
|
-
* content: response.image,
|
|
1020
|
-
* contentType: 'image-base64'
|
|
1021
|
-
* };
|
|
1022
|
-
* }
|
|
1023
|
-
*
|
|
1024
|
-
* async refreshChallenge(): Promise<AXPLoginChallengeData> {
|
|
1025
|
-
* return this.getChallenge();
|
|
1026
|
-
* }
|
|
1027
|
-
*
|
|
1028
|
-
* getChallengeComponent(): Type<AXPLoginChallengeComponentBase> {
|
|
1029
|
-
* return MyCaptchaChallengeComponent;
|
|
1030
|
-
* }
|
|
1031
|
-
* }
|
|
1032
|
-
* ```
|
|
1033
|
-
*/
|
|
1034
|
-
class AXPLoginChallengeProvider {
|
|
1035
|
-
/**
|
|
1036
|
-
* Returns the component type for rendering the challenge UI
|
|
1037
|
-
*
|
|
1038
|
-
* Override this method to provide a custom challenge UI component.
|
|
1039
|
-
* If not overridden (returns null), the login component will use
|
|
1040
|
-
* a default built-in UI.
|
|
1041
|
-
*
|
|
1042
|
-
* @returns Component type extending AXPLoginChallengeComponentBase, or null for default UI
|
|
1043
|
-
*/
|
|
1044
|
-
getChallengeComponent() {
|
|
1045
|
-
return null;
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
//#endregion
|
|
1049
|
-
|
|
1050
|
-
//#region ---- Injection Token ----
|
|
1051
|
-
/**
|
|
1052
|
-
* Injection token for the login challenge provider
|
|
1053
|
-
*
|
|
1054
|
-
* This token is optional - if not provided, no challenge mechanism will be used.
|
|
1055
|
-
*
|
|
1056
|
-
* @example
|
|
1057
|
-
* ```typescript
|
|
1058
|
-
* // In your app module or provider configuration:
|
|
1059
|
-
* providers: [
|
|
1060
|
-
* {
|
|
1061
|
-
* provide: AXP_LOGIN_CHALLENGE_PROVIDER,
|
|
1062
|
-
* useClass: MyImageCaptchaProvider
|
|
1063
|
-
* }
|
|
1064
|
-
* ]
|
|
1065
|
-
*
|
|
1066
|
-
* // In a component:
|
|
1067
|
-
* private challengeProvider = inject(AXP_LOGIN_CHALLENGE_PROVIDER, { optional: true });
|
|
1068
|
-
* ```
|
|
1069
|
-
*/
|
|
1070
|
-
const AXP_LOGIN_CHALLENGE_PROVIDER = new InjectionToken('AXP_LOGIN_CHALLENGE_PROVIDER');
|
|
1071
|
-
//#endregion
|
|
1072
|
-
|
|
1073
|
-
//#region ---- Base Challenge Component ----
|
|
1074
|
-
/**
|
|
1075
|
-
* Base class for login challenge UI components
|
|
1076
|
-
*
|
|
1077
|
-
* Providers can extend this class to create custom challenge UIs.
|
|
1078
|
-
* The login component will render this component and listen to its outputs.
|
|
1079
|
-
*
|
|
1080
|
-
* @example
|
|
1081
|
-
* ```typescript
|
|
1082
|
-
* @Component({
|
|
1083
|
-
* selector: 'my-captcha-challenge',
|
|
1084
|
-
* template: `
|
|
1085
|
-
* <div class="captcha-container">
|
|
1086
|
-
* <img [src]="'data:image/png;base64,' + challengeData().content" />
|
|
1087
|
-
* <input
|
|
1088
|
-
* type="text"
|
|
1089
|
-
* [value]="response()"
|
|
1090
|
-
* (input)="onResponseChange($event)"
|
|
1091
|
-
* />
|
|
1092
|
-
* <button (click)="onRefreshClick()">Refresh</button>
|
|
1093
|
-
* </div>
|
|
1094
|
-
* `
|
|
1095
|
-
* })
|
|
1096
|
-
* export class MyCaptchaChallengeComponent extends AXPLoginChallengeComponentBase {
|
|
1097
|
-
* response = signal('');
|
|
1098
|
-
*
|
|
1099
|
-
* onResponseChange(event: Event) {
|
|
1100
|
-
* const value = (event.target as HTMLInputElement).value;
|
|
1101
|
-
* this.response.set(value);
|
|
1102
|
-
* this.responseChange.emit(value);
|
|
1103
|
-
* }
|
|
1104
|
-
*
|
|
1105
|
-
* onRefreshClick() {
|
|
1106
|
-
* this.refreshRequest.emit();
|
|
1107
|
-
* }
|
|
1108
|
-
* }
|
|
1109
|
-
* ```
|
|
1110
|
-
*/
|
|
1111
|
-
class AXPLoginChallengeComponentBase {
|
|
1112
|
-
constructor() {
|
|
1113
|
-
//#region ---- Inputs ----
|
|
1114
|
-
/**
|
|
1115
|
-
* Challenge data to display
|
|
1116
|
-
* Contains the image/content and metadata from the server
|
|
1117
|
-
*/
|
|
1118
|
-
this.challengeData = input.required(...(ngDevMode ? [{ debugName: "challengeData" }] : []));
|
|
1119
|
-
/**
|
|
1120
|
-
* Whether the challenge is currently loading (e.g., refreshing)
|
|
1121
|
-
*/
|
|
1122
|
-
this.isLoading = input(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
1123
|
-
//#endregion
|
|
1124
|
-
//#region ---- Outputs ----
|
|
1125
|
-
/**
|
|
1126
|
-
* Emits when the user enters or changes their response
|
|
1127
|
-
* The login component will capture this value and include it in credentials
|
|
1128
|
-
*/
|
|
1129
|
-
this.responseChange = output();
|
|
1130
|
-
/**
|
|
1131
|
-
* Emits when the user requests a new challenge (e.g., clicks refresh button)
|
|
1132
|
-
* The login component will call provider.refreshChallenge()
|
|
1133
|
-
*/
|
|
1134
|
-
this.refreshRequest = output();
|
|
1135
|
-
}
|
|
1136
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLoginChallengeComponentBase, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1137
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.12", type: AXPLoginChallengeComponentBase, isStandalone: true, selector: "ng-component", inputs: { challengeData: { classPropertyName: "challengeData", publicName: "challengeData", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { responseChange: "responseChange", refreshRequest: "refreshRequest" }, ngImport: i0, template: '', isInline: true }); }
|
|
1138
|
-
}
|
|
1139
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLoginChallengeComponentBase, decorators: [{
|
|
1140
|
-
type: Component,
|
|
1141
|
-
args: [{
|
|
1142
|
-
template: '',
|
|
1143
|
-
standalone: true,
|
|
1144
|
-
}]
|
|
1145
|
-
}], propDecorators: { challengeData: [{ type: i0.Input, args: [{ isSignal: true, alias: "challengeData", required: true }] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: false }] }], responseChange: [{ type: i0.Output, args: ["responseChange"] }], refreshRequest: [{ type: i0.Output, args: ["refreshRequest"] }] } });
|
|
1146
|
-
|
|
1147
1103
|
/**
|
|
1148
1104
|
* Generated bundle index. Do not edit.
|
|
1149
1105
|
*/
|
|
1150
1106
|
|
|
1151
|
-
export { AXPAuthGuard, AXPAuthModule, AXPAuthStrategy, AXPAuthStrategyRegistryService, AXPFeatureDirective, AXPFeatureGuard,
|
|
1107
|
+
export { AXPAuthGuard, AXPAuthModule, AXPAuthStrategy, AXPAuthStrategyRegistryService, AXPFeatureDirective, AXPFeatureGuard, AXPPermissionDefinitionBuilder, AXPPermissionDefinitionGroupBuilder, AXPPermissionDefinitionProviderContext, AXPPermissionDefinitionService, AXPPermissionDirective, AXPPermissionEvaluatorScopeProvider, AXPPermissionGuard, AXPSessionContext, AXPSessionService, AXPSessionStatus, AXPUnauthenticatedError, AXPUnauthorizedError, AXP_APPLICATION_LOADER, AXP_FEATURE_CHECKER, AXP_FEATURE_LOADER, AXP_PERMISSION_CHECKER, AXP_PERMISSION_DEFINITION_PROVIDER, AXP_PERMISSION_LOADER, AXP_TENANT_LOADER, JwtUtil, PkceUtil, TimeUtil, initializeAppState };
|
|
1152
1108
|
//# sourceMappingURL=acorex-platform-auth.mjs.map
|