diff --git a/ui/src/pages/Dashboard/Dashboard.module.css b/ui/src/pages/Dashboard/Dashboard.module.css index 3f800f71..df225b34 100644 --- a/ui/src/pages/Dashboard/Dashboard.module.css +++ b/ui/src/pages/Dashboard/Dashboard.module.css @@ -58,6 +58,18 @@ letter-spacing: 0.5px; color: var(--text-muted); margin-bottom: 10px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.panelSectionMeta { + font-size: 11px; + font-weight: 400; + text-transform: none; + letter-spacing: 0; + color: var(--text-muted); + font-family: var(--font-mono); } .overviewGrid { diff --git a/ui/src/pages/Dashboard/Dashboard.tsx b/ui/src/pages/Dashboard/Dashboard.tsx index 45d6697a..53c7af21 100644 --- a/ui/src/pages/Dashboard/Dashboard.tsx +++ b/ui/src/pages/Dashboard/Dashboard.tsx @@ -6,7 +6,7 @@ import { Alert, Collapsible, CodeBlock, ShortcutsBar, } from '@cameleer/design-system'; import type { Column } from '@cameleer/design-system'; -import { useSearchExecutions, useExecutionStats, useStatsTimeseries, useExecutionDetail, useProcessorSnapshot } from '../../api/queries/executions'; +import { useSearchExecutions, useExecutionStats, useStatsTimeseries, useExecutionDetail } from '../../api/queries/executions'; import { useDiagramByRoute } from '../../api/queries/diagrams'; import { useGlobalFilters } from '@cameleer/design-system'; import type { ExecutionSummary } from '../../api/types'; @@ -28,8 +28,6 @@ export default function Dashboard() { const timeTo = timeRange.end.toISOString(); const [selectedId, setSelectedId] = useState(null); - const [detailTab, setDetailTab] = useState('overview'); - const [processorIdx, setProcessorIdx] = useState(null); const timeWindowSeconds = (timeRange.end.getTime() - timeRange.start.getTime()) / 1000; @@ -42,7 +40,6 @@ export default function Dashboard() { offset: 0, limit: 50, }, true); const { data: detail } = useExecutionDetail(selectedId); - const { data: snapshot } = useProcessorSnapshot(selectedId, processorIdx); const { data: diagram } = useDiagramByRoute(detail?.groupName, detail?.routeId); const rows: Row[] = useMemo(() => @@ -109,95 +106,7 @@ export default function Dashboard() { }, ]; - const detailTabs = detail ? [ - { - label: 'Overview', value: 'overview', - content: ( - <> -
- -
-
-
Overview
-
-
- Status - - - {detail.status} - -
-
- Duration - {formatDuration(detail.durationMs)} -
-
- Route - {detail.routeId} -
-
- Agent - {detail.agentId ?? '—'} -
-
- Correlation - {detail.correlationId ?? '—'} -
-
- Timestamp - {detail.startTime ? new Date(detail.startTime).toISOString().replace('T', ' ').slice(0, 19) : '—'} -
-
-
- {detail.errorMessage && ( -
-
Errors
- - {detail.errorMessage.split(':')[0]} -
{detail.errorMessage.includes(':') ? detail.errorMessage.substring(detail.errorMessage.indexOf(':') + 1).trim() : ''}
-
- {detail.errorStackTrace && ( - - - - )} -
- )} - - ), - }, - { - label: 'Processors', value: 'processors', - content: (() => { - const procList = detail.processors?.length ? detail.processors : (detail.children ?? []); - return procList.length ? ( - setProcessorIdx(i)} - selectedIndex={processorIdx ?? undefined} - /> - ) :
No processor data
; - })(), - }, - { - label: 'Route Flow', value: 'flow', - content: diagram ? ( - { /* optionally select processor */ }} - /> - ) :
No diagram available
, - }, - ] : []; + const procList = detail ? (detail.processors?.length ? detail.processors : (detail.children ?? [])) : []; return (
@@ -255,7 +164,7 @@ export default function Dashboard() { { setSelectedId(row.id); setProcessorIdx(null); }} + onRowClick={(row) => { setSelectedId(row.id); }} selectedId={selectedId ?? undefined} sortable pageSize={25} @@ -267,10 +176,94 @@ export default function Dashboard() { key={selectedId} open={true} onClose={() => setSelectedId(null)} - title={`Exchange ${selectedId.slice(0, 12)}...`} - tabs={detailTabs} + title={`${detail.routeId} — ${selectedId.slice(0, 12)}`} className={styles.detailPanelOverride} - /> + > + {/* Open full details link */} +
+ +
+ + {/* Overview */} +
+
Overview
+
+
+ Status + + + {detail.status} + +
+
+ Duration + {formatDuration(detail.durationMs)} +
+
+ Route + {detail.routeId} +
+
+ Agent + {detail.agentId ?? '—'} +
+
+ Correlation + {detail.correlationId ?? '—'} +
+
+ Timestamp + {detail.startTime ? new Date(detail.startTime).toISOString().replace('T', ' ').slice(0, 19) : '—'} +
+
+
+ + {/* Errors */} + {detail.errorMessage && ( +
+
Errors
+ + {detail.errorMessage.split(':')[0]} +
{detail.errorMessage.includes(':') ? detail.errorMessage.substring(detail.errorMessage.indexOf(':') + 1).trim() : ''}
+
+ {detail.errorStackTrace && ( + + + + )} +
+ )} + + {/* Route Flow */} +
+
Route Flow
+ {diagram ? ( + {}} + /> + ) :
No diagram available
} +
+ + {/* Processor Timeline */} +
+
+ Processor Timeline + {formatDuration(detail.durationMs)} +
+ {procList.length ? ( + + ) :
No processor data
} +
+ )}
);