@flusys/ng-iam 4.1.1 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -382
- package/fesm2022/{flusys-ng-iam-action-form-page.component-DJbMu2aV.mjs → flusys-ng-iam-action-form-page.component-D_vwcCjG.mjs} +14 -26
- package/fesm2022/flusys-ng-iam-action-form-page.component-D_vwcCjG.mjs.map +1 -0
- package/fesm2022/{flusys-ng-iam-action-list-page.component-DYnYC7Nn.mjs → flusys-ng-iam-action-list-page.component-DRK79zUR.mjs} +4 -4
- package/fesm2022/{flusys-ng-iam-action-list-page.component-DYnYC7Nn.mjs.map → flusys-ng-iam-action-list-page.component-DRK79zUR.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-iam-flusys-ng-iam-CnVOy_4s.mjs → flusys-ng-iam-flusys-ng-iam-C6I4k78L.mjs} +1140 -1340
- package/fesm2022/flusys-ng-iam-flusys-ng-iam-C6I4k78L.mjs.map +1 -0
- package/fesm2022/{flusys-ng-iam-permission-page.component-_cLVilgz.mjs → flusys-ng-iam-permission-page.component-CZebeUhC.mjs} +2 -2
- package/fesm2022/{flusys-ng-iam-permission-page.component-_cLVilgz.mjs.map → flusys-ng-iam-permission-page.component-CZebeUhC.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-iam-role-form-page.component-BuZmko2b.mjs → flusys-ng-iam-role-form-page.component-49dKMKOj.mjs} +11 -20
- package/fesm2022/flusys-ng-iam-role-form-page.component-49dKMKOj.mjs.map +1 -0
- package/fesm2022/{flusys-ng-iam-role-list-page.component-C7GVYYIn.mjs → flusys-ng-iam-role-list-page.component-CT7CvvHj.mjs} +114 -39
- package/fesm2022/flusys-ng-iam-role-list-page.component-CT7CvvHj.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam.mjs +1 -1
- package/package.json +4 -4
- package/types/flusys-ng-iam.d.ts +44 -250
- package/fesm2022/flusys-ng-iam-action-form-page.component-DJbMu2aV.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-flusys-ng-iam-CnVOy_4s.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-role-form-page.component-BuZmko2b.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-role-list-page.component-C7GVYYIn.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,66 +1,9 @@
|
|
|
1
1
|
# @flusys/ng-iam
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Identity and Access Management UI for FLUSYS Angular apps — role management, permission assignment, and reactive permission checking via signals.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@flusys/ng-iam)
|
|
6
|
-
[](https://www.typescriptlang.org)
|
|
8
|
-
[](LICENSE)
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Table of Contents
|
|
13
|
-
|
|
14
|
-
- [Overview](#overview)
|
|
15
|
-
- [Features](#features)
|
|
16
|
-
- [Compatibility](#compatibility)
|
|
17
|
-
- [Installation](#installation)
|
|
18
|
-
- [Quick Start](#quick-start)
|
|
19
|
-
- [Permission Modes](#permission-modes)
|
|
20
|
-
- [RBAC Mode](#rbac-mode)
|
|
21
|
-
- [DIRECT Mode](#direct-mode)
|
|
22
|
-
- [FULL Mode](#full-mode)
|
|
23
|
-
- [Module Registration](#module-registration)
|
|
24
|
-
- [Permission State Service](#permission-state-service)
|
|
25
|
-
- [IAM API Services](#iam-api-services)
|
|
26
|
-
- [Components](#components)
|
|
27
|
-
- [PermissionPageComponent](#permissionpagecomponent)
|
|
28
|
-
- [LogicBuilderComponent](#logicbuildercomponent)
|
|
29
|
-
- [Integration](#integration)
|
|
30
|
-
- [API Endpoints](#api-endpoints)
|
|
31
|
-
- [Troubleshooting](#troubleshooting)
|
|
32
|
-
- [License](#license)
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## Overview
|
|
37
|
-
|
|
38
|
-
`@flusys/ng-iam` provides the complete Identity and Access Management UI for FLUSYS applications. It supports three independent permission modes (RBAC, DIRECT, FULL) and integrates with the backend `nestjs-iam` module.
|
|
39
|
-
|
|
40
|
-
The package uses the Provider Interface Pattern — it never imports from `ng-auth` directly. Instead it injects `USER_PROVIDER` and `COMPANY_PROVIDER` from `ng-shared` to get current user and company context.
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Features
|
|
45
|
-
|
|
46
|
-
- ✅ Three permission modes: RBAC, DIRECT, FULL
|
|
47
|
-
- ✅ `PermissionStateService` — signal-based permission state with 1-hour cache
|
|
48
|
-
- ✅ Role management UI (create, assign users, set permissions)
|
|
49
|
-
- ✅ Direct permission assignment UI (assign permissions directly to users)
|
|
50
|
-
- ✅ `LogicBuilderComponent` — visual AND/OR/nested logic builder for complex permissions
|
|
51
|
-
- ✅ Permission cache auto-invalidation on role/permission change
|
|
52
|
-
- ✅ `provideIamProviders()` — registers permission evaluator with `ng-shared`
|
|
53
|
-
- ✅ Lazy-loaded IAM pages
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## Compatibility
|
|
58
|
-
|
|
59
|
-
| Package | Version |
|
|
60
|
-
|---------|---------|
|
|
61
|
-
| Angular | 21+ |
|
|
62
|
-
| @flusys/ng-core | 4.x |
|
|
63
|
-
| @flusys/ng-shared | 4.x |
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
64
7
|
|
|
65
8
|
---
|
|
66
9
|
|
|
@@ -70,24 +13,7 @@ The package uses the Provider Interface Pattern — it never imports from `ng-au
|
|
|
70
13
|
npm install @flusys/ng-iam @flusys/ng-core @flusys/ng-shared
|
|
71
14
|
```
|
|
72
15
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
## Quick Start
|
|
76
|
-
|
|
77
|
-
### 1. Enable IAM in Config
|
|
78
|
-
|
|
79
|
-
```typescript
|
|
80
|
-
// environments/environment.ts
|
|
81
|
-
export const environment = {
|
|
82
|
-
permissionMode: 'FULL', // 'RBAC' | 'DIRECT' | 'FULL'
|
|
83
|
-
services: {
|
|
84
|
-
auth: { enabled: true },
|
|
85
|
-
iam: { enabled: true },
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### 2. Register IAM Providers
|
|
16
|
+
## 1. Register Providers
|
|
91
17
|
|
|
92
18
|
```typescript
|
|
93
19
|
// app.config.ts
|
|
@@ -95,13 +21,12 @@ import { provideIamProviders } from '@flusys/ng-iam';
|
|
|
95
21
|
|
|
96
22
|
export const appConfig: ApplicationConfig = {
|
|
97
23
|
providers: [
|
|
98
|
-
...provideIamProviders(),
|
|
99
|
-
// Provides: PERMISSION_VALIDATOR (used by HasPermissionDirective, PermissionGuard)
|
|
24
|
+
...provideIamProviders(), // registers PROFILE_PERMISSION_PROVIDER for ng-shared's permission directives/guards
|
|
100
25
|
],
|
|
101
26
|
};
|
|
102
27
|
```
|
|
103
28
|
|
|
104
|
-
|
|
29
|
+
## 2. Add IAM Routes
|
|
105
30
|
|
|
106
31
|
```typescript
|
|
107
32
|
// app.routes.ts
|
|
@@ -115,337 +40,56 @@ export const routes: Routes = [
|
|
|
115
40
|
];
|
|
116
41
|
```
|
|
117
42
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
## Permission Modes
|
|
121
|
-
|
|
122
|
-
### RBAC Mode
|
|
123
|
-
|
|
124
|
-
Role-Based Access Control. Users are assigned roles; roles hold permissions.
|
|
125
|
-
|
|
126
|
-
```
|
|
127
|
-
User ──assigned──► Role ──has──► Permissions
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
**Active controllers:**
|
|
131
|
-
- Role management (create roles, assign permissions to roles)
|
|
132
|
-
- Role assignment (assign roles to users)
|
|
133
|
-
|
|
134
|
-
**Config:**
|
|
135
|
-
```typescript
|
|
136
|
-
{ permissionMode: 'RBAC' }
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### DIRECT Mode
|
|
140
|
-
|
|
141
|
-
Permissions assigned directly to users. No roles.
|
|
142
|
-
|
|
143
|
-
```
|
|
144
|
-
User ──directly assigned──► Permissions
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
**Active controllers:**
|
|
148
|
-
- User permission assignment
|
|
149
|
-
|
|
150
|
-
**Config:**
|
|
151
|
-
```typescript
|
|
152
|
-
{ permissionMode: 'DIRECT' }
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### FULL Mode
|
|
156
|
-
|
|
157
|
-
Both RBAC and DIRECT combined. User gets union of role permissions + direct permissions.
|
|
158
|
-
|
|
159
|
-
```
|
|
160
|
-
User ──assigned──► Role ──has──► Permissions
|
|
161
|
-
└──directly──────────────► Permissions
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
**Config:**
|
|
165
|
-
```typescript
|
|
166
|
-
{ permissionMode: 'FULL' }
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
---
|
|
170
|
-
|
|
171
|
-
## Module Registration
|
|
172
|
-
|
|
173
|
-
### `provideIamProviders()`
|
|
174
|
-
|
|
175
|
-
```typescript
|
|
176
|
-
import { provideIamProviders } from '@flusys/ng-iam';
|
|
177
|
-
|
|
178
|
-
// app.config.ts
|
|
179
|
-
providers: [
|
|
180
|
-
...provideIamProviders(),
|
|
181
|
-
]
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
Registers:
|
|
185
|
-
- `PERMISSION_VALIDATOR` — implementation of `IPermissionValidator` used by `HasPermissionDirective` and `PermissionGuard` from `ng-shared`
|
|
43
|
+
All routes are protected by `permissionGuard` using constants from `ng-shared`.
|
|
186
44
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
## Permission State Service
|
|
45
|
+
## 3. Load Permissions
|
|
190
46
|
|
|
191
|
-
`PermissionStateService`
|
|
47
|
+
Call `PermissionStateService.loadPermissions()` after login (e.g., in `appInitGuard` or after session restore). It fetches the current user's effective permissions from `POST /iam/permissions/my-permissions` and populates `PermissionValidatorService` from `ng-shared`.
|
|
192
48
|
|
|
193
49
|
```typescript
|
|
194
50
|
import { PermissionStateService } from '@flusys/ng-iam';
|
|
195
51
|
|
|
196
52
|
@Component({ ... })
|
|
197
|
-
export class
|
|
198
|
-
private permState = inject(PermissionStateService);
|
|
199
|
-
|
|
200
|
-
// Signals
|
|
201
|
-
permissions = this.permState.permissions; // Signal<string[]>
|
|
202
|
-
isLoaded = this.permState.isLoaded; // Signal<boolean>
|
|
203
|
-
isLoading = this.permState.isLoading; // Signal<boolean>
|
|
53
|
+
export class AppShellComponent {
|
|
54
|
+
private readonly permState = inject(PermissionStateService);
|
|
204
55
|
|
|
205
|
-
//
|
|
206
|
-
|
|
207
|
-
this.permState.hasPermission('product:update')
|
|
208
|
-
);
|
|
56
|
+
readonly permissions = this.permState.permissions; // Signal<IMyPermissionsResponseDto | null>
|
|
57
|
+
readonly isLoading = this.permState.isLoading; // Signal<boolean>
|
|
209
58
|
|
|
210
|
-
|
|
211
|
-
this.permState.
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
// Load permissions (called by appInitGuard after login)
|
|
215
|
-
loadPermissions(): void {
|
|
216
|
-
this.permState.load();
|
|
59
|
+
loadOnInit() {
|
|
60
|
+
this.permState.loadPermissions().subscribe();
|
|
217
61
|
}
|
|
218
62
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
this.permState.invalidate();
|
|
63
|
+
isLoaded() {
|
|
64
|
+
return this.permState.isLoaded(); // true when permissions are set in PermissionValidatorService
|
|
222
65
|
}
|
|
223
66
|
}
|
|
224
67
|
```
|
|
225
68
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
| Member | Type | Description |
|
|
229
|
-
|--------|------|-------------|
|
|
230
|
-
| `permissions` | `Signal<string[]>` | Current user's permission list |
|
|
231
|
-
| `isLoaded` | `Signal<boolean>` | True when permissions are loaded |
|
|
232
|
-
| `isLoading` | `Signal<boolean>` | True when loading is in progress |
|
|
233
|
-
| `hasPermission(key)` | `boolean` | Single permission check |
|
|
234
|
-
| `hasAllPermissions(keys[])` | `boolean` | AND logic — all must match |
|
|
235
|
-
| `hasAnyPermission(keys[])` | `boolean` | OR logic — at least one must match |
|
|
236
|
-
| `load()` | `Observable<void>` | Load permissions from backend |
|
|
237
|
-
| `invalidate()` | `void` | Clear cache and force reload |
|
|
238
|
-
|
|
239
|
-
### Permission Key Format
|
|
240
|
-
|
|
241
|
-
```
|
|
242
|
-
resource:action
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
Examples:
|
|
246
|
-
```
|
|
247
|
-
product:read
|
|
248
|
-
product:create
|
|
249
|
-
product:update
|
|
250
|
-
product:delete
|
|
251
|
-
admin:manage
|
|
252
|
-
user:read
|
|
253
|
-
report:export
|
|
254
|
-
```
|
|
69
|
+
## 4. Check Permissions in Templates
|
|
255
70
|
|
|
256
|
-
|
|
257
|
-
```
|
|
258
|
-
* — all permissions
|
|
259
|
-
product:* — all product actions
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
---
|
|
263
|
-
|
|
264
|
-
## IAM API Services
|
|
265
|
-
|
|
266
|
-
### ActionApiService
|
|
267
|
-
|
|
268
|
-
Manages available permission actions (resource:action pairs):
|
|
269
|
-
|
|
270
|
-
```typescript
|
|
271
|
-
import { ActionApiService } from '@flusys/ng-iam';
|
|
272
|
-
|
|
273
|
-
@Injectable({ ... })
|
|
274
|
-
export class MyService {
|
|
275
|
-
private actionApi = inject(ActionApiService);
|
|
276
|
-
|
|
277
|
-
getActions(): Observable<IListResponse<IAction>> {
|
|
278
|
-
return this.actionApi.getAll({ pageSize: 100 });
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
### RoleApiService
|
|
284
|
-
|
|
285
|
-
Manages roles and their permission assignments:
|
|
286
|
-
|
|
287
|
-
```typescript
|
|
288
|
-
import { RoleApiService } from '@flusys/ng-iam';
|
|
289
|
-
|
|
290
|
-
@Injectable({ ... })
|
|
291
|
-
export class MyService {
|
|
292
|
-
private roleApi = inject(RoleApiService);
|
|
293
|
-
|
|
294
|
-
createRole(name: string, permissions: string[]): Observable<ISingleResponse<IRole>> {
|
|
295
|
-
return this.roleApi.insert({ name, permissions });
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
assignRoleToUser(userId: string, roleId: string): Observable<IMessageResponse> {
|
|
299
|
-
return this.roleApi.assignToUser({ userId, roleId });
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
### UserPermissionApiService
|
|
305
|
-
|
|
306
|
-
Manages direct permission assignments to users:
|
|
307
|
-
|
|
308
|
-
```typescript
|
|
309
|
-
import { UserPermissionApiService } from '@flusys/ng-iam';
|
|
310
|
-
|
|
311
|
-
@Injectable({ ... })
|
|
312
|
-
export class MyService {
|
|
313
|
-
private userPermApi = inject(UserPermissionApiService);
|
|
314
|
-
|
|
315
|
-
assignPermissions(userId: string, permissions: string[]): Observable<IMessageResponse> {
|
|
316
|
-
return this.userPermApi.assign({ userId, permissions });
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
---
|
|
322
|
-
|
|
323
|
-
## Components
|
|
324
|
-
|
|
325
|
-
### PermissionPageComponent
|
|
326
|
-
|
|
327
|
-
Full-page IAM management UI. Renders different panels based on `permissionMode`:
|
|
328
|
-
|
|
329
|
-
| Mode | Panels Shown |
|
|
330
|
-
|------|-------------|
|
|
331
|
-
| `RBAC` | Roles list, Role editor, User-role assignment |
|
|
332
|
-
| `DIRECT` | User permission editor |
|
|
333
|
-
| `FULL` | All RBAC panels + User permission editor |
|
|
334
|
-
|
|
335
|
-
```typescript
|
|
336
|
-
// In routes:
|
|
337
|
-
{
|
|
338
|
-
path: 'iam',
|
|
339
|
-
loadComponent: () =>
|
|
340
|
-
import('@flusys/ng-iam').then(m => m.PermissionPageComponent),
|
|
341
|
-
}
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
### LogicBuilderComponent
|
|
345
|
-
|
|
346
|
-
Visual drag-and-drop AND/OR nested logic builder for complex permission rules.
|
|
347
|
-
|
|
348
|
-
```html
|
|
349
|
-
<flusys-logic-builder
|
|
350
|
-
[availableActions]="actions"
|
|
351
|
-
[(logicTree)]="permissionLogic"
|
|
352
|
-
(logicChange)="onLogicChange($event)"
|
|
353
|
-
/>
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
**Supports:**
|
|
357
|
-
- AND groups (all conditions must match)
|
|
358
|
-
- OR groups (any condition must match)
|
|
359
|
-
- Nesting (AND inside OR, etc.)
|
|
360
|
-
- Individual permission conditions
|
|
361
|
-
- Visual drag-to-reorder
|
|
362
|
-
|
|
363
|
-
---
|
|
364
|
-
|
|
365
|
-
## Integration
|
|
366
|
-
|
|
367
|
-
### With HasPermissionDirective (from ng-shared)
|
|
368
|
-
|
|
369
|
-
Once `provideIamProviders()` is registered, `HasPermissionDirective` works automatically:
|
|
71
|
+
Once `provideIamProviders()` is registered and `loadPermissions()` has been called, permission directives from `ng-shared` work automatically:
|
|
370
72
|
|
|
371
73
|
```html
|
|
372
|
-
|
|
74
|
+
<!-- show element if user has the action code -->
|
|
75
|
+
<button *hasPermission="'product.update'">Edit</button>
|
|
373
76
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
</div>
|
|
77
|
+
<!-- show element if user has any of these action codes -->
|
|
78
|
+
<div *hasPermission="['admin.manage', 'product.delete']">Admin area</div>
|
|
377
79
|
```
|
|
378
80
|
|
|
379
|
-
|
|
81
|
+
Use `permissionGuard` from `ng-shared` to protect routes:
|
|
380
82
|
|
|
381
83
|
```typescript
|
|
84
|
+
import { permissionGuard } from '@flusys/ng-shared';
|
|
85
|
+
|
|
382
86
|
{
|
|
383
87
|
path: 'admin',
|
|
384
|
-
canActivate: [
|
|
385
|
-
data: { permission: 'admin:manage' },
|
|
88
|
+
canActivate: [permissionGuard('admin.manage')],
|
|
386
89
|
loadComponent: () => import('./admin.component'),
|
|
387
90
|
}
|
|
388
91
|
```
|
|
389
92
|
|
|
390
|
-
### With appInitGuard (from ng-auth)
|
|
391
|
-
|
|
392
|
-
`appInitGuard` automatically loads permissions after session restoration when `iam.enabled: true`:
|
|
393
|
-
|
|
394
|
-
```typescript
|
|
395
|
-
// The guard calls PermissionStateService.load() automatically
|
|
396
|
-
// No manual setup needed
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
---
|
|
400
|
-
|
|
401
|
-
## API Endpoints
|
|
402
|
-
|
|
403
|
-
| Method | Endpoint | Description |
|
|
404
|
-
|--------|----------|-------------|
|
|
405
|
-
| POST | `/iam/action/get-all` | List all permission actions |
|
|
406
|
-
| POST | `/iam/action/insert` | Create action |
|
|
407
|
-
| POST | `/iam/action/update` | Update action |
|
|
408
|
-
| POST | `/iam/action/delete` | Delete action |
|
|
409
|
-
| POST | `/iam/role/get-all` | List all roles |
|
|
410
|
-
| POST | `/iam/role/get/:id` | Get role by ID |
|
|
411
|
-
| POST | `/iam/role/insert` | Create role |
|
|
412
|
-
| POST | `/iam/role/update` | Update role |
|
|
413
|
-
| POST | `/iam/role/delete` | Delete role |
|
|
414
|
-
| POST | `/iam/role/assign-user` | Assign role to user |
|
|
415
|
-
| POST | `/iam/role/unassign-user` | Remove role from user |
|
|
416
|
-
| POST | `/iam/user-permission/get/:userId` | Get user's direct permissions |
|
|
417
|
-
| POST | `/iam/user-permission/assign` | Assign direct permissions to user |
|
|
418
|
-
| POST | `/iam/permission/get-my-permissions` | Get current user's effective permissions |
|
|
419
|
-
|
|
420
|
-
---
|
|
421
|
-
|
|
422
|
-
## Troubleshooting
|
|
423
|
-
|
|
424
|
-
**`HasPermissionDirective` always hides content**
|
|
425
|
-
|
|
426
|
-
Permissions aren't loaded. Check that:
|
|
427
|
-
1. `provideIamProviders()` is in `app.config.ts`
|
|
428
|
-
2. `services.iam.enabled: true` in environment
|
|
429
|
-
3. `appInitGuard` runs and calls `PermissionStateService.load()`
|
|
430
|
-
|
|
431
|
-
**Permissions don't refresh after role change**
|
|
432
|
-
|
|
433
|
-
Call `PermissionStateService.invalidate()` after modifying roles/permissions:
|
|
434
|
-
|
|
435
|
-
```typescript
|
|
436
|
-
this.permState.invalidate(); // Clears 1-hour cache, forces reload
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
**`FULL` mode shows RBAC UI but not direct permissions UI**
|
|
440
|
-
|
|
441
|
-
Verify `permissionMode: 'FULL'` in your environment and that `PermissionPageComponent` reads the mode from `APP_CONFIG`.
|
|
442
|
-
|
|
443
|
-
**Permission check for wildcards (`product:*`) not working**
|
|
444
|
-
|
|
445
|
-
Ensure the backend sends flat expanded permissions, not wildcards. The client evaluates exact string matches plus wildcard expansion.
|
|
446
|
-
|
|
447
|
-
---
|
|
448
|
-
|
|
449
93
|
## License
|
|
450
94
|
|
|
451
95
|
MIT © FLUSYS
|
|
@@ -6,8 +6,7 @@ import { ActivatedRoute, Router } from '@angular/router';
|
|
|
6
6
|
import { TRANSLATE_ADAPTER } from '@flusys/ng-core';
|
|
7
7
|
import { AngularModule, PrimeModule, TranslatePipe } from '@flusys/ng-shared';
|
|
8
8
|
import { MessageService } from 'primeng/api';
|
|
9
|
-
import {
|
|
10
|
-
import { A as ActionApiService, a as ActionType, L as LogicBuilderComponent } from './flusys-ng-iam-flusys-ng-iam-CnVOy_4s.mjs';
|
|
9
|
+
import { A as ActionApiService, a as ActionType, L as LogicBuilderComponent } from './flusys-ng-iam-flusys-ng-iam-C6I4k78L.mjs';
|
|
11
10
|
import * as i1 from '@angular/forms';
|
|
12
11
|
import * as i2 from 'primeng/button';
|
|
13
12
|
import * as i3 from 'primeng/checkbox';
|
|
@@ -44,7 +43,6 @@ class ActionFormPageComponent {
|
|
|
44
43
|
parentId: '',
|
|
45
44
|
serial: '',
|
|
46
45
|
isActive: true,
|
|
47
|
-
metadata: null,
|
|
48
46
|
}, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
|
|
49
47
|
actionTypes = computed(() => [
|
|
50
48
|
{ label: this.translate('iam.action.type.backend.label'), value: ActionType.BACKEND },
|
|
@@ -69,10 +67,10 @@ class ActionFormPageComponent {
|
|
|
69
67
|
}
|
|
70
68
|
async initializeForm(id) {
|
|
71
69
|
try {
|
|
72
|
-
const response = await
|
|
70
|
+
const response = await this.actionApi.getAll({
|
|
73
71
|
pagination: { currentPage: 0, pageSize: 10000 },
|
|
74
72
|
select: ['id', 'name', 'code', 'actionType', 'permissionLogic'],
|
|
75
|
-
})
|
|
73
|
+
});
|
|
76
74
|
if (response?.success && response.data) {
|
|
77
75
|
this.allActionsForLogic.set(response.data.map((a) => ({ id: a.id, name: a.name ?? this.translate('shared.unnamed') })));
|
|
78
76
|
this.allActions.set(response.data);
|
|
@@ -88,9 +86,9 @@ class ActionFormPageComponent {
|
|
|
88
86
|
async loadAction(id) {
|
|
89
87
|
this.isLoading.set(true);
|
|
90
88
|
try {
|
|
91
|
-
const response = await this.actionApi.
|
|
89
|
+
const response = await this.actionApi.findById(id, [
|
|
92
90
|
'id', 'name', 'description', 'code', 'actionType',
|
|
93
|
-
'permissionLogic', 'parentId', 'serial', 'isActive',
|
|
91
|
+
'permissionLogic', 'parentId', 'serial', 'isActive',
|
|
94
92
|
]);
|
|
95
93
|
if (response?.success && response.data) {
|
|
96
94
|
const action = response.data;
|
|
@@ -105,7 +103,6 @@ class ActionFormPageComponent {
|
|
|
105
103
|
parentId: action.parentId ?? '',
|
|
106
104
|
serial: action.serial?.toString() ?? '',
|
|
107
105
|
isActive: action.isActive ?? true,
|
|
108
|
-
metadata: action.metadata ?? null,
|
|
109
106
|
});
|
|
110
107
|
}
|
|
111
108
|
else {
|
|
@@ -137,25 +134,16 @@ class ActionFormPageComponent {
|
|
|
137
134
|
code: formValue.code || undefined,
|
|
138
135
|
parentId: formValue.parentId || undefined,
|
|
139
136
|
serial: formValue.serial ? parseInt(formValue.serial, 10) : undefined,
|
|
140
|
-
metadata: formValue.metadata ?? undefined,
|
|
141
137
|
permissionLogic: formValue.permissionLogic ?? undefined,
|
|
142
138
|
};
|
|
143
|
-
|
|
144
|
-
await this.actionApi.
|
|
145
|
-
this.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
await this.actionApi.insertAsync(dto);
|
|
153
|
-
this.messageService.add({
|
|
154
|
-
severity: 'success',
|
|
155
|
-
summary: this.translate('shared.success'),
|
|
156
|
-
detail: this.translate('iam.action.create.success'),
|
|
157
|
-
});
|
|
158
|
-
}
|
|
139
|
+
const response = this.isEditMode()
|
|
140
|
+
? await this.actionApi.update(dto)
|
|
141
|
+
: await this.actionApi.insert(dto);
|
|
142
|
+
this.messageService.add({
|
|
143
|
+
severity: 'success',
|
|
144
|
+
summary: this.translate('shared.success'),
|
|
145
|
+
detail: response.messageKey ? this.translate(response.messageKey, response.messageVariables) : (response.message ?? ''),
|
|
146
|
+
});
|
|
159
147
|
this.router.navigate(['/iam/actions']);
|
|
160
148
|
}
|
|
161
149
|
catch {
|
|
@@ -398,4 +386,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
398
386
|
}], ctorParameters: () => [] });
|
|
399
387
|
|
|
400
388
|
export { ActionFormPageComponent };
|
|
401
|
-
//# sourceMappingURL=flusys-ng-iam-action-form-page.component-
|
|
389
|
+
//# sourceMappingURL=flusys-ng-iam-action-form-page.component-D_vwcCjG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flusys-ng-iam-action-form-page.component-D_vwcCjG.mjs","sources":["../../../projects/ng-iam/pages/action/action-form-page.component.ts"],"sourcesContent":["import { Component, computed, effect, inject, signal } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { form, FormField, required } from '@angular/forms/signals';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { TRANSLATE_ADAPTER } from '@flusys/ng-core';\nimport { AngularModule, ILogicNode, PrimeModule, TranslatePipe } from '@flusys/ng-shared';\nimport { MessageService } from 'primeng/api';\nimport { firstValueFrom } from 'rxjs';\nimport { LogicBuilderComponent } from '../../components/logic-builder.component';\nimport { ActionType, IAction } from '../../interfaces/action.interface';\nimport { ActionApiService } from '../../services/action-api.service';\n\ninterface IActionFormModel {\n id: string;\n name: string;\n description: string;\n code: string;\n actionType: ActionType;\n permissionLogic: ILogicNode | null;\n parentId: string;\n serial: string;\n isActive: boolean;\n}\n\n@Component({\n selector: 'lib-action-form-page',\n imports: [AngularModule, PrimeModule, FormField, LogicBuilderComponent, TranslatePipe],\n template: `\n <div class=\"card\">\n <h3 class=\"text-lg sm:text-xl font-semibold mb-4\">\n {{ isEditMode() ? ('iam.action.edit' | translate) : ('iam.action.new' | translate) }}\n </h3>\n\n <form (ngSubmit)=\"onSubmit()\" class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Name -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"name\" class=\"font-medium\">{{ 'iam.action.name' | translate }} *</label>\n <input\n pInputText\n id=\"name\"\n [formField]=\"actionForm.name\"\n [placeholder]=\"'iam.action.name.placeholder' | translate\" />\n </div>\n\n <!-- Code -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"code\" class=\"font-medium\">{{ 'iam.action.code' | translate }}</label>\n <input\n pInputText\n id=\"code\"\n [formField]=\"actionForm.code\"\n [placeholder]=\"'iam.action.code.placeholder' | translate\" />\n </div>\n\n <!-- Description -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"description\" class=\"font-medium\">{{ 'shared.description' | translate }}</label>\n <input\n pInputText\n id=\"description\"\n [formField]=\"actionForm.description\"\n [placeholder]=\"'shared.description.placeholder' | translate\" />\n </div>\n\n <!-- Action Type -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"actionType\" class=\"font-medium\">{{ 'iam.action.type' | translate }} *</label>\n <select\n id=\"actionType\"\n class=\"p-inputtext w-full\"\n [formField]=\"actionForm.actionType\">\n @for (type of actionTypes(); track type.value) {\n <option [value]=\"type.value\">{{ type.label }}</option>\n }\n </select>\n </div>\n\n <!-- Parent Action -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"parentId\" class=\"font-medium\">{{ 'iam.action.parent' | translate }}</label>\n <select\n id=\"parentId\"\n class=\"p-inputtext w-full\"\n [formField]=\"actionForm.parentId\">\n <option value=\"\">{{ 'iam.action.select.parent' | translate }}</option>\n @for (action of availableActions(); track action.id) {\n <option [value]=\"action.id\">{{ action.name }}</option>\n }\n </select>\n </div>\n\n <!-- Order -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"serial\" class=\"font-medium\">{{ 'shared.display.order' | translate }}</label>\n <input\n pInputText\n id=\"serial\"\n type=\"number\"\n [formField]=\"actionForm.serial\"\n [placeholder]=\"'shared.display.order.placeholder' | translate\" />\n </div>\n\n <!-- Is Active -->\n <div class=\"flex items-end gap-2 pb-1 md:col-span-2\">\n <p-checkbox\n [formField]=\"actionForm.isActive\"\n [binary]=\"true\"\n inputId=\"isActive\" />\n <label for=\"isActive\">{{ 'shared.active' | translate }}</label>\n </div>\n\n <!-- Permission Logic Builder -->\n <div class=\"md:col-span-2\">\n <lib-logic-builder\n [logic]=\"formModel().permissionLogic\"\n [actions]=\"allActionsForLogic()\"\n (logicChange)=\"onLogicChange($event)\" />\n </div>\n\n <!-- Actions -->\n <div class=\"flex justify-end gap-2 md:col-span-2 pt-4\">\n <p-button\n [label]=\"'shared.cancel' | translate\"\n severity=\"secondary\"\n [outlined]=\"true\"\n (onClick)=\"onBack()\" />\n <p-button\n [label]=\"isEditMode() ? ('shared.update' | translate) : ('shared.create' | translate)\"\n type=\"submit\"\n [loading]=\"isLoading()\"\n [disabled]=\"!isFormValid() || isLoading()\" />\n </div>\n </form>\n </div>\n `,\n})\nexport class ActionFormPageComponent {\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n private readonly actionApi = inject(ActionApiService);\n private readonly messageService = inject(MessageService);\n private readonly translateAdapter = inject(TRANSLATE_ADAPTER, { optional: true });\n private readonly routeParams = toSignal(this.route.paramMap);\n private initialized = false;\n\n private translate(key: string, vars?: Record<string, string | number>): string {\n return this.translateAdapter?.translate(key, vars) ?? key;\n }\n\n readonly isLoading = signal(false);\n readonly existingAction = signal<IAction | null>(null);\n readonly isEditMode = computed(() => !!this.existingAction());\n readonly allActionsForLogic = signal<Array<{ id: string; name: string }>>([]);\n readonly allActions = signal<IAction[]>([]);\n\n readonly availableActions = computed(() => {\n const actions = this.allActions();\n const currentId = this.existingAction()?.id;\n return currentId ? actions.filter((a) => a.id !== currentId) : actions;\n });\n\n readonly formModel = signal<IActionFormModel>({\n id: '',\n name: '',\n description: '',\n code: '',\n actionType: ActionType.BACKEND,\n permissionLogic: null,\n parentId: '',\n serial: '',\n isActive: true,\n });\n\n readonly actionTypes = computed(() => [\n { label: this.translate('iam.action.type.backend.label'), value: ActionType.BACKEND },\n { label: this.translate('iam.action.type.frontend.label'), value: ActionType.FRONTEND },\n { label: this.translate('iam.action.type.both.label'), value: ActionType.BOTH },\n ]);\n\n readonly actionForm = form(this.formModel, (f) => {\n required(f.name, { message: this.translate('shared.validation.required', { field: this.translate('iam.action.name') }) });\n });\n\n readonly isFormValid = computed(() => {\n const model = this.formModel();\n return model.name.trim().length > 0;\n });\n\n constructor() {\n effect(() => {\n const params = this.routeParams();\n if (!params || this.initialized) return;\n\n this.initialized = true;\n this.initializeForm(params.get('id'));\n });\n }\n\n private async initializeForm(id: string | null): Promise<void> {\n try {\n const response = await this.actionApi.getAll({\n pagination: { currentPage: 0, pageSize: 10000 },\n select: ['id', 'name', 'code', 'actionType', 'permissionLogic'],\n });\n if (response?.success && response.data) {\n this.allActionsForLogic.set(response.data.map((a) => ({ id: a.id!, name: a.name ?? this.translate('shared.unnamed') })));\n this.allActions.set(response.data);\n }\n } catch {\n // Ignored - form will show empty parent dropdown\n }\n\n if (id && id !== 'new') {\n await this.loadAction(id);\n }\n }\n\n async loadAction(id: string): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.actionApi.findById(id, [\n 'id', 'name', 'description', 'code', 'actionType',\n 'permissionLogic', 'parentId', 'serial', 'isActive',\n ]);\n\n if (response?.success && response.data) {\n const action = response.data;\n this.existingAction.set(action);\n this.formModel.set({\n id: action.id ?? '',\n name: action.name ?? '',\n description: action.description ?? '',\n code: action.code ?? '',\n actionType: action.actionType ?? ActionType.BACKEND,\n permissionLogic: action.permissionLogic ?? null,\n parentId: action.parentId ?? '',\n serial: action.serial?.toString() ?? '',\n isActive: action.isActive ?? true,\n });\n } else {\n this.router.navigate(['/iam/actions']);\n }\n } catch {\n this.router.navigate(['/iam/actions']);\n } finally {\n this.isLoading.set(false);\n }\n }\n\n async onSubmit(): Promise<void> {\n if (!this.isFormValid()) {\n this.messageService.add({\n severity: 'error',\n summary: this.translate('shared.validation.error'),\n detail: this.translate('shared.fill.required.fields'),\n });\n return;\n }\n\n this.isLoading.set(true);\n\n try {\n const formValue = this.formModel();\n const dto = {\n ...formValue,\n description: formValue.description || undefined,\n code: formValue.code || undefined,\n parentId: formValue.parentId || undefined,\n serial: formValue.serial ? parseInt(formValue.serial, 10) : undefined,\n permissionLogic: formValue.permissionLogic ?? undefined,\n };\n\n const response = this.isEditMode()\n ? await this.actionApi.update(dto)\n : await this.actionApi.insert(dto);\n\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: response.messageKey ? this.translate(response.messageKey, response.messageVariables as Record<string, string | number>) : (response.message ?? ''),\n });\n\n this.router.navigate(['/iam/actions']);\n } catch {\n // Handled by global interceptor\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onBack(): void {\n this.router.navigate(['/iam/actions']);\n }\n\n onLogicChange(logic: ILogicNode | null): void {\n this.formModel.update((model) => ({ ...model, permissionLogic: logic }));\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ import { MessageService, ConfirmationService } from 'primeng/api';
|
|
|
8
8
|
import * as i5 from 'primeng/tag';
|
|
9
9
|
import { TagModule } from 'primeng/tag';
|
|
10
10
|
import { firstValueFrom } from 'rxjs';
|
|
11
|
-
import { A as ActionApiService, a as ActionType, c as convertActionToTreeNode } from './flusys-ng-iam-flusys-ng-iam-
|
|
11
|
+
import { A as ActionApiService, a as ActionType, c as convertActionToTreeNode } from './flusys-ng-iam-flusys-ng-iam-C6I4k78L.mjs';
|
|
12
12
|
import * as i2 from 'primeng/button';
|
|
13
13
|
import * as i6 from 'primeng/tooltip';
|
|
14
14
|
import * as i7 from 'primeng/treetable';
|
|
@@ -77,12 +77,12 @@ class ActionListPageComponent {
|
|
|
77
77
|
icon: 'pi pi-exclamation-triangle',
|
|
78
78
|
accept: async () => {
|
|
79
79
|
try {
|
|
80
|
-
await this.actionApi.
|
|
80
|
+
const response = await this.actionApi.delete({ id: action.id, type: 'delete' });
|
|
81
81
|
await this.loadActions();
|
|
82
82
|
this.messageService.add({
|
|
83
83
|
severity: 'success',
|
|
84
84
|
summary: this.translate('shared.success'),
|
|
85
|
-
detail: this.translate(
|
|
85
|
+
detail: response?.messageKey ? this.translate(response.messageKey, response.messageVariables) : (response?.message ?? ''),
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
88
|
catch {
|
|
@@ -268,4 +268,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
268
268
|
}], ctorParameters: () => [] });
|
|
269
269
|
|
|
270
270
|
export { ActionListPageComponent };
|
|
271
|
-
//# sourceMappingURL=flusys-ng-iam-action-list-page.component-
|
|
271
|
+
//# sourceMappingURL=flusys-ng-iam-action-list-page.component-DRK79zUR.mjs.map
|