# Updates Page Component Structure ## Visual Hierarchy ``` Updates Page ├── Header Section │ ├── Title: "Agent Updates" │ ├── Subtitle: "Manage agent version rollouts..." │ └── Refresh Button (with spinner) │ └── Rollouts Card ├── Card Header │ └── Title: "Rollouts" │ └── Card Content ├── Loading State (spinner + "Loading rollouts...") ├── Error State (error icon + message + retry button) ├── Empty State ("No rollouts yet...") │ └── Rollouts Table ├── Table Header │ ├── Version │ ├── OS / Arch │ ├── Channel │ ├── Health │ ├── Success Rate │ ├── Beta Agents │ ├── Stable Agents │ └── Actions │ └── Table Body (for each rollout) ├── Version (monospace) ├── OS / Arch (gray text) ├── Channel Badge (blue/purple) ├── Health Badge (green/yellow/red/gray) ├── Success Rate (colored %) ├── Beta Count ├── Stable Count └── Action Buttons ├── Promote Button (arrow up) └── Rollback Button (rotate ccw) ``` ## Component Breakdown ### Main Component: `Updates` - State Management: - `rollouts` - Array of rollout data - `isLoading` - Loading state - `error` - Error message - `promoteDialog` - Promote dialog state - `rollbackDialog` - Rollback dialog state - Effects: - Initial data fetch - 30-second auto-refresh - Mutations: - `promoteMutation` - Handles promotion with force option - `rollbackMutation` - Handles rollback with reason ### Sub-Components #### `HealthStatusBadge` Props: `{ status: string }` Variants: - healthy → green + CheckCircle - warning → yellow + AlertTriangle - critical → red + AlertCircle - blocked → dark red + X - unknown → gray (no icon) #### `ChannelBadge` Props: `{ channel: string }` Variants: - beta → blue badge - stable → purple badge #### `PromoteDialog` Props: - `rollout` - Rollout to promote - `onClose` - Close handler - `onConfirm` - Confirm with force flag - `isLoading` - Loading state - `showForceOption` - Show force promote option Features: - Normal promotion flow - Force promotion flow (after 403) - Warning message for force promote #### `RollbackDialog` Props: - `rollout` - Rollout to rollback - `onClose` - Close handler - `onConfirm` - Confirm with reason - `isLoading` - Loading state Features: - Required reason text input - Warning about force-downgrade - Disabled confirm until reason entered ## Data Flow ``` ┌─────────────────┐ │ Initial Load │ └────────┬────────┘ │ ▼ ┌─────────────────────────────┐ │ fetchRollouts() │ │ GET /api/updates/rollouts │ └────────┬────────────────────┘ │ ▼ ┌────────────────────┐ ┌──────────────────┐ │ setRollouts() │◄─────┤ Auto-refresh │ │ setIsLoading() │ │ (every 30s) │ └────────────────────┘ └──────────────────┘ User Action: Promote ┌─────────────────────┐ │ Click Promote Btn │ └────────┬────────────┘ │ ▼ ┌───────────────────────┐ │ Open Promote Dialog │ └────────┬──────────────┘ │ ▼ ┌──────────────────────────────────────┐ │ User Confirms │ │ POST /api/updates/rollouts/promote │ └────────┬─────────────────────────────┘ │ ├──► Success │ ├─► Show success toast │ ├─► Close dialog │ ├─► Refresh rollouts │ └─► Invalidate agent cache │ └──► 403 (Health Failed) ├─► Show force promote dialog └─► User can force promote User Action: Rollback ┌──────────────────────┐ │ Click Rollback Btn │ └────────┬─────────────┘ │ ▼ ┌────────────────────────┐ │ Open Rollback Dialog │ │ User enters reason │ └────────┬───────────────┘ │ ▼ ┌───────────────────────────────────────┐ │ User Confirms │ │ POST /api/updates/rollouts/rollback │ └────────┬──────────────────────────────┘ │ ├──► Success │ ├─► Show toast with agent count │ ├─► Close dialog │ ├─► Refresh rollouts │ └─► Invalidate agent cache │ └──► Error └─► Show error toast ``` ## API Contract ### GET /api/updates/rollouts Response: `RolloutInfo[]` ```json [ { "version": "0.6.27", "os": "windows", "arch": "x86_64", "channel": "beta", "health": { "status": "healthy", "total_attempts": 50, "success_count": 48, "failure_count": 2, "crash_count": 0 }, "beta_agent_count": 15, "stable_agent_count": 230, "created_at": "2026-05-24T10:30:00Z" } ] ``` ### POST /api/updates/rollouts/:version/promote Request: ```json { "os": "windows", "arch": "x86_64", "force": false } ``` Response (200): ```json { "message": "Version 0.6.27 promoted to stable" } ``` Response (403 - Health Check Failed): ```json { "error": "Health check failed: crash rate too high" } ``` ### POST /api/updates/rollouts/:version/rollback Request: ```json { "os": "windows", "arch": "x86_64", "reason": "Critical bug causing memory leaks" } ``` Response: ```json { "message": "Version 0.6.27 rolled back", "agents_downgraded": 15 } ``` ## Styling Classes ### Color Coding - Success rates: - >= 95%: `text-green-600 dark:text-green-400` - >= 80%: `text-yellow-600 dark:text-yellow-400` - < 80%: `text-red-600 dark:text-red-400` ### Badge Variants - Green (healthy): `bg-green-500/15 text-green-600 dark:text-green-400` - Yellow (warning): `bg-yellow-500/15 text-yellow-700 dark:text-yellow-400` - Red (critical/error): `bg-red-500/15 text-red-600 dark:text-red-400` - Blue (beta): `bg-blue-500/15 text-blue-600 dark:text-blue-400` - Purple (stable): `bg-purple-500/15 text-purple-600 dark:text-purple-400` ### Table Styling - Header: `border-b border-[hsl(var(--border))]` - Row hover: `hover:bg-[hsl(var(--muted))]/50` - Monospace font: `font-mono text-sm` ## Accessibility Features - Semantic HTML (table, th, td) - Button tooltips for disabled states - Dialog aria-labels (via Radix UI) - Loading states announced - Error states with retry option - Required field indicators (*) on forms - Focus management in dialogs - Keyboard navigation support ## Responsive Design - Table container with horizontal scroll - Card layout adapts to screen size - Dialog responsive (max-w-lg) - Mobile-friendly button spacing - Text wrapping for long content ## Error Handling - Network errors → error state with retry - 403 on promote → show force option - Empty rollouts → empty state message - Loading timeout → error state - Mutation errors → toast notification