refactor(ui): remove detail panel slide-in and inspect column from exchange table
Row click now navigates directly to the split view with diagram. Removed: DetailPanel, inspect column, unused imports (ExternalLink, ProcessorTimeline, RouteFlow, useExecutionDetail, useDiagramLayout, buildFlowSegments). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,9 @@
|
|||||||
import { useState, useMemo, useCallback } from 'react'
|
import { useState, useMemo, useCallback } from 'react'
|
||||||
import { useParams, useNavigate, useSearchParams } from 'react-router'
|
import { useParams, useNavigate, useSearchParams } from 'react-router'
|
||||||
import { ExternalLink, AlertTriangle, X, Search } from 'lucide-react'
|
import { AlertTriangle, X, Search } from 'lucide-react'
|
||||||
import {
|
import {
|
||||||
DataTable,
|
DataTable,
|
||||||
DetailPanel,
|
|
||||||
ShortcutsBar,
|
ShortcutsBar,
|
||||||
ProcessorTimeline,
|
|
||||||
RouteFlow,
|
|
||||||
KpiStrip,
|
KpiStrip,
|
||||||
StatusDot,
|
StatusDot,
|
||||||
MonoText,
|
MonoText,
|
||||||
@@ -18,11 +15,8 @@ import {
|
|||||||
useSearchExecutions,
|
useSearchExecutions,
|
||||||
useExecutionStats,
|
useExecutionStats,
|
||||||
useStatsTimeseries,
|
useStatsTimeseries,
|
||||||
useExecutionDetail,
|
|
||||||
} from '../../api/queries/executions'
|
} from '../../api/queries/executions'
|
||||||
import { useDiagramLayout } from '../../api/queries/diagrams'
|
|
||||||
import type { ExecutionSummary } from '../../api/types'
|
import type { ExecutionSummary } from '../../api/types'
|
||||||
import { buildFlowSegments } from '../../utils/diagram-mapping'
|
|
||||||
import styles from './Dashboard.module.css'
|
import styles from './Dashboard.module.css'
|
||||||
|
|
||||||
// Row type extends ExecutionSummary with an `id` field for DataTable
|
// Row type extends ExecutionSummary with an `id` field for DataTable
|
||||||
@@ -199,7 +193,6 @@ export default function Dashboard() {
|
|||||||
const [searchParams, setSearchParams] = useSearchParams()
|
const [searchParams, setSearchParams] = useSearchParams()
|
||||||
const textFilter = searchParams.get('text') || undefined
|
const textFilter = searchParams.get('text') || undefined
|
||||||
const [selectedId, setSelectedId] = useState<string | undefined>()
|
const [selectedId, setSelectedId] = useState<string | undefined>()
|
||||||
const [panelOpen, setPanelOpen] = useState(false)
|
|
||||||
const [sortField, setSortField] = useState<string>('startTime')
|
const [sortField, setSortField] = useState<string>('startTime')
|
||||||
const [sortDir, setSortDir] = useState<'asc' | 'desc'>('desc')
|
const [sortDir, setSortDir] = useState<'asc' | 'desc'>('desc')
|
||||||
|
|
||||||
@@ -236,8 +229,6 @@ export default function Dashboard() {
|
|||||||
},
|
},
|
||||||
!textFilter,
|
!textFilter,
|
||||||
)
|
)
|
||||||
const { data: detail } = useExecutionDetail(selectedId ?? null)
|
|
||||||
const { data: diagram } = useDiagramLayout(detail?.diagramContentHash ?? null)
|
|
||||||
|
|
||||||
// ─── Rows ────────────────────────────────────────────────────────────────
|
// ─── Rows ────────────────────────────────────────────────────────────────
|
||||||
const rows: Row[] = useMemo(
|
const rows: Row[] = useMemo(
|
||||||
@@ -333,39 +324,15 @@ export default function Dashboard() {
|
|||||||
[totalCount, failedCount, successRate, throughput, exchangeTrend, successRateDelta, errorDelta, sparkExchanges, sparkErrors, sparkLatency, sparkThroughput, stats?.p99LatencyMs],
|
[totalCount, failedCount, successRate, throughput, exchangeTrend, successRateDelta, errorDelta, sparkExchanges, sparkErrors, sparkLatency, sparkThroughput, stats?.p99LatencyMs],
|
||||||
)
|
)
|
||||||
|
|
||||||
// ─── Table columns with inspect action ───────────────────────────────────
|
// ─── Table columns ──────────────────────────────────────────────────────
|
||||||
const columns: Column<Row>[] = useMemo(() => {
|
const columns: Column<Row>[] = useMemo(() => buildBaseColumns(), [])
|
||||||
const inspectCol: Column<Row> = {
|
|
||||||
key: 'correlationId',
|
|
||||||
header: '',
|
|
||||||
width: '36px',
|
|
||||||
render: (_: unknown, row: Row) => (
|
|
||||||
<button
|
|
||||||
className={styles.inspectLink}
|
|
||||||
title="Inspect exchange"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation()
|
|
||||||
navigate(`/exchanges/${row.applicationName}/${row.routeId}/${row.executionId}`)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ExternalLink size={14} />
|
|
||||||
</button>
|
|
||||||
),
|
|
||||||
}
|
|
||||||
const base = buildBaseColumns()
|
|
||||||
const [statusCol, ...rest] = base
|
|
||||||
return [statusCol, inspectCol, ...rest]
|
|
||||||
}, [navigate])
|
|
||||||
|
|
||||||
// ─── Row click / detail panel ────────────────────────────────────────────
|
// ─── Row click → navigate to diagram view ────────────────────────────────
|
||||||
const selectedRow = useMemo(
|
|
||||||
() => rows.find((r) => r.id === selectedId),
|
|
||||||
[rows, selectedId],
|
|
||||||
)
|
|
||||||
|
|
||||||
function handleRowClick(row: Row) {
|
function handleRowClick(row: Row) {
|
||||||
setSelectedId(row.id)
|
setSelectedId(row.id)
|
||||||
setPanelOpen(true)
|
// Navigate to the split view with diagram
|
||||||
|
navigate(`/exchanges/${row.applicationName}/${row.routeId}/${row.executionId}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRowAccent(row: Row): 'error' | 'warning' | undefined {
|
function handleRowAccent(row: Row): 'error' | 'warning' | undefined {
|
||||||
@@ -373,24 +340,6 @@ export default function Dashboard() {
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Detail panel data ───────────────────────────────────────────────────
|
|
||||||
const procList = detail
|
|
||||||
? (detail.processors ?? [])
|
|
||||||
: []
|
|
||||||
|
|
||||||
const routeFlows = useMemo(() => {
|
|
||||||
if (diagram?.nodes) {
|
|
||||||
return buildFlowSegments(diagram.nodes || [], procList).flows
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
}, [diagram, procList])
|
|
||||||
|
|
||||||
const flatProcs = useMemo(() => flattenProcessors(procList), [procList])
|
|
||||||
|
|
||||||
// Error info from detail
|
|
||||||
const errorClass = detail?.errorMessage?.split(':')[0] ?? ''
|
|
||||||
const errorMsg = detail?.errorMessage ?? ''
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Scrollable content */}
|
{/* Scrollable content */}
|
||||||
@@ -450,91 +399,6 @@ export default function Dashboard() {
|
|||||||
|
|
||||||
{/* Shortcuts bar */}
|
{/* Shortcuts bar */}
|
||||||
<ShortcutsBar shortcuts={SHORTCUTS} />
|
<ShortcutsBar shortcuts={SHORTCUTS} />
|
||||||
|
|
||||||
{/* Detail panel — auto-portals to AppShell level via design system */}
|
|
||||||
{selectedRow && detail && (
|
|
||||||
<DetailPanel
|
|
||||||
open={panelOpen}
|
|
||||||
onClose={() => setPanelOpen(false)}
|
|
||||||
title={`${detail.routeId} \u2014 ${selectedRow.executionId.slice(0, 12)}`}
|
|
||||||
>
|
|
||||||
<div className={styles.panelSection}>
|
|
||||||
<button
|
|
||||||
className={styles.openDetailLink}
|
|
||||||
onClick={() => navigate(`/exchanges/${detail.applicationName}/${detail.routeId}/${detail.executionId}`)}
|
|
||||||
>
|
|
||||||
Open full details →
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.panelSection}>
|
|
||||||
<div className={styles.panelSectionTitle}>Overview</div>
|
|
||||||
<div className={styles.overviewGrid}>
|
|
||||||
<div className={styles.overviewRow}>
|
|
||||||
<span className={styles.overviewLabel}>Status</span>
|
|
||||||
<span className={styles.statusCell}>
|
|
||||||
<StatusDot variant={statusToVariant(detail.status)} />
|
|
||||||
<span>{statusLabel(detail.status)}</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.overviewRow}>
|
|
||||||
<span className={styles.overviewLabel}>Duration</span>
|
|
||||||
<MonoText size="sm">{formatDuration(detail.durationMs)}</MonoText>
|
|
||||||
</div>
|
|
||||||
<div className={styles.overviewRow}>
|
|
||||||
<span className={styles.overviewLabel}>Route</span>
|
|
||||||
<span>{detail.routeId}</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.overviewRow}>
|
|
||||||
<span className={styles.overviewLabel}>Agent</span>
|
|
||||||
<MonoText size="sm">{detail.agentId ?? '\u2014'}</MonoText>
|
|
||||||
</div>
|
|
||||||
<div className={styles.overviewRow}>
|
|
||||||
<span className={styles.overviewLabel}>Correlation</span>
|
|
||||||
<MonoText size="xs">{detail.correlationId ?? '\u2014'}</MonoText>
|
|
||||||
</div>
|
|
||||||
<div className={styles.overviewRow}>
|
|
||||||
<span className={styles.overviewLabel}>Timestamp</span>
|
|
||||||
<MonoText size="xs">{detail.startTime ? new Date(detail.startTime).toISOString() : '\u2014'}</MonoText>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{errorMsg && (
|
|
||||||
<div className={styles.panelSection}>
|
|
||||||
<div className={styles.panelSectionTitle}>Errors</div>
|
|
||||||
<div className={styles.errorBlock}>
|
|
||||||
<div className={styles.errorClass}>{errorClass}</div>
|
|
||||||
<div className={styles.errorMessage}>{errorMsg}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className={styles.panelSection}>
|
|
||||||
<div className={styles.panelSectionTitle}>Route Flow</div>
|
|
||||||
{routeFlows.length > 0 ? (
|
|
||||||
<RouteFlow flows={routeFlows} />
|
|
||||||
) : (
|
|
||||||
<div style={{ color: 'var(--text-muted)', fontSize: 12 }}>No diagram available</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.panelSection}>
|
|
||||||
<div className={styles.panelSectionTitle}>
|
|
||||||
Processor Timeline
|
|
||||||
<span className={styles.panelSectionMeta}>{formatDuration(detail.durationMs)}</span>
|
|
||||||
</div>
|
|
||||||
{flatProcs.length > 0 ? (
|
|
||||||
<ProcessorTimeline
|
|
||||||
processors={flatProcs}
|
|
||||||
totalMs={detail.durationMs}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div style={{ color: 'var(--text-muted)', fontSize: 12 }}>No processor data</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</DetailPanel>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user