@flusys/ng-iam 3.0.0 → 4.0.0-lts

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 (25) hide show
  1. package/README.md +2 -2
  2. package/fesm2022/{flusys-ng-iam-action-form-page.component-eXpZNJ_H.mjs → flusys-ng-iam-action-form-page.component-BQx9yset.mjs} +62 -50
  3. package/fesm2022/flusys-ng-iam-action-form-page.component-BQx9yset.mjs.map +1 -0
  4. package/fesm2022/{flusys-ng-iam-action-list-page.component-BtJlGcTj.mjs → flusys-ng-iam-action-list-page.component-BrpZujxk.mjs} +51 -42
  5. package/fesm2022/flusys-ng-iam-action-list-page.component-BrpZujxk.mjs.map +1 -0
  6. package/fesm2022/{flusys-ng-iam-flusys-ng-iam-CJAQT60K.mjs → flusys-ng-iam-flusys-ng-iam-Co4ot9My.mjs} +641 -341
  7. package/fesm2022/flusys-ng-iam-flusys-ng-iam-Co4ot9My.mjs.map +1 -0
  8. package/fesm2022/{flusys-ng-iam-iam-container.component-UYJjqYV9.mjs → flusys-ng-iam-iam-container.component-CQA2B6cU.mjs} +14 -13
  9. package/fesm2022/flusys-ng-iam-iam-container.component-CQA2B6cU.mjs.map +1 -0
  10. package/fesm2022/{flusys-ng-iam-permission-page.component-DcgT7L3_.mjs → flusys-ng-iam-permission-page.component-Dpk90y72.mjs} +14 -13
  11. package/fesm2022/flusys-ng-iam-permission-page.component-Dpk90y72.mjs.map +1 -0
  12. package/fesm2022/{flusys-ng-iam-role-form-page.component-D_AAEay2.mjs → flusys-ng-iam-role-form-page.component-CVfRQpoa.mjs} +38 -35
  13. package/fesm2022/flusys-ng-iam-role-form-page.component-CVfRQpoa.mjs.map +1 -0
  14. package/fesm2022/{flusys-ng-iam-role-list-page.component-D4J1by6Q.mjs → flusys-ng-iam-role-list-page.component-BHB8X5r7.mjs} +41 -38
  15. package/fesm2022/flusys-ng-iam-role-list-page.component-BHB8X5r7.mjs.map +1 -0
  16. package/fesm2022/flusys-ng-iam.mjs +1 -1
  17. package/package.json +7 -5
  18. package/types/flusys-ng-iam.d.ts +13 -5
  19. package/fesm2022/flusys-ng-iam-action-form-page.component-eXpZNJ_H.mjs.map +0 -1
  20. package/fesm2022/flusys-ng-iam-action-list-page.component-BtJlGcTj.mjs.map +0 -1
  21. package/fesm2022/flusys-ng-iam-flusys-ng-iam-CJAQT60K.mjs.map +0 -1
  22. package/fesm2022/flusys-ng-iam-iam-container.component-UYJjqYV9.mjs.map +0 -1
  23. package/fesm2022/flusys-ng-iam-permission-page.component-DcgT7L3_.mjs.map +0 -1
  24. package/fesm2022/flusys-ng-iam-role-form-page.component-D_AAEay2.mjs.map +0 -1
  25. package/fesm2022/flusys-ng-iam-role-list-page.component-D4J1by6Q.mjs.map +0 -1
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  | Item | Value |
10
10
  |------|-------|
11
11
  | Package | `@flusys/ng-iam` |
12
- | Version | 3.0.0 |
12
+ | Version | 4.0.0-rc |
13
13
  | Dependencies | ng-core, ng-shared, ng-layout (IMenuItem only) |
14
14
  | CSS Framework | Tailwind CSS (not PrimeFlex) |
15
15
  | Build | `npm run build:ng-iam` |
@@ -604,5 +604,5 @@ Registers `PROFILE_PERMISSION_PROVIDER` with `ProfilePermissionProviderAdapter`.
604
604
  ---
605
605
 
606
606
  **Last Updated:** 2026-02-25
607
- **Version:** 3.0.0
607
+ **Version:** 3.0.1
608
608
  **Angular Version:** 21
@@ -1,12 +1,13 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, signal, computed, effect, ChangeDetectionStrategy, Component } from '@angular/core';
2
+ import { inject, signal, computed, effect, Component } from '@angular/core';
3
3
  import { toSignal } from '@angular/core/rxjs-interop';
4
4
  import { form, required, FormField } from '@angular/forms/signals';
5
5
  import { ActivatedRoute, Router } from '@angular/router';
6
- import { AngularModule, PrimeModule } from '@flusys/ng-shared';
6
+ import { TRANSLATE_ADAPTER } from '@flusys/ng-core';
7
+ import { AngularModule, PrimeModule, TranslatePipe } from '@flusys/ng-shared';
7
8
  import { MessageService } from 'primeng/api';
8
9
  import { firstValueFrom } from 'rxjs';
9
- import { A as ActionApiService, a as ActionType, L as LogicBuilderComponent } from './flusys-ng-iam-flusys-ng-iam-CJAQT60K.mjs';
10
+ import { A as ActionApiService, a as ActionType, L as LogicBuilderComponent } from './flusys-ng-iam-flusys-ng-iam-Co4ot9My.mjs';
10
11
  import * as i1 from '@angular/forms';
11
12
  import * as i2 from 'primeng/button';
12
13
  import * as i3 from 'primeng/checkbox';
@@ -17,8 +18,12 @@ class ActionFormPageComponent {
17
18
  router = inject(Router);
18
19
  actionApi = inject(ActionApiService);
19
20
  messageService = inject(MessageService);
21
+ translateAdapter = inject(TRANSLATE_ADAPTER, { optional: true });
20
22
  routeParams = toSignal(this.route.paramMap);
21
23
  initialized = false;
24
+ translate(key, vars) {
25
+ return this.translateAdapter?.translate(key, vars) ?? key;
26
+ }
22
27
  isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
23
28
  existingAction = signal(null, ...(ngDevMode ? [{ debugName: "existingAction" }] : []));
24
29
  isEditMode = computed(() => !!this.existingAction(), ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
@@ -41,13 +46,13 @@ class ActionFormPageComponent {
41
46
  isActive: true,
42
47
  metadata: null,
43
48
  }, ...(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
+ actionTypes = computed(() => [
50
+ { label: this.translate('iam.action.type.backend.label'), value: ActionType.BACKEND },
51
+ { label: this.translate('iam.action.type.frontend.label'), value: ActionType.FRONTEND },
52
+ { label: this.translate('iam.action.type.both.label'), value: ActionType.BOTH },
53
+ ], ...(ngDevMode ? [{ debugName: "actionTypes" }] : []));
49
54
  actionForm = form(this.formModel, (f) => {
50
- required(f.name, { message: 'Name is required' });
55
+ required(f.name, { message: this.translate('shared.validation.required', { field: this.translate('iam.action.name') }) });
51
56
  });
52
57
  isFormValid = computed(() => {
53
58
  const model = this.formModel();
@@ -69,7 +74,7 @@ class ActionFormPageComponent {
69
74
  select: ['id', 'name', 'code', 'actionType', 'permissionLogic'],
70
75
  }));
71
76
  if (response?.success && response.data) {
72
- this.allActionsForLogic.set(response.data.map((a) => ({ id: a.id, name: a.name ?? 'Unnamed' })));
77
+ this.allActionsForLogic.set(response.data.map((a) => ({ id: a.id, name: a.name ?? this.translate('shared.unnamed') })));
73
78
  this.allActions.set(response.data);
74
79
  }
75
80
  }
@@ -118,8 +123,8 @@ class ActionFormPageComponent {
118
123
  if (!this.isFormValid()) {
119
124
  this.messageService.add({
120
125
  severity: 'error',
121
- summary: 'Validation Error',
122
- detail: 'Please fill in all required fields.',
126
+ summary: this.translate('shared.validation.error'),
127
+ detail: this.translate('shared.fill.required.fields'),
123
128
  });
124
129
  return;
125
130
  }
@@ -137,11 +142,19 @@ class ActionFormPageComponent {
137
142
  };
138
143
  if (this.isEditMode()) {
139
144
  await this.actionApi.updateAsync(dto);
140
- this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Action updated successfully.' });
145
+ this.messageService.add({
146
+ severity: 'success',
147
+ summary: this.translate('shared.success'),
148
+ detail: this.translate('iam.action.update.success'),
149
+ });
141
150
  }
142
151
  else {
143
152
  await this.actionApi.insertAsync(dto);
144
- this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Action created successfully.' });
153
+ this.messageService.add({
154
+ severity: 'success',
155
+ summary: this.translate('shared.success'),
156
+ detail: this.translate('iam.action.create.success'),
157
+ });
145
158
  }
146
159
  this.router.navigate(['/iam/actions']);
147
160
  }
@@ -162,48 +175,48 @@ class ActionFormPageComponent {
162
175
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: ActionFormPageComponent, isStandalone: true, selector: "lib-action-form-page", ngImport: i0, template: `
163
176
  <div class="card">
164
177
  <h3 class="text-lg sm:text-xl font-semibold mb-4">
165
- {{ isEditMode() ? 'Edit Action' : 'New Action' }}
178
+ {{ isEditMode() ? ('iam.action.edit' | translate) : ('iam.action.new' | translate) }}
166
179
  </h3>
167
180
 
168
181
  <form (ngSubmit)="onSubmit()" class="grid grid-cols-1 md:grid-cols-2 gap-4">
169
182
  <!-- Name -->
170
183
  <div class="flex flex-col gap-2">
171
- <label for="name" class="font-medium">Name *</label>
184
+ <label for="name" class="font-medium">{{ 'iam.action.name' | translate }} *</label>
172
185
  <input
173
186
  pInputText
174
187
  id="name"
175
188
  [formField]="actionForm.name"
176
- placeholder="Enter action name" />
189
+ [placeholder]="'iam.action.name.placeholder' | translate" />
177
190
  </div>
178
191
 
179
192
  <!-- Code -->
180
193
  <div class="flex flex-col gap-2">
181
- <label for="code" class="font-medium">Code</label>
194
+ <label for="code" class="font-medium">{{ 'iam.action.code' | translate }}</label>
182
195
  <input
183
196
  pInputText
184
197
  id="code"
185
198
  [formField]="actionForm.code"
186
- placeholder="Enter action code" />
199
+ [placeholder]="'iam.action.code.placeholder' | translate" />
187
200
  </div>
188
201
 
189
202
  <!-- Description -->
190
203
  <div class="flex flex-col gap-2">
191
- <label for="description" class="font-medium">Description</label>
204
+ <label for="description" class="font-medium">{{ 'shared.description' | translate }}</label>
192
205
  <input
193
206
  pInputText
194
207
  id="description"
195
208
  [formField]="actionForm.description"
196
- placeholder="Enter description" />
209
+ [placeholder]="'shared.description.placeholder' | translate" />
197
210
  </div>
198
211
 
199
212
  <!-- Action Type -->
200
213
  <div class="flex flex-col gap-2">
201
- <label for="actionType" class="font-medium">Action Type *</label>
214
+ <label for="actionType" class="font-medium">{{ 'iam.action.type' | translate }} *</label>
202
215
  <select
203
216
  id="actionType"
204
217
  class="p-inputtext w-full"
205
218
  [formField]="actionForm.actionType">
206
- @for (type of actionTypes; track type.value) {
219
+ @for (type of actionTypes(); track type.value) {
207
220
  <option [value]="type.value">{{ type.label }}</option>
208
221
  }
209
222
  </select>
@@ -211,12 +224,12 @@ class ActionFormPageComponent {
211
224
 
212
225
  <!-- Parent Action -->
213
226
  <div class="flex flex-col gap-2">
214
- <label for="parentId" class="font-medium">Parent Action</label>
227
+ <label for="parentId" class="font-medium">{{ 'iam.action.parent' | translate }}</label>
215
228
  <select
216
229
  id="parentId"
217
230
  class="p-inputtext w-full"
218
231
  [formField]="actionForm.parentId">
219
- <option value="">Select parent action</option>
232
+ <option value="">{{ 'iam.action.select.parent' | translate }}</option>
220
233
  @for (action of availableActions(); track action.id) {
221
234
  <option [value]="action.id">{{ action.name }}</option>
222
235
  }
@@ -225,13 +238,13 @@ class ActionFormPageComponent {
225
238
 
226
239
  <!-- Order -->
227
240
  <div class="flex flex-col gap-2">
228
- <label for="serial" class="font-medium">Display Order</label>
241
+ <label for="serial" class="font-medium">{{ 'shared.display.order' | translate }}</label>
229
242
  <input
230
243
  pInputText
231
244
  id="serial"
232
245
  type="number"
233
246
  [formField]="actionForm.serial"
234
- placeholder="Enter display order" />
247
+ [placeholder]="'shared.display.order.placeholder' | translate" />
235
248
  </div>
236
249
 
237
250
  <!-- Is Active -->
@@ -240,7 +253,7 @@ class ActionFormPageComponent {
240
253
  [formField]="actionForm.isActive"
241
254
  [binary]="true"
242
255
  inputId="isActive" />
243
- <label for="isActive">Active</label>
256
+ <label for="isActive">{{ 'shared.active' | translate }}</label>
244
257
  </div>
245
258
 
246
259
  <!-- Permission Logic Builder -->
@@ -254,71 +267,70 @@ class ActionFormPageComponent {
254
267
  <!-- Actions -->
255
268
  <div class="flex justify-end gap-2 md:col-span-2 pt-4">
256
269
  <p-button
257
- label="Cancel"
270
+ [label]="'shared.cancel' | translate"
258
271
  severity="secondary"
259
272
  [outlined]="true"
260
273
  (onClick)="onBack()" />
261
274
  <p-button
262
- [label]="isEditMode() ? 'Update' : 'Create'"
275
+ [label]="isEditMode() ? ('shared.update' | translate) : ('shared.create' | translate)"
263
276
  type="submit"
264
277
  [loading]="isLoading()"
265
278
  [disabled]="!isFormValid() || isLoading()" />
266
279
  </div>
267
280
  </form>
268
281
  </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 });
282
+ `, 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"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
270
283
  }
271
284
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: ActionFormPageComponent, decorators: [{
272
285
  type: Component,
273
286
  args: [{
274
287
  selector: 'lib-action-form-page',
275
- imports: [AngularModule, PrimeModule, FormField, LogicBuilderComponent],
276
- changeDetection: ChangeDetectionStrategy.OnPush,
288
+ imports: [AngularModule, PrimeModule, FormField, LogicBuilderComponent, TranslatePipe],
277
289
  template: `
278
290
  <div class="card">
279
291
  <h3 class="text-lg sm:text-xl font-semibold mb-4">
280
- {{ isEditMode() ? 'Edit Action' : 'New Action' }}
292
+ {{ isEditMode() ? ('iam.action.edit' | translate) : ('iam.action.new' | translate) }}
281
293
  </h3>
282
294
 
283
295
  <form (ngSubmit)="onSubmit()" class="grid grid-cols-1 md:grid-cols-2 gap-4">
284
296
  <!-- Name -->
285
297
  <div class="flex flex-col gap-2">
286
- <label for="name" class="font-medium">Name *</label>
298
+ <label for="name" class="font-medium">{{ 'iam.action.name' | translate }} *</label>
287
299
  <input
288
300
  pInputText
289
301
  id="name"
290
302
  [formField]="actionForm.name"
291
- placeholder="Enter action name" />
303
+ [placeholder]="'iam.action.name.placeholder' | translate" />
292
304
  </div>
293
305
 
294
306
  <!-- Code -->
295
307
  <div class="flex flex-col gap-2">
296
- <label for="code" class="font-medium">Code</label>
308
+ <label for="code" class="font-medium">{{ 'iam.action.code' | translate }}</label>
297
309
  <input
298
310
  pInputText
299
311
  id="code"
300
312
  [formField]="actionForm.code"
301
- placeholder="Enter action code" />
313
+ [placeholder]="'iam.action.code.placeholder' | translate" />
302
314
  </div>
303
315
 
304
316
  <!-- Description -->
305
317
  <div class="flex flex-col gap-2">
306
- <label for="description" class="font-medium">Description</label>
318
+ <label for="description" class="font-medium">{{ 'shared.description' | translate }}</label>
307
319
  <input
308
320
  pInputText
309
321
  id="description"
310
322
  [formField]="actionForm.description"
311
- placeholder="Enter description" />
323
+ [placeholder]="'shared.description.placeholder' | translate" />
312
324
  </div>
313
325
 
314
326
  <!-- Action Type -->
315
327
  <div class="flex flex-col gap-2">
316
- <label for="actionType" class="font-medium">Action Type *</label>
328
+ <label for="actionType" class="font-medium">{{ 'iam.action.type' | translate }} *</label>
317
329
  <select
318
330
  id="actionType"
319
331
  class="p-inputtext w-full"
320
332
  [formField]="actionForm.actionType">
321
- @for (type of actionTypes; track type.value) {
333
+ @for (type of actionTypes(); track type.value) {
322
334
  <option [value]="type.value">{{ type.label }}</option>
323
335
  }
324
336
  </select>
@@ -326,12 +338,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
326
338
 
327
339
  <!-- Parent Action -->
328
340
  <div class="flex flex-col gap-2">
329
- <label for="parentId" class="font-medium">Parent Action</label>
341
+ <label for="parentId" class="font-medium">{{ 'iam.action.parent' | translate }}</label>
330
342
  <select
331
343
  id="parentId"
332
344
  class="p-inputtext w-full"
333
345
  [formField]="actionForm.parentId">
334
- <option value="">Select parent action</option>
346
+ <option value="">{{ 'iam.action.select.parent' | translate }}</option>
335
347
  @for (action of availableActions(); track action.id) {
336
348
  <option [value]="action.id">{{ action.name }}</option>
337
349
  }
@@ -340,13 +352,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
340
352
 
341
353
  <!-- Order -->
342
354
  <div class="flex flex-col gap-2">
343
- <label for="serial" class="font-medium">Display Order</label>
355
+ <label for="serial" class="font-medium">{{ 'shared.display.order' | translate }}</label>
344
356
  <input
345
357
  pInputText
346
358
  id="serial"
347
359
  type="number"
348
360
  [formField]="actionForm.serial"
349
- placeholder="Enter display order" />
361
+ [placeholder]="'shared.display.order.placeholder' | translate" />
350
362
  </div>
351
363
 
352
364
  <!-- Is Active -->
@@ -355,7 +367,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
355
367
  [formField]="actionForm.isActive"
356
368
  [binary]="true"
357
369
  inputId="isActive" />
358
- <label for="isActive">Active</label>
370
+ <label for="isActive">{{ 'shared.active' | translate }}</label>
359
371
  </div>
360
372
 
361
373
  <!-- Permission Logic Builder -->
@@ -369,12 +381,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
369
381
  <!-- Actions -->
370
382
  <div class="flex justify-end gap-2 md:col-span-2 pt-4">
371
383
  <p-button
372
- label="Cancel"
384
+ [label]="'shared.cancel' | translate"
373
385
  severity="secondary"
374
386
  [outlined]="true"
375
387
  (onClick)="onBack()" />
376
388
  <p-button
377
- [label]="isEditMode() ? 'Update' : 'Create'"
389
+ [label]="isEditMode() ? ('shared.update' | translate) : ('shared.create' | translate)"
378
390
  type="submit"
379
391
  [loading]="isLoading()"
380
392
  [disabled]="!isFormValid() || isLoading()" />
@@ -386,4 +398,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
386
398
  }], ctorParameters: () => [] });
387
399
 
388
400
  export { ActionFormPageComponent };
389
- //# sourceMappingURL=flusys-ng-iam-action-form-page.component-eXpZNJ_H.mjs.map
401
+ //# sourceMappingURL=flusys-ng-iam-action-form-page.component-BQx9yset.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flusys-ng-iam-action-form-page.component-BQx9yset.mjs","sources":["../../../projects/ng-iam/pages/action/action-form-page.component.ts"],"sourcesContent":["import { 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 { TRANSLATE_ADAPTER } from '@flusys/ng-core';\nimport { AngularModule, ILogicNode, PrimeModule, TranslatePipe } 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, TranslatePipe],\n template: `\n <div class=\"card\">\n <h3 class=\"text-lg sm:text-xl font-semibold mb-4\">\n {{ isEditMode() ? ('iam.action.edit' | translate) : ('iam.action.new' | translate) }}\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\">{{ 'iam.action.name' | translate }} *</label>\n <input\n pInputText\n id=\"name\"\n [formField]=\"actionForm.name\"\n [placeholder]=\"'iam.action.name.placeholder' | translate\" />\n </div>\n\n <!-- Code -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"code\" class=\"font-medium\">{{ 'iam.action.code' | translate }}</label>\n <input\n pInputText\n id=\"code\"\n [formField]=\"actionForm.code\"\n [placeholder]=\"'iam.action.code.placeholder' | translate\" />\n </div>\n\n <!-- Description -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"description\" class=\"font-medium\">{{ 'shared.description' | translate }}</label>\n <input\n pInputText\n id=\"description\"\n [formField]=\"actionForm.description\"\n [placeholder]=\"'shared.description.placeholder' | translate\" />\n </div>\n\n <!-- Action Type -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"actionType\" class=\"font-medium\">{{ 'iam.action.type' | translate }} *</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\">{{ 'iam.action.parent' | translate }}</label>\n <select\n id=\"parentId\"\n class=\"p-inputtext w-full\"\n [formField]=\"actionForm.parentId\">\n <option value=\"\">{{ 'iam.action.select.parent' | translate }}</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\">{{ 'shared.display.order' | translate }}</label>\n <input\n pInputText\n id=\"serial\"\n type=\"number\"\n [formField]=\"actionForm.serial\"\n [placeholder]=\"'shared.display.order.placeholder' | translate\" />\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\">{{ 'shared.active' | translate }}</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]=\"'shared.cancel' | translate\"\n severity=\"secondary\"\n [outlined]=\"true\"\n (onClick)=\"onBack()\" />\n <p-button\n [label]=\"isEditMode() ? ('shared.update' | translate) : ('shared.create' | translate)\"\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 translateAdapter = inject(TRANSLATE_ADAPTER, { optional: true });\n private readonly routeParams = toSignal(this.route.paramMap);\n private initialized = false;\n\n private translate(key: string, vars?: Record<string, string | number>): string {\n return this.translateAdapter?.translate(key, vars) ?? key;\n }\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 = computed(() => [\n { label: this.translate('iam.action.type.backend.label'), value: ActionType.BACKEND },\n { label: this.translate('iam.action.type.frontend.label'), value: ActionType.FRONTEND },\n { label: this.translate('iam.action.type.both.label'), value: ActionType.BOTH },\n ]);\n\n readonly actionForm = form(this.formModel, (f) => {\n required(f.name, { message: this.translate('shared.validation.required', { field: this.translate('iam.action.name') }) });\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 ?? this.translate('shared.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: this.translate('shared.validation.error'),\n detail: this.translate('shared.fill.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({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: this.translate('iam.action.update.success'),\n });\n } else {\n await this.actionApi.insertAsync(dto);\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: this.translate('iam.action.create.success'),\n });\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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"}