From 069e53cec6e27957fc1c36dbad6ba94025c41b87 Mon Sep 17 00:00:00 2001 From: sepehr Date: Thu, 16 Oct 2025 17:34:13 +0300 Subject: [PATCH] feat: redesign user management interface - Complete UI/UX overhaul of user manager - Improved user permissions handling - Enhanced user role management - Better user filtering and search capabilities --- .../user_manager/user_manager.component.html | 300 +++++++----- .../user_manager/user_manager.component.ts | 50 ++ src/app/views/user_manager/user_manager.scss | 458 ++++++++++++++++++ 3 files changed, 696 insertions(+), 112 deletions(-) diff --git a/src/app/views/user_manager/user_manager.component.html b/src/app/views/user_manager/user_manager.component.html index 0637be2..1365cef 100644 --- a/src/app/views/user_manager/user_manager.component.html +++ b/src/app/views/user_manager/user_manager.component.html @@ -56,124 +56,200 @@ -
Editing User {{SelectedUser['name']}}
-
Adding new User
+
Edit: {{SelectedUser['username']}}
+
Add User
- -
- - -
- - - First Name - - - Last Name - - - -
- - -
- -
- - -
- -
MikroWizard permisssions :
- - - - - - - - - - - - - - + + +
+
+
Basic Information
+ Enter the user's personal details and login credentials +
+ + + + + + + + + + + + + + + - - - -
Mikrotik permisssions :
- - - -   {{value}} - - - - {{value}} - - - - - - - - -
-
- - - - - -
- Add new Permission - - - - - - - - {{group.name}} - - - - - - - - - - - {{perm.name}} - - - - - - - -
- - -
- -
+ + +
+
+
System Access Levels
+ Control what system features this user can access and modify +
+
+ R = Read Only + W = Read & Write + F = Full Control + × = No Access +
+
+
+ {{ perm.key.replace('_', ' ') }} +
+ + + + +
+
+
+
+ + +
+
+
Device Access Control
+ Grant access to specific device groups with defined permission levels +
+ + +
+
+ + Add Device Permission +
+ + +
+ + +
+
+ {{group.name}} +
+
+
+ No groups found +
+
+
+ +
+ + +
+
+ {{perm.name}} +
+
+
+ No permissions found +
+
+
+ + + + +
+
+ + +
+
+
Current Device Access
+ {{userperms.length}} permission(s) +
+ +
+
+
{{i + 1}}
+
+
+ + {{perm.group_name}} +
+
+ + {{perm.perm_name}} +
+
+ +
+
+ +
+
+ +
+
+ No device access granted +

Add permissions above to grant access to device groups

+
+
+
+
+ +
- - - + +
+
+ + +
diff --git a/src/app/views/user_manager/user_manager.component.ts b/src/app/views/user_manager/user_manager.component.ts index d41859e..60b6595 100644 --- a/src/app/views/user_manager/user_manager.component.ts +++ b/src/app/views/user_manager/user_manager.component.ts @@ -78,6 +78,12 @@ export class UserManagerComponent implements OnInit { public permission: any = {}; public allDevGroups: any = []; public allPerms: any = []; + public devgroupSearch: string = ''; + public permissionSearch: string = ''; + public filteredDevGroups: any = []; + public filteredPermissions: any = []; + public showDevGroupDropdown: boolean = false; + public showPermissionDropdown: boolean = false; public DeletePermConfirmModalVisible: boolean = false; public userperms: any = {}; public userresttrictions: any = false; @@ -129,6 +135,40 @@ export class UserManagerComponent implements OnInit { this.adminperms[key] = value; } + filterDevGroups(event: any): void { + const query = event.target.value.toLowerCase(); + this.filteredDevGroups = this.allDevGroups.filter((group: any) => + group.name.toLowerCase().includes(query) + ); + } + + filterPermissions(event: any): void { + const query = event.target.value.toLowerCase(); + this.filteredPermissions = this.allPerms.filter((perm: any) => + perm.name.toLowerCase().includes(query) + ); + } + + selectDevGroup(group: any): void { + this.devgroup = group; + this.devgroupSearch = group.name; + this.showDevGroupDropdown = false; + } + + selectPermission(perm: any): void { + this.permission = perm; + this.permissionSearch = perm.name; + this.showPermissionDropdown = false; + } + + hideDevGroupDropdown(): void { + setTimeout(() => this.showDevGroupDropdown = false, 200); + } + + hidePermissionDropdown(): void { + setTimeout(() => this.showPermissionDropdown = false, 200); + } + public rowSelection: boolean | GuiRowSelection = { enabled: true, type: GuiRowSelectionType.CHECKBOX, @@ -226,6 +266,7 @@ export class UserManagerComponent implements OnInit { _self.allPerms = res.map((x: any) => { return { id: x["id"], name: x.name }; }); + _self.filteredPermissions = [..._self.allPerms]; _self.data_provider.get_devgroup_list().then((res) => { if ("error" in res && res.error.indexOf("Unauthorized")) { _self.show_toast( @@ -238,6 +279,7 @@ export class UserManagerComponent implements OnInit { _self.allDevGroups = res.map((x: any) => { return { id: x["id"], name: x.name }; }); + _self.filteredDevGroups = [..._self.allDevGroups]; } }); } @@ -254,6 +296,10 @@ export class UserManagerComponent implements OnInit { action: "add", }; this.adminperms = { ...this.defadminperms }; + this.devgroup = {}; + this.permission = {}; + this.devgroupSearch = ''; + this.permissionSearch = ''; this.EditTaskModalVisible = true; return; } @@ -263,6 +309,10 @@ export class UserManagerComponent implements OnInit { } else this.adminperms = { ...this.defadminperms }; _self.SelectedUser["action"] = "edit"; _self.get_user_perms(_self.SelectedUser["id"]); + _self.devgroup = {}; + _self.permission = {}; + _self.devgroupSearch = ''; + _self.permissionSearch = ''; _self.EditTaskModalVisible = true; } diff --git a/src/app/views/user_manager/user_manager.scss b/src/app/views/user_manager/user_manager.scss index 37a3dcd..e08d0da 100644 --- a/src/app/views/user_manager/user_manager.scss +++ b/src/app/views/user_manager/user_manager.scss @@ -1,4 +1,462 @@ table tr td{ padding-bottom:20px; vertical-align:top +} + +/* Enhanced Modal Styles */ +.permission-item { + transition: all 0.2s ease; + background: #fafafa; + min-height: 60px; +} + +.permission-item:hover { + background: #f0f0f0; + transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +/* Modern Form Sections */ +.user-form-section, .permissions-section, .device-permissions-section { + border-radius: 8px; + background: #f8f9fa; + padding: 1rem; + border: 1px solid #e9ecef; +} + +.section-title { + color: #495057; + font-weight: 600; + margin-bottom: 0.75rem; + font-size: 0.95rem; +} + +.form-input { + border-radius: 6px; + border: 1px solid #ced4da; + padding: 0.5rem 0.75rem; + font-size: 0.9rem; + transition: all 0.2s ease; +} + +.form-input:focus { + border-color: #0d6efd; + box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25); +} + +/* Compact Permissions */ +.permissions-compact { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 0.5rem; +} + +.perm-row { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.4rem 0.6rem; + background: white; + border: 1px solid #dee2e6; + border-radius: 6px; + transition: all 0.2s ease; +} + +.perm-row:hover { + background: #f1f3f4; + border-color: #adb5bd; +} + +.perm-label { + font-size: 0.85rem; + font-weight: 500; + color: #495057; + text-transform: capitalize; + flex: 1; +} + +.perm-controls { + display: flex; + gap: 2px; +} + +.perm-controls .btn { + padding: 0.2rem 0.4rem; + font-size: 0.7rem; + font-weight: 600; + min-width: 24px; + border-radius: 4px; +} + +/* Section Headers */ +.section-header { + border-bottom: 1px solid #e9ecef; + padding-bottom: 0.5rem; +} + +/* Permission Legend */ +.permission-legend { + display: flex; + flex-wrap: wrap; + gap: 1rem; + padding: 0.5rem; + background: #f8f9fa; + border-radius: 4px; + border: 1px solid #e9ecef; +} + +.legend-item { + display: flex; + align-items: center; + gap: 0.25rem; + font-size: 0.75rem; + color: #6c757d; +} + +.legend-color { + width: 12px; + height: 12px; + border-radius: 2px; + display: inline-block; +} + +/* Add Permission Card */ +.add-permission-card { + background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); + border: 2px dashed #0d6efd; + border-radius: 8px; + padding: 1rem; + transition: all 0.2s ease; +} + +.add-permission-card:hover { + border-color: #0a58ca; + background: linear-gradient(135deg, #e7f3ff 0%, #cfe2ff 100%); +} + +.add-header { + display: flex; + align-items: center; + font-size: 0.9rem; + color: #495057; + margin-bottom: 0.5rem; +} + +.add-btn { + font-weight: 600; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +.add-btn:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +/* Current Permissions */ +.current-permissions { + background: white; + border-radius: 8px; + border: 1px solid #dee2e6; + overflow: hidden; +} + +.permissions-header { + background: #f8f9fa; + padding: 0.75rem 1rem; + border-bottom: 1px solid #dee2e6; + display: flex; + justify-content: space-between; + align-items: center; +} + +.permissions-list { + max-height: 250px; + overflow-y: auto; +} + +.permission-item { + display: flex; + align-items: center; + padding: 0.75rem 1rem; + border-bottom: 1px solid #f1f3f4; + transition: all 0.2s ease; +} + +.permission-item:last-child { + border-bottom: none; +} + +.permission-item:hover { + background: #f8f9fa; +} + +.perm-number { + background: #0d6efd; + color: white; + width: 24px; + height: 24px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.75rem; + font-weight: 600; + margin-right: 0.75rem; + flex-shrink: 0; +} + +.perm-info { + flex: 1; +} + +.perm-main { + display: flex; + align-items: center; + margin-bottom: 0.25rem; +} + +.perm-detail { + display: flex; + align-items: center; +} + +.group-name { + font-size: 0.85rem; + font-weight: 600; + color: #495057; +} + +.perm-name { + font-size: 0.75rem; + color: #6c757d; +} + +.remove-btn { + margin-left: 0.5rem; + flex-shrink: 0; +} + +/* Empty State */ +.empty-permissions { + display: flex; + align-items: center; + padding: 2rem 1rem; + text-align: center; +} + +.empty-icon { + font-size: 2rem; + margin-right: 1rem; + opacity: 0.5; +} + +.empty-text strong { + display: block; + margin-bottom: 0.25rem; + color: #495057; +} + +.compact-select { + font-size: 0.85rem; + height: calc(1.8em + 0.75rem + 2px); + padding: 0.375rem 0.75rem; + border-radius: 0.375rem; +} + +.compact-select:focus { + border-color: #0d6efd; + box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25); +} + +/* Search Select Components */ +.search-select-wrapper { + position: relative; +} + +.search-label { + display: block; + font-size: 0.8rem; + color: #6c757d; + margin-bottom: 0.25rem; + font-weight: 500; +} + +.search-input { + width: 100%; +} + +.search-dropdown { + position: absolute; + top: 100%; + left: 0; + right: 0; + background: white; + border: 1px solid #ced4da; + border-top: none; + border-radius: 0 0 0.375rem 0.375rem; + max-height: 200px; + overflow-y: auto; + z-index: 1000; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +.search-option { + padding: 0.5rem 0.75rem; + cursor: pointer; + border-bottom: 1px solid #f1f3f4; + font-size: 0.85rem; + transition: background-color 0.2s ease; +} + +.search-option:hover { + background-color: #f8f9fa; +} + +.search-option:last-child { + border-bottom: none; +} + +.search-no-results { + padding: 0.75rem; + text-align: center; + color: #6c757d; + font-size: 0.8rem; + font-style: italic; + background: white; + border: 1px solid #ced4da; + border-top: none; + border-radius: 0 0 0.375rem 0.375rem; + position: absolute; + top: 100%; + left: 0; + right: 0; + z-index: 1000; +} + +.badge { + font-size: 0.7rem; +} + +.add-permission-form { + border: 1px dashed #dee2e6; +} + +.c-modal-body { + max-height: 85vh; + overflow-y: auto; +} + +.c-card-header { + border-bottom: 1px solid #e9ecef; +} + +.permission-item small { + color: #6c757d; + font-weight: 500; +} + +.c-button-group .btn { + font-size: 0.75rem; + font-weight: 500; + min-width: 28px; +} + +.compact-field { + font-size: 0.85rem; +} + +.compact-field .mat-form-field-wrapper { + padding-bottom: 0.5em; +} + +/* Mobile Responsive */ +@media (max-width: 576px) { + .c-modal-dialog { + margin: 0.25rem; + } + + .user-form-section, .permissions-section, .device-permissions-section { + padding: 0.75rem; + margin-bottom: 0.75rem; + } + + .permissions-compact { + grid-template-columns: 1fr; + } + + .perm-row { + flex-direction: column; + align-items: stretch; + gap: 0.5rem; + padding: 0.5rem; + } + + .perm-label { + text-align: center; + margin-bottom: 0.25rem; + } + + .perm-controls { + justify-content: center; + } + + .add-permission-card { + padding: 0.75rem; + } + + .permission-legend { + gap: 0.5rem; + justify-content: center; + } + + .permissions-header { + flex-direction: column; + align-items: flex-start; + gap: 0.5rem; + } + + .empty-permissions { + flex-direction: column; + text-align: center; + } + + .empty-icon { + margin-right: 0; + margin-bottom: 0.5rem; + } + + .section-title { + font-size: 0.9rem; + } + + .c-button-group .btn { + font-size: 0.7rem; + padding: 0.25rem 0.3rem; + min-width: 24px; + } + + .c-modal-body { + max-height: 90vh; + padding: 0.5rem !important; + } + + .c-card-body { + padding: 0.75rem !important; + } + + .add-permission-form { + padding: 0.75rem !important; + } +} + +@media (max-width: 768px) { + .c-modal-footer { + flex-direction: column; + align-items: stretch; + } + + .c-modal-footer > div { + width: 100%; + text-align: center; + } } \ No newline at end of file