@flusys/ng-iam 0.1.0-alpha.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.
@@ -0,0 +1,468 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { form, required, FormField } from '@angular/forms/signals';
4
+ import { ActivatedRoute, Router } from '@angular/router';
5
+ import { AngularModule, PrimeModule } from '@flusys/ng-shared';
6
+ import { MessageService } from 'primeng/api';
7
+ import { firstValueFrom } from 'rxjs';
8
+ import { A as ActionApiService, a as ActionType, L as LogicBuilderComponent } from './flusys-ng-iam-flusys-ng-iam-me7pTNTO.mjs';
9
+ import * as i1 from '@angular/forms';
10
+ import * as i2 from 'primeng/inputtext';
11
+ import * as i3 from 'primeng/button';
12
+
13
+ /**
14
+ * Action Form Page Component
15
+ * Create/Edit action with signal-based form pattern (matches ng-auth)
16
+ */
17
+ class ActionFormPageComponent {
18
+ route = inject(ActivatedRoute);
19
+ router = inject(Router);
20
+ actionApi = inject(ActionApiService);
21
+ messageService = inject(MessageService);
22
+ /** Loading state */
23
+ isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
24
+ /** Existing action data when editing */
25
+ existingAction = signal(null, ...(ngDevMode ? [{ debugName: "existingAction" }] : []));
26
+ /** Whether in edit mode */
27
+ isEditMode = computed(() => !!this.existingAction(), ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
28
+ /** All actions for LogicBuilder */
29
+ allActionsForLogic = signal([], ...(ngDevMode ? [{ debugName: "allActionsForLogic" }] : []));
30
+ /** All loaded actions for parent dropdown */
31
+ allActions = signal([], ...(ngDevMode ? [{ debugName: "allActions" }] : []));
32
+ /** Available actions for parent dropdown (excludes current action to prevent circular reference) */
33
+ availableActions = computed(() => {
34
+ const actions = this.allActions();
35
+ const currentId = this.existingAction()?.id;
36
+ return currentId ? actions.filter(a => a.id !== currentId) : actions;
37
+ }, ...(ngDevMode ? [{ debugName: "availableActions" }] : []));
38
+ // ============================================
39
+ // Form (Signal Forms)
40
+ // ============================================
41
+ /** Form model */
42
+ formModel = signal({
43
+ id: '',
44
+ name: '',
45
+ description: '',
46
+ code: '',
47
+ actionType: ActionType.BACKEND,
48
+ permissionLogic: null,
49
+ parentId: '',
50
+ serial: '',
51
+ isActive: true,
52
+ metadata: null,
53
+ }, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
54
+ /** Available action types for dropdown */
55
+ actionTypes = [
56
+ { label: 'Backend (API Endpoints)', value: ActionType.BACKEND },
57
+ { label: 'Frontend (UI Features)', value: ActionType.FRONTEND },
58
+ { label: 'Both (Backend + Frontend)', value: ActionType.BOTH },
59
+ ];
60
+ /** Form with validation schema */
61
+ actionForm = form(this.formModel, (f) => {
62
+ required(f.name, { message: 'Name is required' });
63
+ });
64
+ /** Check if form is valid */
65
+ isFormValid = computed(() => {
66
+ const model = this.formModel();
67
+ return model.name.trim().length > 0;
68
+ }, ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
69
+ async ngOnInit() {
70
+ const id = this.route.snapshot.paramMap.get('id');
71
+ // Load ALL actions FIRST - critical for LogicBuilder to display action names
72
+ try {
73
+ const response = await firstValueFrom(this.actionApi.getAll('', {
74
+ pagination: { currentPage: 0, pageSize: 10000 },
75
+ select: ['id', 'name', 'code', 'actionType', 'permissionLogic'],
76
+ }));
77
+ if (response?.success && response.data) {
78
+ // Set actions for LogicBuilder dropdown
79
+ this.allActionsForLogic.set(response.data.map(a => ({ id: a.id, name: a.name ?? 'Unnamed' })));
80
+ // Store loaded actions locally for parent dropdown
81
+ this.allActions.set(response.data);
82
+ }
83
+ }
84
+ catch (error) {
85
+ console.error('[ActionFormPage] Failed to load actions:', error);
86
+ }
87
+ // THEN load the specific action (ensures actions are loaded before setting permissionLogic)
88
+ if (id && id !== 'new') {
89
+ await this.loadAction(id);
90
+ }
91
+ }
92
+ async loadAction(id) {
93
+ this.isLoading.set(true);
94
+ try {
95
+ // Load fresh data from API to ensure permissionLogic is included
96
+ const response = await this.actionApi.findByIdAsync(id, [
97
+ 'id',
98
+ 'name',
99
+ 'description',
100
+ 'code',
101
+ 'actionType',
102
+ 'permissionLogic',
103
+ 'parentId',
104
+ 'serial',
105
+ 'isActive',
106
+ 'metadata',
107
+ ]);
108
+ if (response?.success && response.data) {
109
+ const action = response.data;
110
+ // Set existing action for reference
111
+ this.existingAction.set(action);
112
+ // Populate form with action data
113
+ this.formModel.set({
114
+ id: action.id ?? '',
115
+ name: action.name ?? '',
116
+ description: action.description ?? '',
117
+ code: action.code ?? '',
118
+ actionType: action.actionType ?? ActionType.BACKEND,
119
+ permissionLogic: action.permissionLogic ?? null,
120
+ parentId: action.parentId ?? '',
121
+ serial: action.serial?.toString() ?? '',
122
+ isActive: action.isActive ?? true,
123
+ metadata: action.metadata ?? null,
124
+ });
125
+ }
126
+ else {
127
+ this.messageService.add({
128
+ severity: 'error',
129
+ summary: 'Error',
130
+ detail: 'Action not found.',
131
+ });
132
+ this.router.navigate(['/iam/actions']);
133
+ }
134
+ }
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
+ });
142
+ this.router.navigate(['/iam/actions']);
143
+ }
144
+ finally {
145
+ this.isLoading.set(false);
146
+ }
147
+ }
148
+ async onSubmit() {
149
+ if (!this.isFormValid()) {
150
+ this.messageService.add({
151
+ severity: 'error',
152
+ summary: 'Validation Error',
153
+ detail: 'Please fill in all required fields.',
154
+ });
155
+ return;
156
+ }
157
+ this.isLoading.set(true);
158
+ try {
159
+ const formValue = this.formModel();
160
+ // Convert empty strings to undefined for DTO compatibility
161
+ const dto = {
162
+ ...formValue,
163
+ description: formValue.description || undefined,
164
+ code: formValue.code || undefined,
165
+ parentId: formValue.parentId || undefined,
166
+ serial: formValue.serial ? parseInt(formValue.serial, 10) : undefined,
167
+ metadata: formValue.metadata ?? undefined,
168
+ permissionLogic: formValue.permissionLogic ?? undefined,
169
+ };
170
+ if (this.isEditMode()) {
171
+ await this.actionApi.updateAsync(dto);
172
+ this.messageService.add({
173
+ severity: 'success',
174
+ summary: 'Success',
175
+ detail: 'Action updated successfully.',
176
+ });
177
+ }
178
+ else {
179
+ await this.actionApi.insertAsync(dto);
180
+ this.messageService.add({
181
+ severity: 'success',
182
+ summary: 'Success',
183
+ detail: 'Action created successfully.',
184
+ });
185
+ }
186
+ this.router.navigate(['/iam/actions']);
187
+ }
188
+ catch (error) {
189
+ this.messageService.add({
190
+ severity: 'error',
191
+ summary: 'Error',
192
+ detail: error.message || 'Failed to save action.',
193
+ });
194
+ }
195
+ finally {
196
+ this.isLoading.set(false);
197
+ }
198
+ }
199
+ onBack() {
200
+ this.router.navigate(['/iam/actions']);
201
+ }
202
+ /**
203
+ * Handle permission logic changes from LogicBuilder
204
+ */
205
+ onLogicChange(logic) {
206
+ this.formModel.update(model => ({
207
+ ...model,
208
+ permissionLogic: logic
209
+ }));
210
+ }
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: `
213
+ <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>
224
+
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>
237
+
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>
248
+
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>
259
+
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>
272
+
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>
286
+
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>
298
+
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>
308
+ </div>
309
+
310
+ <!-- Permission Logic Builder -->
311
+ <div class="mt-6">
312
+ <lib-logic-builder
313
+ [logic]="formModel().permissionLogic"
314
+ [actions]="allActionsForLogic()"
315
+ (logicChange)="onLogicChange($event)" />
316
+ </div>
317
+
318
+ <!-- Actions -->
319
+ <div class="flex justify-end gap-2 mt-6">
320
+ <p-button
321
+ label="Cancel"
322
+ severity="secondary"
323
+ [outlined]="true"
324
+ (onClick)="onBack()" />
325
+ <p-button
326
+ [label]="isEditMode() ? 'Update' : 'Create'"
327
+ type="submit"
328
+ [loading]="isLoading()"
329
+ [disabled]="!isFormValid() || isLoading()" />
330
+ </div>
331
+ </form>
332
+ </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 });
334
+ }
335
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ActionFormPageComponent, decorators: [{
336
+ type: Component,
337
+ args: [{
338
+ selector: 'lib-action-form-page',
339
+ standalone: true,
340
+ imports: [AngularModule, PrimeModule, FormField, LogicBuilderComponent],
341
+ changeDetection: ChangeDetectionStrategy.OnPush,
342
+ template: `
343
+ <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>
354
+
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>
367
+
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>
378
+
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>
389
+
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>
402
+
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>
416
+
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>
428
+
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>
438
+ </div>
439
+
440
+ <!-- Permission Logic Builder -->
441
+ <div class="mt-6">
442
+ <lib-logic-builder
443
+ [logic]="formModel().permissionLogic"
444
+ [actions]="allActionsForLogic()"
445
+ (logicChange)="onLogicChange($event)" />
446
+ </div>
447
+
448
+ <!-- Actions -->
449
+ <div class="flex justify-end gap-2 mt-6">
450
+ <p-button
451
+ label="Cancel"
452
+ severity="secondary"
453
+ [outlined]="true"
454
+ (onClick)="onBack()" />
455
+ <p-button
456
+ [label]="isEditMode() ? 'Update' : 'Create'"
457
+ type="submit"
458
+ [loading]="isLoading()"
459
+ [disabled]="!isFormValid() || isLoading()" />
460
+ </div>
461
+ </form>
462
+ </div>
463
+ `,
464
+ }]
465
+ }] });
466
+
467
+ export { ActionFormPageComponent };
468
+ //# sourceMappingURL=flusys-ng-iam-action-form-page.component-BojLw61e.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flusys-ng-iam-action-form-page.component-BojLw61e.mjs","sources":["../../../projects/ng-iam/pages/action/action-form-page.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, inject, OnInit, signal } from '@angular/core';\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: any | null;\n parentId: string;\n serial: string;\n isActive: boolean;\n metadata: any | 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 <div class=\"flex justify-between items-center mb-4\">\n <h3 class=\"text-xl font-semibold\">\n {{ isEditMode() ? 'Edit Action' : 'New Action' }}\n </h3>\n <p-button\n label=\"Back\"\n icon=\"pi pi-arrow-left\"\n [outlined]=\"true\"\n (onClick)=\"onBack()\" />\n </div>\n\n <form (ngSubmit)=\"onSubmit()\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Name -->\n <div>\n <label for=\"name\" class=\"block font-medium mb-2\">Name *</label>\n <input\n pInputText\n id=\"name\"\n [formField]=\"actionForm.name\"\n class=\"w-full\"\n placeholder=\"Enter action name\" />\n </div>\n\n <!-- Code -->\n <div>\n <label for=\"code\" class=\"block font-medium mb-2\">Code</label>\n <input\n pInputText\n id=\"code\"\n [formField]=\"actionForm.code\"\n class=\"w-full\"\n placeholder=\"Enter action code\" />\n </div>\n\n <!-- Description -->\n <div class=\"md:col-span-2\">\n <label for=\"description\" class=\"block font-medium mb-2\">Description</label>\n <input\n pInputText\n id=\"description\"\n [formField]=\"actionForm.description\"\n class=\"w-full\"\n placeholder=\"Enter description\" />\n </div>\n\n <!-- Action Type -->\n <div>\n <label for=\"actionType\" class=\"block font-medium mb-2\">Action Type *</label>\n <select\n id=\"actionType\"\n class=\"p-select-native\"\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>\n <label for=\"parentId\" class=\"block font-medium mb-2\">Parent Action</label>\n <select\n id=\"parentId\"\n class=\"p-select-native\"\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>\n <label for=\"serial\" class=\"block font-medium mb-2\">Display Order</label>\n <input\n pInputText\n id=\"serial\"\n type=\"number\"\n [formField]=\"actionForm.serial\"\n class=\"w-full\"\n placeholder=\"Enter display order\" />\n </div>\n\n <!-- Is Active -->\n <div class=\"flex items-center pt-6\">\n <label class=\"p-checkbox-native\">\n <input\n type=\"checkbox\"\n [formField]=\"actionForm.isActive\" />\n <span>Active</span>\n </label>\n </div>\n </div>\n\n <!-- Permission Logic Builder -->\n <div class=\"mt-6\">\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 mt-6\">\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 implements OnInit {\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 /** 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 async ngOnInit(): Promise<void> {\n const id = this.route.snapshot.paramMap.get('id');\n\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 (error) {\n console.error('[ActionFormPage] Failed to load actions:', error);\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 this.messageService.add({\n severity: 'error',\n summary: 'Error',\n detail: 'Action not found.',\n });\n this.router.navigate(['/iam/actions']);\n }\n } catch (error) {\n console.error('[ActionFormPage] Failed to load action:', error);\n this.messageService.add({\n severity: 'error',\n summary: 'Error',\n detail: 'Failed to load action.',\n });\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 (error: any) {\n this.messageService.add({\n severity: 'error',\n summary: 'Error',\n detail: error.message || 'Failed to save action.',\n });\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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"}