@masterteam/users-groups 0.0.13 → 0.0.15

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.
@@ -13,6 +13,7 @@ import { Table } from '@masterteam/components/table';
13
13
  import * as i1 from 'primeng/skeleton';
14
14
  import { SkeletonModule } from 'primeng/skeleton';
15
15
  import { Avatar } from '@masterteam/components/avatar';
16
+ import { Icon } from '@masterteam/icons';
16
17
  import { ModalService } from '@masterteam/components/modal';
17
18
  import { toSignal } from '@angular/core/rxjs-interop';
18
19
  import * as i2 from '@angular/forms';
@@ -21,6 +22,7 @@ import { DynamicForm } from '@masterteam/forms/dynamic-form';
21
22
  import { ModalRef, DialogService } from '@masterteam/components/dialog';
22
23
  import { Tabs } from '@masterteam/components/tabs';
23
24
  import { finalize } from 'rxjs';
25
+ import { SecureImagePipe } from '@masterteam/components/upload-field';
24
26
 
25
27
  class GetUsers {
26
28
  static type = '[UsersGroups] Get Users';
@@ -62,6 +64,13 @@ class DeleteUser {
62
64
  this.userName = userName;
63
65
  }
64
66
  }
67
+ class GetUserSummary {
68
+ userName;
69
+ static type = '[UsersGroups] Get User Summary';
70
+ constructor(userName) {
71
+ this.userName = userName;
72
+ }
73
+ }
65
74
  class ResetUserPassword {
66
75
  id;
67
76
  payload;
@@ -122,6 +131,7 @@ var UsersGroupsActionKey;
122
131
  UsersGroupsActionKey["CreateUser"] = "createUser";
123
132
  UsersGroupsActionKey["UpdateUser"] = "updateUser";
124
133
  UsersGroupsActionKey["DeleteUser"] = "deleteUser";
134
+ UsersGroupsActionKey["GetUserSummary"] = "getUserSummary";
125
135
  UsersGroupsActionKey["AddUserToGroup"] = "addUserToGroup";
126
136
  UsersGroupsActionKey["DeleteUserFromGroup"] = "deleteUserFromGroup";
127
137
  UsersGroupsActionKey["GetGroups"] = "getGroups";
@@ -152,6 +162,9 @@ let UsersGroupsState = class UsersGroupsState extends CrudStateBase {
152
162
  static getSelectedUser(state) {
153
163
  return state.selectedUser;
154
164
  }
165
+ static getUserSummary(state) {
166
+ return state.userSummary;
167
+ }
155
168
  static getGroups(state) {
156
169
  return state.groups;
157
170
  }
@@ -223,13 +236,15 @@ let UsersGroupsState = class UsersGroupsState extends CrudStateBase {
223
236
  key: UsersGroupsActionKey.AddUserToGroup,
224
237
  request$: req$,
225
238
  onSuccess: (response, state) => {
226
- const newMembers = response.data?.members ?? [];
227
- const existingMembers = state.selectedGroup?.members ?? [];
239
+ const updatedGroup = response.data;
240
+ if (!updatedGroup)
241
+ return {};
228
242
  return {
229
243
  selectedGroup: {
230
244
  ...(state.selectedGroup ?? {}),
231
- members: [...existingMembers, ...newMembers],
245
+ ...updatedGroup,
232
246
  },
247
+ groups: this.adapter.upsertOne(state.groups, updatedGroup, 'id'),
233
248
  };
234
249
  },
235
250
  });
@@ -268,6 +283,17 @@ let UsersGroupsState = class UsersGroupsState extends CrudStateBase {
268
283
  id: userName,
269
284
  });
270
285
  }
286
+ getUserSummary(ctx, { userName }) {
287
+ const req$ = this.http.get(`identity/users/${userName}/summary`, { context: this.context });
288
+ return handleApiRequest({
289
+ ctx,
290
+ key: UsersGroupsActionKey.GetUserSummary,
291
+ request$: req$,
292
+ onSuccess: (response) => ({
293
+ userSummary: response.data ?? null,
294
+ }),
295
+ });
296
+ }
271
297
  resetUserPassword(ctx, { id, payload }) {
272
298
  const req$ = this.http.put(`Identity/users/${id}/password/reset`, payload, {
273
299
  context: this.context,
@@ -391,6 +417,9 @@ __decorate([
391
417
  __decorate([
392
418
  Action(DeleteUser)
393
419
  ], UsersGroupsState.prototype, "deleteUser", null);
420
+ __decorate([
421
+ Action(GetUserSummary)
422
+ ], UsersGroupsState.prototype, "getUserSummary", null);
394
423
  __decorate([
395
424
  Action(ResetUserPassword)
396
425
  ], UsersGroupsState.prototype, "resetUserPassword", null);
@@ -421,6 +450,9 @@ __decorate([
421
450
  __decorate([
422
451
  Selector()
423
452
  ], UsersGroupsState, "getSelectedUser", null);
453
+ __decorate([
454
+ Selector()
455
+ ], UsersGroupsState, "getUserSummary", null);
424
456
  __decorate([
425
457
  Selector()
426
458
  ], UsersGroupsState, "getGroups", null);
@@ -439,6 +471,7 @@ UsersGroupsState = __decorate([
439
471
  defaults: {
440
472
  users: [],
441
473
  selectedUser: null,
474
+ userSummary: null,
442
475
  groups: [],
443
476
  selectedGroup: null,
444
477
  loadingActive: [],
@@ -448,7 +481,7 @@ UsersGroupsState = __decorate([
448
481
  ], UsersGroupsState);
449
482
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UsersGroupsState, decorators: [{
450
483
  type: Injectable
451
- }], propDecorators: { getUsers: [], getUser: [], createUser: [], addUserToGroup: [], updateUser: [], deleteUser: [], resetUserPassword: [], deleteUserFromGroup: [], getGroups: [], getGroup: [], createGroup: [], updateGroup: [], deleteGroup: [], clearSelectedGroup: [] } });
484
+ }], propDecorators: { getUsers: [], getUser: [], createUser: [], addUserToGroup: [], updateUser: [], deleteUser: [], getUserSummary: [], resetUserPassword: [], deleteUserFromGroup: [], getGroups: [], getGroup: [], createGroup: [], updateGroup: [], deleteGroup: [], clearSelectedGroup: [] } });
452
485
 
453
486
  class UsersGroupsFacade {
454
487
  store = inject(Store);
@@ -457,6 +490,7 @@ class UsersGroupsFacade {
457
490
  // ============================================================================
458
491
  users = select(UsersGroupsState.getUsers);
459
492
  selectedUser = select(UsersGroupsState.getSelectedUser);
493
+ userSummary = select(UsersGroupsState.getUserSummary);
460
494
  groups = select(UsersGroupsState.getGroups);
461
495
  selectedGroup = select(UsersGroupsState.getSelectedGroup);
462
496
  // ============================================================================
@@ -471,6 +505,7 @@ class UsersGroupsFacade {
471
505
  isSavingUser = computed(() => this.loadingActive().includes(UsersGroupsActionKey.CreateUser) ||
472
506
  this.loadingActive().includes(UsersGroupsActionKey.UpdateUser), ...(ngDevMode ? [{ debugName: "isSavingUser" }] : /* istanbul ignore next */ []));
473
507
  isDeletingUser = computed(() => this.loadingActive().includes(UsersGroupsActionKey.DeleteUser), ...(ngDevMode ? [{ debugName: "isDeletingUser" }] : /* istanbul ignore next */ []));
508
+ isLoadingUserSummary = computed(() => this.loadingActive().includes(UsersGroupsActionKey.GetUserSummary), ...(ngDevMode ? [{ debugName: "isLoadingUserSummary" }] : /* istanbul ignore next */ []));
474
509
  isLoadingGroups = computed(() => this.loadingActive().includes(UsersGroupsActionKey.GetGroups), ...(ngDevMode ? [{ debugName: "isLoadingGroups" }] : /* istanbul ignore next */ []));
475
510
  isLoadingGroup = computed(() => this.loadingActive().includes(UsersGroupsActionKey.GetGroup), ...(ngDevMode ? [{ debugName: "isLoadingGroup" }] : /* istanbul ignore next */ []));
476
511
  isSavingGroup = computed(() => this.loadingActive().includes(UsersGroupsActionKey.CreateGroup) ||
@@ -503,6 +538,9 @@ class UsersGroupsFacade {
503
538
  deleteUser(userName) {
504
539
  return this.store.dispatch(new DeleteUser(userName));
505
540
  }
541
+ getUserSummary(userName) {
542
+ return this.store.dispatch(new GetUserSummary(userName));
543
+ }
506
544
  resetUserPassword(id, payload) {
507
545
  return this.store.dispatch(new ResetUserPassword(id, payload));
508
546
  }
@@ -596,6 +634,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
596
634
  }] });
597
635
 
598
636
  class UserForm {
637
+ passwordPattern = '^(?=.*[A-Z])(?=.*[^a-zA-Z0-9])(?=.*[a-z])(?=.*\\d).{6,}$';
599
638
  modal = inject(ModalService);
600
639
  ref = inject(ModalRef);
601
640
  userForEdit = input(null, ...(ngDevMode ? [{ debugName: "userForEdit" }] : /* istanbul ignore next */ []));
@@ -671,7 +710,7 @@ class UserForm {
671
710
  fields: [
672
711
  new UploadFileFieldConfig({
673
712
  key: 'image',
674
- label: 'Avatar',
713
+ label: this.translocoService.translate('users-groups.avatar'),
675
714
  shape: 'circle',
676
715
  endPoint: 'avatar',
677
716
  context: this.contextGatway,
@@ -703,7 +742,10 @@ class UserForm {
703
742
  key: 'mobile',
704
743
  label: this.translocoService.translate('users-groups.mobile'),
705
744
  placeholder: this.translocoService.translate('users-groups.mobile'),
706
- validators: [ValidatorConfig.required()],
745
+ validators: [
746
+ ValidatorConfig.required(),
747
+ ValidatorConfig.pattern('^\\+?[0-9]{7,15}$', this.translocoService.translate('users-groups.mobile-invalid')),
748
+ ],
707
749
  colSpan: this.fieldColSpan(),
708
750
  order: 4,
709
751
  },
@@ -776,6 +818,7 @@ class UserForm {
776
818
  }
777
819
  updateFormFields() {
778
820
  if (!this.userForEdit()?.userName) {
821
+ const passwordRules = this.translocoService.translate('users-groups.password-rules');
779
822
  this.externalUserFormConfig().sections[0].fields.push({
780
823
  key: 'userName',
781
824
  label: this.translocoService.translate('users-groups.user-name'),
@@ -791,9 +834,10 @@ class UserForm {
791
834
  key: 'password',
792
835
  label: this.translocoService.translate('users-groups.password'),
793
836
  placeholder: this.translocoService.translate('users-groups.password'),
837
+ hint: passwordRules,
794
838
  validators: [
795
839
  ValidatorConfig.required(),
796
- ValidatorConfig.pattern('^(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).+$', "Passwords must have at least one non alphanumeric character.\nPasswords must have at least one uppercase ('A'-'Z')."),
840
+ ValidatorConfig.pattern(this.passwordPattern, passwordRules),
797
841
  ],
798
842
  inputType: 'password',
799
843
  colSpan: 6,
@@ -803,9 +847,14 @@ class UserForm {
803
847
  key: 'confirmPassword',
804
848
  label: this.translocoService.translate('users-groups.confirm-password'),
805
849
  placeholder: this.translocoService.translate('users-groups.confirm-password'),
850
+ hint: passwordRules,
806
851
  validators: [
807
852
  ValidatorConfig.required(),
808
- ValidatorConfig.pattern('^(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).+$', "Passwords must have at least one non alphanumeric character.\nPasswords must have at least one uppercase ('A'-'Z')."),
853
+ ValidatorConfig.pattern(this.passwordPattern, passwordRules),
854
+ ValidatorConfig.custom((value, control) => {
855
+ const password = control?.parent?.get('password')?.value;
856
+ return !value || !password || value === password;
857
+ }, this.translocoService.translate('users-groups.passwords-must-match')),
809
858
  ],
810
859
  inputType: 'password',
811
860
  colSpan: 6,
@@ -815,7 +864,7 @@ class UserForm {
815
864
  }
816
865
  }
817
866
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UserForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
818
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: UserForm, isStandalone: true, selector: "mt-user-form", inputs: { userForEdit: { classPropertyName: "userForEdit", publicName: "userForEdit", isSignal: true, isRequired: false, transformFunction: null } }, providers: [DialogService], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div [class]=\"'flex flex-col gap-1 p-4 ' + modal.contentClass\">\r\n @if (!getUserFormLoading()) {\r\n <div class=\"flex justify-center\">\r\n <div class=\"w-60\">\r\n <mt-tabs\r\n [(active)]=\"selectedTab\"\r\n [options]=\"tabsList\"\r\n fluid\r\n size=\"small\"\r\n [disabled]=\"!!this.userForEdit()?.userName\"\r\n ></mt-tabs>\r\n </div>\r\n </div>\r\n\r\n <form class=\"col-span-1\">\r\n @if (selectedTab() === \"internal\") {\r\n <mt-dynamic-form\r\n [formConfig]=\"internalUserFormConfig()\"\r\n [formControl]=\"internalUserFormControl\"\r\n />\r\n } @else {\r\n <mt-dynamic-form\r\n [formConfig]=\"externalUserFormConfig()\"\r\n [formControl]=\"externalUserFormControl\"\r\n />\r\n }\r\n </form>\r\n } @else {\r\n <p-skeleton class=\"my-4 mt-7\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n }\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n [label]=\"selectedUser() ? ('save' | transloco) : ('add' | transloco)\"\r\n (click)=\"onSubmit()\"\r\n [loading]=\"createUpdateUserLoading()\"\r\n [disabled]=\"isSubmitDisabled()\"\r\n />\r\n </div>\r\n</ng-container>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { 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: DynamicForm, selector: "mt-dynamic-form", inputs: ["formConfig", "forcedHiddenFieldKeys", "preserveForcedHiddenValues", "visibleSectionKeys"], outputs: ["runtimeMessagesChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
867
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: UserForm, isStandalone: true, selector: "mt-user-form", inputs: { userForEdit: { classPropertyName: "userForEdit", publicName: "userForEdit", isSignal: true, isRequired: false, transformFunction: null } }, providers: [DialogService], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div [class]=\"'flex flex-col gap-1 p-4 ' + modal.contentClass\">\r\n @if (!getUserFormLoading()) {\r\n <div class=\"flex justify-center\">\r\n <div class=\"w-60\">\r\n <mt-tabs\r\n [(active)]=\"selectedTab\"\r\n [options]=\"tabsList\"\r\n fluid\r\n size=\"small\"\r\n [disabled]=\"!!this.userForEdit()?.userName\"\r\n ></mt-tabs>\r\n </div>\r\n </div>\r\n\r\n <form class=\"col-span-1\">\r\n @if (selectedTab() === \"internal\") {\r\n <mt-dynamic-form\r\n [formConfig]=\"internalUserFormConfig()\"\r\n [formControl]=\"internalUserFormControl\"\r\n />\r\n } @else {\r\n <mt-dynamic-form\r\n [formConfig]=\"externalUserFormConfig()\"\r\n [formControl]=\"externalUserFormControl\"\r\n />\r\n }\r\n </form>\r\n } @else {\r\n <p-skeleton class=\"my-4 mt-7\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n }\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n variant=\"outlined\"\r\n [disabled]=\"createUpdateUserLoading()\"\r\n (click)=\"ref.close(false)\"\r\n />\r\n <mt-button\r\n [label]=\"selectedUser() ? ('save' | transloco) : ('add' | transloco)\"\r\n (click)=\"onSubmit()\"\r\n [loading]=\"createUpdateUserLoading()\"\r\n [disabled]=\"isSubmitDisabled()\"\r\n />\r\n </div>\r\n</ng-container>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { 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: DynamicForm, selector: "mt-dynamic-form", inputs: ["formConfig", "forcedHiddenFieldKeys", "preserveForcedHiddenValues", "visibleSectionKeys"], outputs: ["runtimeMessagesChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
819
868
  }
820
869
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UserForm, decorators: [{
821
870
  type: Component,
@@ -828,38 +877,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
828
877
  ReactiveFormsModule,
829
878
  Tabs,
830
879
  TranslocoPipe,
831
- ], providers: [DialogService], template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div [class]=\"'flex flex-col gap-1 p-4 ' + modal.contentClass\">\r\n @if (!getUserFormLoading()) {\r\n <div class=\"flex justify-center\">\r\n <div class=\"w-60\">\r\n <mt-tabs\r\n [(active)]=\"selectedTab\"\r\n [options]=\"tabsList\"\r\n fluid\r\n size=\"small\"\r\n [disabled]=\"!!this.userForEdit()?.userName\"\r\n ></mt-tabs>\r\n </div>\r\n </div>\r\n\r\n <form class=\"col-span-1\">\r\n @if (selectedTab() === \"internal\") {\r\n <mt-dynamic-form\r\n [formConfig]=\"internalUserFormConfig()\"\r\n [formControl]=\"internalUserFormControl\"\r\n />\r\n } @else {\r\n <mt-dynamic-form\r\n [formConfig]=\"externalUserFormConfig()\"\r\n [formControl]=\"externalUserFormControl\"\r\n />\r\n }\r\n </form>\r\n } @else {\r\n <p-skeleton class=\"my-4 mt-7\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n }\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n [label]=\"selectedUser() ? ('save' | transloco) : ('add' | transloco)\"\r\n (click)=\"onSubmit()\"\r\n [loading]=\"createUpdateUserLoading()\"\r\n [disabled]=\"isSubmitDisabled()\"\r\n />\r\n </div>\r\n</ng-container>\r\n" }]
880
+ ], providers: [DialogService], template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div [class]=\"'flex flex-col gap-1 p-4 ' + modal.contentClass\">\r\n @if (!getUserFormLoading()) {\r\n <div class=\"flex justify-center\">\r\n <div class=\"w-60\">\r\n <mt-tabs\r\n [(active)]=\"selectedTab\"\r\n [options]=\"tabsList\"\r\n fluid\r\n size=\"small\"\r\n [disabled]=\"!!this.userForEdit()?.userName\"\r\n ></mt-tabs>\r\n </div>\r\n </div>\r\n\r\n <form class=\"col-span-1\">\r\n @if (selectedTab() === \"internal\") {\r\n <mt-dynamic-form\r\n [formConfig]=\"internalUserFormConfig()\"\r\n [formControl]=\"internalUserFormControl\"\r\n />\r\n } @else {\r\n <mt-dynamic-form\r\n [formConfig]=\"externalUserFormConfig()\"\r\n [formControl]=\"externalUserFormControl\"\r\n />\r\n }\r\n </form>\r\n } @else {\r\n <p-skeleton class=\"my-4 mt-7\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n }\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n variant=\"outlined\"\r\n [disabled]=\"createUpdateUserLoading()\"\r\n (click)=\"ref.close(false)\"\r\n />\r\n <mt-button\r\n [label]=\"selectedUser() ? ('save' | transloco) : ('add' | transloco)\"\r\n (click)=\"onSubmit()\"\r\n [loading]=\"createUpdateUserLoading()\"\r\n [disabled]=\"isSubmitDisabled()\"\r\n />\r\n </div>\r\n</ng-container>\r\n" }]
832
881
  }], ctorParameters: () => [], propDecorators: { userForEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "userForEdit", required: false }] }] } });
833
- function passwordMatchValidator(passwordControlName, confirmPasswordControlName) {
834
- return (group) => {
835
- // 1. Get the controls from the group
836
- const passwordControl = group.get(passwordControlName);
837
- const confirmPasswordControl = group.get(confirmPasswordControlName);
838
- // 2. Basic checks (if controls don't exist, or if one is null, it's not a mismatch error)
839
- if (!passwordControl || !confirmPasswordControl) {
840
- return null;
841
- }
842
- // 3. Check for value mismatch
843
- if (passwordControl.value !== confirmPasswordControl.value) {
844
- // 4. Set the error on the 'confirm password' control for clearer user feedback
845
- confirmPasswordControl.setErrors({ mismatch: true });
846
- return { mismatch: true }; // The group itself has a mismatch error
847
- }
848
- else {
849
- // 5. If they match, clear any previous mismatch error on the 'confirm password' control
850
- if (confirmPasswordControl.hasError('mismatch')) {
851
- const errors = confirmPasswordControl.errors;
852
- if (errors) {
853
- delete errors['mismatch'];
854
- confirmPasswordControl.setErrors(Object.keys(errors).length > 0 ? errors : null);
855
- }
856
- }
857
- return null; // No mismatch error
858
- }
859
- };
860
- }
861
882
 
862
883
  class ResetPasswordForm {
884
+ passwordPattern = '^(?=.*[A-Z])(?=.*[^a-zA-Z0-9])(?=.*[a-z])(?=.*\\d).{6,}$';
863
885
  modal = inject(ModalService);
864
886
  ref = inject(ModalRef);
865
887
  translocoService = inject(TranslocoService);
@@ -885,9 +907,10 @@ class ResetPasswordForm {
885
907
  key: 'newPassword',
886
908
  inputType: 'password',
887
909
  label: this.translocoService.translate('users-groups.new-password'),
910
+ hint: this.translocoService.translate('users-groups.password-rules'),
888
911
  validators: [
889
912
  ValidatorConfig.required(),
890
- ValidatorConfig.pattern('^(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).+$', "Passwords must have at least one non alphanumeric character.\nPasswords must have at least one uppercase ('A'-'Z')."),
913
+ ValidatorConfig.pattern(this.passwordPattern, this.translocoService.translate('users-groups.password-rules')),
891
914
  ],
892
915
  },
893
916
  ],
@@ -913,7 +936,7 @@ class ResetPasswordForm {
913
936
  });
914
937
  }
915
938
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ResetPasswordForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
916
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: ResetPasswordForm, isStandalone: true, selector: "mt-reset-password-form", inputs: { user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null } }, providers: [DialogService], ngImport: i0, 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]=\"'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", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: DynamicForm, selector: "mt-dynamic-form", inputs: ["formConfig", "forcedHiddenFieldKeys", "preserveForcedHiddenValues", "visibleSectionKeys"], outputs: ["runtimeMessagesChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
939
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: ResetPasswordForm, isStandalone: true, selector: "mt-reset-password-form", inputs: { user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null } }, providers: [DialogService], ngImport: i0, 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", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: DynamicForm, selector: "mt-dynamic-form", inputs: ["formConfig", "forcedHiddenFieldKeys", "preserveForcedHiddenValues", "visibleSectionKeys"], outputs: ["runtimeMessagesChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
917
940
  }
918
941
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ResetPasswordForm, decorators: [{
919
942
  type: Component,
@@ -925,7 +948,133 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
925
948
  DynamicForm,
926
949
  ReactiveFormsModule,
927
950
  TranslocoPipe,
928
- ], 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]=\"'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" }]
951
+ ], 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" }]
952
+ }], propDecorators: { user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: false }] }] } });
953
+
954
+ class UserLinkedGroups {
955
+ facade = inject(UsersGroupsFacade);
956
+ translocoService = inject(TranslocoService);
957
+ ref = inject(ModalRef);
958
+ user = input(null, ...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
959
+ context = new HttpContext().set(REQUEST_CONTEXT, {
960
+ useBaseUrl: true,
961
+ });
962
+ loading = this.facade.isLoadingUserSummary;
963
+ summary = this.facade.userSummary;
964
+ activeTab = signal('groups', ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
965
+ groups = computed(() => {
966
+ const lang = this.lang();
967
+ return (this.summary()?.groups ?? []).map((group) => ({
968
+ id: group.id,
969
+ name: this.resolveTranslated(group.name, lang),
970
+ isActivated: !!group.isActivated,
971
+ membersCount: group.membersCount ?? 0,
972
+ }));
973
+ }, ...(ngDevMode ? [{ debugName: "groups" }] : /* istanbul ignore next */ []));
974
+ roles = computed(() => {
975
+ const lang = this.lang();
976
+ return (this.summary()?.roles ?? []).map((role) => ({
977
+ id: role.id,
978
+ name: this.resolveTranslated(role.name, lang),
979
+ moduleType: role.moduleType ?? '',
980
+ }));
981
+ }, ...(ngDevMode ? [{ debugName: "roles" }] : /* istanbul ignore next */ []));
982
+ permissions = computed(() => {
983
+ const lang = this.lang();
984
+ return (this.summary()?.permissions ?? []).map((permission) => ({
985
+ id: permission.id,
986
+ name: this.resolveTranslated(permission.name, lang),
987
+ command: permission.command ?? '',
988
+ moduleType: permission.moduleType ?? '',
989
+ }));
990
+ }, ...(ngDevMode ? [{ debugName: "permissions" }] : /* istanbul ignore next */ []));
991
+ accessibilities = computed(() => {
992
+ const lang = this.lang();
993
+ return (this.summary()?.accessibilities ?? []).map((accessibility) => ({
994
+ id: accessibility.id,
995
+ name: this.resolveTranslated(accessibility.moduleName, lang),
996
+ category: this.resolveTranslated(accessibility.name, lang),
997
+ }));
998
+ }, ...(ngDevMode ? [{ debugName: "accessibilities" }] : /* istanbul ignore next */ []));
999
+ userImage = computed(() => this.summary()?.user?.image ?? this.user()?.image ?? '', ...(ngDevMode ? [{ debugName: "userImage" }] : /* istanbul ignore next */ []));
1000
+ userDisplayName = computed(() => this.summary()?.user?.displayName ?? this.user()?.displayName ?? '', ...(ngDevMode ? [{ debugName: "userDisplayName" }] : /* istanbul ignore next */ []));
1001
+ tabs = computed(() => [
1002
+ {
1003
+ label: `${this.translocoService.translate('users-groups.groups')} (${this.groups().length})`,
1004
+ value: 'groups',
1005
+ },
1006
+ {
1007
+ label: `${this.translocoService.translate('users-groups.permissions')} (${this.permissions().length})`,
1008
+ value: 'permissions',
1009
+ },
1010
+ {
1011
+ label: `${this.translocoService.translate('users-groups.roles')} (${this.roles().length})`,
1012
+ value: 'roles',
1013
+ },
1014
+ {
1015
+ label: `${this.translocoService.translate('users-groups.accessibilities')} (${this.accessibilities().length})`,
1016
+ value: 'accessibilities',
1017
+ },
1018
+ ], ...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
1019
+ isEmpty = computed(() => {
1020
+ if (this.loading())
1021
+ return false;
1022
+ switch (this.activeTab()) {
1023
+ case 'groups':
1024
+ return this.groups().length === 0;
1025
+ case 'permissions':
1026
+ return this.permissions().length === 0;
1027
+ case 'roles':
1028
+ return this.roles().length === 0;
1029
+ case 'accessibilities':
1030
+ return this.accessibilities().length === 0;
1031
+ }
1032
+ }, ...(ngDevMode ? [{ debugName: "isEmpty" }] : /* istanbul ignore next */ []));
1033
+ ngOnInit() {
1034
+ const userName = this.user()?.userName;
1035
+ if (!userName)
1036
+ return;
1037
+ this.facade.getUserSummary(userName);
1038
+ }
1039
+ lang() {
1040
+ return this.translocoService.getActiveLang();
1041
+ }
1042
+ resolveTranslated(value, lang) {
1043
+ if (!value)
1044
+ return '';
1045
+ if (typeof value === 'object') {
1046
+ const v = value;
1047
+ return v['display'] || v[lang] || v['en'] || v['ar'] || '';
1048
+ }
1049
+ if (typeof value === 'string') {
1050
+ const trimmed = value.trim();
1051
+ if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
1052
+ try {
1053
+ const parsed = JSON.parse(trimmed);
1054
+ return parsed[lang] || parsed['en'] || parsed['ar'] || '';
1055
+ }
1056
+ catch {
1057
+ return value;
1058
+ }
1059
+ }
1060
+ return value;
1061
+ }
1062
+ return '';
1063
+ }
1064
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UserLinkedGroups, deps: [], target: i0.ɵɵFactoryTarget.Component });
1065
+ 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" }] });
1066
+ }
1067
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UserLinkedGroups, decorators: [{
1068
+ type: Component,
1069
+ args: [{ selector: 'mt-user-linked-groups', standalone: true, imports: [
1070
+ CommonModule,
1071
+ TranslocoDirective,
1072
+ SkeletonModule,
1073
+ Icon,
1074
+ Tabs,
1075
+ Avatar,
1076
+ SecureImagePipe,
1077
+ ], 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" }]
929
1078
  }], propDecorators: { user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: false }] }] } });
930
1079
 
931
1080
  class Users {
@@ -974,6 +1123,14 @@ class Users {
974
1123
  ], ...(ngDevMode ? [{ debugName: "tableActions" }] : /* istanbul ignore next */ []));
975
1124
  deletingRowIds = signal([], ...(ngDevMode ? [{ debugName: "deletingRowIds" }] : /* istanbul ignore next */ []));
976
1125
  rowActions = signal([
1126
+ {
1127
+ icon: 'general.link-01',
1128
+ tooltip: this.translocoService.translate('users-groups.linked-groups'),
1129
+ color: 'secondary',
1130
+ action: (row) => {
1131
+ this.openLinkedGroupsDialog(row);
1132
+ },
1133
+ },
977
1134
  {
978
1135
  icon: 'security.key-01',
979
1136
  tooltip: this.translocoService.translate('users-groups.reset-password'),
@@ -1039,8 +1196,9 @@ class Users {
1039
1196
  },
1040
1197
  },
1041
1198
  {
1042
- key: 'lastLoginTime.displayValue',
1199
+ key: 'lastLoginTime.actualValue',
1043
1200
  label: this.translocoService.translate('users-groups.last-seen'),
1201
+ type: 'dateTime',
1044
1202
  },
1045
1203
  ], ...(ngDevMode ? [{ debugName: "tableColumns" }] : /* istanbul ignore next */ []));
1046
1204
  loading = this.facade.isLoadingUsers;
@@ -1078,12 +1236,30 @@ class Users {
1078
1236
  },
1079
1237
  });
1080
1238
  }
1239
+ openLinkedGroupsDialog(user) {
1240
+ this.modal.openModal(UserLinkedGroups, 'dialog', {
1241
+ header: this.translocoService.translate('users-groups.summary'),
1242
+ styleClass: '!w-[50rem]',
1243
+ dismissableMask: true,
1244
+ dismissible: true,
1245
+ inputValues: {
1246
+ user,
1247
+ },
1248
+ });
1249
+ }
1081
1250
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: Users, deps: [], target: i0.ɵɵFactoryTarget.Component });
1082
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.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'\">\r\n <div class=\"mt-5\">\r\n <ng-template #typeCol let-row>\r\n <div>{{ row.isExternal ? t(\"external\") : t(\"internal\") }}</div>\r\n </ng-template>\r\n <ng-template #userCol let-row>\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar [icon]=\"'custom.user-pp'\"> </mt-avatar> {{ row.displayName }}\r\n </div>\r\n </ng-template>\r\n\r\n <mt-table\r\n [tabs]=\"tabs()\"\r\n [(activeTab)]=\"activeTab\"\r\n [data]=\"users()\"\r\n [columns]=\"tableColumns()\"\r\n [actions]=\"tableActions()\"\r\n [rowActions]=\"rowActions()\"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [loading]=\"loading()\"\r\n storageKey=\"users-groups-users-table\"\r\n >\r\n </mt-table>\r\n </div>\r\n</ng-container>\r\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", "loading", "updating", "lazy", "lazyLocalSort", "lazyTotalRecords", "reorderableColumns", "reorderableRows", "dataKey", "storageKey", "storageMode", "exportable", "exportFilename", "actionShape", "tableLayout", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange"] }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }] });
1251
+ 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'\">\r\n <div class=\"mt-5\">\r\n <ng-template #typeCol let-row>\r\n @if (row.isExternal) {\r\n <span\r\n class=\"inline-flex items-center gap-1 rounded-md bg-slate-50 dark:bg-slate-900/30 p-2\"\r\n >\r\n <mt-icon\r\n icon=\"general.link-external-02\"\r\n class=\"text-slate-600 dark:text-slate-300 text-sm\"\r\n />\r\n <span class=\"text-slate-700 dark:text-slate-200 text-xs font-medium\">\r\n {{ t(\"external\") }}\r\n </span>\r\n </span>\r\n } @else {\r\n <span\r\n class=\"inline-flex items-center gap-1 rounded-md bg-emerald-50 dark:bg-emerald-900/30 p-2\"\r\n >\r\n <mt-icon\r\n icon=\"user.users-01\"\r\n class=\"text-emerald-600 dark:text-emerald-300 text-sm\"\r\n />\r\n <span\r\n class=\"text-emerald-700 dark:text-emerald-200 text-xs font-medium\"\r\n >\r\n {{ t(\"internal\") }}\r\n </span>\r\n </span>\r\n }\r\n </ng-template>\r\n <ng-template #userCol let-row>\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar [icon]=\"'custom.user-pp'\"> </mt-avatar> {{ row.displayName }}\r\n </div>\r\n </ng-template>\r\n\r\n <mt-table\r\n [tabs]=\"tabs()\"\r\n [(activeTab)]=\"activeTab\"\r\n [data]=\"users()\"\r\n [columns]=\"tableColumns()\"\r\n [actions]=\"tableActions()\"\r\n [rowActions]=\"rowActions()\"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [loading]=\"loading()\"\r\n storageKey=\"users-groups-users-table\"\r\n >\r\n </mt-table>\r\n </div>\r\n</ng-container>\r\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"] }] });
1083
1252
  }
1084
1253
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: Users, decorators: [{
1085
1254
  type: Component,
1086
- args: [{ selector: 'mt-users', standalone: true, imports: [CommonModule, SkeletonModule, Table, Avatar, TranslocoDirective], template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div class=\"mt-5\">\r\n <ng-template #typeCol let-row>\r\n <div>{{ row.isExternal ? t(\"external\") : t(\"internal\") }}</div>\r\n </ng-template>\r\n <ng-template #userCol let-row>\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar [icon]=\"'custom.user-pp'\"> </mt-avatar> {{ row.displayName }}\r\n </div>\r\n </ng-template>\r\n\r\n <mt-table\r\n [tabs]=\"tabs()\"\r\n [(activeTab)]=\"activeTab\"\r\n [data]=\"users()\"\r\n [columns]=\"tableColumns()\"\r\n [actions]=\"tableActions()\"\r\n [rowActions]=\"rowActions()\"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [loading]=\"loading()\"\r\n storageKey=\"users-groups-users-table\"\r\n >\r\n </mt-table>\r\n </div>\r\n</ng-container>\r\n" }]
1255
+ args: [{ selector: 'mt-users', standalone: true, imports: [
1256
+ CommonModule,
1257
+ SkeletonModule,
1258
+ Table,
1259
+ Avatar,
1260
+ Icon,
1261
+ TranslocoDirective,
1262
+ ], template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div class=\"mt-5\">\r\n <ng-template #typeCol let-row>\r\n @if (row.isExternal) {\r\n <span\r\n class=\"inline-flex items-center gap-1 rounded-md bg-slate-50 dark:bg-slate-900/30 p-2\"\r\n >\r\n <mt-icon\r\n icon=\"general.link-external-02\"\r\n class=\"text-slate-600 dark:text-slate-300 text-sm\"\r\n />\r\n <span class=\"text-slate-700 dark:text-slate-200 text-xs font-medium\">\r\n {{ t(\"external\") }}\r\n </span>\r\n </span>\r\n } @else {\r\n <span\r\n class=\"inline-flex items-center gap-1 rounded-md bg-emerald-50 dark:bg-emerald-900/30 p-2\"\r\n >\r\n <mt-icon\r\n icon=\"user.users-01\"\r\n class=\"text-emerald-600 dark:text-emerald-300 text-sm\"\r\n />\r\n <span\r\n class=\"text-emerald-700 dark:text-emerald-200 text-xs font-medium\"\r\n >\r\n {{ t(\"internal\") }}\r\n </span>\r\n </span>\r\n }\r\n </ng-template>\r\n <ng-template #userCol let-row>\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar [icon]=\"'custom.user-pp'\"> </mt-avatar> {{ row.displayName }}\r\n </div>\r\n </ng-template>\r\n\r\n <mt-table\r\n [tabs]=\"tabs()\"\r\n [(activeTab)]=\"activeTab\"\r\n [data]=\"users()\"\r\n [columns]=\"tableColumns()\"\r\n [actions]=\"tableActions()\"\r\n [rowActions]=\"rowActions()\"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [loading]=\"loading()\"\r\n storageKey=\"users-groups-users-table\"\r\n >\r\n </mt-table>\r\n </div>\r\n</ng-container>\r\n" }]
1087
1263
  }], propDecorators: { typeCol: [{ type: i0.ViewChild, args: ['typeCol', { isSignal: true }] }], userCol: [{ type: i0.ViewChild, args: ['userCol', { isSignal: true }] }] } });
1088
1264
 
1089
1265
  class GroupForm {
@@ -1205,7 +1381,7 @@ class GroupForm {
1205
1381
  });
1206
1382
  }
1207
1383
  this.internalUserFormControl.valueChanges.subscribe((value) => {
1208
- const isUserExistInMembers = this.selectedGroup()?.members?.find((member) => member?.user?.id === value?.userField?.id);
1384
+ const isUserExistInMembers = !!this.selectedGroup()?.members?.find((member) => member?.id === value?.userField?.id);
1209
1385
  this.isUserExistInMembers.set(isUserExistInMembers);
1210
1386
  });
1211
1387
  }
@@ -1248,7 +1424,7 @@ class GroupForm {
1248
1424
  }
1249
1425
  }
1250
1426
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: GroupForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
1251
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: GroupForm, isStandalone: true, selector: "mt-group-form", inputs: { groupForEdit: { classPropertyName: "groupForEdit", publicName: "groupForEdit", isSignal: true, isRequired: false, transformFunction: null } }, providers: [DialogService], viewQueries: [{ propertyName: "userCol", first: true, predicate: ["userCol"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div [class]=\"'flex flex-col gap-1 p-4 ' + modal.contentClass\">\r\n @if (!getGroupFormLoading()) {\r\n <form class=\"col-span-1\">\r\n <mt-dynamic-form\r\n [formConfig]=\"groupFormConfig()\"\r\n [formControl]=\"groupFormControl\"\r\n />\r\n </form>\r\n\r\n @if (groupForEdit()) {\r\n <div class=\"flex gap-3 items-end mt-6 pt-4 border-t-1 border-surface\">\r\n <mt-dynamic-form\r\n class=\"flex-1\"\r\n [formConfig]=\"internalUserFormConfig()\"\r\n [formControl]=\"internalUserFormControl\"\r\n />\r\n <mt-button\r\n icon=\"general.plus\"\r\n class=\"mb-0\"\r\n variant=\"outlined\"\r\n (click)=\"onAddUser()\"\r\n [disabled]=\"\r\n addUserToGroupLoading() ||\r\n isUserExistInMembers() ||\r\n !internalUserFormControl.value?.userField\r\n \"\r\n />\r\n </div>\r\n\r\n <mt-table\r\n [data]=\"selectedGroup()?.members || []\"\r\n [columns]=\"tableColumns()\"\r\n [rowActions]=\"rowActions()\"\r\n storageKey=\"users-groups-group-members-table\"\r\n [generalSearch]=\"false\"\r\n [showFilters]=\"false\"\r\n [loading]=\"addUserToGroupLoading()\"\r\n >\r\n </mt-table>\r\n <ng-template #userCol let-row>\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar [icon]=\"'custom.user-pp'\"> </mt-avatar>\r\n {{ row?.displayName }}\r\n </div>\r\n </ng-template>\r\n }\r\n } @else {\r\n <p-skeleton class=\"my-4 mt-7\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n }\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n [label]=\"selectedGroup() ? ('save' | transloco) : ('add' | transloco)\"\r\n (click)=\"onSubmit()\"\r\n [loading]=\"createUpdateGroupLoading()\"\r\n [disabled]=\"!this.groupFormControl.valid\"\r\n />\r\n </div>\r\n</ng-container>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { 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: DynamicForm, selector: "mt-dynamic-form", inputs: ["formConfig", "forcedHiddenFieldKeys", "preserveForcedHiddenValues", "visibleSectionKeys"], outputs: ["runtimeMessagesChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "component", type: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "lazyLocalSearch", "showFilters", "loading", "updating", "lazy", "lazyLocalSort", "lazyTotalRecords", "reorderableColumns", "reorderableRows", "dataKey", "storageKey", "storageMode", "exportable", "exportFilename", "actionShape", "tableLayout", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
1427
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: GroupForm, isStandalone: true, selector: "mt-group-form", inputs: { groupForEdit: { classPropertyName: "groupForEdit", publicName: "groupForEdit", isSignal: true, isRequired: false, transformFunction: null } }, providers: [DialogService], viewQueries: [{ propertyName: "userCol", first: true, predicate: ["userCol"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div [class]=\"'flex flex-col gap-1 p-4 ' + modal.contentClass\">\r\n @if (!getGroupFormLoading()) {\r\n <form class=\"col-span-1\">\r\n <mt-dynamic-form\r\n [formConfig]=\"groupFormConfig()\"\r\n [formControl]=\"groupFormControl\"\r\n />\r\n </form>\r\n\r\n @if (groupForEdit()) {\r\n <div class=\"flex gap-3 items-end mt-6 pt-4 border-t-1 border-surface\">\r\n <mt-dynamic-form\r\n class=\"flex-1\"\r\n [formConfig]=\"internalUserFormConfig()\"\r\n [formControl]=\"internalUserFormControl\"\r\n />\r\n <mt-button\r\n icon=\"general.plus\"\r\n class=\"mb-0\"\r\n variant=\"outlined\"\r\n (click)=\"onAddUser()\"\r\n [disabled]=\"\r\n addUserToGroupLoading() ||\r\n isUserExistInMembers() ||\r\n !internalUserFormControl.value?.userField\r\n \"\r\n />\r\n </div>\r\n\r\n <mt-table\r\n noCard\r\n [data]=\"selectedGroup()?.members || []\"\r\n [columns]=\"tableColumns()\"\r\n [rowActions]=\"rowActions()\"\r\n storageKey=\"users-groups-group-members-table\"\r\n [generalSearch]=\"false\"\r\n [showFilters]=\"false\"\r\n [loading]=\"addUserToGroupLoading()\"\r\n >\r\n </mt-table>\r\n <ng-template #userCol let-row>\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar [icon]=\"'custom.user-pp'\"> </mt-avatar>\r\n {{ row?.displayName }}\r\n </div>\r\n </ng-template>\r\n }\r\n } @else {\r\n <p-skeleton class=\"my-4 mt-7\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n }\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n variant=\"outlined\"\r\n [disabled]=\"createUpdateGroupLoading()\"\r\n (click)=\"ref.close(false)\"\r\n />\r\n <mt-button\r\n [label]=\"selectedGroup() ? ('save' | transloco) : ('add' | transloco)\"\r\n (click)=\"onSubmit()\"\r\n [loading]=\"createUpdateGroupLoading()\"\r\n [disabled]=\"!this.groupFormControl.valid\"\r\n />\r\n </div>\r\n</ng-container>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { 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: DynamicForm, selector: "mt-dynamic-form", inputs: ["formConfig", "forcedHiddenFieldKeys", "preserveForcedHiddenValues", "visibleSectionKeys"], outputs: ["runtimeMessagesChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { 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: "pipe", type: TranslocoPipe, name: "transloco" }] });
1252
1428
  }
1253
1429
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: GroupForm, decorators: [{
1254
1430
  type: Component,
@@ -1262,7 +1438,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
1262
1438
  TranslocoPipe,
1263
1439
  Avatar,
1264
1440
  Table,
1265
- ], providers: [DialogService], template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div [class]=\"'flex flex-col gap-1 p-4 ' + modal.contentClass\">\r\n @if (!getGroupFormLoading()) {\r\n <form class=\"col-span-1\">\r\n <mt-dynamic-form\r\n [formConfig]=\"groupFormConfig()\"\r\n [formControl]=\"groupFormControl\"\r\n />\r\n </form>\r\n\r\n @if (groupForEdit()) {\r\n <div class=\"flex gap-3 items-end mt-6 pt-4 border-t-1 border-surface\">\r\n <mt-dynamic-form\r\n class=\"flex-1\"\r\n [formConfig]=\"internalUserFormConfig()\"\r\n [formControl]=\"internalUserFormControl\"\r\n />\r\n <mt-button\r\n icon=\"general.plus\"\r\n class=\"mb-0\"\r\n variant=\"outlined\"\r\n (click)=\"onAddUser()\"\r\n [disabled]=\"\r\n addUserToGroupLoading() ||\r\n isUserExistInMembers() ||\r\n !internalUserFormControl.value?.userField\r\n \"\r\n />\r\n </div>\r\n\r\n <mt-table\r\n [data]=\"selectedGroup()?.members || []\"\r\n [columns]=\"tableColumns()\"\r\n [rowActions]=\"rowActions()\"\r\n storageKey=\"users-groups-group-members-table\"\r\n [generalSearch]=\"false\"\r\n [showFilters]=\"false\"\r\n [loading]=\"addUserToGroupLoading()\"\r\n >\r\n </mt-table>\r\n <ng-template #userCol let-row>\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar [icon]=\"'custom.user-pp'\"> </mt-avatar>\r\n {{ row?.displayName }}\r\n </div>\r\n </ng-template>\r\n }\r\n } @else {\r\n <p-skeleton class=\"my-4 mt-7\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n }\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n [label]=\"selectedGroup() ? ('save' | transloco) : ('add' | transloco)\"\r\n (click)=\"onSubmit()\"\r\n [loading]=\"createUpdateGroupLoading()\"\r\n [disabled]=\"!this.groupFormControl.valid\"\r\n />\r\n </div>\r\n</ng-container>\r\n" }]
1441
+ ], providers: [DialogService], template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div [class]=\"'flex flex-col gap-1 p-4 ' + modal.contentClass\">\r\n @if (!getGroupFormLoading()) {\r\n <form class=\"col-span-1\">\r\n <mt-dynamic-form\r\n [formConfig]=\"groupFormConfig()\"\r\n [formControl]=\"groupFormControl\"\r\n />\r\n </form>\r\n\r\n @if (groupForEdit()) {\r\n <div class=\"flex gap-3 items-end mt-6 pt-4 border-t-1 border-surface\">\r\n <mt-dynamic-form\r\n class=\"flex-1\"\r\n [formConfig]=\"internalUserFormConfig()\"\r\n [formControl]=\"internalUserFormControl\"\r\n />\r\n <mt-button\r\n icon=\"general.plus\"\r\n class=\"mb-0\"\r\n variant=\"outlined\"\r\n (click)=\"onAddUser()\"\r\n [disabled]=\"\r\n addUserToGroupLoading() ||\r\n isUserExistInMembers() ||\r\n !internalUserFormControl.value?.userField\r\n \"\r\n />\r\n </div>\r\n\r\n <mt-table\r\n noCard\r\n [data]=\"selectedGroup()?.members || []\"\r\n [columns]=\"tableColumns()\"\r\n [rowActions]=\"rowActions()\"\r\n storageKey=\"users-groups-group-members-table\"\r\n [generalSearch]=\"false\"\r\n [showFilters]=\"false\"\r\n [loading]=\"addUserToGroupLoading()\"\r\n >\r\n </mt-table>\r\n <ng-template #userCol let-row>\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar [icon]=\"'custom.user-pp'\"> </mt-avatar>\r\n {{ row?.displayName }}\r\n </div>\r\n </ng-template>\r\n }\r\n } @else {\r\n <p-skeleton class=\"my-4 mt-7\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n <p-skeleton class=\"my-4\" height=\"3rem\" />\r\n }\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n variant=\"outlined\"\r\n [disabled]=\"createUpdateGroupLoading()\"\r\n (click)=\"ref.close(false)\"\r\n />\r\n <mt-button\r\n [label]=\"selectedGroup() ? ('save' | transloco) : ('add' | transloco)\"\r\n (click)=\"onSubmit()\"\r\n [loading]=\"createUpdateGroupLoading()\"\r\n [disabled]=\"!this.groupFormControl.valid\"\r\n />\r\n </div>\r\n</ng-container>\r\n" }]
1266
1442
  }], ctorParameters: () => [], propDecorators: { groupForEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupForEdit", required: false }] }], userCol: [{ type: i0.ViewChild, args: ['userCol', { isSignal: true }] }] } });
1267
1443
 
1268
1444
  class Groups {
@@ -1352,7 +1528,7 @@ class Groups {
1352
1528
  });
1353
1529
  }
1354
1530
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: Groups, deps: [], target: i0.ɵɵFactoryTarget.Component });
1355
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.8", type: Groups, isStandalone: true, selector: "mt-groups", viewQueries: [{ propertyName: "workspaceCol", first: true, predicate: ["workspaceCol"], descendants: true, isSignal: true }, { propertyName: "groupCol", first: true, predicate: ["groupCol"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div class=\"mt-5\">\r\n <ng-template #workspaceCol let-row>\r\n <div>{{ row.workspace }}</div>\r\n </ng-template>\r\n <ng-template #groupCol let-row>\r\n <div class=\"flex items-center gap-2\">\r\n {{ row.name?.display }}\r\n </div>\r\n </ng-template>\r\n\r\n <mt-table\r\n [(activeTab)]=\"activeTab\"\r\n [data]=\"allGroups()\"\r\n [columns]=\"tableColumns()\"\r\n [actions]=\"tableActions()\"\r\n [rowActions]=\"rowActions()\"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [loading]=\"loading()\"\r\n storageKey=\"users-groups-groups-table\"\r\n >\r\n </mt-table>\r\n </div>\r\n</ng-container>\r\n", styles: [".groups{padding:2rem}\n"], 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", "loading", "updating", "lazy", "lazyLocalSort", "lazyTotalRecords", "reorderableColumns", "reorderableRows", "dataKey", "storageKey", "storageMode", "exportable", "exportFilename", "actionShape", "tableLayout", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }] });
1531
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.8", type: Groups, isStandalone: true, selector: "mt-groups", viewQueries: [{ propertyName: "workspaceCol", first: true, predicate: ["workspaceCol"], descendants: true, isSignal: true }, { propertyName: "groupCol", first: true, predicate: ["groupCol"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'users-groups'\">\r\n <div class=\"mt-5\">\r\n <ng-template #workspaceCol let-row>\r\n <div>{{ row.workspace }}</div>\r\n </ng-template>\r\n <ng-template #groupCol let-row>\r\n <div class=\"flex items-center gap-2\">\r\n {{ row.name?.display }}\r\n </div>\r\n </ng-template>\r\n\r\n <mt-table\r\n [(activeTab)]=\"activeTab\"\r\n [data]=\"allGroups()\"\r\n [columns]=\"tableColumns()\"\r\n [actions]=\"tableActions()\"\r\n [rowActions]=\"rowActions()\"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [loading]=\"loading()\"\r\n storageKey=\"users-groups-groups-table\"\r\n >\r\n </mt-table>\r\n </div>\r\n</ng-container>\r\n", styles: [".groups{padding:2rem}\n"], 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }] });
1356
1532
  }
1357
1533
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: Groups, decorators: [{
1358
1534
  type: Component,
@@ -1365,5 +1541,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
1365
1541
  * Generated bundle index. Do not edit.
1366
1542
  */
1367
1543
 
1368
- export { AddUserToGroup, ClearSelectedGroup, CreateGroup, CreateUser, DeleteGroup, DeleteUser, DeleteUserFromGroup, GetGroup, GetGroups, GetUser, GetUsers, GroupForm, Groups, ResetUserPassword, UpdateGroup, UpdateUser, UserForm, Users, UsersGroups, UsersGroupsActionKey, UsersGroupsFacade, UsersGroupsState };
1544
+ export { AddUserToGroup, ClearSelectedGroup, CreateGroup, CreateUser, DeleteGroup, DeleteUser, DeleteUserFromGroup, GetGroup, GetGroups, GetUser, GetUserSummary, GetUsers, GroupForm, Groups, ResetUserPassword, UpdateGroup, UpdateUser, UserForm, Users, UsersGroups, UsersGroupsActionKey, UsersGroupsFacade, UsersGroupsState };
1369
1545
  //# sourceMappingURL=masterteam-users-groups.mjs.map