Files
cameleer-server/ui/src/pages/executions/ProcessorTree.tsx

71 lines
2.7 KiB
TypeScript
Raw Normal View History

import { useExecutionDetail } from '../../api/queries/executions';
import type { ProcessorNode as ProcessorNodeType } from '../../api/schema';
import styles from './ProcessorTree.module.css';
const ICON_MAP: Record<string, { label: string; className: string }> = {
from: { label: 'EP', className: styles.iconEndpoint },
to: { label: 'EP', className: styles.iconEndpoint },
toD: { label: 'EP', className: styles.iconEndpoint },
choice: { label: 'CB', className: styles.iconEip },
when: { label: 'CB', className: styles.iconEip },
otherwise: { label: 'CB', className: styles.iconEip },
split: { label: 'CB', className: styles.iconEip },
aggregate: { label: 'CB', className: styles.iconEip },
filter: { label: 'CB', className: styles.iconEip },
multicast: { label: 'CB', className: styles.iconEip },
recipientList: { label: 'CB', className: styles.iconEip },
routingSlip: { label: 'CB', className: styles.iconEip },
dynamicRouter: { label: 'CB', className: styles.iconEip },
exception: { label: '!!', className: styles.iconError },
onException: { label: '!!', className: styles.iconError },
};
function getIcon(type: string, status: string) {
if (status === 'FAILED') return { label: '!!', className: styles.iconError };
const key = type.toLowerCase();
return ICON_MAP[key] ?? { label: 'PR', className: styles.iconProcessor };
}
export function ProcessorTree({ executionId }: { executionId: string }) {
const { data, isLoading } = useExecutionDetail(executionId);
if (isLoading) return <div className={styles.tree}><div className={styles.loading}>Loading processor tree...</div></div>;
if (!data) return null;
return (
<div className={styles.tree}>
<h4 className={styles.title}>Processor Execution Tree</h4>
{data.processors.map((proc) => (
<ProcessorNodeView key={proc.index} node={proc} />
))}
</div>
);
}
function ProcessorNodeView({ node }: { node: ProcessorNodeType }) {
const icon = getIcon(node.processorType, node.status);
return (
<div>
<div className={styles.procNode}>
<div className={styles.procConnector} />
<div className={`${styles.procIcon} ${icon.className}`}>{icon.label}</div>
<div className={styles.procInfo}>
<div className={styles.procType}>{node.processorType}</div>
{node.uri && <div className={styles.procUri}>{node.uri}</div>}
</div>
<div className={styles.procTiming}>
<span className={styles.procDuration}>{node.duration}ms</span>
</div>
</div>
{node.children.length > 0 && (
<div className={styles.nested}>
{node.children.map((child) => (
<ProcessorNodeView key={child.index} node={child} />
))}
</div>
)}
</div>
);
}