# User Management Component Redesign ## Executive Summary This document outlines the redesign of the Spry Authentication user management components. The redesign focuses on: 1. Converting `UserManagementPage` to `UserManagementComponent` for better placement control 2. Removing all CSS classes to avoid conflicts with application-defined styles 3. Implementing an HTML5 `
`/`` pattern for user display 4. Using separate view/edit components that swap via HTMX for cleaner separation 5. Integrating permission editing directly into the edit component (removing standalone `PermissionEditorComponent`) --- ## Current Implementation Overview ### Component Hierarchy ```mermaid graph TD A[UserManagementPage - PageComponent] --> B[UserListComponent] A --> C[UserFormComponent] B --> D[UserListItemComponent - per user] C --> E[PermissionEditorComponent] ``` ### Current Components | Component | Type | Purpose | |-----------|------|---------| | [`UserManagementPage`](src/Authentication/Components/UserManagementPage.vala) | PageComponent | Full HTML page with embedded CSS, permission check, orchestrates child components | | [`UserListComponent`](src/Authentication/Components/UserListComponent.vala) | Component | Table of users with search/pagination, creates UserListItemComponent per row | | [`UserListItemComponent`](src/Authentication/Components/UserListItemComponent.vala) | Component | Single table row with user info and action buttons | | [`UserFormComponent`](src/Authentication/Components/UserFormComponent.vala) | Component | Modal form for create/edit with validation | | [`PermissionEditorComponent`](src/Authentication/Components/PermissionEditorComponent.vala) | Component | Checkbox-based permission selection | ### Current Issues 1. **Tight Coupling to Page Structure**: `UserManagementPage` is a `PageComponent` that generates a full HTML document, limiting where it can be placed 2. **CSS Class Pollution**: Extensive use of CSS classes like `.admin-container`, `.btn`, `.modal-overlay`, `.spry-user-list` may conflict with application styles 3. **Modal-Based Editing**: Separate modal form disrupts the flow and requires additional clicks 4. **Complex Component Tree**: Five separate components increase maintenance burden --- ## New Design ### Component Hierarchy ```mermaid graph TD A[UserManagementComponent - Container] --> B[UserDetailsComponent - view mode per user] A --> C[UserDetailEditComponent - edit mode swaps in] A --> D[NewUserComponent - for creation] C --> E[Integrated Permission Editing] D --> E ``` ### Simplified Component Structure | Component | Type | Purpose | |-----------|------|---------| | `UserManagementComponent` | Component | Container with header, new user button, user list outlet | | `UserDetailsComponent` | Component | View-only `
` element for displaying one user | | `UserDetailEditComponent` | Component | Edit mode `
` element with form fields and integrated permission editing | | `NewUserComponent` | Component | Create form using same pattern as edit, with integrated permission editing | ### Key Changes 1. **`UserManagementPage` → `UserManagementComponent`**: - Changed from `PageComponent` to `Component` - No longer generates full HTML document - Application can place it anywhere 2. **Separate View/Edit Components**: - `UserDetailsComponent` handles read-only display - `UserDetailEditComponent` handles editing (swapped in via HTMX) - Clean separation of concerns - each component has a single responsibility 3. **Remove `PermissionEditorComponent`**: - Permission editing functionality integrated directly into `UserDetailEditComponent` and `NewUserComponent` - Reduces component complexity and eliminates unnecessary abstraction 4. **Remove `UserFormComponent`, `UserListComponent`, `UserListItemComponent`**: - Functionality distributed among new focused components --- ## HTML Structure Design ### UserManagementComponent ```html

Users

``` ### UserDetailsComponent - View Mode Only This component handles read-only display of a single user. When the user clicks "Edit", the entire component is swapped out for `UserDetailEditComponent`. ```html
permission(s)
User ID
Username
Email
Created
Permissions
``` ### UserDetailEditComponent - Edit Mode with Integrated Permissions This component is swapped in when editing. It includes inline permission editing (no separate component). ```html
Editing...
User ID
Username *
Email *
New Password Minimum 8 characters if changing
Permissions
Common:
Custom Permissions:
``` ### NewUserComponent - For Creating New Users Uses the same pattern as edit mode with integrated permission editing. ```html
+ New User
Username * Alphanumeric and underscores only, min 3 chars
Email *
Password * Minimum 8 characters
Permissions
Common:
Custom Permissions:
``` --- ## HTMX Attributes and Targets ### Target Strategy All actions must properly target the correct DOM elements for HTMX swapping. The key insight is that view and edit components swap each other out using the same element ID: | Action | Source Component | Target | Swap | Result | |--------|------------------|--------|------|--------| | `:StartEdit` | UserDetailsComponent | `user-{user_id}` | outerHTML | Swaps in UserDetailEditComponent | | `:SaveEdit` | UserDetailEditComponent | `user-{user_id}` | outerHTML | Swaps in UserDetailsComponent - view | | `:CancelEdit` | UserDetailEditComponent | `user-{user_id}` | outerHTML | Swaps in UserDetailsComponent - view | | `:AddPermission` | UserDetailEditComponent | `user-{user_id}` | outerHTML | Re-renders edit component with new permission | | `:RemovePermission` | UserDetailEditComponent | `user-{user_id}` | outerHTML | Re-renders edit component without permission | | `:DeleteUser` | UserDetailsComponent | `user-management` | outerHTML | Refreshes entire user list | | `:CreateUser` | NewUserComponent | `user-management` | outerHTML | Refreshes list with new user added | | `:CancelCreate` | NewUserComponent | `user-management` | outerHTML | Hides create form | | `:ShowCreateUser` | UserManagementComponent | `user-management` | outerHTML | Shows NewUserComponent | ### Global ID Strategy - `UserManagementComponent`: `id="user-management"` (static, for cross-component targeting) - `UserDetailsComponent`: `id="user-{user_id}"` (dynamic per user) - `UserDetailEditComponent`: `id="user-{user_id}"` (same ID - they swap each other) - `NewUserComponent`: `id="new-user"` (static) ### Component Swap Flow Diagram ```mermaid sequenceDiagram participant U as User participant UV as UserDetailsComponent - View participant UE as UserDetailEditComponent - Edit participant UM as UserManagementComponent participant S as Server/Service Note over U,S: Edit Flow - Component Swap U->>UV: Click Edit button UV->>S: POST with :StartEdit action S->>S: Create UserDetailEditComponent with user data S->>UE: Return UserDetailEditComponent - swaps in at same ID U->>UE: Modify fields, click Save UE->>S: POST with :SaveEdit action S->>S: Validate and save to UserService S->>S: Create UserDetailsComponent with updated data S->>UV: Return UserDetailsComponent - swaps back at same ID Note over U,S: Delete Flow U->>UV: Click Delete button UV->>S: POST with :DeleteUser action targeting user-management S->>S: Delete user via UserService S->>UM: Return refreshed UserManagementComponent Note over U,S: Create Flow U->>UM: Click Create User button UM->>S: POST with :ShowCreateUser action S->>UM: Return UserManagementComponent with NewUserComponent U->>UM: Fill form, click Create UM->>S: POST with :CreateUser action targeting user-management S->>S: Create user via UserService S->>UM: Return refreshed UserManagementComponent without form ``` --- ## Inline Editing Behavior ### State Management Each `UserDetailsComponent` maintains its own editing state: ```vala public class UserDetailsComponent : Component { // State private User _user; public bool is_editing { get; private set; default = false; } public string? error_message { get; private set; default = null; } // Exposed for template public string user_id { get { return _user.id; } } public string username { get { return _user.username; } } public string email { get { return _user.email; } } public string created_at { get { return _user.created_at.format("%Y-%m-%d"); } } public string[] permissions { get { return _user.permissions; } } // Actions public void start_edit() { is_editing = true; error_message = null; } public void cancel_edit() { is_editing = false; error_message = null; } } ``` ### Edit Toggle Flow 1. **View Mode** (default): Shows read-only table with Edit/Delete buttons 2. **Click Edit**: Triggers `:StartEdit` action, sets `is_editing = true`, re-renders 3. **Edit Mode**: Shows form inputs in table rows with Save/Cancel buttons 4. **Save**: Validates input, calls UserService, on success sets `is_editing = false` 5. **Cancel**: Sets `is_editing = false`, discards changes --- ## New User Creation Pattern ### Visibility Control The `UserManagementComponent` controls whether the create form is visible: ```vala public class UserManagementComponent : Component { public bool show_create_form { get; private set; default = false; } public string? success_message { get; private set; default = null; } public string? error_message { get; private set; default = null; } public async override void handle_action(string action) throws Error { switch (action) { case "ShowCreateUser": show_create_form = true; break; case "CancelCreate": show_create_form = false; break; case "CreateUser": // Handled by NewUserDetailsComponent, but we refresh here show_create_form = false; success_message = "User created successfully"; yield refresh_users_async(); break; case "DeleteUser": // Handle delete, refresh list yield handle_delete_async(); break; } } } ``` ### Creation Flow 1. User clicks "Create User" button in header 2. `UserManagementComponent` sets `show_create_form = true` 3. `NewUserDetailsComponent` renders at top of list with empty fields 4. User fills in fields and clicks "Create User" 5. On success: form hides, success message shows, user list refreshes 6. On error: error message shows in form, form stays visible --- ## CSS Removal Strategy ### Before (CSS Classes) ```html

User Management

...
...
``` ### After (Inline Styles) ```html

User Management

...
``` ### Style Guidelines 1. **Use minimal inline styles** only for essential layout 2. **No class attributes** except for semantic purposes (not styling) 3. **Prefer semantic HTML** (`
`, ``, ``) 4. **Use CSS custom properties** if the application wants to override defaults: ```html
``` --- ## API/Endpoint Requirements ### No New Endpoints Required The redesign uses the existing Spry component action pattern: - Actions are handled within components via `handle_action()` - No new HTTP endpoints need to be created - Existing `UserService` and `PermissionService` methods are sufficient ### Service Dependencies Components continue to use: - `UserService`: create_user_async, get_user_async, update_user_async, delete_user_async, list_users_async - `PermissionService`: set_permission_async, has_permission_by_id_async - `SessionService`: authenticate_request_async (for permission checks) - `ComponentFactory`: create child components ### Potential Future Enhancements 1. **Bulk Operations**: Add `delete_users_async(string[] ids)` for multi-select delete 2. **Search API**: Add `search_users_async(string query)` to UserService for efficient searching 3. **Audit Logging**: Add methods to track who changed what and when --- ## Implementation Checklist ### Files to Create - [ ] `src/Authentication/Components/UserManagementComponent.vala` - New container component - [ ] `src/Authentication/Components/UserDetailsComponent.vala` - View-only details/summary component - [ ] `src/Authentication/Components/UserDetailEditComponent.vala` - Edit mode with integrated permissions - [ ] `src/Authentication/Components/NewUserComponent.vala` - Create form with integrated permissions ### Files to Modify - [ ] `src/Authentication/meson.build` - Add new component files, remove old ones - [ ] `examples/UsersExample.vala` - Update to use new component ### Files to Deprecate/Remove - [ ] `src/Authentication/Components/UserManagementPage.vala` - Replace with UserManagementComponent - [ ] `src/Authentication/Components/UserListComponent.vala` - Merged into UserManagementComponent - [ ] `src/Authentication/Components/UserListItemComponent.vala` - Replaced by UserDetailsComponent - [ ] `src/Authentication/Components/UserFormComponent.vala` - Functionality moved to UserDetailEditComponent and NewUserComponent - [ ] `src/Authentication/Components/PermissionEditorComponent.vala` - Functionality integrated directly into edit/create components --- ## Migration Guide for Applications ### Before (using UserManagementPage) ```vala // Register as a page - generates full HTML document application.add_transient(); application.add_endpoint(new EndpointRoute("/admin/users")); ``` ### After (using UserManagementComponent) ```vala // Option 1: Use in your own PageComponent public class AdminPage : PageComponent { public override string markup { return """ ...
"""; } } // Option 2: Create a simple wrapper page public class UserAdminPage : PageComponent { private ComponentFactory _factory = inject(); public override string markup { return """ User Management """; } public override async void prepare() throws Error { var component = _factory.create(); add_outlet_child("content", component); add_globals_from(component); } } ``` --- ## Summary This redesign simplifies the user management component architecture from 5 components to 3, removes all CSS class dependencies, and implements a modern `
`/`` pattern with inline editing. The key benefits are: 1. **Flexibility**: Applications can place `UserManagementComponent` anywhere in their layout 2. **No Style Conflicts**: Inline styles avoid CSS class collisions 3. **Better UX**: Inline editing is more intuitive than modal forms 4. **Maintainability**: Fewer components with clearer responsibilities 5. **Consistency**: Same editable table pattern for both editing and creating