@memberjunction/ng-explorer-settings 6.1.0-edge.4 → 6.1.0-edge.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/application-management/application-dialog/application-dialog.component.js +2 -2
- package/dist/lib/application-management/application-dialog/application-dialog.component.js.map +1 -1
- package/dist/lib/application-management/application-management.component.js +4 -4
- package/dist/lib/application-management/application-management.component.js.map +1 -1
- package/dist/lib/entity-permissions/entity-permissions.component.js +3 -3
- package/dist/lib/entity-permissions/entity-permissions.component.js.map +1 -1
- package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.js +1 -1
- package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.js.map +1 -1
- package/dist/lib/notification-preferences/notification-preferences.component.js +1 -1
- package/dist/lib/role-management/role-dialog/role-dialog.component.js +1 -1
- package/dist/lib/role-management/role-dialog/role-dialog.component.js.map +1 -1
- package/dist/lib/role-management/role-management.component.js +4 -4
- package/dist/lib/role-management/role-management.component.js.map +1 -1
- package/dist/lib/settings/settings.component.js +1 -1
- package/dist/lib/shared/settings-card.component.js +1 -1
- package/dist/lib/sql-logging/sql-logging.component.js +3 -3
- package/dist/lib/sql-logging/sql-logging.component.js.map +1 -1
- package/dist/lib/user-app-config/user-app-config-content.component.js +1 -1
- package/dist/lib/user-app-config/user-app-config.component.js +1 -1
- package/dist/lib/user-management/user-dialog/user-dialog.component.d.ts +2 -0
- package/dist/lib/user-management/user-dialog/user-dialog.component.d.ts.map +1 -1
- package/dist/lib/user-management/user-dialog/user-dialog.component.js +25 -4
- package/dist/lib/user-management/user-dialog/user-dialog.component.js.map +1 -1
- package/dist/lib/user-management/user-management.component.d.ts +5 -0
- package/dist/lib/user-management/user-management.component.d.ts.map +1 -1
- package/dist/lib/user-management/user-management.component.js +61 -9
- package/dist/lib/user-management/user-management.component.js.map +1 -1
- package/dist/lib/user-profile-settings/user-profile-settings.component.js +1 -1
- package/package.json +26 -26
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-dialog.component.js","sourceRoot":"","sources":["../../../../src/lib/user-management/user-dialog/user-dialog.component.ts","../../../../src/lib/user-management/user-dialog/user-dialog.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, OnChanges, SimpleChanges, inject, HostListener, ViewEncapsulation, ChangeDetectorRef, NgZone } from '@angular/core';\n\nimport { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';\nimport { Metadata, RunView } from '@memberjunction/core';\nimport { MJUserEntity, MJRoleEntity, MJUserRoleEntity } from '@memberjunction/core-entities';\n\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nexport interface UserDialogData {\n user?: MJUserEntity;\n mode: 'create' | 'edit';\n availableRoles: MJRoleEntity[];\n}\n\nexport interface UserDialogResult {\n action: 'save' | 'cancel';\n user?: MJUserEntity;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-user-dialog',\n encapsulation: ViewEncapsulation.None,\n templateUrl: './user-dialog.component.html',\n styleUrls: ['./user-dialog.component.css']\n})\nexport class UserDialogComponent extends BaseAngularComponent implements OnInit, OnDestroy, OnChanges {\n @Input() data: UserDialogData | null = null;\n @Input() visible = false;\n @Output() result = new EventEmitter<UserDialogResult>();\n\n private fb = inject(FormBuilder);\n private cdr = inject(ChangeDetectorRef);\n private ngZone = inject(NgZone);\n private get metadata() { return this.ProviderToUse; }\n public userForm: FormGroup;\n public isLoading = false;\n public error: string | null = null;\n public selectedRoleIds = new Set<string>();\n public existingUserRoles: MJUserRoleEntity[] = [];\n\n constructor() {\n super();\n this.userForm = this.fb.group({\n name: ['', [Validators.required, Validators.email]],\n firstName: [''],\n lastName: [''],\n email: ['', [Validators.required, Validators.email]],\n title: [''],\n type: ['User', Validators.required],\n isActive: [true]\n });\n }\n\n ngOnInit(): void {\n // Initial setup\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n // Always clear state when data changes to prevent persistence bugs\n if (changes['data']) {\n this.selectedRoleIds.clear();\n this.existingUserRoles = [];\n \n if (this.data?.user && this.isEditMode) {\n this.loadUserData();\n } else {\n this.resetForm();\n }\n }\n \n // Reset form when dialog becomes visible and not in edit mode\n if (changes['visible'] && this.visible && !this.isEditMode) {\n this.resetForm();\n }\n }\n\n ngOnDestroy(): void {\n // Cleanup if needed\n }\n\n private resetForm(): void {\n this.userForm.reset({\n name: '',\n firstName: '',\n lastName: '',\n email: '',\n title: '',\n type: 'User',\n isActive: true\n });\n this.selectedRoleIds.clear();\n this.error = null;\n }\n\n @HostListener('document:keydown.escape', ['$event'])\n onEscapeKey(event: Event): void {\n if (this.visible) {\n this.onCancel();\n }\n }\n\n public get windowTitle(): string {\n return this.isEditMode ? 'Edit User' : 'Create New User';\n }\n\n public get isEditMode(): boolean {\n return this.data?.mode === 'edit';\n }\n\n private async loadUserData(): Promise<void> {\n if (!this.data?.user) return;\n\n const user = this.data.user;\n this.userForm.patchValue({\n name: user.Name,\n firstName: user.FirstName,\n lastName: user.LastName,\n email: user.Email,\n title: user.Title,\n type: user.Type,\n isActive: user.IsActive\n });\n\n // Load existing user roles\n await this.loadExistingUserRoles(user.ID);\n }\n\n private async loadExistingUserRoles(userId: string): Promise<void> {\n try {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const result = await rv.RunView<MJUserRoleEntity>({\n EntityName: 'MJ: User Roles',\n ExtraFilter: `UserID='${userId}'`,\n ResultType: 'entity_object'\n });\n\n if (result.Success && result.Results) {\n this.existingUserRoles = result.Results;\n // Pre-select existing roles\n for (const userRole of this.existingUserRoles) {\n this.selectedRoleIds.add(userRole.RoleID);\n }\n }\n } catch (error) {\n console.warn('Failed to load existing user roles:', error);\n }\n }\n\n public onRoleToggle(roleId: string, event: Event): void {\n event.stopPropagation();\n const checkbox = event.target as HTMLInputElement;\n if (checkbox.checked) {\n this.selectedRoleIds.add(roleId);\n } else {\n this.selectedRoleIds.delete(roleId);\n }\n }\n\n public toggleRole(roleId: string): void {\n if (this.selectedRoleIds.has(roleId)) {\n this.selectedRoleIds.delete(roleId);\n } else {\n this.selectedRoleIds.add(roleId);\n }\n }\n\n public async onSubmit(): Promise<void> {\n if (this.userForm.invalid) {\n this.markFormGroupTouched(this.userForm);\n return;\n }\n\n this.isLoading = true;\n this.error = null;\n\n try {\n let user: MJUserEntity;\n\n if (this.isEditMode && this.data?.user) {\n // Edit existing user\n user = this.data.user;\n } else {\n // Create new user\n user = await this.metadata.GetEntityObject<MJUserEntity>('MJ: Users');\n user.NewRecord();\n }\n\n // Update user properties\n const formValue = this.userForm.value;\n user.Name = formValue.name;\n user.FirstName = formValue.firstName;\n user.LastName = formValue.lastName;\n user.Email = formValue.email;\n user.Title = formValue.title;\n user.Type = formValue.type;\n user.IsActive = formValue.isActive;\n\n // Save user\n const saveResult = await user.Save();\n if (!saveResult) {\n throw new Error(user.LatestResult?.Message || 'Failed to save user');\n }\n\n // Handle role assignments\n await this.updateUserRoles(user.ID);\n\n this.result.emit({ action: 'save', user });\n\n } catch (error: unknown) {\n console.error('Error saving user:', error);\n this.ngZone.run(() => {\n this.error = error instanceof Error ? error.message : 'An unexpected error occurred';\n this.cdr.markForCheck();\n });\n } finally {\n this.ngZone.run(() => {\n this.isLoading = false;\n this.cdr.markForCheck();\n });\n }\n }\n\n private async updateUserRoles(userId: string): Promise<void> {\n try {\n // Get current role IDs from existing UserRole entities\n const existingRoleIds = new Set(this.existingUserRoles.map(ur => ur.RoleID));\n\n // Determine roles to add and remove\n const rolesToAdd = Array.from(this.selectedRoleIds).filter(roleId => !existingRoleIds.has(roleId));\n const rolesToRemove = this.existingUserRoles.filter(userRole => !this.selectedRoleIds.has(userRole.RoleID));\n\n if (rolesToAdd.length === 0 && rolesToRemove.length === 0) {\n return;\n }\n\n // Batch all role deletes and adds into one transactional GraphQL call\n const tg = await this.metadata.CreateTransactionGroup();\n\n for (const userRole of rolesToRemove) {\n userRole.TransactionGroup = tg;\n await userRole.Delete();\n }\n\n for (const roleId of rolesToAdd) {\n const userRole = await this.metadata.GetEntityObject<MJUserRoleEntity>('MJ: User Roles');\n userRole.NewRecord();\n userRole.UserID = userId;\n userRole.RoleID = roleId;\n userRole.TransactionGroup = tg;\n await userRole.Save();\n }\n\n if (!await tg.Submit()) {\n throw new Error('Failed to update user roles — all changes have been rolled back');\n }\n } catch (error) {\n console.error('Error updating user roles:', error);\n throw error;\n }\n }\n\n public onCancel(): void {\n this.result.emit({ action: 'cancel' });\n }\n\n private markFormGroupTouched(formGroup: FormGroup): void {\n Object.keys(formGroup.controls).forEach(key => {\n const control = formGroup.get(key);\n control?.markAsTouched();\n });\n }\n}","<!-- MD3 Modal Dialog -->\n@if (visible) {\n <div class=\"modal-backdrop\" (click)=\"onCancel()\">\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <!-- Modal Header with MJ Blue -->\n <div class=\"modal-header\">\n <div class=\"dialog-header\">\n <h2 class=\"dialog-title\">\n <i class=\"fa-solid fa-user\"></i>\n {{ isEditMode ? 'Edit User' : 'Create New User' }}\n </h2>\n <p class=\"dialog-subtitle\">\n {{ isEditMode ? 'Update user information and role assignments' : 'Add a new user to the system' }}\n </p>\n </div>\n <button type=\"button\" class=\"modal-close\" (click)=\"onCancel()\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <form [formGroup]=\"userForm\" (ngSubmit)=\"onSubmit()\">\n @if (error) {\n <div class=\"content-section\">\n <mj-alert Variant=\"error\" [Message]=\"error\" />\n </div>\n }\n <!-- Basic Information Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-id-card\"></i>\n Basic Information\n </h3>\n <p class=\"section-description\">Enter the user's personal and contact details</p>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-field\">\n <label class=\"field-label required\" for=\"name\">Username/Email</label>\n <input\n id=\"name\"\n type=\"email\"\n class=\"field-input\"\n formControlName=\"name\"\n placeholder=\"john@company.com\"\n [class.error]=\"userForm.get('name')?.invalid && userForm.get('name')?.touched\"\n />\n @if (userForm.get('name')?.invalid && userForm.get('name')?.touched) {\n <div class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n @if (userForm.get('name')?.errors?.['required']) {\n Username/Email is required\n }\n @if (userForm.get('name')?.errors?.['email']) {\n Please enter a valid email address\n }\n </div>\n }\n </div>\n <div class=\"form-row\">\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"firstName\">First Name</label>\n <input\n id=\"firstName\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"firstName\"\n placeholder=\"John\"\n />\n </div>\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"lastName\">Last Name</label>\n <input\n id=\"lastName\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"lastName\"\n placeholder=\"Doe\"\n />\n </div>\n </div>\n <div class=\"form-field\">\n <label class=\"field-label required\" for=\"email\">Email Address</label>\n <input\n id=\"email\"\n type=\"email\"\n class=\"field-input\"\n formControlName=\"email\"\n placeholder=\"john@company.com\"\n [class.error]=\"userForm.get('email')?.invalid && userForm.get('email')?.touched\"\n />\n @if (userForm.get('email')?.invalid && userForm.get('email')?.touched) {\n <div class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n @if (userForm.get('email')?.errors?.['required']) {\n Email address is required\n }\n @if (userForm.get('email')?.errors?.['email']) {\n Please enter a valid email address\n }\n </div>\n }\n </div>\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"title\">Job Title</label>\n <input\n id=\"title\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"title\"\n placeholder=\"Software Engineer\"\n />\n </div>\n </div>\n </div>\n </div>\n <!-- User Settings Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-cog\"></i>\n User Settings\n </h3>\n <p class=\"section-description\">Configure user type and account status</p>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"type\">User Type</label>\n <select id=\"type\" class=\"field-select\" formControlName=\"type\">\n <option value=\"User\">Standard User</option>\n <option value=\"Owner\">System Owner</option>\n </select>\n </div>\n <div class=\"form-field\">\n <div class=\"checkbox-field\">\n <input\n id=\"isActive\"\n type=\"checkbox\"\n class=\"checkbox-input\"\n formControlName=\"isActive\"\n />\n <label class=\"checkbox-label\" for=\"isActive\">\n <div class=\"checkbox-indicator\"></div>\n <div>\n <strong>Active Account</strong>\n <div style=\"font-size: 12px; color: var(--md-on-surface-variant); margin-top: 2px;\">\n User can log in and access the system\n </div>\n </div>\n </label>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <!-- Role Assignment Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-user-tag\"></i>\n Role Assignment\n </h3>\n <p class=\"section-description\">Select the roles to assign to this user</p>\n </div>\n <div class=\"roles-grid\">\n @for (role of data?.availableRoles; track role.ID) {\n <div class=\"role-card\"\n [class.selected]=\"selectedRoleIds.has(role.ID)\"\n (click)=\"toggleRole(role.ID)\">\n <div class=\"role-content\">\n <div class=\"checkbox-field\">\n <input\n type=\"checkbox\"\n class=\"checkbox-input\"\n [id]=\"'role-' + role.ID\"\n [checked]=\"selectedRoleIds.has(role.ID)\"\n (change)=\"onRoleToggle(role.ID, $event)\"\n />\n <label class=\"checkbox-label\" [for]=\"'role-' + role.ID\">\n <div class=\"checkbox-indicator\"></div>\n </label>\n </div>\n <div class=\"role-info\">\n <h4 class=\"role-name\">{{ role.Name }}</h4>\n @if (role.Description) {\n <p class=\"role-description\">{{ role.Description }}</p>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Modal Footer -->\n <div class=\"modal-footer\">\n <button\n type=\"submit\"\n class=\"btn btn-primary\"\n [disabled]=\"userForm.invalid || isLoading\"\n >\n @if (isLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Saving...\n } @else {\n <i class=\"fa-solid fa-save\"></i>\n {{ isEditMode ? 'Update User' : 'Create User' }}\n }\n </button>\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"onCancel()\">\n <i class=\"fa-solid fa-times\"></i>\n Cancel\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n}\n"]}
|
|
1
|
+
{"version":3,"file":"user-dialog.component.js","sourceRoot":"","sources":["../../../../src/lib/user-management/user-dialog/user-dialog.component.ts","../../../../src/lib/user-management/user-dialog/user-dialog.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, OnChanges, SimpleChanges, inject, HostListener, ViewEncapsulation, ChangeDetectorRef, NgZone } from '@angular/core';\n\nimport { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';\nimport { Metadata, RunView } from '@memberjunction/core';\nimport { MJUserEntity, MJRoleEntity, MJUserRoleEntity } from '@memberjunction/core-entities';\n\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nexport interface UserDialogData {\n user?: MJUserEntity;\n mode: 'create' | 'edit';\n availableRoles: MJRoleEntity[];\n}\n\nexport interface UserDialogResult {\n action: 'save' | 'cancel';\n user?: MJUserEntity;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-user-dialog',\n encapsulation: ViewEncapsulation.None,\n templateUrl: './user-dialog.component.html',\n styleUrls: ['./user-dialog.component.css']\n})\nexport class UserDialogComponent extends BaseAngularComponent implements OnInit, OnDestroy, OnChanges {\n @Input() data: UserDialogData | null = null;\n @Input() visible = false;\n @Output() result = new EventEmitter<UserDialogResult>();\n\n private fb = inject(FormBuilder);\n private cdr = inject(ChangeDetectorRef);\n private ngZone = inject(NgZone);\n private get metadata() { return this.ProviderToUse; }\n public userForm: FormGroup;\n public isLoading = false;\n public error: string | null = null;\n public selectedRoleIds = new Set<string>();\n public existingUserRoles: MJUserRoleEntity[] = [];\n\n constructor() {\n super();\n this.userForm = this.fb.group({\n name: ['', [Validators.required, Validators.email]],\n firstName: [''],\n lastName: [''],\n email: ['', [Validators.required, Validators.email]],\n title: [''],\n type: ['User', Validators.required],\n isActive: [true]\n });\n }\n\n ngOnInit(): void {\n // Initial setup\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n // Always clear state when data changes to prevent persistence bugs\n if (changes['data']) {\n this.selectedRoleIds.clear();\n this.existingUserRoles = [];\n \n if (this.data?.user && this.isEditMode) {\n this.loadUserData();\n } else {\n this.resetForm();\n }\n }\n \n // Reset form when dialog becomes visible and not in edit mode\n if (changes['visible'] && this.visible && !this.isEditMode) {\n this.resetForm();\n }\n }\n\n ngOnDestroy(): void {\n // Cleanup if needed\n }\n\n private resetForm(): void {\n this.userForm.reset({\n name: '',\n firstName: '',\n lastName: '',\n email: '',\n title: '',\n type: 'User',\n isActive: true\n });\n this.selectedRoleIds.clear();\n this.error = null;\n }\n\n @HostListener('document:keydown.escape', ['$event'])\n onEscapeKey(event: Event): void {\n if (this.visible) {\n this.onCancel();\n }\n }\n\n public get windowTitle(): string {\n return this.isEditMode ? 'Edit User' : 'Create New User';\n }\n\n public get isEditMode(): boolean {\n return this.data?.mode === 'edit';\n }\n\n private async loadUserData(): Promise<void> {\n if (!this.data?.user) return;\n\n const user = this.data.user;\n this.userForm.patchValue({\n name: user.Name,\n firstName: user.FirstName,\n lastName: user.LastName,\n email: user.Email,\n title: user.Title,\n type: user.Type,\n isActive: user.IsActive\n });\n\n // Load existing user roles\n await this.loadExistingUserRoles(user.ID);\n }\n\n private async loadExistingUserRoles(userId: string): Promise<void> {\n try {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const result = await rv.RunView<MJUserRoleEntity>({\n EntityName: 'MJ: User Roles',\n ExtraFilter: `UserID='${userId}'`,\n ResultType: 'entity_object'\n });\n\n if (result.Success && result.Results) {\n this.existingUserRoles = result.Results;\n // Pre-select existing roles\n for (const userRole of this.existingUserRoles) {\n this.selectedRoleIds.add(userRole.RoleID);\n }\n }\n } catch (error) {\n console.warn('Failed to load existing user roles:', error);\n }\n }\n\n public onRoleToggle(roleId: string, event: Event): void {\n event.stopPropagation();\n const checkbox = event.target as HTMLInputElement;\n if (checkbox.checked) {\n this.selectedRoleIds.add(roleId);\n } else {\n this.selectedRoleIds.delete(roleId);\n }\n }\n\n public toggleRole(roleId: string): void {\n if (this.selectedRoleIds.has(roleId)) {\n this.selectedRoleIds.delete(roleId);\n } else {\n this.selectedRoleIds.add(roleId);\n }\n }\n\n public async onSubmit(): Promise<void> {\n if (this.userForm.invalid) {\n this.markFormGroupTouched(this.userForm);\n return;\n }\n\n this.isLoading = true;\n this.error = null;\n\n try {\n let user: MJUserEntity;\n\n if (this.isEditMode && this.data?.user) {\n // Edit existing user\n user = this.data.user;\n } else {\n // Create new user\n user = await this.metadata.GetEntityObject<MJUserEntity>('MJ: Users');\n user.NewRecord();\n }\n\n // Update user properties\n const formValue = this.userForm.value;\n user.Name = formValue.name;\n user.FirstName = formValue.firstName;\n user.LastName = formValue.lastName;\n user.Email = formValue.email;\n user.Title = formValue.title;\n user.Type = formValue.type;\n user.IsActive = formValue.isActive;\n\n // Save user\n const saveResult = await user.Save();\n if (!saveResult) {\n throw new Error(user.LatestResult?.Message || 'Failed to save user');\n }\n\n // Handle role assignments\n await this.updateUserRoles(user.ID);\n\n this.result.emit({ action: 'save', user });\n\n } catch (error: unknown) {\n console.error('Error saving user:', error);\n this.ngZone.run(() => {\n this.error = error instanceof Error ? error.message : 'An unexpected error occurred';\n this.cdr.markForCheck();\n });\n } finally {\n this.ngZone.run(() => {\n this.isLoading = false;\n this.cdr.markForCheck();\n });\n }\n }\n\n private async updateUserRoles(userId: string): Promise<void> {\n try {\n // Get current role IDs from existing UserRole entities\n const existingRoleIds = new Set(this.existingUserRoles.map(ur => ur.RoleID));\n\n // Determine roles to add and remove\n const rolesToAdd = Array.from(this.selectedRoleIds).filter(roleId => !existingRoleIds.has(roleId));\n const rolesToRemove = this.existingUserRoles.filter(userRole => !this.selectedRoleIds.has(userRole.RoleID));\n\n if (rolesToAdd.length === 0 && rolesToRemove.length === 0) {\n return;\n }\n\n // Batch all role deletes and adds into one transactional GraphQL call\n const tg = await this.metadata.CreateTransactionGroup();\n\n // Each Delete()/Save() only ENROLS the row in the group; the write is deferred to Submit().\n // A false return therefore means the row was refused CLIENT-side and never enrolled — so\n // submitting anyway writes a PARTIAL change, or an empty one whose Submit() returns true for\n // having nothing to do, and either way the dialog closes reporting success. Same rule and\n // same reason as `UserManagementComponent.executeBulkRoleAssign`, where the transaction-group\n // semantics — and why the server-side #4282 guard is NOT what this catches — are set out in full.\n const refusals: string[] = [];\n\n for (const userRole of rolesToRemove) {\n userRole.TransactionGroup = tg;\n if (!await userRole.Delete()) {\n refusals.push(`Remove ${this.describeRole(userRole.RoleID)}: ${userRole.LatestResult?.CompleteMessage ?? 'unknown error'}`);\n }\n }\n\n for (const roleId of rolesToAdd) {\n const userRole = await this.metadata.GetEntityObject<MJUserRoleEntity>('MJ: User Roles');\n userRole.NewRecord();\n userRole.UserID = userId;\n userRole.RoleID = roleId;\n userRole.TransactionGroup = tg;\n if (!await userRole.Save()) {\n refusals.push(`Add ${this.describeRole(roleId)}: ${userRole.LatestResult?.CompleteMessage ?? 'unknown error'}`);\n }\n }\n\n if (refusals.length > 0) {\n // Nothing was written: the refused rows never enrolled, and the rest are still only queued\n // because Submit() is not reached.\n throw new Error(`Failed to update user roles — no role changes were made.\\n${refusals.join('\\n')}`);\n }\n\n if (!await tg.Submit()) {\n throw new Error('Failed to update user roles — all changes have been rolled back');\n }\n } catch (error) {\n console.error('Error updating user roles:', error);\n throw error;\n }\n }\n\n /** Names a role for a refusal message; falls back to the ID when the catalog has no match. */\n private describeRole(roleId: string): string {\n return this.data?.availableRoles.find(r => UUIDsEqual(r.ID, roleId))?.Name ?? roleId;\n }\n\n public onCancel(): void {\n this.result.emit({ action: 'cancel' });\n }\n\n private markFormGroupTouched(formGroup: FormGroup): void {\n Object.keys(formGroup.controls).forEach(key => {\n const control = formGroup.get(key);\n control?.markAsTouched();\n });\n }\n}","<!-- MD3 Modal Dialog -->\n@if (visible) {\n <div class=\"modal-backdrop\" (click)=\"onCancel()\">\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <!-- Modal Header with MJ Blue -->\n <div class=\"modal-header\">\n <div class=\"dialog-header\">\n <h2 class=\"dialog-title\">\n <i class=\"fa-solid fa-user\"></i>\n {{ isEditMode ? 'Edit User' : 'Create New User' }}\n </h2>\n <p class=\"dialog-subtitle\">\n {{ isEditMode ? 'Update user information and role assignments' : 'Add a new user to the system' }}\n </p>\n </div>\n <button type=\"button\" class=\"modal-close\" (click)=\"onCancel()\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <form [formGroup]=\"userForm\" (ngSubmit)=\"onSubmit()\">\n @if (error) {\n <div class=\"content-section\">\n <mj-alert Variant=\"error\" [Message]=\"error\" />\n </div>\n }\n <!-- Basic Information Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-id-card\"></i>\n Basic Information\n </h3>\n <p class=\"section-description\">Enter the user's personal and contact details</p>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-field\">\n <label class=\"field-label required\" for=\"name\">Username/Email</label>\n <input\n id=\"name\"\n type=\"email\"\n class=\"field-input\"\n formControlName=\"name\"\n placeholder=\"john@company.com\"\n [class.error]=\"userForm.get('name')?.invalid && userForm.get('name')?.touched\"\n />\n @if (userForm.get('name')?.invalid && userForm.get('name')?.touched) {\n <div class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n @if (userForm.get('name')?.errors?.['required']) {\n Username/Email is required\n }\n @if (userForm.get('name')?.errors?.['email']) {\n Please enter a valid email address\n }\n </div>\n }\n </div>\n <div class=\"form-row\">\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"firstName\">First Name</label>\n <input\n id=\"firstName\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"firstName\"\n placeholder=\"John\"\n />\n </div>\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"lastName\">Last Name</label>\n <input\n id=\"lastName\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"lastName\"\n placeholder=\"Doe\"\n />\n </div>\n </div>\n <div class=\"form-field\">\n <label class=\"field-label required\" for=\"email\">Email Address</label>\n <input\n id=\"email\"\n type=\"email\"\n class=\"field-input\"\n formControlName=\"email\"\n placeholder=\"john@company.com\"\n [class.error]=\"userForm.get('email')?.invalid && userForm.get('email')?.touched\"\n />\n @if (userForm.get('email')?.invalid && userForm.get('email')?.touched) {\n <div class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n @if (userForm.get('email')?.errors?.['required']) {\n Email address is required\n }\n @if (userForm.get('email')?.errors?.['email']) {\n Please enter a valid email address\n }\n </div>\n }\n </div>\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"title\">Job Title</label>\n <input\n id=\"title\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"title\"\n placeholder=\"Software Engineer\"\n />\n </div>\n </div>\n </div>\n </div>\n <!-- User Settings Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-cog\"></i>\n User Settings\n </h3>\n <p class=\"section-description\">Configure user type and account status</p>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"type\">User Type</label>\n <select id=\"type\" class=\"field-select\" formControlName=\"type\">\n <option value=\"User\">Standard User</option>\n <option value=\"Owner\">System Owner</option>\n </select>\n </div>\n <div class=\"form-field\">\n <div class=\"checkbox-field\">\n <input\n id=\"isActive\"\n type=\"checkbox\"\n class=\"checkbox-input\"\n formControlName=\"isActive\"\n />\n <label class=\"checkbox-label\" for=\"isActive\">\n <div class=\"checkbox-indicator\"></div>\n <div>\n <strong>Active Account</strong>\n <div style=\"font-size: 12px; color: var(--md-on-surface-variant); margin-top: 2px;\">\n User can log in and access the system\n </div>\n </div>\n </label>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <!-- Role Assignment Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-user-tag\"></i>\n Role Assignment\n </h3>\n <p class=\"section-description\">Select the roles to assign to this user</p>\n </div>\n <div class=\"roles-grid\">\n @for (role of data?.availableRoles; track role.ID) {\n <div class=\"role-card\"\n [class.selected]=\"selectedRoleIds.has(role.ID)\"\n (click)=\"toggleRole(role.ID)\">\n <div class=\"role-content\">\n <div class=\"checkbox-field\">\n <input\n type=\"checkbox\"\n class=\"checkbox-input\"\n [id]=\"'role-' + role.ID\"\n [checked]=\"selectedRoleIds.has(role.ID)\"\n (change)=\"onRoleToggle(role.ID, $event)\"\n />\n <label class=\"checkbox-label\" [for]=\"'role-' + role.ID\">\n <div class=\"checkbox-indicator\"></div>\n </label>\n </div>\n <div class=\"role-info\">\n <h4 class=\"role-name\">{{ role.Name }}</h4>\n @if (role.Description) {\n <p class=\"role-description\">{{ role.Description }}</p>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Modal Footer -->\n <div class=\"modal-footer\">\n <button\n type=\"submit\"\n class=\"btn btn-primary\"\n [disabled]=\"userForm.invalid || isLoading\"\n >\n @if (isLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Saving...\n } @else {\n <i class=\"fa-solid fa-save\"></i>\n {{ isEditMode ? 'Update User' : 'Create User' }}\n }\n </button>\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"onCancel()\">\n <i class=\"fa-solid fa-times\"></i>\n Cancel\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n}\n"]}
|
|
@@ -148,6 +148,11 @@ export declare class UserManagementComponent extends BaseDashboard implements On
|
|
|
148
148
|
toggleUserExpansion(userId: string): void;
|
|
149
149
|
isUserExpanded(userId: string): boolean;
|
|
150
150
|
getUserRoles(userId: string): MJRoleEntity[];
|
|
151
|
+
/**
|
|
152
|
+
* Names a user for an error message. Falls back to the raw ID rather than to a placeholder so a
|
|
153
|
+
* refusal for a user who has dropped out of the loaded page is still traceable.
|
|
154
|
+
*/
|
|
155
|
+
private describeUser;
|
|
151
156
|
static ɵfac: i0.ɵɵFactoryDeclaration<UserManagementComponent, never>;
|
|
152
157
|
static ɵcmp: i0.ɵɵComponentDeclaration<UserManagementComponent, "mj-user-management", never, {}, {}, never, never, false, never>;
|
|
153
158
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-management.component.d.ts","sourceRoot":"","sources":["../../../src/lib/user-management/user-management.component.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"user-management.component.d.ts","sourceRoot":"","sources":["../../../src/lib/user-management/user-management.component.ts"],"names":[],"mappings":"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"}
|
|
@@ -118,7 +118,7 @@ function UserManagementComponent_Conditional_21_For_8_Conditional_25_Conditional
|
|
|
118
118
|
function UserManagementComponent_Conditional_21_For_8_Conditional_25_Template(rf, ctx) { if (rf & 1) {
|
|
119
119
|
const _r7 = i0.ɵɵgetCurrentView();
|
|
120
120
|
i0.ɵɵelementStart(0, "div", 68)(1, "div", 69);
|
|
121
|
-
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_21_For_8_Conditional_25_Template_div_click_1_listener($event) {
|
|
121
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_21_For_8_Conditional_25_Template_div_click_1_listener($event) { return $event.stopPropagation(); });
|
|
122
122
|
i0.ɵɵelementStart(2, "span", 59);
|
|
123
123
|
i0.ɵɵelement(3, "i", 60);
|
|
124
124
|
i0.ɵɵtext(4);
|
|
@@ -219,7 +219,7 @@ function UserManagementComponent_Conditional_21_For_8_Template(rf, ctx) { if (rf
|
|
|
219
219
|
i0.ɵɵelementStart(0, "div", 49)(1, "div", 50);
|
|
220
220
|
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_21_For_8_Template_div_click_1_listener() { const user_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleUserExpansion(user_r6.ID)); })("keydown.enter", function UserManagementComponent_Conditional_21_For_8_Template_div_keydown_enter_1_listener() { const user_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleUserExpansion(user_r6.ID)); });
|
|
221
221
|
i0.ɵɵelementStart(2, "div", 51);
|
|
222
|
-
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_21_For_8_Template_div_click_2_listener($event) {
|
|
222
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_21_For_8_Template_div_click_2_listener($event) { return $event.stopPropagation(); });
|
|
223
223
|
i0.ɵɵelementStart(3, "input", 52);
|
|
224
224
|
i0.ɵɵlistener("change", function UserManagementComponent_Conditional_21_For_8_Template_input_change_3_listener($event) { const user_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleUserSelection(user_r6.ID, $event)); });
|
|
225
225
|
i0.ɵɵelementEnd()();
|
|
@@ -237,7 +237,7 @@ function UserManagementComponent_Conditional_21_For_8_Template(rf, ctx) { if (rf
|
|
|
237
237
|
i0.ɵɵtext(15);
|
|
238
238
|
i0.ɵɵelementEnd();
|
|
239
239
|
i0.ɵɵelementStart(16, "div", 61);
|
|
240
|
-
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_21_For_8_Template_div_click_16_listener($event) {
|
|
240
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_21_For_8_Template_div_click_16_listener($event) { return $event.stopPropagation(); });
|
|
241
241
|
i0.ɵɵelementStart(17, "button", 62);
|
|
242
242
|
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_21_For_8_Template_button_click_17_listener() { const user_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.editUser(user_r6)); });
|
|
243
243
|
i0.ɵɵelement(18, "i", 63);
|
|
@@ -328,7 +328,7 @@ function UserManagementComponent_Conditional_23_Template(rf, ctx) { if (rf & 1)
|
|
|
328
328
|
i0.ɵɵelementStart(0, "div", 89);
|
|
329
329
|
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_23_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.showDeleteConfirm = false); });
|
|
330
330
|
i0.ɵɵelementStart(1, "div", 90);
|
|
331
|
-
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_23_Template_div_click_1_listener($event) {
|
|
331
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_23_Template_div_click_1_listener($event) { return $event.stopPropagation(); });
|
|
332
332
|
i0.ɵɵelementStart(2, "div", 91)(3, "h3", 92);
|
|
333
333
|
i0.ɵɵelement(4, "i", 93);
|
|
334
334
|
i0.ɵɵtext(5, " Confirm Delete ");
|
|
@@ -402,7 +402,7 @@ function UserManagementComponent_Conditional_24_Template(rf, ctx) { if (rf & 1)
|
|
|
402
402
|
i0.ɵɵelementStart(0, "div", 100);
|
|
403
403
|
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_24_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelBulkAction()); });
|
|
404
404
|
i0.ɵɵelementStart(1, "div", 90);
|
|
405
|
-
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_24_Template_div_click_1_listener($event) {
|
|
405
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_24_Template_div_click_1_listener($event) { return $event.stopPropagation(); });
|
|
406
406
|
i0.ɵɵelementStart(2, "div", 91)(3, "h3", 101);
|
|
407
407
|
i0.ɵɵconditionalCreate(4, UserManagementComponent_Conditional_24_Conditional_4_Template, 1, 0, "i", 93)(5, UserManagementComponent_Conditional_24_Conditional_5_Template, 1, 0, "i", 102)(6, UserManagementComponent_Conditional_24_Conditional_6_Template, 1, 0, "i", 103);
|
|
408
408
|
i0.ɵɵtext(7);
|
|
@@ -464,7 +464,7 @@ function UserManagementComponent_Conditional_25_Template(rf, ctx) { if (rf & 1)
|
|
|
464
464
|
i0.ɵɵelementStart(0, "div", 108);
|
|
465
465
|
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_25_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelBulkRoleAssign()); });
|
|
466
466
|
i0.ɵɵelementStart(1, "div", 90);
|
|
467
|
-
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_25_Template_div_click_1_listener($event) {
|
|
467
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_25_Template_div_click_1_listener($event) { return $event.stopPropagation(); });
|
|
468
468
|
i0.ɵɵelementStart(2, "div", 91)(3, "h3", 109);
|
|
469
469
|
i0.ɵɵelement(4, "i", 33);
|
|
470
470
|
i0.ɵɵtext(5);
|
|
@@ -980,8 +980,21 @@ let UserManagementComponent = class UserManagementComponent extends BaseDashboar
|
|
|
980
980
|
async toggleUserStatus(user) {
|
|
981
981
|
try {
|
|
982
982
|
user.IsActive = !user.IsActive;
|
|
983
|
-
|
|
983
|
+
// BaseEntity.Save() returns false on a validation failure — it does NOT throw. Discarding
|
|
984
|
+
// the result meant the catch below never ran for a refused save: no revert, no message, and
|
|
985
|
+
// calculateStats() re-rendered the row as toggled, so the UI asserted success while nothing
|
|
986
|
+
// had been written. Reachable for every non-Owner admin since the #4260 privilege-elevation
|
|
987
|
+
// guard on MJ: Users, because deactivating a user is a write to another user's row.
|
|
988
|
+
// Mirrors deleteUser() above, which already checks its result this way.
|
|
989
|
+
if (!(await user.Save())) {
|
|
990
|
+
throw new Error(user.LatestResult?.Message || 'Failed to update user status');
|
|
991
|
+
}
|
|
984
992
|
this.ngZone.run(() => {
|
|
993
|
+
// Clear any banner left by a PREVIOUS refused toggle. Without this a non-Owner who is
|
|
994
|
+
// refused on one row, then succeeds on a row they may edit (their own), keeps reading the
|
|
995
|
+
// stale refusal. `loadInitialData()` is the only other place `error` is reset and this path
|
|
996
|
+
// does not call it.
|
|
997
|
+
this.error = null;
|
|
985
998
|
this.calculateStats();
|
|
986
999
|
this.cdr.markForCheck();
|
|
987
1000
|
});
|
|
@@ -990,6 +1003,7 @@ let UserManagementComponent = class UserManagementComponent extends BaseDashboar
|
|
|
990
1003
|
console.error('Error updating user status:', error);
|
|
991
1004
|
this.ngZone.run(() => {
|
|
992
1005
|
user.IsActive = !user.IsActive; // Revert on error
|
|
1006
|
+
this.error = error instanceof Error ? error.message : 'Failed to update user status';
|
|
993
1007
|
this.cdr.markForCheck();
|
|
994
1008
|
});
|
|
995
1009
|
}
|
|
@@ -1314,13 +1328,43 @@ let UserManagementComponent = class UserManagementComponent extends BaseDashboar
|
|
|
1314
1328
|
});
|
|
1315
1329
|
if (usersNeedingRole.length > 0) {
|
|
1316
1330
|
const tg = await this.metadata.CreateTransactionGroup();
|
|
1331
|
+
// Each Save() only ENROLS the row in the group — the write is deferred to Submit(). Inside
|
|
1332
|
+
// a TransactionGroup, Save() therefore reports ENROLMENT, not the write's outcome: the
|
|
1333
|
+
// provider queues the item locally and returns true with no round trip
|
|
1334
|
+
// (`GraphQLDataProvider.Save` — "part of a TG always return true").
|
|
1335
|
+
//
|
|
1336
|
+
// So the role-elevation guard is NOT what this check catches. `MJUserRoleEntityServer`
|
|
1337
|
+
// (issue #4282) lives in `@memberjunction/core-entities-server`, which no browser package
|
|
1338
|
+
// depends on, so it never registers here — it refuses on the server, during Submit().
|
|
1339
|
+
//
|
|
1340
|
+
// And today that refusal reaches the user NOWHERE. `ExecuteTransactionGroup` discards the
|
|
1341
|
+
// refused row's `Save()` return, so the row never enrols in the SERVER's group either; an
|
|
1342
|
+
// all-refused batch submits an empty group, whose `Submit()` returns true for having
|
|
1343
|
+
// nothing to do, and the screen closes with no message at all. Verified end to end against
|
|
1344
|
+
// a live server: a non-Owner assigning a role they do not hold is correctly refused (no row
|
|
1345
|
+
// is written) and is reported as success. Tracked as issue #4309 — fixing it belongs in the
|
|
1346
|
+
// resolver, which is the only layer that still knows which row was refused and why.
|
|
1347
|
+
//
|
|
1348
|
+
// What this check DOES catch is a CLIENT-side refusal — a CheckPermissions denial or a
|
|
1349
|
+
// field-rule failure — which really does return false here, leaving that row unenrolled.
|
|
1350
|
+
// Ignoring the return meant an all-refused batch left the group EMPTY, and an empty group's
|
|
1351
|
+
// Submit() returns true for having nothing to do, so the screen reported success having
|
|
1352
|
+
// assigned nothing. That is the failure this guards; keep it.
|
|
1353
|
+
const refusals = [];
|
|
1317
1354
|
for (const userId of usersNeedingRole) {
|
|
1318
1355
|
const userRole = await this.metadata.GetEntityObject('MJ: User Roles');
|
|
1319
1356
|
userRole.NewRecord();
|
|
1320
1357
|
userRole.UserID = userId;
|
|
1321
1358
|
userRole.RoleID = this.bulkRoleId;
|
|
1322
1359
|
userRole.TransactionGroup = tg;
|
|
1323
|
-
await userRole.Save()
|
|
1360
|
+
if (!await userRole.Save()) {
|
|
1361
|
+
refusals.push(`${this.describeUser(userId)}: ${userRole.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
if (refusals.length > 0) {
|
|
1365
|
+
// Nothing was written: the refused rows never enrolled, and the rest are still only
|
|
1366
|
+
// queued because Submit() is not reached.
|
|
1367
|
+
throw new Error(`Failed to assign roles — nothing was changed.\n${refusals.join('\n')}`);
|
|
1324
1368
|
}
|
|
1325
1369
|
if (!await tg.Submit()) {
|
|
1326
1370
|
throw new Error('Failed to assign roles — all changes have been rolled back');
|
|
@@ -1400,6 +1444,14 @@ let UserManagementComponent = class UserManagementComponent extends BaseDashboar
|
|
|
1400
1444
|
const roleIds = this.userRoleMap.get(userId) || [];
|
|
1401
1445
|
return this.roles.filter(role => roleIds.some(id => UUIDsEqual(id, role.ID)));
|
|
1402
1446
|
}
|
|
1447
|
+
/**
|
|
1448
|
+
* Names a user for an error message. Falls back to the raw ID rather than to a placeholder so a
|
|
1449
|
+
* refusal for a user who has dropped out of the loaded page is still traceable.
|
|
1450
|
+
*/
|
|
1451
|
+
describeUser(userId) {
|
|
1452
|
+
const user = this.users.find(u => UUIDsEqual(u.ID, userId));
|
|
1453
|
+
return user?.Email ?? user?.Name ?? userId;
|
|
1454
|
+
}
|
|
1403
1455
|
static ɵfac = function UserManagementComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || UserManagementComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.NgZone)); };
|
|
1404
1456
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UserManagementComponent, selectors: [["mj-user-management"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 26, vars: 17, consts: [["AriaLabel", "Filter users", "Title", "Users", "Subtitle", "Manage user accounts, roles, and access"], ["meta", ""], ["Label", "users", 3, "Count", "Total"], ["toolbar", ""], ["Placeholder", "Search users by name or email...", 3, "ValueChange", "Value"], ["Label", "Filters", "Icon", "fa-solid fa-filter", 3, "ClearAllRequested", "ActiveCount", "ShowClearAll"], [3, "ValuesChange", "Reset", "Fields", "Values"], ["actions", ""], [3, "Clicked", "Loading"], ["mjButton", "", "variant", "secondary", "size", "sm", "aria-label", "Export users to file", 3, "click"], [1, "fa-solid", "fa-download"], [1, "mj-action-label"], ["mjButton", "", "variant", "primary", "size", "sm", "aria-label", "Add new user", 3, "click"], [1, "fa-solid", "fa-plus"], ["role", "toolbar", "aria-label", "Bulk actions", 1, "bulk-action-toolbar"], ["role", "status", "aria-live", "polite", "aria-busy", "true", 1, "loading-container"], ["role", "alert", "aria-live", "assertive", 1, "error-container"], ["role", "list", "aria-label", "Users list", 1, "users-list"], [3, "result", "data", "visible"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "delete-dialog-title", "aria-describedby", "delete-dialog-desc", 1, "modal-backdrop"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "bulk-action-dialog-title", "aria-describedby", "bulk-action-dialog-desc", 1, "modal-backdrop"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "bulk-role-dialog-title", "aria-describedby", "bulk-role-dialog-desc", 1, "modal-backdrop"], [1, "bulk-selection-info"], ["aria-hidden", "true", 1, "fa-solid", "fa-check-square"], ["mjButton", "", "variant", "flat", "size", "sm", "aria-label", "Clear selection", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-times"], [1, "bulk-action-buttons"], ["mjButton", "", "variant", "secondary", "size", "sm", "aria-label", "Enable selected users", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-toggle-on"], [1, "btn-text"], ["mjButton", "", "variant", "secondary", "size", "sm", "aria-label", "Disable selected users", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-toggle-off"], ["mjButton", "", "variant", "secondary", "size", "sm", "aria-label", "Assign role to selected users", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-user-tag"], ["mjButton", "", "variant", "danger", "size", "sm", "aria-label", "Delete selected users", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-trash"], ["text", "Loading users...", "size", "medium"], [1, "error-content"], ["aria-hidden", "true", 1, "fa-solid", "fa-exclamation-triangle", "error-icon"], [1, "error-message"], ["aria-label", "Retry loading users", 1, "retry-button", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-refresh"], [1, "list-header"], [1, "select-all-label"], ["type", "checkbox", "aria-label", "Select all users", 1, "checkbox", 3, "change", "checked", "indeterminate"], [1, "select-all-text"], [1, "selection-count"], ["role", "listitem", 1, "user-card", 3, "expanded", "selected"], ["Icon", "fa-solid fa-users-slash", "Title", "No users found", "Message", "Try adjusting your filters or add a new user", "ActionIcon", "fa-solid fa-rotate-left", 3, "Variant", "ActionText"], ["role", "listitem", 1, "user-card"], ["role", "button", "tabindex", "0", 1, "user-header", 3, "click", "keydown.enter"], [1, "user-selection", 3, "click"], ["type", "checkbox", 1, "checkbox", 3, "change", "checked"], [1, "user-info"], ["aria-hidden", "true", 1, "user-avatar"], [1, "user-details"], [1, "user-name"], [1, "user-email"], [1, "user-meta"], [1, "status-badge"], ["aria-hidden", "true"], [1, "user-actions", "desktop-only", 3, "click"], ["mjButton", "", "variant", "flat", "size", "sm", "title", "Edit", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-edit"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click", "title"], ["mjButton", "", "variant", "danger", "size", "sm", "title", "Delete", 3, "click"], ["aria-label", "Toggle user details", 1, "expand-btn"], ["aria-hidden", "true", 1, "fa-solid", "fa-chevron-down"], [1, "user-content"], [1, "mobile-actions-bar", 3, "click"], [1, "mobile-action-buttons"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click"], [1, "btn-label"], ["mjButton", "", "variant", "danger", "size", "sm", 3, "click"], [1, "user-stats"], [1, "stat-item"], [1, "stat-label"], [1, "stat-value"], ["aria-hidden", "true", 1, "fa-solid", "fa-id-card"], ["aria-hidden", "true", 1, "fa-solid", "fa-calendar"], ["aria-hidden", "true", 1, "fa-solid", "fa-clock"], [1, "roles-section"], [1, "section-title"], ["aria-hidden", "true", 1, "fa-solid", "fa-user-shield"], [1, "roles-grid"], [1, "no-roles"], [1, "role-item"], ["aria-hidden", "true", 1, "fa-solid", "fa-shield"], ["Icon", "fa-solid fa-users-slash", "Title", "No users found", "Message", "Try adjusting your filters or add a new user", "ActionIcon", "fa-solid fa-rotate-left", 3, "Action", "Variant", "ActionText"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "delete-dialog-title", "aria-describedby", "delete-dialog-desc", 1, "modal-backdrop", 3, "click"], [1, "modal-dialog", 3, "click"], [1, "modal-header"], ["id", "delete-dialog-title", 1, "modal-title"], ["aria-hidden", "true", 1, "fa-solid", "fa-exclamation-triangle", "text-danger"], ["aria-label", "Close dialog", 1, "modal-close", 3, "click"], ["id", "delete-dialog-desc", 1, "modal-body"], [1, "text-muted"], [1, "modal-footer"], ["mjButton", "", "variant", "danger", 3, "click"], ["mjButton", "", 3, "click"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "bulk-action-dialog-title", "aria-describedby", "bulk-action-dialog-desc", 1, "modal-backdrop", 3, "click"], ["id", "bulk-action-dialog-title", 1, "modal-title"], ["aria-hidden", "true", 1, "fa-solid", "fa-toggle-on", "text-success"], ["aria-hidden", "true", 1, "fa-solid", "fa-toggle-off", "text-warning"], ["id", "bulk-action-dialog-desc", 1, "modal-body"], ["mjButton", "", 3, "click", "variant", "disabled"], ["mjButton", "", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-spinner", "fa-spin"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "bulk-role-dialog-title", "aria-describedby", "bulk-role-dialog-desc", 1, "modal-backdrop", 3, "click"], ["id", "bulk-role-dialog-title", 1, "modal-title"], ["id", "bulk-role-dialog-desc", 1, "modal-body"], [1, "form-field"], ["for", "bulk-role-select", 1, "field-label"], ["id", "bulk-role-select", "aria-label", "Select role to assign", 1, "field-select", 3, "ngModelChange", "ngModel"], ["value", ""], [3, "value"], ["mjButton", "", "variant", "primary", 3, "click", "disabled"]], template: function UserManagementComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1405
1457
|
i0.ɵɵelementStart(0, "mj-page-header-interior", 0)(1, "div", 1);
|
|
@@ -1467,7 +1519,7 @@ let UserManagementComponent = class UserManagementComponent extends BaseDashboar
|
|
|
1467
1519
|
i0.ɵɵconditional(ctx.showBulkActionConfirm ? 24 : -1);
|
|
1468
1520
|
i0.ɵɵadvance();
|
|
1469
1521
|
i0.ɵɵconditional(ctx.showBulkRoleAssign ? 25 : -1);
|
|
1470
|
-
} }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.LoadingComponent, i3.MJButtonDirective, i3.MJPageHeaderInteriorComponent, i3.MJPageBodyInteriorComponent, i3.MJPageSearchComponent, i3.MJFilterPopoverComponent, i3.MJFilterPanelComponent, i3.MJRefreshButtonComponent, i3.MJStatBadgeComponent, i3.MJEmptyStateComponent, i4.UserDialogComponent, i5.DatePipe], styles: ["\n\n\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n\n\n\n\n.sticky-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n}\n\n\n\n\n\n.scrollable-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 1.5rem 2rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem;\n }\n}\n\n@media (min-width: 1440px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem 2.5rem;\n }\n}\n\n\n\n\n\n.action-buttons[_ngcontent-%COMP%] {\n flex-shrink: 0;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .action-buttons[_ngcontent-%COMP%] {\n padding: 1rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .action-buttons[_ngcontent-%COMP%] {\n justify-content: center;\n flex-wrap: wrap;\n }\n}\n\n\n\n\n\n.mj-grid-4[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 1rem 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n grid-template-columns: repeat(4, 1fr);\n padding: 0 1.5rem 1rem 1.5rem;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1rem;\n }\n}\n\n\n\n.mj-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n pointer-events: none;\n}\n\n@media (min-width: 768px) {\n .mj-card[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n }\n}\n\n\n\n\n\n.stat-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .stat-icon[_ngcontent-%COMP%] {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n.stat-icon-total[_ngcontent-%COMP%] {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-active[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n\n\n\n\n.stat-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n letter-spacing: -0.02em;\n}\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 2rem;\n }\n}\n\n.stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 0.25rem;\n}\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n }\n}\n\n\n\n\n\n.filters-section[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n margin: 0 1rem 0.75rem 1rem;\n padding: 0.75rem;\n border-radius: var(--mj-radius-lg);\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .filters-section[_ngcontent-%COMP%] {\n margin: 0 1.5rem 1rem 1.5rem;\n padding: 1rem 1.25rem;\n }\n}\n\n.filters-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 1rem;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n@media (min-width: 768px) {\n .filters-row[_ngcontent-%COMP%] {\n gap: 1.5rem;\n }\n}\n\n.mj-filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mj-filter-label[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n\n\n\n\n.mj-search[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n min-width: 200px;\n}\n\n@media (min-width: 640px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 280px;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 400px;\n max-width: 600px;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 500px;\n max-width: 800px;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n left: 1.25rem;\n font-size: 1.125rem;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.875rem 1rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem 1rem 3.25rem;\n font-size: 1.0625rem;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1.125rem 1.5rem 1.125rem 3.5rem;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n background: var(--mj-bg-page);\n}\n\n.mj-search[_ngcontent-%COMP%]:focus-within .mj-search-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n\n\n\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n overflow: visible;\n position: relative;\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-sm);\n padding: 1rem;\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .content-area[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n\n\n\n\n.expand-btn[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: var(--mj-radius-full);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n\n\n\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.status-badge.status-active[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success);\n}\n\n.status-badge.status-inactive[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error);\n}\n\n.status-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.625rem;\n}\n\n\n\n\n\n.mobile-actions-bar[_ngcontent-%COMP%] {\n display: none;\n}\n\n.mobile-action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n}\n\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 1.5rem;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-text[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-subtext[_ngcontent-%COMP%] {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n}\n\n\n\n\n\n.error-container[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-icon[_ngcontent-%COMP%] {\n font-size: 3.5rem;\n color: var(--mj-status-error);\n margin-bottom: 1rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-message[_ngcontent-%COMP%] {\n font-size: 1.0625rem;\n color: var(--mj-text-primary);\n margin: 0 0 1.5rem 0;\n}\n\n\n\n\n\n.modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 1rem;\n animation: _ngcontent-%COMP%_fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-dialog[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 500px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n}\n\n.modal-body[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 1rem;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n line-height: 1.5;\n}\n\n.modal-body[_ngcontent-%COMP%] p[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-start;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .modal-dialog[_ngcontent-%COMP%] {\n width: 95%;\n max-height: 85vh;\n }\n\n .modal-header[_ngcontent-%COMP%] {\n padding: 1rem;\n }\n\n .modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n\n .modal-body[_ngcontent-%COMP%] {\n padding: 1rem;\n }\n\n .modal-footer[_ngcontent-%COMP%] {\n padding: 1rem;\n flex-direction: column;\n }\n\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.filter-button[_ngcontent-%COMP%] {\n display: none;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n min-width: 44px;\n}\n\n.filter-button[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.filter-button[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1rem;\n}\n\n\n\n\n\n.filter-modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: flex-end;\n justify-content: center;\n z-index: 1000;\n animation: _ngcontent-%COMP%_fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n}\n\n.filter-modal[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUpFromBottom 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.filter-modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.filter-modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.filter-modal-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 1.375rem;\n}\n\n.filter-modal-close[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.filter-modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.filter-modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n.filter-modal-footer[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.filter-modal-footer[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n flex: 1;\n margin: 0;\n}\n\n\n\n.filter-options-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.filter-group-label[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.filter-group-options[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.filter-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.filter-option[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.filter-option[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%], \n.filter-option[_ngcontent-%COMP%] input[type=\"radio\"][_ngcontent-%COMP%] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.filter-option-label[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 1rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] .filter-option-label[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n\n\n\n\n.text-danger[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.text-warning[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-500);\n}\n\n.text-success[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n\n\n\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideUpFromBottom {\n from {\n transform: translateY(100%);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n\n\n\n\n.mj-search-input[_ngcontent-%COMP%]:focus-visible, \nbutton[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n\n\n\n\n@media (prefers-reduced-motion: reduce) {\n *[_ngcontent-%COMP%], \n *[_ngcontent-%COMP%]::before, \n *[_ngcontent-%COMP%]::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}", "\n\n\n\n\n\n\n\n\n\n\n\n.status-chips[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n flex-shrink: 0;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.mj-grid-4[_ngcontent-%COMP%] {\n display: none;\n}\n\n@media (min-width: 768px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n display: grid;\n }\n}\n\n\n\n@media (min-width: 768px) {\n .stat-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n font-size: 1.25rem;\n }\n}\n\n\n\n.stat-icon-total[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-accent) 25%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-inactive[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n.stat-icon-admin[_ngcontent-%COMP%] {\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-700);\n}\n\n\n\n\n\n.bulk-action-toolbar[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n background: var(--mj-brand-accent-subtle);\n border-bottom: 1px solid var(--mj-border-default);\n animation: slideDown 0.2s ease;\n}\n\n@media (min-width: 768px) {\n .bulk-action-toolbar[_ngcontent-%COMP%] {\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 1rem 1.5rem;\n }\n}\n\n.bulk-selection-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.bulk-selection-info[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n}\n\n.bulk-action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n\n@media (max-width: 639px) {\n .bulk-action-buttons[_ngcontent-%COMP%] .btn-text[_ngcontent-%COMP%] {\n display: none;\n }\n\n .bulk-action-buttons[_ngcontent-%COMP%] .mj-btn-sm[_ngcontent-%COMP%] {\n padding: 0.5rem;\n min-width: 36px;\n }\n}\n\n\n\n\n\n.users-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.list-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n border: 1px solid var(--mj-border-default);\n margin-bottom: 0.5rem;\n}\n\n.select-all-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n cursor: pointer;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.select-all-text[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.selection-count[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-accent) 25%, transparent);\n padding: 0.25rem 0.75rem;\n border-radius: var(--mj-radius-full);\n}\n\n.user-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n overflow: hidden;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.user-card[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.expanded[_ngcontent-%COMP%] {\n box-shadow: var(--mj-shadow-lg);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.selected[_ngcontent-%COMP%] {\n background: var(--mj-brand-accent-subtle);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.selected[_ngcontent-%COMP%] .user-header[_ngcontent-%COMP%] {\n background: transparent;\n}\n\n.user-card.selected[_ngcontent-%COMP%]:hover .user-header[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.user-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n cursor: pointer;\n background: var(--mj-bg-surface);\n transition: background-color 0.2s ease;\n}\n\n.user-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .user-header[_ngcontent-%COMP%] {\n padding: 0.875rem 1rem;\n gap: 0.625rem;\n }\n}\n\n.user-selection[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n\n.checkbox[_ngcontent-%COMP%] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n}\n\n.user-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex: 1;\n min-width: 0;\n}\n\n.user-avatar[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-full);\n background: linear-gradient(135deg, var(--mj-brand-primary) 0%, var(--mj-brand-primary-light) 100%);\n color: var(--mj-brand-on-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.875rem;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n@media (max-width: 639px) {\n .user-avatar[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 0.8125rem;\n }\n\n .user-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n }\n\n .user-name[_ngcontent-%COMP%] {\n font-size: 0.9375rem;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .user-email[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n}\n\n.user-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.user-name[_ngcontent-%COMP%] {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.user-email[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n margin: 0.125rem 0 0 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.user-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex-shrink: 0;\n}\n\n@media (max-width: 767px) {\n .user-meta[_ngcontent-%COMP%] .status-badge[_ngcontent-%COMP%], \n .user-meta[_ngcontent-%COMP%] .user-actions[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .user-meta[_ngcontent-%COMP%] {\n gap: 0;\n }\n}\n\n.desktop-only[_ngcontent-%COMP%] {\n display: none;\n}\n\n@media (min-width: 768px) {\n .desktop-only[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.25rem;\n }\n}\n\n.user-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.25rem;\n}\n\n.user-card.expanded[_ngcontent-%COMP%] .expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n\n\n.user-content[_ngcontent-%COMP%] {\n padding: 1.25rem 1.5rem;\n background: var(--mj-bg-page);\n border-top: 1px solid var(--mj-border-default);\n animation: slideDown 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n\n\n.mobile-actions-bar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-bottom: 1rem;\n margin-bottom: 1rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .mobile-actions-bar[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n.mobile-action-buttons[_ngcontent-%COMP%] .btn-label[_ngcontent-%COMP%] {\n margin-left: 0.375rem;\n}\n\n\n\n.user-stats[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 1rem;\n margin-bottom: 1rem;\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 0.875rem;\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n}\n\n\n\n.roles-section[_ngcontent-%COMP%] {\n padding-top: 1rem;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.section-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.75rem 0;\n}\n\n.section-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 1.125rem;\n}\n\n.roles-grid[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n}\n\n.role-item[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-800);\n border: 1px solid var(--mj-color-warning-500);\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.role-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.625rem;\n}\n\n.no-roles[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n\n\n\n\n.error-container[_ngcontent-%COMP%] .retry-button[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 600;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n min-height: 44px;\n}\n\n.error-container[_ngcontent-%COMP%] .retry-button[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.error-container[_ngcontent-%COMP%] .retry-button[_ngcontent-%COMP%]:active {\n background: var(--mj-color-brand-400);\n transform: scale(0.98);\n}\n\n\n\n\n\n.form-field[_ngcontent-%COMP%] {\n margin-bottom: 1rem;\n}\n\n.form-field[_ngcontent-%COMP%] .field-label[_ngcontent-%COMP%] {\n display: block;\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-bottom: 0.5rem;\n}\n\n.form-field[_ngcontent-%COMP%] .field-select[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid var(--mj-color-neutral-400);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-page);\n font-size: 1rem;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.form-field[_ngcontent-%COMP%] .field-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n\n\n.checkbox[_ngcontent-%COMP%]:focus-visible, \n.user-header[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n\n\n\n\n@media (min-width: 1440px) {\n .bulk-action-toolbar[_ngcontent-%COMP%] {\n padding: 1.25rem 2rem;\n }\n\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1.5rem;\n padding: 0 2rem 1rem 2rem;\n }\n\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem;\n }\n}\n\n\n\n\n\n@media (max-width: 639px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 0.75rem 0.5rem 0.75rem;\n }\n\n .mj-card[_ngcontent-%COMP%] {\n padding: 0.75rem;\n gap: 0.75rem;\n }\n\n .stat-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 1.125rem;\n }\n\n .stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 1.5rem;\n }\n\n .stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.6875rem;\n }\n\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 0.75rem;\n }\n\n .list-header[_ngcontent-%COMP%] {\n padding: 0.625rem 0.75rem;\n }\n}"] });
|
|
1522
|
+
} }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.LoadingComponent, i3.MJButtonDirective, i3.MJPageHeaderInteriorComponent, i3.MJPageBodyInteriorComponent, i3.MJPageSearchComponent, i3.MJFilterPopoverComponent, i3.MJFilterPanelComponent, i3.MJRefreshButtonComponent, i3.MJStatBadgeComponent, i3.MJEmptyStateComponent, i4.UserDialogComponent, i5.DatePipe], styles: ["\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n\n\n\n.sticky-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n}\n\n\n\n\n.scrollable-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 1.5rem 2rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem;\n }\n}\n\n@media (min-width: 1440px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem 2.5rem;\n }\n}\n\n\n\n\n.action-buttons[_ngcontent-%COMP%] {\n flex-shrink: 0;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .action-buttons[_ngcontent-%COMP%] {\n padding: 1rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .action-buttons[_ngcontent-%COMP%] {\n justify-content: center;\n flex-wrap: wrap;\n }\n}\n\n\n\n\n.mj-grid-4[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 1rem 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n grid-template-columns: repeat(4, 1fr);\n padding: 0 1.5rem 1rem 1.5rem;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1rem;\n }\n}\n\n\n.mj-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n pointer-events: none;\n}\n\n@media (min-width: 768px) {\n .mj-card[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n }\n}\n\n\n\n\n.stat-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .stat-icon[_ngcontent-%COMP%] {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n.stat-icon-total[_ngcontent-%COMP%] {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-active[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n\n\n\n.stat-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n letter-spacing: -0.02em;\n}\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 2rem;\n }\n}\n\n.stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 0.25rem;\n}\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n }\n}\n\n\n\n\n.filters-section[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n margin: 0 1rem 0.75rem 1rem;\n padding: 0.75rem;\n border-radius: var(--mj-radius-lg);\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .filters-section[_ngcontent-%COMP%] {\n margin: 0 1.5rem 1rem 1.5rem;\n padding: 1rem 1.25rem;\n }\n}\n\n.filters-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 1rem;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n@media (min-width: 768px) {\n .filters-row[_ngcontent-%COMP%] {\n gap: 1.5rem;\n }\n}\n\n.mj-filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mj-filter-label[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n\n\n\n.mj-search[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n min-width: 200px;\n}\n\n@media (min-width: 640px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 280px;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 400px;\n max-width: 600px;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 500px;\n max-width: 800px;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n left: 1.25rem;\n font-size: 1.125rem;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.875rem 1rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem 1rem 3.25rem;\n font-size: 1.0625rem;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1.125rem 1.5rem 1.125rem 3.5rem;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n background: var(--mj-bg-page);\n}\n\n.mj-search[_ngcontent-%COMP%]:focus-within .mj-search-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n\n\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n overflow: visible;\n position: relative;\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-sm);\n padding: 1rem;\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .content-area[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n\n\n\n.expand-btn[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: var(--mj-radius-full);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n\n\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.status-badge.status-active[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success);\n}\n\n.status-badge.status-inactive[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error);\n}\n\n.status-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.625rem;\n}\n\n\n\n\n.mobile-actions-bar[_ngcontent-%COMP%] {\n display: none;\n}\n\n.mobile-action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n}\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 1.5rem;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-text[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-subtext[_ngcontent-%COMP%] {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n}\n\n\n\n\n.error-container[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-icon[_ngcontent-%COMP%] {\n font-size: 3.5rem;\n color: var(--mj-status-error);\n margin-bottom: 1rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-message[_ngcontent-%COMP%] {\n font-size: 1.0625rem;\n color: var(--mj-text-primary);\n margin: 0 0 1.5rem 0;\n}\n\n\n\n\n.modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 1rem;\n animation: _ngcontent-%COMP%_fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-dialog[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 500px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n}\n\n.modal-body[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 1rem;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n line-height: 1.5;\n}\n\n.modal-body[_ngcontent-%COMP%] p[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-start;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .modal-dialog[_ngcontent-%COMP%] {\n width: 95%;\n max-height: 85vh;\n }\n\n .modal-header[_ngcontent-%COMP%] {\n padding: 1rem;\n }\n\n .modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n\n .modal-body[_ngcontent-%COMP%] {\n padding: 1rem;\n }\n\n .modal-footer[_ngcontent-%COMP%] {\n padding: 1rem;\n flex-direction: column;\n }\n\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.filter-button[_ngcontent-%COMP%] {\n display: none;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n min-width: 44px;\n}\n\n.filter-button[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.filter-button[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1rem;\n}\n\n\n\n\n.filter-modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: flex-end;\n justify-content: center;\n z-index: 1000;\n animation: _ngcontent-%COMP%_fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n}\n\n.filter-modal[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUpFromBottom 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.filter-modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.filter-modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.filter-modal-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 1.375rem;\n}\n\n.filter-modal-close[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.filter-modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.filter-modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n.filter-modal-footer[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.filter-modal-footer[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n flex: 1;\n margin: 0;\n}\n\n\n.filter-options-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.filter-group-label[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.filter-group-options[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.filter-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.filter-option[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.filter-option[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%], \n.filter-option[_ngcontent-%COMP%] input[type=\"radio\"][_ngcontent-%COMP%] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.filter-option-label[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 1rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] .filter-option-label[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n\n\n\n.text-danger[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.text-warning[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-500);\n}\n\n.text-success[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n\n\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideUpFromBottom {\n from {\n transform: translateY(100%);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n\n\n\n.mj-search-input[_ngcontent-%COMP%]:focus-visible, \nbutton[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n\n\n\n@media (prefers-reduced-motion: reduce) {\n *[_ngcontent-%COMP%], \n *[_ngcontent-%COMP%]::before, \n *[_ngcontent-%COMP%]::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}", "\n\n\n\n\n\n\n\n\n\n.status-chips[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n flex-shrink: 0;\n}\n\n\n\n\n\n\n\n\n\n\n\n.mj-grid-4[_ngcontent-%COMP%] {\n display: none;\n}\n\n@media (min-width: 768px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n display: grid;\n }\n}\n\n\n@media (min-width: 768px) {\n .stat-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n font-size: 1.25rem;\n }\n}\n\n\n.stat-icon-total[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-accent) 25%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-inactive[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n.stat-icon-admin[_ngcontent-%COMP%] {\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-700);\n}\n\n\n\n\n.bulk-action-toolbar[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n background: var(--mj-brand-accent-subtle);\n border-bottom: 1px solid var(--mj-border-default);\n animation: slideDown 0.2s ease;\n}\n\n@media (min-width: 768px) {\n .bulk-action-toolbar[_ngcontent-%COMP%] {\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 1rem 1.5rem;\n }\n}\n\n.bulk-selection-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.bulk-selection-info[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n}\n\n.bulk-action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n\n@media (max-width: 639px) {\n .bulk-action-buttons[_ngcontent-%COMP%] .btn-text[_ngcontent-%COMP%] {\n display: none;\n }\n\n .bulk-action-buttons[_ngcontent-%COMP%] .mj-btn-sm[_ngcontent-%COMP%] {\n padding: 0.5rem;\n min-width: 36px;\n }\n}\n\n\n\n\n.users-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.list-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n border: 1px solid var(--mj-border-default);\n margin-bottom: 0.5rem;\n}\n\n.select-all-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n cursor: pointer;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.select-all-text[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.selection-count[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-accent) 25%, transparent);\n padding: 0.25rem 0.75rem;\n border-radius: var(--mj-radius-full);\n}\n\n.user-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n overflow: hidden;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.user-card[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.expanded[_ngcontent-%COMP%] {\n box-shadow: var(--mj-shadow-lg);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.selected[_ngcontent-%COMP%] {\n background: var(--mj-brand-accent-subtle);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.selected[_ngcontent-%COMP%] .user-header[_ngcontent-%COMP%] {\n background: transparent;\n}\n\n.user-card.selected[_ngcontent-%COMP%]:hover .user-header[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.user-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n cursor: pointer;\n background: var(--mj-bg-surface);\n transition: background-color 0.2s ease;\n}\n\n.user-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .user-header[_ngcontent-%COMP%] {\n padding: 0.875rem 1rem;\n gap: 0.625rem;\n }\n}\n\n.user-selection[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n\n.checkbox[_ngcontent-%COMP%] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n}\n\n.user-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex: 1;\n min-width: 0;\n}\n\n.user-avatar[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-full);\n background: linear-gradient(135deg, var(--mj-brand-primary) 0%, var(--mj-brand-primary-light) 100%);\n color: var(--mj-brand-on-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.875rem;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n@media (max-width: 639px) {\n .user-avatar[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 0.8125rem;\n }\n\n .user-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n }\n\n .user-name[_ngcontent-%COMP%] {\n font-size: 0.9375rem;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .user-email[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n}\n\n.user-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.user-name[_ngcontent-%COMP%] {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.user-email[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n margin: 0.125rem 0 0 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.user-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex-shrink: 0;\n}\n\n@media (max-width: 767px) {\n .user-meta[_ngcontent-%COMP%] .status-badge[_ngcontent-%COMP%], \n .user-meta[_ngcontent-%COMP%] .user-actions[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .user-meta[_ngcontent-%COMP%] {\n gap: 0;\n }\n}\n\n.desktop-only[_ngcontent-%COMP%] {\n display: none;\n}\n\n@media (min-width: 768px) {\n .desktop-only[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.25rem;\n }\n}\n\n.user-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.25rem;\n}\n\n.user-card.expanded[_ngcontent-%COMP%] .expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n\n.user-content[_ngcontent-%COMP%] {\n padding: 1.25rem 1.5rem;\n background: var(--mj-bg-page);\n border-top: 1px solid var(--mj-border-default);\n animation: slideDown 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n\n.mobile-actions-bar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-bottom: 1rem;\n margin-bottom: 1rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .mobile-actions-bar[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n.mobile-action-buttons[_ngcontent-%COMP%] .btn-label[_ngcontent-%COMP%] {\n margin-left: 0.375rem;\n}\n\n\n.user-stats[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 1rem;\n margin-bottom: 1rem;\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 0.875rem;\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n}\n\n\n.roles-section[_ngcontent-%COMP%] {\n padding-top: 1rem;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.section-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.75rem 0;\n}\n\n.section-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 1.125rem;\n}\n\n.roles-grid[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n}\n\n.role-item[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-800);\n border: 1px solid var(--mj-color-warning-500);\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.role-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.625rem;\n}\n\n.no-roles[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n\n\n\n.error-container[_ngcontent-%COMP%] .retry-button[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 600;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n min-height: 44px;\n}\n\n.error-container[_ngcontent-%COMP%] .retry-button[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.error-container[_ngcontent-%COMP%] .retry-button[_ngcontent-%COMP%]:active {\n background: var(--mj-color-brand-400);\n transform: scale(0.98);\n}\n\n\n\n\n.form-field[_ngcontent-%COMP%] {\n margin-bottom: 1rem;\n}\n\n.form-field[_ngcontent-%COMP%] .field-label[_ngcontent-%COMP%] {\n display: block;\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-bottom: 0.5rem;\n}\n\n.form-field[_ngcontent-%COMP%] .field-select[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid var(--mj-color-neutral-400);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-page);\n font-size: 1rem;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.form-field[_ngcontent-%COMP%] .field-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n\n.checkbox[_ngcontent-%COMP%]:focus-visible, \n.user-header[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n\n\n\n@media (min-width: 1440px) {\n .bulk-action-toolbar[_ngcontent-%COMP%] {\n padding: 1.25rem 2rem;\n }\n\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1.5rem;\n padding: 0 2rem 1rem 2rem;\n }\n\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem;\n }\n}\n\n\n\n\n@media (max-width: 639px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 0.75rem 0.5rem 0.75rem;\n }\n\n .mj-card[_ngcontent-%COMP%] {\n padding: 0.75rem;\n gap: 0.75rem;\n }\n\n .stat-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 1.125rem;\n }\n\n .stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 1.5rem;\n }\n\n .stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.6875rem;\n }\n\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 0.75rem;\n }\n\n .list-header[_ngcontent-%COMP%] {\n padding: 0.625rem 0.75rem;\n }\n}"] });
|
|
1471
1523
|
};
|
|
1472
1524
|
UserManagementComponent = __decorate([
|
|
1473
1525
|
RegisterClass(BaseDashboard, 'UserManagement')
|