@flusys/ng-iam 1.0.0-beta → 1.0.0

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 (30) hide show
  1. package/README.md +225 -24
  2. package/fesm2022/flusys-ng-iam-action-form-page.component-CVN8sV-c.mjs +389 -0
  3. package/fesm2022/flusys-ng-iam-action-form-page.component-CVN8sV-c.mjs.map +1 -0
  4. package/fesm2022/flusys-ng-iam-action-list-page.component-CQ6RazN0.mjs +262 -0
  5. package/fesm2022/flusys-ng-iam-action-list-page.component-CQ6RazN0.mjs.map +1 -0
  6. package/fesm2022/{flusys-ng-iam-flusys-ng-iam-C-MQjakK.mjs → flusys-ng-iam-flusys-ng-iam-DrGHlTiz.mjs} +1062 -1550
  7. package/fesm2022/flusys-ng-iam-flusys-ng-iam-DrGHlTiz.mjs.map +1 -0
  8. package/fesm2022/flusys-ng-iam-iam-container.component-BToYxEej.mjs +92 -0
  9. package/fesm2022/flusys-ng-iam-iam-container.component-BToYxEej.mjs.map +1 -0
  10. package/fesm2022/flusys-ng-iam-permission-page.component-BS7xXmsn.mjs +137 -0
  11. package/fesm2022/flusys-ng-iam-permission-page.component-BS7xXmsn.mjs.map +1 -0
  12. package/fesm2022/{flusys-ng-iam-role-form-page.component-eZM1EPps.mjs → flusys-ng-iam-role-form-page.component-BjPwXkip.mjs} +107 -149
  13. package/fesm2022/flusys-ng-iam-role-form-page.component-BjPwXkip.mjs.map +1 -0
  14. package/fesm2022/flusys-ng-iam-role-list-page.component-Cz-jk-R_.mjs +299 -0
  15. package/fesm2022/flusys-ng-iam-role-list-page.component-Cz-jk-R_.mjs.map +1 -0
  16. package/fesm2022/flusys-ng-iam.mjs +1 -1
  17. package/package.json +10 -10
  18. package/types/flusys-ng-iam.d.ts +103 -437
  19. package/fesm2022/flusys-ng-iam-action-form-page.component-0b9GwJqa.mjs +0 -467
  20. package/fesm2022/flusys-ng-iam-action-form-page.component-0b9GwJqa.mjs.map +0 -1
  21. package/fesm2022/flusys-ng-iam-action-list-page.component-BpvewEGL.mjs +0 -281
  22. package/fesm2022/flusys-ng-iam-action-list-page.component-BpvewEGL.mjs.map +0 -1
  23. package/fesm2022/flusys-ng-iam-flusys-ng-iam-C-MQjakK.mjs.map +0 -1
  24. package/fesm2022/flusys-ng-iam-iam-container.component-Chl5MDkV.mjs +0 -97
  25. package/fesm2022/flusys-ng-iam-iam-container.component-Chl5MDkV.mjs.map +0 -1
  26. package/fesm2022/flusys-ng-iam-permission-page.component-e_RX5mky.mjs +0 -143
  27. package/fesm2022/flusys-ng-iam-permission-page.component-e_RX5mky.mjs.map +0 -1
  28. package/fesm2022/flusys-ng-iam-role-form-page.component-eZM1EPps.mjs.map +0 -1
  29. package/fesm2022/flusys-ng-iam-role-list-page.component-BgzxmHjk.mjs +0 -266
  30. package/fesm2022/flusys-ng-iam-role-list-page.component-BgzxmHjk.mjs.map +0 -1
@@ -0,0 +1,389 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, signal, computed, effect, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { toSignal } from '@angular/core/rxjs-interop';
4
+ import { form, required, FormField } from '@angular/forms/signals';
5
+ import { ActivatedRoute, Router } from '@angular/router';
6
+ import { AngularModule, PrimeModule } from '@flusys/ng-shared';
7
+ import { MessageService } from 'primeng/api';
8
+ import { firstValueFrom } from 'rxjs';
9
+ import { A as ActionApiService, a as ActionType, L as LogicBuilderComponent } from './flusys-ng-iam-flusys-ng-iam-DrGHlTiz.mjs';
10
+ import * as i1 from '@angular/forms';
11
+ import * as i2 from 'primeng/button';
12
+ import * as i3 from 'primeng/checkbox';
13
+ import * as i4 from 'primeng/inputtext';
14
+
15
+ class ActionFormPageComponent {
16
+ route = inject(ActivatedRoute);
17
+ router = inject(Router);
18
+ actionApi = inject(ActionApiService);
19
+ messageService = inject(MessageService);
20
+ routeParams = toSignal(this.route.paramMap);
21
+ initialized = false;
22
+ isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
23
+ existingAction = signal(null, ...(ngDevMode ? [{ debugName: "existingAction" }] : []));
24
+ isEditMode = computed(() => !!this.existingAction(), ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
25
+ allActionsForLogic = signal([], ...(ngDevMode ? [{ debugName: "allActionsForLogic" }] : []));
26
+ allActions = signal([], ...(ngDevMode ? [{ debugName: "allActions" }] : []));
27
+ availableActions = computed(() => {
28
+ const actions = this.allActions();
29
+ const currentId = this.existingAction()?.id;
30
+ return currentId ? actions.filter((a) => a.id !== currentId) : actions;
31
+ }, ...(ngDevMode ? [{ debugName: "availableActions" }] : []));
32
+ formModel = signal({
33
+ id: '',
34
+ name: '',
35
+ description: '',
36
+ code: '',
37
+ actionType: ActionType.BACKEND,
38
+ permissionLogic: null,
39
+ parentId: '',
40
+ serial: '',
41
+ isActive: true,
42
+ metadata: null,
43
+ }, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
44
+ actionTypes = [
45
+ { label: 'Backend (API Endpoints)', value: ActionType.BACKEND },
46
+ { label: 'Frontend (UI Features)', value: ActionType.FRONTEND },
47
+ { label: 'Both (Backend + Frontend)', value: ActionType.BOTH },
48
+ ];
49
+ actionForm = form(this.formModel, (f) => {
50
+ required(f.name, { message: 'Name is required' });
51
+ });
52
+ isFormValid = computed(() => {
53
+ const model = this.formModel();
54
+ return model.name.trim().length > 0;
55
+ }, ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
56
+ constructor() {
57
+ effect(() => {
58
+ const params = this.routeParams();
59
+ if (!params || this.initialized)
60
+ return;
61
+ this.initialized = true;
62
+ this.initializeForm(params.get('id'));
63
+ });
64
+ }
65
+ async initializeForm(id) {
66
+ try {
67
+ const response = await firstValueFrom(this.actionApi.getAll('', {
68
+ pagination: { currentPage: 0, pageSize: 10000 },
69
+ select: ['id', 'name', 'code', 'actionType', 'permissionLogic'],
70
+ }));
71
+ if (response?.success && response.data) {
72
+ this.allActionsForLogic.set(response.data.map((a) => ({ id: a.id, name: a.name ?? 'Unnamed' })));
73
+ this.allActions.set(response.data);
74
+ }
75
+ }
76
+ catch {
77
+ // Ignored - form will show empty parent dropdown
78
+ }
79
+ if (id && id !== 'new') {
80
+ await this.loadAction(id);
81
+ }
82
+ }
83
+ async loadAction(id) {
84
+ this.isLoading.set(true);
85
+ try {
86
+ const response = await this.actionApi.findByIdAsync(id, [
87
+ 'id', 'name', 'description', 'code', 'actionType',
88
+ 'permissionLogic', 'parentId', 'serial', 'isActive', 'metadata',
89
+ ]);
90
+ if (response?.success && response.data) {
91
+ const action = response.data;
92
+ this.existingAction.set(action);
93
+ this.formModel.set({
94
+ id: action.id ?? '',
95
+ name: action.name ?? '',
96
+ description: action.description ?? '',
97
+ code: action.code ?? '',
98
+ actionType: action.actionType ?? ActionType.BACKEND,
99
+ permissionLogic: action.permissionLogic ?? null,
100
+ parentId: action.parentId ?? '',
101
+ serial: action.serial?.toString() ?? '',
102
+ isActive: action.isActive ?? true,
103
+ metadata: action.metadata ?? null,
104
+ });
105
+ }
106
+ else {
107
+ this.router.navigate(['/iam/actions']);
108
+ }
109
+ }
110
+ catch {
111
+ this.router.navigate(['/iam/actions']);
112
+ }
113
+ finally {
114
+ this.isLoading.set(false);
115
+ }
116
+ }
117
+ async onSubmit() {
118
+ if (!this.isFormValid()) {
119
+ this.messageService.add({
120
+ severity: 'error',
121
+ summary: 'Validation Error',
122
+ detail: 'Please fill in all required fields.',
123
+ });
124
+ return;
125
+ }
126
+ this.isLoading.set(true);
127
+ try {
128
+ const formValue = this.formModel();
129
+ const dto = {
130
+ ...formValue,
131
+ description: formValue.description || undefined,
132
+ code: formValue.code || undefined,
133
+ parentId: formValue.parentId || undefined,
134
+ serial: formValue.serial ? parseInt(formValue.serial, 10) : undefined,
135
+ metadata: formValue.metadata ?? undefined,
136
+ permissionLogic: formValue.permissionLogic ?? undefined,
137
+ };
138
+ if (this.isEditMode()) {
139
+ await this.actionApi.updateAsync(dto);
140
+ this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Action updated successfully.' });
141
+ }
142
+ else {
143
+ await this.actionApi.insertAsync(dto);
144
+ this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Action created successfully.' });
145
+ }
146
+ this.router.navigate(['/iam/actions']);
147
+ }
148
+ catch {
149
+ // Handled by global interceptor
150
+ }
151
+ finally {
152
+ this.isLoading.set(false);
153
+ }
154
+ }
155
+ onBack() {
156
+ this.router.navigate(['/iam/actions']);
157
+ }
158
+ onLogicChange(logic) {
159
+ this.formModel.update((model) => ({ ...model, permissionLogic: logic }));
160
+ }
161
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ActionFormPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
162
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ActionFormPageComponent, isStandalone: true, selector: "lib-action-form-page", ngImport: i0, template: `
163
+ <div class="card">
164
+ <h3 class="text-lg sm:text-xl font-semibold mb-4">
165
+ {{ isEditMode() ? 'Edit Action' : 'New Action' }}
166
+ </h3>
167
+
168
+ <form (ngSubmit)="onSubmit()" class="grid grid-cols-1 md:grid-cols-2 gap-4">
169
+ <!-- Name -->
170
+ <div class="flex flex-col gap-2">
171
+ <label for="name" class="font-medium">Name *</label>
172
+ <input
173
+ pInputText
174
+ id="name"
175
+ [formField]="actionForm.name"
176
+ placeholder="Enter action name" />
177
+ </div>
178
+
179
+ <!-- Code -->
180
+ <div class="flex flex-col gap-2">
181
+ <label for="code" class="font-medium">Code</label>
182
+ <input
183
+ pInputText
184
+ id="code"
185
+ [formField]="actionForm.code"
186
+ placeholder="Enter action code" />
187
+ </div>
188
+
189
+ <!-- Description -->
190
+ <div class="flex flex-col gap-2">
191
+ <label for="description" class="font-medium">Description</label>
192
+ <input
193
+ pInputText
194
+ id="description"
195
+ [formField]="actionForm.description"
196
+ placeholder="Enter description" />
197
+ </div>
198
+
199
+ <!-- Action Type -->
200
+ <div class="flex flex-col gap-2">
201
+ <label for="actionType" class="font-medium">Action Type *</label>
202
+ <select
203
+ id="actionType"
204
+ class="p-inputtext w-full"
205
+ [formField]="actionForm.actionType">
206
+ @for (type of actionTypes; track type.value) {
207
+ <option [value]="type.value">{{ type.label }}</option>
208
+ }
209
+ </select>
210
+ </div>
211
+
212
+ <!-- Parent Action -->
213
+ <div class="flex flex-col gap-2">
214
+ <label for="parentId" class="font-medium">Parent Action</label>
215
+ <select
216
+ id="parentId"
217
+ class="p-inputtext w-full"
218
+ [formField]="actionForm.parentId">
219
+ <option value="">Select parent action</option>
220
+ @for (action of availableActions(); track action.id) {
221
+ <option [value]="action.id">{{ action.name }}</option>
222
+ }
223
+ </select>
224
+ </div>
225
+
226
+ <!-- Order -->
227
+ <div class="flex flex-col gap-2">
228
+ <label for="serial" class="font-medium">Display Order</label>
229
+ <input
230
+ pInputText
231
+ id="serial"
232
+ type="number"
233
+ [formField]="actionForm.serial"
234
+ placeholder="Enter display order" />
235
+ </div>
236
+
237
+ <!-- Is Active -->
238
+ <div class="flex items-end gap-2 pb-1 md:col-span-2">
239
+ <p-checkbox
240
+ [formField]="actionForm.isActive"
241
+ [binary]="true"
242
+ inputId="isActive" />
243
+ <label for="isActive">Active</label>
244
+ </div>
245
+
246
+ <!-- Permission Logic Builder -->
247
+ <div class="md:col-span-2">
248
+ <lib-logic-builder
249
+ [logic]="formModel().permissionLogic"
250
+ [actions]="allActionsForLogic()"
251
+ (logicChange)="onLogicChange($event)" />
252
+ </div>
253
+
254
+ <!-- Actions -->
255
+ <div class="flex justify-end gap-2 md:col-span-2 pt-4">
256
+ <p-button
257
+ label="Cancel"
258
+ severity="secondary"
259
+ [outlined]="true"
260
+ (onClick)="onBack()" />
261
+ <p-button
262
+ [label]="isEditMode() ? 'Update' : 'Create'"
263
+ type="submit"
264
+ [loading]="isLoading()"
265
+ [disabled]="!isFormValid() || isLoading()" />
266
+ </div>
267
+ </form>
268
+ </div>
269
+ `, 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 });
270
+ }
271
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ActionFormPageComponent, decorators: [{
272
+ type: Component,
273
+ args: [{
274
+ selector: 'lib-action-form-page',
275
+ imports: [AngularModule, PrimeModule, FormField, LogicBuilderComponent],
276
+ changeDetection: ChangeDetectionStrategy.OnPush,
277
+ template: `
278
+ <div class="card">
279
+ <h3 class="text-lg sm:text-xl font-semibold mb-4">
280
+ {{ isEditMode() ? 'Edit Action' : 'New Action' }}
281
+ </h3>
282
+
283
+ <form (ngSubmit)="onSubmit()" class="grid grid-cols-1 md:grid-cols-2 gap-4">
284
+ <!-- Name -->
285
+ <div class="flex flex-col gap-2">
286
+ <label for="name" class="font-medium">Name *</label>
287
+ <input
288
+ pInputText
289
+ id="name"
290
+ [formField]="actionForm.name"
291
+ placeholder="Enter action name" />
292
+ </div>
293
+
294
+ <!-- Code -->
295
+ <div class="flex flex-col gap-2">
296
+ <label for="code" class="font-medium">Code</label>
297
+ <input
298
+ pInputText
299
+ id="code"
300
+ [formField]="actionForm.code"
301
+ placeholder="Enter action code" />
302
+ </div>
303
+
304
+ <!-- Description -->
305
+ <div class="flex flex-col gap-2">
306
+ <label for="description" class="font-medium">Description</label>
307
+ <input
308
+ pInputText
309
+ id="description"
310
+ [formField]="actionForm.description"
311
+ placeholder="Enter description" />
312
+ </div>
313
+
314
+ <!-- Action Type -->
315
+ <div class="flex flex-col gap-2">
316
+ <label for="actionType" class="font-medium">Action Type *</label>
317
+ <select
318
+ id="actionType"
319
+ class="p-inputtext w-full"
320
+ [formField]="actionForm.actionType">
321
+ @for (type of actionTypes; track type.value) {
322
+ <option [value]="type.value">{{ type.label }}</option>
323
+ }
324
+ </select>
325
+ </div>
326
+
327
+ <!-- Parent Action -->
328
+ <div class="flex flex-col gap-2">
329
+ <label for="parentId" class="font-medium">Parent Action</label>
330
+ <select
331
+ id="parentId"
332
+ class="p-inputtext w-full"
333
+ [formField]="actionForm.parentId">
334
+ <option value="">Select parent action</option>
335
+ @for (action of availableActions(); track action.id) {
336
+ <option [value]="action.id">{{ action.name }}</option>
337
+ }
338
+ </select>
339
+ </div>
340
+
341
+ <!-- Order -->
342
+ <div class="flex flex-col gap-2">
343
+ <label for="serial" class="font-medium">Display Order</label>
344
+ <input
345
+ pInputText
346
+ id="serial"
347
+ type="number"
348
+ [formField]="actionForm.serial"
349
+ placeholder="Enter display order" />
350
+ </div>
351
+
352
+ <!-- Is Active -->
353
+ <div class="flex items-end gap-2 pb-1 md:col-span-2">
354
+ <p-checkbox
355
+ [formField]="actionForm.isActive"
356
+ [binary]="true"
357
+ inputId="isActive" />
358
+ <label for="isActive">Active</label>
359
+ </div>
360
+
361
+ <!-- Permission Logic Builder -->
362
+ <div class="md:col-span-2">
363
+ <lib-logic-builder
364
+ [logic]="formModel().permissionLogic"
365
+ [actions]="allActionsForLogic()"
366
+ (logicChange)="onLogicChange($event)" />
367
+ </div>
368
+
369
+ <!-- Actions -->
370
+ <div class="flex justify-end gap-2 md:col-span-2 pt-4">
371
+ <p-button
372
+ label="Cancel"
373
+ severity="secondary"
374
+ [outlined]="true"
375
+ (onClick)="onBack()" />
376
+ <p-button
377
+ [label]="isEditMode() ? 'Update' : 'Create'"
378
+ type="submit"
379
+ [loading]="isLoading()"
380
+ [disabled]="!isFormValid() || isLoading()" />
381
+ </div>
382
+ </form>
383
+ </div>
384
+ `,
385
+ }]
386
+ }], ctorParameters: () => [] });
387
+
388
+ export { ActionFormPageComponent };
389
+ //# sourceMappingURL=flusys-ng-iam-action-form-page.component-CVN8sV-c.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flusys-ng-iam-action-form-page.component-CVN8sV-c.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 { 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 metadata: Record<string, unknown> | null;\n}\n\n@Component({\n selector: 'lib-action-form-page',\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 private readonly routeParams = toSignal(this.route.paramMap);\n private initialized = false;\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 metadata: null,\n });\n\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 readonly actionForm = form(this.formModel, (f) => {\n required(f.name, { message: 'Name is required' });\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 firstValueFrom(\n this.actionApi.getAll('', {\n pagination: { currentPage: 0, pageSize: 10000 },\n select: ['id', 'name', 'code', 'actionType', 'permissionLogic'],\n }),\n );\n if (response?.success && response.data) {\n this.allActionsForLogic.set(response.data.map((a) => ({ id: a.id!, name: a.name ?? '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.findByIdAsync(id, [\n 'id', 'name', 'description', 'code', 'actionType',\n 'permissionLogic', 'parentId', 'serial', 'isActive', 'metadata',\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 metadata: action.metadata ?? null,\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: '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 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({ severity: 'success', summary: 'Success', detail: 'Action updated successfully.' });\n } else {\n await this.actionApi.insertAsync(dto);\n this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Action created successfully.' });\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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"}