From a94e72ccbc10f499073bc6cbfe2baa1250f69d40 Mon Sep 17 00:00:00 2001 From: Lukas May Date: Fri, 6 Mar 2026 13:35:14 +0100 Subject: [PATCH] feat: Wire AddAccountDialog and UpdateCredentialsDialog into health page and AccountCard - health.tsx: Add Account button + AddAccountDialog, Refresh button with tooltip and spinner calling refreshAccounts mutation, inline account error state instead of full-page error, updated empty state text, and active-agent warning on delete confirm - AccountCard.tsx: Show KeyRound button when credentials/token invalid, opens UpdateCredentialsDialog pre-populated with account identity Co-Authored-By: Claude Sonnet 4.6 --- apps/web/src/components/AccountCard.tsx | 23 +++- apps/web/src/routes/settings/health.tsx | 151 ++++++++++++++++-------- 2 files changed, 125 insertions(+), 49 deletions(-) diff --git a/apps/web/src/components/AccountCard.tsx b/apps/web/src/components/AccountCard.tsx index 5ec5bf0..2912dd3 100644 --- a/apps/web/src/components/AccountCard.tsx +++ b/apps/web/src/components/AccountCard.tsx @@ -1,7 +1,9 @@ -import { CheckCircle2, XCircle, AlertTriangle, Trash2 } from "lucide-react"; +import { useState } from "react"; +import { CheckCircle2, XCircle, AlertTriangle, Trash2, KeyRound } from "lucide-react"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; +import { UpdateCredentialsDialog } from "./UpdateCredentialsDialog"; function formatResetTime(isoDate: string): string { const now = Date.now(); @@ -100,6 +102,7 @@ export function AccountCard({ account: AccountData; onDelete?: (e: React.MouseEvent) => void; }) { + const [updateCredOpen, setUpdateCredOpen] = useState(false); const hasWarning = account.credentialsValid && !account.isExhausted && account.error; const statusIcon = !account.credentialsValid ? ( @@ -123,6 +126,7 @@ export function AccountCard({ const usage = account.usage; return ( + <> {/* Header row */} @@ -147,6 +151,17 @@ export function AccountCard({ {statusText} + {(!account.credentialsValid || !account.tokenValid) && ( + + )} {onDelete && ( - - ) - } - - if (!data) return null - - const { server, accounts, projects } = data + const server = data?.server + const accounts = data?.accounts ?? [] + const projects = data?.projects ?? [] return (
@@ -95,37 +102,76 @@ function HealthCheckPage() {
{/* Server Status */} - - - - - Server Status - - - -
- -
-

Running

-

- Uptime: {formatUptime(server.uptime)} - {server.startedAt && ( - <> - {' '} - · Started{' '} - {new Date(server.startedAt).toLocaleString()} - - )} -

+ {server && ( + + + + + Server Status + + + +
+ +
+

Running

+

+ Uptime: {formatUptime(server.uptime)} + {server.startedAt && ( + <> + {' '} + · Started{' '} + {new Date(server.startedAt).toLocaleString()} + + )} +

+
-
- - + + + )} {/* Accounts */}
-

Accounts

- {accounts.length === 0 ? ( +
+

Accounts

+
+ + + + + + Clear expired exhaustion flags + + + +
+
+ {isError ? ( + + +

+ Could not load account status. Retrying… +

+
+
+ ) : accounts.length === 0 ? (

@@ -133,7 +179,7 @@ function HealthCheckPage() { cw account add {' '} - to register one. + to register one, or click 'Add Account' above.

@@ -143,7 +189,14 @@ function HealthCheckPage() { key={account.id} account={account} onDelete={(e) => { - if (e.shiftKey || window.confirm(`Remove account "${account.email}"?`)) { + if ( + e.shiftKey || + (account.activeAgentCount > 0 + ? window.confirm( + `This account has ${account.activeAgentCount} active agent(s). Deleting it will not stop those agents but they will lose their account association. Continue?` + ) + : window.confirm(`Remove account "${account.email}"?`)) + ) { removeAccount.mutate({ id: account.id }) } }} @@ -186,6 +239,8 @@ function HealthCheckPage() { )) )}
+ +
) }