diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 3c7ebf1..dce30fb 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -46,7 +46,7 @@ {"id":"wg-admin-qtb","title":"Replace clipboard copy with config display window for SSH sessions","description":"# Replace Clipboard Copy with Configuration Display\n\n## Problem\n\nThe TUI application currently has a \"Copy Public Key\" feature (press 'c' in detail screen) that doesn't work over SSH sessions. When running the application remotely via SSH:\n\n1. **Clipboard access is not available** - SSH sessions don't provide clipboard functionality\n2. **Feature is non-functional** - Users cannot copy public keys or configuration\n3. **Workaround required** - Users must manually locate and read config files\n4. **Poor UX** - No easy way to get client configuration for use\n\n## Current Implementation\n\nThe detail screen has a `copyPublicKey()` function that:\n- Returns `clipboardCopiedMsg` message\n- Shows \"Public key copied to clipboard!\" feedback\n- Uses no actual clipboard library (not implemented)\n- Is completely non-functional over SSH\n\n## Proposed Solution\n\nReplace the clipboard copy feature with a **Configuration Display Modal** that:\n\n### 1. Shows Full Client Configuration\n- Displays complete WireGuard client configuration file\n- Includes all sections: [Interface] and [Peer]\n- Shows keys, IPs, endpoints, and all configuration options\n- Useful for:\n - Copying configuration to other devices\n - Manual configuration setup\n - Troubleshooting and debugging\n - Sharing with other users\n\n### 2. Scrollable Content\n- Uses Bubble Tea viewport component for scrolling\n- Supports keyboard navigation:\n - ↑/k - Line up\n - ↓/j - Line down\n - pgup/b - Page up\n - pgdown/f - Page down\n - g - Go to top\n - G - Go to bottom\n- Handles long configurations gracefully\n\n### 3. SSH-Friendly\n- Modal displays text directly on screen\n- Users can select and copy text with mouse in terminal\n- Works in any terminal emulator over SSH\n- No clipboard API required\n\n### 4. Easy to Close\n- Esc key closes modal\n- q key closes modal\n- Returns to detail screen\n\n## Implementation Details\n\n### New Component: ConfigDisplayModal\n\nCreated `internal/tui/components/config-display.go` with:\n\n**Features:**\n- Displays full client configuration in styled modal\n- Scrollable viewport for long content\n- Rounded border with title \"šŸ“‹ Client Configuration\"\n- Help text at bottom with navigation instructions\n- Centered on screen with proper positioning\n\n**Key Bindings:**\n```\n↑/j - Scroll down\n↓/k - Scroll up\npgup/b - Page up\npgdn/f - Page down\ng - Go to top\nG - Go to bottom\nEsc/q - Close modal\n```\n\n### Updated Detail Screen\n\nChanged `internal/tui/screens/detail.go`:\n\n**Removed:**\n- `clipboardCopied` field from DetailScreen struct\n- `clipboardTimer` field from DetailScreen struct\n- `copyPublicKey()` function\n- `clipboardCopiedMsg` type\n- Clipboard timeout handling logic\n- \"āœ“ Public key copied to clipboard!\" display\n\n**Added:**\n- `configDisplay *components.ConfigDisplayModel` field\n- `showConfig bool` field\n- `loadConfig()` function that:\n - Loads client configuration via `wireguard.GetClientConfigContent()`\n - Creates config display modal\n - Shows modal with loaded content\n- Config display modal handling in Update() method\n- Config display modal rendering in View() method\n\n**Changed:**\n- Key handler for 'c': Now calls `loadConfig()` instead of `copyPublicKey()`\n- Help text: Changed from \"[c] Copy Public Key\" to \"[c] View Config\"\n\n## Benefits\n\n1. **Works over SSH** - No clipboard API needed\n2. **More useful** - Shows full configuration, not just public key\n3. **Better UX** - Scrollable, easy to read and select\n4. **Flexible** - Users can copy any part of the configuration\n5. **No external dependencies** - Pure terminal-based solution\n\n## Use Cases\n\n### Scenario 1: User needs config for manual setup\n1. Open client details\n2. Press 'c' to view config\n3. Select and copy full configuration text\n4. Paste into configuration file on target device\n\n### Scenario 2: Troubleshooting\n1. Open client details\n2. Press 'c' to view config\n3. Compare with working configuration\n4. Identify differences or issues\n\n### Scenario 3: Sharing configuration\n1. Open client details\n2. Press 'c' to view config\n3. Select config content\n4. Copy and share with other users/admins\n\n## Files Created\n\n- `internal/tui/components/config-display.go` - Configuration display modal component\n\n## Files Modified\n\n- `internal/tui/screens/detail.go`\n - Updated DetailScreen struct\n - Replaced copyPublicKey with loadConfig\n - Added config display handling\n - Updated help text\n\n## Technical Notes\n\n- Uses Bubble Tea viewport for scrolling\n- Leverages existing `wireguard.GetClientConfigContent()` function\n- Modal styled with lipgloss (rounded border, consistent colors)\n- Viewport dimensions: 76x24 (content area)\n- Modal dimensions: 80x24 (with borders and padding)\n\n## Testing Considerations\n\n- Test with long configuration files (ensure scrolling works)\n- Test with various terminal sizes (ensure modal centers correctly)\n- Test over SSH session (ensure text is selectable/copyable)\n- Test with mouse-enabled terminals (verify selection works)","status":"closed","priority":1,"issue_type":"feature","owner":"Calmcacil@Raion","created_at":"2026-01-12T22:30:26.291472155+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T22:36:25.862565024+01:00","closed_at":"2026-01-12T22:36:25.862565024+01:00","close_reason":"Implemented config display modal to replace non-functional clipboard copy. Users can now view full client configuration in a scrollable window that works over SSH sessions. Press 'c' in detail screen to view config."} {"id":"wg-admin-rfo","title":"CRITICAL: Cannot exit client details screen - navigation broken","description":"# CRITICAL BUG - Cannot exit screens\n\n## Problem\n\nUser is unable to navigate back from certain screens in the TUI. When opening client details or restore screens, pressing the back key ('b' or 'esc') does nothing, forcing the user to kill the process from a separate terminal.\n\n## Root Cause\n\nThe screen Update() method returns `(Screen, tea.Cmd)` tuple. When a screen wants to signal \"go back to previous screen\", it should return `(nil, tea.Cmd)` as the first value.\n\nHowever, both `detail.go` and `restore.go` were incorrectly returning `(s, nil)` instead of `(nil, nil)` when the back key was pressed. This caused the main model's navigation logic to never detect the screen change:\n\n```go\n// In main.go line 107:\nif newScreen == nil { // This check fails because newScreen == s, not nil\n // Go back to previous screen\n m.currentScreen = m.previousScreen\n m.previousScreen = nil\n}\n```\n\n## Issues Found\n\n### detail.go (line 116)\n**Before:**\n```go\ncase \"b\", \"esc\":\n // Return to list screen - signal parent to switch screens\n return s, nil // BUG: Returns current screen, not nil\n```\n\n**After:**\n```go\ncase \"b\", \"esc\":\n // Return to list screen - signal parent to switch screens\n return nil, nil // FIXED: Returns nil to signal screen change\n```\n\n### restore.go (line 101)\n**Before:**\n```go\ncase \"q\", \"esc\":\n // Return to list screen - signal parent to switch screens\n return s, nil // BUG: Returns current screen, not nil\n```\n\n**After:**\n```go\ncase \"q\", \"esc\":\n // Return to list screen - signal parent to switch screens\n return nil, nil // FIXED: Returns nil to signal screen change\n```\n\n## Impact\n\n- Users get trapped in detail and restore screens\n- Cannot return to main list screen\n- Must kill process and restart application\n- Critical usability issue\n\n## Fix Applied\n\nChanged both occurrences from `return s, nil` to `return nil, nil` to properly signal the main model to switch back to the previous screen.\n\n## Verification\n\n- Build successful with no errors\n- Navigation logic now correctly detects nil return value\n- Screen switching works as expected\n\n## Files Modified\n\n- `internal/tui/screens/detail.go` - Line 116\n- `internal/tui/screens/restore.go` - Line 101","status":"closed","priority":0,"issue_type":"bug","owner":"Calmcacil@Raion","created_at":"2026-01-12T22:22:51.43957087+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T22:27:03.641284763+01:00","closed_at":"2026-01-12T22:27:03.641284763+01:00","close_reason":"Fixed navigation bug by changing 'return s, nil' to 'return nil, nil' in detail.go and restore.go. Both screens now correctly signal main model to switch back to previous screen when back key is pressed."} {"id":"wg-admin-slj","title":"Refactor WireGuard scripts into modular architecture","description":"Refactor monolithic wireguard.sh into two separate scripts: wg-install.sh for initial setup, wg-client-manager for client operations. Use interactive 'read' prompts with 'WGI_' prefixed environment variable overrides. Add validation functions, security hardening, and remove all hardcoded sensitive information from repository.","status":"closed","priority":2,"issue_type":"task","owner":"Calmcacil@Raion","created_at":"2026-01-12T16:27:18.232667092+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T17:11:02.639140093+01:00","closed_at":"2026-01-12T17:11:02.639140093+01:00","close_reason":"Refactoring complete: wg-install.sh (921 lines) and wg-client-manager (545 lines) scripts have been created and are functional. wireguard.sh retained for backwards compatibility.","dependencies":[{"issue_id":"wg-admin-slj","depends_on_id":"wg-admin-abw","type":"blocks","created_at":"2026-01-12T16:28:21.930404739+01:00","created_by":"Calmcacil"},{"issue_id":"wg-admin-slj","depends_on_id":"wg-admin-qpy","type":"blocks","created_at":"2026-01-12T16:28:21.936380993+01:00","created_by":"Calmcacil"},{"issue_id":"wg-admin-slj","depends_on_id":"wg-admin-0wc","type":"blocks","created_at":"2026-01-12T16:28:21.983754904+01:00","created_by":"Calmcacil"}]} -{"id":"wg-admin-ti0","title":"Investigate q key behavior and parseHandshake bug","description":"Investigate q key behavior causing app to not return properly from client details. parseHandshake fix has been committed separately.","status":"in_progress","priority":1,"issue_type":"bug","owner":"Calmcacil@Raion","created_at":"2026-01-12T19:26:35.435240285+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T22:59:01.015097211+01:00"} +{"id":"wg-admin-ti0","title":"Investigate q key behavior and parseHandshake bug","description":"Investigate q key behavior causing app to not return properly from client details. parseHandshake fix has been committed separately.","status":"closed","priority":1,"issue_type":"bug","owner":"Calmcacil@Raion","created_at":"2026-01-12T19:26:35.435240285+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T23:02:04.361621453+01:00","closed_at":"2026-01-12T23:02:04.361621453+01:00","close_reason":"Fixed q key behavior to return to list screen instead of quitting app"} {"id":"wg-admin-tv6","title":"Add client delete functionality","description":"Implement delete client workflow with confirmation modal. Remove client config from server, delete client files, auto-backup before deletion, and reload WireGuard configuration.","status":"closed","priority":2,"issue_type":"task","owner":"Calmcacil@Raion","created_at":"2026-01-12T17:03:30.281557572+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T17:48:31.867154638+01:00","closed_at":"2026-01-12T17:48:31.867154638+01:00","close_reason":"Delete with confirmation modal implemented. Auto-backup before deletion, removes client configs and peer from WireGuard. Integrated with detail screen.","dependencies":[{"issue_id":"wg-admin-tv6","depends_on_id":"wg-admin-dd2","type":"blocks","created_at":"2026-01-12T17:04:36.207822184+01:00","created_by":"Calmcacil"}]} {"id":"wg-admin-u4f","title":"Research handshake timing discrepancy in wg show vs app","description":"Research why wg show wg0 shows different handshake timing than the app. Found that parseHandshake function only parses first time unit (e.g., '14 hours' from '14 hours, 24 minutes, 40 seconds ago'), ignoring subsequent units causing significant time discrepancy.","status":"closed","priority":2,"issue_type":"task","owner":"Calmcacil@Raion","created_at":"2026-01-12T19:14:02.054350138+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T19:14:09.570320895+01:00","closed_at":"2026-01-12T19:14:09.570320895+01:00","close_reason":"Research complete - identified parseHandshake only parsing first time unit in compound expressions"} {"id":"wg-admin-v7g","title":"Fix search box functionality on main client list screen","description":"# Fix Search Box Functionality\n\n## Problem\n\nThe search box on the main client list screen is not working properly. Users press '/' to activate search, but the functionality does not work as expected.\n\n## Current Implementation\n\nIn `internal/tui/screens/list.go`:\n\n**Activation (lines 55-59):**\n```go\nif msg.String() == \"/\" \u0026\u0026 !s.search.IsActive() {\n s.search.Activate()\n return s, nil\n}\n```\n\n**Search Active Handling (lines 61-67):**\n```go\nif s.search.IsActive() {\n s.search, cmd = s.search.Update(msg)\n // Apply filter to clients\n s.applyFilter()\n return s, cmd\n}\n```\n\n**View Rendering (line 135):**\n```go\nreturn s.search.View() + \"\\n\" + s.table.View()\n```\n\n## Possible Issues\n\n### 1. Search Not Focusing Input\nThe search component may not be properly setting input focus when activated.\n\n### 2. Table Not Rebuilding After Filter\nThe `applyFilter()` function may not be properly rebuilding the table with filtered results.\n\n### 3. Keyboard Event Handling\nSearch input may not be receiving keyboard events properly when active.\n\n### 4. Search Component Internal Issues\nThe SearchModel component in `internal/tui/components/search.go` may have bugs:\n- Input not updating\n- Filter not applying correctly\n- Active state not being tracked properly\n\n## Investigation Needed\n\n1. **Test search activation**: Verify pressing '/' actually activates search\n2. **Test search input**: Verify typing characters updates search input field\n3. **Test filtering**: Verify filtering actually filters the client list\n4. **Check component**: Review SearchModel implementation for bugs\n5. **Test filter application**: Verify `applyFilter()` correctly rebuilds table\n\n## Expected Behavior\n\n1. User presses '/' to activate search\n2. Search bar appears with focus indicator\n3. User types search query (e.g., \"laptop\")\n4. Table filters to show only matching clients\n5. Matching text is highlighted (if implemented)\n6. User can navigate table results\n7. Press 'Enter' to select filtered result\n8. Press 'Esc' to clear search\n\n## Files to Check\n\n- `internal/tui/screens/list.go` - Main list screen with search\n- `internal/tui/components/search.go` - Search component\n- `internal/tui/screens/detail.go` - Check for comparison (if search works there)\n\n## Dependencies\n\nNone - this is a bug fix\n\n## Priority\n\n**CRITICAL (P0)** - Search is a primary navigation feature and should work reliably","status":"closed","priority":0,"issue_type":"bug","owner":"Calmcacil@Raion","created_at":"2026-01-12T22:38:54.032294512+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T22:54:27.21756834+01:00","closed_at":"2026-01-12T22:54:27.21756834+01:00","close_reason":"Not a bug - search functionality works correctly with '/' key to activate. User confirmed it's resolved."}