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 && (
+
+ >
);
}
diff --git a/apps/web/src/routes/settings/health.tsx b/apps/web/src/routes/settings/health.tsx
index ca62c0f..be96ca7 100644
--- a/apps/web/src/routes/settings/health.tsx
+++ b/apps/web/src/routes/settings/health.tsx
@@ -1,9 +1,13 @@
+import { useState } from 'react'
import { createFileRoute } from '@tanstack/react-router'
import {
CheckCircle2,
XCircle,
RefreshCw,
Server,
+ Plus,
+ RotateCcw,
+ Loader2,
} from 'lucide-react'
import { toast } from 'sonner'
import { trpc } from '@/lib/trpc'
@@ -11,6 +15,8 @@ import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Skeleton } from '@/components/Skeleton'
import { AccountCard } from '@/components/AccountCard'
+import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@/components/ui/tooltip'
+import { AddAccountDialog } from '@/components/AddAccountDialog'
export const Route = createFileRoute('/settings/health')({
component: HealthCheckPage,
@@ -45,7 +51,23 @@ function HealthCheckPage() {
},
})
- const { data, isLoading, isError, error, refetch } = healthQuery
+ const [addAccountOpen, setAddAccountOpen] = useState(false)
+
+ const refreshAccounts = trpc.refreshAccounts.useMutation({
+ onSuccess: (data) => {
+ const msg =
+ data.cleared === 0
+ ? 'No expired flags to clear.'
+ : `Cleared ${data.cleared} expired exhaustion flag(s).`
+ toast.success(msg)
+ void utils.systemHealthCheck.invalidate()
+ },
+ onError: (err) => {
+ toast.error(`Failed to refresh: ${err.message}`)
+ },
+ })
+
+ const { data, isLoading, isError, refetch } = healthQuery
// Loading state
if (isLoading) {
@@ -61,24 +83,9 @@ function HealthCheckPage() {
)
}
- // Error state
- if (isError) {
- return (
-
-
-
- Failed to load health check: {error?.message ?? 'Unknown error'}
-
-
-
- )
- }
-
- 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() {
))
)}
+
+
)
}