@acorex-platform/module-security-management-client 0.0.15 → 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.
Files changed (16) hide show
  1. package/fesm2022/acorex-platform-module-security-management-client-acorex-platform-module-security-management-client-jSDkyMMZ.mjs +2088 -0
  2. package/fesm2022/acorex-platform-module-security-management-client-acorex-platform-module-security-management-client-jSDkyMMZ.mjs.map +1 -0
  3. package/fesm2022/acorex-platform-module-security-management-client-contracts.mjs +158 -1677
  4. package/fesm2022/acorex-platform-module-security-management-client-contracts.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-module-security-management-client-index-DOHWBEzM.mjs +462 -0
  6. package/fesm2022/acorex-platform-module-security-management-client-index-DOHWBEzM.mjs.map +1 -0
  7. package/fesm2022/acorex-platform-module-security-management-client-send-password-reset-email.command-CoQgWdya.mjs +81 -0
  8. package/fesm2022/acorex-platform-module-security-management-client-send-password-reset-email.command-CoQgWdya.mjs.map +1 -0
  9. package/fesm2022/{acorex-platform-module-security-management-client-terminate-session.command-CKq-4Z4O.mjs → acorex-platform-module-security-management-client-terminate-session.command-dsU7scOK.mjs} +19 -12
  10. package/fesm2022/acorex-platform-module-security-management-client-terminate-session.command-dsU7scOK.mjs.map +1 -0
  11. package/fesm2022/acorex-platform-module-security-management-client.mjs +1 -1704
  12. package/fesm2022/acorex-platform-module-security-management-client.mjs.map +1 -1
  13. package/package.json +1 -1
  14. package/types/acorex-platform-module-security-management-client-contracts.d.ts +208 -33
  15. package/types/acorex-platform-module-security-management-client.d.ts +139 -35
  16. package/fesm2022/acorex-platform-module-security-management-client-terminate-session.command-CKq-4Z4O.mjs.map +0 -1
@@ -1,1705 +1,2 @@
1
- import * as i0 from '@angular/core';
2
- import { Injectable, NgModule, inject, signal, input, output, computed, ViewEncapsulation, Component, effect, ChangeDetectionStrategy } from '@angular/core';
3
- import { AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, AXP_MODULE_MANIFEST_PROVIDER, AXP_FEATURE_DEFINITION_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXP_CONTEXT_DEFINITION_PROVIDER, setupPopupFooterKeyboardShortcuts } from '@acorex-platform/framework-client/core';
4
- import { AXPEntityService, AXP_ENTITY_DEFINITION_LOADER, AXPEntityDefinitionRegistryService, AXPEntityModifyEvent } from '@acorex-platform/framework-client/layout/entity';
5
- import { RootConfig, AXPSecurityManagementFeatureKeys, AXMSecurityManagementDataSourceKeys, AXM_USER_ACCESS_STATE_DEFINITION_KEY, AXMUserAccessState, AXM_USER_EFFECTIVE_STATE_DEFINITION_KEY, AXMUserEffectiveState, AXPSecurityManagementMenuKeys, AXPSecurityManagementPermissionKeys } from '@acorex-platform/module-security-management-client/contracts';
6
- import { AXPSessionService, AXP_PERMISSION_DEFINITION_PROVIDER, AXPPermissionDefinitionService } from '@acorex-platform/framework-client/auth';
7
- import { AXPSearchCommandProvider, createEntitySearchCommand, AXP_MENU_PROVIDER, AXP_SEARCH_PROVIDER, AXP_STATUS_PROVIDERS, AXPSettingsService, AXPRefreshEvent, AXPCommonSettings } from '@acorex-platform/framework-client/common';
8
- import { provideCommandSetups, AXPCommandService } from '@acorex-platform/framework-client/runtime';
9
- import { AXPWidgetsList, AXPWidgetsCatalog, AXPStatusProvider, AXPSystemStatusType } from '@acorex-platform/framework-shared/core';
10
- import { AXPWidgetCoreModule, AXP_WIDGET_DEFINITION_PROVIDER, AXPValueWidgetComponent, AXPColumnWidgetComponent } from '@acorex-platform/framework-client/layout/widget-core';
11
- import { AXPWidgetGroupEnum } from '@acorex-platform/framework-shared/widget-core';
12
- import { AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_DISABLED_PROPERTY } from '@acorex-platform/framework-client/layout/widgets';
13
- import * as i3 from '@acorex/cdk/common';
14
- import { AXDataSource, AXCommonModule } from '@acorex/cdk/common';
15
- import { AXPCommonMenuKeys } from '@acorex-platform/module-common-client/contracts';
16
- import * as i1 from '@angular/common';
17
- import { CommonModule } from '@angular/common';
18
- import { AXBasePageComponent } from '@acorex/components/page';
19
- import { AXFormModule } from '@acorex/components/form';
20
- import * as i4 from '@acorex/components/button';
21
- import { AXButtonModule } from '@acorex/components/button';
22
- import { AXTextBoxModule } from '@acorex/components/text-box';
23
- import * as i6 from '@acorex/components/check-box';
24
- import { AXCheckBoxModule } from '@acorex/components/check-box';
25
- import * as i5 from '@acorex/components/label';
26
- import { AXLabelModule } from '@acorex/components/label';
27
- import * as i8 from '@acorex/components/decorators';
28
- import { AXDecoratorModule } from '@acorex/components/decorators';
29
- import * as i12 from '@acorex/core/translation';
30
- import { AXTranslationService, AXTranslationModule, resolveMultiLanguageString } from '@acorex/core/translation';
31
- import * as i7 from '@acorex/components/tabs';
32
- import { AXTabsModule } from '@acorex/components/tabs';
33
- import * as i9 from '@acorex/components/badge';
34
- import { AXBadgeModule } from '@acorex/components/badge';
35
- import * as i2 from '@angular/forms';
36
- import { FormsModule } from '@angular/forms';
37
- import { AXTooltipModule } from '@acorex/components/tooltip';
38
- import * as i10 from '@acorex/components/skeleton';
39
- import { AXSkeletonModule } from '@acorex/components/skeleton';
40
- import * as i11 from '@acorex/components/search-box';
41
- import { AXSearchBoxModule } from '@acorex/components/search-box';
42
- import { AXPStateMessageComponent } from '@acorex-platform/framework-client/layout/components';
43
- import { isEmpty, trim, isString, isArray, castArray } from 'lodash-es';
44
- import { AXPopupService } from '@acorex/components/popup';
45
- import { AXToastService } from '@acorex/components/toast';
46
- import { AXPWorkflowEventService } from '@acorex-platform/framework-client/workflow';
47
-
48
- //#region ---- Device Sessions Service ----
49
- /**
50
- * Terminates device sessions for the current or specified session.
51
- * Implementations are provided by connectivity layers (e.g. mock or API).
52
- */
53
- class AXMDeviceSessionsService {
54
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMDeviceSessionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
55
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMDeviceSessionsService }); }
56
- }
57
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMDeviceSessionsService, decorators: [{
58
- type: Injectable
59
- }] });
60
-
61
- //#region ---- Imports ----
62
- //#endregion
63
- //#region ---- Manifest Definition ----
64
- /**
65
- * Security Management Module Manifest.
66
- * Defines module metadata, features, and provider references.
67
- */
68
- const SecurityManagementManifest = {
69
- name: RootConfig.module.name,
70
- version: '1.0.0',
71
- title: RootConfig.module.title,
72
- icon: RootConfig.module.icon,
73
- i18n: RootConfig.config.i18n,
74
- required: true,
75
- // Module dependencies (optional)
76
- };
77
- //#endregion
78
-
79
- class AXMEntityProvider {
80
- preload() {
81
- const { entities, module } = RootConfig;
82
- return [entities.users.name, entities.roles.name, entities.deviceSessions.name].map((entity) => ({
83
- module: module.name,
84
- entity,
85
- }));
86
- }
87
- async get(moduleName, entityName) {
88
- const { entities, module } = RootConfig;
89
- if (moduleName == module.name) {
90
- switch (entityName) {
91
- case RootConfig.entities.users.name:
92
- return (await import('@acorex-platform/module-security-management-client/contracts')).usersFactory();
93
- case RootConfig.entities.roles.name:
94
- return (await import('@acorex-platform/module-security-management-client/contracts')).rolesFactory();
95
- case RootConfig.entities.profile.name:
96
- return (await import('@acorex-platform/module-security-management-client/contracts')).profileFactory();
97
- case RootConfig.entities.deviceSessions.name:
98
- return (await import('@acorex-platform/module-security-management-client/contracts')).deviceSessionsFactory();
99
- case RootConfig.entities.policy.name:
100
- return (await import('@acorex-platform/module-security-management-client/contracts')).policyFactory();
101
- }
102
- }
103
- return null;
104
- }
105
- async list() {
106
- const m = RootConfig.module.name;
107
- return Promise.resolve(Object.values(RootConfig.entities).map((e) => ({ name: e.name, module: m })));
108
- }
109
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMEntityProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
110
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMEntityProvider }); }
111
- }
112
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMEntityProvider, decorators: [{
113
- type: Injectable
114
- }] });
115
-
116
- //#region ---- Imports ----
117
- //#endregion
118
- //#region ---- Feature Definition Provider ----
119
- /**
120
- * Security Management Module Feature Definition Provider.
121
- * Provides feature definitions for the Security Management module.
122
- */
123
- class AXMSecurityManagementFeatureDefinitionProvider {
124
- async provide(context) {
125
- const i18n = RootConfig.config.i18n;
126
- // Manage Roles feature
127
- context.addFeature(AXPSecurityManagementFeatureKeys.ManageRoles, {
128
- title: `@${i18n}:features.manage-roles.title`,
129
- description: `@${i18n}:features.manage-roles.description`,
130
- defaultValue: true,
131
- type: 'boolean',
132
- });
133
- // Manage Users feature
134
- context.addFeature(AXPSecurityManagementFeatureKeys.ManageUsers, {
135
- title: `@${i18n}:features.manage-users.title`,
136
- description: `@${i18n}:features.manage-users.description`,
137
- defaultValue: true,
138
- type: 'boolean',
139
- });
140
- // Max Total Users feature (widget configuration)
141
- context.addFeature(AXPSecurityManagementFeatureKeys.MaxTotalUsers, {
142
- title: `@${i18n}:features.max-total-users.title`,
143
- description: `@${i18n}:features.max-total-users.description`,
144
- defaultValue: 100,
145
- type: 'number',
146
- interface: {
147
- type: AXPWidgetsList.Editors.NumberBox,
148
- options: {
149
- placeholder: `@${i18n}:features.max-total-users.title`,
150
- min: 1,
151
- max: 10000,
152
- step: 1,
153
- },
154
- },
155
- });
156
- // Manage Sessions feature
157
- context.addFeature(AXPSecurityManagementFeatureKeys.ManageSessions, {
158
- title: `@${i18n}:features.manage-sessions.title`,
159
- description: `@${i18n}:features.manage-sessions.description`,
160
- defaultValue: true,
161
- type: 'boolean',
162
- });
163
- // Manage Policies feature
164
- context.addFeature(AXPSecurityManagementFeatureKeys.ManagePolicies, {
165
- title: `@${i18n}:features.manage-policies.title`,
166
- description: `@${i18n}:features.manage-policies.description`,
167
- defaultValue: true,
168
- type: 'boolean',
169
- });
170
- }
171
- }
172
- //#endregion
173
-
174
- const AXPPermissionsWidget = {
175
- name: "permissions-editor",
176
- title: "Permissions Editor",
177
- description: 'Widget for managing permissions with full editor interface',
178
- type: 'view',
179
- categories: [],
180
- groups: [AXPWidgetGroupEnum.EntityWidget],
181
- icon: "fa-light fa-user-shield",
182
- properties: [
183
- AXP_NAME_PROPERTY,
184
- AXP_DATA_PATH_PROPERTY,
185
- AXP_DISABLED_PROPERTY,
186
- ],
187
- components: {
188
- view: {
189
- component: () => Promise.resolve().then(function () { return permissionsWidgetView_component; }).then((c) => c.AXPPermissionsWidgetViewComponent),
190
- },
191
- edit: {
192
- component: () => Promise.resolve().then(function () { return permissionsWidgetEdit_component; }).then((c) => c.AXPPermissionsWidgetEditComponent),
193
- },
194
- column: {
195
- component: () => Promise.resolve().then(function () { return permissionsWidgetColumn_component; }).then((c) => c.AXPPermissionsWidgetColumnComponent),
196
- },
197
- }
198
- };
199
-
200
- //#endregion
201
- //#region ---- Permissions Widgets Provider ----
202
- const WIDGETS = [AXPPermissionsWidget];
203
- class AXPPermissionsWidgetsProvider {
204
- getWidgets() {
205
- return WIDGETS;
206
- }
207
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPermissionsWidgetsProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
208
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPermissionsWidgetsProvider }); }
209
- }
210
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPermissionsWidgetsProvider, decorators: [{
211
- type: Injectable
212
- }] });
213
-
214
- class AXMPermissionsModule {
215
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPermissionsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
216
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: AXMPermissionsModule, imports: [AXPWidgetCoreModule] }); }
217
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPermissionsModule, providers: [
218
- { provide: AXP_WIDGET_DEFINITION_PROVIDER, useClass: AXPPermissionsWidgetsProvider, multi: true },
219
- provideCommandSetups([
220
- {
221
- key: 'assign-permissions',
222
- command: () => Promise.resolve().then(function () { return assignPermissions_command; }).then((c) => c.AXMAssignPermissionsCommand),
223
- },
224
- ]),
225
- ], imports: [AXPWidgetCoreModule] }); }
226
- }
227
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPermissionsModule, decorators: [{
228
- type: NgModule,
229
- args: [{
230
- imports: [
231
- AXPWidgetCoreModule,
232
- ],
233
- providers: [
234
- { provide: AXP_WIDGET_DEFINITION_PROVIDER, useClass: AXPPermissionsWidgetsProvider, multi: true },
235
- provideCommandSetups([
236
- {
237
- key: 'assign-permissions',
238
- command: () => Promise.resolve().then(function () { return assignPermissions_command; }).then((c) => c.AXMAssignPermissionsCommand),
239
- },
240
- ]),
241
- ],
242
- }]
243
- }] });
244
-
245
- class AXMSecurityManagementEvaluatorScopeProvider {
246
- constructor() {
247
- this.sessionService = inject(AXPSessionService);
248
- }
249
- async provide(context) {
250
- context.addScope('session', {
251
- currentUser: () => {
252
- return this.sessionService.user;
253
- },
254
- user: () => {
255
- return this.sessionService.user;
256
- },
257
- currentApplication: () => {
258
- return this.sessionService.application;
259
- },
260
- currentTenant: () => {
261
- return this.sessionService.tenant;
262
- },
263
- currentPermissions: () => {
264
- return this.sessionService.permissions;
265
- },
266
- });
267
- }
268
- }
269
-
270
- class AXMUsersDataSourceDefinition {
271
- constructor() {
272
- this.entityService = inject(AXPEntityService);
273
- this.userService = this.entityService.withEntity(RootConfig.module.name, RootConfig.entities.users.name).data();
274
- }
275
- items() {
276
- return Promise.resolve([
277
- {
278
- name: AXMSecurityManagementDataSourceKeys.Users,
279
- title: 'Users',
280
- source: () => {
281
- return new AXDataSource({
282
- key: 'id',
283
- load: async (_) => {
284
- try {
285
- const res = await this.userService.query();
286
- return {
287
- items: res.items.map((item) => ({
288
- ...item,
289
- displayName: item.displayName,
290
- })),
291
- total: res.total,
292
- };
293
- }
294
- catch (e) {
295
- console.log(e);
296
- throw e;
297
- }
298
- },
299
- byKey: async (key) => {
300
- return await this.userService.byKey(key);
301
- },
302
- pageSize: 100,
303
- });
304
- },
305
- columns: [
306
- {
307
- name: 'id',
308
- title: 'ID',
309
- datatype: 'uuid',
310
- type: AXPWidgetsCatalog.text,
311
- },
312
- {
313
- name: 'displayName',
314
- title: `Display Name`,
315
- datatype: 'string',
316
- type: AXPWidgetsCatalog.text,
317
- },
318
- {
319
- name: 'username',
320
- title: `Username`,
321
- datatype: 'string',
322
- type: AXPWidgetsCatalog.text,
323
- },
324
- ],
325
- filters: [
326
- {
327
- field: 'username',
328
- title: 'Username',
329
- operator: {
330
- type: 'equal',
331
- },
332
- widget: {
333
- type: AXPWidgetsCatalog.text,
334
- },
335
- filterType: {
336
- advance: true,
337
- inline: true,
338
- },
339
- },
340
- ],
341
- textField: {
342
- name: 'displayName',
343
- title: 'Display Name',
344
- },
345
- valueField: {
346
- name: 'id',
347
- title: 'ID',
348
- },
349
- },
350
- ]);
351
- }
352
- }
353
-
354
- //#region ---- Imports ----
355
- //#endregion
356
- //#region ---- User access state provider ----
357
- /**
358
- * Sign-in readiness from the authentication subsystem (distinct from account lifecycle / `accountState`).
359
- * Transitions listed here are the only paths offered in the status UI and validated when executing a status change command.
360
- */
361
- class AXMUserAccessStateProvider extends AXPStatusProvider {
362
- constructor() {
363
- super(...arguments);
364
- this.key = AXM_USER_ACCESS_STATE_DEFINITION_KEY;
365
- this.defaultStatus = AXMUserAccessState.Allowed;
366
- this.statuses = [
367
- {
368
- name: AXMUserAccessState.Allowed,
369
- title: '@security-management:users.entities.user.access.states.allowed',
370
- description: '@security-management:users.entities.user.access.descriptions.allowed',
371
- icon: 'fa-light fa-circle-check',
372
- color: 'success',
373
- order: 1,
374
- isInitial: true,
375
- isFinal: false,
376
- },
377
- {
378
- name: AXMUserAccessState.Blocked,
379
- title: '@security-management:users.entities.user.access.states.blocked',
380
- description: '@security-management:users.entities.user.access.descriptions.blocked',
381
- icon: 'fa-light fa-ban',
382
- color: 'danger',
383
- order: 2,
384
- isInitial: false,
385
- isFinal: false,
386
- },
387
- {
388
- name: AXMUserAccessState.Expired,
389
- title: '@security-management:users.entities.user.access.states.expired',
390
- description: '@security-management:users.entities.user.access.descriptions.expired',
391
- icon: 'fa-light fa-clock',
392
- color: 'danger',
393
- order: 3,
394
- isInitial: false,
395
- isFinal: true,
396
- generateView: false,
397
- },
398
- ];
399
- this.transitions = [
400
- {
401
- from: AXMUserAccessState.Allowed,
402
- to: AXMUserAccessState.Blocked,
403
- title: '@security-management:users.entities.user.access.transitions.block-sign-in',
404
- },
405
- {
406
- from: AXMUserAccessState.Allowed,
407
- to: AXMUserAccessState.Expired,
408
- title: '@security-management:users.entities.user.access.transitions.require-credential-renewal',
409
- },
410
- {
411
- from: AXMUserAccessState.Blocked,
412
- to: AXMUserAccessState.Allowed,
413
- title: '@security-management:users.entities.user.access.transitions.unblock-sign-in',
414
- },
415
- {
416
- from: AXMUserAccessState.Expired,
417
- to: AXMUserAccessState.Allowed,
418
- title: '@security-management:users.entities.user.access.transitions.restore-after-credential-renewal',
419
- },
420
- ];
421
- }
422
- }
423
- //#endregion
424
-
425
- //#region ---- Imports ----
426
- //#endregion
427
- //#region ---- User effective state provider ----
428
- /**
429
- * Unified operational state for lists, filters, and page chrome (derived from lifecycle + sign-in gate).
430
- */
431
- class AXMUserEffectiveStateProvider extends AXPStatusProvider {
432
- constructor() {
433
- super(...arguments);
434
- this.key = AXM_USER_EFFECTIVE_STATE_DEFINITION_KEY;
435
- this.defaultStatus = AXMUserEffectiveState.Active;
436
- this.statuses = [
437
- {
438
- name: AXMUserEffectiveState.Pending,
439
- title: '@security-management:users.entities.user.effective.states.pending',
440
- description: '@security-management:users.entities.user.effective.descriptions.pending',
441
- icon: 'fa-light fa-hourglass-half',
442
- color: 'warning',
443
- order: 1,
444
- generateView: true,
445
- },
446
- {
447
- name: AXMUserEffectiveState.Active,
448
- title: '@security-management:users.entities.user.effective.states.active',
449
- description: '@security-management:users.entities.user.effective.descriptions.active',
450
- icon: 'fa-light fa-circle-check',
451
- color: 'success',
452
- order: 2,
453
- generateView: true,
454
- },
455
- {
456
- name: AXMUserEffectiveState.SignInBlocked,
457
- title: '@security-management:users.entities.user.effective.states.sign-in-blocked',
458
- description: '@security-management:users.entities.user.effective.descriptions.sign-in-blocked',
459
- icon: 'fa-light fa-shield-halved',
460
- color: 'danger',
461
- order: 3,
462
- generateView: true,
463
- },
464
- {
465
- name: AXMUserEffectiveState.CredentialExpired,
466
- title: '@security-management:users.entities.user.effective.states.credential-expired',
467
- description: '@security-management:users.entities.user.effective.descriptions.credential-expired',
468
- icon: 'fa-light fa-key',
469
- color: 'danger',
470
- order: 4,
471
- generateView: true,
472
- },
473
- {
474
- name: AXMUserEffectiveState.Suspended,
475
- title: '@security-management:users.entities.user.effective.states.suspended',
476
- description: '@security-management:users.entities.user.effective.descriptions.suspended',
477
- icon: 'fa-light fa-pause-circle',
478
- color: 'warning',
479
- order: 5,
480
- generateView: true,
481
- },
482
- {
483
- name: AXMUserEffectiveState.Inactive,
484
- title: '@security-management:users.entities.user.effective.states.inactive',
485
- description: '@security-management:users.entities.user.effective.descriptions.inactive',
486
- icon: 'fa-light fa-user-slash',
487
- color: 'danger',
488
- order: 6,
489
- generateView: true,
490
- },
491
- {
492
- name: AXMUserEffectiveState.Archived,
493
- title: '@security-management:users.entities.user.effective.states.archived',
494
- description: '@security-management:users.entities.user.effective.descriptions.archived',
495
- icon: 'fa-light fa-box-archive',
496
- color: 'danger',
497
- order: 7,
498
- generateView: true,
499
- },
500
- ];
501
- this.transitions = [];
502
- }
503
- }
504
- //#endregion
505
-
506
- //#region ---- Imports ----
507
- //#endregion
508
- //#region ---- User account status provider ----
509
- /**
510
- * Account-level state for SecurityManagement.User (lifecycle / admin).
511
- * Sign-in lockout is expressed as `accessState === blocked`, not as `accountState`.
512
- */
513
- class AXMUserStatusProvider extends AXPStatusProvider {
514
- constructor() {
515
- super(...arguments);
516
- this.key = 'security-management.account-state.user';
517
- this.defaultStatus = AXPSystemStatusType.Active;
518
- this.statuses = [
519
- {
520
- name: AXPSystemStatusType.Pending,
521
- title: '@security-management:users.entities.user.states.pending',
522
- description: '@security-management:users.entities.user.account.descriptions.pending',
523
- icon: 'fa-light fa-envelope-open-text',
524
- color: 'warning',
525
- order: 1,
526
- isInitial: true,
527
- isFinal: false,
528
- generateView: true,
529
- },
530
- {
531
- name: AXPSystemStatusType.Active,
532
- title: '@security-management:users.entities.user.states.active',
533
- description: '@security-management:users.entities.user.account.descriptions.active',
534
- icon: 'fa-light fa-user-check',
535
- color: 'success',
536
- order: 1,
537
- isInitial: false,
538
- isFinal: false,
539
- generateView: true,
540
- },
541
- {
542
- name: AXPSystemStatusType.Suspended,
543
- title: '@security-management:users.entities.user.states.suspended',
544
- description: '@security-management:users.entities.user.account.descriptions.suspended',
545
- icon: 'fa-light fa-pause-circle',
546
- color: 'warning',
547
- order: 5,
548
- isInitial: false,
549
- isFinal: false,
550
- generateView: true,
551
- },
552
- {
553
- name: AXPSystemStatusType.Inactive,
554
- title: '@security-management:users.entities.user.states.inactive',
555
- description: '@security-management:users.entities.user.account.descriptions.inactive',
556
- icon: 'fa-light fa-user-slash',
557
- color: 'danger',
558
- order: 2,
559
- isInitial: false,
560
- isFinal: false,
561
- generateView: true,
562
- },
563
- {
564
- name: AXPSystemStatusType.Archived,
565
- title: '@security-management:users.entities.user.states.archived',
566
- description: '@security-management:users.entities.user.account.descriptions.archived',
567
- icon: 'fa-light fa-box-archive',
568
- color: 'danger',
569
- order: 5,
570
- isInitial: false,
571
- isFinal: true,
572
- generateView: true,
573
- },
574
- ];
575
- this.transitions = [
576
- {
577
- from: AXPSystemStatusType.Pending,
578
- to: AXPSystemStatusType.Active,
579
- title: '@security-management:users.entities.user.transitions.activate',
580
- },
581
- {
582
- from: AXPSystemStatusType.Pending,
583
- to: AXPSystemStatusType.Inactive,
584
- title: '@security-management:users.entities.user.transitions.cancel-invitation',
585
- },
586
- {
587
- from: AXPSystemStatusType.Active,
588
- to: AXPSystemStatusType.Suspended,
589
- title: '@security-management:users.entities.user.transitions.suspend',
590
- },
591
- {
592
- from: AXPSystemStatusType.Suspended,
593
- to: AXPSystemStatusType.Active,
594
- title: '@security-management:users.entities.user.transitions.restore',
595
- },
596
- {
597
- from: AXPSystemStatusType.Active,
598
- to: AXPSystemStatusType.Inactive,
599
- title: '@security-management:users.entities.user.transitions.disable',
600
- },
601
- {
602
- from: AXPSystemStatusType.Inactive,
603
- to: AXPSystemStatusType.Active,
604
- title: '@security-management:users.entities.user.transitions.enable',
605
- },
606
- {
607
- from: AXPSystemStatusType.Suspended,
608
- to: AXPSystemStatusType.Inactive,
609
- title: '@security-management:users.entities.user.transitions.disable',
610
- },
611
- {
612
- from: AXPSystemStatusType.Active,
613
- to: AXPSystemStatusType.Archived,
614
- title: '@security-management:users.entities.user.transitions.archive',
615
- },
616
- {
617
- from: AXPSystemStatusType.Suspended,
618
- to: AXPSystemStatusType.Archived,
619
- title: '@security-management:users.entities.user.transitions.archive',
620
- },
621
- {
622
- from: AXPSystemStatusType.Inactive,
623
- to: AXPSystemStatusType.Archived,
624
- title: '@security-management:users.entities.user.transitions.archive',
625
- },
626
- {
627
- from: AXPSystemStatusType.Pending,
628
- to: AXPSystemStatusType.Archived,
629
- title: '@security-management:users.entities.user.transitions.archive',
630
- },
631
- {
632
- from: AXPSystemStatusType.Archived,
633
- to: AXPSystemStatusType.Active,
634
- title: '@security-management:users.entities.user.transitions.restore-archived',
635
- },
636
- ];
637
- }
638
- }
639
- //#endregion
640
-
641
- class AXMMenuProvider {
642
- constructor() {
643
- this.entityService = inject(AXPEntityService);
644
- }
645
- async provide(context) {
646
- const moduleName = RootConfig.module.name;
647
- // Check if Security submenu exists under Administration, create it if not
648
- const securityMenu = context.find(AXPSecurityManagementMenuKeys.Root);
649
- if (!securityMenu.exists) {
650
- // Add Security submenu to Administration group
651
- context.find(AXPCommonMenuKeys.Administration).addItems([
652
- {
653
- priority: 1,
654
- text: '@security-management:module.menus.root.title',
655
- icon: RootConfig.module.icon,
656
- name: AXPSecurityManagementMenuKeys.Root,
657
- type: 'menu',
658
- children: [],
659
- policy: {
660
- features: [RootConfig.module.name],
661
- },
662
- },
663
- ]);
664
- }
665
- // Add menu items under Security submenu
666
- context.find(AXPSecurityManagementMenuKeys.Root).addItems([
667
- {
668
- priority: 9003,
669
- text: RootConfig.entities.users.titlePlural,
670
- icon: RootConfig.entities.users.icon,
671
- name: AXPSecurityManagementMenuKeys.Users,
672
- path: this.entityService.createPath(moduleName, RootConfig.entities.users.name),
673
- policy: {
674
- features: [moduleName],
675
- permissions: [AXPSecurityManagementPermissionKeys.User.View],
676
- },
677
- },
678
- {
679
- priority: 9004,
680
- text: RootConfig.entities.roles.titlePlural,
681
- path: this.entityService.createPath(moduleName, RootConfig.entities.roles.name),
682
- icon: RootConfig.entities.roles.icon,
683
- name: AXPSecurityManagementMenuKeys.Roles,
684
- policy: {
685
- features: [moduleName],
686
- permissions: [AXPSecurityManagementPermissionKeys.Role.View],
687
- },
688
- },
689
- {
690
- priority: 9005,
691
- text: RootConfig.entities.deviceSessions.titlePlural,
692
- path: this.entityService.createPath(moduleName, RootConfig.entities.deviceSessions.name),
693
- icon: RootConfig.entities.deviceSessions.icon,
694
- name: AXPSecurityManagementMenuKeys.DeviceSessions,
695
- policy: {
696
- features: [moduleName],
697
- permissions: [AXPSecurityManagementPermissionKeys.DeviceSession.View],
698
- },
699
- },
700
- // {
701
- // priority: 9006,
702
- // text: RootConfig.entities.policy.titlePlural,
703
- // path: this.entityService.createPath(moduleName, RootConfig.entities.policy.name),
704
- // icon: RootConfig.entities.policy.icon,
705
- // name: AXPSecurityManagementMenuKeys.Policy,
706
- // policy: {
707
- // permissions: [AXPSecurityManagementPermissionKeys.Policy.View],
708
- // },
709
- // },
710
- ]);
711
- }
712
- }
713
-
714
- //#endregion
715
- //#region ---- Permission Definition Provider ----
716
- class AXMPermissionDefinitionProvider {
717
- //#region ---- Define Method ----
718
- async define(context) {
719
- const keys = AXPSecurityManagementPermissionKeys;
720
- // I18n path constants
721
- const MODULE_PERMISSIONS = '@security-management:module.permissions';
722
- const USERS_PERMISSIONS = '@security-management:users.permissions';
723
- const ROLES_PERMISSIONS = '@security-management:roles.permissions';
724
- const SESSIONS_PERMISSIONS = '@security-management:sessions.permissions';
725
- const POLICIES_PERMISSIONS = '@security-management:policies.permissions';
726
- context
727
- .addGroup(RootConfig.module.name, `${MODULE_PERMISSIONS}.title`, `${MODULE_PERMISSIONS}.description`)
728
- //
729
- .addPermission(keys.User.Management, `${USERS_PERMISSIONS}.manage.title`, `${USERS_PERMISSIONS}.manage.description`)
730
- .addChild(keys.User.View, `${USERS_PERMISSIONS}.view.title`, `${USERS_PERMISSIONS}.view.description`)
731
- .addChild(keys.User.Create, `${USERS_PERMISSIONS}.create.title`, `${USERS_PERMISSIONS}.create.description`)
732
- .addChild(keys.User.Edit, `${USERS_PERMISSIONS}.edit.title`, `${USERS_PERMISSIONS}.edit.description`)
733
- .addChild(keys.User.Delete, `${USERS_PERMISSIONS}.delete.title`, `${USERS_PERMISSIONS}.delete.description`)
734
- .endPermission()
735
- //
736
- .addPermission(keys.Role.Management, `${ROLES_PERMISSIONS}.manage.title`, `${ROLES_PERMISSIONS}.manage.description`)
737
- .addChild(keys.Role.View, `${ROLES_PERMISSIONS}.view.title`, `${ROLES_PERMISSIONS}.view.description`)
738
- .addChild(keys.Role.Create, `${ROLES_PERMISSIONS}.create.title`, `${ROLES_PERMISSIONS}.create.description`)
739
- .addChild(keys.Role.Edit, `${ROLES_PERMISSIONS}.edit.title`, `${ROLES_PERMISSIONS}.edit.description`)
740
- .addChild(keys.Role.Delete, `${ROLES_PERMISSIONS}.delete.title`, `${ROLES_PERMISSIONS}.delete.description`)
741
- .endPermission()
742
- //
743
- .addPermission(keys.DeviceSession.Management, `${SESSIONS_PERMISSIONS}.manage.title`, `${SESSIONS_PERMISSIONS}.manage.description`)
744
- .addChild(keys.DeviceSession.View, `${SESSIONS_PERMISSIONS}.view.title`, `${SESSIONS_PERMISSIONS}.view.description`)
745
- .addChild(keys.DeviceSession.Terminate, `${SESSIONS_PERMISSIONS}.terminate.title`, `${SESSIONS_PERMISSIONS}.terminate.description`)
746
- .endPermission()
747
- //
748
- .addPermission(keys.Policy.Management, `${POLICIES_PERMISSIONS}.manage.title`, `${POLICIES_PERMISSIONS}.manage.description`)
749
- .addChild(keys.Policy.View, `${POLICIES_PERMISSIONS}.view.title`, `${POLICIES_PERMISSIONS}.view.description`)
750
- .addChild(keys.Policy.Create, `${POLICIES_PERMISSIONS}.create.title`, `${POLICIES_PERMISSIONS}.create.description`)
751
- .addChild(keys.Policy.Edit, `${POLICIES_PERMISSIONS}.edit.title`, `${POLICIES_PERMISSIONS}.edit.description`)
752
- .addChild(keys.Policy.Delete, `${POLICIES_PERMISSIONS}.delete.title`, `${POLICIES_PERMISSIONS}.delete.description`)
753
- .endPermission()
754
- //
755
- .endGroup();
756
- }
757
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPermissionDefinitionProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
758
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPermissionDefinitionProvider }); }
759
- }
760
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPermissionDefinitionProvider, decorators: [{
761
- type: Injectable
762
- }] });
763
-
764
- // TODO: Refactor to generic provider (do it later)
765
- //
766
- // Move this logic to a generic AXPEntityCreateSearchCommandProvider in libs/platform/layout/entity.
767
- // The generic provider should:
768
- // - Inject AXPEntityDefinitionRegistryService and AXPSessionService
769
- // - Override search(text) to build commands dynamically from registry
770
- // - Filter entities: only aggregate roots (commands?.create exists AND !parentKey)
771
- // - Filter by permission: sessionService.authorize() for both Create and Management
772
- // Permission convention: `${module}:Permission:${entity.name}.Create` or `.Management`
773
- // - Use createEntityCommandOptions() with Entity:Create command (same pattern as below)
774
- // - Register in entity module as AXP_SEARCH_PROVIDER
775
- // - Remove this and other module-specific search command providers that only add entity-create commands
776
- class AXMSearchCommandProvider extends AXPSearchCommandProvider {
777
- constructor() {
778
- super(...arguments);
779
- this.commands = [
780
- createEntitySearchCommand({
781
- id: 'create-security-user',
782
- entityKey: `${RootConfig.module.name}.${RootConfig.entities.users.name}`,
783
- entityInfo: { name: RootConfig.entities.users.name, module: RootConfig.module.name, title: RootConfig.entities.users.title },
784
- titleKey: '@security-management:users.permissions.create.title',
785
- descriptionKey: '@security-management:users.permissions.create.description',
786
- icon: RootConfig.entities.users.icon,
787
- }),
788
- createEntitySearchCommand({
789
- id: 'create-security-role',
790
- entityKey: `${RootConfig.module.name}.${RootConfig.entities.roles.name}`,
791
- entityInfo: { name: RootConfig.entities.roles.name, module: RootConfig.module.name, title: RootConfig.entities.roles.title },
792
- titleKey: '@security-management:roles.permissions.create.title',
793
- descriptionKey: '@security-management:roles.permissions.create.description',
794
- icon: RootConfig.entities.roles.icon,
795
- }),
796
- ];
797
- }
798
- }
799
-
800
- //#region ---- User context definitions ----
801
- class AXMSecurityManagementContextDefinitionProvider {
802
- async items() {
803
- return [
804
- {
805
- name: 'userId',
806
- title: 'User ID',
807
- description: 'Identifier of the signed-in user from the current session. Used to scope AI actions and audit to the active account.',
808
- ai: {
809
- promptLabel: 'User id',
810
- usageHint: 'Treat as the active user unless the request explicitly refers to another person.',
811
- valueKind: 'string',
812
- order: 10,
813
- },
814
- },
815
- {
816
- name: 'userDisplayName',
817
- title: 'User display name',
818
- description: 'Human-readable name of the signed-in user (name or title from session). Used for personalized responses.',
819
- ai: {
820
- promptLabel: 'User display name',
821
- usageHint: 'Use for polite address; do not invent a different name.',
822
- valueKind: 'string',
823
- order: 11,
824
- },
825
- },
826
- ];
827
- }
828
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMSecurityManagementContextDefinitionProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
829
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMSecurityManagementContextDefinitionProvider }); }
830
- }
831
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMSecurityManagementContextDefinitionProvider, decorators: [{
832
- type: Injectable
833
- }] });
834
-
835
- class AXMSecurityManagementModule {
836
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMSecurityManagementModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
837
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: AXMSecurityManagementModule, imports: [AXMPermissionsModule] }); }
838
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMSecurityManagementModule, providers: [
839
- // Module-specific providers (not part of manifest system)
840
- {
841
- provide: AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER,
842
- useClass: AXMSecurityManagementEvaluatorScopeProvider,
843
- multi: true,
844
- },
845
- // Module Manifest Provider
846
- {
847
- provide: AXP_MODULE_MANIFEST_PROVIDER,
848
- useValue: SecurityManagementManifest,
849
- multi: true,
850
- },
851
- // Provider references (now using tokens)
852
- {
853
- provide: AXP_PERMISSION_DEFINITION_PROVIDER,
854
- useClass: AXMPermissionDefinitionProvider,
855
- multi: true,
856
- },
857
- {
858
- provide: AXP_MENU_PROVIDER,
859
- useClass: AXMMenuProvider,
860
- multi: true,
861
- },
862
- {
863
- provide: AXP_ENTITY_DEFINITION_LOADER,
864
- useClass: AXMEntityProvider,
865
- multi: true,
866
- },
867
- {
868
- provide: AXP_SEARCH_PROVIDER,
869
- useClass: AXMSearchCommandProvider,
870
- multi: true,
871
- },
872
- {
873
- provide: AXP_FEATURE_DEFINITION_PROVIDER,
874
- useClass: AXMSecurityManagementFeatureDefinitionProvider,
875
- multi: true,
876
- },
877
- {
878
- provide: AXP_STATUS_PROVIDERS,
879
- useClass: AXMUserStatusProvider,
880
- multi: true,
881
- },
882
- {
883
- provide: AXP_STATUS_PROVIDERS,
884
- useClass: AXMUserAccessStateProvider,
885
- multi: true,
886
- },
887
- {
888
- provide: AXP_STATUS_PROVIDERS,
889
- useClass: AXMUserEffectiveStateProvider,
890
- multi: true,
891
- },
892
- {
893
- provide: AXP_DATASOURCE_DEFINITION_PROVIDER,
894
- useClass: AXMUsersDataSourceDefinition,
895
- multi: true,
896
- },
897
- {
898
- provide: AXP_CONTEXT_DEFINITION_PROVIDER,
899
- useClass: AXMSecurityManagementContextDefinitionProvider,
900
- multi: true,
901
- },
902
- provideCommandSetups([
903
- {
904
- key: 'Session:Terminate',
905
- command: () => import('./acorex-platform-module-security-management-client-terminate-session.command-CKq-4Z4O.mjs').then((c) => c.AXPTerminateSessionCommand),
906
- },
907
- ]),
908
- ], imports: [AXMPermissionsModule] }); }
909
- }
910
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMSecurityManagementModule, decorators: [{
911
- type: NgModule,
912
- args: [{
913
- imports: [
914
- AXMPermissionsModule,
915
- ],
916
- exports: [],
917
- declarations: [],
918
- providers: [
919
- // Module-specific providers (not part of manifest system)
920
- {
921
- provide: AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER,
922
- useClass: AXMSecurityManagementEvaluatorScopeProvider,
923
- multi: true,
924
- },
925
- // Module Manifest Provider
926
- {
927
- provide: AXP_MODULE_MANIFEST_PROVIDER,
928
- useValue: SecurityManagementManifest,
929
- multi: true,
930
- },
931
- // Provider references (now using tokens)
932
- {
933
- provide: AXP_PERMISSION_DEFINITION_PROVIDER,
934
- useClass: AXMPermissionDefinitionProvider,
935
- multi: true,
936
- },
937
- {
938
- provide: AXP_MENU_PROVIDER,
939
- useClass: AXMMenuProvider,
940
- multi: true,
941
- },
942
- {
943
- provide: AXP_ENTITY_DEFINITION_LOADER,
944
- useClass: AXMEntityProvider,
945
- multi: true,
946
- },
947
- {
948
- provide: AXP_SEARCH_PROVIDER,
949
- useClass: AXMSearchCommandProvider,
950
- multi: true,
951
- },
952
- {
953
- provide: AXP_FEATURE_DEFINITION_PROVIDER,
954
- useClass: AXMSecurityManagementFeatureDefinitionProvider,
955
- multi: true,
956
- },
957
- {
958
- provide: AXP_STATUS_PROVIDERS,
959
- useClass: AXMUserStatusProvider,
960
- multi: true,
961
- },
962
- {
963
- provide: AXP_STATUS_PROVIDERS,
964
- useClass: AXMUserAccessStateProvider,
965
- multi: true,
966
- },
967
- {
968
- provide: AXP_STATUS_PROVIDERS,
969
- useClass: AXMUserEffectiveStateProvider,
970
- multi: true,
971
- },
972
- {
973
- provide: AXP_DATASOURCE_DEFINITION_PROVIDER,
974
- useClass: AXMUsersDataSourceDefinition,
975
- multi: true,
976
- },
977
- {
978
- provide: AXP_CONTEXT_DEFINITION_PROVIDER,
979
- useClass: AXMSecurityManagementContextDefinitionProvider,
980
- multi: true,
981
- },
982
- provideCommandSetups([
983
- {
984
- key: 'Session:Terminate',
985
- command: () => import('./acorex-platform-module-security-management-client-terminate-session.command-CKq-4Z4O.mjs').then((c) => c.AXPTerminateSessionCommand),
986
- },
987
- ]),
988
- ],
989
- }]
990
- }] });
991
-
992
- // #region ---------------- Imports ----------------
993
- // #endregion
994
- class AXPPermissionsEditorComponent extends AXBasePageComponent {
995
- // #endregion
996
- // #region ---------------- Constructor ----------------
997
- constructor() {
998
- super();
999
- // #region ---------------- Class Properties ----------------
1000
- /** Service for fetching permission groups and definitions */
1001
- this.permissionService = inject(AXPPermissionDefinitionService);
1002
- /** Session service for checking module access */
1003
- this.sessionService = inject(AXPSessionService);
1004
- /** Translation service for resolving permission labels during search */
1005
- this.translationService = inject(AXTranslationService);
1006
- /** Currently selected permission group */
1007
- this.selectedGroup = signal(null, ...(ngDevMode ? [{ debugName: "selectedGroup" }] : /* istanbul ignore next */ []));
1008
- /** Current search query */
1009
- this.searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : /* istanbul ignore next */ []));
1010
- /** All available permission groups */
1011
- this.groups = signal([], ...(ngDevMode ? [{ debugName: "groups" }] : /* istanbul ignore next */ []));
1012
- /** Initial permissions to be selected - exposed as signal input */
1013
- this.initialPermissions = input([], ...(ngDevMode ? [{ debugName: "initialPermissions" }] : /* istanbul ignore next */ []));
1014
- /** Whether the editor is in read-only mode */
1015
- this.readOnly = input(false, ...(ngDevMode ? [{ debugName: "readOnly" }] : /* istanbul ignore next */ []));
1016
- /** Whether popup footer actions (Cancel / Select) are shown */
1017
- this.showActions = input(false, ...(ngDevMode ? [{ debugName: "showActions" }] : /* istanbul ignore next */ []));
1018
- /** List of selected permission names */
1019
- this.selectedPermissions = signal([], ...(ngDevMode ? [{ debugName: "selectedPermissions" }] : /* istanbul ignore next */ []));
1020
- /** Event emitted when permissions selection changes */
1021
- this.permissionsChanged = output();
1022
- /** Event emitted when permissions are applied/selected */
1023
- this.permissionsSelected = output();
1024
- /** Whether permission groups are being loaded */
1025
- this.isEditorLoading = signal(true, ...(ngDevMode ? [{ debugName: "isEditorLoading" }] : /* istanbul ignore next */ []));
1026
- /**
1027
- * Computed: Returns mapped permissions for the selected group.
1028
- */
1029
- this.items = computed(() => {
1030
- const permissions = this.selectedGroup()?.permissions || [];
1031
- return this.mapPermissions(permissions);
1032
- }, ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
1033
- /**
1034
- * Computed: Returns groups with badge counts, sorted by title.
1035
- */
1036
- this.groupsWithBadge = computed(() => {
1037
- const groups = this.groups();
1038
- const result = groups.map((group) => {
1039
- return {
1040
- ...group,
1041
- badge: this.getBadge(group) || '',
1042
- };
1043
- });
1044
- return result.sort((a, b) => a.title.localeCompare(b.title));
1045
- }, ...(ngDevMode ? [{ debugName: "groupsWithBadge" }] : /* istanbul ignore next */ []));
1046
- /** Sidebar group placeholders for the loading skeleton */
1047
- this.groupSkeletonPlaceholders = computed(() => [
1048
- 'w-4/5',
1049
- 'w-3/5',
1050
- 'w-4/5',
1051
- 'w-3/5',
1052
- 'w-4/5',
1053
- 'w-3/5',
1054
- 'w-4/5',
1055
- ], ...(ngDevMode ? [{ debugName: "groupSkeletonPlaceholders" }] : /* istanbul ignore next */ []));
1056
- /** Permission group placeholders (parent + child rows) for the loading skeleton */
1057
- this.permissionGroupSkeletonPlaceholders = computed(() => [
1058
- { childCount: 4 },
1059
- { childCount: 4 },
1060
- { childCount: 2 },
1061
- { childCount: 4 },
1062
- ], ...(ngDevMode ? [{ debugName: "permissionGroupSkeletonPlaceholders" }] : /* istanbul ignore next */ []));
1063
- /** Child row placeholders for a permission group skeleton */
1064
- this.childSkeletonPlaceholders = (count) => Array.from({ length: count }, (_, index) => index);
1065
- /** Whether the user is actively searching permissions */
1066
- this.isSearchActive = computed(() => !isEmpty(trim(this.searchQuery())), ...(ngDevMode ? [{ debugName: "isSearchActive" }] : /* istanbul ignore next */ []));
1067
- /** Grouped search results across all permission groups */
1068
- this.searchResultsGrouped = computed(() => {
1069
- const normalizedQuery = trim(this.searchQuery()).toLowerCase();
1070
- if (!normalizedQuery) {
1071
- return [];
1072
- }
1073
- return this.groupsWithBadge()
1074
- .map((group) => ({
1075
- group,
1076
- items: this.mapPermissions(this.getFilteredGroupPermissions(group, normalizedQuery)),
1077
- }))
1078
- .filter((result) => !isEmpty(result.items));
1079
- }, ...(ngDevMode ? [{ debugName: "searchResultsGrouped" }] : /* istanbul ignore next */ []));
1080
- /** Whether the active search returned any permission groups */
1081
- this.hasSearchResults = computed(() => !isEmpty(this.searchResultsGrouped()), ...(ngDevMode ? [{ debugName: "hasSearchResults" }] : /* istanbul ignore next */ []));
1082
- setupPopupFooterKeyboardShortcuts(() => {
1083
- if (!this.isShowActions()) {
1084
- return [];
1085
- }
1086
- return [
1087
- {
1088
- title: '@general:actions.cancel.title',
1089
- command: 'cancel',
1090
- handler: () => this.handleCancelClick(),
1091
- },
1092
- {
1093
- title: '@general:actions.select.title',
1094
- command: 'select',
1095
- handler: () => this.handleSelectClick(),
1096
- },
1097
- ];
1098
- }, { id: 'permissions-editor-popup', when: () => this.isShowActions() });
1099
- }
1100
- // #endregion
1101
- // #region ---------------- Computed Properties ----------------
1102
- /**
1103
- * Reads a signal input or a plain value assigned by AXPopupService data binding.
1104
- */
1105
- readBoundValue(value, fallback) {
1106
- if (typeof value === 'function') {
1107
- return value();
1108
- }
1109
- return (value ?? fallback);
1110
- }
1111
- /** Whether popup footer actions are visible (supports popup data and input binding). */
1112
- isShowActions() {
1113
- return this.readBoundValue(this.showActions, false);
1114
- }
1115
- /** Whether the editor is read-only (supports popup data and input binding). */
1116
- isReadOnlyMode() {
1117
- return this.readBoundValue(this.readOnly, false);
1118
- }
1119
- /** Initial permission selection (supports popup data and input binding). */
1120
- getInitialPermissions() {
1121
- return this.readBoundValue(this.initialPermissions, []);
1122
- }
1123
- /**
1124
- * Recursively maps permissions to include selection state and children.
1125
- */
1126
- mapPermissions(items) {
1127
- return (items || []).map((item) => {
1128
- const children = item.children;
1129
- return {
1130
- ...item,
1131
- isSelected: this.isSelected(item.name),
1132
- children: children?.length ? this.mapPermissions(children) : null,
1133
- };
1134
- });
1135
- }
1136
- // #endregion
1137
- // #region ---------------- Utility Methods ----------------
1138
- /**
1139
- * Extracts module name from a permission group name.
1140
- * Handles multiple formats:
1141
- * - Permission key format: 'SecurityManagement:Permission:SecurityManagement.Management' -> 'SecurityManagement'
1142
- * - PascalCase: 'TenantManagement' -> 'TenantManagement'
1143
- * - kebab-case: 'tenant-management' -> 'TenantManagement' (converts to PascalCase)
1144
- */
1145
- extractModuleNameFromGroupName(groupName) {
1146
- // If it contains ':', extract the first part (permission key format)
1147
- if (groupName.includes(':')) {
1148
- const parts = groupName.split(':');
1149
- return parts[0];
1150
- }
1151
- // If it's kebab-case, convert to PascalCase
1152
- if (groupName.includes('-')) {
1153
- return groupName
1154
- .split('-')
1155
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
1156
- .join('');
1157
- }
1158
- // Otherwise, assume it's already PascalCase
1159
- return groupName;
1160
- }
1161
- /**
1162
- * Filters permission groups to only include those from enabled modules.
1163
- */
1164
- filterGroupsByEnabledModules(groups) {
1165
- return groups.filter((group) => {
1166
- const moduleName = this.extractModuleNameFromGroupName(group.name);
1167
- return this.sessionService.isModuleEnabled(moduleName);
1168
- });
1169
- }
1170
- /**
1171
- * Recursively collects all permission names (parents and children) from an array.
1172
- */
1173
- collectAllPermissionNames(permissions) {
1174
- let names = [];
1175
- for (const item of permissions) {
1176
- names.push(item.name);
1177
- if (item.children?.length) {
1178
- names = names.concat(this.collectAllPermissionNames(item.children));
1179
- }
1180
- }
1181
- return names;
1182
- }
1183
- /**
1184
- * Returns the badge count for a group (all selected permissions, including parents).
1185
- */
1186
- getBadge(group) {
1187
- const allNames = this.collectAllPermissionNames(group.permissions || []);
1188
- const selectedPermissions = this.selectedPermissions();
1189
- const count = allNames.filter((name) => selectedPermissions.includes(name)).length;
1190
- return count.toString();
1191
- }
1192
- /**
1193
- * Checks if a permission is selected.
1194
- */
1195
- isSelected(name) {
1196
- return this.selectedPermissions().includes(name);
1197
- }
1198
- /**
1199
- * Checks if a permission is selected.
1200
- */
1201
- badgeToNumber(value) {
1202
- return Number(value);
1203
- }
1204
- /**
1205
- * Returns true when searchable text contains the query.
1206
- */
1207
- matchesSearchText(text, normalizedQuery) {
1208
- if (!text) {
1209
- return false;
1210
- }
1211
- const translated = this.translationService.translateSync(text) || text;
1212
- return (translated.toLowerCase().includes(normalizedQuery) ||
1213
- text.toLowerCase().includes(normalizedQuery));
1214
- }
1215
- /**
1216
- * Returns true when a permission title or description matches the query.
1217
- */
1218
- matchesPermission(permission, normalizedQuery) {
1219
- return (this.matchesSearchText(permission.title, normalizedQuery) ||
1220
- this.matchesSearchText(permission.description, normalizedQuery));
1221
- }
1222
- /**
1223
- * Returns true when a permission group title or description matches the query.
1224
- */
1225
- matchesGroup(group, normalizedQuery) {
1226
- return (this.matchesSearchText(group.title, normalizedQuery) ||
1227
- this.matchesSearchText(group.description, normalizedQuery));
1228
- }
1229
- /**
1230
- * Filters permissions while keeping ancestor nodes for matching descendants.
1231
- */
1232
- filterPermissions(items, normalizedQuery) {
1233
- const result = [];
1234
- for (const item of items) {
1235
- const filteredChildren = this.filterPermissions(item.children ?? [], normalizedQuery);
1236
- const selfMatches = this.matchesPermission(item, normalizedQuery);
1237
- if (selfMatches || !isEmpty(filteredChildren)) {
1238
- result.push({
1239
- ...item,
1240
- children: filteredChildren,
1241
- });
1242
- }
1243
- }
1244
- return result;
1245
- }
1246
- /**
1247
- * Returns filtered permissions for a group, or all permissions when the group itself matches.
1248
- */
1249
- getFilteredGroupPermissions(group, normalizedQuery) {
1250
- const permissions = group.permissions ?? [];
1251
- if (this.matchesGroup(group, normalizedQuery)) {
1252
- return permissions;
1253
- }
1254
- return this.filterPermissions(permissions, normalizedQuery);
1255
- }
1256
- /**
1257
- * Recursively collects all descendant permission names for a single item (including itself).
1258
- */
1259
- collectPermissionNames(item) {
1260
- let names = [item.name];
1261
- if (item.children) {
1262
- for (const child of item.children) {
1263
- names = names.concat(this.collectPermissionNames(child));
1264
- }
1265
- }
1266
- return names;
1267
- }
1268
- /**
1269
- * Gets the current selected permissions.
1270
- */
1271
- getSelectedPermissions() {
1272
- return this.selectedPermissions();
1273
- }
1274
- /**
1275
- * Sets the selected permissions.
1276
- */
1277
- setSelectedPermissions(permissions) {
1278
- this.selectedPermissions.set(permissions || []);
1279
- this.permissionsChanged.emit(this.selectedPermissions());
1280
- }
1281
- /**
1282
- * Applies/selects the current permissions.
1283
- */
1284
- selectPermissions() {
1285
- this.permissionsSelected.emit(this.selectedPermissions());
1286
- }
1287
- // #endregion
1288
- // #region ---------------- Lifecycle Methods ----------------
1289
- /**
1290
- * Initializes the component and loads permission groups.
1291
- * Filters groups to only show permissions from modules enabled for the current tenant.
1292
- */
1293
- async ngOnInit() {
1294
- super.ngOnInit();
1295
- try {
1296
- const allGroups = await this.permissionService.getGroups();
1297
- const filteredGroups = this.filterGroupsByEnabledModules(allGroups);
1298
- this.groups.set(filteredGroups);
1299
- // Select first group if available
1300
- if (filteredGroups.length > 0) {
1301
- this.selectedGroup.set(filteredGroups[0]);
1302
- }
1303
- this.selectedPermissions.set(this.getInitialPermissions());
1304
- }
1305
- finally {
1306
- this.isEditorLoading.set(false);
1307
- }
1308
- }
1309
- // #endregion
1310
- // #region ---------------- UI Handlers ----------------
1311
- /**
1312
- * Handles group tab/menu item click.
1313
- */
1314
- handleMenuItemClick(item) {
1315
- this.selectedGroup.set(item);
1316
- }
1317
- /**
1318
- * Updates the search query when the search box value changes.
1319
- */
1320
- handleSearchChanged(event) {
1321
- this.searchQuery.set(event.value ?? '');
1322
- }
1323
- /**
1324
- * Handles permission checkbox toggle (checks/unchecks all children recursively).
1325
- */
1326
- onPermissionToggle(item, e) {
1327
- // Don't allow changes in read-only mode
1328
- if (this.isReadOnlyMode()) {
1329
- return;
1330
- }
1331
- const names = this.collectPermissionNames(item);
1332
- if (e.value) {
1333
- // Add all names (parent + children), avoiding duplicates
1334
- const set = new Set([...this.selectedPermissions(), ...names]);
1335
- this.selectedPermissions.set(Array.from(set));
1336
- }
1337
- else {
1338
- // Remove all names (parent + children)
1339
- this.selectedPermissions.set(this.selectedPermissions().filter((name) => !names.includes(name)));
1340
- }
1341
- this.permissionsChanged.emit(this.selectedPermissions());
1342
- }
1343
- /**
1344
- * Closes the popup without applying permission changes.
1345
- */
1346
- handleCancelClick() {
1347
- this.close();
1348
- }
1349
- /**
1350
- * Applies the current selection and closes the popup.
1351
- */
1352
- handleSelectClick() {
1353
- const permissions = this.getSelectedPermissions();
1354
- this.permissionsSelected.emit(permissions);
1355
- this.close(permissions);
1356
- }
1357
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPermissionsEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1358
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPPermissionsEditorComponent, isStandalone: true, selector: "axm-permissions-editor", inputs: { initialPermissions: { classPropertyName: "initialPermissions", publicName: "initialPermissions", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, showActions: { classPropertyName: "showActions", publicName: "showActions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { permissionsChanged: "permissionsChanged", permissionsSelected: "permissionsSelected" }, host: { properties: { "attr.aria-busy": "isEditorLoading() ? \"true\" : null" }, classAttribute: "axm-permissions-editor flex h-full max-h-[75vh] min-h-0 flex-col overflow-hidden" }, usesInheritance: true, ngImport: i0, template: "@if (isEditorLoading()) {\n <div class=\"__body flex min-h-0 flex-1 overflow-hidden\">\n <div class=\"__groups p-4 w-2/5\" aria-hidden=\"true\">\n <div class=\"flex flex-col gap-3 h-full\">\n @for (widthClass of groupSkeletonPlaceholders(); track $index) {\n <div class=\"flex items-center py-2\">\n <div class=\"h-5 rounded-md overflow-hidden\" [class]=\"widthClass\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n </div>\n }\n </div>\n </div>\n\n <div\n class=\"__permissions flex w-3/5 flex-col overflow-hidden border-s\"\n aria-hidden=\"true\"\n >\n <div class=\"__header p-4 border-b border-lightest\">\n <div class=\"h-6 w-48 rounded-md overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n </div>\n\n <div class=\"__content flex flex-col gap-1 p-4\">\n @for (group of permissionGroupSkeletonPlaceholders(); track $index) {\n <div class=\"__skeleton-permission-group\">\n <div class=\"flex items-center gap-2 py-1\">\n <div class=\"h-4 w-4 shrink-0 rounded-sm overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n <div class=\"h-4 w-40 max-w-full rounded-md overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n <div class=\"h-3 w-3 shrink-0 rounded-full overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n </div>\n\n <div class=\"__children p-2 mt-1 ms-1\">\n @for (\n childIndex of childSkeletonPlaceholders(group.childCount);\n track childIndex\n ) {\n <div class=\"flex items-center gap-2 py-1 ps-2\">\n <div class=\"h-4 w-4 shrink-0 rounded-sm overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n <div class=\"h-4 w-32 max-w-full rounded-md overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n <div class=\"h-3 w-3 shrink-0 rounded-full overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n} @else {\n <div class=\"__search px-4 pt-4 pb-3 border-b border-border-lightest\">\n <ax-search-box\n [axAutoFocus]\n [ngModel]=\"searchQuery()\"\n (onValueChanged)=\"handleSearchChanged($event)\"\n [placeholder]=\"\n '@security-management:permissions-feature.components.permissions-editor.search.placeholder'\n | translate\n | async\n \"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n </div>\n\n <div class=\"__body flex min-h-0 flex-1 overflow-hidden\">\n @if (isSearchActive()) {\n <div\n class=\"__permissions __permissions--search flex min-h-0 flex-1 flex-col overflow-hidden\"\n >\n @if (hasSearchResults()) {\n <div class=\"__search-results flex flex-col\">\n @for (result of searchResultsGrouped(); track result.group.name) {\n <section class=\"__search-group\">\n <div\n class=\"__header shrink-0 p-4 border-b border-border-lightest\"\n >\n <span class=\"h6\">{{\n result.group.title | translate | async\n }}</span>\n </div>\n\n <div class=\"__content flex p-4\">\n <ul class=\"__list\">\n <ng-container\n *ngTemplateOutlet=\"\n recursiveList;\n context: { $implicit: result.items }\n \"\n ></ng-container>\n </ul>\n </div>\n </section>\n }\n </div>\n } @else {\n <div class=\"__empty flex flex-1 items-center justify-center p-8\">\n <axp-state-message\n icon=\"fa-light fa-search\"\n [title]=\"\n '@security-management:permissions-feature.components.permissions-editor.empty-states.no-results.title'\n \"\n [description]=\"\n '@security-management:permissions-feature.components.permissions-editor.empty-states.no-results.description'\n \"\n >\n </axp-state-message>\n </div>\n }\n </div>\n } @else {\n <div class=\"__groups w-2/5 p-4\">\n <ax-tabs location=\"start\" look=\"with-line-color\" class=\"h-full\">\n @for (group of groupsWithBadge(); track $index) {\n <ax-tab-item\n [active]=\"group.name === selectedGroup()?.name\"\n [text]=\"(group.title | translate | async)!\"\n (onClick)=\"handleMenuItemClick(group)\"\n >\n @if (badgeToNumber(group.badge) > 0) {\n <ax-suffix>\n <ax-badge color=\"primary\" [text]=\"group.badge\"></ax-badge>\n </ax-suffix>\n }\n </ax-tab-item>\n }\n </ax-tabs>\n </div>\n\n <div class=\"__permissions flex w-3/5 flex-col overflow-hidden border-s\">\n <div class=\"__header shrink-0 p-4 border-b border-border-lightest\">\n <span>{{ selectedGroup()?.title! | translate | async }}</span>\n </div>\n\n <div class=\"__content flex p-4\">\n <ul class=\"__list\">\n <ng-container\n *ngTemplateOutlet=\"recursiveList; context: { $implicit: items() }\"\n ></ng-container>\n </ul>\n </div>\n </div>\n }\n </div>\n}\n\n@if (isShowActions()) {\n <ax-footer>\n <ax-suffix>\n <ax-button\n look=\"solid\"\n [text]=\"'@general:actions.cancel.title' | translate | async\"\n (onClick)=\"handleCancelClick()\"\n ></ax-button>\n <ax-button\n look=\"solid\"\n color=\"primary\"\n [text]=\"'@general:actions.select.title' | translate | async\"\n (onClick)=\"handleSelectClick()\"\n >\n <ax-prefix>\n <i class=\"fa-solid fa-check\"></i>\n </ax-prefix>\n </ax-button>\n </ax-suffix>\n </ax-footer>\n}\n\n<ng-template #recursiveList let-items>\n @for (item of items; track $index) {\n <li class=\"__item py-1 ps-2\">\n <ax-check-box\n [ngModel]=\"item.isSelected\"\n [readonly]=\"isReadOnlyMode()\"\n (onValueChanged)=\"onPermissionToggle(item, $event)\"\n >\n <ax-label>\n {{ item.title | translate | async }}\n @if (item.description) {\n <i\n class=\"ps-2 text-xs fa-light fa-circle-info\"\n [title]=\"(item.description | translate | async) ?? ''\"\n ></i>\n }\n </ax-label>\n </ax-check-box>\n\n @if (item.children && item.children.length > 0) {\n <ul class=\"__children p-2 mt-1 ms-1\">\n <ng-container\n *ngTemplateOutlet=\"\n recursiveList;\n context: { $implicit: item.children }\n \"\n ></ng-container>\n </ul>\n }\n </li>\n }\n</ng-template>\n", styles: ["@layer properties;.axm-permissions-editor{display:flex;height:100%;max-height:75vh;min-height:0;flex-direction:column;overflow:hidden}.axm-permissions-editor .__search{flex-shrink:0}.axm-permissions-editor .__body{display:flex;min-height:0;flex:1;overflow:hidden}.axm-permissions-editor .__groups{min-height:0;overflow-y:auto}.axm-permissions-editor .__groups .__tabs{height:100%}.axm-permissions-editor .__permissions{display:flex;min-height:0;flex-direction:column;overflow:hidden}.axm-permissions-editor .__permissions .__header{flex-shrink:0}.axm-permissions-editor .__permissions .__header .__title{font-size:1rem;font-weight:500;line-height:1rem}.axm-permissions-editor .__permissions .__content{min-height:0;flex:1;overflow-y:auto}.axm-permissions-editor .__permissions .__content .__list{width:100%}.axm-permissions-editor .__permissions .__content .__list .__item .__children{margin-left:calc(var(--spacing, .25rem) * 2);border-left-style:var(--tw-border-style);border-left-width:1px;--tw-border-style: dashed;border-style:dashed;border-color:rgba(var(--ax-sys-color-lighter-surface))}.axm-permissions-editor .__permissions .__permissions--search{width:100%}.axm-permissions-editor .__permissions .__permissions--search .__search-results{min-height:0;width:100%;flex:1;overflow-y:auto}.axm-permissions-editor .__permissions .__permissions--search .__search-group:not(:last-child){border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface))}@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.2 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type:
1359
- // Angular
1360
- CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXCommonModule }, { kind: "directive", type: i3.AXAutoFocusDirective, selector: "[axAutoFocus]", inputs: ["axAutoFocus", "axAutoFocusTime"] }, { kind: "ngmodule", type:
1361
- // ACoreX
1362
- AXFormModule }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i4.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: AXLabelModule }, { kind: "component", type: i5.AXLabelComponent, selector: "ax-label", inputs: ["required", "for"], outputs: ["requiredChange"] }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i6.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "isLoading", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i7.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged"] }, { kind: "component", type: i7.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i8.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i8.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: AXTranslationModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i9.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXTooltipModule }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i10.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i11.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: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "titleParams", "descriptionParams", "look"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i12.AXTranslatorPipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None }); }
1363
- }
1364
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPermissionsEditorComponent, decorators: [{
1365
- type: Component,
1366
- args: [{ selector: 'axm-permissions-editor', imports: [
1367
- // Angular
1368
- CommonModule,
1369
- FormsModule,
1370
- AXCommonModule,
1371
- // ACoreX
1372
- AXFormModule,
1373
- AXTextBoxModule,
1374
- AXButtonModule,
1375
- AXLabelModule,
1376
- AXCheckBoxModule,
1377
- AXTabsModule,
1378
- AXDecoratorModule,
1379
- AXTranslationModule,
1380
- AXBadgeModule,
1381
- AXCheckBoxModule,
1382
- AXTooltipModule,
1383
- AXSkeletonModule,
1384
- AXSearchBoxModule,
1385
- AXPStateMessageComponent,
1386
- ], encapsulation: ViewEncapsulation.None, host: {
1387
- class: 'axm-permissions-editor flex h-full max-h-[75vh] min-h-0 flex-col overflow-hidden',
1388
- '[attr.aria-busy]': 'isEditorLoading() ? "true" : null',
1389
- }, template: "@if (isEditorLoading()) {\n <div class=\"__body flex min-h-0 flex-1 overflow-hidden\">\n <div class=\"__groups p-4 w-2/5\" aria-hidden=\"true\">\n <div class=\"flex flex-col gap-3 h-full\">\n @for (widthClass of groupSkeletonPlaceholders(); track $index) {\n <div class=\"flex items-center py-2\">\n <div class=\"h-5 rounded-md overflow-hidden\" [class]=\"widthClass\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n </div>\n }\n </div>\n </div>\n\n <div\n class=\"__permissions flex w-3/5 flex-col overflow-hidden border-s\"\n aria-hidden=\"true\"\n >\n <div class=\"__header p-4 border-b border-lightest\">\n <div class=\"h-6 w-48 rounded-md overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n </div>\n\n <div class=\"__content flex flex-col gap-1 p-4\">\n @for (group of permissionGroupSkeletonPlaceholders(); track $index) {\n <div class=\"__skeleton-permission-group\">\n <div class=\"flex items-center gap-2 py-1\">\n <div class=\"h-4 w-4 shrink-0 rounded-sm overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n <div class=\"h-4 w-40 max-w-full rounded-md overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n <div class=\"h-3 w-3 shrink-0 rounded-full overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n </div>\n\n <div class=\"__children p-2 mt-1 ms-1\">\n @for (\n childIndex of childSkeletonPlaceholders(group.childCount);\n track childIndex\n ) {\n <div class=\"flex items-center gap-2 py-1 ps-2\">\n <div class=\"h-4 w-4 shrink-0 rounded-sm overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n <div class=\"h-4 w-32 max-w-full rounded-md overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n <div class=\"h-3 w-3 shrink-0 rounded-full overflow-hidden\">\n <ax-skeleton\n [animated]=\"true\"\n style=\"display: block; width: 100%; height: 100%\"\n ></ax-skeleton>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n} @else {\n <div class=\"__search px-4 pt-4 pb-3 border-b border-border-lightest\">\n <ax-search-box\n [axAutoFocus]\n [ngModel]=\"searchQuery()\"\n (onValueChanged)=\"handleSearchChanged($event)\"\n [placeholder]=\"\n '@security-management:permissions-feature.components.permissions-editor.search.placeholder'\n | translate\n | async\n \"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n </div>\n\n <div class=\"__body flex min-h-0 flex-1 overflow-hidden\">\n @if (isSearchActive()) {\n <div\n class=\"__permissions __permissions--search flex min-h-0 flex-1 flex-col overflow-hidden\"\n >\n @if (hasSearchResults()) {\n <div class=\"__search-results flex flex-col\">\n @for (result of searchResultsGrouped(); track result.group.name) {\n <section class=\"__search-group\">\n <div\n class=\"__header shrink-0 p-4 border-b border-border-lightest\"\n >\n <span class=\"h6\">{{\n result.group.title | translate | async\n }}</span>\n </div>\n\n <div class=\"__content flex p-4\">\n <ul class=\"__list\">\n <ng-container\n *ngTemplateOutlet=\"\n recursiveList;\n context: { $implicit: result.items }\n \"\n ></ng-container>\n </ul>\n </div>\n </section>\n }\n </div>\n } @else {\n <div class=\"__empty flex flex-1 items-center justify-center p-8\">\n <axp-state-message\n icon=\"fa-light fa-search\"\n [title]=\"\n '@security-management:permissions-feature.components.permissions-editor.empty-states.no-results.title'\n \"\n [description]=\"\n '@security-management:permissions-feature.components.permissions-editor.empty-states.no-results.description'\n \"\n >\n </axp-state-message>\n </div>\n }\n </div>\n } @else {\n <div class=\"__groups w-2/5 p-4\">\n <ax-tabs location=\"start\" look=\"with-line-color\" class=\"h-full\">\n @for (group of groupsWithBadge(); track $index) {\n <ax-tab-item\n [active]=\"group.name === selectedGroup()?.name\"\n [text]=\"(group.title | translate | async)!\"\n (onClick)=\"handleMenuItemClick(group)\"\n >\n @if (badgeToNumber(group.badge) > 0) {\n <ax-suffix>\n <ax-badge color=\"primary\" [text]=\"group.badge\"></ax-badge>\n </ax-suffix>\n }\n </ax-tab-item>\n }\n </ax-tabs>\n </div>\n\n <div class=\"__permissions flex w-3/5 flex-col overflow-hidden border-s\">\n <div class=\"__header shrink-0 p-4 border-b border-border-lightest\">\n <span>{{ selectedGroup()?.title! | translate | async }}</span>\n </div>\n\n <div class=\"__content flex p-4\">\n <ul class=\"__list\">\n <ng-container\n *ngTemplateOutlet=\"recursiveList; context: { $implicit: items() }\"\n ></ng-container>\n </ul>\n </div>\n </div>\n }\n </div>\n}\n\n@if (isShowActions()) {\n <ax-footer>\n <ax-suffix>\n <ax-button\n look=\"solid\"\n [text]=\"'@general:actions.cancel.title' | translate | async\"\n (onClick)=\"handleCancelClick()\"\n ></ax-button>\n <ax-button\n look=\"solid\"\n color=\"primary\"\n [text]=\"'@general:actions.select.title' | translate | async\"\n (onClick)=\"handleSelectClick()\"\n >\n <ax-prefix>\n <i class=\"fa-solid fa-check\"></i>\n </ax-prefix>\n </ax-button>\n </ax-suffix>\n </ax-footer>\n}\n\n<ng-template #recursiveList let-items>\n @for (item of items; track $index) {\n <li class=\"__item py-1 ps-2\">\n <ax-check-box\n [ngModel]=\"item.isSelected\"\n [readonly]=\"isReadOnlyMode()\"\n (onValueChanged)=\"onPermissionToggle(item, $event)\"\n >\n <ax-label>\n {{ item.title | translate | async }}\n @if (item.description) {\n <i\n class=\"ps-2 text-xs fa-light fa-circle-info\"\n [title]=\"(item.description | translate | async) ?? ''\"\n ></i>\n }\n </ax-label>\n </ax-check-box>\n\n @if (item.children && item.children.length > 0) {\n <ul class=\"__children p-2 mt-1 ms-1\">\n <ng-container\n *ngTemplateOutlet=\"\n recursiveList;\n context: { $implicit: item.children }\n \"\n ></ng-container>\n </ul>\n }\n </li>\n }\n</ng-template>\n", styles: ["@layer properties;.axm-permissions-editor{display:flex;height:100%;max-height:75vh;min-height:0;flex-direction:column;overflow:hidden}.axm-permissions-editor .__search{flex-shrink:0}.axm-permissions-editor .__body{display:flex;min-height:0;flex:1;overflow:hidden}.axm-permissions-editor .__groups{min-height:0;overflow-y:auto}.axm-permissions-editor .__groups .__tabs{height:100%}.axm-permissions-editor .__permissions{display:flex;min-height:0;flex-direction:column;overflow:hidden}.axm-permissions-editor .__permissions .__header{flex-shrink:0}.axm-permissions-editor .__permissions .__header .__title{font-size:1rem;font-weight:500;line-height:1rem}.axm-permissions-editor .__permissions .__content{min-height:0;flex:1;overflow-y:auto}.axm-permissions-editor .__permissions .__content .__list{width:100%}.axm-permissions-editor .__permissions .__content .__list .__item .__children{margin-left:calc(var(--spacing, .25rem) * 2);border-left-style:var(--tw-border-style);border-left-width:1px;--tw-border-style: dashed;border-style:dashed;border-color:rgba(var(--ax-sys-color-lighter-surface))}.axm-permissions-editor .__permissions .__permissions--search{width:100%}.axm-permissions-editor .__permissions .__permissions--search .__search-results{min-height:0;width:100%;flex:1;overflow-y:auto}.axm-permissions-editor .__permissions .__permissions--search .__search-group:not(:last-child){border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface))}@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.2 | MIT License | https://tailwindcss.com */\n"] }]
1390
- }], ctorParameters: () => [], propDecorators: { initialPermissions: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialPermissions", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], showActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showActions", required: false }] }], permissionsChanged: [{ type: i0.Output, args: ["permissionsChanged"] }], permissionsSelected: [{ type: i0.Output, args: ["permissionsSelected"] }] } });
1391
-
1392
- var permissionsEditor_component = /*#__PURE__*/Object.freeze({
1393
- __proto__: null,
1394
- AXPPermissionsEditorComponent: AXPPermissionsEditorComponent
1395
- });
1396
-
1397
- //#endregion
1398
- //#region ---- Command ----
1399
- class AXMAssignPermissionsCommand {
1400
- constructor() {
1401
- //#region ---- Services & Dependencies ----
1402
- this.popupService = inject(AXPopupService);
1403
- this.translationService = inject(AXTranslationService);
1404
- this.entityRegistry = inject(AXPEntityDefinitionRegistryService);
1405
- this.toastService = inject(AXToastService);
1406
- this.settingsService = inject(AXPSettingsService);
1407
- this.workflowEventService = inject(AXPWorkflowEventService);
1408
- }
1409
- //#endregion
1410
- //#region ---- Execute ----
1411
- async execute(input) {
1412
- try {
1413
- const role = input.__context__?.data;
1414
- if (!role || !isString(role['id']) || isEmpty(role['id'])) {
1415
- return {
1416
- success: false,
1417
- message: {
1418
- text: await this.translationService.translateAsync('@general:messages.entity.invalid-data'),
1419
- },
1420
- };
1421
- }
1422
- const component = await Promise.resolve().then(function () { return permissionsEditor_component; }).then((m) => m.AXPPermissionsEditorComponent);
1423
- const editorTitle = await this.translationService.translateAsync('@security-management:permissions-feature.terms.permissions-editor');
1424
- const roleTitle = this.resolveRoleTitle(role['title']);
1425
- const initialPermissions = isArray(role['permissions']) ? role['permissions'] : [];
1426
- const popupResult = await this.popupService.open(component, {
1427
- title: roleTitle ? `${editorTitle} - ${roleTitle}` : editorTitle,
1428
- size: 'md',
1429
- data: {
1430
- initialPermissions,
1431
- showActions: true,
1432
- },
1433
- });
1434
- const permissions = popupResult?.data;
1435
- if (!isArray(permissions)) {
1436
- return { success: true, data: null, metadata: { refresh: false } };
1437
- }
1438
- const entityKey = `${RootConfig.module.name}.${RootConfig.entities.roles.name}`;
1439
- const [moduleName, entityName] = entityKey.split('.');
1440
- const entityRef = await this.entityRegistry.resolve(moduleName, entityName);
1441
- const updatePayload = {
1442
- ...role,
1443
- permissions,
1444
- };
1445
- const updated = await (entityRef.commands?.update?.execute)(updatePayload);
1446
- await this.showSuccessToast();
1447
- this.workflowEventService.dispatch(AXPEntityModifyEvent({ entity: entityKey, values: updated }));
1448
- this.workflowEventService.dispatch(AXPRefreshEvent({ entity: entityKey }));
1449
- return {
1450
- success: true,
1451
- data: permissions,
1452
- };
1453
- }
1454
- catch (error) {
1455
- const message = error instanceof Error ? error.message : 'Failed to assign permissions.';
1456
- return {
1457
- success: false,
1458
- message: { text: message },
1459
- };
1460
- }
1461
- }
1462
- //#endregion
1463
- //#region ---- Utility Methods ----
1464
- resolveRoleTitle(title) {
1465
- if (!title) {
1466
- return '';
1467
- }
1468
- const locale = this.translationService.getActiveLang?.() ?? 'en-US';
1469
- if (isString(title)) {
1470
- return resolveMultiLanguageString(title, locale).trim();
1471
- }
1472
- return resolveMultiLanguageString(String(title), locale).trim();
1473
- }
1474
- async showSuccessToast() {
1475
- const enableOperationToasts = await this.settingsService.get(AXPCommonSettings.EnableOperationToasts);
1476
- if (!enableOperationToasts) {
1477
- return;
1478
- }
1479
- this.toastService.show({
1480
- color: 'success',
1481
- title: await this.translationService.translateAsync('@general:workflow.entity-modified-title'),
1482
- content: await this.translationService.translateAsync('@general:workflow.entity-modified-body'),
1483
- });
1484
- }
1485
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMAssignPermissionsCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1486
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMAssignPermissionsCommand }); }
1487
- }
1488
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMAssignPermissionsCommand, decorators: [{
1489
- type: Injectable
1490
- }] });
1491
-
1492
- var assignPermissions_command = /*#__PURE__*/Object.freeze({
1493
- __proto__: null,
1494
- AXMAssignPermissionsCommand: AXMAssignPermissionsCommand
1495
- });
1496
-
1497
- class AXPPermissionsWidgetViewComponent extends AXPValueWidgetComponent {
1498
- constructor() {
1499
- super(...arguments);
1500
- this.permissionService = inject(AXPPermissionDefinitionService);
1501
- this.commandService = inject(AXPCommandService);
1502
- this.groups = signal([], ...(ngDevMode ? [{ debugName: "groups" }] : /* istanbul ignore next */ []));
1503
- this.loadGroupsEffect = effect(async () => {
1504
- // Load groups when component initializes
1505
- if (this.groups().length === 0) {
1506
- const groupsData = await this.permissionService.getGroups();
1507
- this.groups.set(groupsData);
1508
- }
1509
- }, ...(ngDevMode ? [{ debugName: "loadGroupsEffect" }] : /* istanbul ignore next */ []));
1510
- this.selectedPermissionsByGroup = computed(() => {
1511
- const selected = new Set(this.getValue() ?? []);
1512
- const result = {};
1513
- for (const group of this.groups()) {
1514
- const permPaths = [];
1515
- const findPermissionPaths = (items, path = []) => {
1516
- for (const item of items) {
1517
- const currentPath = [...path, item];
1518
- if (selected.has(item.name)) {
1519
- const displayPath = currentPath.map(p => p.title).join(' > ');
1520
- permPaths.push({
1521
- group,
1522
- path: currentPath,
1523
- displayPath
1524
- });
1525
- }
1526
- if (item.children?.length) {
1527
- findPermissionPaths(item.children, currentPath);
1528
- }
1529
- }
1530
- };
1531
- findPermissionPaths(group.permissions);
1532
- result[group.name] = permPaths;
1533
- }
1534
- return result;
1535
- }, ...(ngDevMode ? [{ debugName: "selectedPermissionsByGroup" }] : /* istanbul ignore next */ []));
1536
- this.isEmpty = computed(() => {
1537
- return Object.values(this.selectedPermissionsByGroup()).every(arr => !arr.length);
1538
- }, ...(ngDevMode ? [{ debugName: "isEmpty" }] : /* istanbul ignore next */ []));
1539
- }
1540
- async openPermissionsEditor() {
1541
- await this.commandService.execute('assign-permissions', {
1542
- __context__: {
1543
- data: this.contextService.data(),
1544
- entity: `${RootConfig.module.name}.${RootConfig.entities.roles.name}`,
1545
- },
1546
- });
1547
- }
1548
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPermissionsWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1549
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPPermissionsWidgetViewComponent, isStandalone: true, selector: "axm-permissions-widget-view", usesInheritance: true, ngImport: i0, template: `
1550
- <!-- <axm-permissions-editor
1551
- [initialPermissions]="getValue() || []"
1552
- [readOnly]="true">
1553
- </axm-permissions-editor> -->
1554
- <div class="flex flex-col gap-2">
1555
- @for (group of groups(); track group.name) {
1556
- @if (selectedPermissionsByGroup()[group.name]?.length) {
1557
- <div>
1558
- <div class="text-xs font-semibold mb-2 text-muted">{{ group.title }}</div>
1559
- <div class="flex gap-1 flex-wrap">
1560
- @for (permPath of selectedPermissionsByGroup()[group.name]; track permPath.path[permPath.path.length - 1].name) {
1561
- <ax-badge [text]="permPath.displayPath" color="primary" size="sm"></ax-badge>
1562
- }
1563
- </div>
1564
- </div>
1565
- }
1566
- }
1567
- @if (isEmpty()) {
1568
- <axp-state-message
1569
- icon="fa-light fa-shield-check"
1570
- [title]="'@security-management:permissions-feature.components.permissions-editor.empty-states.no-permissions.title'"
1571
- [description]="'@security-management:permissions-feature.components.permissions-editor.empty-states.no-permissions.description'">
1572
- </axp-state-message>
1573
- }
1574
- </div>
1575
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i9.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "titleParams", "descriptionParams", "look"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1576
- }
1577
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPermissionsWidgetViewComponent, decorators: [{
1578
- type: Component,
1579
- args: [{
1580
- selector: 'axm-permissions-widget-view',
1581
- template: `
1582
- <!-- <axm-permissions-editor
1583
- [initialPermissions]="getValue() || []"
1584
- [readOnly]="true">
1585
- </axm-permissions-editor> -->
1586
- <div class="flex flex-col gap-2">
1587
- @for (group of groups(); track group.name) {
1588
- @if (selectedPermissionsByGroup()[group.name]?.length) {
1589
- <div>
1590
- <div class="text-xs font-semibold mb-2 text-muted">{{ group.title }}</div>
1591
- <div class="flex gap-1 flex-wrap">
1592
- @for (permPath of selectedPermissionsByGroup()[group.name]; track permPath.path[permPath.path.length - 1].name) {
1593
- <ax-badge [text]="permPath.displayPath" color="primary" size="sm"></ax-badge>
1594
- }
1595
- </div>
1596
- </div>
1597
- }
1598
- }
1599
- @if (isEmpty()) {
1600
- <axp-state-message
1601
- icon="fa-light fa-shield-check"
1602
- [title]="'@security-management:permissions-feature.components.permissions-editor.empty-states.no-permissions.title'"
1603
- [description]="'@security-management:permissions-feature.components.permissions-editor.empty-states.no-permissions.description'">
1604
- </axp-state-message>
1605
- }
1606
- </div>
1607
- `,
1608
- standalone: true,
1609
- changeDetection: ChangeDetectionStrategy.OnPush,
1610
- imports: [AXBadgeModule, AXTranslationModule, AXPStateMessageComponent]
1611
- }]
1612
- }] });
1613
-
1614
- var permissionsWidgetView_component = /*#__PURE__*/Object.freeze({
1615
- __proto__: null,
1616
- AXPPermissionsWidgetViewComponent: AXPPermissionsWidgetViewComponent
1617
- });
1618
-
1619
- class AXPPermissionsWidgetEditComponent extends AXPValueWidgetComponent {
1620
- // #region ---------------- UI Handlers ----------------
1621
- /**
1622
- * Handles permissions changes from the editor.
1623
- */
1624
- onPermissionsChanged(permissions) {
1625
- this.setValue(permissions);
1626
- }
1627
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPermissionsWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1628
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.9", type: AXPPermissionsWidgetEditComponent, isStandalone: true, selector: "axm-permissions-widget-edit", usesInheritance: true, ngImport: i0, template: `
1629
- <axm-permissions-editor
1630
- [initialPermissions]="getValue() || []"
1631
- [readOnly]="false"
1632
- (permissionsChanged)="onPermissionsChanged($event)">
1633
- </axm-permissions-editor>
1634
- `, isInline: true, dependencies: [{ kind: "component", type: AXPPermissionsEditorComponent, selector: "axm-permissions-editor", inputs: ["initialPermissions", "readOnly", "showActions"], outputs: ["permissionsChanged", "permissionsSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1635
- }
1636
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPermissionsWidgetEditComponent, decorators: [{
1637
- type: Component,
1638
- args: [{
1639
- selector: 'axm-permissions-widget-edit',
1640
- template: `
1641
- <axm-permissions-editor
1642
- [initialPermissions]="getValue() || []"
1643
- [readOnly]="false"
1644
- (permissionsChanged)="onPermissionsChanged($event)">
1645
- </axm-permissions-editor>
1646
- `,
1647
- standalone: true,
1648
- changeDetection: ChangeDetectionStrategy.OnPush,
1649
- imports: [
1650
- AXPPermissionsEditorComponent
1651
- ]
1652
- }]
1653
- }] });
1654
-
1655
- var permissionsWidgetEdit_component = /*#__PURE__*/Object.freeze({
1656
- __proto__: null,
1657
- AXPPermissionsWidgetEditComponent: AXPPermissionsWidgetEditComponent
1658
- });
1659
-
1660
- class AXPPermissionsWidgetColumnComponent extends AXPColumnWidgetComponent {
1661
- constructor() {
1662
- super(...arguments);
1663
- this.count = computed(() => castArray(this.rawValue).length, ...(ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []));
1664
- this.commandService = inject(AXPCommandService);
1665
- }
1666
- async openPermissionsEditor() {
1667
- await this.commandService.execute('assign-permissions', {
1668
- __context__: {
1669
- data: this.rowData,
1670
- entity: `${RootConfig.module.name}.${RootConfig.entities.roles.name}`,
1671
- },
1672
- });
1673
- }
1674
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPermissionsWidgetColumnComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1675
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.9", type: AXPPermissionsWidgetColumnComponent, isStandalone: true, selector: "axm-permissions-widget-column", inputs: { rawValue: "rawValue", rowData: "rowData" }, usesInheritance: true, ngImport: i0, template: `
1676
- <span class="cursor-pointer text-primary underline" (click)="openPermissionsEditor()">{{count()}} {{'@security-management:permissions-feature.terms.permissions' | translate | async}}</span>
1677
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i12.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1678
- }
1679
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPermissionsWidgetColumnComponent, decorators: [{
1680
- type: Component,
1681
- args: [{
1682
- selector: 'axm-permissions-widget-column',
1683
- template: `
1684
- <span class="cursor-pointer text-primary underline" (click)="openPermissionsEditor()">{{count()}} {{'@security-management:permissions-feature.terms.permissions' | translate | async}}</span>
1685
- `,
1686
- standalone: true,
1687
- changeDetection: ChangeDetectionStrategy.OnPush,
1688
- imports: [CommonModule, AXTranslationModule],
1689
- inputs: ['rawValue', 'rowData']
1690
- }]
1691
- }] });
1692
-
1693
- var permissionsWidgetColumn_component = /*#__PURE__*/Object.freeze({
1694
- __proto__: null,
1695
- AXPPermissionsWidgetColumnComponent: AXPPermissionsWidgetColumnComponent
1696
- });
1697
-
1698
- // Permission Editor Components
1699
-
1700
- /**
1701
- * Generated bundle index. Do not edit.
1702
- */
1703
-
1704
- export { AXMAssignPermissionsCommand, AXMDeviceSessionsService, AXMPermissionsModule, AXMSecurityManagementModule, AXPPermissionsEditorComponent, AXPPermissionsWidget, AXPPermissionsWidgetColumnComponent, AXPPermissionsWidgetEditComponent, AXPPermissionsWidgetViewComponent };
1
+ export { A as AXMAssignPermissionsCommand, a as AXMDeviceSessionsService, b as AXMPermissionsModule, c as AXMRolePermissionGrantService, d as AXMRolePermissionsPageComponent, e as AXMRolePermissionsPageComponentProvider, f as AXMSecurityManagementModule, g as AXPPermissionsEditorComponent, h as AXPPermissionsWidget, i as AXPPermissionsWidgetColumnComponent, j as AXPPermissionsWidgetEditComponent, k as AXPPermissionsWidgetViewComponent } from './acorex-platform-module-security-management-client-acorex-platform-module-security-management-client-jSDkyMMZ.mjs';
1705
2
  //# sourceMappingURL=acorex-platform-module-security-management-client.mjs.map