@flusys/ng-iam 0.1.0-beta.3 → 1.0.0-rc

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 (28) hide show
  1. package/README.md +225 -25
  2. package/fesm2022/{flusys-ng-iam-action-form-page.component-BVWZMlLU.mjs → flusys-ng-iam-action-form-page.component-C_BRrrWW.mjs} +181 -210
  3. package/fesm2022/flusys-ng-iam-action-form-page.component-C_BRrrWW.mjs.map +1 -0
  4. package/fesm2022/flusys-ng-iam-action-list-page.component-Daf93zpS.mjs +289 -0
  5. package/fesm2022/flusys-ng-iam-action-list-page.component-Daf93zpS.mjs.map +1 -0
  6. package/fesm2022/{flusys-ng-iam-flusys-ng-iam-D_i24Gub.mjs → flusys-ng-iam-flusys-ng-iam-BPIpfrjN.mjs} +967 -1087
  7. package/fesm2022/flusys-ng-iam-flusys-ng-iam-BPIpfrjN.mjs.map +1 -0
  8. package/fesm2022/flusys-ng-iam-iam-container.component-Bn4kQtxW.mjs +92 -0
  9. package/fesm2022/flusys-ng-iam-iam-container.component-Bn4kQtxW.mjs.map +1 -0
  10. package/fesm2022/{flusys-ng-iam-permission-page.component-C0yLMdW5.mjs → flusys-ng-iam-permission-page.component-CmxOBJPu.mjs} +45 -16
  11. package/fesm2022/flusys-ng-iam-permission-page.component-CmxOBJPu.mjs.map +1 -0
  12. package/fesm2022/{flusys-ng-iam-role-form-page.component-Co6bbHik.mjs → flusys-ng-iam-role-form-page.component-ByNueI1a.mjs} +110 -138
  13. package/fesm2022/flusys-ng-iam-role-form-page.component-ByNueI1a.mjs.map +1 -0
  14. package/fesm2022/flusys-ng-iam-role-list-page.component-CFly5KnH.mjs +316 -0
  15. package/fesm2022/flusys-ng-iam-role-list-page.component-CFly5KnH.mjs.map +1 -0
  16. package/fesm2022/flusys-ng-iam.mjs +1 -1
  17. package/package.json +5 -5
  18. package/types/flusys-ng-iam.d.ts +89 -37
  19. package/fesm2022/flusys-ng-iam-action-form-page.component-BVWZMlLU.mjs.map +0 -1
  20. package/fesm2022/flusys-ng-iam-action-list-page.component-CCp7M7xo.mjs +0 -282
  21. package/fesm2022/flusys-ng-iam-action-list-page.component-CCp7M7xo.mjs.map +0 -1
  22. package/fesm2022/flusys-ng-iam-flusys-ng-iam-D_i24Gub.mjs.map +0 -1
  23. package/fesm2022/flusys-ng-iam-iam-container.component-BFKoNtdz.mjs +0 -97
  24. package/fesm2022/flusys-ng-iam-iam-container.component-BFKoNtdz.mjs.map +0 -1
  25. package/fesm2022/flusys-ng-iam-permission-page.component-C0yLMdW5.mjs.map +0 -1
  26. package/fesm2022/flusys-ng-iam-role-form-page.component-Co6bbHik.mjs.map +0 -1
  27. package/fesm2022/flusys-ng-iam-role-list-page.component-KJUVOrf0.mjs +0 -267
  28. package/fesm2022/flusys-ng-iam-role-list-page.component-KJUVOrf0.mjs.map +0 -1
@@ -1,14 +1,16 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
2
+ import { inject, signal, computed, effect, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { toSignal } from '@angular/core/rxjs-interop';
3
4
  import { form, required, FormField } from '@angular/forms/signals';
4
5
  import { ActivatedRoute, Router } from '@angular/router';
5
6
  import { AngularModule, PrimeModule } from '@flusys/ng-shared';
6
7
  import { MessageService } from 'primeng/api';
7
8
  import { firstValueFrom } from 'rxjs';
8
- import { A as ActionApiService, a as ActionType, L as LogicBuilderComponent } from './flusys-ng-iam-flusys-ng-iam-D_i24Gub.mjs';
9
+ import { A as ActionApiService, a as ActionType, L as LogicBuilderComponent } from './flusys-ng-iam-flusys-ng-iam-BPIpfrjN.mjs';
9
10
  import * as i1 from '@angular/forms';
10
- import * as i2 from 'primeng/inputtext';
11
- import * as i3 from 'primeng/button';
11
+ import * as i2 from 'primeng/button';
12
+ import * as i3 from 'primeng/checkbox';
13
+ import * as i4 from 'primeng/inputtext';
12
14
 
13
15
  /**
14
16
  * Action Form Page Component
@@ -19,6 +21,8 @@ class ActionFormPageComponent {
19
21
  router = inject(Router);
20
22
  actionApi = inject(ActionApiService);
21
23
  messageService = inject(MessageService);
24
+ routeParams = toSignal(this.route.paramMap);
25
+ initialized = false;
22
26
  /** Loading state */
23
27
  isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
24
28
  /** Existing action data when editing */
@@ -66,8 +70,16 @@ class ActionFormPageComponent {
66
70
  const model = this.formModel();
67
71
  return model.name.trim().length > 0;
68
72
  }, ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
69
- async ngOnInit() {
70
- const id = this.route.snapshot.paramMap.get('id');
73
+ constructor() {
74
+ effect(() => {
75
+ const params = this.routeParams();
76
+ if (!params || this.initialized)
77
+ return;
78
+ this.initialized = true;
79
+ this.initializeForm(params.get('id'));
80
+ });
81
+ }
82
+ async initializeForm(id) {
71
83
  // Load ALL actions FIRST - critical for LogicBuilder to display action names
72
84
  try {
73
85
  const response = await firstValueFrom(this.actionApi.getAll('', {
@@ -81,8 +93,8 @@ class ActionFormPageComponent {
81
93
  this.allActions.set(response.data);
82
94
  }
83
95
  }
84
- catch (error) {
85
- console.error('[ActionFormPage] Failed to load actions:', error);
96
+ catch {
97
+ // Actions load failed - form will show empty parent dropdown
86
98
  }
87
99
  // THEN load the specific action (ensures actions are loaded before setting permissionLogic)
88
100
  if (id && id !== 'new') {
@@ -124,21 +136,12 @@ class ActionFormPageComponent {
124
136
  });
125
137
  }
126
138
  else {
127
- this.messageService.add({
128
- severity: 'error',
129
- summary: 'Error',
130
- detail: 'Action not found.',
131
- });
139
+ // Error toast handled by global interceptor
132
140
  this.router.navigate(['/iam/actions']);
133
141
  }
134
142
  }
135
- catch (error) {
136
- console.error('[ActionFormPage] Failed to load action:', error);
137
- this.messageService.add({
138
- severity: 'error',
139
- summary: 'Error',
140
- detail: 'Failed to load action.',
141
- });
143
+ catch {
144
+ // Error toast handled by global interceptor
142
145
  this.router.navigate(['/iam/actions']);
143
146
  }
144
147
  finally {
@@ -185,12 +188,8 @@ class ActionFormPageComponent {
185
188
  }
186
189
  this.router.navigate(['/iam/actions']);
187
190
  }
188
- catch (error) {
189
- this.messageService.add({
190
- severity: 'error',
191
- summary: 'Error',
192
- detail: error.message || 'Failed to save action.',
193
- });
191
+ catch {
192
+ // Error toast handled by global interceptor
194
193
  }
195
194
  finally {
196
195
  this.isLoading.set(false);
@@ -208,107 +207,93 @@ class ActionFormPageComponent {
208
207
  permissionLogic: logic
209
208
  }));
210
209
  }
211
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ActionFormPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
212
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: ActionFormPageComponent, isStandalone: true, selector: "lib-action-form-page", ngImport: i0, template: `
210
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ActionFormPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
211
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ActionFormPageComponent, isStandalone: true, selector: "lib-action-form-page", ngImport: i0, template: `
213
212
  <div class="card">
214
- <div class="flex justify-between items-center mb-4">
215
- <h3 class="text-xl font-semibold">
216
- {{ isEditMode() ? 'Edit Action' : 'New Action' }}
217
- </h3>
218
- <p-button
219
- label="Back"
220
- icon="pi pi-arrow-left"
221
- [outlined]="true"
222
- (onClick)="onBack()" />
223
- </div>
213
+ <h3 class="text-lg sm:text-xl font-semibold mb-4">
214
+ {{ isEditMode() ? 'Edit Action' : 'New Action' }}
215
+ </h3>
224
216
 
225
- <form (ngSubmit)="onSubmit()">
226
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
227
- <!-- Name -->
228
- <div>
229
- <label for="name" class="block font-medium mb-2">Name *</label>
230
- <input
231
- pInputText
232
- id="name"
233
- [formField]="actionForm.name"
234
- class="w-full"
235
- placeholder="Enter action name" />
236
- </div>
217
+ <form (ngSubmit)="onSubmit()" class="grid grid-cols-1 md:grid-cols-2 gap-4">
218
+ <!-- Name -->
219
+ <div class="flex flex-col gap-2">
220
+ <label for="name" class="font-medium">Name *</label>
221
+ <input
222
+ pInputText
223
+ id="name"
224
+ [formField]="actionForm.name"
225
+ placeholder="Enter action name" />
226
+ </div>
237
227
 
238
- <!-- Code -->
239
- <div>
240
- <label for="code" class="block font-medium mb-2">Code</label>
241
- <input
242
- pInputText
243
- id="code"
244
- [formField]="actionForm.code"
245
- class="w-full"
246
- placeholder="Enter action code" />
247
- </div>
228
+ <!-- Code -->
229
+ <div class="flex flex-col gap-2">
230
+ <label for="code" class="font-medium">Code</label>
231
+ <input
232
+ pInputText
233
+ id="code"
234
+ [formField]="actionForm.code"
235
+ placeholder="Enter action code" />
236
+ </div>
248
237
 
249
- <!-- Description -->
250
- <div class="md:col-span-2">
251
- <label for="description" class="block font-medium mb-2">Description</label>
252
- <input
253
- pInputText
254
- id="description"
255
- [formField]="actionForm.description"
256
- class="w-full"
257
- placeholder="Enter description" />
258
- </div>
238
+ <!-- Description -->
239
+ <div class="flex flex-col gap-2">
240
+ <label for="description" class="font-medium">Description</label>
241
+ <input
242
+ pInputText
243
+ id="description"
244
+ [formField]="actionForm.description"
245
+ placeholder="Enter description" />
246
+ </div>
259
247
 
260
- <!-- Action Type -->
261
- <div>
262
- <label for="actionType" class="block font-medium mb-2">Action Type *</label>
263
- <select
264
- id="actionType"
265
- class="p-select-native"
266
- [formField]="actionForm.actionType">
267
- @for (type of actionTypes; track type.value) {
268
- <option [value]="type.value">{{ type.label }}</option>
269
- }
270
- </select>
271
- </div>
248
+ <!-- Action Type -->
249
+ <div class="flex flex-col gap-2">
250
+ <label for="actionType" class="font-medium">Action Type *</label>
251
+ <select
252
+ id="actionType"
253
+ class="p-inputtext w-full"
254
+ [formField]="actionForm.actionType">
255
+ @for (type of actionTypes; track type.value) {
256
+ <option [value]="type.value">{{ type.label }}</option>
257
+ }
258
+ </select>
259
+ </div>
272
260
 
273
- <!-- Parent Action -->
274
- <div>
275
- <label for="parentId" class="block font-medium mb-2">Parent Action</label>
276
- <select
277
- id="parentId"
278
- class="p-select-native"
279
- [formField]="actionForm.parentId">
280
- <option value="">Select parent action</option>
281
- @for (action of availableActions(); track action.id) {
282
- <option [value]="action.id">{{ action.name }}</option>
283
- }
284
- </select>
285
- </div>
261
+ <!-- Parent Action -->
262
+ <div class="flex flex-col gap-2">
263
+ <label for="parentId" class="font-medium">Parent Action</label>
264
+ <select
265
+ id="parentId"
266
+ class="p-inputtext w-full"
267
+ [formField]="actionForm.parentId">
268
+ <option value="">Select parent action</option>
269
+ @for (action of availableActions(); track action.id) {
270
+ <option [value]="action.id">{{ action.name }}</option>
271
+ }
272
+ </select>
273
+ </div>
286
274
 
287
- <!-- Order -->
288
- <div>
289
- <label for="serial" class="block font-medium mb-2">Display Order</label>
290
- <input
291
- pInputText
292
- id="serial"
293
- type="number"
294
- [formField]="actionForm.serial"
295
- class="w-full"
296
- placeholder="Enter display order" />
297
- </div>
275
+ <!-- Order -->
276
+ <div class="flex flex-col gap-2">
277
+ <label for="serial" class="font-medium">Display Order</label>
278
+ <input
279
+ pInputText
280
+ id="serial"
281
+ type="number"
282
+ [formField]="actionForm.serial"
283
+ placeholder="Enter display order" />
284
+ </div>
298
285
 
299
- <!-- Is Active -->
300
- <div class="flex items-center pt-6">
301
- <label class="p-checkbox-native">
302
- <input
303
- type="checkbox"
304
- [formField]="actionForm.isActive" />
305
- <span>Active</span>
306
- </label>
307
- </div>
286
+ <!-- Is Active -->
287
+ <div class="flex items-end gap-2 pb-1 md:col-span-2">
288
+ <p-checkbox
289
+ [formField]="actionForm.isActive"
290
+ [binary]="true"
291
+ inputId="isActive" />
292
+ <label for="isActive">Active</label>
308
293
  </div>
309
294
 
310
295
  <!-- Permission Logic Builder -->
311
- <div class="mt-6">
296
+ <div class="md:col-span-2">
312
297
  <lib-logic-builder
313
298
  [logic]="formModel().permissionLogic"
314
299
  [actions]="allActionsForLogic()"
@@ -316,7 +301,7 @@ class ActionFormPageComponent {
316
301
  </div>
317
302
 
318
303
  <!-- Actions -->
319
- <div class="flex justify-end gap-2 mt-6">
304
+ <div class="flex justify-end gap-2 md:col-span-2 pt-4">
320
305
  <p-button
321
306
  label="Cancel"
322
307
  severity="secondary"
@@ -330,9 +315,9 @@ class ActionFormPageComponent {
330
315
  </div>
331
316
  </form>
332
317
  </div>
333
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i3.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: LogicBuilderComponent, selector: "lib-logic-builder", inputs: ["logic", "actions"], outputs: ["logicChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
318
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: LogicBuilderComponent, selector: "lib-logic-builder", inputs: ["logic", "actions"], outputs: ["logicChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
334
319
  }
335
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ActionFormPageComponent, decorators: [{
320
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ActionFormPageComponent, decorators: [{
336
321
  type: Component,
337
322
  args: [{
338
323
  selector: 'lib-action-form-page',
@@ -341,104 +326,90 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
341
326
  changeDetection: ChangeDetectionStrategy.OnPush,
342
327
  template: `
343
328
  <div class="card">
344
- <div class="flex justify-between items-center mb-4">
345
- <h3 class="text-xl font-semibold">
346
- {{ isEditMode() ? 'Edit Action' : 'New Action' }}
347
- </h3>
348
- <p-button
349
- label="Back"
350
- icon="pi pi-arrow-left"
351
- [outlined]="true"
352
- (onClick)="onBack()" />
353
- </div>
329
+ <h3 class="text-lg sm:text-xl font-semibold mb-4">
330
+ {{ isEditMode() ? 'Edit Action' : 'New Action' }}
331
+ </h3>
354
332
 
355
- <form (ngSubmit)="onSubmit()">
356
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
357
- <!-- Name -->
358
- <div>
359
- <label for="name" class="block font-medium mb-2">Name *</label>
360
- <input
361
- pInputText
362
- id="name"
363
- [formField]="actionForm.name"
364
- class="w-full"
365
- placeholder="Enter action name" />
366
- </div>
333
+ <form (ngSubmit)="onSubmit()" class="grid grid-cols-1 md:grid-cols-2 gap-4">
334
+ <!-- Name -->
335
+ <div class="flex flex-col gap-2">
336
+ <label for="name" class="font-medium">Name *</label>
337
+ <input
338
+ pInputText
339
+ id="name"
340
+ [formField]="actionForm.name"
341
+ placeholder="Enter action name" />
342
+ </div>
367
343
 
368
- <!-- Code -->
369
- <div>
370
- <label for="code" class="block font-medium mb-2">Code</label>
371
- <input
372
- pInputText
373
- id="code"
374
- [formField]="actionForm.code"
375
- class="w-full"
376
- placeholder="Enter action code" />
377
- </div>
344
+ <!-- Code -->
345
+ <div class="flex flex-col gap-2">
346
+ <label for="code" class="font-medium">Code</label>
347
+ <input
348
+ pInputText
349
+ id="code"
350
+ [formField]="actionForm.code"
351
+ placeholder="Enter action code" />
352
+ </div>
378
353
 
379
- <!-- Description -->
380
- <div class="md:col-span-2">
381
- <label for="description" class="block font-medium mb-2">Description</label>
382
- <input
383
- pInputText
384
- id="description"
385
- [formField]="actionForm.description"
386
- class="w-full"
387
- placeholder="Enter description" />
388
- </div>
354
+ <!-- Description -->
355
+ <div class="flex flex-col gap-2">
356
+ <label for="description" class="font-medium">Description</label>
357
+ <input
358
+ pInputText
359
+ id="description"
360
+ [formField]="actionForm.description"
361
+ placeholder="Enter description" />
362
+ </div>
389
363
 
390
- <!-- Action Type -->
391
- <div>
392
- <label for="actionType" class="block font-medium mb-2">Action Type *</label>
393
- <select
394
- id="actionType"
395
- class="p-select-native"
396
- [formField]="actionForm.actionType">
397
- @for (type of actionTypes; track type.value) {
398
- <option [value]="type.value">{{ type.label }}</option>
399
- }
400
- </select>
401
- </div>
364
+ <!-- Action Type -->
365
+ <div class="flex flex-col gap-2">
366
+ <label for="actionType" class="font-medium">Action Type *</label>
367
+ <select
368
+ id="actionType"
369
+ class="p-inputtext w-full"
370
+ [formField]="actionForm.actionType">
371
+ @for (type of actionTypes; track type.value) {
372
+ <option [value]="type.value">{{ type.label }}</option>
373
+ }
374
+ </select>
375
+ </div>
402
376
 
403
- <!-- Parent Action -->
404
- <div>
405
- <label for="parentId" class="block font-medium mb-2">Parent Action</label>
406
- <select
407
- id="parentId"
408
- class="p-select-native"
409
- [formField]="actionForm.parentId">
410
- <option value="">Select parent action</option>
411
- @for (action of availableActions(); track action.id) {
412
- <option [value]="action.id">{{ action.name }}</option>
413
- }
414
- </select>
415
- </div>
377
+ <!-- Parent Action -->
378
+ <div class="flex flex-col gap-2">
379
+ <label for="parentId" class="font-medium">Parent Action</label>
380
+ <select
381
+ id="parentId"
382
+ class="p-inputtext w-full"
383
+ [formField]="actionForm.parentId">
384
+ <option value="">Select parent action</option>
385
+ @for (action of availableActions(); track action.id) {
386
+ <option [value]="action.id">{{ action.name }}</option>
387
+ }
388
+ </select>
389
+ </div>
416
390
 
417
- <!-- Order -->
418
- <div>
419
- <label for="serial" class="block font-medium mb-2">Display Order</label>
420
- <input
421
- pInputText
422
- id="serial"
423
- type="number"
424
- [formField]="actionForm.serial"
425
- class="w-full"
426
- placeholder="Enter display order" />
427
- </div>
391
+ <!-- Order -->
392
+ <div class="flex flex-col gap-2">
393
+ <label for="serial" class="font-medium">Display Order</label>
394
+ <input
395
+ pInputText
396
+ id="serial"
397
+ type="number"
398
+ [formField]="actionForm.serial"
399
+ placeholder="Enter display order" />
400
+ </div>
428
401
 
429
- <!-- Is Active -->
430
- <div class="flex items-center pt-6">
431
- <label class="p-checkbox-native">
432
- <input
433
- type="checkbox"
434
- [formField]="actionForm.isActive" />
435
- <span>Active</span>
436
- </label>
437
- </div>
402
+ <!-- Is Active -->
403
+ <div class="flex items-end gap-2 pb-1 md:col-span-2">
404
+ <p-checkbox
405
+ [formField]="actionForm.isActive"
406
+ [binary]="true"
407
+ inputId="isActive" />
408
+ <label for="isActive">Active</label>
438
409
  </div>
439
410
 
440
411
  <!-- Permission Logic Builder -->
441
- <div class="mt-6">
412
+ <div class="md:col-span-2">
442
413
  <lib-logic-builder
443
414
  [logic]="formModel().permissionLogic"
444
415
  [actions]="allActionsForLogic()"
@@ -446,7 +417,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
446
417
  </div>
447
418
 
448
419
  <!-- Actions -->
449
- <div class="flex justify-end gap-2 mt-6">
420
+ <div class="flex justify-end gap-2 md:col-span-2 pt-4">
450
421
  <p-button
451
422
  label="Cancel"
452
423
  severity="secondary"
@@ -462,7 +433,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
462
433
  </div>
463
434
  `,
464
435
  }]
465
- }] });
436
+ }], ctorParameters: () => [] });
466
437
 
467
438
  export { ActionFormPageComponent };
468
- //# sourceMappingURL=flusys-ng-iam-action-form-page.component-BVWZMlLU.mjs.map
439
+ //# sourceMappingURL=flusys-ng-iam-action-form-page.component-C_BRrrWW.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flusys-ng-iam-action-form-page.component-C_BRrrWW.mjs","sources":["../../../projects/ng-iam/pages/action/action-form-page.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, 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 { AngularModule, ILogicNode, PrimeModule } from '@flusys/ng-shared';\nimport { MessageService } from 'primeng/api';\nimport { firstValueFrom } from 'rxjs';\nimport { ActionApiService } from '../../services/action-api.service';\nimport { IAction, ActionType } from '../../interfaces/action.interface';\nimport { LogicBuilderComponent } from '../../components/logic-builder.component';\n\n/** Action form model interface */\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 metadata: Record<string, unknown> | null;\n}\n\n/**\n * Action Form Page Component\n * Create/Edit action with signal-based form pattern (matches ng-auth)\n */\n@Component({\n selector: 'lib-action-form-page',\n standalone: true,\n imports: [AngularModule, PrimeModule, FormField, LogicBuilderComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"card\">\n <h3 class=\"text-lg sm:text-xl font-semibold mb-4\">\n {{ isEditMode() ? 'Edit Action' : 'New Action' }}\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\">Name *</label>\n <input\n pInputText\n id=\"name\"\n [formField]=\"actionForm.name\"\n placeholder=\"Enter action name\" />\n </div>\n\n <!-- Code -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"code\" class=\"font-medium\">Code</label>\n <input\n pInputText\n id=\"code\"\n [formField]=\"actionForm.code\"\n placeholder=\"Enter action code\" />\n </div>\n\n <!-- Description -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"description\" class=\"font-medium\">Description</label>\n <input\n pInputText\n id=\"description\"\n [formField]=\"actionForm.description\"\n placeholder=\"Enter description\" />\n </div>\n\n <!-- Action Type -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"actionType\" class=\"font-medium\">Action Type *</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\">Parent Action</label>\n <select\n id=\"parentId\"\n class=\"p-inputtext w-full\"\n [formField]=\"actionForm.parentId\">\n <option value=\"\">Select parent action</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\">Display Order</label>\n <input\n pInputText\n id=\"serial\"\n type=\"number\"\n [formField]=\"actionForm.serial\"\n placeholder=\"Enter display order\" />\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\">Active</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=\"Cancel\"\n severity=\"secondary\"\n [outlined]=\"true\"\n (onClick)=\"onBack()\" />\n <p-button\n [label]=\"isEditMode() ? 'Update' : 'Create'\"\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\n private readonly routeParams = toSignal(this.route.paramMap);\n private initialized = false;\n\n /** Loading state */\n readonly isLoading = signal(false);\n\n /** Existing action data when editing */\n readonly existingAction = signal<IAction | null>(null);\n\n /** Whether in edit mode */\n readonly isEditMode = computed(() => !!this.existingAction());\n\n /** All actions for LogicBuilder */\n readonly allActionsForLogic = signal<Array<{ id: string; name: string }>>([]);\n\n /** All loaded actions for parent dropdown */\n readonly allActions = signal<IAction[]>([]);\n\n /** Available actions for parent dropdown (excludes current action to prevent circular reference) */\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 // ============================================\n // Form (Signal Forms)\n // ============================================\n\n /** Form model */\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 metadata: null,\n });\n\n /** Available action types for dropdown */\n readonly actionTypes = [\n { label: 'Backend (API Endpoints)', value: ActionType.BACKEND },\n { label: 'Frontend (UI Features)', value: ActionType.FRONTEND },\n { label: 'Both (Backend + Frontend)', value: ActionType.BOTH },\n ];\n\n /** Form with validation schema */\n readonly actionForm = form(this.formModel, (f) => {\n required(f.name, { message: 'Name is required' });\n });\n\n /** Check if form is valid */\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 // Load ALL actions FIRST - critical for LogicBuilder to display action names\n try {\n const response = await firstValueFrom(\n this.actionApi.getAll('', {\n pagination: { currentPage: 0, pageSize: 10000 },\n select: ['id', 'name', 'code', 'actionType', 'permissionLogic'],\n })\n );\n\n if (response?.success && response.data) {\n // Set actions for LogicBuilder dropdown\n this.allActionsForLogic.set(\n response.data.map(a => ({ id: a.id!, name: a.name ?? 'Unnamed' }))\n );\n\n // Store loaded actions locally for parent dropdown\n this.allActions.set(response.data);\n }\n } catch {\n // Actions load failed - form will show empty parent dropdown\n }\n\n // THEN load the specific action (ensures actions are loaded before setting permissionLogic)\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 // Load fresh data from API to ensure permissionLogic is included\n const response = await this.actionApi.findByIdAsync(id, [\n 'id',\n 'name',\n 'description',\n 'code',\n 'actionType',\n 'permissionLogic',\n 'parentId',\n 'serial',\n 'isActive',\n 'metadata',\n ]);\n\n if (response?.success && response.data) {\n const action = response.data;\n\n // Set existing action for reference\n this.existingAction.set(action);\n\n // Populate form with action data\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 metadata: action.metadata ?? null,\n });\n } else {\n // Error toast handled by global interceptor\n this.router.navigate(['/iam/actions']);\n }\n } catch {\n // Error toast handled by global interceptor\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: 'Validation Error',\n detail: 'Please fill in all required fields.',\n });\n return;\n }\n\n this.isLoading.set(true);\n\n try {\n const formValue = this.formModel();\n\n // Convert empty strings to undefined for DTO compatibility\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 metadata: formValue.metadata ?? undefined,\n permissionLogic: formValue.permissionLogic ?? undefined,\n };\n\n if (this.isEditMode()) {\n await this.actionApi.updateAsync(dto);\n this.messageService.add({\n severity: 'success',\n summary: 'Success',\n detail: 'Action updated successfully.',\n });\n } else {\n await this.actionApi.insertAsync(dto);\n this.messageService.add({\n severity: 'success',\n summary: 'Success',\n detail: 'Action created successfully.',\n });\n }\n\n this.router.navigate(['/iam/actions']);\n } catch {\n // Error toast 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 /**\n * Handle permission logic changes from LogicBuilder\n */\n onLogicChange(logic: ILogicNode | null): void {\n this.formModel.update(model => ({\n ...model,\n permissionLogic: logic\n }));\n }\n}\n"],"names":[],"mappings":"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"}