@flusys/ng-iam 1.1.1-beta → 1.2.0-rc.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.
Files changed (32) hide show
  1. package/README.md +44 -1027
  2. package/fesm2022/flusys-ng-iam-action-form-page.component-Vc5Toouu.mjs +502 -0
  3. package/fesm2022/flusys-ng-iam-action-form-page.component-Vc5Toouu.mjs.map +1 -0
  4. package/fesm2022/flusys-ng-iam-action-list-page.component-UGKclpFx.mjs +348 -0
  5. package/fesm2022/flusys-ng-iam-action-list-page.component-UGKclpFx.mjs.map +1 -0
  6. package/fesm2022/flusys-ng-iam-flusys-ng-iam-CrycDULz.mjs +4561 -0
  7. package/fesm2022/flusys-ng-iam-flusys-ng-iam-CrycDULz.mjs.map +1 -0
  8. package/fesm2022/flusys-ng-iam-iam-container.component-D0m8u6nu.mjs +105 -0
  9. package/fesm2022/flusys-ng-iam-iam-container.component-D0m8u6nu.mjs.map +1 -0
  10. package/fesm2022/flusys-ng-iam-permission-page.component-x88X4AgJ.mjs +143 -0
  11. package/fesm2022/flusys-ng-iam-permission-page.component-x88X4AgJ.mjs.map +1 -0
  12. package/fesm2022/flusys-ng-iam-role-form-page.component-InsxdriD.mjs +335 -0
  13. package/fesm2022/flusys-ng-iam-role-form-page.component-InsxdriD.mjs.map +1 -0
  14. package/fesm2022/flusys-ng-iam-role-list-page.component-8NGXCeSZ.mjs +389 -0
  15. package/fesm2022/flusys-ng-iam-role-list-page.component-8NGXCeSZ.mjs.map +1 -0
  16. package/fesm2022/flusys-ng-iam.mjs +1 -1
  17. package/package.json +11 -10
  18. package/types/flusys-ng-iam.d.ts +107 -686
  19. package/fesm2022/flusys-ng-iam-action-form-page.component-C1j10Qhw.mjs +0 -467
  20. package/fesm2022/flusys-ng-iam-action-form-page.component-C1j10Qhw.mjs.map +0 -1
  21. package/fesm2022/flusys-ng-iam-action-list-page.component-BCzSardO.mjs +0 -281
  22. package/fesm2022/flusys-ng-iam-action-list-page.component-BCzSardO.mjs.map +0 -1
  23. package/fesm2022/flusys-ng-iam-flusys-ng-iam-DISrddPh.mjs +0 -4940
  24. package/fesm2022/flusys-ng-iam-flusys-ng-iam-DISrddPh.mjs.map +0 -1
  25. package/fesm2022/flusys-ng-iam-iam-container.component-BkhqmzLi.mjs +0 -97
  26. package/fesm2022/flusys-ng-iam-iam-container.component-BkhqmzLi.mjs.map +0 -1
  27. package/fesm2022/flusys-ng-iam-permission-page.component-BSQFPt_N.mjs +0 -143
  28. package/fesm2022/flusys-ng-iam-permission-page.component-BSQFPt_N.mjs.map +0 -1
  29. package/fesm2022/flusys-ng-iam-role-form-page.component-Cqziu_BM.mjs +0 -314
  30. package/fesm2022/flusys-ng-iam-role-form-page.component-Cqziu_BM.mjs.map +0 -1
  31. package/fesm2022/flusys-ng-iam-role-list-page.component-BObCxHiB.mjs +0 -266
  32. package/fesm2022/flusys-ng-iam-role-list-page.component-BObCxHiB.mjs.map +0 -1
@@ -0,0 +1,105 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, computed, Component } from '@angular/core';
3
+ import { RouterOutlet } from '@angular/router';
4
+ import { APP_CONFIG, getPermissionMode } from '@flusys/ng-core';
5
+ import { PermissionValidatorService, TranslateService, ACTION_PERMISSIONS, ROLE_PERMISSIONS, ROLE_ACTION_PERMISSIONS, USER_ROLE_PERMISSIONS, USER_ACTION_PERMISSIONS, COMPANY_ACTION_PERMISSIONS, RouterTabsComponent, TranslatePipe } from '@flusys/ng-shared';
6
+
7
+ /**
8
+ * IAM Container Component
9
+ *
10
+ * Main container for IAM module with tab navigation
11
+ * Routes: Actions | Roles (conditional) | Users (permission assignment)
12
+ */
13
+ class IamContainerComponent {
14
+ appConfig = inject(APP_CONFIG);
15
+ permissionValidator = inject(PermissionValidatorService);
16
+ translateService = inject(TranslateService);
17
+ /** All available tabs */
18
+ allTabs = [
19
+ {
20
+ id: 'actions',
21
+ labelKey: 'iam.action.title',
22
+ icon: 'bolt',
23
+ route: 'actions',
24
+ permission: [ACTION_PERMISSIONS.READ],
25
+ },
26
+ {
27
+ id: 'roles',
28
+ labelKey: 'iam.role.title',
29
+ icon: 'shield',
30
+ route: 'roles',
31
+ requiresRBAC: true,
32
+ permission: [ROLE_PERMISSIONS.READ],
33
+ },
34
+ {
35
+ id: 'permissions',
36
+ labelKey: 'iam.permission.title',
37
+ icon: 'key',
38
+ route: 'permissions',
39
+ permission: [
40
+ ROLE_ACTION_PERMISSIONS.READ,
41
+ USER_ROLE_PERMISSIONS.READ,
42
+ USER_ACTION_PERMISSIONS.READ,
43
+ COMPANY_ACTION_PERMISSIONS.READ,
44
+ ],
45
+ },
46
+ ];
47
+ /** Visible tabs based on permission mode */
48
+ visibleTabs = computed(() => {
49
+ const permissionMode = getPermissionMode(this.appConfig);
50
+ return this.allTabs
51
+ .filter((tab) => {
52
+ const hasPermission = this.permissionValidator.hasAnyPermission(tab.permission);
53
+ return (hasPermission &&
54
+ (!tab.requiresRBAC ||
55
+ permissionMode === 'rbac' ||
56
+ permissionMode === 'full'));
57
+ })
58
+ .map((tab) => ({
59
+ id: tab.id,
60
+ label: this.translateService.translate(tab.labelKey),
61
+ icon: tab.icon,
62
+ route: tab.route,
63
+ }));
64
+ }, /* @ts-ignore */
65
+ ...(ngDevMode ? [{ debugName: "visibleTabs" }] : /* istanbul ignore next */ []));
66
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: IamContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
67
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.6", type: IamContainerComponent, isStandalone: true, selector: "lib-iam-container", ngImport: i0, template: `
68
+ <div class="p-4">
69
+ <div class="mb-4">
70
+ <h1 class="text-xl sm:text-2xl font-bold m-0">
71
+ {{ 'iam.title' | translate }}
72
+ </h1>
73
+ <p class="text-muted-color mt-1">{{ 'iam.subtitle' | translate }}</p>
74
+ </div>
75
+
76
+ <lib-router-tabs [tabs]="visibleTabs()" class="mb-4" />
77
+
78
+ <router-outlet />
79
+ </div>
80
+ `, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: RouterTabsComponent, selector: "lib-router-tabs", inputs: ["tabs"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
81
+ }
82
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: IamContainerComponent, decorators: [{
83
+ type: Component,
84
+ args: [{
85
+ selector: 'lib-iam-container',
86
+ imports: [RouterOutlet, TranslatePipe, RouterTabsComponent],
87
+ template: `
88
+ <div class="p-4">
89
+ <div class="mb-4">
90
+ <h1 class="text-xl sm:text-2xl font-bold m-0">
91
+ {{ 'iam.title' | translate }}
92
+ </h1>
93
+ <p class="text-muted-color mt-1">{{ 'iam.subtitle' | translate }}</p>
94
+ </div>
95
+
96
+ <lib-router-tabs [tabs]="visibleTabs()" class="mb-4" />
97
+
98
+ <router-outlet />
99
+ </div>
100
+ `,
101
+ }]
102
+ }] });
103
+
104
+ export { IamContainerComponent };
105
+ //# sourceMappingURL=flusys-ng-iam-iam-container.component-D0m8u6nu.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flusys-ng-iam-iam-container.component-D0m8u6nu.mjs","sources":["../../../projects/ng-iam/pages/iam-container/iam-container.component.ts"],"sourcesContent":["import { Component, computed, inject } from '@angular/core';\nimport { RouterOutlet } from '@angular/router';\nimport { APP_CONFIG, getPermissionMode } from '@flusys/ng-core';\nimport {\n ACTION_PERMISSIONS,\n COMPANY_ACTION_PERMISSIONS,\n PermissionValidatorService,\n ROLE_ACTION_PERMISSIONS,\n ROLE_PERMISSIONS,\n RouterTabItem,\n RouterTabsComponent,\n TranslatePipe,\n TranslateService,\n USER_ACTION_PERMISSIONS,\n USER_ROLE_PERMISSIONS,\n} from '@flusys/ng-shared';\n\ninterface ITab {\n id: string;\n labelKey: string;\n icon: string;\n route: string;\n requiresRBAC?: boolean;\n permission: string[];\n}\n\n/**\n * IAM Container Component\n *\n * Main container for IAM module with tab navigation\n * Routes: Actions | Roles (conditional) | Users (permission assignment)\n */\n@Component({\n selector: 'lib-iam-container',\n imports: [RouterOutlet, TranslatePipe, RouterTabsComponent],\n template: `\n <div class=\"p-4\">\n <div class=\"mb-4\">\n <h1 class=\"text-xl sm:text-2xl font-bold m-0\">\n {{ 'iam.title' | translate }}\n </h1>\n <p class=\"text-muted-color mt-1\">{{ 'iam.subtitle' | translate }}</p>\n </div>\n\n <lib-router-tabs [tabs]=\"visibleTabs()\" class=\"mb-4\" />\n\n <router-outlet />\n </div>\n `,\n})\nexport class IamContainerComponent {\n private readonly appConfig = inject(APP_CONFIG);\n\n private readonly permissionValidator = inject(PermissionValidatorService);\n private readonly translateService = inject(TranslateService);\n\n /** All available tabs */\n private readonly allTabs: ITab[] = [\n {\n id: 'actions',\n labelKey: 'iam.action.title',\n icon: 'bolt',\n route: 'actions',\n permission: [ACTION_PERMISSIONS.READ],\n },\n {\n id: 'roles',\n labelKey: 'iam.role.title',\n icon: 'shield',\n route: 'roles',\n requiresRBAC: true,\n permission: [ROLE_PERMISSIONS.READ],\n },\n {\n id: 'permissions',\n labelKey: 'iam.permission.title',\n icon: 'key',\n route: 'permissions',\n permission: [\n ROLE_ACTION_PERMISSIONS.READ,\n USER_ROLE_PERMISSIONS.READ,\n USER_ACTION_PERMISSIONS.READ,\n COMPANY_ACTION_PERMISSIONS.READ,\n ],\n },\n ];\n\n /** Visible tabs based on permission mode */\n readonly visibleTabs = computed<RouterTabItem[]>(() => {\n const permissionMode = getPermissionMode(this.appConfig);\n return this.allTabs\n .filter((tab) => {\n const hasPermission = this.permissionValidator.hasAnyPermission(\n tab.permission,\n );\n return (\n hasPermission &&\n (!tab.requiresRBAC ||\n permissionMode === 'rbac' ||\n permissionMode === 'full')\n );\n })\n .map((tab) => ({\n id: tab.id,\n label: this.translateService.translate(tab.labelKey),\n icon: tab.icon,\n route: tab.route,\n }));\n });\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, signal, computed, effect, untracked, Component } from '@angular/core';
3
+ import { COMPANY_ACTION_PERMISSIONS, USER_ACTION_PERMISSIONS, USER_ROLE_PERMISSIONS, ROLE_ACTION_PERMISSIONS, AngularModule, HasPermissionDirective, TranslatePipe } from '@flusys/ng-shared';
4
+ import { APP_CONFIG, getPermissionMode, isCompanyFeatureEnabled } from '@flusys/ng-core';
5
+ import { b as RoleActionSelectorComponent, C as CompanyActionSelectorComponent, U as UserRoleSelectorComponent, d as UserActionSelectorComponent } from './flusys-ng-iam-flusys-ng-iam-CrycDULz.mjs';
6
+ import * as i2 from '@flusys/ng-ui';
7
+ import { UiModule } from '@flusys/ng-ui';
8
+
9
+ /** Permission codes for each tab */
10
+ const TAB_PERMISSIONS = {
11
+ 'role-actions': ROLE_ACTION_PERMISSIONS.READ,
12
+ 'user-roles': USER_ROLE_PERMISSIONS.READ,
13
+ 'user-actions': USER_ACTION_PERMISSIONS.READ,
14
+ 'company-actions': COMPANY_ACTION_PERMISSIONS.READ,
15
+ };
16
+ /** Main permission management interface with tabs for role/user/company permission assignment */
17
+ class PermissionPageComponent {
18
+ appConfig = inject(APP_CONFIG);
19
+ activeTab = signal('', /* @ts-ignore */
20
+ ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
21
+ /** Available tabs based on permission mode */
22
+ availableTabs = computed(() => {
23
+ const permissionMode = getPermissionMode(this.appConfig);
24
+ const tabs = [];
25
+ if (permissionMode === 'rbac' || permissionMode === 'full') {
26
+ tabs.push({ id: 'role-actions', labelKey: 'iam.permission.role.actions', icon: 'shield', permission: TAB_PERMISSIONS['role-actions'] }, { id: 'user-roles', labelKey: 'iam.permission.user.roles', icon: 'user', permission: TAB_PERMISSIONS['user-roles'] });
27
+ }
28
+ if (permissionMode === 'direct' || permissionMode === 'full') {
29
+ tabs.push({ id: 'user-actions', labelKey: 'iam.permission.user.actions', icon: 'key', permission: TAB_PERMISSIONS['user-actions'] });
30
+ }
31
+ if (isCompanyFeatureEnabled(this.appConfig)) {
32
+ tabs.push({ id: 'company-actions', labelKey: 'iam.permission.company.actions', icon: 'building', permission: TAB_PERMISSIONS['company-actions'] });
33
+ }
34
+ return tabs;
35
+ }, /* @ts-ignore */
36
+ ...(ngDevMode ? [{ debugName: "availableTabs" }] : /* istanbul ignore next */ []));
37
+ constructor() {
38
+ effect(() => {
39
+ const tabs = this.availableTabs();
40
+ const currentTab = untracked(() => this.activeTab());
41
+ if (!currentTab || !tabs.some((t) => t.id === currentTab)) {
42
+ if (tabs.length > 0) {
43
+ this.activeTab.set(tabs[0].id);
44
+ }
45
+ }
46
+ });
47
+ }
48
+ setActiveTab(tabId) {
49
+ this.activeTab.set(tabId);
50
+ }
51
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: PermissionPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
52
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: PermissionPageComponent, isStandalone: true, selector: "lib-permission-page", ngImport: i0, template: `
53
+ <div class="card">
54
+ <h3 class="text-xl font-semibold mb-4">{{ 'iam.permission.title' | translate }}</h3>
55
+
56
+ <div class="scrollbar-hide flex gap-2 mb-4 overflow-x-auto flex-nowrap">
57
+ @for (tab of availableTabs(); track tab.id) {
58
+ <button
59
+ fButton
60
+ *hasPermission="tab.permission"
61
+ [outlined]="activeTab() !== tab.id"
62
+ size="small"
63
+ class="shrink-0"
64
+ (click)="setActiveTab(tab.id)"
65
+ >
66
+ <ui-icon pButtonIcon [name]="tab.icon"></ui-icon>
67
+ <span pButtonLabel>{{ tab.labelKey | translate }}</span>
68
+ </button>
69
+ }
70
+ </div>
71
+
72
+ <div class="mt-4">
73
+ @switch (activeTab()) {
74
+ @case ('role-actions') {
75
+ <flusys-role-action-selector />
76
+ }
77
+ @case ('user-roles') {
78
+ <flusys-user-role-selector />
79
+ }
80
+ @case ('user-actions') {
81
+ <flusys-user-action-selector />
82
+ }
83
+ @case ('company-actions') {
84
+ <flusys-company-action-selector />
85
+ }
86
+ }
87
+ </div>
88
+ </div>
89
+ `, isInline: true, styles: [".scrollbar-hide{-ms-overflow-style:none;scrollbar-width:none}.scrollbar-hide::-webkit-scrollbar{display:none}\n"], dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: UiModule }, { kind: "directive", type: i2.FButtonDirective, selector: "[fButton]", inputs: ["severity", "text", "outlined", "link", "variant", "rounded", "raised", "fluid", "disabled", "loading", "loadingIcon", "size", "label", "icon", "iconPos", "ariaLabel", "plain"] }, { kind: "component", type: i2.UiIconComponent, selector: "ui-icon", inputs: ["name", "size", "spin", "fill", "severity"] }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }, { kind: "component", type: RoleActionSelectorComponent, selector: "flusys-role-action-selector" }, { kind: "component", type: CompanyActionSelectorComponent, selector: "flusys-company-action-selector" }, { kind: "component", type: UserRoleSelectorComponent, selector: "flusys-user-role-selector" }, { kind: "component", type: UserActionSelectorComponent, selector: "flusys-user-action-selector" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
90
+ }
91
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: PermissionPageComponent, decorators: [{
92
+ type: Component,
93
+ args: [{ selector: 'lib-permission-page', imports: [
94
+ AngularModule,
95
+ UiModule,
96
+ HasPermissionDirective,
97
+ TranslatePipe,
98
+ RoleActionSelectorComponent,
99
+ CompanyActionSelectorComponent,
100
+ UserRoleSelectorComponent,
101
+ UserActionSelectorComponent
102
+ ], template: `
103
+ <div class="card">
104
+ <h3 class="text-xl font-semibold mb-4">{{ 'iam.permission.title' | translate }}</h3>
105
+
106
+ <div class="scrollbar-hide flex gap-2 mb-4 overflow-x-auto flex-nowrap">
107
+ @for (tab of availableTabs(); track tab.id) {
108
+ <button
109
+ fButton
110
+ *hasPermission="tab.permission"
111
+ [outlined]="activeTab() !== tab.id"
112
+ size="small"
113
+ class="shrink-0"
114
+ (click)="setActiveTab(tab.id)"
115
+ >
116
+ <ui-icon pButtonIcon [name]="tab.icon"></ui-icon>
117
+ <span pButtonLabel>{{ tab.labelKey | translate }}</span>
118
+ </button>
119
+ }
120
+ </div>
121
+
122
+ <div class="mt-4">
123
+ @switch (activeTab()) {
124
+ @case ('role-actions') {
125
+ <flusys-role-action-selector />
126
+ }
127
+ @case ('user-roles') {
128
+ <flusys-user-role-selector />
129
+ }
130
+ @case ('user-actions') {
131
+ <flusys-user-action-selector />
132
+ }
133
+ @case ('company-actions') {
134
+ <flusys-company-action-selector />
135
+ }
136
+ }
137
+ </div>
138
+ </div>
139
+ `, styles: [".scrollbar-hide{-ms-overflow-style:none;scrollbar-width:none}.scrollbar-hide::-webkit-scrollbar{display:none}\n"] }]
140
+ }], ctorParameters: () => [] });
141
+
142
+ export { PermissionPageComponent };
143
+ //# sourceMappingURL=flusys-ng-iam-permission-page.component-x88X4AgJ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flusys-ng-iam-permission-page.component-x88X4AgJ.mjs","sources":["../../../projects/ng-iam/pages/permission/permission-page.component.ts"],"sourcesContent":["import { Component, computed, effect, inject, signal, untracked } from '@angular/core';\nimport {\n AngularModule,\n HasPermissionDirective,\n ROLE_ACTION_PERMISSIONS,\n USER_ROLE_PERMISSIONS,\n USER_ACTION_PERMISSIONS,\n COMPANY_ACTION_PERMISSIONS,\n TranslatePipe,\n} from '@flusys/ng-shared';\nimport { APP_CONFIG, getPermissionMode, isCompanyFeatureEnabled } from '@flusys/ng-core';\nimport { RoleActionSelectorComponent } from '../../components/role-action-selector.component';\nimport { CompanyActionSelectorComponent } from '../../components/company-action-selector.component';\nimport { UserRoleSelectorComponent } from '../../components/user-role-selector.component';\nimport { UserActionSelectorComponent } from '../../components/user-action-selector.component';\nimport { UiModule } from '@flusys/ng-ui';\n\n/** Permission codes for each tab */\nconst TAB_PERMISSIONS = {\n 'role-actions': ROLE_ACTION_PERMISSIONS.READ,\n 'user-roles': USER_ROLE_PERMISSIONS.READ,\n 'user-actions': USER_ACTION_PERMISSIONS.READ,\n 'company-actions': COMPANY_ACTION_PERMISSIONS.READ,\n} as const;\n\n/** Main permission management interface with tabs for role/user/company permission assignment */\n@Component({\n selector: 'lib-permission-page',\n imports: [\n AngularModule,\n UiModule,\n HasPermissionDirective,\n TranslatePipe,\n RoleActionSelectorComponent,\n CompanyActionSelectorComponent,\n UserRoleSelectorComponent,\n UserActionSelectorComponent\n ],\n styles: `\n .scrollbar-hide {\n -ms-overflow-style: none;\n scrollbar-width: none;\n &::-webkit-scrollbar { display: none; }\n }\n `,\n template: `\n <div class=\"card\">\n <h3 class=\"text-xl font-semibold mb-4\">{{ 'iam.permission.title' | translate }}</h3>\n\n <div class=\"scrollbar-hide flex gap-2 mb-4 overflow-x-auto flex-nowrap\">\n @for (tab of availableTabs(); track tab.id) {\n <button\n fButton\n *hasPermission=\"tab.permission\"\n [outlined]=\"activeTab() !== tab.id\"\n size=\"small\"\n class=\"shrink-0\"\n (click)=\"setActiveTab(tab.id)\"\n >\n <ui-icon pButtonIcon [name]=\"tab.icon\"></ui-icon>\n <span pButtonLabel>{{ tab.labelKey | translate }}</span>\n </button>\n }\n </div>\n\n <div class=\"mt-4\">\n @switch (activeTab()) {\n @case ('role-actions') {\n <flusys-role-action-selector />\n }\n @case ('user-roles') {\n <flusys-user-role-selector />\n }\n @case ('user-actions') {\n <flusys-user-action-selector />\n }\n @case ('company-actions') {\n <flusys-company-action-selector />\n }\n }\n </div>\n </div>\n `,\n})\nexport class PermissionPageComponent {\n private readonly appConfig = inject(APP_CONFIG);\n\n readonly activeTab = signal<string>('');\n\n /** Available tabs based on permission mode */\n readonly availableTabs = computed(() => {\n const permissionMode = getPermissionMode(this.appConfig);\n const tabs: Array<{ id: string; labelKey: string; icon: string; permission: string }> = [];\n\n if (permissionMode === 'rbac' || permissionMode === 'full') {\n tabs.push(\n { id: 'role-actions', labelKey: 'iam.permission.role.actions', icon: 'shield', permission: TAB_PERMISSIONS['role-actions'] },\n { id: 'user-roles', labelKey: 'iam.permission.user.roles', icon: 'user', permission: TAB_PERMISSIONS['user-roles'] }\n );\n }\n\n if (permissionMode === 'direct' || permissionMode === 'full') {\n tabs.push({ id: 'user-actions', labelKey: 'iam.permission.user.actions', icon: 'key', permission: TAB_PERMISSIONS['user-actions'] });\n }\n\n if (isCompanyFeatureEnabled(this.appConfig)) {\n tabs.push({ id: 'company-actions', labelKey: 'iam.permission.company.actions', icon: 'building', permission: TAB_PERMISSIONS['company-actions'] });\n }\n\n return tabs;\n });\n\n constructor() {\n effect(() => {\n const tabs = this.availableTabs();\n const currentTab = untracked(() => this.activeTab());\n if (!currentTab || !tabs.some((t) => t.id === currentTab)) {\n if (tabs.length > 0) {\n this.activeTab.set(tabs[0].id);\n }\n }\n });\n }\n\n setActiveTab(tabId: string): void {\n this.activeTab.set(tabId);\n }\n}\n"],"names":["i1"],"mappings":"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"}
@@ -0,0 +1,335 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, signal, computed, effect, 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 { APP_CONFIG, isCompanyFeatureEnabled } from '@flusys/ng-core';
7
+ import { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';
8
+ import * as i2 from '@flusys/ng-ui';
9
+ import { MessageService, UiModule } from '@flusys/ng-ui';
10
+ import { TranslateService, AngularModule, TranslatePipe } from '@flusys/ng-shared';
11
+ import { R as RoleApiService } from './flusys-ng-iam-flusys-ng-iam-CrycDULz.mjs';
12
+ import * as i1 from '@angular/forms';
13
+
14
+ class RoleFormPageComponent {
15
+ route = inject(ActivatedRoute);
16
+ router = inject(Router);
17
+ appConfig = inject(APP_CONFIG);
18
+ companyContext = inject(LAYOUT_AUTH_STATE);
19
+ roleApi = inject(RoleApiService);
20
+ messageService = inject(MessageService);
21
+ translateAdapter = inject(TranslateService, {
22
+ optional: true,
23
+ });
24
+ routeParams = toSignal(this.route.paramMap);
25
+ initialized = false;
26
+ translate(key, vars) {
27
+ return this.translateAdapter?.translate(key, vars) ?? key;
28
+ }
29
+ isLoading = signal(false, /* @ts-ignore */
30
+ ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
31
+ existingRole = signal(null, /* @ts-ignore */
32
+ ...(ngDevMode ? [{ debugName: "existingRole" }] : /* istanbul ignore next */ []));
33
+ isEditMode = computed(() => !!this.existingRole(), /* @ts-ignore */
34
+ ...(ngDevMode ? [{ debugName: "isEditMode" }] : /* istanbul ignore next */ []));
35
+ formModel = signal({
36
+ id: '',
37
+ name: '',
38
+ description: '',
39
+ serial: '',
40
+ isActive: true,
41
+ }, /* @ts-ignore */
42
+ ...(ngDevMode ? [{ debugName: "formModel" }] : /* istanbul ignore next */ []));
43
+ roleForm = form(this.formModel, (f) => {
44
+ required(f.name, {
45
+ message: this.translate('shared.validation.required', {
46
+ field: this.translate('iam.role.name'),
47
+ }),
48
+ });
49
+ });
50
+ isFormValid = computed(() => {
51
+ const model = this.formModel();
52
+ return model.name.trim().length > 0;
53
+ }, /* @ts-ignore */
54
+ ...(ngDevMode ? [{ debugName: "isFormValid" }] : /* istanbul ignore next */ []));
55
+ constructor() {
56
+ effect(() => {
57
+ const params = this.routeParams();
58
+ if (!params || this.initialized)
59
+ return;
60
+ this.initialized = true;
61
+ const id = params.get('id');
62
+ if (id && id !== 'new') {
63
+ this.loadRole(id);
64
+ }
65
+ });
66
+ }
67
+ async loadRole(id) {
68
+ this.isLoading.set(true);
69
+ try {
70
+ const response = await this.roleApi.findById(id);
71
+ const role = response?.data;
72
+ if (role) {
73
+ this.existingRole.set(role);
74
+ this.formModel.set({
75
+ id: role.id,
76
+ name: role.name,
77
+ description: role.description ?? '',
78
+ serial: role.serial?.toString() ?? '',
79
+ isActive: role.isActive,
80
+ });
81
+ }
82
+ else {
83
+ // Error toast handled by global interceptor
84
+ this.router.navigate(['/iam/roles']);
85
+ }
86
+ }
87
+ catch {
88
+ // Error toast handled by global interceptor
89
+ this.router.navigate(['/iam/roles']);
90
+ }
91
+ finally {
92
+ this.isLoading.set(false);
93
+ }
94
+ }
95
+ async onSubmit() {
96
+ if (!this.isFormValid()) {
97
+ this.messageService.add({
98
+ severity: 'error',
99
+ summary: this.translate('shared.validation.error'),
100
+ detail: this.translate('shared.fill.required.fields'),
101
+ });
102
+ return;
103
+ }
104
+ this.isLoading.set(true);
105
+ try {
106
+ const formValue = this.formModel();
107
+ // Get company context if feature enabled
108
+ const companyId = isCompanyFeatureEnabled(this.appConfig)
109
+ ? this.companyContext.currentCompanyInfo()?.id || undefined
110
+ : undefined;
111
+ // Convert empty strings to undefined for DTO compatibility
112
+ const dto = {
113
+ ...formValue,
114
+ description: formValue.description || undefined,
115
+ serial: formValue.serial ? parseInt(formValue.serial, 10) : undefined,
116
+ companyId: this.isEditMode() ? undefined : companyId,
117
+ };
118
+ const response = this.isEditMode()
119
+ ? await this.roleApi.update(dto)
120
+ : await this.roleApi.insert(dto);
121
+ this.messageService.add({
122
+ severity: 'success',
123
+ summary: this.translate('shared.success'),
124
+ detail: response.messageKey
125
+ ? this.translate(response.messageKey, response.messageVariables)
126
+ : (response.message ?? ''),
127
+ });
128
+ this.router.navigate(['/iam/roles']);
129
+ }
130
+ catch {
131
+ // Error toast handled by global interceptor
132
+ }
133
+ finally {
134
+ this.isLoading.set(false);
135
+ }
136
+ }
137
+ onBack() {
138
+ this.router.navigate(['/iam/roles']);
139
+ }
140
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: RoleFormPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
141
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: RoleFormPageComponent, isStandalone: true, selector: "lib-role-form-page", ngImport: i0, template: `
142
+ <div class="card">
143
+ <h3 class="text-lg sm:text-xl font-semibold mb-4">
144
+ {{
145
+ isEditMode()
146
+ ? ('iam.role.edit' | translate)
147
+ : ('iam.role.new' | translate)
148
+ }}
149
+ </h3>
150
+
151
+ <form
152
+ (ngSubmit)="onSubmit()"
153
+ class="grid grid-cols-1 md:grid-cols-2 gap-4"
154
+ >
155
+ <!-- Name -->
156
+ <div class="flex flex-col gap-2">
157
+ <label for="name" class="font-medium"
158
+ >{{ 'iam.role.name' | translate }} *</label
159
+ >
160
+ <input
161
+ fInputText
162
+ id="name"
163
+ [formField]="roleForm.name"
164
+ [placeholder]="'iam.role.name.placeholder' | translate"
165
+ />
166
+ </div>
167
+
168
+ <!-- Description -->
169
+ <div class="flex flex-col gap-2">
170
+ <label for="description" class="font-medium">{{
171
+ 'shared.description' | translate
172
+ }}</label>
173
+ <input
174
+ fInputText
175
+ id="description"
176
+ [formField]="roleForm.description"
177
+ [placeholder]="'shared.description.placeholder' | translate"
178
+ />
179
+ </div>
180
+
181
+ <!-- Order -->
182
+ <div class="flex flex-col gap-2">
183
+ <label for="serial" class="font-medium">{{
184
+ 'shared.display.order' | translate
185
+ }}</label>
186
+ <input
187
+ fInputText
188
+ id="serial"
189
+ type="number"
190
+ [formField]="roleForm.serial"
191
+ [placeholder]="'shared.display.order.placeholder' | translate"
192
+ />
193
+ </div>
194
+
195
+ <!-- Is Active -->
196
+ <div class="flex items-end gap-2 pb-1">
197
+ <f-checkbox
198
+ [formField]="roleForm.isActive"
199
+ [binary]="true"
200
+ inputId="isActive"
201
+ />
202
+ <label for="isActive">{{ 'shared.active' | translate }}</label>
203
+ </div>
204
+
205
+ <!-- Actions -->
206
+ <div class="flex justify-end gap-2 md:col-span-2 pt-4">
207
+ <button
208
+ fButton
209
+ severity="secondary"
210
+ [outlined]="true"
211
+ (click)="onBack()"
212
+ >
213
+ <span pButtonLabel>{{ 'shared.cancel' | translate }}</span>
214
+ </button>
215
+ <button
216
+ fButton
217
+ type="submit"
218
+ [disabled]="!isFormValid() || isLoading()"
219
+ >
220
+ @if (isLoading()) {
221
+ <ui-icon pButtonIcon name="spinner" [spin]="true"></ui-icon>
222
+ }
223
+ <span pButtonLabel>{{
224
+ isEditMode()
225
+ ? ('shared.update' | translate)
226
+ : ('shared.create' | translate)
227
+ }}</span>
228
+ </button>
229
+ </div>
230
+ </form>
231
+ </div>
232
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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: UiModule }, { kind: "directive", type: i2.FButtonDirective, selector: "[fButton]", inputs: ["severity", "text", "outlined", "link", "variant", "rounded", "raised", "fluid", "disabled", "loading", "loadingIcon", "size", "label", "icon", "iconPos", "ariaLabel", "plain"] }, { kind: "component", type: i2.CheckboxComponent, selector: "f-checkbox", inputs: ["label", "binary", "disabled", "readonly", "inputId", "invalid", "indeterminate", "variant", "size", "touched", "styleClass", "style", "checked"], outputs: ["onChange", "onBlur", "touch", "checkedChange"] }, { kind: "directive", type: i2.InputTextDirective, selector: "[fInputText]", inputs: ["invalid", "touched", "variant", "size", "fluid"] }, { kind: "component", type: i2.UiIconComponent, selector: "ui-icon", inputs: ["name", "size", "spin", "fill", "severity"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"], exportAs: ["formField"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
233
+ }
234
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: RoleFormPageComponent, decorators: [{
235
+ type: Component,
236
+ args: [{
237
+ selector: 'lib-role-form-page',
238
+ imports: [AngularModule, UiModule, FormField, TranslatePipe],
239
+ template: `
240
+ <div class="card">
241
+ <h3 class="text-lg sm:text-xl font-semibold mb-4">
242
+ {{
243
+ isEditMode()
244
+ ? ('iam.role.edit' | translate)
245
+ : ('iam.role.new' | translate)
246
+ }}
247
+ </h3>
248
+
249
+ <form
250
+ (ngSubmit)="onSubmit()"
251
+ class="grid grid-cols-1 md:grid-cols-2 gap-4"
252
+ >
253
+ <!-- Name -->
254
+ <div class="flex flex-col gap-2">
255
+ <label for="name" class="font-medium"
256
+ >{{ 'iam.role.name' | translate }} *</label
257
+ >
258
+ <input
259
+ fInputText
260
+ id="name"
261
+ [formField]="roleForm.name"
262
+ [placeholder]="'iam.role.name.placeholder' | translate"
263
+ />
264
+ </div>
265
+
266
+ <!-- Description -->
267
+ <div class="flex flex-col gap-2">
268
+ <label for="description" class="font-medium">{{
269
+ 'shared.description' | translate
270
+ }}</label>
271
+ <input
272
+ fInputText
273
+ id="description"
274
+ [formField]="roleForm.description"
275
+ [placeholder]="'shared.description.placeholder' | translate"
276
+ />
277
+ </div>
278
+
279
+ <!-- Order -->
280
+ <div class="flex flex-col gap-2">
281
+ <label for="serial" class="font-medium">{{
282
+ 'shared.display.order' | translate
283
+ }}</label>
284
+ <input
285
+ fInputText
286
+ id="serial"
287
+ type="number"
288
+ [formField]="roleForm.serial"
289
+ [placeholder]="'shared.display.order.placeholder' | translate"
290
+ />
291
+ </div>
292
+
293
+ <!-- Is Active -->
294
+ <div class="flex items-end gap-2 pb-1">
295
+ <f-checkbox
296
+ [formField]="roleForm.isActive"
297
+ [binary]="true"
298
+ inputId="isActive"
299
+ />
300
+ <label for="isActive">{{ 'shared.active' | translate }}</label>
301
+ </div>
302
+
303
+ <!-- Actions -->
304
+ <div class="flex justify-end gap-2 md:col-span-2 pt-4">
305
+ <button
306
+ fButton
307
+ severity="secondary"
308
+ [outlined]="true"
309
+ (click)="onBack()"
310
+ >
311
+ <span pButtonLabel>{{ 'shared.cancel' | translate }}</span>
312
+ </button>
313
+ <button
314
+ fButton
315
+ type="submit"
316
+ [disabled]="!isFormValid() || isLoading()"
317
+ >
318
+ @if (isLoading()) {
319
+ <ui-icon pButtonIcon name="spinner" [spin]="true"></ui-icon>
320
+ }
321
+ <span pButtonLabel>{{
322
+ isEditMode()
323
+ ? ('shared.update' | translate)
324
+ : ('shared.create' | translate)
325
+ }}</span>
326
+ </button>
327
+ </div>
328
+ </form>
329
+ </div>
330
+ `,
331
+ }]
332
+ }], ctorParameters: () => [] });
333
+
334
+ export { RoleFormPageComponent };
335
+ //# sourceMappingURL=flusys-ng-iam-role-form-page.component-InsxdriD.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flusys-ng-iam-role-form-page.component-InsxdriD.mjs","sources":["../../../projects/ng-iam/pages/role/role-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 { APP_CONFIG, isCompanyFeatureEnabled } from '@flusys/ng-core';\nimport { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';\nimport { MessageService } from '@flusys/ng-ui';\nimport {\n AngularModule,\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport { IRole } from '../../interfaces/role.interface';\nimport { RoleApiService } from '../../services/role-api.service';\nimport { UiModule } from '@flusys/ng-ui';\n\ninterface IRoleFormModel {\n id: string;\n name: string;\n description: string;\n serial: string;\n isActive: boolean;\n}\n\n@Component({\n selector: 'lib-role-form-page',\n imports: [AngularModule, UiModule, FormField, TranslatePipe],\n template: `\n <div class=\"card\">\n <h3 class=\"text-lg sm:text-xl font-semibold mb-4\">\n {{\n isEditMode()\n ? ('iam.role.edit' | translate)\n : ('iam.role.new' | translate)\n }}\n </h3>\n\n <form\n (ngSubmit)=\"onSubmit()\"\n class=\"grid grid-cols-1 md:grid-cols-2 gap-4\"\n >\n <!-- Name -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"name\" class=\"font-medium\"\n >{{ 'iam.role.name' | translate }} *</label\n >\n <input\n fInputText\n id=\"name\"\n [formField]=\"roleForm.name\"\n [placeholder]=\"'iam.role.name.placeholder' | translate\"\n />\n </div>\n\n <!-- Description -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"description\" class=\"font-medium\">{{\n 'shared.description' | translate\n }}</label>\n <input\n fInputText\n id=\"description\"\n [formField]=\"roleForm.description\"\n [placeholder]=\"'shared.description.placeholder' | translate\"\n />\n </div>\n\n <!-- Order -->\n <div class=\"flex flex-col gap-2\">\n <label for=\"serial\" class=\"font-medium\">{{\n 'shared.display.order' | translate\n }}</label>\n <input\n fInputText\n id=\"serial\"\n type=\"number\"\n [formField]=\"roleForm.serial\"\n [placeholder]=\"'shared.display.order.placeholder' | translate\"\n />\n </div>\n\n <!-- Is Active -->\n <div class=\"flex items-end gap-2 pb-1\">\n <f-checkbox\n [formField]=\"roleForm.isActive\"\n [binary]=\"true\"\n inputId=\"isActive\"\n />\n <label for=\"isActive\">{{ 'shared.active' | translate }}</label>\n </div>\n\n <!-- Actions -->\n <div class=\"flex justify-end gap-2 md:col-span-2 pt-4\">\n <button\n fButton\n severity=\"secondary\"\n [outlined]=\"true\"\n (click)=\"onBack()\"\n >\n <span pButtonLabel>{{ 'shared.cancel' | translate }}</span>\n </button>\n <button\n fButton\n type=\"submit\"\n [disabled]=\"!isFormValid() || isLoading()\"\n >\n @if (isLoading()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n }\n <span pButtonLabel>{{ \n isEditMode()\n ? ('shared.update' | translate)\n : ('shared.create' | translate)\n }}</span>\n </button>\n </div>\n </form>\n </div>\n `,\n})\nexport class RoleFormPageComponent {\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n private readonly appConfig = inject(APP_CONFIG);\n private readonly companyContext = inject(LAYOUT_AUTH_STATE);\n private readonly roleApi = inject(RoleApiService);\n private readonly messageService = inject(MessageService);\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\n\n private readonly routeParams = toSignal(this.route.paramMap);\n private initialized = false;\n\n private translate(\n key: string,\n vars?: Record<string, string | number>,\n ): string {\n return this.translateAdapter?.translate(key, vars) ?? key;\n }\n\n readonly isLoading = signal(false);\n readonly existingRole = signal<IRole | null>(null);\n readonly isEditMode = computed(() => !!this.existingRole());\n\n readonly formModel = signal<IRoleFormModel>({\n id: '',\n name: '',\n description: '',\n serial: '',\n isActive: true,\n });\n\n readonly roleForm = form(this.formModel, (f) => {\n required(f.name, {\n message: this.translate('shared.validation.required', {\n field: this.translate('iam.role.name'),\n }),\n });\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 const id = params.get('id');\n if (id && id !== 'new') {\n this.loadRole(id);\n }\n });\n }\n\n async loadRole(id: string): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.roleApi.findById(id);\n const role = response?.data;\n\n if (role) {\n this.existingRole.set(role);\n this.formModel.set({\n id: role.id,\n name: role.name,\n description: role.description ?? '',\n serial: role.serial?.toString() ?? '',\n isActive: role.isActive,\n });\n } else {\n // Error toast handled by global interceptor\n this.router.navigate(['/iam/roles']);\n }\n } catch {\n // Error toast handled by global interceptor\n this.router.navigate(['/iam/roles']);\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\n // Get company context if feature enabled\n const companyId = isCompanyFeatureEnabled(this.appConfig)\n ? this.companyContext.currentCompanyInfo()?.id || undefined\n : undefined;\n\n // Convert empty strings to undefined for DTO compatibility\n const dto = {\n ...formValue,\n description: formValue.description || undefined,\n serial: formValue.serial ? parseInt(formValue.serial, 10) : undefined,\n companyId: this.isEditMode() ? undefined : companyId,\n };\n\n const response = this.isEditMode()\n ? await this.roleApi.update(dto)\n : await this.roleApi.insert(dto);\n\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: response.messageKey\n ? this.translate(\n response.messageKey,\n response.messageVariables as Record<string, string | number>,\n )\n : (response.message ?? ''),\n });\n\n this.router.navigate(['/iam/roles']);\n } catch {\n // Error toast handled by global interceptor\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onBack(): void {\n this.router.navigate(['/iam/roles']);\n }\n}\n"],"names":[],"mappings":"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"}