@masterteam/users-groups 0.0.14 → 0.0.16
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.
|
@@ -22,6 +22,7 @@ import { DynamicForm } from '@masterteam/forms/dynamic-form';
|
|
|
22
22
|
import { ModalRef, DialogService } from '@masterteam/components/dialog';
|
|
23
23
|
import { Tabs } from '@masterteam/components/tabs';
|
|
24
24
|
import { finalize } from 'rxjs';
|
|
25
|
+
import { SecureImagePipe } from '@masterteam/components/upload-field';
|
|
25
26
|
|
|
26
27
|
class GetUsers {
|
|
27
28
|
static type = '[UsersGroups] Get Users';
|
|
@@ -63,6 +64,20 @@ class DeleteUser {
|
|
|
63
64
|
this.userName = userName;
|
|
64
65
|
}
|
|
65
66
|
}
|
|
67
|
+
class LinkUserToApplication {
|
|
68
|
+
userName;
|
|
69
|
+
static type = '[UsersGroups] Link User To Application';
|
|
70
|
+
constructor(userName) {
|
|
71
|
+
this.userName = userName;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
class GetUserSummary {
|
|
75
|
+
userName;
|
|
76
|
+
static type = '[UsersGroups] Get User Summary';
|
|
77
|
+
constructor(userName) {
|
|
78
|
+
this.userName = userName;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
66
81
|
class ResetUserPassword {
|
|
67
82
|
id;
|
|
68
83
|
payload;
|
|
@@ -123,6 +138,8 @@ var UsersGroupsActionKey;
|
|
|
123
138
|
UsersGroupsActionKey["CreateUser"] = "createUser";
|
|
124
139
|
UsersGroupsActionKey["UpdateUser"] = "updateUser";
|
|
125
140
|
UsersGroupsActionKey["DeleteUser"] = "deleteUser";
|
|
141
|
+
UsersGroupsActionKey["LinkUserToApplication"] = "linkUserToApplication";
|
|
142
|
+
UsersGroupsActionKey["GetUserSummary"] = "getUserSummary";
|
|
126
143
|
UsersGroupsActionKey["AddUserToGroup"] = "addUserToGroup";
|
|
127
144
|
UsersGroupsActionKey["DeleteUserFromGroup"] = "deleteUserFromGroup";
|
|
128
145
|
UsersGroupsActionKey["GetGroups"] = "getGroups";
|
|
@@ -144,6 +161,9 @@ let UsersGroupsState = class UsersGroupsState extends CrudStateBase {
|
|
|
144
161
|
context = new HttpContext().set(REQUEST_CONTEXT, {
|
|
145
162
|
useBaseUrl: false,
|
|
146
163
|
});
|
|
164
|
+
encodeUserName(userName) {
|
|
165
|
+
return encodeURIComponent(String(userName));
|
|
166
|
+
}
|
|
147
167
|
// ============================================================================
|
|
148
168
|
// Data Selectors - Individual selectors for fine-grained reactivity
|
|
149
169
|
// ============================================================================
|
|
@@ -153,6 +173,9 @@ let UsersGroupsState = class UsersGroupsState extends CrudStateBase {
|
|
|
153
173
|
static getSelectedUser(state) {
|
|
154
174
|
return state.selectedUser;
|
|
155
175
|
}
|
|
176
|
+
static getUserSummary(state) {
|
|
177
|
+
return state.userSummary;
|
|
178
|
+
}
|
|
156
179
|
static getGroups(state) {
|
|
157
180
|
return state.groups;
|
|
158
181
|
}
|
|
@@ -185,7 +208,8 @@ let UsersGroupsState = class UsersGroupsState extends CrudStateBase {
|
|
|
185
208
|
});
|
|
186
209
|
}
|
|
187
210
|
getUser(ctx, { userName }) {
|
|
188
|
-
const
|
|
211
|
+
const encodedUserName = this.encodeUserName(userName ?? '');
|
|
212
|
+
const req$ = this.http.get(`Identity/users/${encodedUserName}?editMode=true`, { context: this.context });
|
|
189
213
|
return handleApiRequest({
|
|
190
214
|
ctx,
|
|
191
215
|
key: UsersGroupsActionKey.GetUser,
|
|
@@ -238,7 +262,8 @@ let UsersGroupsState = class UsersGroupsState extends CrudStateBase {
|
|
|
238
262
|
});
|
|
239
263
|
}
|
|
240
264
|
updateUser(ctx, { changes, id }) {
|
|
241
|
-
const
|
|
265
|
+
const encodedUserName = this.encodeUserName(id ?? '');
|
|
266
|
+
const req$ = this.http.put(`Identity/users/${encodedUserName}`, changes, {
|
|
242
267
|
context: this.context,
|
|
243
268
|
});
|
|
244
269
|
return handleApiRequest({
|
|
@@ -260,19 +285,58 @@ let UsersGroupsState = class UsersGroupsState extends CrudStateBase {
|
|
|
260
285
|
});
|
|
261
286
|
}
|
|
262
287
|
deleteUser(ctx, { userName }) {
|
|
263
|
-
const
|
|
288
|
+
const encodedUserName = this.encodeUserName(userName);
|
|
289
|
+
const userNameKey = String(userName);
|
|
290
|
+
const req$ = this.http.delete(`Identity/users/${encodedUserName}`, {
|
|
264
291
|
context: this.context,
|
|
265
292
|
});
|
|
266
|
-
return
|
|
293
|
+
return handleApiRequest({
|
|
294
|
+
ctx,
|
|
267
295
|
key: UsersGroupsActionKey.DeleteUser,
|
|
268
296
|
request$: req$,
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
297
|
+
onSuccess: (_response, state) => ({
|
|
298
|
+
users: this.adapter.updateOne(state.users, userNameKey, { isLinkedToCurrentApplication: false }, 'userName'),
|
|
299
|
+
}),
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
linkUserToApplication(ctx, { userName }) {
|
|
303
|
+
const encodedUserName = this.encodeUserName(userName);
|
|
304
|
+
const userNameKey = String(userName);
|
|
305
|
+
const req$ = this.http.put(`Identity/users/${encodedUserName}/application/link`, {}, {
|
|
306
|
+
context: this.context,
|
|
307
|
+
});
|
|
308
|
+
return handleApiRequest({
|
|
309
|
+
ctx,
|
|
310
|
+
key: UsersGroupsActionKey.LinkUserToApplication,
|
|
311
|
+
request$: req$,
|
|
312
|
+
onSuccess: (response, state) => {
|
|
313
|
+
const linkedUser = {
|
|
314
|
+
...(state.users.find((user) => user.userName === userNameKey) ?? {}),
|
|
315
|
+
...(response.data ?? {}),
|
|
316
|
+
userName: userNameKey,
|
|
317
|
+
isLinkedToCurrentApplication: true,
|
|
318
|
+
};
|
|
319
|
+
return {
|
|
320
|
+
users: this.adapter.upsertOne(state.users, linkedUser, 'userName'),
|
|
321
|
+
};
|
|
322
|
+
},
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
getUserSummary(ctx, { userName }) {
|
|
326
|
+
const encodedUserName = this.encodeUserName(userName);
|
|
327
|
+
const req$ = this.http.get(`identity/users/${encodedUserName}/summary`, { context: this.context });
|
|
328
|
+
return handleApiRequest({
|
|
329
|
+
ctx,
|
|
330
|
+
key: UsersGroupsActionKey.GetUserSummary,
|
|
331
|
+
request$: req$,
|
|
332
|
+
onSuccess: (response) => ({
|
|
333
|
+
userSummary: response.data ?? null,
|
|
334
|
+
}),
|
|
272
335
|
});
|
|
273
336
|
}
|
|
274
337
|
resetUserPassword(ctx, { id, payload }) {
|
|
275
|
-
const
|
|
338
|
+
const encodedUserName = this.encodeUserName(id);
|
|
339
|
+
const req$ = this.http.put(`Identity/users/${encodedUserName}/password/reset`, payload, {
|
|
276
340
|
context: this.context,
|
|
277
341
|
});
|
|
278
342
|
return handleApiRequest({
|
|
@@ -394,6 +458,12 @@ __decorate([
|
|
|
394
458
|
__decorate([
|
|
395
459
|
Action(DeleteUser)
|
|
396
460
|
], UsersGroupsState.prototype, "deleteUser", null);
|
|
461
|
+
__decorate([
|
|
462
|
+
Action(LinkUserToApplication)
|
|
463
|
+
], UsersGroupsState.prototype, "linkUserToApplication", null);
|
|
464
|
+
__decorate([
|
|
465
|
+
Action(GetUserSummary)
|
|
466
|
+
], UsersGroupsState.prototype, "getUserSummary", null);
|
|
397
467
|
__decorate([
|
|
398
468
|
Action(ResetUserPassword)
|
|
399
469
|
], UsersGroupsState.prototype, "resetUserPassword", null);
|
|
@@ -424,6 +494,9 @@ __decorate([
|
|
|
424
494
|
__decorate([
|
|
425
495
|
Selector()
|
|
426
496
|
], UsersGroupsState, "getSelectedUser", null);
|
|
497
|
+
__decorate([
|
|
498
|
+
Selector()
|
|
499
|
+
], UsersGroupsState, "getUserSummary", null);
|
|
427
500
|
__decorate([
|
|
428
501
|
Selector()
|
|
429
502
|
], UsersGroupsState, "getGroups", null);
|
|
@@ -442,6 +515,7 @@ UsersGroupsState = __decorate([
|
|
|
442
515
|
defaults: {
|
|
443
516
|
users: [],
|
|
444
517
|
selectedUser: null,
|
|
518
|
+
userSummary: null,
|
|
445
519
|
groups: [],
|
|
446
520
|
selectedGroup: null,
|
|
447
521
|
loadingActive: [],
|
|
@@ -451,7 +525,7 @@ UsersGroupsState = __decorate([
|
|
|
451
525
|
], UsersGroupsState);
|
|
452
526
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UsersGroupsState, decorators: [{
|
|
453
527
|
type: Injectable
|
|
454
|
-
}], propDecorators: { getUsers: [], getUser: [], createUser: [], addUserToGroup: [], updateUser: [], deleteUser: [], resetUserPassword: [], deleteUserFromGroup: [], getGroups: [], getGroup: [], createGroup: [], updateGroup: [], deleteGroup: [], clearSelectedGroup: [] } });
|
|
528
|
+
}], propDecorators: { getUsers: [], getUser: [], createUser: [], addUserToGroup: [], updateUser: [], deleteUser: [], linkUserToApplication: [], getUserSummary: [], resetUserPassword: [], deleteUserFromGroup: [], getGroups: [], getGroup: [], createGroup: [], updateGroup: [], deleteGroup: [], clearSelectedGroup: [] } });
|
|
455
529
|
|
|
456
530
|
class UsersGroupsFacade {
|
|
457
531
|
store = inject(Store);
|
|
@@ -460,6 +534,7 @@ class UsersGroupsFacade {
|
|
|
460
534
|
// ============================================================================
|
|
461
535
|
users = select(UsersGroupsState.getUsers);
|
|
462
536
|
selectedUser = select(UsersGroupsState.getSelectedUser);
|
|
537
|
+
userSummary = select(UsersGroupsState.getUserSummary);
|
|
463
538
|
groups = select(UsersGroupsState.getGroups);
|
|
464
539
|
selectedGroup = select(UsersGroupsState.getSelectedGroup);
|
|
465
540
|
// ============================================================================
|
|
@@ -474,6 +549,8 @@ class UsersGroupsFacade {
|
|
|
474
549
|
isSavingUser = computed(() => this.loadingActive().includes(UsersGroupsActionKey.CreateUser) ||
|
|
475
550
|
this.loadingActive().includes(UsersGroupsActionKey.UpdateUser), ...(ngDevMode ? [{ debugName: "isSavingUser" }] : /* istanbul ignore next */ []));
|
|
476
551
|
isDeletingUser = computed(() => this.loadingActive().includes(UsersGroupsActionKey.DeleteUser), ...(ngDevMode ? [{ debugName: "isDeletingUser" }] : /* istanbul ignore next */ []));
|
|
552
|
+
isLinkingUserToApplication = computed(() => this.loadingActive().includes(UsersGroupsActionKey.LinkUserToApplication), ...(ngDevMode ? [{ debugName: "isLinkingUserToApplication" }] : /* istanbul ignore next */ []));
|
|
553
|
+
isLoadingUserSummary = computed(() => this.loadingActive().includes(UsersGroupsActionKey.GetUserSummary), ...(ngDevMode ? [{ debugName: "isLoadingUserSummary" }] : /* istanbul ignore next */ []));
|
|
477
554
|
isLoadingGroups = computed(() => this.loadingActive().includes(UsersGroupsActionKey.GetGroups), ...(ngDevMode ? [{ debugName: "isLoadingGroups" }] : /* istanbul ignore next */ []));
|
|
478
555
|
isLoadingGroup = computed(() => this.loadingActive().includes(UsersGroupsActionKey.GetGroup), ...(ngDevMode ? [{ debugName: "isLoadingGroup" }] : /* istanbul ignore next */ []));
|
|
479
556
|
isSavingGroup = computed(() => this.loadingActive().includes(UsersGroupsActionKey.CreateGroup) ||
|
|
@@ -506,6 +583,12 @@ class UsersGroupsFacade {
|
|
|
506
583
|
deleteUser(userName) {
|
|
507
584
|
return this.store.dispatch(new DeleteUser(userName));
|
|
508
585
|
}
|
|
586
|
+
linkUserToApplication(userName) {
|
|
587
|
+
return this.store.dispatch(new LinkUserToApplication(userName));
|
|
588
|
+
}
|
|
589
|
+
getUserSummary(userName) {
|
|
590
|
+
return this.store.dispatch(new GetUserSummary(userName));
|
|
591
|
+
}
|
|
509
592
|
resetUserPassword(id, payload) {
|
|
510
593
|
return this.store.dispatch(new ResetUserPassword(id, payload));
|
|
511
594
|
}
|
|
@@ -878,6 +961,21 @@ class ResetPasswordForm {
|
|
|
878
961
|
ValidatorConfig.pattern(this.passwordPattern, this.translocoService.translate('users-groups.password-rules')),
|
|
879
962
|
],
|
|
880
963
|
},
|
|
964
|
+
{
|
|
965
|
+
key: 'confirmPassword',
|
|
966
|
+
inputType: 'password',
|
|
967
|
+
label: this.translocoService.translate('users-groups.confirm-password'),
|
|
968
|
+
placeholder: this.translocoService.translate('users-groups.confirm-password'),
|
|
969
|
+
hint: this.translocoService.translate('users-groups.password-rules'),
|
|
970
|
+
validators: [
|
|
971
|
+
ValidatorConfig.required(),
|
|
972
|
+
ValidatorConfig.pattern(this.passwordPattern, this.translocoService.translate('users-groups.password-rules')),
|
|
973
|
+
ValidatorConfig.custom((value, control) => {
|
|
974
|
+
const newPassword = control?.parent?.get('newPassword')?.value;
|
|
975
|
+
return !value || !newPassword || value === newPassword;
|
|
976
|
+
}, this.translocoService.translate('users-groups.passwords-must-match')),
|
|
977
|
+
],
|
|
978
|
+
},
|
|
881
979
|
],
|
|
882
980
|
},
|
|
883
981
|
],
|
|
@@ -886,6 +984,7 @@ class ResetPasswordForm {
|
|
|
886
984
|
this.resetPasswordFormControl.setValue({
|
|
887
985
|
displayName: this.user()?.displayName || '',
|
|
888
986
|
newPassword: '',
|
|
987
|
+
confirmPassword: '',
|
|
889
988
|
});
|
|
890
989
|
}
|
|
891
990
|
onSubmit() {
|
|
@@ -916,9 +1015,136 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
916
1015
|
], providers: [DialogService], template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <form class=\"p-4\" [class]=\"modal.contentClass\">\r\n <mt-dynamic-form\r\n [formConfig]=\"resetPasswordFormConfig()\"\r\n [formControl]=\"resetPasswordFormControl\"\r\n />\r\n </form>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n variant=\"outlined\"\r\n [disabled]=\"passwordResetLoading()\"\r\n (click)=\"ref.close(false)\"\r\n />\r\n <mt-button\r\n [label]=\"'save' | transloco\"\r\n (click)=\"onSubmit()\"\r\n [loading]=\"passwordResetLoading()\"\r\n [disabled]=\"!this.resetPasswordFormControl.valid\"\r\n />\r\n </div>\r\n</ng-container>\r\n" }]
|
|
917
1016
|
}], propDecorators: { user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: false }] }] } });
|
|
918
1017
|
|
|
1018
|
+
class UserLinkedGroups {
|
|
1019
|
+
facade = inject(UsersGroupsFacade);
|
|
1020
|
+
translocoService = inject(TranslocoService);
|
|
1021
|
+
ref = inject(ModalRef);
|
|
1022
|
+
user = input(null, ...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
|
|
1023
|
+
context = new HttpContext().set(REQUEST_CONTEXT, {
|
|
1024
|
+
useBaseUrl: true,
|
|
1025
|
+
});
|
|
1026
|
+
loading = this.facade.isLoadingUserSummary;
|
|
1027
|
+
summary = this.facade.userSummary;
|
|
1028
|
+
activeTab = signal('groups', ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
|
|
1029
|
+
groups = computed(() => {
|
|
1030
|
+
const lang = this.lang();
|
|
1031
|
+
return (this.summary()?.groups ?? []).map((group) => ({
|
|
1032
|
+
id: group.id,
|
|
1033
|
+
name: this.resolveTranslated(group.name, lang),
|
|
1034
|
+
isActivated: !!group.isActivated,
|
|
1035
|
+
membersCount: group.membersCount ?? 0,
|
|
1036
|
+
}));
|
|
1037
|
+
}, ...(ngDevMode ? [{ debugName: "groups" }] : /* istanbul ignore next */ []));
|
|
1038
|
+
roles = computed(() => {
|
|
1039
|
+
const lang = this.lang();
|
|
1040
|
+
return (this.summary()?.roles ?? []).map((role) => ({
|
|
1041
|
+
id: role.id,
|
|
1042
|
+
name: this.resolveTranslated(role.name, lang),
|
|
1043
|
+
moduleType: role.moduleType ?? '',
|
|
1044
|
+
}));
|
|
1045
|
+
}, ...(ngDevMode ? [{ debugName: "roles" }] : /* istanbul ignore next */ []));
|
|
1046
|
+
permissions = computed(() => {
|
|
1047
|
+
const lang = this.lang();
|
|
1048
|
+
return (this.summary()?.permissions ?? []).map((permission) => ({
|
|
1049
|
+
id: permission.id,
|
|
1050
|
+
name: this.resolveTranslated(permission.name, lang),
|
|
1051
|
+
command: permission.command ?? '',
|
|
1052
|
+
moduleType: permission.moduleType ?? '',
|
|
1053
|
+
}));
|
|
1054
|
+
}, ...(ngDevMode ? [{ debugName: "permissions" }] : /* istanbul ignore next */ []));
|
|
1055
|
+
accessibilities = computed(() => {
|
|
1056
|
+
const lang = this.lang();
|
|
1057
|
+
return (this.summary()?.accessibilities ?? []).map((accessibility) => ({
|
|
1058
|
+
id: accessibility.id,
|
|
1059
|
+
name: this.resolveTranslated(accessibility.moduleName, lang),
|
|
1060
|
+
category: this.resolveTranslated(accessibility.name, lang),
|
|
1061
|
+
}));
|
|
1062
|
+
}, ...(ngDevMode ? [{ debugName: "accessibilities" }] : /* istanbul ignore next */ []));
|
|
1063
|
+
userImage = computed(() => this.summary()?.user?.image ?? this.user()?.image ?? '', ...(ngDevMode ? [{ debugName: "userImage" }] : /* istanbul ignore next */ []));
|
|
1064
|
+
userDisplayName = computed(() => this.summary()?.user?.displayName ?? this.user()?.displayName ?? '', ...(ngDevMode ? [{ debugName: "userDisplayName" }] : /* istanbul ignore next */ []));
|
|
1065
|
+
tabs = computed(() => [
|
|
1066
|
+
{
|
|
1067
|
+
label: `${this.translocoService.translate('users-groups.groups')} (${this.groups().length})`,
|
|
1068
|
+
value: 'groups',
|
|
1069
|
+
},
|
|
1070
|
+
{
|
|
1071
|
+
label: `${this.translocoService.translate('users-groups.permissions')} (${this.permissions().length})`,
|
|
1072
|
+
value: 'permissions',
|
|
1073
|
+
},
|
|
1074
|
+
{
|
|
1075
|
+
label: `${this.translocoService.translate('users-groups.roles')} (${this.roles().length})`,
|
|
1076
|
+
value: 'roles',
|
|
1077
|
+
},
|
|
1078
|
+
{
|
|
1079
|
+
label: `${this.translocoService.translate('users-groups.accessibilities')} (${this.accessibilities().length})`,
|
|
1080
|
+
value: 'accessibilities',
|
|
1081
|
+
},
|
|
1082
|
+
], ...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
|
|
1083
|
+
isEmpty = computed(() => {
|
|
1084
|
+
if (this.loading())
|
|
1085
|
+
return false;
|
|
1086
|
+
switch (this.activeTab()) {
|
|
1087
|
+
case 'groups':
|
|
1088
|
+
return this.groups().length === 0;
|
|
1089
|
+
case 'permissions':
|
|
1090
|
+
return this.permissions().length === 0;
|
|
1091
|
+
case 'roles':
|
|
1092
|
+
return this.roles().length === 0;
|
|
1093
|
+
case 'accessibilities':
|
|
1094
|
+
return this.accessibilities().length === 0;
|
|
1095
|
+
}
|
|
1096
|
+
}, ...(ngDevMode ? [{ debugName: "isEmpty" }] : /* istanbul ignore next */ []));
|
|
1097
|
+
ngOnInit() {
|
|
1098
|
+
const userName = this.user()?.userName;
|
|
1099
|
+
if (!userName)
|
|
1100
|
+
return;
|
|
1101
|
+
this.facade.getUserSummary(userName);
|
|
1102
|
+
}
|
|
1103
|
+
lang() {
|
|
1104
|
+
return this.translocoService.getActiveLang();
|
|
1105
|
+
}
|
|
1106
|
+
resolveTranslated(value, lang) {
|
|
1107
|
+
if (!value)
|
|
1108
|
+
return '';
|
|
1109
|
+
if (typeof value === 'object') {
|
|
1110
|
+
const v = value;
|
|
1111
|
+
return v['display'] || v[lang] || v['en'] || v['ar'] || '';
|
|
1112
|
+
}
|
|
1113
|
+
if (typeof value === 'string') {
|
|
1114
|
+
const trimmed = value.trim();
|
|
1115
|
+
if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
|
|
1116
|
+
try {
|
|
1117
|
+
const parsed = JSON.parse(trimmed);
|
|
1118
|
+
return parsed[lang] || parsed['en'] || parsed['ar'] || '';
|
|
1119
|
+
}
|
|
1120
|
+
catch {
|
|
1121
|
+
return value;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
return value;
|
|
1125
|
+
}
|
|
1126
|
+
return '';
|
|
1127
|
+
}
|
|
1128
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UserLinkedGroups, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1129
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: UserLinkedGroups, isStandalone: true, selector: "mt-user-linked-groups", inputs: { user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div class=\"flex flex-col gap-4 p-4 max-h-[75vh] overflow-auto\">\r\n <div class=\"flex items-center min-w-0\">\r\n <mt-tabs\r\n class=\"flex-1 min-w-0\"\r\n [options]=\"tabs()\"\r\n [(active)]=\"activeTab\"\r\n mode=\"underline\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n ></mt-tabs>\r\n <div\r\n class=\"flex items-center gap-2 pb-2 px-2 shrink-0 border-b border-slate-200 dark:border-slate-700\"\r\n >\r\n <mt-avatar\r\n [image]=\"\r\n userImage()\r\n ? $any(userImage() | secureImage: true : context : 'avatar/')\r\n : ''\r\n \"\r\n [icon]=\"'user.user-01'\"\r\n styleClass=\"w-8! h-8! text-lg! text-gray-600! bg-surface-300!\"\r\n ></mt-avatar>\r\n <div class=\"flex flex-col min-w-0\">\r\n <span\r\n class=\"text-sm font-medium text-slate-600 dark:text-slate-100 truncate\"\r\n [title]=\"userDisplayName()\"\r\n >\r\n {{ userDisplayName() }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n @if (loading()) {\r\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\r\n <p-skeleton height=\"4rem\"></p-skeleton>\r\n <p-skeleton height=\"4rem\"></p-skeleton>\r\n <p-skeleton height=\"4rem\"></p-skeleton>\r\n <p-skeleton height=\"4rem\"></p-skeleton>\r\n </div>\r\n } @else if (isEmpty()) {\r\n <div\r\n class=\"flex flex-col items-center justify-center text-center py-10 gap-2 text-slate-500 dark:text-slate-400\"\r\n >\r\n <mt-icon icon=\"general.link-broken-01\" class=\"text-2xl\" />\r\n <span class=\"text-sm font-medium\">\r\n @switch (activeTab()) {\r\n @case (\"groups\") {\r\n {{ t(\"no-linked-groups\") }}\r\n }\r\n @case (\"permissions\") {\r\n {{ t(\"no-permissions\") }}\r\n }\r\n @case (\"roles\") {\r\n {{ t(\"no-roles\") }}\r\n }\r\n @case (\"accessibilities\") {\r\n {{ t(\"no-accessibilities\") }}\r\n }\r\n }\r\n </span>\r\n </div>\r\n } @else {\r\n @switch (activeTab()) {\r\n @case (\"groups\") {\r\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-3 pb-3\">\r\n @for (group of groups(); track group.id) {\r\n <div\r\n class=\"flex flex-col gap-2 rounded-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 p-3 hover:shadow-sm transition-shadow\"\r\n >\r\n <div class=\"flex items-start justify-between gap-2\">\r\n <div class=\"flex items-center gap-3 min-w-0\">\r\n <span\r\n class=\"inline-flex items-center justify-center rounded-md bg-indigo-50 dark:bg-indigo-900/30 p-2\"\r\n >\r\n <mt-icon\r\n icon=\"user.users-01\"\r\n class=\"text-indigo-600 dark:text-indigo-300 text-xl\"\r\n />\r\n </span>\r\n <div class=\"flex flex-col min-w-0\">\r\n <span\r\n class=\"text-md text-slate-800 dark:text-slate-100 truncate\"\r\n [title]=\"group.name\"\r\n >\r\n {{ group.name }}\r\n </span>\r\n <span\r\n class=\"inline-flex items-center gap-1 text-xs text-slate-500 dark:text-slate-400\"\r\n >\r\n <mt-icon icon=\"user.users-01\" class=\"text-sm\" />\r\n {{ group.membersCount }} {{ t(\"users-number\") }}\r\n </span>\r\n </div>\r\n </div>\r\n\r\n @if (group.isActivated) {\r\n <span\r\n class=\"inline-flex items-center gap-1 rounded-md bg-emerald-50 dark:bg-emerald-900/30 px-2 py-0.5 shrink-0\"\r\n >\r\n <span\r\n class=\"w-1.5 h-1.5 rounded-full bg-emerald-500\"\r\n ></span>\r\n <span\r\n class=\"text-emerald-700 dark:text-emerald-200 text-xs font-medium\"\r\n >\r\n {{ t(\"active\") }}\r\n </span>\r\n </span>\r\n } @else {\r\n <span\r\n class=\"inline-flex items-center gap-1 rounded-md bg-slate-100 dark:bg-slate-700 px-2 py-0.5 shrink-0\"\r\n >\r\n <span\r\n class=\"w-1.5 h-1.5 rounded-full bg-slate-400\"\r\n ></span>\r\n <span\r\n class=\"text-slate-600 dark:text-slate-200 text-xs font-medium\"\r\n >\r\n {{ t(\"inactive\") }}\r\n </span>\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @case (\"permissions\") {\r\n <div\r\n class=\"flex flex-col divide-y divide-slate-100 dark:divide-slate-700 rounded-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800\"\r\n >\r\n @for (permission of permissions(); track permission.id) {\r\n <div class=\"flex items-center gap-3 p-3\">\r\n <span\r\n class=\"inline-flex items-center justify-center rounded-md bg-amber-50 dark:bg-amber-900/30 p-2 shrink-0\"\r\n >\r\n <mt-icon\r\n icon=\"security.shield-tick\"\r\n class=\"text-amber-600 dark:text-amber-300 text-lg\"\r\n />\r\n </span>\r\n <div class=\"flex flex-col min-w-0 flex-1\">\r\n <span\r\n class=\"text-sm font-medium text-slate-800 dark:text-slate-100 truncate\"\r\n [title]=\"permission.name\"\r\n >\r\n {{ permission.name }}\r\n </span>\r\n <span\r\n class=\"text-xs text-slate-500 dark:text-slate-400 truncate\"\r\n [title]=\"permission.command\"\r\n >\r\n {{ permission.command }}\r\n </span>\r\n </div>\r\n @if (permission.moduleType) {\r\n <span\r\n class=\"inline-flex items-center rounded-md bg-slate-50 dark:bg-slate-900/30 px-2 py-0.5 shrink-0 text-xs text-slate-600 dark:text-slate-300 font-medium\"\r\n >\r\n {{ permission.moduleType }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @case (\"roles\") {\r\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-3 pb-3\">\r\n @for (role of roles(); track role.id) {\r\n <div\r\n class=\"flex items-center gap-3 rounded-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 p-3\"\r\n >\r\n <span\r\n class=\"inline-flex items-center justify-center rounded-md bg-violet-50 dark:bg-violet-900/30 p-2 shrink-0\"\r\n >\r\n <mt-icon\r\n icon=\"user.user-check-01\"\r\n class=\"text-violet-600 dark:text-violet-300 text-xl\"\r\n />\r\n </span>\r\n <div class=\"flex flex-col min-w-0 flex-1\">\r\n <span\r\n class=\"text-md text-slate-800 dark:text-slate-100 truncate\"\r\n [title]=\"role.name\"\r\n >\r\n {{ role.name }}\r\n </span>\r\n @if (role.moduleType) {\r\n <span class=\"text-xs text-slate-500 dark:text-slate-400\">\r\n {{ role.moduleType }}\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @case (\"accessibilities\") {\r\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-3 pb-3\">\r\n @for (accessibility of accessibilities(); track accessibility.id) {\r\n <div\r\n class=\"flex items-center gap-3 rounded-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 p-3\"\r\n >\r\n <span\r\n class=\"inline-flex items-center justify-center rounded-md bg-sky-50 dark:bg-sky-900/30 p-2 shrink-0\"\r\n >\r\n <mt-icon\r\n icon=\"security.lock-unlocked-01\"\r\n class=\"text-sky-600 dark:text-sky-300 text-xl\"\r\n />\r\n </span>\r\n <div class=\"flex flex-col min-w-0 flex-1\">\r\n <span\r\n class=\"text-md text-slate-800 dark:text-slate-100 truncate\"\r\n [title]=\"accessibility.name\"\r\n >\r\n {{ accessibility.name }}\r\n </span>\r\n @if (accessibility.category) {\r\n <span class=\"text-xs text-slate-500 dark:text-slate-400\">\r\n {{ accessibility.category }}\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n</ng-container>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "pipe", type: SecureImagePipe, name: "secureImage" }] });
|
|
1130
|
+
}
|
|
1131
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UserLinkedGroups, decorators: [{
|
|
1132
|
+
type: Component,
|
|
1133
|
+
args: [{ selector: 'mt-user-linked-groups', standalone: true, imports: [
|
|
1134
|
+
CommonModule,
|
|
1135
|
+
TranslocoDirective,
|
|
1136
|
+
SkeletonModule,
|
|
1137
|
+
Icon,
|
|
1138
|
+
Tabs,
|
|
1139
|
+
Avatar,
|
|
1140
|
+
SecureImagePipe,
|
|
1141
|
+
], template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div class=\"flex flex-col gap-4 p-4 max-h-[75vh] overflow-auto\">\r\n <div class=\"flex items-center min-w-0\">\r\n <mt-tabs\r\n class=\"flex-1 min-w-0\"\r\n [options]=\"tabs()\"\r\n [(active)]=\"activeTab\"\r\n mode=\"underline\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n ></mt-tabs>\r\n <div\r\n class=\"flex items-center gap-2 pb-2 px-2 shrink-0 border-b border-slate-200 dark:border-slate-700\"\r\n >\r\n <mt-avatar\r\n [image]=\"\r\n userImage()\r\n ? $any(userImage() | secureImage: true : context : 'avatar/')\r\n : ''\r\n \"\r\n [icon]=\"'user.user-01'\"\r\n styleClass=\"w-8! h-8! text-lg! text-gray-600! bg-surface-300!\"\r\n ></mt-avatar>\r\n <div class=\"flex flex-col min-w-0\">\r\n <span\r\n class=\"text-sm font-medium text-slate-600 dark:text-slate-100 truncate\"\r\n [title]=\"userDisplayName()\"\r\n >\r\n {{ userDisplayName() }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n @if (loading()) {\r\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\r\n <p-skeleton height=\"4rem\"></p-skeleton>\r\n <p-skeleton height=\"4rem\"></p-skeleton>\r\n <p-skeleton height=\"4rem\"></p-skeleton>\r\n <p-skeleton height=\"4rem\"></p-skeleton>\r\n </div>\r\n } @else if (isEmpty()) {\r\n <div\r\n class=\"flex flex-col items-center justify-center text-center py-10 gap-2 text-slate-500 dark:text-slate-400\"\r\n >\r\n <mt-icon icon=\"general.link-broken-01\" class=\"text-2xl\" />\r\n <span class=\"text-sm font-medium\">\r\n @switch (activeTab()) {\r\n @case (\"groups\") {\r\n {{ t(\"no-linked-groups\") }}\r\n }\r\n @case (\"permissions\") {\r\n {{ t(\"no-permissions\") }}\r\n }\r\n @case (\"roles\") {\r\n {{ t(\"no-roles\") }}\r\n }\r\n @case (\"accessibilities\") {\r\n {{ t(\"no-accessibilities\") }}\r\n }\r\n }\r\n </span>\r\n </div>\r\n } @else {\r\n @switch (activeTab()) {\r\n @case (\"groups\") {\r\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-3 pb-3\">\r\n @for (group of groups(); track group.id) {\r\n <div\r\n class=\"flex flex-col gap-2 rounded-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 p-3 hover:shadow-sm transition-shadow\"\r\n >\r\n <div class=\"flex items-start justify-between gap-2\">\r\n <div class=\"flex items-center gap-3 min-w-0\">\r\n <span\r\n class=\"inline-flex items-center justify-center rounded-md bg-indigo-50 dark:bg-indigo-900/30 p-2\"\r\n >\r\n <mt-icon\r\n icon=\"user.users-01\"\r\n class=\"text-indigo-600 dark:text-indigo-300 text-xl\"\r\n />\r\n </span>\r\n <div class=\"flex flex-col min-w-0\">\r\n <span\r\n class=\"text-md text-slate-800 dark:text-slate-100 truncate\"\r\n [title]=\"group.name\"\r\n >\r\n {{ group.name }}\r\n </span>\r\n <span\r\n class=\"inline-flex items-center gap-1 text-xs text-slate-500 dark:text-slate-400\"\r\n >\r\n <mt-icon icon=\"user.users-01\" class=\"text-sm\" />\r\n {{ group.membersCount }} {{ t(\"users-number\") }}\r\n </span>\r\n </div>\r\n </div>\r\n\r\n @if (group.isActivated) {\r\n <span\r\n class=\"inline-flex items-center gap-1 rounded-md bg-emerald-50 dark:bg-emerald-900/30 px-2 py-0.5 shrink-0\"\r\n >\r\n <span\r\n class=\"w-1.5 h-1.5 rounded-full bg-emerald-500\"\r\n ></span>\r\n <span\r\n class=\"text-emerald-700 dark:text-emerald-200 text-xs font-medium\"\r\n >\r\n {{ t(\"active\") }}\r\n </span>\r\n </span>\r\n } @else {\r\n <span\r\n class=\"inline-flex items-center gap-1 rounded-md bg-slate-100 dark:bg-slate-700 px-2 py-0.5 shrink-0\"\r\n >\r\n <span\r\n class=\"w-1.5 h-1.5 rounded-full bg-slate-400\"\r\n ></span>\r\n <span\r\n class=\"text-slate-600 dark:text-slate-200 text-xs font-medium\"\r\n >\r\n {{ t(\"inactive\") }}\r\n </span>\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @case (\"permissions\") {\r\n <div\r\n class=\"flex flex-col divide-y divide-slate-100 dark:divide-slate-700 rounded-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800\"\r\n >\r\n @for (permission of permissions(); track permission.id) {\r\n <div class=\"flex items-center gap-3 p-3\">\r\n <span\r\n class=\"inline-flex items-center justify-center rounded-md bg-amber-50 dark:bg-amber-900/30 p-2 shrink-0\"\r\n >\r\n <mt-icon\r\n icon=\"security.shield-tick\"\r\n class=\"text-amber-600 dark:text-amber-300 text-lg\"\r\n />\r\n </span>\r\n <div class=\"flex flex-col min-w-0 flex-1\">\r\n <span\r\n class=\"text-sm font-medium text-slate-800 dark:text-slate-100 truncate\"\r\n [title]=\"permission.name\"\r\n >\r\n {{ permission.name }}\r\n </span>\r\n <span\r\n class=\"text-xs text-slate-500 dark:text-slate-400 truncate\"\r\n [title]=\"permission.command\"\r\n >\r\n {{ permission.command }}\r\n </span>\r\n </div>\r\n @if (permission.moduleType) {\r\n <span\r\n class=\"inline-flex items-center rounded-md bg-slate-50 dark:bg-slate-900/30 px-2 py-0.5 shrink-0 text-xs text-slate-600 dark:text-slate-300 font-medium\"\r\n >\r\n {{ permission.moduleType }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @case (\"roles\") {\r\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-3 pb-3\">\r\n @for (role of roles(); track role.id) {\r\n <div\r\n class=\"flex items-center gap-3 rounded-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 p-3\"\r\n >\r\n <span\r\n class=\"inline-flex items-center justify-center rounded-md bg-violet-50 dark:bg-violet-900/30 p-2 shrink-0\"\r\n >\r\n <mt-icon\r\n icon=\"user.user-check-01\"\r\n class=\"text-violet-600 dark:text-violet-300 text-xl\"\r\n />\r\n </span>\r\n <div class=\"flex flex-col min-w-0 flex-1\">\r\n <span\r\n class=\"text-md text-slate-800 dark:text-slate-100 truncate\"\r\n [title]=\"role.name\"\r\n >\r\n {{ role.name }}\r\n </span>\r\n @if (role.moduleType) {\r\n <span class=\"text-xs text-slate-500 dark:text-slate-400\">\r\n {{ role.moduleType }}\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @case (\"accessibilities\") {\r\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-3 pb-3\">\r\n @for (accessibility of accessibilities(); track accessibility.id) {\r\n <div\r\n class=\"flex items-center gap-3 rounded-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 p-3\"\r\n >\r\n <span\r\n class=\"inline-flex items-center justify-center rounded-md bg-sky-50 dark:bg-sky-900/30 p-2 shrink-0\"\r\n >\r\n <mt-icon\r\n icon=\"security.lock-unlocked-01\"\r\n class=\"text-sky-600 dark:text-sky-300 text-xl\"\r\n />\r\n </span>\r\n <div class=\"flex flex-col min-w-0 flex-1\">\r\n <span\r\n class=\"text-md text-slate-800 dark:text-slate-100 truncate\"\r\n [title]=\"accessibility.name\"\r\n >\r\n {{ accessibility.name }}\r\n </span>\r\n @if (accessibility.category) {\r\n <span class=\"text-xs text-slate-500 dark:text-slate-400\">\r\n {{ accessibility.category }}\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n</ng-container>\r\n" }]
|
|
1142
|
+
}], propDecorators: { user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: false }] }] } });
|
|
1143
|
+
|
|
919
1144
|
class Users {
|
|
920
1145
|
typeCol = viewChild.required('typeCol');
|
|
921
1146
|
userCol = viewChild.required('userCol');
|
|
1147
|
+
applicationLinkCol = viewChild.required('applicationLinkCol');
|
|
922
1148
|
facade = inject(UsersGroupsFacade);
|
|
923
1149
|
modal = inject(ModalService);
|
|
924
1150
|
translocoService = inject(TranslocoService);
|
|
@@ -930,6 +1156,8 @@ class Users {
|
|
|
930
1156
|
return all.filter((user) => !user.isExternal);
|
|
931
1157
|
case 'external':
|
|
932
1158
|
return all.filter((user) => user.isExternal);
|
|
1159
|
+
case 'notLinked':
|
|
1160
|
+
return all.filter((user) => !this.isLinkedToCurrentApplication(user));
|
|
933
1161
|
case 'all':
|
|
934
1162
|
default:
|
|
935
1163
|
return all;
|
|
@@ -948,6 +1176,10 @@ class Users {
|
|
|
948
1176
|
label: this.translocoService.translate('users-groups.external'),
|
|
949
1177
|
value: 'external',
|
|
950
1178
|
},
|
|
1179
|
+
{
|
|
1180
|
+
label: this.translocoService.translate('users-groups.not-linked'),
|
|
1181
|
+
value: 'notLinked',
|
|
1182
|
+
},
|
|
951
1183
|
], ...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
|
|
952
1184
|
activeTab = signal('all', ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
|
|
953
1185
|
tableActions = signal([
|
|
@@ -961,7 +1193,17 @@ class Users {
|
|
|
961
1193
|
},
|
|
962
1194
|
], ...(ngDevMode ? [{ debugName: "tableActions" }] : /* istanbul ignore next */ []));
|
|
963
1195
|
deletingRowIds = signal([], ...(ngDevMode ? [{ debugName: "deletingRowIds" }] : /* istanbul ignore next */ []));
|
|
1196
|
+
linkingRowIds = signal([], ...(ngDevMode ? [{ debugName: "linkingRowIds" }] : /* istanbul ignore next */ []));
|
|
964
1197
|
rowActions = signal([
|
|
1198
|
+
{
|
|
1199
|
+
icon: 'general.link-01',
|
|
1200
|
+
tooltip: this.translocoService.translate('users-groups.linked-groups'),
|
|
1201
|
+
color: 'secondary',
|
|
1202
|
+
action: (row) => {
|
|
1203
|
+
this.openLinkedGroupsDialog(row);
|
|
1204
|
+
},
|
|
1205
|
+
hidden: (row) => !this.isLinkedToCurrentApplication(row),
|
|
1206
|
+
},
|
|
965
1207
|
{
|
|
966
1208
|
icon: 'security.key-01',
|
|
967
1209
|
tooltip: this.translocoService.translate('users-groups.reset-password'),
|
|
@@ -969,7 +1211,7 @@ class Users {
|
|
|
969
1211
|
action: (row) => {
|
|
970
1212
|
this.addResetPasswordDialog(row);
|
|
971
1213
|
},
|
|
972
|
-
hidden: (row) => !row.isExternal,
|
|
1214
|
+
hidden: (row) => !row.isExternal || !this.isLinkedToCurrentApplication(row),
|
|
973
1215
|
},
|
|
974
1216
|
{
|
|
975
1217
|
icon: 'custom.pencil',
|
|
@@ -978,25 +1220,49 @@ class Users {
|
|
|
978
1220
|
action: (row) => {
|
|
979
1221
|
this.addUserDialog(row);
|
|
980
1222
|
},
|
|
981
|
-
hidden: (row) => !row.isExternal,
|
|
1223
|
+
hidden: (row) => !row.isExternal || !this.isLinkedToCurrentApplication(row),
|
|
1224
|
+
},
|
|
1225
|
+
{
|
|
1226
|
+
icon: 'user.user-plus-01',
|
|
1227
|
+
tooltip: this.translocoService.translate('users-groups.link-to-application'),
|
|
1228
|
+
color: 'success',
|
|
1229
|
+
variant: 'outlined',
|
|
1230
|
+
action: (row) => {
|
|
1231
|
+
this.linkUserToApplication(row);
|
|
1232
|
+
},
|
|
1233
|
+
hidden: (row) => this.isLinkedToCurrentApplication(row),
|
|
1234
|
+
confirmation: {
|
|
1235
|
+
type: 'popup',
|
|
1236
|
+
header: this.translocoService.translate('users-groups.link-confirm-header'),
|
|
1237
|
+
message: this.translocoService.translate('users-groups.link-confirm-message'),
|
|
1238
|
+
icon: 'user.user-plus-01',
|
|
1239
|
+
acceptLabel: this.translocoService.translate('users-groups.link-to-application'),
|
|
1240
|
+
rejectLabel: this.translocoService.translate('users-groups.cancel'),
|
|
1241
|
+
acceptButton: {
|
|
1242
|
+
severity: 'success',
|
|
1243
|
+
},
|
|
1244
|
+
},
|
|
1245
|
+
loading: (row) => this.linkingRowIds().includes(row.userName),
|
|
982
1246
|
},
|
|
983
1247
|
{
|
|
984
1248
|
icon: 'general.trash-01',
|
|
985
|
-
tooltip: this.translocoService.translate('
|
|
1249
|
+
tooltip: this.translocoService.translate('users-groups.unlink-from-application'),
|
|
986
1250
|
color: 'danger',
|
|
987
1251
|
variant: 'outlined',
|
|
988
1252
|
action: (row) => {
|
|
989
|
-
this.
|
|
990
|
-
this.facade
|
|
991
|
-
.deleteUser(row.userName)
|
|
992
|
-
.pipe(finalize(() => {
|
|
993
|
-
this.deletingRowIds.update((ids) => ids.filter((id) => id !== row.userName));
|
|
994
|
-
}))
|
|
995
|
-
.subscribe();
|
|
1253
|
+
this.unlinkUserFromApplication(row);
|
|
996
1254
|
},
|
|
1255
|
+
hidden: (row) => !this.isLinkedToCurrentApplication(row),
|
|
997
1256
|
confirmation: {
|
|
998
1257
|
type: 'popup',
|
|
999
|
-
|
|
1258
|
+
header: this.translocoService.translate('users-groups.unlink-confirm-header'),
|
|
1259
|
+
message: this.translocoService.translate('users-groups.unlink-confirm-message'),
|
|
1260
|
+
icon: 'general.link-broken-01',
|
|
1261
|
+
acceptLabel: this.translocoService.translate('users-groups.unlink-from-application'),
|
|
1262
|
+
rejectLabel: this.translocoService.translate('users-groups.cancel'),
|
|
1263
|
+
acceptButton: {
|
|
1264
|
+
severity: 'danger',
|
|
1265
|
+
},
|
|
1000
1266
|
},
|
|
1001
1267
|
loading: (row) => this.deletingRowIds().includes(row.userName),
|
|
1002
1268
|
},
|
|
@@ -1018,6 +1284,26 @@ class Users {
|
|
|
1018
1284
|
type: 'custom',
|
|
1019
1285
|
customCellTpl: this.typeCol(),
|
|
1020
1286
|
},
|
|
1287
|
+
{
|
|
1288
|
+
key: 'isLinkedToCurrentApplication',
|
|
1289
|
+
label: this.translocoService.translate('users-groups.application-link'),
|
|
1290
|
+
type: 'custom',
|
|
1291
|
+
customCellTpl: this.applicationLinkCol(),
|
|
1292
|
+
filterConfig: {
|
|
1293
|
+
type: 'select',
|
|
1294
|
+
label: this.translocoService.translate('users-groups.application-link'),
|
|
1295
|
+
options: [
|
|
1296
|
+
{
|
|
1297
|
+
label: this.translocoService.translate('users-groups.linked'),
|
|
1298
|
+
value: true,
|
|
1299
|
+
},
|
|
1300
|
+
{
|
|
1301
|
+
label: this.translocoService.translate('users-groups.not-linked'),
|
|
1302
|
+
value: false,
|
|
1303
|
+
},
|
|
1304
|
+
],
|
|
1305
|
+
},
|
|
1306
|
+
},
|
|
1021
1307
|
{
|
|
1022
1308
|
key: 'email',
|
|
1023
1309
|
label: this.translocoService.translate('users-groups.email'),
|
|
@@ -1037,6 +1323,35 @@ class Users {
|
|
|
1037
1323
|
ngOnInit() {
|
|
1038
1324
|
this.facade.getUsers();
|
|
1039
1325
|
}
|
|
1326
|
+
isLinkedToCurrentApplication(user) {
|
|
1327
|
+
return user?.isLinkedToCurrentApplication !== false;
|
|
1328
|
+
}
|
|
1329
|
+
linkUserToApplication(user) {
|
|
1330
|
+
const userName = user?.userName;
|
|
1331
|
+
if (!userName) {
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
this.linkingRowIds.update((ids) => [...ids, userName]);
|
|
1335
|
+
this.facade
|
|
1336
|
+
.linkUserToApplication(userName)
|
|
1337
|
+
.pipe(finalize(() => {
|
|
1338
|
+
this.linkingRowIds.update((ids) => ids.filter((id) => id !== userName));
|
|
1339
|
+
}))
|
|
1340
|
+
.subscribe();
|
|
1341
|
+
}
|
|
1342
|
+
unlinkUserFromApplication(user) {
|
|
1343
|
+
const userName = user?.userName;
|
|
1344
|
+
if (!userName || !this.isLinkedToCurrentApplication(user)) {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
this.deletingRowIds.update((ids) => [...ids, userName]);
|
|
1348
|
+
this.facade
|
|
1349
|
+
.deleteUser(userName)
|
|
1350
|
+
.pipe(finalize(() => {
|
|
1351
|
+
this.deletingRowIds.update((ids) => ids.filter((id) => id !== userName));
|
|
1352
|
+
}))
|
|
1353
|
+
.subscribe();
|
|
1354
|
+
}
|
|
1040
1355
|
addUserDialog(user = null) {
|
|
1041
1356
|
const modalType = user ? 'drawer' : 'dialog';
|
|
1042
1357
|
this.modal.openModal(UserForm, modalType, {
|
|
@@ -1067,8 +1382,19 @@ class Users {
|
|
|
1067
1382
|
},
|
|
1068
1383
|
});
|
|
1069
1384
|
}
|
|
1385
|
+
openLinkedGroupsDialog(user) {
|
|
1386
|
+
this.modal.openModal(UserLinkedGroups, 'dialog', {
|
|
1387
|
+
header: this.translocoService.translate('users-groups.summary'),
|
|
1388
|
+
styleClass: '!w-[50rem]',
|
|
1389
|
+
dismissableMask: true,
|
|
1390
|
+
dismissible: true,
|
|
1391
|
+
inputValues: {
|
|
1392
|
+
user,
|
|
1393
|
+
},
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1070
1396
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: Users, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1071
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: Users, isStandalone: true, selector: "mt-users", viewQueries: [{ propertyName: "typeCol", first: true, predicate: ["typeCol"], descendants: true, isSignal: true }, { propertyName: "userCol", first: true, predicate: ["userCol"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\
|
|
1397
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: Users, isStandalone: true, selector: "mt-users", viewQueries: [{ propertyName: "typeCol", first: true, predicate: ["typeCol"], descendants: true, isSignal: true }, { propertyName: "userCol", first: true, predicate: ["userCol"], descendants: true, isSignal: true }, { propertyName: "applicationLinkCol", first: true, predicate: ["applicationLinkCol"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\n <div class=\"mt-5\">\n <ng-template #typeCol let-row>\n @if (row.isExternal) {\n <span\n class=\"inline-flex items-center gap-1 rounded-md bg-slate-50 dark:bg-slate-900/30 p-2\"\n >\n <mt-icon\n icon=\"general.link-external-02\"\n class=\"text-slate-600 dark:text-slate-300 text-sm\"\n />\n <span class=\"text-slate-700 dark:text-slate-200 text-xs font-medium\">\n {{ t(\"external\") }}\n </span>\n </span>\n } @else {\n <span\n class=\"inline-flex items-center gap-1 rounded-md bg-emerald-50 dark:bg-emerald-900/30 p-2\"\n >\n <mt-icon\n icon=\"user.users-01\"\n class=\"text-emerald-600 dark:text-emerald-300 text-sm\"\n />\n <span\n class=\"text-emerald-700 dark:text-emerald-200 text-xs font-medium\"\n >\n {{ t(\"internal\") }}\n </span>\n </span>\n }\n </ng-template>\n <ng-template #userCol let-row>\n <div class=\"flex items-center gap-2\">\n <mt-avatar [icon]=\"'custom.user-pp'\"> </mt-avatar> {{ row.displayName }}\n </div>\n </ng-template>\n <ng-template #applicationLinkCol let-row>\n @if (isLinkedToCurrentApplication(row)) {\n <span\n class=\"inline-flex items-center gap-1 rounded-md bg-emerald-50 dark:bg-emerald-900/30 p-2\"\n >\n <mt-icon\n icon=\"user.user-check-01\"\n class=\"text-emerald-600 dark:text-emerald-300 text-sm\"\n />\n <span\n class=\"text-emerald-700 dark:text-emerald-200 text-xs font-medium\"\n >\n {{ t(\"linked\") }}\n </span>\n </span>\n } @else {\n <span\n class=\"inline-flex items-center gap-1 rounded-md bg-amber-50 dark:bg-amber-900/30 p-2\"\n >\n <mt-icon\n icon=\"general.link-broken-01\"\n class=\"text-amber-600 dark:text-amber-300 text-sm\"\n />\n <span class=\"text-amber-700 dark:text-amber-200 text-xs font-medium\">\n {{ t(\"not-linked\") }}\n </span>\n </span>\n }\n </ng-template>\n\n <mt-table\n [tabs]=\"tabs()\"\n [(activeTab)]=\"activeTab\"\n [data]=\"users()\"\n [columns]=\"tableColumns()\"\n [actions]=\"tableActions()\"\n [rowActions]=\"rowActions()\"\n [generalSearch]=\"true\"\n [showFilters]=\"true\"\n [loading]=\"loading()\"\n storageKey=\"users-groups-users-table\"\n >\n </mt-table>\n </div>\n</ng-container>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "lazyLocalSearch", "showFilters", "filterMode", "loading", "updating", "lazy", "lazyLocalSort", "lazyTotalRecords", "reorderableColumns", "reorderableRows", "dataKey", "storageKey", "storageMode", "exportable", "printable", "groupable", "cellClickFilter", "freezeActions", "printTitle", "exportFilename", "actionShape", "rowActionsLoadingFn", "tableLayout", "noCard", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm", "groupBy"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "rowActionsRequested", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange", "groupByChange"] }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }] });
|
|
1072
1398
|
}
|
|
1073
1399
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: Users, decorators: [{
|
|
1074
1400
|
type: Component,
|
|
@@ -1079,8 +1405,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
1079
1405
|
Avatar,
|
|
1080
1406
|
Icon,
|
|
1081
1407
|
TranslocoDirective,
|
|
1082
|
-
], template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\
|
|
1083
|
-
}], propDecorators: { typeCol: [{ type: i0.ViewChild, args: ['typeCol', { isSignal: true }] }], userCol: [{ type: i0.ViewChild, args: ['userCol', { isSignal: true }] }] } });
|
|
1408
|
+
], template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\n <div class=\"mt-5\">\n <ng-template #typeCol let-row>\n @if (row.isExternal) {\n <span\n class=\"inline-flex items-center gap-1 rounded-md bg-slate-50 dark:bg-slate-900/30 p-2\"\n >\n <mt-icon\n icon=\"general.link-external-02\"\n class=\"text-slate-600 dark:text-slate-300 text-sm\"\n />\n <span class=\"text-slate-700 dark:text-slate-200 text-xs font-medium\">\n {{ t(\"external\") }}\n </span>\n </span>\n } @else {\n <span\n class=\"inline-flex items-center gap-1 rounded-md bg-emerald-50 dark:bg-emerald-900/30 p-2\"\n >\n <mt-icon\n icon=\"user.users-01\"\n class=\"text-emerald-600 dark:text-emerald-300 text-sm\"\n />\n <span\n class=\"text-emerald-700 dark:text-emerald-200 text-xs font-medium\"\n >\n {{ t(\"internal\") }}\n </span>\n </span>\n }\n </ng-template>\n <ng-template #userCol let-row>\n <div class=\"flex items-center gap-2\">\n <mt-avatar [icon]=\"'custom.user-pp'\"> </mt-avatar> {{ row.displayName }}\n </div>\n </ng-template>\n <ng-template #applicationLinkCol let-row>\n @if (isLinkedToCurrentApplication(row)) {\n <span\n class=\"inline-flex items-center gap-1 rounded-md bg-emerald-50 dark:bg-emerald-900/30 p-2\"\n >\n <mt-icon\n icon=\"user.user-check-01\"\n class=\"text-emerald-600 dark:text-emerald-300 text-sm\"\n />\n <span\n class=\"text-emerald-700 dark:text-emerald-200 text-xs font-medium\"\n >\n {{ t(\"linked\") }}\n </span>\n </span>\n } @else {\n <span\n class=\"inline-flex items-center gap-1 rounded-md bg-amber-50 dark:bg-amber-900/30 p-2\"\n >\n <mt-icon\n icon=\"general.link-broken-01\"\n class=\"text-amber-600 dark:text-amber-300 text-sm\"\n />\n <span class=\"text-amber-700 dark:text-amber-200 text-xs font-medium\">\n {{ t(\"not-linked\") }}\n </span>\n </span>\n }\n </ng-template>\n\n <mt-table\n [tabs]=\"tabs()\"\n [(activeTab)]=\"activeTab\"\n [data]=\"users()\"\n [columns]=\"tableColumns()\"\n [actions]=\"tableActions()\"\n [rowActions]=\"rowActions()\"\n [generalSearch]=\"true\"\n [showFilters]=\"true\"\n [loading]=\"loading()\"\n storageKey=\"users-groups-users-table\"\n >\n </mt-table>\n </div>\n</ng-container>\n" }]
|
|
1409
|
+
}], propDecorators: { typeCol: [{ type: i0.ViewChild, args: ['typeCol', { isSignal: true }] }], userCol: [{ type: i0.ViewChild, args: ['userCol', { isSignal: true }] }], applicationLinkCol: [{ type: i0.ViewChild, args: ['applicationLinkCol', { isSignal: true }] }] } });
|
|
1084
1410
|
|
|
1085
1411
|
class GroupForm {
|
|
1086
1412
|
modal = inject(ModalService);
|
|
@@ -1361,5 +1687,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
1361
1687
|
* Generated bundle index. Do not edit.
|
|
1362
1688
|
*/
|
|
1363
1689
|
|
|
1364
|
-
export { AddUserToGroup, ClearSelectedGroup, CreateGroup, CreateUser, DeleteGroup, DeleteUser, DeleteUserFromGroup, GetGroup, GetGroups, GetUser, GetUsers, GroupForm, Groups, ResetUserPassword, UpdateGroup, UpdateUser, UserForm, Users, UsersGroups, UsersGroupsActionKey, UsersGroupsFacade, UsersGroupsState };
|
|
1690
|
+
export { AddUserToGroup, ClearSelectedGroup, CreateGroup, CreateUser, DeleteGroup, DeleteUser, DeleteUserFromGroup, GetGroup, GetGroups, GetUser, GetUserSummary, GetUsers, GroupForm, Groups, LinkUserToApplication, ResetUserPassword, UpdateGroup, UpdateUser, UserForm, Users, UsersGroups, UsersGroupsActionKey, UsersGroupsFacade, UsersGroupsState };
|
|
1365
1691
|
//# sourceMappingURL=masterteam-users-groups.mjs.map
|