From 3f60ab8355ff4e434f1c35f097eccb4e02658c79 Mon Sep 17 00:00:00 2001 From: Calmcacil Date: Mon, 12 Jan 2026 22:44:11 +0100 Subject: [PATCH] fix: add background dimming to config display modal Config display modal now dims background content before showing, following the same pattern as delete confirmation modal. This provides visual consistency across all modals and makes it clear to users when a modal is active. Fixes: wg-admin-bfe --- .beads/issues.jsonl | 3 +++ internal/tui/screens/detail.go | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 1083516..2cb2693 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -16,11 +16,13 @@ {"id":"wg-admin-abw","title":"Create wg-client-manager script","description":"Create new wg-client-manager script for client operations: add, remove, list, show, qr. Implement proper command parsing, use interactive 'read' with 'WGI_' environment variable overrides, call validation functions, use atomic config updates.","status":"closed","priority":2,"issue_type":"task","owner":"Calmcacil@Raion","created_at":"2026-01-12T16:27:53.150007325+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T16:48:38.86400169+01:00","closed_at":"2026-01-12T16:48:38.86400169+01:00","close_reason":"Created wg-client-manager script with all required commands (add, remove, list, show, qr). Implements interactive prompts with WGI_ environment variable overrides, uses validation functions, and performs atomic config updates.","dependencies":[{"issue_id":"wg-admin-abw","depends_on_id":"wg-admin-cwb","type":"blocks","created_at":"2026-01-12T16:28:20.280054863+01:00","created_by":"Calmcacil"},{"issue_id":"wg-admin-abw","depends_on_id":"wg-admin-37o","type":"blocks","created_at":"2026-01-12T16:28:20.299310073+01:00","created_by":"Calmcacil"},{"issue_id":"wg-admin-abw","depends_on_id":"wg-admin-lzl","type":"blocks","created_at":"2026-01-12T16:28:20.300924186+01:00","created_by":"Calmcacil"},{"issue_id":"wg-admin-abw","depends_on_id":"wg-admin-wsk","type":"blocks","created_at":"2026-01-12T16:28:20.354270061+01:00","created_by":"Calmcacil"},{"issue_id":"wg-admin-abw","depends_on_id":"wg-admin-0va","type":"blocks","created_at":"2026-01-12T16:28:21.926811217+01:00","created_by":"Calmcacil"}]} {"id":"wg-admin-az7","title":"Fix client details navigation and improve deletion confirmation UX","description":"\n# Issues to Fix\n\n## 1. Navigation Key Binding Issues\n- **Problem**: 'q' key for going back from client details screen doesn't work properly\n- **Solution**: \n - Change 'q' key to 'b' for back navigation (more intuitive)\n - Add 'esc' key binding for back navigation (in addition to 'b')\n - Update help text to reflect new key bindings\n\n## 2. Deletion Confirmation UX Improvements\n- **Problem**: Current confirmation modal has poor formatting and lacks safety checks\n- **Solution**:\n - **Improve modal formatting**: Better visual styling, clearer layout\n - **Add name verification**: Require user to type the client's name before confirming deletion (prevents accidental deletions)\n - Better visual feedback for selected option (Yes/No)\n\n# Files to Modify\n\n1. **internal/tui/screens/detail.go**\n - Line 124: Change key binding from 'q' to 'b'\n - Line 124: Add 'esc' to back navigation (ensure it works)\n - Line 199: Update help text to show new key bindings\n - Lines 127-134: Replace simple confirm modal with name-verification modal\n\n2. **internal/tui/components/confirm.go** (or create new component)\n - Improve modal styling and formatting\n - Add text input field for client name verification\n - Update key bindings for name input field\n\n# Implementation Notes\n\n- The confirm modal currently uses simple Yes/No with arrow keys\n- New approach: Show \"Type the client name to confirm: [input field]\"\n- Only enable confirm button when input matches client name exactly\n- Case-sensitive name matching for safety\n- Add clear visual feedback (red for danger, green for match)\n","status":"closed","priority":0,"issue_type":"bug","owner":"Calmcacil@Raion","created_at":"2026-01-12T22:13:28.830300356+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T22:16:47.251848171+01:00","closed_at":"2026-01-12T22:16:47.251848171+01:00","close_reason":"Fixed navigation key bindings (changed 'q' to 'b', added 'esc') and created improved deletion confirmation modal with name verification for safety."} {"id":"wg-admin-bay","title":"Implement real-time status checking","description":"Implement real-time connection status using 'wg show wg0' command. Check if client public key appears in peers list. Update status in table: Connected (active peer) or Disconnected (not in peers list). Add auto-refresh every 30 seconds using tea.Tick. Manual refresh with 'r' key.","status":"closed","priority":2,"issue_type":"task","owner":"Calmcacil@Raion","created_at":"2026-01-12T17:02:57.643693952+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T17:34:23.96887044+01:00","closed_at":"2026-01-12T17:34:23.96887044+01:00","close_reason":"Implemented real-time status checking functionality: Created status.go with GetClientStatus() and GetAllPeers() functions that parse 'wg show wg0' output to determine connection status. Added PeerStatus struct with PublicKey, Endpoint, AllowedIPs, LatestHandshake, TransferRx, TransferTx, and Status fields. Created tea_messages.go with Tick() command for auto-refresh and ManualRefresh() command for immediate refresh using tea.Tick and custom messages. Status is 'Connected' if handshake is within 3 minutes, otherwise 'Disconnected'.","dependencies":[{"issue_id":"wg-admin-bay","depends_on_id":"wg-admin-xum","type":"blocks","created_at":"2026-01-12T17:04:44.270454474+01:00","created_by":"Calmcacil"}]} +{"id":"wg-admin-bfe","title":"Fix background dimming on modal overlays","description":"# Fix Background Dimming on Modal Overlays\n\n## Problem\n\nBackground content is not properly dimmed when certain modal windows are displayed. This causes visual inconsistency and makes it unclear that a modal is active.\n\n## Current State\n\n### Working Modals (Background Dimmed)\n\n**Delete Confirmation Modal** (`detail.go` line 144-157):\n```go\nif s.showConfirm \u0026\u0026 s.confirmModal != nil {\n // Render underlying content dimmed\n content := s.renderContent()\n dimmedContent := lipgloss.NewStyle().\n Foreground(lipgloss.Color(\"244\")).\n Render(content)\n\n // Overlay confirmation modal\n return lipgloss.JoinVertical(\n lipgloss.Left,\n dimmedContent,\n s.confirmModal.View(),\n )\n}\n```\n\n**Restore Confirmation Modal** (`restore.go` line 147-160):\n```go\nif s.showConfirm \u0026\u0026 s.confirmModal != nil {\n // Render underlying content dimmed\n content := s.renderContent()\n dimmedContent := lipgloss.NewStyle().\n Foreground(lipgloss.Color(\"244\")).\n Render(content)\n\n // Overlay confirmation modal\n return lipgloss.JoinVertical(\n lipgloss.Left,\n dimmedContent,\n s.confirmModal.View(),\n )\n}\n```\n\n### Broken Modals (Background NOT Dimmed)\n\n**Config Display Modal** (`detail.go` line 139-141):\n```go\n// Handle config display modal\nif s.showConfig \u0026\u0026 s.configDisplay != nil {\n return s.configDisplay.View() // BUG: No background dimming!\n}\n```\n\n**Delete Confirm Modal Component** (`internal/tui/components/delete-confirm.go`):\n- The modal renders directly to screen\n- Does NOT dim background content\n- Assumes parent screen will handle dimming\n\n**Old Confirm Modal Component** (`internal/tui/components/confirm.go`):\n- The modal renders directly to screen\n- Does NOT dim background content\n- Assumes parent screen will handle dimming\n\n## Root Cause\n\n1. **Inconsistent Implementation**: Some screens dim background in their View() method, others don't\n2. **Modal Components Don't Dim**: Modal components (ConfigDisplay, Confirm, DeleteConfirm) don't dim background themselves\n3. **Screens Rely on Parents**: Modal components assume parent screens will handle dimming, but this's inconsistent\n\n## Impact\n\n1. **Visual Inconsistency**: Some modals dim background, others don't\n2. **Poor UX**: Users can't tell if a modal is active or just new content\n3. **Confusion**: It's unclear whether content is part of the modal or background\n4. **Accessibility**: Dimming helps focus attention on the modal; without it, focus is unclear\n\n## Proposed Solution\n\n### Option 1: Modals Dim Their Own Background (Recommended)\n\nEach modal component should be responsible for:\n1. Taking screen width/height as parameters\n2. Rendering full screen content (dimmed background + modal overlay)\n3. This makes modals self-contained and consistent\n\n**Implementation:**\n```go\n// In ConfigDisplayModel View()\nfunc (m *ConfigDisplayModel) View() string {\n if !m.Visible {\n return \"\"\n }\n\n // Dimmed background content would need to be passed in\n // OR modal takes a \"background\" parameter to render\n\n // For now, this approach may not work without refactoring\n // See Option 2 below\n}\n```\n\n### Option 2: Screens Handle Dimming for ALL Modals (Current Pattern)\n\nUpdate screens to dim background for ALL modals consistently:\n\n**detail.go** - Already handles delete confirmation, needs to add for config display:\n```go\nif s.showConfig \u0026\u0026 s.configDisplay != nil {\n // Render underlying content dimmed\n content := s.renderContent()\n dimmedContent := lipgloss.NewStyle().\n Foreground(lipgloss.Color(\"244\")).\n Render(content)\n\n // Overlay config modal\n return lipgloss.JoinVertical(\n lipgloss.Left,\n dimmedContent,\n s.configDisplay.View(),\n )\n}\n```\n\n**This is the easiest fix** - just follow the existing pattern!\n\n## Files to Fix\n\n### High Priority (Fix Background Dimming)\n\n1. **`internal/tui/screens/detail.go`** (line 139-141)\n - Add background dimming for config display modal\n - Follow same pattern as delete confirmation modal\n\n2. **`internal/tui/components/confirm.go`**\n - Note: This component is used by restore screen\n - Restore screen already handles dimming correctly\n - No changes needed\n\n3. **`internal/tui/components/delete-confirm.go`**\n - Note: This component is used by detail screen\n - Detail screen already handles dimming correctly\n - No changes needed\n\n## Implementation Steps\n\n### Step 1: Fix Config Display Modal in detail.go\n\n**Change from:**\n```go\nif s.showConfig \u0026\u0026 s.configDisplay != nil {\n return s.configDisplay.View()\n}\n```\n\n**To:**\n```go\nif s.showConfig \u0026\u0026 s.configDisplay != nil {\n // Render underlying content dimmed\n content := s.renderContent()\n dimmedContent := lipgloss.NewStyle().\n Foreground(lipgloss.Color(\"244\")).\n Render(content)\n\n // Overlay config display modal\n return lipgloss.JoinVertical(\n lipgloss.Left,\n dimmedContent,\n s.configDisplay.View(),\n )\n}\n```\n\n### Step 2: Verify All Modals\n\nCheck that all modals follow consistent pattern:\n1. Delete confirmation modal (detail.go) ✓ Already correct\n2. Config display modal (detail.go) ✗ Needs fix\n3. Restore confirmation modal (restore.go) ✓ Already correct\n\n## Expected Behavior\n\nAfter fix:\n1. Config display modal dims background content (color 244)\n2. Modal is clearly visible on top of dimmed background\n3. User understands they're interacting with a modal\n4. Visual consistency across all modals\n\n## Testing\n\n1. Open client details\n2. Press 'c' to view config\n3. Verify background content is dimmed\n4. Verify modal is clearly visible\n5. Close modal and verify normal view returns\n\n## Dependencies\n\nNone - this is a UI consistency fix\n\n## Priority\n\n**CRITICAL (P0)** - Visual consistency is important for UX","status":"open","priority":0,"issue_type":"bug","owner":"Calmcacil@Raion","created_at":"2026-01-12T22:38:54.028354228+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T22:43:24.402405243+01:00"} {"id":"wg-admin-cwb","title":"Implement input validation functions","description":"Create robust validation functions: validate_client_name() (regex check for [a-zA-Z0-9_-]), validate_ip_availability(), validate_dns_servers(), validate_port_range(), validate_config_syntax(). Add validation before client creation and config changes.","status":"closed","priority":2,"issue_type":"task","owner":"Calmcacil@Raion","created_at":"2026-01-12T16:27:53.143579452+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T16:38:18.705584126+01:00","closed_at":"2026-01-12T16:38:18.705584126+01:00","close_reason":"Implemented all validation functions: validate_client_name(), validate_ip_availability(), validate_dns_servers(), validate_port_range(), validate_config_syntax(). Added validation calls in cmd_add and cmd_load_clients."} {"id":"wg-admin-dd2","title":"Implement client detail view","description":"Create detailed view for selected client showing name, IPs, public key, connection status, last handshake time, and transfer stats. Include copy to clipboard functionality and delete button with confirmation.","status":"closed","priority":2,"issue_type":"task","owner":"Calmcacil@Raion","created_at":"2026-01-12T17:03:30.290544009+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T17:54:27.63729296+01:00","closed_at":"2026-01-12T17:54:27.63729296+01:00","close_reason":"Implemented client detail view in internal/tui/screens/detail.go with all required features: displays client name, IPs, public key, connection status, handshake time, transfer stats; copy to clipboard (press 'c'), delete with confirmation (press 'd'), navigation back (press 'q' or 'esc'); styling with lipgloss in two-column layout; integrated with wireguard.GetClientStatus() for real-time status.","dependencies":[{"issue_id":"wg-admin-dd2","depends_on_id":"wg-admin-wf1","type":"blocks","created_at":"2026-01-12T17:04:52.968940596+01:00","created_by":"Calmcacil"}]} {"id":"wg-admin-ddl","title":"Debug connectivity status showing Disconnected incorrectly","description":"Debug why connectivity status shows 'Disconnected' when client is actually connected. Investigate the finalizePeerStatus logic and the 3-minute threshold for connection status.","status":"closed","priority":1,"issue_type":"bug","owner":"Calmcacil@Raion","created_at":"2026-01-12T19:14:49.564914056+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T19:17:12.292551145+01:00","closed_at":"2026-01-12T19:17:12.292551145+01:00","close_reason":"Fixed q key handling to only quit from list screen, increased connection timeout threshold to 5 minutes"} {"id":"wg-admin-dho","title":"Fix 'q' key to go back to list instead of quitting app","description":"Fix key handling in detail screen so 'q' returns to list instead of quitting the entire application. Currently pressing 'q' in detail view closes the app entirely.","status":"closed","priority":1,"issue_type":"bug","owner":"Calmcacil@Raion","created_at":"2026-01-12T19:14:49.562771127+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T19:17:12.284907523+01:00","closed_at":"2026-01-12T19:17:12.284907523+01:00","close_reason":"Fixed q key handling to only quit from list screen, increased connection timeout threshold to 5 minutes"} {"id":"wg-admin-e07","title":"Implement Dracula color scheme theme","description":"Add Dracula color scheme to the theme registry. Use the official Dracula color palette: Background #282A36, Primary (purple) #BD93F9, Success (green) #50FA7B, Warning (orange) #FFB86C, Error (red) #FF5555, Muted #6272A4.","status":"closed","priority":1,"issue_type":"feature","owner":"Calmcacil@Raion","created_at":"2026-01-12T19:07:40.305419584+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T19:08:50.621690085+01:00","closed_at":"2026-01-12T19:08:50.621690085+01:00","close_reason":"Implemented Dracula and Everforest color schemes and set Everforest as default theme"} +{"id":"wg-admin-ee9","title":"Add text selection and copy capability to terminal UI","description":"# Add Text Selection and Copy Capability to Terminal UI\n\n## Problem\n\nUsers need to copy text from the TUI application, but text selection and copying functionality is limited or non-existent. Users cannot control which text gets selected when dragging over it with the mouse.\n\n## Current State\n\n### Terminal Selection Behavior\n- **Mouse selection is terminal-controlled**: The terminal emulator, not the application, controls text selection\n- **No programmatic control**: Applications can't specify which text is selectable\n- **Selection mode varies**: Different terminals have different selection behavior (word, line, block, etc.)\n- **Copy varies**: Copy mechanism depends on terminal/OS combination\n\n### Current Application Support\n- **No clipboard integration**: The app has no clipboard access library\n- **Removed clipboard feature**: We replaced \"Copy Public Key\" with config display modal\n- **Scrollable modals**: Config display and other modals are scrollable but text can still be selected\n\n## Terminal Limitations\n\n### What We CAN'T Control\n\n1. **Selection boundaries**: Can't specify which text is selectable\n2. **Selection mode**: Can't force word/line/block selection\n3. **Copy action**: Can't programmatically trigger copy\n4. **Selection persistence**: Can't control how long selection persists\n5. **Multi-selection**: Can't control multiple selection regions\n\n### What We CAN Control\n\n1. **Text content**: We control what text is displayed\n2. **Visual highlighting**: We can highlight specific text regions\n3. **Copy buttons**: We can add \"copy\" functionality (but requires clipboard API)\n4. **Alternative outputs**: We can export/save content in other ways\n\n## Proposed Solutions\n\n### Option 1: Add Explicit Copy Buttons (Easiest)\n\nAdd copy buttons in modals that use clipboard API:\n\n**For Config Display Modal:**\n- Add \"[C] Copy Full Config\" action\n- Copy entire config to system clipboard\n- Works over SSH with X11 forwarding if available\n\n**Implementation:**\n```go\n// In ConfigDisplayModel Update()\ncase \"c\", \"C\":\n return m, func() tea.Msg {\n return ConfigCopiedMsg{Content: m.config}\n }\n```\n\n**In Detail Screen:**\n```go\ncase ConfigCopiedMsg:\n // Show feedback\n s.configCopied = true\n```\n\n### Option 2: Add Export Feature\n\nAdd ability to export configuration to file:\n\n**For Config Display Modal:**\n- Add \"[S] Save to File\" action\n- Save config to specified path or default location\n- Useful for manual setup and backups\n\n**Implementation:**\n```go\n// In ConfigDisplayModel Update()\ncase \"s\", \"S\":\n return m, func() tea.Msg {\n err := os.WriteFile(s.configPath, m.config, 0644)\n if err != nil {\n return errMsg{err: err}\n }\n return ConfigSavedMsg{Path: s.configPath}\n }\n```\n\n### Option 3: Add Clipboard Library with SSH Support\n\nUse a clipboard library that works over SSH with X11 forwarding:\n\n**Library Option 1: atotto/clipboard**\n```go\nimport \"github.com/atotto/clipboard\"\n\nfunc (m *ConfigDisplayModel) copyToClipboard() {\n err := clipboard.WriteAll(m.config)\n return err\n}\n```\n\n**Works with:**\n- Local sessions (full clipboard access)\n- SSH with X11 forwarding (ssh -X)\n- WSL sessions (Windows Subsystem for Linux)\n\n**Limitations:**\n- Doesn't work over plain SSH\n- Requires X11 or Wayland server access\n\n### Option 4: Improve Documentation on Terminal Selection\n\nAdd help text explaining how to select and copy text:\n\n**Add to Config Display Modal:**\n```\nHelp: ↑/↓ scroll • g/G top/bottom • Esc to close\n\nCopy Instructions:\n• Drag mouse over text to select (depends on terminal)\n• Copy with terminal-specific shortcut (Ctrl+Shift+C or Cmd+C)\n• Or press [C] to copy to clipboard (if available)\n```\n\n**Platform-specific:**\n- **Linux/WSL**: Ctrl+Shift+C (usually)\n- **macOS**: Cmd+C (in Terminal.app)\n- **Windows**: Click right or use terminal copy feature\n- **SSH**: Depends on local terminal, not remote app\n\n### Option 5: Add Highlighted Text Markers (Advanced)\n\nAllow users to mark/select text for copying:\n\n**Features:**\n- Arrow keys move cursor through text\n- Space key marks/unmarks text position\n- Visual indicators show selected region\n- Option to copy marked text\n\n**Complexity:** High - Requires tracking cursor position and selections\n\n## Recommended Approach\n\n**Start with Option 1 (Explicit Copy Button)**\n\n1. Add clipboard library: `github.com/atotto/clipboard`\n2. Add \"Copy to Clipboard\" action in Config Display Modal\n3. Show confirmation when copy succeeds\n4. Handle errors when clipboard unavailable (gracefully degrade)\n5. Document which platforms support clipboard over SSH\n\n**Then consider Option 2 (Export to File)**\n\n1. Add \"Save to File\" action\n2. Use default path or prompt for path\n3. Show success/error feedback\n4. Useful for backups and manual setup\n\n## Implementation Details\n\n### Add Clipboard Library\n\n**Add to go.mod:**\n```bash\ngo get github.com/atotto/clipboard\n```\n\n**Import:**\n```go\nimport \"github.com/atotto/clipboard\"\n```\n\n### Update ConfigDisplay Component\n\n**Add to ConfigDisplayModel:**\n```go\n// Add field for tracking\nclipboardCopied bool\nclipboardTimer int\n```\n\n**Add to Update() method:**\n```go\ncase \"c\", \"C\":\n // Copy full config to clipboard\n err := clipboard.WriteAll(m.config)\n if err != nil {\n return m, func() tea.Msg {\n return errMsg{err: fmt.Errorf(\"clipboard error: %w\", err)}\n }\n }\n m.clipboardCopied = true\n return m, nil\n```\n\n**Add to View() method:**\n```go\n// Show clipboard confirmation\nif m.clipboardCopied {\n helpText += \"\\n\" + successStyle.Render(\"✓ Configuration copied to clipboard!\")\n}\n```\n\n**Add to help text:**\n```\nHelp: ↑/↓ scroll • g/G top/bottom • [C] Copy to Clipboard • Esc close\n```\n\n## Platform Compatibility\n\n### Clipboard Support\n\n| Platform | Library Support | Notes |\n|----------|----------------|-------|\n| Linux (native) | ✓ Works | X11/Wayland required |\n| WSL | ✓ Works | Windows clipboard access |\n| macOS | ✓ Works | Native macOS clipboard |\n| SSH (plain) | ✗ No | X11 forwarding required |\n| SSH (-X flag) | ✓ Works | Uses local clipboard |\n\n### Workarounds for SSH\n\n**If clipboard doesn't work:**\n1. Use terminal selection (mouse drag)\n2. Use terminal copy shortcut\n3. Export to file instead\n4. Use scp/sftp to copy config files directly\n\n## Files to Modify\n\n1. **`go.mod`** - Add clipboard library dependency\n2. **`internal/tui/components/config-display.go`**\n - Add clipboard copy functionality\n - Add visual feedback for copy\n - Update help text\n3. **`internal/tui/screens/detail.go`**\n - Handle clipboard copied messages\n - Show confirmation feedback\n\n## Success Criteria\n\n1. Press 'C' in config modal copies full config to clipboard (when available)\n2. Visual feedback shows \"✓ Configuration copied to clipboard!\"\n3. Graceful degradation when clipboard unavailable\n4. Works on macOS, Linux, WSL\n5. Documented limitations for SSH sessions\n\n## Dependencies\n\n- `github.com/atotto/clipboard` - Cross-platform clipboard access\n\n## Priority\n\n**MEDIUM (P2)** - Improves UX but workarounds exist (terminal selection)","status":"open","priority":2,"issue_type":"feature","owner":"Calmcacil@Raion","created_at":"2026-01-12T22:38:54.083153165+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T22:43:24.556791119+01:00"} {"id":"wg-admin-ej7","title":"Implement color themes","description":"Add support for color themes using lipgloss. Create default theme with primary, success, warning, and error colors. Support theme switching through config file or environment variable.","status":"closed","priority":2,"issue_type":"task","owner":"Calmcacil@Raion","created_at":"2026-01-12T17:03:30.290145203+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T17:48:32.299616088+01:00","closed_at":"2026-01-12T17:48:32.299616088+01:00","close_reason":"Color themes implemented with Theme package. Three built-in themes (default, dark, light) with ColorScheme support. THEME config option and environment variable support added to config.go. Lipgloss styles use theme colors.","dependencies":[{"issue_id":"wg-admin-ej7","depends_on_id":"wg-admin-xum","type":"blocks","created_at":"2026-01-12T17:04:53.269323117+01:00","created_by":"Calmcacil"}]} {"id":"wg-admin-gp4","title":"Create Go TUI epic","description":"Epic: Convert wg-client-manager bash script to a modern, responsive Go TUI application using Bubble Tea framework. Provides better UX with interactive forms, real-time status updates, and intuitive keyboard navigation.","status":"closed","priority":1,"issue_type":"feature","owner":"Calmcacil@Raion","created_at":"2026-01-12T17:03:30.286393088+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T18:06:58.972856627+01:00","closed_at":"2026-01-12T18:06:58.972856627+01:00","close_reason":"All Go TUI tasks completed across 6 phases:\n\nPhase 1 (Foundation): Project init, config system, TUI skeleton\nPhase 2 (Client List): Parsing, table, real-time status \nPhase 3 (Add Client): Form, key generation, config files\nPhase 4 (Detail/Delete): Detail view, delete functionality, QR codes\nPhase 5 (UX): Search, help screen, color themes\nPhase 6 (Backup/Restore): Backup operations, restore functionality\n\nImplementation details:\n- Total packages added: bubbletea, lipgloss, bubbles, huh, qrterminal\n- Files created: 25+ Go source files\n- All features implemented: CRUD clients, status checking, QR codes, themes, search, backup/restore\n- Build successful with ~6MB binary\n- All tasks closed and synced to remote\n\nApplication ready for testing and deployment."} {"id":"wg-admin-gw9","title":"Add search and filter clients","description":"Implement client search functionality with keyboard shortcut (/). Allow filtering by client name, IP address, or status. Highlight matching results in real-time as user types.","status":"closed","priority":2,"issue_type":"task","owner":"Calmcacil@Raion","created_at":"2026-01-12T17:03:30.285733479+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T18:06:07.246176563+01:00","closed_at":"2026-01-12T18:06:07.246176563+01:00","close_reason":"Search component implemented in internal/tui/components/search.go. Real-time filtering by name, IP, or status with '/' activation. Filter types cycle with Tab. Match count display. Integrated with list screen to dynamically update client table.","dependencies":[{"issue_id":"wg-admin-gw9","depends_on_id":"wg-admin-xum","type":"blocks","created_at":"2026-01-12T17:04:36.200521151+01:00","created_by":"Calmcacil"}]} @@ -47,6 +49,7 @@ {"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":"open","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-12T19:27:21.412723919+01:00"} {"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":"open","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:43:24.23164626+01:00"} {"id":"wg-admin-wf1","title":"Create server and client config files","description":"Generate WireGuard configuration files for both server and client. Server config includes PublicKey and AllowedIPs. Client config includes PrivateKey, Address, DNS, Endpoint, and AllowedIPs. Use atomic writes (temp file + mv).","status":"closed","priority":2,"issue_type":"task","owner":"Calmcacil@Raion","created_at":"2026-01-12T17:03:30.273615688+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T17:50:56.576191666+01:00","closed_at":"2026-01-12T17:50:56.576191666+01:00","close_reason":"Implemented WireGuard config file generation with atomic writes. Added GenerateServerConfig and GenerateClientConfig functions in internal/wireguard/config.go. Both functions use temp file + rename pattern for atomicity and set 0600 permissions.","dependencies":[{"issue_id":"wg-admin-wf1","depends_on_id":"wg-admin-o4o","type":"blocks","created_at":"2026-01-12T17:04:44.268995878+01:00","created_by":"Calmcacil"}]} {"id":"wg-admin-wjj","title":"Implement restore functionality","description":"Add restore capability to load backups from /etc/wg-admin/backups/. Include backup list view, restore confirmation, and pre-restore safety backup. Handle missing backups gracefully.","status":"closed","priority":2,"issue_type":"task","owner":"Calmcacil@Raion","created_at":"2026-01-12T17:03:30.29166861+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T18:06:07.558190874+01:00","closed_at":"2026-01-12T18:06:07.558190874+01:00","close_reason":"Restore functionality implemented in internal/backup/restore.go. ListBackups, RestoreBackup with validation. Restore screen with selectable table. Pre-restore safety backup. ReloadWireGuard integration. Successfully completes Phase 6.","dependencies":[{"issue_id":"wg-admin-wjj","depends_on_id":"wg-admin-11o","type":"blocks","created_at":"2026-01-12T17:04:36.234546234+01:00","created_by":"Calmcacil"}]} {"id":"wg-admin-wmn","title":"Fix parseHandshake to correctly parse compound time expressions","description":"Fix parseHandshake function in status.go to correctly parse compound time expressions like '14 hours, 24 minutes, 40 seconds ago'. Currently only parses first time unit, causing app to show incorrect handshake timing that differs from wg show output.","status":"closed","priority":1,"issue_type":"bug","owner":"Calmcacil@Raion","created_at":"2026-01-12T19:14:02.056632886+01:00","created_by":"Calmcacil","updated_at":"2026-01-12T19:26:35.464413104+01:00","closed_at":"2026-01-12T19:26:35.464413104+01:00","close_reason":"Fixed parseHandshake to correctly parse all time units with number-unit pairing"} diff --git a/internal/tui/screens/detail.go b/internal/tui/screens/detail.go index 8658b29..99b4779 100644 --- a/internal/tui/screens/detail.go +++ b/internal/tui/screens/detail.go @@ -137,7 +137,18 @@ func (s *DetailScreen) Update(msg tea.Msg) (Screen, tea.Cmd) { func (s *DetailScreen) View() string { // Handle config display modal if s.showConfig && s.configDisplay != nil { - return s.configDisplay.View() + // Render underlying content dimmed + content := s.renderContent() + dimmedContent := lipgloss.NewStyle(). + Foreground(lipgloss.Color("244")). + Render(content) + + // Overlay config display modal + return lipgloss.JoinVertical( + lipgloss.Left, + dimmedContent, + s.configDisplay.View(), + ) } // Handle confirmation modal