From f9dbb30a4e73aa3cf6177452c0baceeca7f1bc32 Mon Sep 17 00:00:00 2001 From: Renn F Date: Wed, 15 Jul 2026 18:04:00 +0200 Subject: [PATCH] =?UTF-8?q?feat(panel):=20dense=20tooltip=20pass=20?= =?UTF-8?q?=E2=80=94=20org=20surfaces=20+=20layout=20chrome=20(253=20tips)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every sidebar destination, metric derivation, sortable column, queue action, and dialog control explains itself; mobile tab bar shares the sidebar's descriptions so the two nav surfaces can't drift. --- panel/src/app/(dashboard)/a2a/page.tsx | 54 +++--- .../app/(dashboard)/agents/[agentId]/page.tsx | 139 +++++++------ panel/src/app/(dashboard)/agents/page.tsx | 5 + .../(dashboard)/journals/[entryId]/page.tsx | 18 +- panel/src/app/(dashboard)/journals/page.tsx | 21 +- panel/src/app/(dashboard)/metrics/page.tsx | 91 ++++++--- .../components/a2a/a2a-connection-badge.tsx | 30 +-- panel/src/components/a2a/a2a-context-pane.tsx | 56 +++--- .../components/a2a/a2a-conversation-list.tsx | 65 ++++--- panel/src/components/a2a/a2a-filter-bar.tsx | 168 +++++++++------- panel/src/components/a2a/a2a-pair-card.tsx | 18 +- .../src/components/a2a/a2a-reply-composer.tsx | 29 +-- panel/src/components/a2a/a2a-switchboard.tsx | 15 +- panel/src/components/a2a/a2a-transcript.tsx | 52 ++--- .../agents/agent-activity-panel.tsx | 39 ++-- panel/src/components/agents/agent-card.tsx | 70 ++++--- panel/src/components/agents/agent-grid.tsx | 21 +- .../src/components/agents/agent-selector.tsx | 47 +++-- .../components/agents/agent-status-cards.tsx | 48 +++-- .../components/agents/resolve-wait-dialog.tsx | 37 ++-- .../components/agents/spawn-agent-dialog.tsx | 37 ++-- panel/src/components/agents/stream-viewer.tsx | 17 +- .../agents/waiting-agents-alert.tsx | 31 +-- .../components/auditor/auditor-dashboard.tsx | 27 ++- .../components/auditor/create-flag-dialog.tsx | 57 ++++-- .../auditor/findings-queue-panel.tsx | 58 +++--- panel/src/components/auditor/flagged-item.tsx | 68 ++++--- .../auditor/flagged-items-panel.tsx | 43 ++-- .../auditor/quality-metrics-panel.tsx | 10 +- .../src/components/auditor/reports-panel.tsx | 88 +++++---- .../dashboard/active-blockers-panel.tsx | 44 +++-- .../components/dashboard/activity-item.tsx | 23 ++- .../dashboard/auditor-alerts-panel.tsx | 51 +++-- .../dashboard/ceo-approval-queue.tsx | 84 ++++---- .../components/dashboard/command-center.tsx | 13 +- .../dashboard/key-metrics-panel.tsx | 4 +- .../dashboard/playbook-review-queue.tsx | 73 ++++--- .../components/dashboard/pr-review-queue.tsx | 65 ++++--- .../dashboard/quick-actions-bar.tsx | 51 +++-- .../dashboard/recent-activity-feed.tsx | 21 +- .../dashboard/release-proposal-card.tsx | 84 +++++--- .../dashboard/roadmap-review-queue.tsx | 58 +++--- .../dashboard/scorecard-overview-panel.tsx | 18 +- .../dashboard/social-summary-card.tsx | 31 ++- .../dashboard/strategy-signals-panel.tsx | 19 +- .../components/dashboard/team-health-card.tsx | 50 ++--- .../dashboard/usage-overview-panel.tsx | 10 +- .../components/dashboard/video-post-queue.tsx | 20 +- .../src/components/dashboard/x-post-queue.tsx | 20 +- panel/src/components/journals/agent-item.tsx | 8 +- panel/src/components/journals/agent-list.tsx | 17 +- panel/src/components/journals/entry-card.tsx | 34 ++-- .../src/components/journals/entry-filter.tsx | 43 ++-- .../components/journals/entry-type-badge.tsx | 18 +- .../components/journals/growth-summary.tsx | 92 +++++---- .../src/components/journals/journal-view.tsx | 21 +- .../src/components/layout/bottom-tab-bar.tsx | 35 ++-- panel/src/components/layout/header.tsx | 25 ++- panel/src/components/layout/sidebar.tsx | 183 +++++++++++++----- .../components/metrics/model-usage-donut.tsx | 5 +- .../src/components/metrics/sessions-table.tsx | 98 +++++++--- .../components/metrics/task-status-chart.tsx | 5 +- .../metrics/usage-time-series-chart.tsx | 5 +- 63 files changed, 1770 insertions(+), 1017 deletions(-) diff --git a/panel/src/app/(dashboard)/a2a/page.tsx b/panel/src/app/(dashboard)/a2a/page.tsx index ad546dc4..1c49e49d 100644 --- a/panel/src/app/(dashboard)/a2a/page.tsx +++ b/panel/src/app/(dashboard)/a2a/page.tsx @@ -310,15 +310,17 @@ function A2APageContent() { <> {/* Mobile-only back affordance — drills back up to the list. */} {onDetailLevel && ( - + + + )}
@@ -423,21 +425,25 @@ function A2APageContent() { {" ↔ "} {getAgentDisplayName(selected.agent_b)} - - {selected.status} - - - {selected.message_count} msgs · updated{" "} - {formatDistanceToNow(new Date(selected.updated_at))}{" "} - ago - + + + {selected.status} + + + + + {selected.message_count} msgs · updated{" "} + {formatDistanceToNow(new Date(selected.updated_at))}{" "} + ago + +
)} {/* Scoped to the stream pane, not a full-page takeover — diff --git a/panel/src/app/(dashboard)/agents/[agentId]/page.tsx b/panel/src/app/(dashboard)/agents/[agentId]/page.tsx index 5d5abd54..61518acc 100644 --- a/panel/src/app/(dashboard)/agents/[agentId]/page.tsx +++ b/panel/src/app/(dashboard)/agents/[agentId]/page.tsx @@ -19,6 +19,7 @@ import { } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Skeleton } from "@/components/ui/skeleton"; +import { HelpTip } from "@/components/ui/help-tip"; import { ArrowLeft, Play, @@ -118,10 +119,12 @@ export default function AgentDetailPage() { if (isInvalidAgent) { return (
- + + +
@@ -131,16 +134,20 @@ export default function AgentDetailPage() {

The agent may not be running or the ID is invalid.

- - - Spawn Agent - - } - /> + + + + + Spawn Agent + + } + /> + +
@@ -172,47 +179,61 @@ export default function AgentDetailPage() { {displayName} {roleLabel && ( - - - {roleLabel} - + + + + {roleLabel} + + )} {teamLabel && ( - - - {teamLabel} - + + + + {teamLabel} + + )}
-

- {agentId !== displayName ? `@${agentId}` : "Agent Details"} -

+ +

+ {agentId !== displayName ? `@${agentId}` : "Agent Details"} +

+
{isWaiting && } {isActive ? ( <> - - + + + + + + ) : ( - - - Spawn - - } - /> + + + + + Spawn + + } + /> + + )}
@@ -245,16 +266,20 @@ export default function AgentDetailPage() { Live status is unavailable — this agent isn't currently active. Spawn it to see live state.

- - - Spawn Agent - - } - /> + + + + + Spawn Agent + + } + /> + + ) : agent ? ( @@ -287,9 +312,11 @@ export default function AgentDetailPage() { -

- {agent.error_count} error(s) -

+ +

+ {agent.error_count} error(s) +

+
)} diff --git a/panel/src/app/(dashboard)/agents/page.tsx b/panel/src/app/(dashboard)/agents/page.tsx index ee40b32a..816aeca9 100644 --- a/panel/src/app/(dashboard)/agents/page.tsx +++ b/panel/src/app/(dashboard)/agents/page.tsx @@ -108,6 +108,7 @@ export default function AgentsPage() { one Leadership band so a lone Main PM card never wastes a full row. */} 0 && ( {entry.sentiment && ( - {entry.sentiment} + + {entry.sentiment} + )}

{entry.title}

@@ -192,7 +194,9 @@ export default function JournalEntryPage({ params }: JournalEntryPageProps) { {/* Content */} - Content + + Content +
@@ -205,10 +209,12 @@ export default function JournalEntryPage({ params }: JournalEntryPageProps) { {entry.tags.length > 0 && ( - - - Tags - + + + + Tags + +
diff --git a/panel/src/app/(dashboard)/journals/page.tsx b/panel/src/app/(dashboard)/journals/page.tsx index 98eac9be..39b56b46 100644 --- a/panel/src/app/(dashboard)/journals/page.tsx +++ b/panel/src/app/(dashboard)/journals/page.tsx @@ -9,6 +9,7 @@ import { JournalView } from "@/components/journals/journal-view"; import { Card, CardContent } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Skeleton } from "@/components/ui/skeleton"; +import { HelpTip } from "@/components/ui/help-tip"; import { usePageRefresh } from "@/hooks"; import { BookOpen, Search } from "lucide-react"; @@ -179,15 +180,17 @@ function JournalsPageContent() { {/* Agent Search */} -
- - handleAgentSearch(e.target.value)} - placeholder="Search agents..." - className="pl-9" - /> -
+ +
+ + handleAgentSearch(e.target.value)} + placeholder="Search agents..." + className="pl-9" + /> +
+
{/* Agent List */} - - - {title} - - {icon} - + + + + {title} + + {icon} + +
{displayValue}
{subtitle && ( @@ -305,18 +314,21 @@ function PerformanceTabContent() { value={completedToday} subtitle="Tasks finished" icon={} + tip="Tasks whose completed_at timestamp falls on today's calendar date" /> } + tip="Tasks completed in the trailing 7 days from now" /> } + tip="Every task that has ever reached the completed status" /> } + tip="Completed tasks divided by every task in the table, all-time" />
@@ -390,24 +403,28 @@ function PerformanceTabContent() { value={runningAgents} subtitle="Active agents" icon={} + tip="Agents currently spawned and actively working a task" /> } + tip="Agents with no container running — free to be spawned for new work" /> } + tip="Agents stuck waiting unusually long, possibly needing human attention" /> } + tip="Agents whose last spawn exited in an error state" /> @@ -624,12 +641,14 @@ interface ProjectionCardProps { function ProjectionCard({ projection, isLoading }: ProjectionCardProps) { return ( - - - - Monthly Projection - - + + + + + Monthly Projection + + + {isLoading ? ( @@ -699,12 +718,14 @@ interface RoleUsageTableProps { function RoleUsageTable({ data, isLoading }: RoleUsageTableProps) { return ( - - - - Cost & Cache by Role - - + + + + + Cost & Cache by Role + + + {isLoading ? ( @@ -869,6 +890,13 @@ const VALID_METRICS_TABS: MetricsTab[] = [ "scorecards", ]; +const METRICS_TAB_HINTS: Record = { + performance: "Task velocity, status counts, agent load, and team health", + "token-usage": "Token spend, cost projections, cache efficiency, and per-session detail", + delivery: "Cycle time, bottlenecks, and rework rate reconstructed from the audit log", + scorecards: "Per-agent and per-team delivery scorecards", +}; + function isValidMetricsTab(value: string | null): value is MetricsTab { return VALID_METRICS_TABS.includes(value as MetricsTab); } @@ -905,10 +933,29 @@ function MetricsPageContent() { - Performance - Token Usage - Delivery - Scorecards + {VALID_METRICS_TABS.map((tab) => ( + + + {/* TooltipTrigger's asChild Slot merge overwrites the + data-state Radix Tabs sets on this trigger, so the + data-[state=active] style never fires unless it's + re-asserted explicitly after the merge. */} + + {tab === "performance" + ? "Performance" + : tab === "token-usage" + ? "Token Usage" + : tab === "delivery" + ? "Delivery" + : "Scorecards"} + + + {METRICS_TAB_HINTS[tab]} + + ))} diff --git a/panel/src/components/a2a/a2a-connection-badge.tsx b/panel/src/components/a2a/a2a-connection-badge.tsx index 0c9a9e16..522dc613 100644 --- a/panel/src/components/a2a/a2a-connection-badge.tsx +++ b/panel/src/components/a2a/a2a-connection-badge.tsx @@ -12,20 +12,22 @@ import { connectionDotClasses, connectionStateLabel } from "./a2a-utils"; * conversation must read differently from a stream that is the problem. */ export function A2AConnectionBadge({ state }: { state: ConnectionState }) { return ( -
- - - {connectionStateLabel(state)} - - {(state === "connecting" || state === "reconnecting") && ( - - )} - {state === "disconnected" && ( - - )} -
+ +
+ + + {connectionStateLabel(state)} + + {(state === "connecting" || state === "reconnecting") && ( + + )} + {state === "disconnected" && ( + + )} +
+
); } diff --git a/panel/src/components/a2a/a2a-context-pane.tsx b/panel/src/components/a2a/a2a-context-pane.tsx index 5f365a06..b52ac7b3 100644 --- a/panel/src/components/a2a/a2a-context-pane.tsx +++ b/panel/src/components/a2a/a2a-context-pane.tsx @@ -40,12 +40,14 @@ function IdentityCard({ slug }: { slug: string }) {
{getAgentDisplayName(slug)}
- - {teamColor.replace("_", "/")} - + + + {teamColor.replace("_", "/")} + + ); @@ -70,10 +72,12 @@ export function A2AContextPane({ return (
-
- - Context -
+ +
+ + Context +
+
@@ -94,20 +98,24 @@ export function A2AContextPane({
{task.title}
- - {task.status} - - - - View task - + + + {task.status} + + + + + + View task + +
)} diff --git a/panel/src/components/a2a/a2a-conversation-list.tsx b/panel/src/components/a2a/a2a-conversation-list.tsx index 3369bcea..5f861454 100644 --- a/panel/src/components/a2a/a2a-conversation-list.tsx +++ b/panel/src/components/a2a/a2a-conversation-list.tsx @@ -4,6 +4,7 @@ import Link from "next/link"; import { Badge } from "@/components/ui/badge"; import { Skeleton } from "@/components/ui/skeleton"; import { ScrollArea } from "@/components/ui/scroll-area"; +import { HelpTip } from "@/components/ui/help-tip"; import { getAgentDisplayName } from "@/lib/agent-utils"; import type { AdminConversationSummary } from "@/lib/api/a2a"; import { usePulseFlash } from "@/hooks/use-pulse-flash"; @@ -81,42 +82,54 @@ function ConversationRow({ {conversation.topic}
)} -
- {formatDistanceToNow( - new Date( - conversation.last_message_at ?? conversation.created_at, - ), - )}{" "} - ago -
+ +
+ {formatDistanceToNow( + new Date( + conversation.last_message_at ?? conversation.created_at, + ), + )}{" "} + ago +
+
{conversation.last_message_preview && (

{conversation.last_message_preview}

)} {conversation.task_id && ( - e.stopPropagation()} - className="inline-flex items-center gap-1 text-xs text-primary hover:underline mt-1" - > - - Task {conversation.task_id.slice(0, 8)} - + + e.stopPropagation()} + className="inline-flex items-center gap-1 text-xs text-primary hover:underline mt-1" + > + + Task {conversation.task_id.slice(0, 8)} + + )}
- - {conversation.status} - - - {conversation.message_count} msgs - + + + {conversation.status} + + + + + {conversation.message_count} msgs + +
diff --git a/panel/src/components/a2a/a2a-filter-bar.tsx b/panel/src/components/a2a/a2a-filter-bar.tsx index 5abb6062..6207bb44 100644 --- a/panel/src/components/a2a/a2a-filter-bar.tsx +++ b/panel/src/components/a2a/a2a-filter-bar.tsx @@ -10,6 +10,7 @@ import { PopoverTrigger, } from "@/components/ui/popover"; import { SlidersHorizontal, X } from "lucide-react"; +import { HelpTip } from "@/components/ui/help-tip"; import { getAgentDisplayName } from "@/lib/agent-utils"; import { EMPTY_A2A_FILTERS, @@ -128,17 +129,19 @@ export function A2AFilterBar({
- - - + 0 ? `${count} active filter${count === 1 ? "" : "s"} — click to edit` : "Narrow by agent, task, status, or date"}> + + + +
- Agent + + Agent + {filters.agents.length > 0 && ( - + + + )}
@@ -183,7 +190,9 @@ export function A2AFilterBar({
- Task + + Task + @@ -196,45 +205,52 @@ export function A2AFilterBar({ className="mt-1 h-7 text-xs" aria-label="Task id fragment" /> - + + +
- Status + + Status +
{STATUS_OPTIONS.map((opt) => ( - + + + ))}
- Date range + + Date range +
0 && (
- + + +
)} @@ -278,23 +296,27 @@ export function A2AFilterBar({ {chips.map((chip) => ( {chip.label} - + + + ))} - + + +
)}
diff --git a/panel/src/components/a2a/a2a-pair-card.tsx b/panel/src/components/a2a/a2a-pair-card.tsx index f1b4e020..871ef794 100644 --- a/panel/src/components/a2a/a2a-pair-card.tsx +++ b/panel/src/components/a2a/a2a-pair-card.tsx @@ -89,11 +89,19 @@ export function A2APairCard({ {" ↔ "} {getAgentDisplayName(pair.agent_b)}
-
- {hasHistory && pair.last_message_at - ? `${formatDistanceToNow(new Date(pair.last_message_at))} ago` - : "No A2A yet"} -
+ +
+ {hasHistory && pair.last_message_at + ? `${formatDistanceToNow(new Date(pair.last_message_at))} ago` + : "No A2A yet"} +
+
{hasHistory && ( diff --git a/panel/src/components/a2a/a2a-reply-composer.tsx b/panel/src/components/a2a/a2a-reply-composer.tsx index cdf38d8d..975d79dc 100644 --- a/panel/src/components/a2a/a2a-reply-composer.tsx +++ b/panel/src/components/a2a/a2a-reply-composer.tsx @@ -12,6 +12,7 @@ import { } from "@/components/ui/select"; import { Send } from "lucide-react"; import { toast } from "sonner"; +import { HelpTip } from "@/components/ui/help-tip"; import { getAgentDisplayName } from "@/lib/agent-utils"; import { getErrorMessage } from "@/lib/api/client"; import { useReplyAsCeo } from "@/hooks/use-a2a-live"; @@ -88,9 +89,11 @@ export function A2AReplyComposer({
- + + + + +

diff --git a/panel/src/components/a2a/a2a-switchboard.tsx b/panel/src/components/a2a/a2a-switchboard.tsx index 75e45048..9d28d5b8 100644 --- a/panel/src/components/a2a/a2a-switchboard.tsx +++ b/panel/src/components/a2a/a2a-switchboard.tsx @@ -2,6 +2,7 @@ import { Radio } from "lucide-react"; import { Skeleton } from "@/components/ui/skeleton"; +import { HelpTip } from "@/components/ui/help-tip"; import type { AdminPairSummary } from "@/lib/api/a2a"; import { A2APairCard } from "./a2a-pair-card"; import { groupPairsBySection, pairKey } from "./a2a-switchboard-utils"; @@ -56,12 +57,14 @@ export function A2ASwitchboard({

{sections.map((section) => (
-

- {section.label} - - ({section.pairs.length}) - -

+ +

+ {section.label} + + ({section.pairs.length}) + +

+
{section.pairs.map((pair) => { const key = pairKey(pair.agent_a, pair.agent_b); diff --git a/panel/src/components/a2a/a2a-transcript.tsx b/panel/src/components/a2a/a2a-transcript.tsx index 05de109e..b07c53d6 100644 --- a/panel/src/components/a2a/a2a-transcript.tsx +++ b/panel/src/components/a2a/a2a-transcript.tsx @@ -156,9 +156,11 @@ export function A2ATranscript({

Couldn't load this conversation

{onRetry && ( - + + + )}
@@ -224,9 +226,11 @@ export function A2ATranscript({
- - {getAgentDisplayName(message.from_agent)} - + + + {getAgentDisplayName(message.from_agent)} + + {message.message_kind && ( @@ -234,9 +238,11 @@ export function A2ATranscript({ )} - - {formatDistanceToNow(new Date(message.created_at))} ago - + + + {formatDistanceToNow(new Date(message.created_at))} ago + +
{message.content} @@ -248,19 +254,21 @@ export function A2ATranscript({
{showJumpPill && ( - + + + )} ); diff --git a/panel/src/components/agents/agent-activity-panel.tsx b/panel/src/components/agents/agent-activity-panel.tsx index 3d993cdd..3b9f96d8 100644 --- a/panel/src/components/agents/agent-activity-panel.tsx +++ b/panel/src/components/agents/agent-activity-panel.tsx @@ -16,6 +16,7 @@ import { CardDescription, } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; +import { HelpTip } from "@/components/ui/help-tip"; import { GitBranch, BookOpen } from "lucide-react"; import { useUsageTimeSeries } from "@/hooks/use-usage"; import { useWorkSessions } from "@/hooks/use-work-sessions"; @@ -98,7 +99,9 @@ export function AgentActivityPanel({ {/* Token activity sparkline */} - Token Activity + + Token Activity + Last 7 days @@ -153,7 +156,9 @@ export function AgentActivityPanel({ {/* Activity timeline */} - Recent Activity + + Recent Activity + Work sessions & journal entries @@ -172,11 +177,19 @@ export function AgentActivityPanel({ {timeline.map((item, i) => (
  • - {item.kind === "session" ? ( - - ) : ( - - )} + + {item.kind === "session" ? ( + + ) : ( + + )} +

    {item.title}

    @@ -184,11 +197,13 @@ export function AgentActivityPanel({ {item.subtitle}

    - - {formatDistanceToNow(new Date(item.timestamp), { - addSuffix: true, - })} - + + + {formatDistanceToNow(new Date(item.timestamp), { + addSuffix: true, + })} + +
  • ))} diff --git a/panel/src/components/agents/agent-card.tsx b/panel/src/components/agents/agent-card.tsx index 948e8b05..f15976a1 100644 --- a/panel/src/components/agents/agent-card.tsx +++ b/panel/src/components/agents/agent-card.tsx @@ -98,24 +98,30 @@ export function AgentCard({ agent, agentStatus, usageRow }: AgentCardProps) { )} {isActive && ( <> - - - - View Details - - + + + + + View Details + + + - handleStop(true)}> - - Stop Gracefully - - handleStop(false)} - className="text-red-600" - > - - Force Stop - + + handleStop(true)}> + + Stop Gracefully + + + + handleStop(false)} + className="text-red-600" + > + + Force Stop + + )} @@ -139,17 +145,29 @@ export function AgentCard({ agent, agentStatus, usageRow }: AgentCardProps) {
    {detail && ( -

    - {detail.text} -

    + +

    + {detail.text} +

    +
    )} {usageRow && ( -

    - {usageRow.total_tokens >= 1_000 - ? (usageRow.total_tokens / 1_000).toFixed(1) + "K" - : String(usageRow.total_tokens)}{" "} - tok · ${usageRow.cost_usd.toFixed(4)} -

    + +

    + {usageRow.total_tokens >= 1_000 + ? (usageRow.total_tokens / 1_000).toFixed(1) + "K" + : String(usageRow.total_tokens)}{" "} + tok · ${usageRow.cost_usd.toFixed(4)} +

    +
    )}
    diff --git a/panel/src/components/agents/agent-grid.tsx b/panel/src/components/agents/agent-grid.tsx index 5cc71b19..cbde4d78 100644 --- a/panel/src/components/agents/agent-grid.tsx +++ b/panel/src/components/agents/agent-grid.tsx @@ -3,10 +3,14 @@ import { AgentDefinition } from "@/lib/agent-definitions"; import { Badge } from "@/components/ui/badge"; import { Card, CardHeader } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; +import { HelpTip } from "@/components/ui/help-tip"; import { AgentCard } from "./agent-card"; interface AgentGridProps { title: string; + /** Optional hover explanation of what this section groups — e.g. which + * roles fold into "Leadership". Falsy renders the bare heading. */ + titleHint?: string; agents: AgentDefinition[]; agentStatuses: Record; agentUsage?: Record; @@ -20,6 +24,7 @@ const GRID_COLS = "grid-cols-[repeat(auto-fill,minmax(17rem,1fr))]"; export function AgentGrid({ title, + titleHint, agents, agentStatuses, agentUsage, @@ -28,12 +33,16 @@ export function AgentGrid({ return (
    -

    - {title} -

    - - {agents.length} - + +

    + {title} +

    +
    + + + {agents.length} + +
    {isLoading diff --git a/panel/src/components/agents/agent-selector.tsx b/panel/src/components/agents/agent-selector.tsx index 6bb42372..98db0578 100644 --- a/panel/src/components/agents/agent-selector.tsx +++ b/panel/src/components/agents/agent-selector.tsx @@ -13,6 +13,7 @@ import { SelectValue, } from "@/components/ui/select"; import { Badge } from "@/components/ui/badge"; +import { HelpTip } from "@/components/ui/help-tip"; import { User, Users } from "lucide-react"; import { resolveToSlug } from "@/lib/agent-utils"; @@ -151,30 +152,34 @@ export function AgentSelector({ onValueChange={handleValueChange} disabled={disabled || isLoading} > - - - {selectedAgent ? ( -
    - - {selectedAgent.name} - {selectedAgent.role && ( - - {ROLE_LABELS[selectedAgent.role] || selectedAgent.role} - - )} -
    - ) : ( - placeholder - )} -
    -
    + + + + {selectedAgent ? ( +
    + + {selectedAgent.name} + {selectedAgent.role && ( + + {ROLE_LABELS[selectedAgent.role] || selectedAgent.role} + + )} +
    + ) : ( + placeholder + )} +
    +
    +
    {allowClear && value && ( - - - Unassigned - + + + + Unassigned + + )} diff --git a/panel/src/components/agents/agent-status-cards.tsx b/panel/src/components/agents/agent-status-cards.tsx index 08ef14bf..671b7dd3 100644 --- a/panel/src/components/agents/agent-status-cards.tsx +++ b/panel/src/components/agents/agent-status-cards.tsx @@ -2,6 +2,7 @@ import Link from "next/link"; import { formatDistanceToNow } from "date-fns"; import { AgentStatusResponse } from "@/types"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { HelpTip } from "@/components/ui/help-tip"; import { Activity, FileText, Clock, AlertCircle } from "lucide-react"; import { AgentStateBadge } from "./agent-state-badge"; @@ -29,13 +30,15 @@ export function AgentStatusCards({ agent }: AgentStatusCardsProps) { {agent.task_id ? ( - - {agent.task_id.slice(0, 8)}... - + + + {agent.task_id.slice(0, 8)}... + + ) : ( No task assigned )} @@ -49,7 +52,11 @@ export function AgentStatusCards({ agent }: AgentStatusCardsProps) { {agent.started_at ? ( - {formatDistanceToNow(new Date(agent.started_at))} ago + + + {formatDistanceToNow(new Date(agent.started_at))} ago + + ) : ( Not started )} @@ -62,17 +69,22 @@ export function AgentStatusCards({ agent }: AgentStatusCardsProps) { - 0 ? "text-red-600 font-semibold" : "" - } - > - {agent.error_count} - + + 0 ? "text-red-600 font-semibold" : "") + } + > + {agent.error_count} + + {agent.waiting_for && ( -

    - Waiting: {agent.waiting_for} -

    + +

    + Waiting: {agent.waiting_for} +

    +
    )}
    diff --git a/panel/src/components/agents/resolve-wait-dialog.tsx b/panel/src/components/agents/resolve-wait-dialog.tsx index 959c9d0d..0be816a4 100644 --- a/panel/src/components/agents/resolve-wait-dialog.tsx +++ b/panel/src/components/agents/resolve-wait-dialog.tsx @@ -13,6 +13,7 @@ import { DialogTrigger, DialogDescription, } from "@/components/ui/dialog"; +import { HelpTip } from "@/components/ui/help-tip"; import { Send } from "lucide-react"; import { toast } from "sonner"; @@ -48,12 +49,14 @@ export function ResolveWaitDialog({ agentId }: ResolveWaitDialogProps) { return ( - - - + + + + + Resolve Agent Wait @@ -63,7 +66,9 @@ export function ResolveWaitDialog({ agentId }: ResolveWaitDialogProps) {
    - + + +