From a4a2c0bdb5dbdca3da896c2cbeeaa0e8e6e68230 Mon Sep 17 00:00:00 2001 From: santoshkumarradha Date: Tue, 18 Nov 2025 19:54:37 -0500 Subject: [PATCH 01/11] Refines dashboard UI for clarity and modern polish Improves dashboard and table visuals with more consistent spacing, new typography utilities, and subtle animations for a more modern, readable, and interactive feel. Updates badge and button sizing for compactness, enhances sidebar and workflow node visuals, and reworks execution/header sections for higher information density and easier scanning. Aims to boost usability and professional appeal without altering core logic. --- .../components/EnhancedExecutionsTable.tsx | 29 +- .../src/components/Navigation/SidebarNew.tsx | 37 +- .../src/components/SearchWithFilters.tsx | 9 +- .../components/WorkflowDAG/WorkflowNode.tsx | 16 +- .../components/execution/ExecutionHeader.tsx | 484 +++++++++--------- .../web/client/src/components/ui/badge.tsx | 26 +- .../web/client/src/components/ui/button.tsx | 9 +- control-plane/web/client/src/index.css | 9 + .../src/pages/EnhancedDashboardPage.tsx | 169 +++--- 9 files changed, 430 insertions(+), 358 deletions(-) diff --git a/control-plane/web/client/src/components/EnhancedExecutionsTable.tsx b/control-plane/web/client/src/components/EnhancedExecutionsTable.tsx index 09909455..b471e06b 100644 --- a/control-plane/web/client/src/components/EnhancedExecutionsTable.tsx +++ b/control-plane/web/client/src/components/EnhancedExecutionsTable.tsx @@ -226,11 +226,11 @@ export function EnhancedExecutionsTable({ return (
- + -
+
-
+
VC
-
+
-
+
setHoveredRow(execution.execution_id)} onMouseLeave={() => setHoveredRow(null)} onClick={() => onExecutionClick?.(execution)} > -
+ {/* Hover Accent Bar */} +
+ +
@@ -332,13 +335,13 @@ export function EnhancedExecutionsTable({
- + {execution.relative_time}
- + {execution.duration_display}
@@ -350,7 +353,7 @@ export function EnhancedExecutionsTable({
- + …{execution.execution_id.slice(-8)}
diff --git a/control-plane/web/client/src/components/Navigation/SidebarNew.tsx b/control-plane/web/client/src/components/Navigation/SidebarNew.tsx index a315fcd2..038e7db1 100644 --- a/control-plane/web/client/src/components/Navigation/SidebarNew.tsx +++ b/control-plane/web/client/src/components/Navigation/SidebarNew.tsx @@ -14,6 +14,7 @@ import { useSidebar, } from "@/components/ui/sidebar"; import { Icon } from "@/components/ui/icon"; +import { cn } from "@/lib/utils"; interface SidebarNewProps { sections: NavigationSection[]; @@ -24,19 +25,19 @@ export function SidebarNew({ sections }: SidebarNewProps) { const isCollapsed = state === "collapsed"; return ( - + {/* Header - Add bottom spacing and subtle border separator for visual hierarchy */} - + - + -
+
- AgentField - Open Control Plane + AgentField + v1.0.0
@@ -45,15 +46,15 @@ export function SidebarNew({ sections }: SidebarNewProps) { {/* Content - Add spacing between groups */} - + {sections.map((section) => ( - + {/* Apply caption styling for clear header differentiation */} - + {section.title} {/* Add gap after header */} - + {section.items.map((item) => ( @@ -62,8 +63,9 @@ export function SidebarNew({ sections }: SidebarNewProps) { isActive={false} tooltip={isCollapsed ? item.label : undefined} disabled + className="h-8 text-[13px]" > - {item.icon && } + {item.icon && } {item.label} ) : ( @@ -73,9 +75,18 @@ export function SidebarNew({ sections }: SidebarNewProps) { asChild isActive={isActive} tooltip={isCollapsed ? item.label : undefined} + className={cn( + "h-8 text-[13px] transition-all duration-200 relative", + isActive + ? "bg-sidebar-accent text-sidebar-accent-foreground font-medium shadow-sm" + : "text-muted-foreground hover:text-foreground hover:bg-sidebar-accent/50" + )} > - - {item.icon && } + + {isActive && ( +
+ )} + {item.icon && } {item.label} diff --git a/control-plane/web/client/src/components/SearchWithFilters.tsx b/control-plane/web/client/src/components/SearchWithFilters.tsx index 006ff483..64b390a7 100644 --- a/control-plane/web/client/src/components/SearchWithFilters.tsx +++ b/control-plane/web/client/src/components/SearchWithFilters.tsx @@ -144,8 +144,13 @@ export function SearchWithFilters({ />
- {/* Dropdown indicator */} -
+ {/* Command Hint & Dropdown indicator */} +
+ {!inputValue && tags.length === 0 && ( + + K + + )} { } const baseShadow = - "0 12px 24px -14px color-mix(in srgb, var(--foreground) 22%, transparent)"; + "0 4px 12px -2px color-mix(in srgb, var(--foreground) 10%, transparent), 0 2px 6px -1px color-mix(in srgb, var(--foreground) 6%, transparent)"; const accentShadow = `0 0 0 1px ${borderColor}`; - const glowShadow = isDimmed ? "" : `0 0 18px ${glowColor}`; + const glowShadow = isDimmed ? "" : `0 0 12px -2px ${glowColor}`; const compositeShadow = [accentShadow, baseShadow, glowShadow].filter(Boolean).join(", "); - const baseBackground = `linear-gradient(135deg, color-mix(in srgb, ${statusColorVar} 12%, transparent), var(--card))`; + const baseBackground = `linear-gradient(145deg, color-mix(in srgb, ${statusColorVar} 8%, transparent), var(--card))`; let background = baseBackground; if (!hasHighlight) { @@ -357,22 +357,22 @@ export const WorkflowNode = memo(({ data, selected }: WorkflowNodeProps) => { return (
{/* Agent color left border accent */}
- + {label} - + {value}
@@ -102,8 +101,6 @@ export function ExecutionHeader({ }: ExecutionHeaderProps) { const navigate = useNavigate(); const normalizedStatus = normalizeStatus(execution.status); - const statusLabel = - normalizedStatus.charAt(0).toUpperCase() + normalizedStatus.slice(1); const workflowTags = execution.workflow_tags ?? []; const webhookEvents = Array.isArray(execution.webhook_events) ? [...execution.webhook_events].sort( @@ -134,7 +131,7 @@ export function ExecutionHeader({ : webhookSuccessCount > 0 ? `${webhookSuccessCount} delivered` : webhookPending - ? "Pending webhook" + ? "Pending" : "Registered"; const handleNavigateBack = () => { @@ -152,266 +149,269 @@ export function ExecutionHeader({ navigate(`/executions?session_id=${execution.session_id}`); return ( -
- {/* Back Navigation */} -
- + + Executions + + / + {truncateId(execution.execution_id)}
- {/* Main Header - Clean Linear Style */} -
-
-

- {execution.reasoner_id} -

- - {statusLabel} - {webhookRegistered && ( - - - 0 - ? "border-destructive/40 text-destructive" - : webhookSuccessCount > 0 - ? "border-emerald-500/40 text-emerald-500" - : "border-border text-muted-foreground", - )} - > - - {webhookBadgeLabel} - - - -
-
-

- {webhookPending - ? "Awaiting first delivery" - : latestWebhookEvent - ? `Last webhook ${formatWebhookStatusLabel(latestWebhookEvent.status)}` - : "Webhook registered"} -

-

- {webhookPending && - "We will display the latest delivery details as soon as the callback is reported."} - {!webhookPending && latestWebhookEvent && ( - <> - {formatWebhookStatusLabel(latestWebhookEvent.status)} - {latestWebhookEvent.http_status ? ` • HTTP ${latestWebhookEvent.http_status}` : ""} - + {/* Main Header */} +

+ {/* Top Row: Title & Status */} +
+
+
+

+ {execution.reasoner_id} +

+ + {webhookRegistered && ( + + + 0 + ? "border-destructive/40 text-destructive" + : webhookSuccessCount > 0 + ? "border-emerald-500/40 text-emerald-500" + : "border-border text-muted-foreground", )} - {!webhookPending && !latestWebhookEvent && "No deliveries recorded yet."} -

-
- {latestWebhookTimestamp && ( - - {latestWebhookTimestamp} - - )} -
+ > + + {webhookBadgeLabel} + + + +
+
+

+ {webhookPending + ? "Awaiting first delivery" + : latestWebhookEvent + ? `Last webhook ${formatWebhookStatusLabel(latestWebhookEvent.status)}` + : "Webhook registered"} +

+

+ {webhookPending && + "We will display the latest delivery details as soon as the callback is reported."} + {!webhookPending && latestWebhookEvent && ( + <> + {formatWebhookStatusLabel(latestWebhookEvent.status)} + {latestWebhookEvent.http_status ? ` • HTTP ${latestWebhookEvent.http_status}` : ""} + + )} + {!webhookPending && !latestWebhookEvent && "No deliveries recorded yet."} +

+
+ {latestWebhookTimestamp && ( + + {latestWebhookTimestamp} + + )} +
-
- 0 ? "success" : "muted"} - /> - 0 ? "danger" : "muted"} - /> - -
+
+ 0 ? "success" : "muted"} + /> + 0 ? "danger" : "muted"} + /> + +
- {latestWebhookEvent?.error_message && ( -
- {latestWebhookEvent.error_message} -
- )} -
- - )} -
+ {latestWebhookEvent?.error_message && ( +
+ {latestWebhookEvent.error_message} +
+ )} + + + )} +
-
-
- Agent: - - {execution.agent_node_id} - - + {/* Tags Row */} + {workflowTags.length > 0 && ( +
+ {workflowTags.map((tag) => ( + + {tag} + + ))} +
+ )}
+ {/* Primary Actions / VC Status */}
- DID: - -
- -
- ID: - - {truncateId(execution.execution_id)} - - + {vcLoading ? ( + Loading VC... + ) : vcStatus?.has_vc ? ( + + ) : null}
+
- {vcLoading ? ( -
- VC: - Loading… + {/* Metadata Grid - The "Developer Dashboard" Look */} +
+ {/* Column 1: Identity */} +
+
+
Execution ID
+
+ + {execution.execution_id} + + +
- ) : vcStatus?.has_vc ? ( -
- VC: - +
+
Agent Node
+
+ + {truncateId(execution.agent_node_id)} + + + +
- ) : null} -
- -
-
- Workflow: - -
- {execution.session_id && ( -
- Session: - - + {/* Column 2: Context */} +
+
+
Workflow
+
+ + +
- )} - -
- Request: - - {execution.agentfield_request_id - ? truncateId(execution.agentfield_request_id) - : "n/a"} - - {execution.agentfield_request_id && ( - + {execution.session_id && ( +
+
Session
+
+ + +
+
)}
-
- {workflowTags.length > 0 && ( -
- Tags: -
- {workflowTags.map((tag) => ( - - {tag} - - ))} + {/* Column 3: Performance */} +
+
+
Duration
+
+ + {formatDuration(execution.duration_ms)} +
+
+
+
Retries
+
+ + {execution.retry_count} +
-
- )} - -
-
- - Duration: - - {formatDuration(execution.duration_ms)} - -
- -
- - Input: - - {formatBytes(execution.input_size)} - -
- -
- - Output: - - {formatBytes(execution.output_size)} -
-
- - Retries: - - {execution.retry_count} - + {/* Column 4: I/O */} +
+
+
Data Transfer
+
+
+ + {formatBytes(execution.input_size)} +
+
+ + {formatBytes(execution.output_size)} +
+
+
+
+
Request ID
+
+ + {execution.agentfield_request_id + ? truncateId(execution.agentfield_request_id) + : "n/a"} + + {execution.agentfield_request_id && ( + + )} +
+
diff --git a/control-plane/web/client/src/components/ui/badge.tsx b/control-plane/web/client/src/components/ui/badge.tsx index b57b3b2b..1f867f47 100644 --- a/control-plane/web/client/src/components/ui/badge.tsx +++ b/control-plane/web/client/src/components/ui/badge.tsx @@ -13,7 +13,7 @@ import { import type { IconComponent, IconWeight } from "@/components/ui/icon-bridge" const badgeVariants = cva( - "inline-flex items-center gap-1.5 rounded-lg border border-transparent px-2.5 py-1 text-xs font-medium transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", + "inline-flex items-center gap-1.5 rounded-md border border-transparent px-2 py-0.5 text-xs font-medium transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", { variants: { variant: { @@ -31,32 +31,32 @@ const badgeVariants = cva( outline: "text-text-primary border border-border bg-transparent hover:bg-bg-hover shadow-sm", metadata: - "rounded-md bg-muted/40 text-text-secondary border border-border/60 px-2 py-1 text-body-small font-medium", + "rounded-md bg-muted/40 text-text-secondary border border-border/60 px-1.5 py-0.5 text-[10px] font-medium font-mono", count: - "rounded-full bg-bg-secondary text-text-primary border border-border-secondary px-2 py-0.5 text-caption font-semibold uppercase tracking-wide", + "rounded-full bg-bg-secondary text-text-primary border border-border-secondary px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide", pill: - "rounded-full bg-muted/30 text-text-primary border border-border/40 px-3 py-1 text-body-small", + "rounded-full bg-muted/30 text-text-primary border border-border/40 px-2.5 py-0.5 text-[11px]", // Status variants with standardized colors and icons success: - cn(getStatusBadgeClasses("success" satisfies StatusTone)), + cn(getStatusBadgeClasses("success" satisfies StatusTone), "font-mono tracking-tight"), failed: - cn(getStatusBadgeClasses("error" satisfies StatusTone)), + cn(getStatusBadgeClasses("error" satisfies StatusTone), "font-mono tracking-tight"), running: - cn(getStatusBadgeClasses("info" satisfies StatusTone)), + cn(getStatusBadgeClasses("info" satisfies StatusTone), "font-mono tracking-tight"), pending: - cn(getStatusBadgeClasses("warning" satisfies StatusTone)), + cn(getStatusBadgeClasses("warning" satisfies StatusTone), "font-mono tracking-tight"), // Additional status variants for degraded states degraded: - cn(getStatusBadgeClasses("warning" satisfies StatusTone)), + cn(getStatusBadgeClasses("warning" satisfies StatusTone), "font-mono tracking-tight"), unknown: - cn(getStatusBadgeClasses("neutral" satisfies StatusTone)), + cn(getStatusBadgeClasses("neutral" satisfies StatusTone), "font-mono tracking-tight"), }, size: { - sm: "px-2 py-0.5 text-xs", - md: "px-2.5 py-1 text-xs", - lg: "px-3 py-1.5 text-sm", + sm: "px-1.5 py-0 text-[10px]", + md: "px-2 py-0.5 text-xs", + lg: "px-3 py-1 text-sm", }, }, defaultVariants: { diff --git a/control-plane/web/client/src/components/ui/button.tsx b/control-plane/web/client/src/components/ui/button.tsx index fe87aacc..9cfef372 100644 --- a/control-plane/web/client/src/components/ui/button.tsx +++ b/control-plane/web/client/src/components/ui/button.tsx @@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 active:scale-[0.98] active:translate-y-[0.5px]", { variants: { variant: { @@ -21,10 +21,11 @@ const buttonVariants = cva( link: "text-primary underline-offset-4 hover:underline", }, size: { - default: "h-9 px-4 py-2", - sm: "h-8 rounded-md px-3 text-sm", + default: "h-8 px-4 py-2", // Compact default for developer tools + sm: "h-7 rounded-md px-3 text-xs", lg: "h-10 rounded-md px-8 text-base", - icon: "h-9 w-9", + icon: "h-8 w-8", + "icon-sm": "h-7 w-7", }, }, defaultVariants: { diff --git a/control-plane/web/client/src/index.css b/control-plane/web/client/src/index.css index 7e83ca4e..22258801 100644 --- a/control-plane/web/client/src/index.css +++ b/control-plane/web/client/src/index.css @@ -187,6 +187,15 @@ main:focus, letter-spacing: 0.05em; } +.text-label { + font-size: 10px; + line-height: 1.2; + color: var(--text-tertiary); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; +} + /* Interactive elements */ .interactive-hover { transition: all var(--transition-fast); diff --git a/control-plane/web/client/src/pages/EnhancedDashboardPage.tsx b/control-plane/web/client/src/pages/EnhancedDashboardPage.tsx index 32285af9..3cd42123 100644 --- a/control-plane/web/client/src/pages/EnhancedDashboardPage.tsx +++ b/control-plane/web/client/src/pages/EnhancedDashboardPage.tsx @@ -242,13 +242,13 @@ export function EnhancedDashboardPage() { const generatedAt = formatTimestamp(data.generated_at); return ( -
+
- + {generatedAt}