@flusys/ng-iam 9.1.1 → 9.2.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/fesm2022/{flusys-ng-iam-action-list-page.component-Br0PbgRa.mjs → flusys-ng-iam-action-list-page.component-D4jAQRwR.mjs} +5 -2
- package/fesm2022/{flusys-ng-iam-action-list-page.component-Br0PbgRa.mjs.map → flusys-ng-iam-action-list-page.component-D4jAQRwR.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-iam-permission-page.component-BlNt83uR.mjs → flusys-ng-iam-permission-page.component-DBRetWGs.mjs} +6 -7
- package/fesm2022/flusys-ng-iam-permission-page.component-DBRetWGs.mjs.map +1 -0
- package/fesm2022/{flusys-ng-iam-role-list-page.component-BCO_gQ8k.mjs → flusys-ng-iam-role-list-page.component-Dhd0AtOg.mjs} +5 -2
- package/fesm2022/{flusys-ng-iam-role-list-page.component-BCO_gQ8k.mjs.map → flusys-ng-iam-role-list-page.component-Dhd0AtOg.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-iam-user-action-selector.component-CAXEmJWx.mjs → flusys-ng-iam-user-action-selector.component-2wdl9Ci6.mjs} +49 -34
- package/fesm2022/flusys-ng-iam-user-action-selector.component-2wdl9Ci6.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam.mjs +16 -6
- package/fesm2022/flusys-ng-iam.mjs.map +1 -1
- package/package.json +5 -5
- package/types/flusys-ng-iam.d.ts +4 -0
- package/fesm2022/flusys-ng-iam-permission-page.component-BlNt83uR.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-user-action-selector.component-CAXEmJWx.mjs.map +0 -1
|
@@ -63,13 +63,16 @@ var ActionListPageComponent = class ActionListPageComponent {
|
|
|
63
63
|
untracked(() => this.loadActions());
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
|
+
loadSeq = 0;
|
|
66
67
|
async loadActions() {
|
|
68
|
+
const seq = ++this.loadSeq;
|
|
67
69
|
this.isLoading.set(true);
|
|
68
70
|
try {
|
|
69
71
|
const response = await firstValueFrom(this.actionApi.getTree());
|
|
72
|
+
if (seq !== this.loadSeq) return;
|
|
70
73
|
this.rawActions.set(response?.success ? response.data ?? [] : []);
|
|
71
74
|
} catch {} finally {
|
|
72
|
-
this.isLoading.set(false);
|
|
75
|
+
if (seq === this.loadSeq) this.isLoading.set(false);
|
|
73
76
|
}
|
|
74
77
|
}
|
|
75
78
|
onSearchChange(value) {
|
|
@@ -661,4 +664,4 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
661
664
|
});
|
|
662
665
|
export { ActionListPageComponent };
|
|
663
666
|
|
|
664
|
-
//# sourceMappingURL=flusys-ng-iam-action-list-page.component-
|
|
667
|
+
//# sourceMappingURL=flusys-ng-iam-action-list-page.component-D4jAQRwR.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flusys-ng-iam-action-list-page.component-Br0PbgRa.mjs","names":[],"sources":["../../../projects/ng-iam/pages/action/action-list-page.component.ts"],"sourcesContent":["import {\n Component,\n computed,\n effect,\n inject,\n signal,\n untracked,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { Router } from '@angular/router';\nimport { APP_CONFIG, getPermissionMode } from '@flusys/ng-core';\nimport { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';\nimport {\n ACTION_PERMISSIONS,\n HasPermissionDirective,\n TranslatePipe,\n TranslateService,\n USER_ACTION_PERMISSIONS,\n} from '@flusys/ng-shared';\nimport {\n ConfirmationService,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n MessageService,\n TagComponent,\n TooltipDirective,\n TreeNode,\n TreeTableComponent,\n TreeTableTogglerComponent,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport { firstValueFrom } from 'rxjs';\nimport { ActionPermittedUsersDialogComponent } from '../../components/action-permitted-users-dialog.component';\nimport {\n ActionType,\n IAction,\n IActionTreeDto,\n} from '../../interfaces/action.interface';\nimport { ActionApiService } from '../../services/action-api.service';\nimport { convertActionToTreeNode } from '../../utils/tree-utils';\n\nfunction filterActionTree(\n nodes: IActionTreeDto[],\n search: string,\n): IActionTreeDto[] {\n const term = search.trim().toLowerCase();\n if (!term) return nodes;\n\n const filter = (items: IActionTreeDto[]): IActionTreeDto[] =>\n items.reduce<IActionTreeDto[]>((acc, node) => {\n const children = filter(node.children ?? []);\n const matches =\n node.name?.toLowerCase().includes(term) ||\n node.code?.toLowerCase().includes(term);\n if (matches || children.length) {\n acc.push({ ...node, children });\n }\n return acc;\n }, []);\n\n return filter(nodes);\n}\n\n@Component({\n selector: 'lib-action-list-page',\n imports: [\n FButtonDirective,\n FormsModule,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TagComponent,\n TooltipDirective,\n TreeTableComponent,\n TreeTableTogglerComponent,\n UiIconComponent,\n HasPermissionDirective,\n ActionPermittedUsersDialogComponent,\n TranslatePipe,\n ],\n template: `\n <div class=\"card\">\n <div\n class=\"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 mb-4\"\n >\n <h3 class=\"text-lg sm:text-xl font-semibold\">\n {{ 'iam.action.title' | translate }}\n </h3>\n <div class=\"flex flex-wrap items-center gap-2 w-full sm:w-auto\">\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [placeholder]=\"'shared.search' | translate\"\n class=\"w-full\"\n />\n </f-iconfield>\n <button\n fButton\n *hasPermission=\"ACTION_PERMISSIONS.CREATE\"\n (click)=\"onCreate()\"\n class=\"w-full sm:w-auto\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'iam.action.new' | translate }}</span>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-x-auto -mx-4 sm:mx-0\">\n <f-treetable\n [value]=\"treeNodes()\"\n [loading]=\"isLoading()\"\n dataKey=\"id\"\n [tableStyle]=\"{ 'min-width': '50rem' }\"\n >\n <ng-template #header>\n <tr>\n <th>{{ 'iam.action.name' | translate }}</th>\n <th class=\"hidden md:table-cell\">\n {{ 'iam.action.code' | translate }}\n </th>\n <th>{{ 'iam.action.type' | translate }}</th>\n <th class=\"hidden sm:table-cell\">\n {{ 'shared.active' | translate }}\n </th>\n <th class=\"hidden lg:table-cell\">\n {{ 'shared.read.only' | translate }}\n </th>\n <th class=\"w-[100px]\">{{ 'shared.actions' | translate }}</th>\n </tr>\n </ng-template>\n <ng-template #body let-rowNode let-rowData=\"rowData\">\n <tr>\n <td>\n <f-treetabletoggler [rowNode]=\"rowNode\" />\n {{ rowData.name }}\n </td>\n <td class=\"hidden md:table-cell\">{{ rowData.code ?? '-' }}</td>\n <td>\n <f-tag\n [value]=\"getActionTypeLabel(rowData.actionType)\"\n [severity]=\"getActionTypeSeverity(rowData.actionType)\"\n />\n </td>\n <td class=\"hidden sm:table-cell\">\n <f-tag\n [value]=\"\n rowData.isActive\n ? ('shared.active' | translate)\n : ('shared.inactive' | translate)\n \"\n [severity]=\"rowData.isActive ? 'success' : 'secondary'\"\n />\n </td>\n <td class=\"hidden lg:table-cell\">\n <f-tag\n [value]=\"\n rowData.readOnly\n ? ('shared.yes' | translate)\n : ('shared.no' | translate)\n \"\n [severity]=\"rowData.readOnly ? 'warn' : 'secondary'\"\n />\n </td>\n <td>\n <div class=\"flex gap-1\">\n <button\n fButton\n *hasPermission=\"ACTION_PERMISSIONS.UPDATE\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n [disabled]=\"rowData.readOnly\"\n [fTooltip]=\"'shared.edit' | translate\"\n (click)=\"onEdit(rowData)\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n @if (showActionUsers()) {\n <button\n fButton\n *hasPermission=\"USER_ACTION_PERMISSIONS.READ\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n [fTooltip]=\"'iam.permission.view.users' | translate\"\n (click)=\"onViewUsers(rowData)\"\n >\n <ui-icon pButtonIcon name=\"users\"></ui-icon>\n </button>\n }\n <button\n fButton\n *hasPermission=\"ACTION_PERMISSIONS.DELETE\"\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n [fTooltip]=\"'shared.delete' | translate\"\n [disabled]=\"rowData.readOnly\"\n (click)=\"onDelete(rowData)\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n </div>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td colspan=\"6\" class=\"text-center py-4 text-muted-color\">\n {{ 'iam.action.no.actions' | translate }}\n </td>\n </tr>\n </ng-template>\n </f-treetable>\n </div>\n </div>\n\n <flusys-action-permitted-users-dialog\n [visible]=\"permittedUsersDialogVisible()\"\n [action]=\"selectedAction()\"\n (closed)=\"permittedUsersDialogVisible.set(false)\"\n />\n `,\n})\nexport class ActionListPageComponent {\n readonly ACTION_PERMISSIONS = ACTION_PERMISSIONS;\n readonly USER_ACTION_PERMISSIONS = USER_ACTION_PERMISSIONS;\n\n private readonly router = inject(Router);\n private readonly appConfig = inject(APP_CONFIG);\n private readonly companyContext = inject(LAYOUT_AUTH_STATE);\n private readonly actionApi = inject(ActionApiService);\n private readonly messageService = inject(MessageService);\n private readonly confirmationService = inject(ConfirmationService);\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\n\n readonly isLoading = signal(false);\n private readonly rawActions = signal<IActionTreeDto[]>([]);\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n readonly treeNodes = computed<TreeNode<IAction>[]>(() =>\n convertActionToTreeNode(\n filterActionTree(this.rawActions(), this._searchTerm()),\n ),\n );\n readonly permittedUsersDialogVisible = signal(false);\n readonly selectedAction = signal<IAction | null>(null);\n readonly showActionUsers = computed(() => {\n const permissionMode = getPermissionMode(this.appConfig);\n return permissionMode === 'direct' || permissionMode === 'full';\n });\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 private static readonly TYPE_SEVERITIES: Record<\n ActionType,\n 'info' | 'success' | 'warn'\n > = {\n [ActionType.BACKEND]: 'info',\n [ActionType.FRONTEND]: 'success',\n [ActionType.BOTH]: 'warn',\n };\n\n private static readonly TYPE_LABEL_KEYS: Record<ActionType, string> = {\n [ActionType.BACKEND]: 'iam.action.type.backend',\n [ActionType.FRONTEND]: 'iam.action.type.frontend',\n [ActionType.BOTH]: 'iam.action.type.both',\n };\n\n constructor() {\n effect(() => {\n this.companyContext.currentCompanyInfo();\n untracked(() => this.loadActions());\n });\n }\n\n private async loadActions(): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await firstValueFrom(this.actionApi.getTree());\n this.rawActions.set(response?.success ? (response.data ?? []) : []);\n } catch {\n // Handled by global interceptor\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onSearchChange(value: string): void {\n this._searchTerm.set(value);\n }\n\n getActionTypeLabel(type: ActionType): string {\n const key =\n ActionListPageComponent.TYPE_LABEL_KEYS[type] ?? 'shared.unknown';\n return this.translate(key);\n }\n\n getActionTypeSeverity(type: ActionType): 'info' | 'success' | 'warn' {\n return ActionListPageComponent.TYPE_SEVERITIES[type] ?? 'info';\n }\n\n onCreate(): void {\n this.router.navigate(['/iam/actions/new']);\n }\n\n onEdit(action: IAction): void {\n this.router.navigate(['/iam/actions', action.id]);\n }\n\n onViewUsers(action: IAction): void {\n this.selectedAction.set(action);\n this.permittedUsersDialogVisible.set(true);\n }\n\n onDelete(action: IAction): void {\n if (!action?.id || !action?.name) return;\n\n this.confirmationService.confirm({\n message: this.translate('shared.confirm.delete.item', {\n name: action.name,\n }),\n header: this.translate('iam.action.delete.title'),\n icon: 'exclamation-triangle',\n accept: async () => {\n try {\n const response = await this.actionApi.delete({\n id: action.id,\n type: 'permanent',\n });\n await this.loadActions();\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 } catch {\n // Handled by global interceptor\n }\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flusys-ng-iam-action-list-page.component-D4jAQRwR.mjs","names":[],"sources":["../../../projects/ng-iam/pages/action/action-list-page.component.ts"],"sourcesContent":["import {\n Component,\n computed,\n effect,\n inject,\n signal,\n untracked,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { Router } from '@angular/router';\nimport { APP_CONFIG, getPermissionMode } from '@flusys/ng-core';\nimport { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';\nimport {\n ACTION_PERMISSIONS,\n HasPermissionDirective,\n TranslatePipe,\n TranslateService,\n USER_ACTION_PERMISSIONS,\n} from '@flusys/ng-shared';\nimport {\n ConfirmationService,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n MessageService,\n TagComponent,\n TooltipDirective,\n TreeNode,\n TreeTableComponent,\n TreeTableTogglerComponent,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport { firstValueFrom } from 'rxjs';\nimport { ActionPermittedUsersDialogComponent } from '../../components/action-permitted-users-dialog.component';\nimport {\n ActionType,\n IAction,\n IActionTreeDto,\n} from '../../interfaces/action.interface';\nimport { ActionApiService } from '../../services/action-api.service';\nimport { convertActionToTreeNode } from '../../utils/tree-utils';\n\nfunction filterActionTree(\n nodes: IActionTreeDto[],\n search: string,\n): IActionTreeDto[] {\n const term = search.trim().toLowerCase();\n if (!term) return nodes;\n\n const filter = (items: IActionTreeDto[]): IActionTreeDto[] =>\n items.reduce<IActionTreeDto[]>((acc, node) => {\n const children = filter(node.children ?? []);\n const matches =\n node.name?.toLowerCase().includes(term) ||\n node.code?.toLowerCase().includes(term);\n if (matches || children.length) {\n acc.push({ ...node, children });\n }\n return acc;\n }, []);\n\n return filter(nodes);\n}\n\n@Component({\n selector: 'lib-action-list-page',\n imports: [\n FButtonDirective,\n FormsModule,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TagComponent,\n TooltipDirective,\n TreeTableComponent,\n TreeTableTogglerComponent,\n UiIconComponent,\n HasPermissionDirective,\n ActionPermittedUsersDialogComponent,\n TranslatePipe,\n ],\n template: `\n <div class=\"card\">\n <div\n class=\"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 mb-4\"\n >\n <h3 class=\"text-lg sm:text-xl font-semibold\">\n {{ 'iam.action.title' | translate }}\n </h3>\n <div class=\"flex flex-wrap items-center gap-2 w-full sm:w-auto\">\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [placeholder]=\"'shared.search' | translate\"\n class=\"w-full\"\n />\n </f-iconfield>\n <button\n fButton\n *hasPermission=\"ACTION_PERMISSIONS.CREATE\"\n (click)=\"onCreate()\"\n class=\"w-full sm:w-auto\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'iam.action.new' | translate }}</span>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-x-auto -mx-4 sm:mx-0\">\n <f-treetable\n [value]=\"treeNodes()\"\n [loading]=\"isLoading()\"\n dataKey=\"id\"\n [tableStyle]=\"{ 'min-width': '50rem' }\"\n >\n <ng-template #header>\n <tr>\n <th>{{ 'iam.action.name' | translate }}</th>\n <th class=\"hidden md:table-cell\">\n {{ 'iam.action.code' | translate }}\n </th>\n <th>{{ 'iam.action.type' | translate }}</th>\n <th class=\"hidden sm:table-cell\">\n {{ 'shared.active' | translate }}\n </th>\n <th class=\"hidden lg:table-cell\">\n {{ 'shared.read.only' | translate }}\n </th>\n <th class=\"w-[100px]\">{{ 'shared.actions' | translate }}</th>\n </tr>\n </ng-template>\n <ng-template #body let-rowNode let-rowData=\"rowData\">\n <tr>\n <td>\n <f-treetabletoggler [rowNode]=\"rowNode\" />\n {{ rowData.name }}\n </td>\n <td class=\"hidden md:table-cell\">{{ rowData.code ?? '-' }}</td>\n <td>\n <f-tag\n [value]=\"getActionTypeLabel(rowData.actionType)\"\n [severity]=\"getActionTypeSeverity(rowData.actionType)\"\n />\n </td>\n <td class=\"hidden sm:table-cell\">\n <f-tag\n [value]=\"\n rowData.isActive\n ? ('shared.active' | translate)\n : ('shared.inactive' | translate)\n \"\n [severity]=\"rowData.isActive ? 'success' : 'secondary'\"\n />\n </td>\n <td class=\"hidden lg:table-cell\">\n <f-tag\n [value]=\"\n rowData.readOnly\n ? ('shared.yes' | translate)\n : ('shared.no' | translate)\n \"\n [severity]=\"rowData.readOnly ? 'warn' : 'secondary'\"\n />\n </td>\n <td>\n <div class=\"flex gap-1\">\n <button\n fButton\n *hasPermission=\"ACTION_PERMISSIONS.UPDATE\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n [disabled]=\"rowData.readOnly\"\n [fTooltip]=\"'shared.edit' | translate\"\n (click)=\"onEdit(rowData)\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n @if (showActionUsers()) {\n <button\n fButton\n *hasPermission=\"USER_ACTION_PERMISSIONS.READ\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n [fTooltip]=\"'iam.permission.view.users' | translate\"\n (click)=\"onViewUsers(rowData)\"\n >\n <ui-icon pButtonIcon name=\"users\"></ui-icon>\n </button>\n }\n <button\n fButton\n *hasPermission=\"ACTION_PERMISSIONS.DELETE\"\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n [fTooltip]=\"'shared.delete' | translate\"\n [disabled]=\"rowData.readOnly\"\n (click)=\"onDelete(rowData)\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n </div>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td colspan=\"6\" class=\"text-center py-4 text-muted-color\">\n {{ 'iam.action.no.actions' | translate }}\n </td>\n </tr>\n </ng-template>\n </f-treetable>\n </div>\n </div>\n\n <flusys-action-permitted-users-dialog\n [visible]=\"permittedUsersDialogVisible()\"\n [action]=\"selectedAction()\"\n (closed)=\"permittedUsersDialogVisible.set(false)\"\n />\n `,\n})\nexport class ActionListPageComponent {\n readonly ACTION_PERMISSIONS = ACTION_PERMISSIONS;\n readonly USER_ACTION_PERMISSIONS = USER_ACTION_PERMISSIONS;\n\n private readonly router = inject(Router);\n private readonly appConfig = inject(APP_CONFIG);\n private readonly companyContext = inject(LAYOUT_AUTH_STATE);\n private readonly actionApi = inject(ActionApiService);\n private readonly messageService = inject(MessageService);\n private readonly confirmationService = inject(ConfirmationService);\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\n\n readonly isLoading = signal(false);\n private readonly rawActions = signal<IActionTreeDto[]>([]);\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n readonly treeNodes = computed<TreeNode<IAction>[]>(() =>\n convertActionToTreeNode(\n filterActionTree(this.rawActions(), this._searchTerm()),\n ),\n );\n readonly permittedUsersDialogVisible = signal(false);\n readonly selectedAction = signal<IAction | null>(null);\n readonly showActionUsers = computed(() => {\n const permissionMode = getPermissionMode(this.appConfig);\n return permissionMode === 'direct' || permissionMode === 'full';\n });\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 private static readonly TYPE_SEVERITIES: Record<\n ActionType,\n 'info' | 'success' | 'warn'\n > = {\n [ActionType.BACKEND]: 'info',\n [ActionType.FRONTEND]: 'success',\n [ActionType.BOTH]: 'warn',\n };\n\n private static readonly TYPE_LABEL_KEYS: Record<ActionType, string> = {\n [ActionType.BACKEND]: 'iam.action.type.backend',\n [ActionType.FRONTEND]: 'iam.action.type.frontend',\n [ActionType.BOTH]: 'iam.action.type.both',\n };\n\n constructor() {\n effect(() => {\n this.companyContext.currentCompanyInfo();\n untracked(() => this.loadActions());\n });\n }\n\n private loadSeq = 0;\n\n private async loadActions(): Promise<void> {\n const seq = ++this.loadSeq;\n this.isLoading.set(true);\n try {\n const response = await firstValueFrom(this.actionApi.getTree());\n if (seq !== this.loadSeq) return;\n this.rawActions.set(response?.success ? (response.data ?? []) : []);\n } catch {\n // Handled by global interceptor\n } finally {\n if (seq === this.loadSeq) this.isLoading.set(false);\n }\n }\n\n onSearchChange(value: string): void {\n this._searchTerm.set(value);\n }\n\n getActionTypeLabel(type: ActionType): string {\n const key =\n ActionListPageComponent.TYPE_LABEL_KEYS[type] ?? 'shared.unknown';\n return this.translate(key);\n }\n\n getActionTypeSeverity(type: ActionType): 'info' | 'success' | 'warn' {\n return ActionListPageComponent.TYPE_SEVERITIES[type] ?? 'info';\n }\n\n onCreate(): void {\n this.router.navigate(['/iam/actions/new']);\n }\n\n onEdit(action: IAction): void {\n this.router.navigate(['/iam/actions', action.id]);\n }\n\n onViewUsers(action: IAction): void {\n this.selectedAction.set(action);\n this.permittedUsersDialogVisible.set(true);\n }\n\n onDelete(action: IAction): void {\n if (!action?.id || !action?.name) return;\n\n this.confirmationService.confirm({\n message: this.translate('shared.confirm.delete.item', {\n name: action.name,\n }),\n header: this.translate('iam.action.delete.title'),\n icon: 'exclamation-triangle',\n accept: async () => {\n try {\n const response = await this.actionApi.delete({\n id: action.id,\n type: 'permanent',\n });\n await this.loadActions();\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 } catch {\n // Handled by global interceptor\n }\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { i as RoleActionSelectorComponent, n as UserRoleSelectorComponent, r as CompanyActionSelectorComponent, t as UserActionSelectorComponent } from "./flusys-ng-iam-user-action-selector.component-
|
|
1
|
+
import { i as RoleActionSelectorComponent, n as UserRoleSelectorComponent, r as CompanyActionSelectorComponent, t as UserActionSelectorComponent } from "./flusys-ng-iam-user-action-selector.component-2wdl9Ci6.mjs";
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
3
|
import { Component, computed, effect, inject, signal, untracked, viewChild } from "@angular/core";
|
|
4
|
-
import { COMPANY_ACTION_PERMISSIONS, HasPermissionDirective, ROLE_ACTION_PERMISSIONS, TranslatePipe, TranslateService, USER_ACTION_PERMISSIONS, USER_ROLE_PERMISSIONS } from "@flusys/ng-shared";
|
|
4
|
+
import { COMPANY_ACTION_PERMISSIONS, HasPermissionDirective, PermissionValidatorService, ROLE_ACTION_PERMISSIONS, TranslatePipe, TranslateService, USER_ACTION_PERMISSIONS, USER_ROLE_PERMISSIONS } from "@flusys/ng-shared";
|
|
5
5
|
import { APP_CONFIG, getPermissionMode, isCompanyFeatureEnabled } from "@flusys/ng-core";
|
|
6
6
|
import { ConfirmationService, TabComponent, TabListComponent, TabsComponent, UiIconComponent } from "@flusys/ng-ui";
|
|
7
7
|
const TAB_PERMISSIONS = {
|
|
@@ -14,6 +14,7 @@ var PermissionPageComponent = class PermissionPageComponent {
|
|
|
14
14
|
appConfig = inject(APP_CONFIG);
|
|
15
15
|
confirmationService = inject(ConfirmationService);
|
|
16
16
|
translateService = inject(TranslateService);
|
|
17
|
+
permissionValidator = inject(PermissionValidatorService);
|
|
17
18
|
tabsRef = viewChild("tabs", ...ngDevMode ? [{ debugName: "tabsRef" }] : /* istanbul ignore next */ []);
|
|
18
19
|
activeSelectorRef = viewChild("selectorRef", ...ngDevMode ? [{ debugName: "activeSelectorRef" }] : /* istanbul ignore next */ []);
|
|
19
20
|
activeTab = signal("", ...ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []);
|
|
@@ -43,15 +44,13 @@ var PermissionPageComponent = class PermissionPageComponent {
|
|
|
43
44
|
icon: "building",
|
|
44
45
|
permission: TAB_PERMISSIONS["company-actions"]
|
|
45
46
|
});
|
|
46
|
-
return tabs;
|
|
47
|
+
return tabs.filter((tab) => this.permissionValidator.hasPermission(tab.permission));
|
|
47
48
|
}, ...ngDevMode ? [{ debugName: "availableTabs" }] : /* istanbul ignore next */ []);
|
|
48
49
|
constructor() {
|
|
49
50
|
effect(() => {
|
|
50
51
|
const tabs = this.availableTabs();
|
|
51
52
|
const currentTab = untracked(() => this.activeTab());
|
|
52
|
-
if (!currentTab || !tabs.some((t) => t.id === currentTab))
|
|
53
|
-
if (tabs.length > 0) this.activeTab.set(tabs[0].id);
|
|
54
|
-
}
|
|
53
|
+
if (!currentTab || !tabs.some((t) => t.id === currentTab)) this.activeTab.set(tabs[0]?.id ?? "");
|
|
55
54
|
});
|
|
56
55
|
}
|
|
57
56
|
setActiveTab(tabId) {
|
|
@@ -303,4 +302,4 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
303
302
|
});
|
|
304
303
|
export { PermissionPageComponent };
|
|
305
304
|
|
|
306
|
-
//# sourceMappingURL=flusys-ng-iam-permission-page.component-
|
|
305
|
+
//# sourceMappingURL=flusys-ng-iam-permission-page.component-DBRetWGs.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flusys-ng-iam-permission-page.component-DBRetWGs.mjs","names":[],"sources":["../../../projects/ng-iam/pages/permission/permission-page.component.ts"],"sourcesContent":["import {\n Component,\n computed,\n effect,\n inject,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport {\n HasPermissionDirective,\n PermissionValidatorService,\n ROLE_ACTION_PERMISSIONS,\n USER_ROLE_PERMISSIONS,\n USER_ACTION_PERMISSIONS,\n COMPANY_ACTION_PERMISSIONS,\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport {\n APP_CONFIG,\n getPermissionMode,\n isCompanyFeatureEnabled,\n} 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 {\n ConfirmationService,\n TabComponent,\n TabListComponent,\n TabsComponent,\n UiIconComponent,\n} 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/** Structural shape shared by all four permission selector components */\ninterface IPermissionSelectorRef {\n readonly hasChanges: () => boolean;\n}\n\n/** Main permission management interface with tabs for role/user/company permission assignment */\n@Component({\n selector: 'lib-permission-page',\n imports: [\n TabComponent,\n TabListComponent,\n TabsComponent,\n UiIconComponent,\n HasPermissionDirective,\n TranslatePipe,\n RoleActionSelectorComponent,\n CompanyActionSelectorComponent,\n UserRoleSelectorComponent,\n UserActionSelectorComponent,\n ],\n template: `\n <div class=\"card\">\n <div class=\"mb-5\">\n <h3 class=\"text-xl font-semibold mb-1\">\n {{ 'iam.permission.title' | translate }}\n </h3>\n <p class=\"text-sm text-muted-color m-0\">\n {{ 'iam.permission.subtitle' | translate }}\n </p>\n </div>\n\n <f-tabs\n #tabs\n [value]=\"activeTab()\"\n (valueChange)=\"setActiveTab($event)\"\n [scrollable]=\"true\"\n >\n <f-tablist>\n @for (tab of availableTabs(); track tab.id) {\n <f-tab *hasPermission=\"tab.permission\" [value]=\"tab.id\">\n <ui-icon [name]=\"tab.icon\" class=\"mr-2\"></ui-icon\n >{{ tab.labelKey | translate }}\n </f-tab>\n }\n </f-tablist>\n </f-tabs>\n\n <div class=\"mt-5\">\n @switch (activeTab()) {\n @case ('role-actions') {\n <flusys-role-action-selector #selectorRef />\n }\n @case ('user-roles') {\n <flusys-user-role-selector #selectorRef />\n }\n @case ('user-actions') {\n <flusys-user-action-selector #selectorRef />\n }\n @case ('company-actions') {\n <flusys-company-action-selector #selectorRef />\n }\n }\n </div>\n </div>\n `,\n})\nexport class PermissionPageComponent {\n private readonly appConfig = inject(APP_CONFIG);\n private readonly confirmationService = inject(ConfirmationService);\n private readonly translateService = inject(TranslateService);\n private readonly permissionValidator = inject(PermissionValidatorService);\n\n private readonly tabsRef = viewChild<TabsComponent>('tabs');\n private readonly activeSelectorRef =\n viewChild<IPermissionSelectorRef>('selectorRef');\n\n readonly activeTab = signal<string>('');\n\n /** Available tabs based on permission mode and the user's read permissions */\n readonly availableTabs = computed(() => {\n const permissionMode = getPermissionMode(this.appConfig);\n const tabs: Array<{\n id: string;\n labelKey: string;\n icon: string;\n permission: string;\n }> = [];\n\n if (permissionMode === 'rbac' || permissionMode === 'full') {\n tabs.push(\n {\n id: 'role-actions',\n labelKey: 'iam.permission.role.actions',\n icon: 'shield',\n permission: TAB_PERMISSIONS['role-actions'],\n },\n {\n id: 'user-roles',\n labelKey: 'iam.permission.user.roles',\n icon: 'user',\n permission: TAB_PERMISSIONS['user-roles'],\n },\n );\n }\n\n if (permissionMode === 'direct' || permissionMode === 'full') {\n tabs.push({\n id: 'user-actions',\n labelKey: 'iam.permission.user.actions',\n icon: 'key',\n permission: TAB_PERMISSIONS['user-actions'],\n });\n }\n\n if (isCompanyFeatureEnabled(this.appConfig)) {\n tabs.push({\n id: 'company-actions',\n labelKey: 'iam.permission.company.actions',\n icon: 'building',\n permission: TAB_PERMISSIONS['company-actions'],\n });\n }\n\n return tabs.filter((tab) =>\n this.permissionValidator.hasPermission(tab.permission),\n );\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 this.activeTab.set(tabs[0]?.id ?? '');\n }\n });\n }\n\n setActiveTab(tabId: string | number): void {\n const nextTab = String(tabId);\n const previousTab = this.activeTab();\n if (nextTab === previousTab) return;\n\n if (this.activeSelectorRef()?.hasChanges()) {\n this.confirmationService.confirm({\n header: this.translateService.translate(\n 'iam.permission.unsaved.changes.title',\n ),\n message: this.translateService.translate(\n 'iam.permission.unsaved.changes.message',\n ),\n icon: 'exclamation-triangle',\n acceptLabel: this.translateService.translate(\n 'iam.permission.unsaved.changes.discard',\n ),\n rejectLabel: this.translateService.translate('shared.cancel'),\n accept: () => this.activeTab.set(nextTab),\n reject: () => this.tabsRef()?.value.set(previousTab),\n });\n return;\n }\n\n this.activeTab.set(nextTab);\n }\n}\n"],"mappings":"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"}
|
|
@@ -53,7 +53,9 @@ var RoleListPageComponent = class RoleListPageComponent {
|
|
|
53
53
|
});
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
|
+
loadSeq = 0;
|
|
56
57
|
async loadRoles() {
|
|
58
|
+
const seq = ++this.loadSeq;
|
|
57
59
|
this.isLoading.set(true);
|
|
58
60
|
try {
|
|
59
61
|
const enableCompanyFeature = isCompanyFeatureEnabled(this.appConfig);
|
|
@@ -78,10 +80,11 @@ var RoleListPageComponent = class RoleListPageComponent {
|
|
|
78
80
|
select: selectFields,
|
|
79
81
|
sort: { id: "ASC" }
|
|
80
82
|
}, this._searchTerm());
|
|
83
|
+
if (seq !== this.loadSeq) return;
|
|
81
84
|
this.roles.set(response?.data ?? []);
|
|
82
85
|
this.total.set(response?.meta?.total ?? 0);
|
|
83
86
|
} catch {} finally {
|
|
84
|
-
this.isLoading.set(false);
|
|
87
|
+
if (seq === this.loadSeq) this.isLoading.set(false);
|
|
85
88
|
}
|
|
86
89
|
}
|
|
87
90
|
onCreate() {
|
|
@@ -682,4 +685,4 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
682
685
|
});
|
|
683
686
|
export { RoleListPageComponent };
|
|
684
687
|
|
|
685
|
-
//# sourceMappingURL=flusys-ng-iam-role-list-page.component-
|
|
688
|
+
//# sourceMappingURL=flusys-ng-iam-role-list-page.component-Dhd0AtOg.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flusys-ng-iam-role-list-page.component-BCO_gQ8k.mjs","names":[],"sources":["../../../projects/ng-iam/pages/role/role-list-page.component.ts"],"sourcesContent":["import {\n Component,\n computed,\n effect,\n inject,\n signal,\n untracked,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { Router } from '@angular/router';\nimport {\n APP_CONFIG,\n DEFAULT_APP_NAME,\n getPermissionMode,\n isCompanyFeatureEnabled,\n} from '@flusys/ng-core';\nimport { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';\nimport {\n HasPermissionDirective,\n ROLE_PERMISSIONS,\n TranslatePipe,\n TranslateService,\n USER_ROLE_PERMISSIONS,\n} from '@flusys/ng-shared';\nimport {\n ConfirmationService,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n MessageService,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport { RolePermittedUsersDialogComponent } from '../../components/role-permitted-users-dialog.component';\nimport { IRole } from '../../interfaces/role.interface';\nimport { RoleApiService } from '../../services/role-api.service';\n\n@Component({\n selector: 'lib-role-list-page',\n imports: [\n FButtonDirective,\n FormsModule,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n HasPermissionDirective,\n RolePermittedUsersDialogComponent,\n TranslatePipe,\n ],\n template: `\n <div class=\"card\">\n <div\n class=\"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 mb-4\"\n >\n <div>\n <h3 class=\"text-lg sm:text-xl font-semibold\">\n {{ 'iam.role.title' | translate }}\n </h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n {{ 'iam.company.title' | translate }}: {{ currentCompanyName() }}\n </p>\n }\n </div>\n <div class=\"flex flex-wrap items-center gap-2 w-full sm:w-auto\">\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [placeholder]=\"'shared.search' | translate\"\n class=\"w-full\"\n />\n </f-iconfield>\n <button\n fButton\n *hasPermission=\"ROLE_PERMISSIONS.CREATE\"\n (click)=\"onCreate()\"\n class=\"w-full sm:w-auto\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'iam.role.new' | translate }}</span>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-x-auto -mx-4 sm:mx-0\">\n <f-table\n [value]=\"roles()\"\n [loading]=\"isLoading()\"\n [paginator]=\"total() > 0\"\n [rows]=\"pageSize()\"\n [first]=\"first()\"\n [totalRecords]=\"total()\"\n [lazy]=\"true\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n [rowsPerPageOptions]=\"[10, 25, 50]\"\n [scrollable]=\"true\"\n [tableStyle]=\"{ 'min-width': '40rem' }\"\n >\n <ng-template #header>\n <tr>\n <th>{{ 'iam.role.name' | translate }}</th>\n <th class=\"hidden md:table-cell\">\n {{ 'shared.description' | translate }}\n </th>\n <th>{{ 'shared.active' | translate }}</th>\n <th class=\"hidden sm:table-cell\">\n {{ 'shared.read.only' | translate }}\n </th>\n <th class=\"w-[120px]\">{{ 'shared.actions' | translate }}</th>\n </tr>\n </ng-template>\n <ng-template #body let-role>\n <tr>\n <td>{{ role.name }}</td>\n <td class=\"hidden md:table-cell\">\n {{ role.description ?? '-' }}\n </td>\n <td>\n <f-tag\n [value]=\"\n role.isActive\n ? ('shared.active' | translate)\n : ('shared.inactive' | translate)\n \"\n [severity]=\"role.isActive ? 'success' : 'secondary'\"\n />\n </td>\n <td class=\"hidden sm:table-cell\">\n <f-tag\n [value]=\"\n role.readOnly\n ? ('shared.yes' | translate)\n : ('shared.no' | translate)\n \"\n [severity]=\"role.readOnly ? 'warn' : 'secondary'\"\n />\n </td>\n <td>\n <div class=\"flex gap-1\">\n <button\n fButton\n *hasPermission=\"ROLE_PERMISSIONS.UPDATE\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n [disabled]=\"role.readOnly\"\n [fTooltip]=\"'shared.edit' | translate\"\n (click)=\"onEdit(role)\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n @if (showRoleUsers()) {\n <button\n fButton\n *hasPermission=\"USER_ROLE_PERMISSIONS.READ\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n [fTooltip]=\"'iam.permission.view.users' | translate\"\n (click)=\"onViewUsers(role)\"\n >\n <ui-icon pButtonIcon name=\"users\"></ui-icon>\n </button>\n }\n <button\n fButton\n *hasPermission=\"ROLE_PERMISSIONS.DELETE\"\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n [fTooltip]=\"'shared.delete' | translate\"\n [disabled]=\"role.readOnly\"\n (click)=\"onDelete(role)\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n </div>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td colspan=\"5\" class=\"text-center py-4 text-muted-color\">\n {{ 'iam.role.no.roles' | translate }}\n </td>\n </tr>\n </ng-template>\n </f-table>\n </div>\n </div>\n\n <flusys-role-permitted-users-dialog\n [visible]=\"permittedUsersDialogVisible()\"\n [role]=\"selectedRole()\"\n (closed)=\"permittedUsersDialogVisible.set(false)\"\n />\n `,\n})\nexport class RoleListPageComponent {\n readonly ROLE_PERMISSIONS = ROLE_PERMISSIONS;\n readonly USER_ROLE_PERMISSIONS = USER_ROLE_PERMISSIONS;\n\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 confirmationService = inject(ConfirmationService);\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\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 roles = signal<IRole[]>([]);\n readonly isLoading = signal(false);\n readonly total = signal(0);\n readonly pageSize = signal(10);\n readonly first = signal(0);\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n readonly showCompanyInfo = computed(\n () => this.appConfig.enableCompanyFeature,\n );\n readonly showRoleUsers = computed(() => {\n const permissionMode = getPermissionMode(this.appConfig);\n return permissionMode === 'rbac' || permissionMode === 'full';\n });\n readonly currentCompanyName = computed(\n () => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME,\n );\n\n readonly permittedUsersDialogVisible = signal(false);\n readonly selectedRole = signal<IRole | null>(null);\n\n private previousCompanyId: string | undefined | null = undefined;\n\n constructor() {\n effect(() => {\n const currentCompanyId =\n this.companyContext.currentCompanyInfo()?.id ?? null;\n if (this.previousCompanyId === undefined) {\n this.previousCompanyId = currentCompanyId;\n return;\n }\n if (this.previousCompanyId === currentCompanyId) return;\n this.previousCompanyId = currentCompanyId;\n untracked(() => {\n this.first.set(0);\n this.loadRoles();\n });\n });\n }\n\n private async loadRoles(): Promise<void> {\n this.isLoading.set(true);\n try {\n const enableCompanyFeature = isCompanyFeatureEnabled(this.appConfig);\n const companyId = enableCompanyFeature\n ? this.companyContext.currentCompanyInfo()?.id || undefined\n : undefined;\n\n const selectFields = [\n 'id',\n 'name',\n 'description',\n 'isActive',\n 'readOnly',\n 'serial',\n 'createdAt',\n 'deletedAt',\n ];\n if (enableCompanyFeature) {\n selectFields.push('companyId');\n }\n\n const response = await this.roleApi.getAll(\n {\n filter: companyId ? { companyId } : undefined,\n pagination: {\n currentPage: Math.floor(this.first() / this.pageSize()),\n pageSize: this.pageSize(),\n },\n select: selectFields,\n sort: { id: 'ASC' },\n },\n this._searchTerm(),\n );\n\n this.roles.set(response?.data ?? []);\n this.total.set(response?.meta?.total ?? 0);\n } catch {\n // Error toast handled by global interceptor\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onCreate(): void {\n this.router.navigate(['/iam/roles/new']);\n }\n\n onEdit(role: IRole): void {\n this.router.navigate(['/iam/roles', role.id]);\n }\n\n onViewUsers(role: IRole): void {\n this.selectedRole.set(role);\n this.permittedUsersDialogVisible.set(true);\n }\n\n onDelete(role: IRole): void {\n this.confirmationService.confirm({\n message: this.translate('shared.confirm.delete.item', {\n name: role.name,\n }),\n header: this.translate('iam.role.delete.title'),\n icon: 'exclamation-triangle',\n accept: async () => {\n try {\n const response = await this.roleApi.delete({\n id: role.id,\n type: 'permanent',\n });\n\n this.roles.update((list) => list.filter((r) => r.id !== role.id));\n this.total.update((t) => Math.max(0, t - 1));\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 } catch {\n // Error toast handled by global interceptor\n }\n },\n });\n }\n\n onLazyLoad(event: { first?: number | null; rows?: number | null }): void {\n this.first.set(event.first ?? 0);\n this.pageSize.set(event.rows ?? 10);\n this.loadRoles();\n }\n\n onSearchChange(value: string): void {\n this._searchTerm.set(value);\n this.first.set(0);\n this.loadRoles();\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flusys-ng-iam-role-list-page.component-Dhd0AtOg.mjs","names":[],"sources":["../../../projects/ng-iam/pages/role/role-list-page.component.ts"],"sourcesContent":["import {\n Component,\n computed,\n effect,\n inject,\n signal,\n untracked,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { Router } from '@angular/router';\nimport {\n APP_CONFIG,\n DEFAULT_APP_NAME,\n getPermissionMode,\n isCompanyFeatureEnabled,\n} from '@flusys/ng-core';\nimport { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';\nimport {\n HasPermissionDirective,\n ROLE_PERMISSIONS,\n TranslatePipe,\n TranslateService,\n USER_ROLE_PERMISSIONS,\n} from '@flusys/ng-shared';\nimport {\n ConfirmationService,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n MessageService,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport { RolePermittedUsersDialogComponent } from '../../components/role-permitted-users-dialog.component';\nimport { IRole } from '../../interfaces/role.interface';\nimport { RoleApiService } from '../../services/role-api.service';\n\n@Component({\n selector: 'lib-role-list-page',\n imports: [\n FButtonDirective,\n FormsModule,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n HasPermissionDirective,\n RolePermittedUsersDialogComponent,\n TranslatePipe,\n ],\n template: `\n <div class=\"card\">\n <div\n class=\"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 mb-4\"\n >\n <div>\n <h3 class=\"text-lg sm:text-xl font-semibold\">\n {{ 'iam.role.title' | translate }}\n </h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n {{ 'iam.company.title' | translate }}: {{ currentCompanyName() }}\n </p>\n }\n </div>\n <div class=\"flex flex-wrap items-center gap-2 w-full sm:w-auto\">\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [placeholder]=\"'shared.search' | translate\"\n class=\"w-full\"\n />\n </f-iconfield>\n <button\n fButton\n *hasPermission=\"ROLE_PERMISSIONS.CREATE\"\n (click)=\"onCreate()\"\n class=\"w-full sm:w-auto\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'iam.role.new' | translate }}</span>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-x-auto -mx-4 sm:mx-0\">\n <f-table\n [value]=\"roles()\"\n [loading]=\"isLoading()\"\n [paginator]=\"total() > 0\"\n [rows]=\"pageSize()\"\n [first]=\"first()\"\n [totalRecords]=\"total()\"\n [lazy]=\"true\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n [rowsPerPageOptions]=\"[10, 25, 50]\"\n [scrollable]=\"true\"\n [tableStyle]=\"{ 'min-width': '40rem' }\"\n >\n <ng-template #header>\n <tr>\n <th>{{ 'iam.role.name' | translate }}</th>\n <th class=\"hidden md:table-cell\">\n {{ 'shared.description' | translate }}\n </th>\n <th>{{ 'shared.active' | translate }}</th>\n <th class=\"hidden sm:table-cell\">\n {{ 'shared.read.only' | translate }}\n </th>\n <th class=\"w-[120px]\">{{ 'shared.actions' | translate }}</th>\n </tr>\n </ng-template>\n <ng-template #body let-role>\n <tr>\n <td>{{ role.name }}</td>\n <td class=\"hidden md:table-cell\">\n {{ role.description ?? '-' }}\n </td>\n <td>\n <f-tag\n [value]=\"\n role.isActive\n ? ('shared.active' | translate)\n : ('shared.inactive' | translate)\n \"\n [severity]=\"role.isActive ? 'success' : 'secondary'\"\n />\n </td>\n <td class=\"hidden sm:table-cell\">\n <f-tag\n [value]=\"\n role.readOnly\n ? ('shared.yes' | translate)\n : ('shared.no' | translate)\n \"\n [severity]=\"role.readOnly ? 'warn' : 'secondary'\"\n />\n </td>\n <td>\n <div class=\"flex gap-1\">\n <button\n fButton\n *hasPermission=\"ROLE_PERMISSIONS.UPDATE\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n [disabled]=\"role.readOnly\"\n [fTooltip]=\"'shared.edit' | translate\"\n (click)=\"onEdit(role)\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n @if (showRoleUsers()) {\n <button\n fButton\n *hasPermission=\"USER_ROLE_PERMISSIONS.READ\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n [fTooltip]=\"'iam.permission.view.users' | translate\"\n (click)=\"onViewUsers(role)\"\n >\n <ui-icon pButtonIcon name=\"users\"></ui-icon>\n </button>\n }\n <button\n fButton\n *hasPermission=\"ROLE_PERMISSIONS.DELETE\"\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n [fTooltip]=\"'shared.delete' | translate\"\n [disabled]=\"role.readOnly\"\n (click)=\"onDelete(role)\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n </div>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td colspan=\"5\" class=\"text-center py-4 text-muted-color\">\n {{ 'iam.role.no.roles' | translate }}\n </td>\n </tr>\n </ng-template>\n </f-table>\n </div>\n </div>\n\n <flusys-role-permitted-users-dialog\n [visible]=\"permittedUsersDialogVisible()\"\n [role]=\"selectedRole()\"\n (closed)=\"permittedUsersDialogVisible.set(false)\"\n />\n `,\n})\nexport class RoleListPageComponent {\n readonly ROLE_PERMISSIONS = ROLE_PERMISSIONS;\n readonly USER_ROLE_PERMISSIONS = USER_ROLE_PERMISSIONS;\n\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 confirmationService = inject(ConfirmationService);\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\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 roles = signal<IRole[]>([]);\n readonly isLoading = signal(false);\n readonly total = signal(0);\n readonly pageSize = signal(10);\n readonly first = signal(0);\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n readonly showCompanyInfo = computed(\n () => this.appConfig.enableCompanyFeature,\n );\n readonly showRoleUsers = computed(() => {\n const permissionMode = getPermissionMode(this.appConfig);\n return permissionMode === 'rbac' || permissionMode === 'full';\n });\n readonly currentCompanyName = computed(\n () => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME,\n );\n\n readonly permittedUsersDialogVisible = signal(false);\n readonly selectedRole = signal<IRole | null>(null);\n\n private previousCompanyId: string | undefined | null = undefined;\n\n constructor() {\n effect(() => {\n const currentCompanyId =\n this.companyContext.currentCompanyInfo()?.id ?? null;\n if (this.previousCompanyId === undefined) {\n this.previousCompanyId = currentCompanyId;\n return;\n }\n if (this.previousCompanyId === currentCompanyId) return;\n this.previousCompanyId = currentCompanyId;\n untracked(() => {\n this.first.set(0);\n this.loadRoles();\n });\n });\n }\n\n private loadSeq = 0;\n\n private async loadRoles(): Promise<void> {\n const seq = ++this.loadSeq;\n this.isLoading.set(true);\n try {\n const enableCompanyFeature = isCompanyFeatureEnabled(this.appConfig);\n const companyId = enableCompanyFeature\n ? this.companyContext.currentCompanyInfo()?.id || undefined\n : undefined;\n\n const selectFields = [\n 'id',\n 'name',\n 'description',\n 'isActive',\n 'readOnly',\n 'serial',\n 'createdAt',\n 'deletedAt',\n ];\n if (enableCompanyFeature) {\n selectFields.push('companyId');\n }\n\n const response = await this.roleApi.getAll(\n {\n filter: companyId ? { companyId } : undefined,\n pagination: {\n currentPage: Math.floor(this.first() / this.pageSize()),\n pageSize: this.pageSize(),\n },\n select: selectFields,\n sort: { id: 'ASC' },\n },\n this._searchTerm(),\n );\n\n if (seq !== this.loadSeq) return;\n this.roles.set(response?.data ?? []);\n this.total.set(response?.meta?.total ?? 0);\n } catch {\n // Error toast handled by global interceptor\n } finally {\n if (seq === this.loadSeq) this.isLoading.set(false);\n }\n }\n\n onCreate(): void {\n this.router.navigate(['/iam/roles/new']);\n }\n\n onEdit(role: IRole): void {\n this.router.navigate(['/iam/roles', role.id]);\n }\n\n onViewUsers(role: IRole): void {\n this.selectedRole.set(role);\n this.permittedUsersDialogVisible.set(true);\n }\n\n onDelete(role: IRole): void {\n this.confirmationService.confirm({\n message: this.translate('shared.confirm.delete.item', {\n name: role.name,\n }),\n header: this.translate('iam.role.delete.title'),\n icon: 'exclamation-triangle',\n accept: async () => {\n try {\n const response = await this.roleApi.delete({\n id: role.id,\n type: 'permanent',\n });\n\n this.roles.update((list) => list.filter((r) => r.id !== role.id));\n this.total.update((t) => Math.max(0, t - 1));\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 } catch {\n // Error toast handled by global interceptor\n }\n },\n });\n }\n\n onLazyLoad(event: { first?: number | null; rows?: number | null }): void {\n this.first.set(event.first ?? 0);\n this.pageSize.set(event.rows ?? 10);\n this.loadRoles();\n }\n\n onSearchChange(value: string): void {\n this._searchTerm.set(value);\n this.first.set(0);\n this.loadRoles();\n }\n}\n"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { t as RoleApiService } from "./flusys-ng-iam-role-api.service-OwPgmSFc.m
|
|
|
2
2
|
import { a as ActionApiService, i as flattenTree, n as buildTreeFromFlat, r as convertActionToTreeNode } from "./flusys-ng-iam-tree-utils-B1pBG4At.mjs";
|
|
3
3
|
import { t as PermissionApiService } from "./flusys-ng-iam-permission-api.service-C7-Yxvz8.mjs";
|
|
4
4
|
import * as i0 from "@angular/core";
|
|
5
|
-
import { Component, DestroyRef, Service, computed, effect, inject, signal, viewChild } from "@angular/core";
|
|
5
|
+
import { Component, DestroyRef, Service, computed, effect, inject, signal, untracked, viewChild } from "@angular/core";
|
|
6
6
|
import { COMPANY_ACTION_PERMISSIONS, COMPANY_API_PROVIDER, HasPermissionDirective, ROLE_ACTION_PERMISSIONS, TranslatePipe, TranslateService, USER_ACTION_PERMISSIONS, USER_PERMISSION_PROVIDER, USER_ROLE_PERMISSIONS, UserSelectComponent, buildBranchTreeNodes } from "@flusys/ng-shared";
|
|
7
7
|
import { APP_CONFIG, isCompanyFeatureEnabled } from "@flusys/ng-core";
|
|
8
8
|
import { CheckboxComponent, ConfirmationService, FButtonDirective, MessageService, SelectComponent, TableComponent, TagComponent, TooltipDirective, TreeSelectComponent, TreeTableComponent, TreeTableTogglerComponent, UiIconComponent } from "@flusys/ng-ui";
|
|
@@ -190,7 +190,7 @@ var ActionPermissionLogicService = class ActionPermissionLogicService {
|
|
|
190
190
|
}
|
|
191
191
|
showPrerequisiteDialog(action, missingActions, currentSelection, allActions, previousState, onUpdate, onCancel) {
|
|
192
192
|
const logicMessage = action.permissionLogic ? this.buildLogicMessage(action.permissionLogic, missingActions, allActions, currentSelection) : this.buildSimpleMessage(missingActions);
|
|
193
|
-
const actionsToSelect = action.permissionLogic ? this.calculateSmartSelection(action.permissionLogic,
|
|
193
|
+
const actionsToSelect = action.permissionLogic ? this.calculateSmartSelection(action.permissionLogic, currentSelection, allActions) : missingActions;
|
|
194
194
|
const selectionCount = actionsToSelect.length;
|
|
195
195
|
const sanitizedActionName = this.sanitizeHtml(action.name ?? this.t("iam.logic.unknown.action"));
|
|
196
196
|
const acceptLabel = selectionCount === 0 ? this.t("iam.logic.select.action.label") : this.t("iam.logic.auto.select.actions");
|
|
@@ -328,28 +328,24 @@ var ActionPermissionLogicService = class ActionPermissionLogicService {
|
|
|
328
328
|
}
|
|
329
329
|
return null;
|
|
330
330
|
}
|
|
331
|
-
calculateSmartSelection(logic,
|
|
332
|
-
const missingIds = new Set(missingActions.map((a) => a.id));
|
|
331
|
+
calculateSmartSelection(logic, currentSelection, allActions) {
|
|
333
332
|
const actionMap = new Map(allActions.map((a) => [a.id, a]));
|
|
334
333
|
const selectedIds = this.getSelectedIds(currentSelection);
|
|
335
|
-
const requiredIds = this.findRequiredActionIds(logic,
|
|
334
|
+
const requiredIds = this.findRequiredActionIds(logic, selectedIds);
|
|
336
335
|
return Array.from(requiredIds).map((id) => actionMap.get(id)).filter((a) => !!a);
|
|
337
336
|
}
|
|
338
|
-
findRequiredActionIds(node,
|
|
339
|
-
if (node.type === "action" && node.actionId)
|
|
340
|
-
if (missingIds.has(node.actionId)) return /* @__PURE__ */ new Set([node.actionId]);
|
|
341
|
-
return /* @__PURE__ */ new Set();
|
|
342
|
-
}
|
|
337
|
+
findRequiredActionIds(node, selectedIds) {
|
|
338
|
+
if (node.type === "action" && node.actionId) return selectedIds.has(node.actionId) ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([node.actionId]);
|
|
343
339
|
if (node.type === "group" && node.children && node.children.length > 0) {
|
|
344
340
|
if ((node.operator || "AND") === "AND") {
|
|
345
341
|
const required = /* @__PURE__ */ new Set();
|
|
346
|
-
for (const child of node.children) this.findRequiredActionIds(child,
|
|
342
|
+
for (const child of node.children) this.findRequiredActionIds(child, selectedIds).forEach((id) => required.add(id));
|
|
347
343
|
return required;
|
|
348
344
|
} else {
|
|
349
345
|
let minRequired = null;
|
|
350
346
|
let minSize = Infinity;
|
|
351
347
|
for (const child of node.children) {
|
|
352
|
-
const childRequired = this.findRequiredActionIds(child,
|
|
348
|
+
const childRequired = this.findRequiredActionIds(child, selectedIds);
|
|
353
349
|
if (childRequired.size === 0) return /* @__PURE__ */ new Set();
|
|
354
350
|
if (childRequired.size < minSize) {
|
|
355
351
|
minSize = childRequired.size;
|
|
@@ -447,16 +443,14 @@ var BaseActionSelectorComponent = class {
|
|
|
447
443
|
treeNodes = computed(() => convertActionToTreeNode(this.actionsTree()), ...ngDevMode ? [{ debugName: "treeNodes" }] : /* istanbul ignore next */ []);
|
|
448
444
|
allSelected = computed(() => {
|
|
449
445
|
const selMap = this.selectionMap();
|
|
450
|
-
const
|
|
451
|
-
if (
|
|
452
|
-
return
|
|
446
|
+
const actions = this.actions();
|
|
447
|
+
if (actions.length === 0) return false;
|
|
448
|
+
return actions.every((a) => selMap[a.id]);
|
|
453
449
|
}, ...ngDevMode ? [{ debugName: "allSelected" }] : /* istanbul ignore next */ []);
|
|
454
450
|
hasChanges = computed(() => {
|
|
455
451
|
const current = this.selectionMap();
|
|
456
452
|
const initial = this.initialSelection();
|
|
457
|
-
|
|
458
|
-
if (currentKeys.length !== Object.keys(initial).length) return true;
|
|
459
|
-
return currentKeys.some((key) => current[key] !== initial[key]);
|
|
453
|
+
return [.../* @__PURE__ */ new Set([...Object.keys(current), ...Object.keys(initial)])].some((key) => !!current[key] !== !!initial[key]);
|
|
460
454
|
}, ...ngDevMode ? [{ debugName: "hasChanges" }] : /* istanbul ignore next */ []);
|
|
461
455
|
actionsWithUnmetPrerequisites = computed(() => {
|
|
462
456
|
const selMap = this.selectionMap();
|
|
@@ -590,6 +584,8 @@ var RoleActionSelectorComponent = class RoleActionSelectorComponent extends Base
|
|
|
590
584
|
async onRoleChange(signal) {
|
|
591
585
|
const roleId = this.selectedRoleId();
|
|
592
586
|
if (!roleId) return;
|
|
587
|
+
this._selectionMap.set({});
|
|
588
|
+
this._initialSelection.set({});
|
|
593
589
|
this.loading.set(true);
|
|
594
590
|
try {
|
|
595
591
|
const actionsResponse = await firstValueFrom(this.actionApi.getActionsForPermission());
|
|
@@ -1532,6 +1528,8 @@ var CompanyActionSelectorComponent = class CompanyActionSelectorComponent extend
|
|
|
1532
1528
|
async loadData(signal) {
|
|
1533
1529
|
const companyId = this.selectedCompanyId();
|
|
1534
1530
|
if (!companyId) return;
|
|
1531
|
+
this._selectionMap.set({});
|
|
1532
|
+
this._initialSelection.set({});
|
|
1535
1533
|
this.loading.set(true);
|
|
1536
1534
|
try {
|
|
1537
1535
|
const actionsResponse = await firstValueFrom(this.actionApi.getTree(void 0, void 0, false));
|
|
@@ -1587,7 +1585,7 @@ var CompanyActionSelectorComponent = class CompanyActionSelectorComponent extend
|
|
|
1587
1585
|
}).join("\n");
|
|
1588
1586
|
this.confirmationService.confirm({
|
|
1589
1587
|
header: this.translate("iam.permission.prerequisite.validation.failed"),
|
|
1590
|
-
message: `${this.translate("iam.permission.prerequisite.error.message")}\n\n${errorList}\n\n${this.translate("iam.
|
|
1588
|
+
message: `${this.translate("iam.permission.prerequisite.error.message")}\n\n${errorList}\n\n${this.translate("iam.logic.would.you.continue")}`,
|
|
1591
1589
|
icon: "exclamation-triangle",
|
|
1592
1590
|
acceptLabel: this.translate("iam.permission.auto.select.required"),
|
|
1593
1591
|
rejectLabel: this.translate("shared.cancel"),
|
|
@@ -2537,14 +2535,16 @@ var UserRoleSelectorComponent = class UserRoleSelectorComponent {
|
|
|
2537
2535
|
constructor() {
|
|
2538
2536
|
effect(() => {
|
|
2539
2537
|
const userId = this.selectedUserId();
|
|
2540
|
-
|
|
2541
|
-
if (isCompanyFeatureEnabled(this.appConfig)) this.loadUserBranches(userId);
|
|
2542
|
-
this.loadData();
|
|
2543
|
-
} else {
|
|
2544
|
-
this._branches.set([]);
|
|
2538
|
+
untracked(() => {
|
|
2545
2539
|
this.selectedBranchId.set(void 0);
|
|
2546
|
-
|
|
2547
|
-
|
|
2540
|
+
if (userId) {
|
|
2541
|
+
if (isCompanyFeatureEnabled(this.appConfig)) this.loadUserBranches(userId);
|
|
2542
|
+
this.loadData();
|
|
2543
|
+
} else {
|
|
2544
|
+
this._branches.set([]);
|
|
2545
|
+
this.resetState();
|
|
2546
|
+
}
|
|
2547
|
+
});
|
|
2548
2548
|
});
|
|
2549
2549
|
effect(() => {
|
|
2550
2550
|
const userId = this.selectedUserId();
|
|
@@ -2564,19 +2564,26 @@ var UserRoleSelectorComponent = class UserRoleSelectorComponent {
|
|
|
2564
2564
|
this._branches.set(toUserBranches(response?.data));
|
|
2565
2565
|
} catch {}
|
|
2566
2566
|
}
|
|
2567
|
+
loadSeq = 0;
|
|
2567
2568
|
async loadData() {
|
|
2568
2569
|
const userId = this.selectedUserId();
|
|
2569
2570
|
if (!userId) return;
|
|
2570
2571
|
const branchId = this.selectedBranchId();
|
|
2572
|
+
const seq = ++this.loadSeq;
|
|
2573
|
+
this._selectionMap.set({});
|
|
2574
|
+
this._initialSelection.set({});
|
|
2571
2575
|
this.loading.set(true);
|
|
2572
2576
|
try {
|
|
2573
|
-
const
|
|
2577
|
+
const rolesResponse = await this.roleApi.getAll({ pagination: {
|
|
2574
2578
|
currentPage: 0,
|
|
2575
2579
|
pageSize: 100
|
|
2576
|
-
} })
|
|
2580
|
+
} });
|
|
2581
|
+
if (seq !== this.loadSeq) return;
|
|
2582
|
+
const rolesList = rolesResponse?.data ?? [];
|
|
2577
2583
|
this._roles.set(rolesList);
|
|
2578
2584
|
const query = isCompanyFeatureEnabled(this.appConfig) && branchId ? { branchId } : void 0;
|
|
2579
2585
|
const assignedResponse = await firstValueFrom(this.permissionApi.getUserRoles(userId, query));
|
|
2586
|
+
if (seq !== this.loadSeq) return;
|
|
2580
2587
|
const assignedIds = new Set((assignedResponse?.data || []).map((r) => r.roleId));
|
|
2581
2588
|
const selMap = {};
|
|
2582
2589
|
rolesList.forEach((role) => {
|
|
@@ -2585,7 +2592,7 @@ var UserRoleSelectorComponent = class UserRoleSelectorComponent {
|
|
|
2585
2592
|
this._selectionMap.set(selMap);
|
|
2586
2593
|
this._initialSelection.set({ ...selMap });
|
|
2587
2594
|
} catch {} finally {
|
|
2588
|
-
this.loading.set(false);
|
|
2595
|
+
if (seq === this.loadSeq) this.loading.set(false);
|
|
2589
2596
|
}
|
|
2590
2597
|
}
|
|
2591
2598
|
getTooltip(role) {
|
|
@@ -3512,8 +3519,9 @@ var UserActionSelectorComponent = class UserActionSelectorComponent extends Base
|
|
|
3512
3519
|
this._selectedBranchId.set(void 0);
|
|
3513
3520
|
this._branches.set([]);
|
|
3514
3521
|
if (!companyId) {
|
|
3515
|
-
this.
|
|
3516
|
-
this.
|
|
3522
|
+
this.loadSeq++;
|
|
3523
|
+
this.loading.set(false);
|
|
3524
|
+
this.resetState();
|
|
3517
3525
|
return;
|
|
3518
3526
|
}
|
|
3519
3527
|
await this.loadUserBranches(userId, companyId);
|
|
@@ -3553,14 +3561,20 @@ var UserActionSelectorComponent = class UserActionSelectorComponent extends Base
|
|
|
3553
3561
|
isCurrentSelection(userId, companyId) {
|
|
3554
3562
|
return this.selectedUserId() === userId && this.selectedCompanyId() === companyId;
|
|
3555
3563
|
}
|
|
3564
|
+
loadSeq = 0;
|
|
3556
3565
|
async loadData() {
|
|
3557
3566
|
const userId = this.selectedUserId();
|
|
3558
3567
|
if (!userId) return;
|
|
3559
3568
|
const branchId = this.selectedBranchId();
|
|
3560
3569
|
const companyId = this.selectedCompanyId();
|
|
3570
|
+
const seq = ++this.loadSeq;
|
|
3571
|
+
this._selectionMap.set({});
|
|
3572
|
+
this._initialSelection.set({});
|
|
3561
3573
|
this.loading.set(true);
|
|
3562
3574
|
try {
|
|
3563
|
-
const
|
|
3575
|
+
const actionsResponse = await firstValueFrom(this.actionApi.getActionsForPermission(this.isCompanyFeatureActive() ? companyId : void 0));
|
|
3576
|
+
if (seq !== this.loadSeq) return;
|
|
3577
|
+
const flatActions = actionsResponse?.data ?? [];
|
|
3564
3578
|
const actionsTree = buildTreeFromFlat(flatActions);
|
|
3565
3579
|
this._actionsTree.set(actionsTree);
|
|
3566
3580
|
this._actions.set(flatActions);
|
|
@@ -3569,12 +3583,13 @@ var UserActionSelectorComponent = class UserActionSelectorComponent extends Base
|
|
|
3569
3583
|
branchId
|
|
3570
3584
|
} : void 0;
|
|
3571
3585
|
const assignedResponse = await firstValueFrom(this.permissionApi.getUserActions(userId, query));
|
|
3586
|
+
if (seq !== this.loadSeq) return;
|
|
3572
3587
|
const assignedIds = new Set((assignedResponse?.data || []).map((a) => a.actionId));
|
|
3573
3588
|
const selMap = this.buildSelectionMap(flatActions, (action) => assignedIds.has(action.id));
|
|
3574
3589
|
this._selectionMap.set(selMap);
|
|
3575
3590
|
this._initialSelection.set({ ...selMap });
|
|
3576
3591
|
} catch {} finally {
|
|
3577
|
-
this.loading.set(false);
|
|
3592
|
+
if (seq === this.loadSeq) this.loading.set(false);
|
|
3578
3593
|
}
|
|
3579
3594
|
}
|
|
3580
3595
|
async saveChanges() {
|
|
@@ -4589,4 +4604,4 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
4589
4604
|
});
|
|
4590
4605
|
export { ActionPermissionLogicService as a, RoleActionSelectorComponent as i, UserRoleSelectorComponent as n, MAX_DROPDOWN_ITEMS as o, CompanyActionSelectorComponent as r, UserActionSelectorComponent as t };
|
|
4591
4606
|
|
|
4592
|
-
//# sourceMappingURL=flusys-ng-iam-user-action-selector.component-
|
|
4607
|
+
//# sourceMappingURL=flusys-ng-iam-user-action-selector.component-2wdl9Ci6.mjs.map
|