Files
Nexus-Guard-Suite/.omo/plans/archive/button-consistency.md
T
datadunia cbacfea7f2
NexusGuard CI / server-core-test (push) Failing after 3m6s
NexusGuard CI / server-core-build (push) Has been skipped
NexusGuard CI / device-agent-test (push) Failing after 4s
NexusGuard CI / device-agent-cross-build (amd64, linux) (push) Has been skipped
NexusGuard CI / device-agent-cross-build (amd64, windows) (push) Has been skipped
NexusGuard CI / device-agent-cross-build (arm64, linux) (push) Has been skipped
NexusGuard CI / dashboard-test (push) Failing after 4s
NexusGuard CI / dashboard-dist (push) Has been skipped
chore: update submodule refs, clean up plans/evidence, update .gitignore
2026-06-07 23:53:15 +07:00

16 KiB

Button Consistency Normalization

TL;DR

Quick Summary: Replace all raw <button> elements across the dashboard with NgButton component, normalize sizing/spacing, remove flex-1 stretching, and ensure consistent button patterns everywhere.

Deliverables:

  • All raw <button> replaced with NgButton
  • DeviceDetail.vue buttons de-stretched (no more flex-1)
  • Servers.vue modal buttons use NgButton
  • TrafficHistory.vue buttons + hardcoded colors fixed
  • Consistent button hierarchy: primary/secondary/ghost/danger

Estimated Effort: Quick Parallel Execution: YES - 1 wave Critical Path: All tasks independent, can run in parallel


Context

Original Request

User says: "jadikan semua tombol ini sama. seperti di traffic menu. contoh di view device. tombol besar jelek. tombol diskonek jelen buat semua tombol setara"

Translation: Make all buttons the same. Like in the traffic menu. Example in device view — big ugly buttons, disconnect button looks bad. Make all buttons equal.

Interview Summary

Key Discussions:

  • DeviceDetail.vue has flex-1 buttons that stretch to fill container — visually heavy
  • Multiple views still use raw <button> with hardcoded Tailwind classes instead of NgButton
  • TrafficHistory.vue itself still has hardcoded colors (text-cyan-400, bg-cyan-600, bg-black/30)
  • Inconsistent button patterns: some NgButton, some raw, some with flex-1, some without

Button Hierarchy Standard

Context NgButton Config Rationale
Form submit (Save, Create, Register) variant="primary" size="md" Primary action
Cancel / Close / secondary variant="secondary" size="md" Destructive-neutral
Delete (dangerous) variant="danger" size="md" Destructive
Table row actions (Edit, Config, Firewall) variant="ghost" size="sm" Inline, low visual weight
Small utility (Copy, Refresh) size="sm" Compact
Action button row gap-2 NOT space-x-3 OR flex-1 Consistent spacing

Work Objectives

Core Objective

Make every button in the dashboard use NgButton with consistent sizing, spacing, and variant hierarchy.

Concrete Deliverables

  • apps/dashboard-ui/src/views/DeviceDetail.vue — buttons de-stretched
  • apps/dashboard-ui/src/views/Servers.vue — modal buttons use NgButton
  • apps/dashboard-ui/src/views/Users.vue — delete button uses NgButton
  • apps/dashboard-ui/src/views/Devices.vue — action buttons use NgButton
  • apps/dashboard-ui/src/views/TrafficHistory.vue — buttons use NgButton + design tokens
  • apps/dashboard-ui/src/App.vue — logout button uses NgButton

Must Have

  • Zero raw <button> with hardcoded Tailwind classes (except toggle switches and accordion chevrons)
  • All action buttons use NgButton with appropriate variant/size
  • No flex-1 on button rows (causes ugly stretching)
  • Consistent gap-2 spacing between button groups

Must NOT Have (Guardrails)

  • Do NOT change NgButton component itself
  • Do NOT change any API calls or data flow
  • Do NOT change toggle switches (they're custom CSS, not buttons)
  • Do NOT change accordion chevron toggles (functional, not action buttons)
  • Do NOT touch Login.vue (already redesigned)
  • Do NOT touch FirewallEditor.vue (already redesigned)

Verification Strategy

ZERO HUMAN INTERVENTION - ALL verification is agent-executed.

QA Policy

Every task includes agent-executed QA scenarios. Evidence saved to .sisyphus/evidence/task-{N}-{scenario-slug}.{ext}.

  • Frontend/UI: Build check via npm run build
  • Grep checks: Verify zero raw <button class= patterns (excluding known exceptions)

Execution Strategy

Parallel Execution Waves

Wave 1 (Start Immediately — all independent):
├── Task 1: Normalize DeviceDetail.vue buttons [quick]
├── Task 2: Normalize Servers.vue modal buttons [quick]
├── Task 3: Normalize Users.vue delete button [quick]
├── Task 4: Normalize Devices.vue action buttons [quick]
├── Task 5: Normalize TrafficHistory.vue buttons + tokens [quick]
├── Task 6: Normalize App.vue logout button [quick]

Wave FINAL (After ALL tasks):
├── Build verify: npm run build
├── Grep verify: zero raw button patterns
└── Present results to user

Dependency Matrix

  • All tasks (1-6): No dependencies — can all run in parallel
  • Final verification: After all tasks complete

TODOs

  • 1. Normalize DeviceDetail.vue buttons

    What to do:

    • Line 93: Keep w-full on save settings button (it's inside a form, full-width is correct)
    • Lines 114-124: Remove flex-1 from all 3 action buttons (Regenerate Token, Regenerate Keys, Delete Device). Change flex space-x-3 to flex items-center gap-2
    • Lines 141-145: Remove flex-1 from Config & QR button. Remove the wrapping <div class="flex space-x-3"> since it's a single button — just use <NgButton> directly
    • Line 153: Copy token button already size="sm" — OK
    • Line 187: Refresh button already size="sm" — OK

    Must NOT do:

    • Do NOT change the save settings w-full (form submit, full-width is correct)
    • Do NOT change toggle switches or accordion chevrons

    Recommended Agent Profile:

    • Category: quick
    • Skills: []

    Parallelization:

    • Can Run In Parallel: YES
    • Parallel Group: Wave 1 (with Tasks 2-6)
    • Blocks: Final verification
    • Blocked By: None

    References:

    • apps/dashboard-ui/src/views/DeviceDetail.vue — Lines 114-124 (action buttons), 141-145 (config button)
    • apps/dashboard-ui/src/components/ui/NgButton.vue — API: variant, size, loading, disabled

    Acceptance Criteria:

    QA Scenarios:

    Scenario: No flex-1 on NgButton in DeviceDetail
      Tool: Bash
      Steps:
        1. Run: grep "flex-1" apps/dashboard-ui/src/views/DeviceDetail.vue
      Expected Result: 0 matches
      Evidence: .sisyphus/evidence/task-1-no-flex1.txt
    
    Scenario: Build succeeds
      Tool: Bash
      Steps:
        1. Run: cd apps/dashboard-ui && npm run build
      Expected Result: Exit code 0
      Evidence: .sisyphus/evidence/task-1-build.txt
    

    Commit: YES (groups with 2-6)


  • 2. Normalize Servers.vue modal buttons

    What to do:

    • Line 127: <button type="submit" ... class="flex-1 bg-accent ...">Register Node</button><NgButton type="submit" :loading="loading">Register Node</NgButton>
    • Line 128: <button type="button" @click="showAddModal = false" ... class="flex-1 bg-bg-elevated ...">Cancel</button><NgButton variant="secondary" @click="showAddModal = false">Cancel</NgButton>
    • Line 281: <button type="submit" ... class="flex-1 bg-accent ...">Save</button><NgButton type="submit" :loading="loading">Save</NgButton>
    • Line 282: <button type="button" @click="closeEdit" ... class="flex-1 bg-bg-elevated ...">Cancel</button><NgButton variant="secondary" @click="closeEdit">Cancel</NgButton>
    • Button rows in modals: wrap in <div class="flex items-center gap-2 pt-4">
    • Lines 156-157: Table action buttons (Edit, Delete) → NgButton variant="ghost" size="sm"

    Must NOT do:

    • Do NOT change form inputs or validation logic
    • Do NOT change toggle switches

    Recommended Agent Profile:

    • Category: quick
    • Skills: []

    Parallelization:

    • Can Run In Parallel: YES
    • Parallel Group: Wave 1 (with Tasks 1, 3-6)
    • Blocks: Final verification
    • Blocked By: None

    References:

    • apps/dashboard-ui/src/views/Servers.vue — Lines 127-128 (add modal buttons), 156-157 (table actions), 281-282 (edit modal buttons)

    Acceptance Criteria:

    QA Scenarios:

    Scenario: No raw button in Servers modal
      Tool: Bash
      Steps:
        1. Run: grep -n '<button' apps/dashboard-ui/src/views/Servers.vue | grep -v 'NgButton' | grep -v 'toggle' | grep -v 'chevron' | grep -v 'accordion'
      Expected Result: 0 matches (excluding toggle/accordion)
      Evidence: .sisyphus/evidence/task-2-no-raw-button.txt
    
    Scenario: Build succeeds
      Tool: Bash
      Steps:
        1. Run: cd apps/dashboard-ui && npm run build
      Expected Result: Exit code 0
      Evidence: .sisyphus/evidence/task-2-build.txt
    

    Commit: YES (groups with 1, 3-6)


  • 3. Normalize Users.vue delete button

    What to do:

    • Line 51: <button v-if="user.Username !== 'admin'" @click="handleDelete(user.ID)" class="text-danger hover:text-danger text-sm font-semibold">Delete</button><NgButton v-if="user.Username !== 'admin'" variant="ghost" size="sm" @click="handleDelete(user.ID)">Delete</NgButton>
    • Import NgButton if not already imported (it is — line 67)

    Must NOT do:

    • Do NOT change the delete confirmation logic

    Recommended Agent Profile:

    • Category: quick
    • Skills: []

    Parallelization:

    • Can Run In Parallel: YES
    • Parallel Group: Wave 1 (with Tasks 1-2, 4-6)
    • Blocks: Final verification
    • Blocked By: None

    References:

    • apps/dashboard-ui/src/views/Users.vue — Line 51

    Acceptance Criteria:

    QA Scenarios:

    Scenario: No raw button in Users
      Tool: Bash
      Steps:
        1. Run: grep -n '<button' apps/dashboard-ui/src/views/Users.vue | grep -v 'NgButton'
      Expected Result: 0 matches
      Evidence: .sisyphus/evidence/task-3-no-raw-button.txt
    
    Scenario: Build succeeds
      Tool: Bash
      Steps:
        1. Run: cd apps/dashboard-ui && npm run build
      Expected Result: Exit code 0
      Evidence: .sisyphus/evidence/task-3-build.txt
    

    Commit: YES (groups with 1-2, 4-6)


  • 4. Normalize Devices.vue action buttons

    What to do:

    • Lines 45-47: Replace raw <button> with NgButton variant="ghost" size="sm":
      <NgButton v-if="device.InternalIP && authStore.isAdmin" variant="ghost" size="sm" @click="openConfigModal(device.ID)">Config</NgButton>
      <NgButton variant="ghost" size="sm" @click="openFirewall(device.ID)">Firewall</NgButton>
      <NgButton variant="ghost" size="sm" @click="handleDelete(device.ID, device.Name)">Delete</NgButton>
      
    • Import NgButton if not already imported (it is — line 78)

    Must NOT do:

    • Do NOT change the delete confirmation logic

    Recommended Agent Profile:

    • Category: quick
    • Skills: []

    Parallelization:

    • Can Run In Parallel: YES
    • Parallel Group: Wave 1 (with Tasks 1-3, 5-6)
    • Blocks: Final verification
    • Blocked By: None

    References:

    • apps/dashboard-ui/src/views/Devices.vue — Lines 45-47

    Acceptance Criteria:

    QA Scenarios:

    Scenario: No raw button in Devices
      Tool: Bash
      Steps:
        1. Run: grep -n '<button' apps/dashboard-ui/src/views/Devices.vue | grep -v 'NgButton'
      Expected Result: 0 matches
      Evidence: .sisyphus/evidence/task-4-no-raw-button.txt
    
    Scenario: Build succeeds
      Tool: Bash
      Steps:
        1. Run: cd apps/dashboard-ui && npm run build
      Expected Result: Exit code 0
      Evidence: .sisyphus/evidence/task-4-build.txt
    

    Commit: YES (groups with 1-3, 5-6)


  • 5. Normalize TrafficHistory.vue buttons + hardcoded colors

    What to do:

    • Import NgButton and useToast/useConfirm if needed
    • Line 5-11: Export CSV button → <NgButton @click="exportToCSV" :disabled="trafficData.length === 0">Export CSV</NgButton>
    • Lines 53-59: Apply Filters button → <NgButton type="submit" :loading="loading">{{ loading ? 'Loading...' : 'Apply Filters' }}</NgButton>
    • Lines 110-116: Previous button → <NgButton size="sm" @click="currentPage--" :disabled="currentPage === 1">Previous</NgButton>
    • Lines 118-124: Next button → <NgButton size="sm" @click="currentPage++" :disabled="currentPage >= totalPages">Next</NgButton>
    • Replace ALL hardcoded colors with design tokens:
      • text-cyan-400text-accent
      • bg-cyan-600bg-accent
      • bg-black/30bg-bg-base/30
      • border-white/5border-border-subtle/50
      • text-gray-400text-text-muted
      • text-gray-500text-text-muted
      • bg-gradient-to-br from-gray-900/90 to-gray-800/90bg-gradient-to-br from-bg-surface/90 to-bg-elevated/90
      • border-white/10border-border-subtle
      • text-whitetext-text-primary
      • bg-black/50bg-bg-base/50
      • hover:bg-white/5hover:bg-bg-elevated/50
      • hover:bg-black/50hover:bg-bg-base/50
      • hover:text-whitehover:text-text-primary
      • text-cyan-400text-accent
      • text-blue-400text-info
      • hover:shadow-cyan-500/50hover:shadow-accent/50
    • Update <NgButton> import

    Must NOT do:

    • Do NOT change the CSV export logic
    • Do NOT change the pagination logic
    • Do NOT change the date filtering logic

    Recommended Agent Profile:

    • Category: quick
    • Skills: []

    Parallelization:

    • Can Run In Parallel: YES
    • Parallel Group: Wave 1 (with Tasks 1-4, 6)
    • Blocks: Final verification
    • Blocked By: None

    References:

    • apps/dashboard-ui/src/views/TrafficHistory.vue — Full file (326 lines). Raw buttons + extensive hardcoded colors
    • apps/dashboard-ui/src/components/ui/NgButton.vue — API reference

    Acceptance Criteria:

    QA Scenarios:

    Scenario: No raw button in TrafficHistory
      Tool: Bash
      Steps:
        1. Run: grep -n '<button' apps/dashboard-ui/src/views/TrafficHistory.vue | grep -v 'NgButton'
      Expected Result: 0 matches
      Evidence: .sisyphus/evidence/task-5-no-raw-button.txt
    
    Scenario: No hardcoded colors
      Tool: Bash
      Steps:
        1. Run: grep -cE "text-cyan-|bg-cyan-|bg-black|border-white/|text-gray-|text-blue-|hover:bg-white" apps/dashboard-ui/src/views/TrafficHistory.vue
      Expected Result: 0 matches
      Evidence: .sisyphus/evidence/task-5-no-hardcoded.txt
    
    Scenario: Build succeeds
      Tool: Bash
      Steps:
        1. Run: cd apps/dashboard-ui && npm run build
      Expected Result: Exit code 0
      Evidence: .sisyphus/evidence/task-5-build.txt
    

    Commit: YES (groups with 1-4, 6)


  • 6. Normalize App.vue logout button

    What to do:

    • Line 16: <button @click="authStore.logout" class="w-full text-left px-4 py-2 text-sm text-red-400 hover:bg-red-500/10 rounded-lg transition">Logout</button><NgButton variant="ghost" @click="authStore.logout" class="w-full justify-start">Logout</NgButton>
    • Line 24: <button @click="authStore.logout" class="text-red-400 text-sm">Logout</button><NgButton variant="ghost" size="sm" @click="authStore.logout">Logout</NgButton>
    • Import NgButton

    Must NOT do:

    • Do NOT change the logout logic
    • Do NOT change sidebar behavior

    Recommended Agent Profile:

    • Category: quick
    • Skills: []

    Parallelization:

    • Can Run In Parallel: YES
    • Parallel Group: Wave 1 (with Tasks 1-5)
    • Blocks: Final verification
    • Blocked By: None

    References:

    • apps/dashboard-ui/src/App.vue — Lines 16, 24

    Acceptance Criteria:

    QA Scenarios:

    Scenario: No raw button in App.vue
      Tool: Bash
      Steps:
        1. Run: grep -n '<button' apps/dashboard-ui/src/App.vue | grep -v 'NgButton'
      Expected Result: 0 matches
      Evidence: .sisyphus/evidence/task-6-no-raw-button.txt
    
    Scenario: Build succeeds
      Tool: Bash
      Steps:
        1. Run: cd apps/dashboard-ui && npm run build
      Expected Result: Exit code 0
      Evidence: .sisyphus/evidence/task-6-build.txt
    

    Commit: YES (groups with 1-5)


Final Verification Wave

After ALL tasks complete:

Wave FINAL:
├── F1: Build verify — npm run build passes
├── F2: Grep verify — zero raw <button class= across all .vue files
├── F3: Grep verify — zero hardcoded colors in TrafficHistory.vue
└── F4: Present results to user

Commit Strategy

  • Commit D: All button normalization changes
    • Files: DeviceDetail.vue, Servers.vue, Users.vue, Devices.vue, TrafficHistory.vue, App.vue
    • Pre-commit: cd apps/dashboard-ui && npm run build

Success Criteria

Verification Commands

cd apps/dashboard-ui && npm run build  # Expected: ✓ built in Xs
grep -rn '<button' src/ --include="*.vue" | grep -v 'NgButton' | grep -v 'toggle' | grep -v 'chevron' | grep -v 'sr-only'  # Expected: 0 matches (excluding known exceptions)
grep -cE "text-cyan-|bg-cyan-|bg-black|border-white/" src/views/TrafficHistory.vue  # Expected: 0

Final Checklist

  • All raw <button> replaced with NgButton
  • No flex-1 on button rows
  • Consistent gap-2 spacing
  • TrafficHistory.vue hardcoded colors replaced with tokens
  • Frontend builds without errors