feat(ui): show process diagram when route is selected in sidebar
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m47s
CI / docker (push) Successful in 1m3s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 37s

This commit is contained in:
hsiegeln
2026-03-28 15:58:38 +01:00
parent 2fade7192a
commit 816a034d4a

View File

@@ -1,5 +1,5 @@
import { useState, useMemo, useCallback, useRef, useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router';
import { useNavigate, useLocation, useParams } from 'react-router';
import { useGlobalFilters } from '@cameleer/design-system';
import { useExecutionDetail } from '../../api/queries/executions';
import { useDiagramByRoute } from '../../api/queries/diagrams';
@@ -16,6 +16,7 @@ import type { SelectedExchange } from '../Dashboard/Dashboard';
export default function ExchangesPage() {
const navigate = useNavigate();
const location = useLocation();
const { appId: scopedAppId, routeId: scopedRouteId } = useParams<{ appId?: string; routeId?: string }>();
// Restore selection from browser history state (enables Back/Forward)
const stateSelected = (location.state as any)?.selectedExchange as SelectedExchange | undefined;
@@ -70,12 +71,18 @@ export default function ExchangesPage() {
document.addEventListener('pointerup', onUp);
}, []);
// No exchange selected: full-width Dashboard
if (!selected) {
// Show split view when a route is scoped (sidebar) or an exchange is selected
const showSplit = !!selected || !!scopedRouteId;
if (!showSplit) {
return <Dashboard onExchangeSelect={handleExchangeSelect} />;
}
// Exchange selected: resizable split — Dashboard on left, diagram on right
// Determine what the right panel shows
const panelAppId = selected?.applicationName ?? scopedAppId!;
const panelRouteId = selected?.routeId ?? scopedRouteId!;
const panelExchangeId = selected?.executionId ?? undefined;
return (
<div ref={containerRef} className={styles.splitView}>
<div className={styles.leftPanel} style={{ width: `${splitPercent}%` }}>
@@ -84,9 +91,9 @@ export default function ExchangesPage() {
<div className={styles.splitter} onPointerDown={handleSplitterDown} />
<div className={styles.rightPanel} style={{ width: `${100 - splitPercent}%` }}>
<DiagramPanel
appId={selected.applicationName}
routeId={selected.routeId}
exchangeId={selected.executionId}
appId={panelAppId}
routeId={panelRouteId}
exchangeId={panelExchangeId}
onCorrelatedSelect={handleCorrelatedSelect}
onClearSelection={handleClearSelection}
/>
@@ -100,7 +107,7 @@ export default function ExchangesPage() {
interface DiagramPanelProps {
appId: string;
routeId: string;
exchangeId: string;
exchangeId?: string;
onCorrelatedSelect: (executionId: string, applicationName: string, routeId: string) => void;
onClearSelection: () => void;
}
@@ -111,7 +118,8 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
const timeFrom = timeRange.start.toISOString();
const timeTo = timeRange.end.toISOString();
const { data: detail } = useExecutionDetail(exchangeId);
const { data: detail } = useExecutionDetail(exchangeId ?? null);
const diagramQuery = useDiagramByRoute(appId, routeId);
const { data: catalog } = useRouteCatalog(timeFrom, timeTo);
const knownRouteIds = useMemo(() => {
@@ -132,7 +140,8 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
}
}, [appId, navigate]);
if (detail) {
// Exchange selected: show header + execution diagram
if (exchangeId && detail) {
return (
<>
<ExchangeHeader detail={detail} onCorrelatedSelect={onCorrelatedSelect} onClearSelection={onClearSelection} />
@@ -146,9 +155,22 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
);
}
// No exchange selected: show topology-only diagram
if (diagramQuery.data) {
return (
<ProcessDiagram
application={appId}
routeId={routeId}
diagramLayout={diagramQuery.data}
knownRouteIds={knownRouteIds}
onNodeAction={handleNodeAction}
/>
);
}
return (
<div className={styles.emptyRight}>
Loading execution...
Loading diagram...
</div>
);
}