@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.
- package/fesm2022/flusys-ng-iam-action-form-page.component-BojLw61e.mjs +468 -0
- package/fesm2022/flusys-ng-iam-action-form-page.component-BojLw61e.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam-action-list-page.component-CFZsCdCc.mjs +282 -0
- package/fesm2022/flusys-ng-iam-action-list-page.component-CFZsCdCc.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam-flusys-ng-iam-me7pTNTO.mjs +5053 -0
- package/fesm2022/flusys-ng-iam-flusys-ng-iam-me7pTNTO.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam-iam-container.component-BFKoNtdz.mjs +97 -0
- package/fesm2022/flusys-ng-iam-iam-container.component-BFKoNtdz.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam-permission-page.component-jZgTau_R.mjs +143 -0
- package/fesm2022/flusys-ng-iam-permission-page.component-jZgTau_R.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam-role-form-page.component-BjL-Y3rx.mjs +314 -0
- package/fesm2022/flusys-ng-iam-role-form-page.component-BjL-Y3rx.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam-role-list-page.component-Sw0CBlkz.mjs +262 -0
- package/fesm2022/flusys-ng-iam-role-list-page.component-Sw0CBlkz.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam.mjs +2 -0
- package/fesm2022/flusys-ng-iam.mjs.map +1 -0
- package/package.json +29 -0
- package/types/flusys-ng-iam.d.ts +1140 -0
|
@@ -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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"}
|