@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.
- package/README.md +225 -24
- package/fesm2022/flusys-ng-iam-action-form-page.component-CVN8sV-c.mjs +389 -0
- package/fesm2022/flusys-ng-iam-action-form-page.component-CVN8sV-c.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam-action-list-page.component-CQ6RazN0.mjs +262 -0
- package/fesm2022/flusys-ng-iam-action-list-page.component-CQ6RazN0.mjs.map +1 -0
- package/fesm2022/{flusys-ng-iam-flusys-ng-iam-C-MQjakK.mjs → flusys-ng-iam-flusys-ng-iam-DrGHlTiz.mjs} +1062 -1550
- package/fesm2022/flusys-ng-iam-flusys-ng-iam-DrGHlTiz.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam-iam-container.component-BToYxEej.mjs +92 -0
- package/fesm2022/flusys-ng-iam-iam-container.component-BToYxEej.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam-permission-page.component-BS7xXmsn.mjs +137 -0
- package/fesm2022/flusys-ng-iam-permission-page.component-BS7xXmsn.mjs.map +1 -0
- package/fesm2022/{flusys-ng-iam-role-form-page.component-eZM1EPps.mjs → flusys-ng-iam-role-form-page.component-BjPwXkip.mjs} +107 -149
- package/fesm2022/flusys-ng-iam-role-form-page.component-BjPwXkip.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam-role-list-page.component-Cz-jk-R_.mjs +299 -0
- package/fesm2022/flusys-ng-iam-role-list-page.component-Cz-jk-R_.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam.mjs +1 -1
- package/package.json +10 -10
- package/types/flusys-ng-iam.d.ts +103 -437
- package/fesm2022/flusys-ng-iam-action-form-page.component-0b9GwJqa.mjs +0 -467
- package/fesm2022/flusys-ng-iam-action-form-page.component-0b9GwJqa.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-action-list-page.component-BpvewEGL.mjs +0 -281
- package/fesm2022/flusys-ng-iam-action-list-page.component-BpvewEGL.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-flusys-ng-iam-C-MQjakK.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-iam-container.component-Chl5MDkV.mjs +0 -97
- package/fesm2022/flusys-ng-iam-iam-container.component-Chl5MDkV.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-permission-page.component-e_RX5mky.mjs +0 -143
- package/fesm2022/flusys-ng-iam-permission-page.component-e_RX5mky.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-role-form-page.component-eZM1EPps.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-role-list-page.component-BgzxmHjk.mjs +0 -266
- 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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"}
|