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