@flusys/ng-iam 9.1.2 → 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.
@@ -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-Br0PbgRa.mjs.map
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-CAXEmJWx.mjs";
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-BlNt83uR.mjs.map
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":";;;;;;AAqCA,MAAM,kBAAkB;CACtB,gBAAgB,wBAAwB;CACxC,cAAc,sBAAsB;CACpC,gBAAgB,wBAAwB;CACxC,mBAAmB,2BAA2B;AACtC;AAoEV,IAAa,0BAAb,MAAa,wBAAuB;CACjB,YAAY,OAAO,UAAU;CAC7B,sBAAsB,OAAO,mBAAmB;CAChD,mBAAmB,OAAO,gBAAgB;CAC1C,sBAAsB,OAAO,0BAA0B;CAEvD,UAAU,UAAyB,QAAO,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAC1C,oBACf,UAAkC,eAAc,GAAA,YAAA,CAAA,EAAA,WAAA,oBAAA,CAAA,+BAAA,CAAA,CAAA;CAEzC,YAAY,OAAe,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAG9B,gBAAgB,eAAc;EACrC,MAAM,iBAAiB,kBAAkB,KAAK,SAAS;EACvD,MAAM,OAKD,CAAA;EAEL,IAAI,mBAAmB,UAAU,mBAAmB,QAClD,KAAK,KACH;GACE,IAAI;GACJ,UAAU;GACV,MAAM;GACN,YAAY,gBAAgB;EAC7B,GACD;GACE,IAAI;GACJ,UAAU;GACV,MAAM;GACN,YAAY,gBAAgB;EAC7B,CAAA;EAIL,IAAI,mBAAmB,YAAY,mBAAmB,QACpD,KAAK,KAAK;GACR,IAAI;GACJ,UAAU;GACV,MAAM;GACN,YAAY,gBAAgB;EAC7B,CAAA;EAGH,IAAI,wBAAwB,KAAK,SAAS,GACxC,KAAK,KAAK;GACR,IAAI;GACJ,UAAU;GACV,MAAM;GACN,YAAY,gBAAgB;EAC7B,CAAA;EAGH,OAAO,KAAK,QAAQ,QAClB,KAAK,oBAAoB,cAAc,IAAI,UAAU,CAAC;CAE1D,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;CAEF,cAAA;EACE,aAAY;GACV,MAAM,OAAO,KAAK,cAAa;GAC/B,MAAM,aAAa,gBAAgB,KAAK,UAAS,CAAE;GACnD,IAAI,CAAC,cAAc,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,UAAU,GACtD,KAAK,UAAU,IAAI,KAAK,EAAE,EAAE,MAAM,EAAE;EAExC,CAAC;CACH;CAEA,aAAa,OAAsB;EACjC,MAAM,UAAU,OAAO,KAAK;EAC5B,MAAM,cAAc,KAAK,UAAS;EAClC,IAAI,YAAY,aAAa;EAE7B,IAAI,KAAK,kBAAiB,CAAE,EAAE,WAAU,GAAI;GAC1C,KAAK,oBAAoB,QAAQ;IAC/B,QAAQ,KAAK,iBAAiB,UAC5B,sCAAsC;IAExC,SAAS,KAAK,iBAAiB,UAC7B,wCAAwC;IAE1C,MAAM;IACN,aAAa,KAAK,iBAAiB,UACjC,wCAAwC;IAE1C,aAAa,KAAK,iBAAiB,UAAU,eAAe;IAC5D,cAAc,KAAK,UAAU,IAAI,OAAO;IACxC,cAAc,KAAK,QAAO,CAAE,EAAE,MAAM,IAAI,WAAW;GACpD,CAAA;GACD;EACF;EAEA,KAAK,UAAU,IAAI,OAAO;CAC5B;CAjGW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAuB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAvB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAuB,cAAA;EAAA,UAAA;EAAA,aAAA,CAAA;GAAA,cAAA;GAAA,OAAA;GAAA,WAAA,CAAA,MAAA;GAAA,aAAA;GAAA,UAAA;EAAA,GAAA;GAAA,cAAA;GAAA,OAAA;GAAA,WAAA,CAAA,aAAA;GAAA,aAAA;GAAA,UAAA;EAAA,CAAA;EAAA,UAAA;EAAA,UA9CxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4CT,UAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MAvDC;IAAY,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,SAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACZ;IAAgB,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAChB;IAAa,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,eAAA,aAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACb;IAAe,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACf;IAAsB,UAAA;IAAA,QAAA,CAAA,eAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAEtB;IAA2B,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAC3B;IAA8B,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAC9B;IAAyB,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACzB;IAA2B,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAJ3B;IAAa,MAAA;GAAA;EAAA;CAAA,CAAA;;AAoDJ,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAuB,YAAA,CAAA;EA5DnC,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,SAAS;IACP;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;GACD;GACD,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6CX,CAAA;CAOqD,CAAA;CAAA,sBAAA,CAAA;CAAA,gBAAA;EAAA,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,QAAM,EAAA,UAAA,KAAA,CAAA;EAAA,CAAA;EAAA,mBAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAEtB,eAAa,EAAA,UAAA,KAAA,CAAA;EAAA,CAAA;CAAA;AAAA,CAAA"}
@@ -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-BCO_gQ8k.mjs.map
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":";;;;;;;;;;;AAiNA,IAAa,wBAAb,MAAa,sBAAqB;CACvB,mBAAmB;CACnB,wBAAwB;CAEhB,SAAS,OAAO,MAAM;CACtB,YAAY,OAAO,UAAU;CAC7B,iBAAiB,OAAO,iBAAiB;CACzC,UAAU,OAAO,cAAc;CAC/B,iBAAiB,OAAO,cAAc;CACtC,sBAAsB,OAAO,mBAAmB;CAChD,mBAAmB,OAAO,kBAAkB,EAC3D,UAAU,KACX,CAAA;CAEO,UACN,KACA,MAAsC;EAEtC,OAAO,KAAK,kBAAkB,UAAU,KAAK,IAAI,KAAK;CACxD;CAES,QAAQ,OAAgB,CAAA,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAC3B,YAAY,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CACzB,QAAQ,OAAO,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACjB,WAAW,OAAO,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CACrB,QAAQ,OAAO,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACT,cAAc,OAAO,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAChC,aAAa,KAAK,YAAY,WAAU;CACxC,kBAAkB,eACnB,KAAK,UAAU,sBACtB,GAAA,YAAA,CAAA,EAAA,WAAA,kBAAA,CAAA,+BAAA,CAAA,CAAA;CACQ,gBAAgB,eAAc;EACrC,MAAM,iBAAiB,kBAAkB,KAAK,SAAS;EACvD,OAAO,mBAAmB,UAAU,mBAAmB;CACzD,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;CACO,qBAAqB,eACtB,KAAK,eAAe,mBAAkB,CAAE,EAAE,QAAQ,kBACzD,GAAA,YAAA,CAAA,EAAA,WAAA,qBAAA,CAAA,+BAAA,CAAA,CAAA;CAEQ,8BAA8B,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,8BAAA,CAAA,+BAAA,CAAA,CAAA;CAC3C,eAAe,OAAqB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CAE1C,oBAA+C;CAEvD,cAAA;EACE,aAAY;GACV,MAAM,mBACJ,KAAK,eAAe,mBAAkB,CAAE,EAAE,MAAM;GAClD,IAAI,KAAK,sBAAsB,QAAW;IACxC,KAAK,oBAAoB;IACzB;GACF;GACA,IAAI,KAAK,sBAAsB,kBAAkB;GACjD,KAAK,oBAAoB;GACzB,gBAAe;IACb,KAAK,MAAM,IAAI,CAAC;IAChB,KAAK,UAAS;GAChB,CAAC;EACH,CAAC;CACH;CAEQ,UAAU;CAEV,MAAM,YAAS;EACrB,MAAM,MAAM,EAAE,KAAK;EACnB,KAAK,UAAU,IAAI,IAAI;EACvB,IAAI;GACF,MAAM,uBAAuB,wBAAwB,KAAK,SAAS;GACnE,MAAM,YAAY,uBACd,KAAK,eAAe,mBAAkB,CAAE,EAAE,MAAM,SAChD;GAEJ,MAAM,eAAe;IACnB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;GACD;GACD,IAAI,sBACF,aAAa,KAAK,WAAW;GAG/B,MAAM,WAAW,MAAM,KAAK,QAAQ,OAClC;IACE,QAAQ,YAAY,EAAE,UAAS,IAAK;IACpC,YAAY;KACV,aAAa,KAAK,MAAM,KAAK,MAAK,IAAK,KAAK,SAAQ,CAAE;KACtD,UAAU,KAAK,SAAQ;IACxB;IACD,QAAQ;IACR,MAAM,EAAE,IAAI,MAAK;GAClB,GACD,KAAK,YAAW,CAAE;GAGpB,IAAI,QAAQ,KAAK,SAAS;GAC1B,KAAK,MAAM,IAAI,UAAU,QAAQ,CAAA,CAAE;GACnC,KAAK,MAAM,IAAI,UAAU,MAAM,SAAS,CAAC;EAC3C,QAAQ,CAER,UAAU;GACR,IAAI,QAAQ,KAAK,SAAS,KAAK,UAAU,IAAI,KAAK;EACpD;CACF;CAEA,WAAQ;EACN,KAAK,OAAO,SAAS,CAAC,gBAAgB,CAAC;CACzC;CAEA,OAAO,MAAW;EAChB,KAAK,OAAO,SAAS,CAAC,cAAc,KAAK,EAAE,CAAC;CAC9C;CAEA,YAAY,MAAW;EACrB,KAAK,aAAa,IAAI,IAAI;EAC1B,KAAK,4BAA4B,IAAI,IAAI;CAC3C;CAEA,SAAS,MAAW;EAClB,KAAK,oBAAoB,QAAQ;GAC/B,SAAS,KAAK,UAAU,8BAA8B,EACpD,MAAM,KAAK,KACZ,CAAA;GACD,QAAQ,KAAK,UAAU,uBAAuB;GAC9C,MAAM;GACN,QAAQ,YAAW;IACjB,IAAI;KACF,MAAM,WAAW,MAAM,KAAK,QAAQ,OAAO;MACzC,IAAI,KAAK;MACT,MAAM;KACP,CAAA;KAED,KAAK,MAAM,QAAQ,SAAS,KAAK,QAAQ,MAAM,EAAE,OAAO,KAAK,EAAE,CAAC;KAChE,KAAK,MAAM,QAAQ,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;KAE3C,KAAK,eAAe,IAAI;MACtB,UAAU;MACV,SAAS,KAAK,UAAU,gBAAgB;MACxC,QAAQ,UAAU,aACd,KAAK,UACH,SAAS,YACT,SAAS,gBAAmD,IAE9D,UAAU;KACf,CAAA;IACH,QAAQ,CAER;GACF;EACD,CAAA;CACH;CAEA,WAAW,OAAsD;EAC/D,KAAK,MAAM,IAAI,MAAM,SAAS,CAAC;EAC/B,KAAK,SAAS,IAAI,MAAM,QAAQ,EAAE;EAClC,KAAK,UAAS;CAChB;CAEA,eAAe,OAAa;EAC1B,KAAK,YAAY,IAAI,KAAK;EAC1B,KAAK,MAAM,IAAI,CAAC;EAChB,KAAK,UAAS;CAChB;CAtKW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAqB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAArB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAqB,cAAA;EAAA,UAAA;EAAA,UAAA;EAAA,UAzJtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuJT,UAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MApKC;IAAgB,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAChB;GAAW;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,eAAA;IAAA,UAAA,CAAA,SAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACX;IAAkB,UAAA;IAAA,QAAA,CAAA,gBAAA,YAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAClB;IAAkB,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAClB;IAAkB,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAClB;IAAc,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACd;IAAY,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACZ;IAAgB,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAChB;IAAe,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACf;IAAsB,UAAA;IAAA,QAAA,CAAA,eAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACtB;IAAiC,UAAA;IAAA,QAAA,CAAA,WAAA,MAAA;IAAA,SAAA,CAAA,QAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACjC;IAAa,MAAA;GAAA;EAAA;CAAA,CAAA;;AA2JJ,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAqB,YAAA,CAAA;EAzKjC,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,SAAS;IACP;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;GACD;GACD,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwJX,CAAA"}
@@ -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, missingActions, currentSelection, allActions) : missingActions;
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, missingActions, currentSelection, allActions) {
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, missingIds, selectedIds);
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, missingIds, selectedIds) {
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, missingIds, selectedIds).forEach((id) => required.add(id));
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, missingIds, selectedIds);
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 total = this.actions().length;
451
- if (total === 0) return false;
452
- return Object.values(selMap).filter((v) => v).length === total;
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
- const currentKeys = Object.keys(current);
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.permission.auto.select.prompt")}`,
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
- if (userId) {
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
- this.resetState();
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 rolesList = (await this.roleApi.getAll({ pagination: {
2577
+ const rolesResponse = await this.roleApi.getAll({ pagination: {
2574
2578
  currentPage: 0,
2575
2579
  pageSize: 100
2576
- } }))?.data ?? [];
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._actionsTree.set([]);
3516
- this._actions.set([]);
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 flatActions = (await firstValueFrom(this.actionApi.getActionsForPermission(this.isCompanyFeatureActive() ? companyId : void 0)))?.data ?? [];
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-CAXEmJWx.mjs.map
4607
+ //# sourceMappingURL=flusys-ng-iam-user-action-selector.component-2wdl9Ci6.mjs.map