@flusys/ng-iam 7.1.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/{flusys-ng-iam-action-form-page.component-Ci56tFEu.mjs → flusys-ng-iam-action-form-page.component-CF_ixS-r.mjs} +18 -15
- package/fesm2022/flusys-ng-iam-action-form-page.component-CF_ixS-r.mjs.map +1 -0
- package/fesm2022/{flusys-ng-iam-action-list-page.component-BRi_CpGl.mjs → flusys-ng-iam-action-list-page.component-BveT0xT6.mjs} +62 -10
- package/fesm2022/flusys-ng-iam-action-list-page.component-BveT0xT6.mjs.map +1 -0
- package/fesm2022/{flusys-ng-iam-flusys-ng-iam-BEAhj9ma.mjs → flusys-ng-iam-flusys-ng-iam-CjLr3bfY.mjs} +661 -169
- package/fesm2022/flusys-ng-iam-flusys-ng-iam-CjLr3bfY.mjs.map +1 -0
- package/fesm2022/{flusys-ng-iam-iam-container.component-D0m8u6nu.mjs → flusys-ng-iam-iam-container.component-XBoIeQ0t.mjs} +4 -4
- package/fesm2022/{flusys-ng-iam-iam-container.component-D0m8u6nu.mjs.map → flusys-ng-iam-iam-container.component-XBoIeQ0t.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-iam-permission-page.component-CVaxwwcS.mjs → flusys-ng-iam-permission-page.component-CGtj1EiO.mjs} +12 -11
- package/fesm2022/flusys-ng-iam-permission-page.component-CGtj1EiO.mjs.map +1 -0
- package/fesm2022/{flusys-ng-iam-role-form-page.component-ByMbnQ53.mjs → flusys-ng-iam-role-form-page.component-Cfc8za3D.mjs} +20 -14
- package/fesm2022/flusys-ng-iam-role-form-page.component-Cfc8za3D.mjs.map +1 -0
- package/fesm2022/{flusys-ng-iam-role-list-page.component-BCtoWvFQ.mjs → flusys-ng-iam-role-list-page.component-vFHxd3Q-.mjs} +61 -10
- package/fesm2022/flusys-ng-iam-role-list-page.component-vFHxd3Q-.mjs.map +1 -0
- package/fesm2022/flusys-ng-iam.mjs +1 -1
- package/package.json +5 -5
- package/types/flusys-ng-iam.d.ts +99 -72
- package/fesm2022/flusys-ng-iam-action-form-page.component-Ci56tFEu.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-action-list-page.component-BRi_CpGl.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-flusys-ng-iam-BEAhj9ma.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-permission-page.component-CVaxwwcS.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-role-form-page.component-ByMbnQ53.mjs.map +0 -1
- package/fesm2022/flusys-ng-iam-role-list-page.component-BCtoWvFQ.mjs.map +0 -1
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
3
|
-
import { ApiResourceService, TranslateService, PermissionValidatorService,
|
|
2
|
+
import { Service, inject, signal, input, output, effect, Component, computed, DestroyRef, viewChild } from '@angular/core';
|
|
3
|
+
import { ApiResourceService, TranslateService, PermissionValidatorService, TranslatePipe, ROLE_ACTION_PERMISSIONS, HasPermissionDirective, COMPANY_ACTION_PERMISSIONS, COMPANY_API_PROVIDER, USER_ROLE_PERMISSIONS, USER_PERMISSION_PROVIDER, UserSelectComponent, USER_ACTION_PERMISSIONS, USER_PROVIDER, PROFILE_PERMISSION_PROVIDER, ACTION_PERMISSIONS, ROLE_PERMISSIONS, permissionGuard, anyPermissionGuard, resolveTranslationModule, SHARED_MESSAGES } from '@flusys/ng-shared';
|
|
4
4
|
import { APP_CONFIG, getServiceUrl, BaseApiService, isCompanyFeatureEnabled, getPermissionMode } from '@flusys/ng-core';
|
|
5
|
-
import
|
|
6
|
-
import { ConfirmationService, MessageService, UiModule } from '@flusys/ng-ui';
|
|
5
|
+
import { ConfirmationService, MessageService, FButtonDirective, SelectComponent, TooltipDirective, UiIconComponent, CheckboxComponent, TagComponent, TreeTableComponent, TreeTableTogglerComponent, TableComponent, DialogComponent, ProgressSpinnerComponent } from '@flusys/ng-ui';
|
|
7
6
|
import { HttpClient } from '@angular/common/http';
|
|
8
7
|
import { of, firstValueFrom, map as map$1 } from 'rxjs';
|
|
9
8
|
import { tap, catchError, map } from 'rxjs/operators';
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import * as i1$1 from '@angular/forms';
|
|
9
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
10
|
+
import * as i1 from '@angular/forms';
|
|
13
11
|
import { FormsModule } from '@angular/forms';
|
|
14
12
|
import { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';
|
|
15
13
|
|
|
@@ -85,6 +83,11 @@ const IAM_MESSAGES = {
|
|
|
85
83
|
'iam.action.type.backend': 'Backend',
|
|
86
84
|
'iam.action.type.frontend': 'Frontend',
|
|
87
85
|
'iam.action.type.both': 'Both',
|
|
86
|
+
// components/role-permitted-users-dialog.component.ts, components/action-permitted-users-dialog.component.ts
|
|
87
|
+
'iam.permission.view.users': 'View Users',
|
|
88
|
+
'iam.permission.no.users': 'No users found',
|
|
89
|
+
'iam.permission.remove': 'Remove Access',
|
|
90
|
+
'iam.permission.remove.confirm': 'Remove access for {{name}}?',
|
|
88
91
|
'iam.action.delete.title': 'Delete Action',
|
|
89
92
|
// pages/action/action-form-page.component.ts
|
|
90
93
|
'iam.action.edit': 'Edit Action',
|
|
@@ -239,12 +242,11 @@ class RoleApiService extends ApiResourceService {
|
|
|
239
242
|
constructor() {
|
|
240
243
|
super('roles', 'iam');
|
|
241
244
|
}
|
|
242
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
243
|
-
static ɵprov = i0.ɵɵ
|
|
245
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: RoleApiService, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
246
|
+
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.5", ngImport: i0, type: RoleApiService });
|
|
244
247
|
}
|
|
245
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
246
|
-
type:
|
|
247
|
-
args: [{ providedIn: 'root' }]
|
|
248
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: RoleApiService, decorators: [{
|
|
249
|
+
type: Service
|
|
248
250
|
}], ctorParameters: () => [] });
|
|
249
251
|
|
|
250
252
|
class ActionApiService extends ApiResourceService {
|
|
@@ -269,12 +271,11 @@ class ActionApiService extends ApiResourceService {
|
|
|
269
271
|
const iamBaseUrl = getServiceUrl(this.appConfig, 'iam');
|
|
270
272
|
return this.http.post(`${iamBaseUrl}/actions/tree`, body);
|
|
271
273
|
}
|
|
272
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
273
|
-
static ɵprov = i0.ɵɵ
|
|
274
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ActionApiService, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
275
|
+
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.5", ngImport: i0, type: ActionApiService });
|
|
274
276
|
}
|
|
275
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
276
|
-
type:
|
|
277
|
-
args: [{ providedIn: 'root' }]
|
|
277
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ActionApiService, decorators: [{
|
|
278
|
+
type: Service
|
|
278
279
|
}], ctorParameters: () => [] });
|
|
279
280
|
|
|
280
281
|
function extractRequiredActionIds(logic) {
|
|
@@ -806,12 +807,11 @@ class ActionPermissionLogicService {
|
|
|
806
807
|
}
|
|
807
808
|
return `${indent}${this.t('iam.logic.invalid')}`;
|
|
808
809
|
}
|
|
809
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
810
|
-
static ɵprov = i0.ɵɵ
|
|
810
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ActionPermissionLogicService, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
811
|
+
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.5", ngImport: i0, type: ActionPermissionLogicService });
|
|
811
812
|
}
|
|
812
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
813
|
-
type:
|
|
814
|
-
args: [{ providedIn: 'root' }]
|
|
813
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ActionPermissionLogicService, decorators: [{
|
|
814
|
+
type: Service
|
|
815
815
|
}] });
|
|
816
816
|
|
|
817
817
|
class PermissionApiService extends BaseApiService {
|
|
@@ -836,6 +836,14 @@ class PermissionApiService extends BaseApiService {
|
|
|
836
836
|
getRoleActions(roleId) {
|
|
837
837
|
return this.http.post(this.getUrl('permissions/get-role-actions'), { roleId });
|
|
838
838
|
}
|
|
839
|
+
/** Reverse lookup: users assigned to a role */
|
|
840
|
+
getRoleUsers(roleId) {
|
|
841
|
+
return this.http.post(this.getUrl('permissions/get-role-users'), { roleId });
|
|
842
|
+
}
|
|
843
|
+
/** Reverse lookup: users directly assigned an action */
|
|
844
|
+
getActionUsers(actionId) {
|
|
845
|
+
return this.http.post(this.getUrl('permissions/get-action-users'), { actionId });
|
|
846
|
+
}
|
|
839
847
|
assignCompanyActions(data) {
|
|
840
848
|
return this.http.post(this.getUrl('permissions/company-actions/assign'), data);
|
|
841
849
|
}
|
|
@@ -850,12 +858,11 @@ class PermissionApiService extends BaseApiService {
|
|
|
850
858
|
getMyActions() {
|
|
851
859
|
return this.http.post(this.getUrl('permissions/my-actions'), {});
|
|
852
860
|
}
|
|
853
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
854
|
-
static ɵprov = i0.ɵɵ
|
|
861
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PermissionApiService, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
862
|
+
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.5", ngImport: i0, type: PermissionApiService });
|
|
855
863
|
}
|
|
856
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
857
|
-
type:
|
|
858
|
-
args: [{ providedIn: 'root' }]
|
|
864
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PermissionApiService, decorators: [{
|
|
865
|
+
type: Service
|
|
859
866
|
}], ctorParameters: () => [] });
|
|
860
867
|
|
|
861
868
|
/**
|
|
@@ -877,14 +884,11 @@ class MyPermissionsApiService {
|
|
|
877
884
|
getMyPermissions(dto = {}) {
|
|
878
885
|
return this.http.post(`${this.baseUrl}/my-permissions`, dto);
|
|
879
886
|
}
|
|
880
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
881
|
-
static ɵprov = i0.ɵɵ
|
|
887
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: MyPermissionsApiService, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
888
|
+
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.5", ngImport: i0, type: MyPermissionsApiService });
|
|
882
889
|
}
|
|
883
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
884
|
-
type:
|
|
885
|
-
args: [{
|
|
886
|
-
providedIn: 'root',
|
|
887
|
-
}]
|
|
890
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: MyPermissionsApiService, decorators: [{
|
|
891
|
+
type: Service
|
|
888
892
|
}] });
|
|
889
893
|
|
|
890
894
|
class PermissionStateService {
|
|
@@ -913,12 +917,11 @@ class PermissionStateService {
|
|
|
913
917
|
isLoaded() {
|
|
914
918
|
return this._permissions() !== null && this.permissionValidator.isLoaded();
|
|
915
919
|
}
|
|
916
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
917
|
-
static ɵprov = i0.ɵɵ
|
|
920
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PermissionStateService, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
921
|
+
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.5", ngImport: i0, type: PermissionStateService });
|
|
918
922
|
}
|
|
919
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
920
|
-
type:
|
|
921
|
-
args: [{ providedIn: 'root' }]
|
|
923
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PermissionStateService, decorators: [{
|
|
924
|
+
type: Service
|
|
922
925
|
}] });
|
|
923
926
|
|
|
924
927
|
// Role services
|
|
@@ -948,14 +951,12 @@ function createGroupNode(operator = 'AND') {
|
|
|
948
951
|
function createActionNode(actionId = '') {
|
|
949
952
|
return { id: crypto.randomUUID(), type: 'action', actionId };
|
|
950
953
|
}
|
|
951
|
-
/** Visual builder for AND/OR permission logic trees */
|
|
952
954
|
class LogicBuilderComponent {
|
|
953
955
|
logic = input(null, /* @ts-ignore */
|
|
954
956
|
...(ngDevMode ? [{ debugName: "logic" }] : /* istanbul ignore next */ []));
|
|
955
957
|
actions = input([], /* @ts-ignore */
|
|
956
958
|
...(ngDevMode ? [{ debugName: "actions" }] : /* istanbul ignore next */ []));
|
|
957
959
|
logicChange = output();
|
|
958
|
-
/** Internal builder tree state (private writable + public readonly pattern) */
|
|
959
960
|
_builderTree = signal(null, /* @ts-ignore */
|
|
960
961
|
...(ngDevMode ? [{ debugName: "_builderTree" }] : /* istanbul ignore next */ []));
|
|
961
962
|
builderLogic = this._builderTree.asReadonly();
|
|
@@ -1003,14 +1004,12 @@ class LogicBuilderComponent {
|
|
|
1003
1004
|
updateActionId(nodeId, actionId) {
|
|
1004
1005
|
this.updateNode(nodeId, (node) => ({ ...node, actionId }));
|
|
1005
1006
|
}
|
|
1006
|
-
/** Updates a node in the tree and emits the change */
|
|
1007
1007
|
updateNode(nodeId, updater) {
|
|
1008
1008
|
const tree = this._builderTree();
|
|
1009
1009
|
if (!tree)
|
|
1010
1010
|
return;
|
|
1011
1011
|
this.updateTreeAndEmit(this.updateNodeInTree(tree, nodeId, updater));
|
|
1012
1012
|
}
|
|
1013
|
-
/** Sets the tree and emits the change */
|
|
1014
1013
|
updateTreeAndEmit(tree) {
|
|
1015
1014
|
this._builderTree.set(tree);
|
|
1016
1015
|
this.logicChange.emit(toLogicNode(tree));
|
|
@@ -1035,8 +1034,8 @@ class LogicBuilderComponent {
|
|
|
1035
1034
|
.map((child) => this.removeNodeFromTree(child, targetId)),
|
|
1036
1035
|
};
|
|
1037
1036
|
}
|
|
1038
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
1039
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
1037
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: LogicBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1038
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: LogicBuilderComponent, isStandalone: true, selector: "lib-logic-builder", inputs: { logic: { classPropertyName: "logic", publicName: "logic", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { logicChange: "logicChange" }, ngImport: i0, template: `
|
|
1040
1039
|
<div class="logic-builder">
|
|
1041
1040
|
<div class="flex justify-between items-center mb-3">
|
|
1042
1041
|
<h4 class="text-sm font-semibold m-0">
|
|
@@ -1074,10 +1073,8 @@ class LogicBuilderComponent {
|
|
|
1074
1073
|
<!-- Root Node -->
|
|
1075
1074
|
<div class="text-sm bg-surface-0 dark:bg-surface-900 rounded border border-surface">
|
|
1076
1075
|
<ng-container
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
context: { $implicit: builderLogic()!, depth: 0 }
|
|
1080
|
-
"
|
|
1076
|
+
[ngTemplateOutlet]="nodeTemplate"
|
|
1077
|
+
[ngTemplateOutletContext]="{ $implicit: builderLogic()!, depth: 0 }"
|
|
1081
1078
|
></ng-container>
|
|
1082
1079
|
</div>
|
|
1083
1080
|
</div>
|
|
@@ -1156,10 +1153,8 @@ class LogicBuilderComponent {
|
|
|
1156
1153
|
<div class="ml-5 mt-2 pl-3 border-l-2 border-surface">
|
|
1157
1154
|
@for (child of node.children; track child.id) {
|
|
1158
1155
|
<ng-container
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
context: { $implicit: child, depth: depth + 1 }
|
|
1162
|
-
"
|
|
1156
|
+
[ngTemplateOutlet]="nodeTemplate"
|
|
1157
|
+
[ngTemplateOutletContext]="{ $implicit: child, depth: depth + 1 }"
|
|
1163
1158
|
></ng-container>
|
|
1164
1159
|
}
|
|
1165
1160
|
</div>
|
|
@@ -1198,11 +1193,19 @@ class LogicBuilderComponent {
|
|
|
1198
1193
|
}
|
|
1199
1194
|
</div>
|
|
1200
1195
|
</ng-template>
|
|
1201
|
-
`, isInline: true, styles: [":host{display:block}.node-type{display:inline-flex;align-items:center;padding:.25rem .5rem;border-radius:.25rem;font-weight:600;font-size:.75rem;text-transform:uppercase}.node-type.group{background-color:var(--f-blue-100, #dbeafe);color:var(--f-blue-700, #1e40af)}.node-type.action{background-color:var(--f-green-100, #d1fae5);color:var(--f-green-700, #065f46)}:host-context(.app-dark) .node-type.group{background-color:#3b82f633;color:var(--f-blue-400, #60a5fa)}:host-context(.app-dark) .node-type.action{background-color:#22c55e33;color:var(--f-green-400, #4ade80)}.operator-badge{display:inline-flex;align-items:center;padding:.125rem .5rem;border-radius:9999px;font-weight:600;font-size:.75rem;cursor:pointer;transition:opacity .2s}.operator-badge.and{background-color:var(--f-yellow-100, #fef3c7);color:var(--f-yellow-700, #92400e)}.operator-badge.or{background-color:var(--f-indigo-100, #e0e7ff);color:var(--f-indigo-700, #3730a3)}:host-context(.app-dark) .operator-badge.and{background-color:#eab30833;color:var(--f-yellow-400, #facc15)}:host-context(.app-dark) .operator-badge.or{background-color:#6366f133;color:var(--f-indigo-400, #818cf8)}.operator-badge:hover{opacity:.8}.action-select{background-color:var(--f-surface-0, #ffffff);color:var(--f-text-color, #1f2937)}:host-context(.app-dark) .action-select{background-color:var(--f-surface-900, #1f2937);color:var(--f-text-color, #f9fafb)}.action-select:focus{outline:none;border-color:var(--f-primary-color, #3b82f6)}\n"], dependencies: [{ kind: "ngmodule", type:
|
|
1196
|
+
`, isInline: true, styles: [":host{display:block}.node-type{display:inline-flex;align-items:center;padding:.25rem .5rem;border-radius:.25rem;font-weight:600;font-size:.75rem;text-transform:uppercase}.node-type.group{background-color:var(--f-blue-100, #dbeafe);color:var(--f-blue-700, #1e40af)}.node-type.action{background-color:var(--f-green-100, #d1fae5);color:var(--f-green-700, #065f46)}:host-context(.app-dark) .node-type.group{background-color:#3b82f633;color:var(--f-blue-400, #60a5fa)}:host-context(.app-dark) .node-type.action{background-color:#22c55e33;color:var(--f-green-400, #4ade80)}.operator-badge{display:inline-flex;align-items:center;padding:.125rem .5rem;border-radius:9999px;font-weight:600;font-size:.75rem;cursor:pointer;transition:opacity .2s}.operator-badge.and{background-color:var(--f-yellow-100, #fef3c7);color:var(--f-yellow-700, #92400e)}.operator-badge.or{background-color:var(--f-indigo-100, #e0e7ff);color:var(--f-indigo-700, #3730a3)}:host-context(.app-dark) .operator-badge.and{background-color:#eab30833;color:var(--f-yellow-400, #facc15)}:host-context(.app-dark) .operator-badge.or{background-color:#6366f133;color:var(--f-indigo-400, #818cf8)}.operator-badge:hover{opacity:.8}.action-select{background-color:var(--f-surface-0, #ffffff);color:var(--f-text-color, #1f2937)}:host-context(.app-dark) .action-select{background-color:var(--f-surface-900, #1f2937);color:var(--f-text-color, #f9fafb)}.action-select:focus{outline:none;border-color:var(--f-primary-color, #3b82f6)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: FButtonDirective, selector: "[fButton]", inputs: ["severity", "text", "outlined", "link", "variant", "rounded", "raised", "fluid", "disabled", "loading", "loadingIcon", "size", "label", "icon", "iconPos", "ariaLabel", "plain"] }, { kind: "component", type: SelectComponent, selector: "f-select", inputs: ["options", "optionLabel", "optionValue", "placeholder", "disabled", "filter", "filterBy", "filterMatchMode", "filterLocale", "filterPlaceholder", "resetFilterOnHide", "autofocusFilter", "emptyMessage", "emptyFilterMessage", "showClear", "loading", "loadingIcon", "dropdownIcon", "clearIcon", "inputId", "invalid", "touched", "styleClass", "style", "appendTo", "editable", "readonly", "autofocus", "checkmark", "group", "optionGroupLabel", "optionGroupChildren", "virtualScroll", "virtualScrollItemSize", "lazy"], outputs: ["onFilter", "onChange", "onShow", "onHide", "onBlur", "onFocus", "onClear", "onLazyLoad"] }, { kind: "directive", type: TooltipDirective, selector: "[fTooltip]", inputs: ["fTooltip", "tooltipPosition", "positionStyle", "tooltipStyleClass", "disabled", "tooltipEvent", "showDelay", "hideDelay", "life", "autoHide", "positionTop", "positionLeft", "escape"] }, { kind: "component", type: UiIconComponent, selector: "ui-icon", inputs: ["name", "size", "spin", "fill", "severity"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
1202
1197
|
}
|
|
1203
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
1198
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: LogicBuilderComponent, decorators: [{
|
|
1204
1199
|
type: Component,
|
|
1205
|
-
args: [{ selector: 'lib-logic-builder', imports: [
|
|
1200
|
+
args: [{ selector: 'lib-logic-builder', imports: [
|
|
1201
|
+
FormsModule,
|
|
1202
|
+
NgTemplateOutlet,
|
|
1203
|
+
FButtonDirective,
|
|
1204
|
+
SelectComponent,
|
|
1205
|
+
TooltipDirective,
|
|
1206
|
+
UiIconComponent,
|
|
1207
|
+
TranslatePipe,
|
|
1208
|
+
], template: `
|
|
1206
1209
|
<div class="logic-builder">
|
|
1207
1210
|
<div class="flex justify-between items-center mb-3">
|
|
1208
1211
|
<h4 class="text-sm font-semibold m-0">
|
|
@@ -1240,10 +1243,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
|
|
|
1240
1243
|
<!-- Root Node -->
|
|
1241
1244
|
<div class="text-sm bg-surface-0 dark:bg-surface-900 rounded border border-surface">
|
|
1242
1245
|
<ng-container
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
context: { $implicit: builderLogic()!, depth: 0 }
|
|
1246
|
-
"
|
|
1246
|
+
[ngTemplateOutlet]="nodeTemplate"
|
|
1247
|
+
[ngTemplateOutletContext]="{ $implicit: builderLogic()!, depth: 0 }"
|
|
1247
1248
|
></ng-container>
|
|
1248
1249
|
</div>
|
|
1249
1250
|
</div>
|
|
@@ -1322,10 +1323,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
|
|
|
1322
1323
|
<div class="ml-5 mt-2 pl-3 border-l-2 border-surface">
|
|
1323
1324
|
@for (child of node.children; track child.id) {
|
|
1324
1325
|
<ng-container
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
context: { $implicit: child, depth: depth + 1 }
|
|
1328
|
-
"
|
|
1326
|
+
[ngTemplateOutlet]="nodeTemplate"
|
|
1327
|
+
[ngTemplateOutletContext]="{ $implicit: child, depth: depth + 1 }"
|
|
1329
1328
|
></ng-container>
|
|
1330
1329
|
}
|
|
1331
1330
|
</div>
|
|
@@ -1705,8 +1704,8 @@ class RoleActionSelectorComponent extends BaseActionSelectorComponent {
|
|
|
1705
1704
|
this.saving.set(false);
|
|
1706
1705
|
}
|
|
1707
1706
|
}
|
|
1708
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
1709
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
1707
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: RoleActionSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1708
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: RoleActionSelectorComponent, isStandalone: true, selector: "flusys-role-action-selector", viewQueries: [{ propertyName: "roleSelectRef", first: true, predicate: ["roleSelect"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
1710
1709
|
<div class="role-action-selector">
|
|
1711
1710
|
<div class="surface-card p-4 rounded-border mb-4 shadow-sm">
|
|
1712
1711
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-5">
|
|
@@ -1980,11 +1979,23 @@ class RoleActionSelectorComponent extends BaseActionSelectorComponent {
|
|
|
1980
1979
|
}
|
|
1981
1980
|
}
|
|
1982
1981
|
</div>
|
|
1983
|
-
`, isInline: true, styles: [":host{display:block}.empty-state-icon{width:3rem;height:3rem;border-radius:9999px;display:flex;align-items:center;justify-content:center;background-color:var(--f-primary-50, rgba(59, 130, 246, .08))}:host-context(.app-dark) .empty-state-icon{background-color:#60a5fa1f}.validation-warning{background-color:var(--f-yellow-50, #fefce8);border-left:4px solid var(--f-yellow-500, #eab308);color:var(--f-yellow-700, #a16207)}:host-context(.app-dark) .validation-warning{background-color:#eab3081a;color:var(--f-yellow-400, #facc15)}:host ::ng-deep tr.highlight-warning{background-color:var(--f-red-50, rgba(239, 68, 68, .1))!important}:host-context(.app-dark) ::ng-deep tr.highlight-warning{background-color:#ef444426!important}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1
|
|
1982
|
+
`, isInline: true, styles: [":host{display:block}.empty-state-icon{width:3rem;height:3rem;border-radius:9999px;display:flex;align-items:center;justify-content:center;background-color:var(--f-primary-50, rgba(59, 130, 246, .08))}:host-context(.app-dark) .empty-state-icon{background-color:#60a5fa1f}.validation-warning{background-color:var(--f-yellow-50, #fefce8);border-left:4px solid var(--f-yellow-500, #eab308);color:var(--f-yellow-700, #a16207)}:host-context(.app-dark) .validation-warning{background-color:#eab3081a;color:var(--f-yellow-400, #facc15)}:host ::ng-deep tr.highlight-warning{background-color:var(--f-red-50, rgba(239, 68, 68, .1))!important}:host-context(.app-dark) ::ng-deep tr.highlight-warning{background-color:#ef444426!important}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: CheckboxComponent, selector: "f-checkbox", inputs: ["label", "binary", "disabled", "readonly", "inputId", "invalid", "indeterminate", "variant", "size", "touched", "styleClass", "style", "checked"], outputs: ["onChange", "onBlur", "touch", "checkedChange"] }, { kind: "directive", type: FButtonDirective, selector: "[fButton]", inputs: ["severity", "text", "outlined", "link", "variant", "rounded", "raised", "fluid", "disabled", "loading", "loadingIcon", "size", "label", "icon", "iconPos", "ariaLabel", "plain"] }, { kind: "component", type: SelectComponent, selector: "f-select", inputs: ["options", "optionLabel", "optionValue", "placeholder", "disabled", "filter", "filterBy", "filterMatchMode", "filterLocale", "filterPlaceholder", "resetFilterOnHide", "autofocusFilter", "emptyMessage", "emptyFilterMessage", "showClear", "loading", "loadingIcon", "dropdownIcon", "clearIcon", "inputId", "invalid", "touched", "styleClass", "style", "appendTo", "editable", "readonly", "autofocus", "checkmark", "group", "optionGroupLabel", "optionGroupChildren", "virtualScroll", "virtualScrollItemSize", "lazy"], outputs: ["onFilter", "onChange", "onShow", "onHide", "onBlur", "onFocus", "onClear", "onLazyLoad"] }, { kind: "component", type: TagComponent, selector: "f-tag", inputs: ["value", "severity", "icon", "rounded", "color", "styleClass", "style"] }, { kind: "directive", type: TooltipDirective, selector: "[fTooltip]", inputs: ["fTooltip", "tooltipPosition", "positionStyle", "tooltipStyleClass", "disabled", "tooltipEvent", "showDelay", "hideDelay", "life", "autoHide", "positionTop", "positionLeft", "escape"] }, { kind: "component", type: TreeTableComponent, selector: "f-treetable", inputs: ["value", "loading", "dataKey", "styleClass", "tableStyle", "scrollable", "scrollHeight", "resizableColumns", "lazy", "totalRecords", "paginator", "first", "rows", "rowsPerPageOptions", "showCurrentPageReport", "currentPageReportTemplate", "globalFilterFields", "filterDelay", "selectionMode", "sortMode", "virtualScroll", "virtualScrollItemSize", "sortField", "sortOrder", "multiSortMeta", "filters", "selection", "contextMenuSelection"], outputs: ["sortFieldChange", "sortOrderChange", "multiSortMetaChange", "filtersChange", "selectionChange", "contextMenuSelectionChange", "onLazyLoad", "onSort", "onFilter", "onNodeExpand", "onNodeCollapse", "onNodeSelect", "onNodeUnselect", "onRowContextMenu"] }, { kind: "component", type: TreeTableTogglerComponent, selector: "f-treetabletoggler", inputs: ["rowNode"] }, { kind: "component", type: UiIconComponent, selector: "ui-icon", inputs: ["name", "size", "spin", "fill", "severity"] }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
1984
1983
|
}
|
|
1985
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
1984
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: RoleActionSelectorComponent, decorators: [{
|
|
1986
1985
|
type: Component,
|
|
1987
|
-
args: [{ selector: 'flusys-role-action-selector', imports: [
|
|
1986
|
+
args: [{ selector: 'flusys-role-action-selector', imports: [
|
|
1987
|
+
FormsModule,
|
|
1988
|
+
CheckboxComponent,
|
|
1989
|
+
FButtonDirective,
|
|
1990
|
+
SelectComponent,
|
|
1991
|
+
TagComponent,
|
|
1992
|
+
TooltipDirective,
|
|
1993
|
+
TreeTableComponent,
|
|
1994
|
+
TreeTableTogglerComponent,
|
|
1995
|
+
UiIconComponent,
|
|
1996
|
+
HasPermissionDirective,
|
|
1997
|
+
TranslatePipe,
|
|
1998
|
+
], template: `
|
|
1988
1999
|
<div class="role-action-selector">
|
|
1989
2000
|
<div class="surface-card p-4 rounded-border mb-4 shadow-sm">
|
|
1990
2001
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-5">
|
|
@@ -2422,8 +2433,8 @@ class CompanyActionSelectorComponent extends BaseActionSelectorComponent {
|
|
|
2422
2433
|
},
|
|
2423
2434
|
});
|
|
2424
2435
|
}
|
|
2425
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
2426
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
2436
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: CompanyActionSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2437
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: CompanyActionSelectorComponent, isStandalone: true, selector: "flusys-company-action-selector", viewQueries: [{ propertyName: "companySelectRef", first: true, predicate: ["companySelect"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
2427
2438
|
<div class="company-action-selector">
|
|
2428
2439
|
<div class="surface-card p-4 rounded-border mb-4 shadow-sm">
|
|
2429
2440
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-5">
|
|
@@ -2690,11 +2701,23 @@ class CompanyActionSelectorComponent extends BaseActionSelectorComponent {
|
|
|
2690
2701
|
}
|
|
2691
2702
|
}
|
|
2692
2703
|
</div>
|
|
2693
|
-
`, isInline: true, styles: [":host{display:block}.empty-state-icon{width:3rem;height:3rem;border-radius:9999px;display:flex;align-items:center;justify-content:center;background-color:var(--f-primary-50, rgba(59, 130, 246, .08))}:host-context(.app-dark) .empty-state-icon{background-color:#60a5fa1f}.validation-warning{background-color:var(--f-yellow-50, #fefce8);border-left:4px solid var(--f-yellow-500, #eab308);color:var(--f-yellow-700, #a16207)}:host-context(.app-dark) .validation-warning{background-color:#eab3081a;color:var(--f-yellow-400, #facc15)}:host ::ng-deep tr.highlight-warning{background-color:var(--f-red-50, rgba(239, 68, 68, .1))!important}:host-context(.app-dark) ::ng-deep tr.highlight-warning{background-color:#ef444426!important}\n"], dependencies: [{ kind: "
|
|
2704
|
+
`, isInline: true, styles: [":host{display:block}.empty-state-icon{width:3rem;height:3rem;border-radius:9999px;display:flex;align-items:center;justify-content:center;background-color:var(--f-primary-50, rgba(59, 130, 246, .08))}:host-context(.app-dark) .empty-state-icon{background-color:#60a5fa1f}.validation-warning{background-color:var(--f-yellow-50, #fefce8);border-left:4px solid var(--f-yellow-500, #eab308);color:var(--f-yellow-700, #a16207)}:host-context(.app-dark) .validation-warning{background-color:#eab3081a;color:var(--f-yellow-400, #facc15)}:host ::ng-deep tr.highlight-warning{background-color:var(--f-red-50, rgba(239, 68, 68, .1))!important}:host-context(.app-dark) ::ng-deep tr.highlight-warning{background-color:#ef444426!important}\n"], dependencies: [{ kind: "component", type: CheckboxComponent, selector: "f-checkbox", inputs: ["label", "binary", "disabled", "readonly", "inputId", "invalid", "indeterminate", "variant", "size", "touched", "styleClass", "style", "checked"], outputs: ["onChange", "onBlur", "touch", "checkedChange"] }, { kind: "directive", type: FButtonDirective, selector: "[fButton]", inputs: ["severity", "text", "outlined", "link", "variant", "rounded", "raised", "fluid", "disabled", "loading", "loadingIcon", "size", "label", "icon", "iconPos", "ariaLabel", "plain"] }, { kind: "component", type: SelectComponent, selector: "f-select", inputs: ["options", "optionLabel", "optionValue", "placeholder", "disabled", "filter", "filterBy", "filterMatchMode", "filterLocale", "filterPlaceholder", "resetFilterOnHide", "autofocusFilter", "emptyMessage", "emptyFilterMessage", "showClear", "loading", "loadingIcon", "dropdownIcon", "clearIcon", "inputId", "invalid", "touched", "styleClass", "style", "appendTo", "editable", "readonly", "autofocus", "checkmark", "group", "optionGroupLabel", "optionGroupChildren", "virtualScroll", "virtualScrollItemSize", "lazy"], outputs: ["onFilter", "onChange", "onShow", "onHide", "onBlur", "onFocus", "onClear", "onLazyLoad"] }, { kind: "component", type: TagComponent, selector: "f-tag", inputs: ["value", "severity", "icon", "rounded", "color", "styleClass", "style"] }, { kind: "directive", type: TooltipDirective, selector: "[fTooltip]", inputs: ["fTooltip", "tooltipPosition", "positionStyle", "tooltipStyleClass", "disabled", "tooltipEvent", "showDelay", "hideDelay", "life", "autoHide", "positionTop", "positionLeft", "escape"] }, { kind: "component", type: TreeTableComponent, selector: "f-treetable", inputs: ["value", "loading", "dataKey", "styleClass", "tableStyle", "scrollable", "scrollHeight", "resizableColumns", "lazy", "totalRecords", "paginator", "first", "rows", "rowsPerPageOptions", "showCurrentPageReport", "currentPageReportTemplate", "globalFilterFields", "filterDelay", "selectionMode", "sortMode", "virtualScroll", "virtualScrollItemSize", "sortField", "sortOrder", "multiSortMeta", "filters", "selection", "contextMenuSelection"], outputs: ["sortFieldChange", "sortOrderChange", "multiSortMetaChange", "filtersChange", "selectionChange", "contextMenuSelectionChange", "onLazyLoad", "onSort", "onFilter", "onNodeExpand", "onNodeCollapse", "onNodeSelect", "onNodeUnselect", "onRowContextMenu"] }, { kind: "component", type: TreeTableTogglerComponent, selector: "f-treetabletoggler", inputs: ["rowNode"] }, { kind: "component", type: UiIconComponent, selector: "ui-icon", inputs: ["name", "size", "spin", "fill", "severity"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
2694
2705
|
}
|
|
2695
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
2706
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: CompanyActionSelectorComponent, decorators: [{
|
|
2696
2707
|
type: Component,
|
|
2697
|
-
args: [{ selector: 'flusys-company-action-selector', imports: [
|
|
2708
|
+
args: [{ selector: 'flusys-company-action-selector', imports: [
|
|
2709
|
+
CheckboxComponent,
|
|
2710
|
+
FButtonDirective,
|
|
2711
|
+
SelectComponent,
|
|
2712
|
+
TagComponent,
|
|
2713
|
+
TooltipDirective,
|
|
2714
|
+
TreeTableComponent,
|
|
2715
|
+
TreeTableTogglerComponent,
|
|
2716
|
+
UiIconComponent,
|
|
2717
|
+
FormsModule,
|
|
2718
|
+
HasPermissionDirective,
|
|
2719
|
+
TranslatePipe,
|
|
2720
|
+
], template: `
|
|
2698
2721
|
<div class="company-action-selector">
|
|
2699
2722
|
<div class="surface-card p-4 rounded-border mb-4 shadow-sm">
|
|
2700
2723
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-5">
|
|
@@ -2965,38 +2988,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
|
|
|
2965
2988
|
}], ctorParameters: () => [], propDecorators: { companySelectRef: [{ type: i0.ViewChild, args: ['companySelect', { isSignal: true }] }] } });
|
|
2966
2989
|
|
|
2967
2990
|
/**
|
|
2968
|
-
*
|
|
2969
|
-
*
|
|
2970
|
-
*
|
|
2971
|
-
*
|
|
2972
|
-
* **Architecture:**
|
|
2973
|
-
* - Presentation: DataTable for role list
|
|
2974
|
-
* - Business Logic: Role assignment without dependency validation
|
|
2975
|
-
* - State: Signals with computed dependencies
|
|
2976
|
-
*
|
|
2977
|
-
* **Core Features:**
|
|
2978
|
-
* - User dropdown with async loading
|
|
2979
|
-
* - Branch selector (if company feature enabled)
|
|
2980
|
-
* - Role assignment management (add/remove)
|
|
2981
|
-
* - Real-time change tracking
|
|
2982
|
-
*
|
|
2983
|
-
* **Granularity:**
|
|
2984
|
-
* - Company-wide: branchId = undefined
|
|
2985
|
-
* - Branch-specific: branchId = selected value
|
|
2986
|
-
*
|
|
2987
|
-
* **Performance:**
|
|
2988
|
-
* - Computed signals for reactive updates
|
|
2989
|
-
* - Branch filtering on company context change
|
|
2990
|
-
*
|
|
2991
|
-
* @example
|
|
2992
|
-
* ```html
|
|
2993
|
-
* <flusys-user-role-selector />
|
|
2994
|
-
* ```
|
|
2991
|
+
* Manages user role assignments with branch-level granularity:
|
|
2992
|
+
* `branchId === undefined` means a company-wide assignment, a set value
|
|
2993
|
+
* scopes the assignment to that specific branch.
|
|
2995
2994
|
*/
|
|
2996
2995
|
class UserRoleSelectorComponent {
|
|
2997
|
-
// Permission constants for template
|
|
2998
2996
|
USER_ROLE_PERMISSIONS = USER_ROLE_PERMISSIONS;
|
|
2999
|
-
// Dependencies
|
|
3000
2997
|
appConfig = inject(APP_CONFIG);
|
|
3001
2998
|
companyContext = inject(LAYOUT_AUTH_STATE);
|
|
3002
2999
|
userPermissionProvider = inject(USER_PERMISSION_PROVIDER);
|
|
@@ -3030,30 +3027,25 @@ class UserRoleSelectorComponent {
|
|
|
3030
3027
|
}
|
|
3031
3028
|
this.selectedUserId.set(userId);
|
|
3032
3029
|
}
|
|
3033
|
-
// State - User/Branch Selection
|
|
3034
3030
|
selectedUserId = signal(null, /* @ts-ignore */
|
|
3035
3031
|
...(ngDevMode ? [{ debugName: "selectedUserId" }] : /* istanbul ignore next */ []));
|
|
3036
3032
|
selectedBranchId = signal(undefined, /* @ts-ignore */
|
|
3037
3033
|
...(ngDevMode ? [{ debugName: "selectedBranchId" }] : /* istanbul ignore next */ []));
|
|
3038
3034
|
branches = signal([], /* @ts-ignore */
|
|
3039
3035
|
...(ngDevMode ? [{ debugName: "branches" }] : /* istanbul ignore next */ []));
|
|
3040
|
-
// State - Loading/Saving
|
|
3041
3036
|
loading = signal(false, /* @ts-ignore */
|
|
3042
3037
|
...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
3043
3038
|
saving = signal(false, /* @ts-ignore */
|
|
3044
3039
|
...(ngDevMode ? [{ debugName: "saving" }] : /* istanbul ignore next */ []));
|
|
3045
|
-
// State - Roles (Business Logic)
|
|
3046
3040
|
_roles = signal([], /* @ts-ignore */
|
|
3047
3041
|
...(ngDevMode ? [{ debugName: "_roles" }] : /* istanbul ignore next */ []));
|
|
3048
3042
|
roles = this._roles.asReadonly();
|
|
3049
|
-
// State - Selection
|
|
3050
3043
|
_selectionMap = signal({}, /* @ts-ignore */
|
|
3051
3044
|
...(ngDevMode ? [{ debugName: "_selectionMap" }] : /* istanbul ignore next */ []));
|
|
3052
3045
|
selectionMap = this._selectionMap.asReadonly();
|
|
3053
3046
|
_initialSelection = signal({}, /* @ts-ignore */
|
|
3054
3047
|
...(ngDevMode ? [{ debugName: "_initialSelection" }] : /* istanbul ignore next */ []));
|
|
3055
3048
|
initialSelection = this._initialSelection.asReadonly();
|
|
3056
|
-
// Computed - UI Flags
|
|
3057
3049
|
showBranchSelector = computed(() => isCompanyFeatureEnabled(this.appConfig) === true, /* @ts-ignore */
|
|
3058
3050
|
...(ngDevMode ? [{ debugName: "showBranchSelector" }] : /* istanbul ignore next */ []));
|
|
3059
3051
|
filteredBranches = computed(() => {
|
|
@@ -3063,7 +3055,6 @@ class UserRoleSelectorComponent {
|
|
|
3063
3055
|
return this.branches().filter((b) => b.companyId === currentCompanyId);
|
|
3064
3056
|
}, /* @ts-ignore */
|
|
3065
3057
|
...(ngDevMode ? [{ debugName: "filteredBranches" }] : /* istanbul ignore next */ []));
|
|
3066
|
-
// Computed - Selection State
|
|
3067
3058
|
allSelected = computed(() => {
|
|
3068
3059
|
const selMap = this.selectionMap();
|
|
3069
3060
|
const total = this.roles().length;
|
|
@@ -3073,7 +3064,6 @@ class UserRoleSelectorComponent {
|
|
|
3073
3064
|
return selected === total;
|
|
3074
3065
|
}, /* @ts-ignore */
|
|
3075
3066
|
...(ngDevMode ? [{ debugName: "allSelected" }] : /* istanbul ignore next */ []));
|
|
3076
|
-
// Computed - Change Detection
|
|
3077
3067
|
hasChanges = computed(() => {
|
|
3078
3068
|
const current = this.selectionMap();
|
|
3079
3069
|
const initial = this.initialSelection();
|
|
@@ -3084,7 +3074,6 @@ class UserRoleSelectorComponent {
|
|
|
3084
3074
|
return currentKeys.some((key) => current[key] !== initial[key]);
|
|
3085
3075
|
}, /* @ts-ignore */
|
|
3086
3076
|
...(ngDevMode ? [{ debugName: "hasChanges" }] : /* istanbul ignore next */ []));
|
|
3087
|
-
// Computed - Pending Changes
|
|
3088
3077
|
pendingAdd = computed(() => {
|
|
3089
3078
|
const current = this.selectionMap();
|
|
3090
3079
|
const initial = this.initialSelection();
|
|
@@ -3099,13 +3088,11 @@ class UserRoleSelectorComponent {
|
|
|
3099
3088
|
return allRoles.filter((role) => !current[role.id] && initial[role.id]);
|
|
3100
3089
|
}, /* @ts-ignore */
|
|
3101
3090
|
...(ngDevMode ? [{ debugName: "pendingRemove" }] : /* istanbul ignore next */ []));
|
|
3102
|
-
// Computed - Save Button State
|
|
3103
3091
|
canSave = computed(() => {
|
|
3104
3092
|
return this.hasChanges() && !this.saving();
|
|
3105
3093
|
}, /* @ts-ignore */
|
|
3106
3094
|
...(ngDevMode ? [{ debugName: "canSave" }] : /* istanbul ignore next */ []));
|
|
3107
3095
|
constructor() {
|
|
3108
|
-
// Effect: Load user branches and data when user changes
|
|
3109
3096
|
effect(() => {
|
|
3110
3097
|
const userId = this.selectedUserId();
|
|
3111
3098
|
if (userId) {
|
|
@@ -3120,7 +3107,6 @@ class UserRoleSelectorComponent {
|
|
|
3120
3107
|
this.resetState();
|
|
3121
3108
|
}
|
|
3122
3109
|
});
|
|
3123
|
-
// Effect: Reload data when branch changes
|
|
3124
3110
|
effect(() => {
|
|
3125
3111
|
const userId = this.selectedUserId();
|
|
3126
3112
|
const branchId = this.selectedBranchId();
|
|
@@ -3131,9 +3117,6 @@ class UserRoleSelectorComponent {
|
|
|
3131
3117
|
}
|
|
3132
3118
|
});
|
|
3133
3119
|
}
|
|
3134
|
-
/**
|
|
3135
|
-
* Load user's permitted branches
|
|
3136
|
-
*/
|
|
3137
3120
|
async loadUserBranches(userId) {
|
|
3138
3121
|
try {
|
|
3139
3122
|
const companyId = this.companyContext.currentCompanyInfo()?.id || undefined;
|
|
@@ -3153,9 +3136,6 @@ class UserRoleSelectorComponent {
|
|
|
3153
3136
|
// Error toast handled by global interceptor
|
|
3154
3137
|
}
|
|
3155
3138
|
}
|
|
3156
|
-
/**
|
|
3157
|
-
* Load roles and assignments for selected user
|
|
3158
|
-
*/
|
|
3159
3139
|
async loadData() {
|
|
3160
3140
|
const userId = this.selectedUserId();
|
|
3161
3141
|
if (!userId)
|
|
@@ -3163,19 +3143,16 @@ class UserRoleSelectorComponent {
|
|
|
3163
3143
|
const branchId = this.selectedBranchId();
|
|
3164
3144
|
this.loading.set(true);
|
|
3165
3145
|
try {
|
|
3166
|
-
// Load all roles
|
|
3167
3146
|
const rolesResponse = await this.roleApi.getAll({
|
|
3168
3147
|
pagination: { currentPage: 0, pageSize: MAX_DROPDOWN_ITEMS },
|
|
3169
3148
|
});
|
|
3170
3149
|
const rolesList = rolesResponse?.data ?? [];
|
|
3171
3150
|
this._roles.set(rolesList);
|
|
3172
|
-
// Load existing user-role assignments
|
|
3173
3151
|
const query = isCompanyFeatureEnabled(this.appConfig) && branchId
|
|
3174
3152
|
? { branchId }
|
|
3175
3153
|
: undefined;
|
|
3176
3154
|
const assignedResponse = await firstValueFrom(this.permissionApi.getUserRoles(userId, query));
|
|
3177
3155
|
const assignedIds = new Set((assignedResponse?.data || []).map((r) => r.roleId));
|
|
3178
|
-
// Build selection map
|
|
3179
3156
|
const selMap = {};
|
|
3180
3157
|
rolesList.forEach((role) => {
|
|
3181
3158
|
selMap[role.id] = assignedIds.has(role.id);
|
|
@@ -3190,9 +3167,6 @@ class UserRoleSelectorComponent {
|
|
|
3190
3167
|
this.loading.set(false);
|
|
3191
3168
|
}
|
|
3192
3169
|
}
|
|
3193
|
-
/**
|
|
3194
|
-
* Get tooltip for role checkbox
|
|
3195
|
-
*/
|
|
3196
3170
|
getTooltip(role) {
|
|
3197
3171
|
const selMap = this.selectionMap();
|
|
3198
3172
|
const isCurrentlySelected = selMap[role.id];
|
|
@@ -3201,23 +3175,14 @@ class UserRoleSelectorComponent {
|
|
|
3201
3175
|
}
|
|
3202
3176
|
return `[${this.translate('shared.add')}] ${this.translate('iam.tooltip.click.to.assign.role.to.user')}`;
|
|
3203
3177
|
}
|
|
3204
|
-
/**
|
|
3205
|
-
* Handle role checkbox toggle
|
|
3206
|
-
*/
|
|
3207
3178
|
onRoleToggle(role, newValue) {
|
|
3208
3179
|
const selMap = { ...this.selectionMap() };
|
|
3209
3180
|
selMap[role.id] = newValue;
|
|
3210
3181
|
this._selectionMap.set(selMap);
|
|
3211
3182
|
}
|
|
3212
|
-
/**
|
|
3213
|
-
* Toggle all roles
|
|
3214
|
-
*/
|
|
3215
3183
|
toggleAll() {
|
|
3216
3184
|
this.setAllSelections(!this.allSelected());
|
|
3217
3185
|
}
|
|
3218
|
-
/**
|
|
3219
|
-
* Set all role selections to a given value
|
|
3220
|
-
*/
|
|
3221
3186
|
setAllSelections(value) {
|
|
3222
3187
|
const selMap = {};
|
|
3223
3188
|
this.roles().forEach((role) => {
|
|
@@ -3225,16 +3190,12 @@ class UserRoleSelectorComponent {
|
|
|
3225
3190
|
});
|
|
3226
3191
|
this._selectionMap.set(selMap);
|
|
3227
3192
|
}
|
|
3228
|
-
/**
|
|
3229
|
-
* Save changes to backend
|
|
3230
|
-
*/
|
|
3231
3193
|
async saveChanges() {
|
|
3232
3194
|
const userId = this.selectedUserId();
|
|
3233
3195
|
if (!userId)
|
|
3234
3196
|
return;
|
|
3235
3197
|
const branchId = this.selectedBranchId();
|
|
3236
3198
|
const companyId = this.companyContext.currentCompanyInfo()?.id || undefined;
|
|
3237
|
-
// Validate company context if feature enabled
|
|
3238
3199
|
if (isCompanyFeatureEnabled(this.appConfig) && !companyId) {
|
|
3239
3200
|
this.messageService.add({
|
|
3240
3201
|
severity: 'warn',
|
|
@@ -3243,7 +3204,6 @@ class UserRoleSelectorComponent {
|
|
|
3243
3204
|
});
|
|
3244
3205
|
return;
|
|
3245
3206
|
}
|
|
3246
|
-
// Build payload
|
|
3247
3207
|
const items = [];
|
|
3248
3208
|
this.pendingAdd().forEach((role) => {
|
|
3249
3209
|
items.push({ id: role.id, action: 'add' });
|
|
@@ -3272,7 +3232,6 @@ class UserRoleSelectorComponent {
|
|
|
3272
3232
|
? this.translate(response.messageKey, response.messageVariables)
|
|
3273
3233
|
: response?.message,
|
|
3274
3234
|
});
|
|
3275
|
-
// Update baseline
|
|
3276
3235
|
this._initialSelection.set({ ...this.selectionMap() });
|
|
3277
3236
|
}
|
|
3278
3237
|
catch {
|
|
@@ -3282,16 +3241,13 @@ class UserRoleSelectorComponent {
|
|
|
3282
3241
|
this.saving.set(false);
|
|
3283
3242
|
}
|
|
3284
3243
|
}
|
|
3285
|
-
/**
|
|
3286
|
-
* Reset component state
|
|
3287
|
-
*/
|
|
3288
3244
|
resetState() {
|
|
3289
3245
|
this._roles.set([]);
|
|
3290
3246
|
this._selectionMap.set({});
|
|
3291
3247
|
this._initialSelection.set({});
|
|
3292
3248
|
}
|
|
3293
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
3294
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
3249
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: UserRoleSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3250
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: UserRoleSelectorComponent, isStandalone: true, selector: "flusys-user-role-selector", viewQueries: [{ propertyName: "userSelectRef", first: true, predicate: ["userSelect"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
3295
3251
|
<div class="user-role-selector">
|
|
3296
3252
|
<!-- User and Branch Selectors -->
|
|
3297
3253
|
<div class="surface-card p-4 rounded-border mb-4 shadow-sm">
|
|
@@ -3565,14 +3521,18 @@ class UserRoleSelectorComponent {
|
|
|
3565
3521
|
}
|
|
3566
3522
|
}
|
|
3567
3523
|
</div>
|
|
3568
|
-
`, isInline: true, styles: [":host{display:block}.empty-state-icon{width:3rem;height:3rem;border-radius:9999px;display:flex;align-items:center;justify-content:center;background-color:var(--f-primary-50, rgba(59, 130, 246, .08))}:host-context(.app-dark) .empty-state-icon{background-color:#60a5fa1f}\n"], dependencies: [{ kind: "ngmodule", type:
|
|
3524
|
+
`, isInline: true, styles: [":host{display:block}.empty-state-icon{width:3rem;height:3rem;border-radius:9999px;display:flex;align-items:center;justify-content:center;background-color:var(--f-primary-50, rgba(59, 130, 246, .08))}:host-context(.app-dark) .empty-state-icon{background-color:#60a5fa1f}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: CheckboxComponent, selector: "f-checkbox", inputs: ["label", "binary", "disabled", "readonly", "inputId", "invalid", "indeterminate", "variant", "size", "touched", "styleClass", "style", "checked"], outputs: ["onChange", "onBlur", "touch", "checkedChange"] }, { kind: "directive", type: FButtonDirective, selector: "[fButton]", inputs: ["severity", "text", "outlined", "link", "variant", "rounded", "raised", "fluid", "disabled", "loading", "loadingIcon", "size", "label", "icon", "iconPos", "ariaLabel", "plain"] }, { kind: "component", type: SelectComponent, selector: "f-select", inputs: ["options", "optionLabel", "optionValue", "placeholder", "disabled", "filter", "filterBy", "filterMatchMode", "filterLocale", "filterPlaceholder", "resetFilterOnHide", "autofocusFilter", "emptyMessage", "emptyFilterMessage", "showClear", "loading", "loadingIcon", "dropdownIcon", "clearIcon", "inputId", "invalid", "touched", "styleClass", "style", "appendTo", "editable", "readonly", "autofocus", "checkmark", "group", "optionGroupLabel", "optionGroupChildren", "virtualScroll", "virtualScrollItemSize", "lazy"], outputs: ["onFilter", "onChange", "onShow", "onHide", "onBlur", "onFocus", "onClear", "onLazyLoad"] }, { kind: "component", type: TableComponent, selector: "f-table", inputs: ["value", "lazy", "loading", "rows", "totalRecords", "rowHover", "dataKey", "scrollable", "scrollHeight", "paginator", "first", "rowsPerPageOptions", "showCurrentPageReport", "currentPageReportTemplate", "tableStyle", "styleClass", "globalFilterFields", "filterDelay", "responsiveLayout", "selectionMode", "sortMode", "rowExpandMode", "resizableColumns", "rowStyleClass", "virtualScroll", "virtualScrollItemSize", "sortField", "sortOrder", "multiSortMeta", "filters", "selection", "expandedRowKeys", "contextMenuSelection"], outputs: ["sortFieldChange", "sortOrderChange", "multiSortMetaChange", "filtersChange", "selectionChange", "expandedRowKeysChange", "contextMenuSelectionChange", "onLazyLoad", "onSort", "onFilter", "onRowSelect", "onRowUnselect", "onSelectAllChange", "onRowExpand", "onRowCollapse", "onColResize", "onRowContextMenu"] }, { kind: "directive", type: TooltipDirective, selector: "[fTooltip]", inputs: ["fTooltip", "tooltipPosition", "positionStyle", "tooltipStyleClass", "disabled", "tooltipEvent", "showDelay", "hideDelay", "life", "autoHide", "positionTop", "positionLeft", "escape"] }, { kind: "component", type: UiIconComponent, selector: "ui-icon", inputs: ["name", "size", "spin", "fill", "severity"] }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }, { kind: "component", type: UserSelectComponent, selector: "lib-user-select", inputs: ["showClear", "value"], outputs: ["valueChange", "userSelected"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
3569
3525
|
}
|
|
3570
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
3526
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: UserRoleSelectorComponent, decorators: [{
|
|
3571
3527
|
type: Component,
|
|
3572
3528
|
args: [{ selector: 'flusys-user-role-selector', imports: [
|
|
3573
|
-
CommonModule,
|
|
3574
3529
|
FormsModule,
|
|
3575
|
-
|
|
3530
|
+
CheckboxComponent,
|
|
3531
|
+
FButtonDirective,
|
|
3532
|
+
SelectComponent,
|
|
3533
|
+
TableComponent,
|
|
3534
|
+
TooltipDirective,
|
|
3535
|
+
UiIconComponent,
|
|
3576
3536
|
HasPermissionDirective,
|
|
3577
3537
|
UserSelectComponent,
|
|
3578
3538
|
TranslatePipe,
|
|
@@ -4066,8 +4026,8 @@ class UserActionSelectorComponent extends BaseActionSelectorComponent {
|
|
|
4066
4026
|
this.saving.set(false);
|
|
4067
4027
|
}
|
|
4068
4028
|
}
|
|
4069
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
4070
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
4029
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: UserActionSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4030
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: UserActionSelectorComponent, isStandalone: true, selector: "flusys-user-action-selector", viewQueries: [{ propertyName: "userSelectRef", first: true, predicate: ["userSelect"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
4071
4031
|
<div class="user-action-selector">
|
|
4072
4032
|
<div class="surface-card p-4 rounded-border mb-4 shadow-sm">
|
|
4073
4033
|
<div
|
|
@@ -4398,13 +4358,20 @@ class UserActionSelectorComponent extends BaseActionSelectorComponent {
|
|
|
4398
4358
|
}
|
|
4399
4359
|
}
|
|
4400
4360
|
</div>
|
|
4401
|
-
`, isInline: true, styles: [":host{display:block}.empty-state-icon{width:3rem;height:3rem;border-radius:9999px;display:flex;align-items:center;justify-content:center;background-color:var(--f-primary-50, rgba(59, 130, 246, .08))}:host-context(.app-dark) .empty-state-icon{background-color:#60a5fa1f}.validation-warning{background-color:var(--f-yellow-50, #fefce8);border-left:4px solid var(--f-yellow-500, #eab308);color:var(--f-yellow-700, #a16207)}:host-context(.app-dark) .validation-warning{background-color:#eab3081a;color:var(--f-yellow-400, #facc15)}:host ::ng-deep tr.highlight-warning{background-color:var(--f-red-50, rgba(239, 68, 68, .1))!important}:host-context(.app-dark) ::ng-deep tr.highlight-warning{background-color:#ef444426!important}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1
|
|
4361
|
+
`, isInline: true, styles: [":host{display:block}.empty-state-icon{width:3rem;height:3rem;border-radius:9999px;display:flex;align-items:center;justify-content:center;background-color:var(--f-primary-50, rgba(59, 130, 246, .08))}:host-context(.app-dark) .empty-state-icon{background-color:#60a5fa1f}.validation-warning{background-color:var(--f-yellow-50, #fefce8);border-left:4px solid var(--f-yellow-500, #eab308);color:var(--f-yellow-700, #a16207)}:host-context(.app-dark) .validation-warning{background-color:#eab3081a;color:var(--f-yellow-400, #facc15)}:host ::ng-deep tr.highlight-warning{background-color:var(--f-red-50, rgba(239, 68, 68, .1))!important}:host-context(.app-dark) ::ng-deep tr.highlight-warning{background-color:#ef444426!important}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: CheckboxComponent, selector: "f-checkbox", inputs: ["label", "binary", "disabled", "readonly", "inputId", "invalid", "indeterminate", "variant", "size", "touched", "styleClass", "style", "checked"], outputs: ["onChange", "onBlur", "touch", "checkedChange"] }, { kind: "directive", type: FButtonDirective, selector: "[fButton]", inputs: ["severity", "text", "outlined", "link", "variant", "rounded", "raised", "fluid", "disabled", "loading", "loadingIcon", "size", "label", "icon", "iconPos", "ariaLabel", "plain"] }, { kind: "component", type: SelectComponent, selector: "f-select", inputs: ["options", "optionLabel", "optionValue", "placeholder", "disabled", "filter", "filterBy", "filterMatchMode", "filterLocale", "filterPlaceholder", "resetFilterOnHide", "autofocusFilter", "emptyMessage", "emptyFilterMessage", "showClear", "loading", "loadingIcon", "dropdownIcon", "clearIcon", "inputId", "invalid", "touched", "styleClass", "style", "appendTo", "editable", "readonly", "autofocus", "checkmark", "group", "optionGroupLabel", "optionGroupChildren", "virtualScroll", "virtualScrollItemSize", "lazy"], outputs: ["onFilter", "onChange", "onShow", "onHide", "onBlur", "onFocus", "onClear", "onLazyLoad"] }, { kind: "component", type: TagComponent, selector: "f-tag", inputs: ["value", "severity", "icon", "rounded", "color", "styleClass", "style"] }, { kind: "directive", type: TooltipDirective, selector: "[fTooltip]", inputs: ["fTooltip", "tooltipPosition", "positionStyle", "tooltipStyleClass", "disabled", "tooltipEvent", "showDelay", "hideDelay", "life", "autoHide", "positionTop", "positionLeft", "escape"] }, { kind: "component", type: TreeTableComponent, selector: "f-treetable", inputs: ["value", "loading", "dataKey", "styleClass", "tableStyle", "scrollable", "scrollHeight", "resizableColumns", "lazy", "totalRecords", "paginator", "first", "rows", "rowsPerPageOptions", "showCurrentPageReport", "currentPageReportTemplate", "globalFilterFields", "filterDelay", "selectionMode", "sortMode", "virtualScroll", "virtualScrollItemSize", "sortField", "sortOrder", "multiSortMeta", "filters", "selection", "contextMenuSelection"], outputs: ["sortFieldChange", "sortOrderChange", "multiSortMetaChange", "filtersChange", "selectionChange", "contextMenuSelectionChange", "onLazyLoad", "onSort", "onFilter", "onNodeExpand", "onNodeCollapse", "onNodeSelect", "onNodeUnselect", "onRowContextMenu"] }, { kind: "component", type: TreeTableTogglerComponent, selector: "f-treetabletoggler", inputs: ["rowNode"] }, { kind: "component", type: UiIconComponent, selector: "ui-icon", inputs: ["name", "size", "spin", "fill", "severity"] }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }, { kind: "component", type: UserSelectComponent, selector: "lib-user-select", inputs: ["showClear", "value"], outputs: ["valueChange", "userSelected"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
4402
4362
|
}
|
|
4403
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
4363
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: UserActionSelectorComponent, decorators: [{
|
|
4404
4364
|
type: Component,
|
|
4405
4365
|
args: [{ selector: 'flusys-user-action-selector', imports: [
|
|
4406
4366
|
FormsModule,
|
|
4407
|
-
|
|
4367
|
+
CheckboxComponent,
|
|
4368
|
+
FButtonDirective,
|
|
4369
|
+
SelectComponent,
|
|
4370
|
+
TagComponent,
|
|
4371
|
+
TooltipDirective,
|
|
4372
|
+
TreeTableComponent,
|
|
4373
|
+
TreeTableTogglerComponent,
|
|
4374
|
+
UiIconComponent,
|
|
4408
4375
|
HasPermissionDirective,
|
|
4409
4376
|
UserSelectComponent,
|
|
4410
4377
|
TranslatePipe,
|
|
@@ -4742,6 +4709,530 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
|
|
|
4742
4709
|
`, styles: [":host{display:block}.empty-state-icon{width:3rem;height:3rem;border-radius:9999px;display:flex;align-items:center;justify-content:center;background-color:var(--f-primary-50, rgba(59, 130, 246, .08))}:host-context(.app-dark) .empty-state-icon{background-color:#60a5fa1f}.validation-warning{background-color:var(--f-yellow-50, #fefce8);border-left:4px solid var(--f-yellow-500, #eab308);color:var(--f-yellow-700, #a16207)}:host-context(.app-dark) .validation-warning{background-color:#eab3081a;color:var(--f-yellow-400, #facc15)}:host ::ng-deep tr.highlight-warning{background-color:var(--f-red-50, rgba(239, 68, 68, .1))!important}:host-context(.app-dark) ::ng-deep tr.highlight-warning{background-color:#ef444426!important}\n"] }]
|
|
4743
4710
|
}], ctorParameters: () => [], propDecorators: { userSelectRef: [{ type: i0.ViewChild, args: ['userSelect', { isSignal: true }] }] } });
|
|
4744
4711
|
|
|
4712
|
+
/**
|
|
4713
|
+
* Read-only viewer for users assigned to a role, with a remove-only action
|
|
4714
|
+
* per user. Assigning new users stays on the user-centric
|
|
4715
|
+
* `UserRoleSelectorComponent` flow — this dialog intentionally has no "add"
|
|
4716
|
+
* affordance. Since IAM stays independent of the auth package, user display
|
|
4717
|
+
* info is resolved via the `USER_PROVIDER` injection token rather than a
|
|
4718
|
+
* direct join.
|
|
4719
|
+
*/
|
|
4720
|
+
class RolePermittedUsersDialogComponent {
|
|
4721
|
+
USER_ROLE_PERMISSIONS = USER_ROLE_PERMISSIONS;
|
|
4722
|
+
permissionApi = inject(PermissionApiService);
|
|
4723
|
+
userProvider = inject(USER_PROVIDER);
|
|
4724
|
+
confirmationService = inject(ConfirmationService);
|
|
4725
|
+
messageService = inject(MessageService);
|
|
4726
|
+
translateAdapter = inject(TranslateService, {
|
|
4727
|
+
optional: true,
|
|
4728
|
+
});
|
|
4729
|
+
t(key, params) {
|
|
4730
|
+
return this.translateAdapter?.translate(key, params) ?? key;
|
|
4731
|
+
}
|
|
4732
|
+
visible = input.required(/* @ts-ignore */
|
|
4733
|
+
...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
4734
|
+
role = input.required(/* @ts-ignore */
|
|
4735
|
+
...(ngDevMode ? [{ debugName: "role" }] : /* istanbul ignore next */ []));
|
|
4736
|
+
closed = output();
|
|
4737
|
+
isLoading = signal(false, /* @ts-ignore */
|
|
4738
|
+
...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
|
|
4739
|
+
isRemoving = signal(false, /* @ts-ignore */
|
|
4740
|
+
...(ngDevMode ? [{ debugName: "isRemoving" }] : /* istanbul ignore next */ []));
|
|
4741
|
+
users = signal([], /* @ts-ignore */
|
|
4742
|
+
...(ngDevMode ? [{ debugName: "users" }] : /* istanbul ignore next */ []));
|
|
4743
|
+
constructor() {
|
|
4744
|
+
effect(() => {
|
|
4745
|
+
if (this.visible() && this.role()) {
|
|
4746
|
+
this.loadUsers();
|
|
4747
|
+
}
|
|
4748
|
+
});
|
|
4749
|
+
}
|
|
4750
|
+
async loadUsers() {
|
|
4751
|
+
const role = this.role();
|
|
4752
|
+
if (!role)
|
|
4753
|
+
return;
|
|
4754
|
+
this.isLoading.set(true);
|
|
4755
|
+
try {
|
|
4756
|
+
const response = await firstValueFrom(this.permissionApi.getRoleUsers(role.id));
|
|
4757
|
+
const rows = response.data ?? [];
|
|
4758
|
+
const userIds = rows.map((r) => r.userId);
|
|
4759
|
+
const userInfoMap = await this.resolveUserInfo(userIds);
|
|
4760
|
+
this.users.set(rows.map((r) => {
|
|
4761
|
+
const info = userInfoMap.get(r.userId);
|
|
4762
|
+
return {
|
|
4763
|
+
id: r.id,
|
|
4764
|
+
userId: r.userId,
|
|
4765
|
+
userName: info?.name ?? r.userId,
|
|
4766
|
+
userEmail: info?.email ?? '',
|
|
4767
|
+
};
|
|
4768
|
+
}));
|
|
4769
|
+
}
|
|
4770
|
+
catch {
|
|
4771
|
+
// Error toast handled by global interceptor
|
|
4772
|
+
}
|
|
4773
|
+
finally {
|
|
4774
|
+
this.isLoading.set(false);
|
|
4775
|
+
}
|
|
4776
|
+
}
|
|
4777
|
+
async resolveUserInfo(userIds) {
|
|
4778
|
+
if (userIds.length === 0 || !this.userProvider.getUsersByIds) {
|
|
4779
|
+
return new Map();
|
|
4780
|
+
}
|
|
4781
|
+
try {
|
|
4782
|
+
const response = await firstValueFrom(this.userProvider.getUsersByIds(userIds));
|
|
4783
|
+
return new Map((response.data ?? []).map((u) => [u.id, u]));
|
|
4784
|
+
}
|
|
4785
|
+
catch {
|
|
4786
|
+
return new Map();
|
|
4787
|
+
}
|
|
4788
|
+
}
|
|
4789
|
+
onRemove(user) {
|
|
4790
|
+
const role = this.role();
|
|
4791
|
+
if (!role)
|
|
4792
|
+
return;
|
|
4793
|
+
this.confirmationService.confirm({
|
|
4794
|
+
message: this.t('iam.permission.remove.confirm', { name: user.userName }),
|
|
4795
|
+
header: this.t('iam.permission.remove'),
|
|
4796
|
+
icon: 'exclamation-triangle',
|
|
4797
|
+
acceptButtonStyleClass: 'p-button-danger',
|
|
4798
|
+
accept: async () => {
|
|
4799
|
+
this.isRemoving.set(true);
|
|
4800
|
+
try {
|
|
4801
|
+
const response = await firstValueFrom(this.permissionApi.assignUserRoles({
|
|
4802
|
+
userId: user.userId,
|
|
4803
|
+
items: [{ id: role.id, action: 'remove' }],
|
|
4804
|
+
}));
|
|
4805
|
+
if (response.success) {
|
|
4806
|
+
this.users.update((list) => list.filter((u) => u.id !== user.id));
|
|
4807
|
+
this.messageService.add({
|
|
4808
|
+
severity: 'success',
|
|
4809
|
+
summary: this.t('shared.success'),
|
|
4810
|
+
detail: response?.messageKey
|
|
4811
|
+
? this.t(response.messageKey, response.messageVariables)
|
|
4812
|
+
: (response?.message ?? ''),
|
|
4813
|
+
});
|
|
4814
|
+
}
|
|
4815
|
+
}
|
|
4816
|
+
catch {
|
|
4817
|
+
// Error toast handled by global interceptor
|
|
4818
|
+
}
|
|
4819
|
+
finally {
|
|
4820
|
+
this.isRemoving.set(false);
|
|
4821
|
+
}
|
|
4822
|
+
},
|
|
4823
|
+
});
|
|
4824
|
+
}
|
|
4825
|
+
onClose() {
|
|
4826
|
+
this.closed.emit();
|
|
4827
|
+
}
|
|
4828
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: RolePermittedUsersDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4829
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: RolePermittedUsersDialogComponent, isStandalone: true, selector: "flusys-role-permitted-users-dialog", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: true, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { closed: "closed" }, ngImport: i0, template: `
|
|
4830
|
+
<f-dialog
|
|
4831
|
+
[visible]="visible()"
|
|
4832
|
+
[modal]="true"
|
|
4833
|
+
[closable]="true"
|
|
4834
|
+
[breakpoints]="{ '960px': '90vw', '640px': '95vw' }"
|
|
4835
|
+
[style]="{ width: '50vw', maxWidth: '600px' }"
|
|
4836
|
+
[header]="'iam.permission.view.users' | translate"
|
|
4837
|
+
(onHide)="onClose()"
|
|
4838
|
+
>
|
|
4839
|
+
<div class="mb-4">
|
|
4840
|
+
<p class="text-sm text-muted-color">
|
|
4841
|
+
{{ 'iam.role.name' | translate }}:
|
|
4842
|
+
<strong>{{ role()?.name }}</strong>
|
|
4843
|
+
</p>
|
|
4844
|
+
</div>
|
|
4845
|
+
|
|
4846
|
+
@if (isLoading()) {
|
|
4847
|
+
<div class="flex justify-center items-center py-8">
|
|
4848
|
+
<f-progressspinner />
|
|
4849
|
+
</div>
|
|
4850
|
+
} @else {
|
|
4851
|
+
<div class="flex flex-col gap-3">
|
|
4852
|
+
@for (user of users(); track user.id) {
|
|
4853
|
+
<div
|
|
4854
|
+
class="flex items-center justify-between p-3 border border-surface rounded"
|
|
4855
|
+
>
|
|
4856
|
+
<div>
|
|
4857
|
+
<div class="font-semibold">{{ user.userName }}</div>
|
|
4858
|
+
<div class="text-sm text-muted-color">{{ user.userEmail }}</div>
|
|
4859
|
+
</div>
|
|
4860
|
+
<button
|
|
4861
|
+
fButton
|
|
4862
|
+
*hasPermission="USER_ROLE_PERMISSIONS.ASSIGN"
|
|
4863
|
+
[text]="true"
|
|
4864
|
+
severity="danger"
|
|
4865
|
+
size="small"
|
|
4866
|
+
[disabled]="isRemoving()"
|
|
4867
|
+
[fTooltip]="'shared.remove' | translate"
|
|
4868
|
+
(click)="onRemove(user)"
|
|
4869
|
+
>
|
|
4870
|
+
<ui-icon pButtonIcon name="trash"></ui-icon>
|
|
4871
|
+
</button>
|
|
4872
|
+
</div>
|
|
4873
|
+
} @empty {
|
|
4874
|
+
<div class="text-center py-4 text-muted-color">
|
|
4875
|
+
{{ 'iam.permission.no.users' | translate }}
|
|
4876
|
+
</div>
|
|
4877
|
+
}
|
|
4878
|
+
</div>
|
|
4879
|
+
}
|
|
4880
|
+
|
|
4881
|
+
<ng-template #footer>
|
|
4882
|
+
<button
|
|
4883
|
+
fButton
|
|
4884
|
+
severity="secondary"
|
|
4885
|
+
[outlined]="true"
|
|
4886
|
+
(click)="onClose()"
|
|
4887
|
+
>
|
|
4888
|
+
<span pButtonLabel>{{ 'shared.close' | translate }}</span>
|
|
4889
|
+
</button>
|
|
4890
|
+
</ng-template>
|
|
4891
|
+
</f-dialog>
|
|
4892
|
+
`, isInline: true, dependencies: [{ kind: "component", type: DialogComponent, selector: "f-dialog", inputs: ["header", "visible", "modal", "closable", "closeOnEscape", "dismissableMask", "resizable", "draggable", "maximizable", "blockScroll", "returnFocusOnClose", "position", "style", "styleClass", "breakpoints"], outputs: ["visibleChange", "onShow", "onHide", "onMaximize"] }, { kind: "directive", type: FButtonDirective, selector: "[fButton]", inputs: ["severity", "text", "outlined", "link", "variant", "rounded", "raised", "fluid", "disabled", "loading", "loadingIcon", "size", "label", "icon", "iconPos", "ariaLabel", "plain"] }, { kind: "component", type: ProgressSpinnerComponent, selector: "f-progressspinner", inputs: ["size", "strokeWidth", "animationDuration", "styleClass", "ariaLabel"] }, { kind: "directive", type: TooltipDirective, selector: "[fTooltip]", inputs: ["fTooltip", "tooltipPosition", "positionStyle", "tooltipStyleClass", "disabled", "tooltipEvent", "showDelay", "hideDelay", "life", "autoHide", "positionTop", "positionLeft", "escape"] }, { kind: "component", type: UiIconComponent, selector: "ui-icon", inputs: ["name", "size", "spin", "fill", "severity"] }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
4893
|
+
}
|
|
4894
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: RolePermittedUsersDialogComponent, decorators: [{
|
|
4895
|
+
type: Component,
|
|
4896
|
+
args: [{
|
|
4897
|
+
selector: 'flusys-role-permitted-users-dialog',
|
|
4898
|
+
imports: [
|
|
4899
|
+
DialogComponent,
|
|
4900
|
+
FButtonDirective,
|
|
4901
|
+
ProgressSpinnerComponent,
|
|
4902
|
+
TooltipDirective,
|
|
4903
|
+
UiIconComponent,
|
|
4904
|
+
HasPermissionDirective,
|
|
4905
|
+
TranslatePipe,
|
|
4906
|
+
],
|
|
4907
|
+
template: `
|
|
4908
|
+
<f-dialog
|
|
4909
|
+
[visible]="visible()"
|
|
4910
|
+
[modal]="true"
|
|
4911
|
+
[closable]="true"
|
|
4912
|
+
[breakpoints]="{ '960px': '90vw', '640px': '95vw' }"
|
|
4913
|
+
[style]="{ width: '50vw', maxWidth: '600px' }"
|
|
4914
|
+
[header]="'iam.permission.view.users' | translate"
|
|
4915
|
+
(onHide)="onClose()"
|
|
4916
|
+
>
|
|
4917
|
+
<div class="mb-4">
|
|
4918
|
+
<p class="text-sm text-muted-color">
|
|
4919
|
+
{{ 'iam.role.name' | translate }}:
|
|
4920
|
+
<strong>{{ role()?.name }}</strong>
|
|
4921
|
+
</p>
|
|
4922
|
+
</div>
|
|
4923
|
+
|
|
4924
|
+
@if (isLoading()) {
|
|
4925
|
+
<div class="flex justify-center items-center py-8">
|
|
4926
|
+
<f-progressspinner />
|
|
4927
|
+
</div>
|
|
4928
|
+
} @else {
|
|
4929
|
+
<div class="flex flex-col gap-3">
|
|
4930
|
+
@for (user of users(); track user.id) {
|
|
4931
|
+
<div
|
|
4932
|
+
class="flex items-center justify-between p-3 border border-surface rounded"
|
|
4933
|
+
>
|
|
4934
|
+
<div>
|
|
4935
|
+
<div class="font-semibold">{{ user.userName }}</div>
|
|
4936
|
+
<div class="text-sm text-muted-color">{{ user.userEmail }}</div>
|
|
4937
|
+
</div>
|
|
4938
|
+
<button
|
|
4939
|
+
fButton
|
|
4940
|
+
*hasPermission="USER_ROLE_PERMISSIONS.ASSIGN"
|
|
4941
|
+
[text]="true"
|
|
4942
|
+
severity="danger"
|
|
4943
|
+
size="small"
|
|
4944
|
+
[disabled]="isRemoving()"
|
|
4945
|
+
[fTooltip]="'shared.remove' | translate"
|
|
4946
|
+
(click)="onRemove(user)"
|
|
4947
|
+
>
|
|
4948
|
+
<ui-icon pButtonIcon name="trash"></ui-icon>
|
|
4949
|
+
</button>
|
|
4950
|
+
</div>
|
|
4951
|
+
} @empty {
|
|
4952
|
+
<div class="text-center py-4 text-muted-color">
|
|
4953
|
+
{{ 'iam.permission.no.users' | translate }}
|
|
4954
|
+
</div>
|
|
4955
|
+
}
|
|
4956
|
+
</div>
|
|
4957
|
+
}
|
|
4958
|
+
|
|
4959
|
+
<ng-template #footer>
|
|
4960
|
+
<button
|
|
4961
|
+
fButton
|
|
4962
|
+
severity="secondary"
|
|
4963
|
+
[outlined]="true"
|
|
4964
|
+
(click)="onClose()"
|
|
4965
|
+
>
|
|
4966
|
+
<span pButtonLabel>{{ 'shared.close' | translate }}</span>
|
|
4967
|
+
</button>
|
|
4968
|
+
</ng-template>
|
|
4969
|
+
</f-dialog>
|
|
4970
|
+
`,
|
|
4971
|
+
}]
|
|
4972
|
+
}], ctorParameters: () => [], propDecorators: { visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: true }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: true }] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
4973
|
+
|
|
4974
|
+
/**
|
|
4975
|
+
* Read-only viewer for users directly assigned an action, with a remove-only
|
|
4976
|
+
* action per user. Assigning new users stays on the user-centric
|
|
4977
|
+
* `UserActionSelectorComponent` flow — this dialog intentionally has no
|
|
4978
|
+
* "add" affordance. Since IAM stays independent of the auth package, user
|
|
4979
|
+
* display info is resolved via the `USER_PROVIDER` injection token rather
|
|
4980
|
+
* than a direct join.
|
|
4981
|
+
*/
|
|
4982
|
+
class ActionPermittedUsersDialogComponent {
|
|
4983
|
+
USER_ACTION_PERMISSIONS = USER_ACTION_PERMISSIONS;
|
|
4984
|
+
permissionApi = inject(PermissionApiService);
|
|
4985
|
+
userProvider = inject(USER_PROVIDER);
|
|
4986
|
+
confirmationService = inject(ConfirmationService);
|
|
4987
|
+
messageService = inject(MessageService);
|
|
4988
|
+
translateAdapter = inject(TranslateService, {
|
|
4989
|
+
optional: true,
|
|
4990
|
+
});
|
|
4991
|
+
t(key, params) {
|
|
4992
|
+
return this.translateAdapter?.translate(key, params) ?? key;
|
|
4993
|
+
}
|
|
4994
|
+
visible = input.required(/* @ts-ignore */
|
|
4995
|
+
...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
4996
|
+
action = input.required(/* @ts-ignore */
|
|
4997
|
+
...(ngDevMode ? [{ debugName: "action" }] : /* istanbul ignore next */ []));
|
|
4998
|
+
closed = output();
|
|
4999
|
+
isLoading = signal(false, /* @ts-ignore */
|
|
5000
|
+
...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
|
|
5001
|
+
isRemoving = signal(false, /* @ts-ignore */
|
|
5002
|
+
...(ngDevMode ? [{ debugName: "isRemoving" }] : /* istanbul ignore next */ []));
|
|
5003
|
+
users = signal([], /* @ts-ignore */
|
|
5004
|
+
...(ngDevMode ? [{ debugName: "users" }] : /* istanbul ignore next */ []));
|
|
5005
|
+
constructor() {
|
|
5006
|
+
effect(() => {
|
|
5007
|
+
if (this.visible() && this.action()) {
|
|
5008
|
+
this.loadUsers();
|
|
5009
|
+
}
|
|
5010
|
+
});
|
|
5011
|
+
}
|
|
5012
|
+
async loadUsers() {
|
|
5013
|
+
const action = this.action();
|
|
5014
|
+
if (!action)
|
|
5015
|
+
return;
|
|
5016
|
+
this.isLoading.set(true);
|
|
5017
|
+
try {
|
|
5018
|
+
const response = await firstValueFrom(this.permissionApi.getActionUsers(action.id));
|
|
5019
|
+
const rows = response.data ?? [];
|
|
5020
|
+
const userIds = rows.map((r) => r.userId);
|
|
5021
|
+
const userInfoMap = await this.resolveUserInfo(userIds);
|
|
5022
|
+
this.users.set(rows.map((r) => {
|
|
5023
|
+
const info = userInfoMap.get(r.userId);
|
|
5024
|
+
return {
|
|
5025
|
+
id: r.id,
|
|
5026
|
+
userId: r.userId,
|
|
5027
|
+
userName: info?.name ?? r.userId,
|
|
5028
|
+
userEmail: info?.email ?? '',
|
|
5029
|
+
};
|
|
5030
|
+
}));
|
|
5031
|
+
}
|
|
5032
|
+
catch {
|
|
5033
|
+
// Error toast handled by global interceptor
|
|
5034
|
+
}
|
|
5035
|
+
finally {
|
|
5036
|
+
this.isLoading.set(false);
|
|
5037
|
+
}
|
|
5038
|
+
}
|
|
5039
|
+
async resolveUserInfo(userIds) {
|
|
5040
|
+
if (userIds.length === 0 || !this.userProvider.getUsersByIds) {
|
|
5041
|
+
return new Map();
|
|
5042
|
+
}
|
|
5043
|
+
try {
|
|
5044
|
+
const response = await firstValueFrom(this.userProvider.getUsersByIds(userIds));
|
|
5045
|
+
return new Map((response.data ?? []).map((u) => [u.id, u]));
|
|
5046
|
+
}
|
|
5047
|
+
catch {
|
|
5048
|
+
return new Map();
|
|
5049
|
+
}
|
|
5050
|
+
}
|
|
5051
|
+
onRemove(user) {
|
|
5052
|
+
const action = this.action();
|
|
5053
|
+
if (!action)
|
|
5054
|
+
return;
|
|
5055
|
+
this.confirmationService.confirm({
|
|
5056
|
+
message: this.t('iam.permission.remove.confirm', { name: user.userName }),
|
|
5057
|
+
header: this.t('iam.permission.remove'),
|
|
5058
|
+
icon: 'exclamation-triangle',
|
|
5059
|
+
acceptButtonStyleClass: 'p-button-danger',
|
|
5060
|
+
accept: async () => {
|
|
5061
|
+
this.isRemoving.set(true);
|
|
5062
|
+
try {
|
|
5063
|
+
const response = await firstValueFrom(this.permissionApi.assignUserActions({
|
|
5064
|
+
userId: user.userId,
|
|
5065
|
+
items: [{ id: action.id, action: 'remove' }],
|
|
5066
|
+
}));
|
|
5067
|
+
if (response.success) {
|
|
5068
|
+
this.users.update((list) => list.filter((u) => u.id !== user.id));
|
|
5069
|
+
this.messageService.add({
|
|
5070
|
+
severity: 'success',
|
|
5071
|
+
summary: this.t('shared.success'),
|
|
5072
|
+
detail: response?.messageKey
|
|
5073
|
+
? this.t(response.messageKey, response.messageVariables)
|
|
5074
|
+
: (response?.message ?? ''),
|
|
5075
|
+
});
|
|
5076
|
+
}
|
|
5077
|
+
}
|
|
5078
|
+
catch {
|
|
5079
|
+
// Error toast handled by global interceptor
|
|
5080
|
+
}
|
|
5081
|
+
finally {
|
|
5082
|
+
this.isRemoving.set(false);
|
|
5083
|
+
}
|
|
5084
|
+
},
|
|
5085
|
+
});
|
|
5086
|
+
}
|
|
5087
|
+
onClose() {
|
|
5088
|
+
this.closed.emit();
|
|
5089
|
+
}
|
|
5090
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ActionPermittedUsersDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5091
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: ActionPermittedUsersDialogComponent, isStandalone: true, selector: "flusys-action-permitted-users-dialog", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: true, transformFunction: null }, action: { classPropertyName: "action", publicName: "action", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { closed: "closed" }, ngImport: i0, template: `
|
|
5092
|
+
<f-dialog
|
|
5093
|
+
[visible]="visible()"
|
|
5094
|
+
[modal]="true"
|
|
5095
|
+
[closable]="true"
|
|
5096
|
+
[breakpoints]="{ '960px': '90vw', '640px': '95vw' }"
|
|
5097
|
+
[style]="{ width: '50vw', maxWidth: '600px' }"
|
|
5098
|
+
[header]="'iam.permission.view.users' | translate"
|
|
5099
|
+
(onHide)="onClose()"
|
|
5100
|
+
>
|
|
5101
|
+
<div class="mb-4">
|
|
5102
|
+
<p class="text-sm text-muted-color">
|
|
5103
|
+
{{ 'iam.action.name' | translate }}:
|
|
5104
|
+
<strong>{{ action()?.name }}</strong>
|
|
5105
|
+
</p>
|
|
5106
|
+
</div>
|
|
5107
|
+
|
|
5108
|
+
@if (isLoading()) {
|
|
5109
|
+
<div class="flex justify-center items-center py-8">
|
|
5110
|
+
<f-progressspinner />
|
|
5111
|
+
</div>
|
|
5112
|
+
} @else {
|
|
5113
|
+
<div class="flex flex-col gap-3">
|
|
5114
|
+
@for (user of users(); track user.id) {
|
|
5115
|
+
<div
|
|
5116
|
+
class="flex items-center justify-between p-3 border border-surface rounded"
|
|
5117
|
+
>
|
|
5118
|
+
<div>
|
|
5119
|
+
<div class="font-semibold">{{ user.userName }}</div>
|
|
5120
|
+
<div class="text-sm text-muted-color">{{ user.userEmail }}</div>
|
|
5121
|
+
</div>
|
|
5122
|
+
<button
|
|
5123
|
+
fButton
|
|
5124
|
+
*hasPermission="USER_ACTION_PERMISSIONS.ASSIGN"
|
|
5125
|
+
[text]="true"
|
|
5126
|
+
severity="danger"
|
|
5127
|
+
size="small"
|
|
5128
|
+
[disabled]="isRemoving()"
|
|
5129
|
+
[fTooltip]="'shared.remove' | translate"
|
|
5130
|
+
(click)="onRemove(user)"
|
|
5131
|
+
>
|
|
5132
|
+
<ui-icon pButtonIcon name="trash"></ui-icon>
|
|
5133
|
+
</button>
|
|
5134
|
+
</div>
|
|
5135
|
+
} @empty {
|
|
5136
|
+
<div class="text-center py-4 text-muted-color">
|
|
5137
|
+
{{ 'iam.permission.no.users' | translate }}
|
|
5138
|
+
</div>
|
|
5139
|
+
}
|
|
5140
|
+
</div>
|
|
5141
|
+
}
|
|
5142
|
+
|
|
5143
|
+
<ng-template #footer>
|
|
5144
|
+
<button
|
|
5145
|
+
fButton
|
|
5146
|
+
severity="secondary"
|
|
5147
|
+
[outlined]="true"
|
|
5148
|
+
(click)="onClose()"
|
|
5149
|
+
>
|
|
5150
|
+
<span pButtonLabel>{{ 'shared.close' | translate }}</span>
|
|
5151
|
+
</button>
|
|
5152
|
+
</ng-template>
|
|
5153
|
+
</f-dialog>
|
|
5154
|
+
`, isInline: true, dependencies: [{ kind: "component", type: DialogComponent, selector: "f-dialog", inputs: ["header", "visible", "modal", "closable", "closeOnEscape", "dismissableMask", "resizable", "draggable", "maximizable", "blockScroll", "returnFocusOnClose", "position", "style", "styleClass", "breakpoints"], outputs: ["visibleChange", "onShow", "onHide", "onMaximize"] }, { kind: "directive", type: FButtonDirective, selector: "[fButton]", inputs: ["severity", "text", "outlined", "link", "variant", "rounded", "raised", "fluid", "disabled", "loading", "loadingIcon", "size", "label", "icon", "iconPos", "ariaLabel", "plain"] }, { kind: "component", type: ProgressSpinnerComponent, selector: "f-progressspinner", inputs: ["size", "strokeWidth", "animationDuration", "styleClass", "ariaLabel"] }, { kind: "directive", type: TooltipDirective, selector: "[fTooltip]", inputs: ["fTooltip", "tooltipPosition", "positionStyle", "tooltipStyleClass", "disabled", "tooltipEvent", "showDelay", "hideDelay", "life", "autoHide", "positionTop", "positionLeft", "escape"] }, { kind: "component", type: UiIconComponent, selector: "ui-icon", inputs: ["name", "size", "spin", "fill", "severity"] }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
5155
|
+
}
|
|
5156
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ActionPermittedUsersDialogComponent, decorators: [{
|
|
5157
|
+
type: Component,
|
|
5158
|
+
args: [{
|
|
5159
|
+
selector: 'flusys-action-permitted-users-dialog',
|
|
5160
|
+
imports: [
|
|
5161
|
+
DialogComponent,
|
|
5162
|
+
FButtonDirective,
|
|
5163
|
+
ProgressSpinnerComponent,
|
|
5164
|
+
TooltipDirective,
|
|
5165
|
+
UiIconComponent,
|
|
5166
|
+
HasPermissionDirective,
|
|
5167
|
+
TranslatePipe,
|
|
5168
|
+
],
|
|
5169
|
+
template: `
|
|
5170
|
+
<f-dialog
|
|
5171
|
+
[visible]="visible()"
|
|
5172
|
+
[modal]="true"
|
|
5173
|
+
[closable]="true"
|
|
5174
|
+
[breakpoints]="{ '960px': '90vw', '640px': '95vw' }"
|
|
5175
|
+
[style]="{ width: '50vw', maxWidth: '600px' }"
|
|
5176
|
+
[header]="'iam.permission.view.users' | translate"
|
|
5177
|
+
(onHide)="onClose()"
|
|
5178
|
+
>
|
|
5179
|
+
<div class="mb-4">
|
|
5180
|
+
<p class="text-sm text-muted-color">
|
|
5181
|
+
{{ 'iam.action.name' | translate }}:
|
|
5182
|
+
<strong>{{ action()?.name }}</strong>
|
|
5183
|
+
</p>
|
|
5184
|
+
</div>
|
|
5185
|
+
|
|
5186
|
+
@if (isLoading()) {
|
|
5187
|
+
<div class="flex justify-center items-center py-8">
|
|
5188
|
+
<f-progressspinner />
|
|
5189
|
+
</div>
|
|
5190
|
+
} @else {
|
|
5191
|
+
<div class="flex flex-col gap-3">
|
|
5192
|
+
@for (user of users(); track user.id) {
|
|
5193
|
+
<div
|
|
5194
|
+
class="flex items-center justify-between p-3 border border-surface rounded"
|
|
5195
|
+
>
|
|
5196
|
+
<div>
|
|
5197
|
+
<div class="font-semibold">{{ user.userName }}</div>
|
|
5198
|
+
<div class="text-sm text-muted-color">{{ user.userEmail }}</div>
|
|
5199
|
+
</div>
|
|
5200
|
+
<button
|
|
5201
|
+
fButton
|
|
5202
|
+
*hasPermission="USER_ACTION_PERMISSIONS.ASSIGN"
|
|
5203
|
+
[text]="true"
|
|
5204
|
+
severity="danger"
|
|
5205
|
+
size="small"
|
|
5206
|
+
[disabled]="isRemoving()"
|
|
5207
|
+
[fTooltip]="'shared.remove' | translate"
|
|
5208
|
+
(click)="onRemove(user)"
|
|
5209
|
+
>
|
|
5210
|
+
<ui-icon pButtonIcon name="trash"></ui-icon>
|
|
5211
|
+
</button>
|
|
5212
|
+
</div>
|
|
5213
|
+
} @empty {
|
|
5214
|
+
<div class="text-center py-4 text-muted-color">
|
|
5215
|
+
{{ 'iam.permission.no.users' | translate }}
|
|
5216
|
+
</div>
|
|
5217
|
+
}
|
|
5218
|
+
</div>
|
|
5219
|
+
}
|
|
5220
|
+
|
|
5221
|
+
<ng-template #footer>
|
|
5222
|
+
<button
|
|
5223
|
+
fButton
|
|
5224
|
+
severity="secondary"
|
|
5225
|
+
[outlined]="true"
|
|
5226
|
+
(click)="onClose()"
|
|
5227
|
+
>
|
|
5228
|
+
<span pButtonLabel>{{ 'shared.close' | translate }}</span>
|
|
5229
|
+
</button>
|
|
5230
|
+
</ng-template>
|
|
5231
|
+
</f-dialog>
|
|
5232
|
+
`,
|
|
5233
|
+
}]
|
|
5234
|
+
}], ctorParameters: () => [], propDecorators: { visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: true }] }], action: [{ type: i0.Input, args: [{ isSignal: true, alias: "action", required: true }] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
5235
|
+
|
|
4745
5236
|
// Logic Builder Component
|
|
4746
5237
|
|
|
4747
5238
|
/**
|
|
@@ -4794,11 +5285,12 @@ class ProfilePermissionProviderAdapter {
|
|
|
4794
5285
|
})),
|
|
4795
5286
|
})));
|
|
4796
5287
|
}
|
|
4797
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
4798
|
-
static ɵprov = i0.ɵɵ
|
|
5288
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ProfilePermissionProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
5289
|
+
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.5", ngImport: i0, type: ProfilePermissionProviderAdapter, autoProvided: false });
|
|
4799
5290
|
}
|
|
4800
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
4801
|
-
type:
|
|
5291
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ProfilePermissionProviderAdapter, decorators: [{
|
|
5292
|
+
type: Service,
|
|
5293
|
+
args: [{ autoProvided: false }]
|
|
4802
5294
|
}] });
|
|
4803
5295
|
|
|
4804
5296
|
/** Registers IAM provider adapters for ng-shared interfaces */
|
|
@@ -4845,7 +5337,7 @@ const IAM_ROUTES = [
|
|
|
4845
5337
|
fallbackMessages: { ...IAM_MESSAGES, ...SHARED_MESSAGES },
|
|
4846
5338
|
}),
|
|
4847
5339
|
},
|
|
4848
|
-
loadComponent: () => import('./flusys-ng-iam-iam-container.component-
|
|
5340
|
+
loadComponent: () => import('./flusys-ng-iam-iam-container.component-XBoIeQ0t.mjs').then((m) => m.IamContainerComponent),
|
|
4849
5341
|
children: [
|
|
4850
5342
|
// Actions Management
|
|
4851
5343
|
{
|
|
@@ -4854,15 +5346,15 @@ const IAM_ROUTES = [
|
|
|
4854
5346
|
children: [
|
|
4855
5347
|
{
|
|
4856
5348
|
path: '',
|
|
4857
|
-
loadComponent: () => import('./flusys-ng-iam-action-list-page.component-
|
|
5349
|
+
loadComponent: () => import('./flusys-ng-iam-action-list-page.component-BveT0xT6.mjs').then((m) => m.ActionListPageComponent),
|
|
4858
5350
|
},
|
|
4859
5351
|
{
|
|
4860
5352
|
path: 'new',
|
|
4861
|
-
loadComponent: () => import('./flusys-ng-iam-action-form-page.component-
|
|
5353
|
+
loadComponent: () => import('./flusys-ng-iam-action-form-page.component-CF_ixS-r.mjs').then((m) => m.ActionFormPageComponent),
|
|
4862
5354
|
},
|
|
4863
5355
|
{
|
|
4864
5356
|
path: ':id',
|
|
4865
|
-
loadComponent: () => import('./flusys-ng-iam-action-form-page.component-
|
|
5357
|
+
loadComponent: () => import('./flusys-ng-iam-action-form-page.component-CF_ixS-r.mjs').then((m) => m.ActionFormPageComponent),
|
|
4866
5358
|
},
|
|
4867
5359
|
],
|
|
4868
5360
|
},
|
|
@@ -4873,15 +5365,15 @@ const IAM_ROUTES = [
|
|
|
4873
5365
|
children: [
|
|
4874
5366
|
{
|
|
4875
5367
|
path: '',
|
|
4876
|
-
loadComponent: () => import('./flusys-ng-iam-role-list-page.component-
|
|
5368
|
+
loadComponent: () => import('./flusys-ng-iam-role-list-page.component-vFHxd3Q-.mjs').then((m) => m.RoleListPageComponent),
|
|
4877
5369
|
},
|
|
4878
5370
|
{
|
|
4879
5371
|
path: 'new',
|
|
4880
|
-
loadComponent: () => import('./flusys-ng-iam-role-form-page.component-
|
|
5372
|
+
loadComponent: () => import('./flusys-ng-iam-role-form-page.component-Cfc8za3D.mjs').then((m) => m.RoleFormPageComponent),
|
|
4881
5373
|
},
|
|
4882
5374
|
{
|
|
4883
5375
|
path: ':id',
|
|
4884
|
-
loadComponent: () => import('./flusys-ng-iam-role-form-page.component-
|
|
5376
|
+
loadComponent: () => import('./flusys-ng-iam-role-form-page.component-Cfc8za3D.mjs').then((m) => m.RoleFormPageComponent),
|
|
4885
5377
|
},
|
|
4886
5378
|
],
|
|
4887
5379
|
},
|
|
@@ -4896,7 +5388,7 @@ const IAM_ROUTES = [
|
|
|
4896
5388
|
COMPANY_ACTION_PERMISSIONS.READ,
|
|
4897
5389
|
]),
|
|
4898
5390
|
],
|
|
4899
|
-
loadComponent: () => import('./flusys-ng-iam-permission-page.component-
|
|
5391
|
+
loadComponent: () => import('./flusys-ng-iam-permission-page.component-CGtj1EiO.mjs').then((m) => m.PermissionPageComponent),
|
|
4900
5392
|
},
|
|
4901
5393
|
// Default redirect to the first tab the user has permission to see
|
|
4902
5394
|
{
|
|
@@ -4914,5 +5406,5 @@ const IAM_ROUTES = [
|
|
|
4914
5406
|
* Generated bundle index. Do not edit.
|
|
4915
5407
|
*/
|
|
4916
5408
|
|
|
4917
|
-
export { ActionApiService as A, CompanyActionSelectorComponent as C, IAM_MESSAGES as I, LogicBuilderComponent as L, MAX_DROPDOWN_ITEMS as M, PermissionApiService as P, RoleApiService as R, UserRoleSelectorComponent as U, ActionType as a,
|
|
4918
|
-
//# sourceMappingURL=flusys-ng-iam-flusys-ng-iam-
|
|
5409
|
+
export { ActionApiService as A, CompanyActionSelectorComponent as C, IAM_MESSAGES as I, LogicBuilderComponent as L, MAX_DROPDOWN_ITEMS as M, PermissionApiService as P, RoleApiService as R, UserRoleSelectorComponent as U, ActionType as a, ActionPermittedUsersDialogComponent as b, convertActionToTreeNode as c, buildActionParentTree as d, RolePermittedUsersDialogComponent as e, RoleActionSelectorComponent as f, UserActionSelectorComponent as g, ActionPermissionLogicService as h, IAM_ROUTES as i, MyPermissionsApiService as j, PermissionStateService as k, ProfilePermissionProviderAdapter as l, provideIamProviders as p };
|
|
5410
|
+
//# sourceMappingURL=flusys-ng-iam-flusys-ng-iam-CjLr3bfY.mjs.map
|