121 lines
3.6 KiB
TypeScript
121 lines
3.6 KiB
TypeScript
|
|
import { useState } from 'react';
|
||
|
|
import type { ExecutionSummary } from '../../api/schema';
|
||
|
|
import { StatusPill } from '../../components/shared/StatusPill';
|
||
|
|
import { DurationBar } from '../../components/shared/DurationBar';
|
||
|
|
import { AppBadge } from '../../components/shared/AppBadge';
|
||
|
|
import { ProcessorTree } from './ProcessorTree';
|
||
|
|
import { ExchangeDetail } from './ExchangeDetail';
|
||
|
|
import styles from './ResultsTable.module.css';
|
||
|
|
|
||
|
|
interface ResultsTableProps {
|
||
|
|
results: ExecutionSummary[];
|
||
|
|
loading: boolean;
|
||
|
|
}
|
||
|
|
|
||
|
|
function formatTime(iso: string) {
|
||
|
|
return new Date(iso).toLocaleTimeString('en-GB', {
|
||
|
|
hour: '2-digit',
|
||
|
|
minute: '2-digit',
|
||
|
|
second: '2-digit',
|
||
|
|
fractionalSecondDigits: 3,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function ResultsTable({ results, loading }: ResultsTableProps) {
|
||
|
|
const [expandedId, setExpandedId] = useState<string | null>(null);
|
||
|
|
|
||
|
|
if (loading && results.length === 0) {
|
||
|
|
return (
|
||
|
|
<div className={styles.tableWrap}>
|
||
|
|
<div className={styles.loadingOverlay}>Loading executions...</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (results.length === 0) {
|
||
|
|
return (
|
||
|
|
<div className={styles.tableWrap}>
|
||
|
|
<div className={styles.emptyState}>No executions found matching your filters.</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className={styles.tableWrap}>
|
||
|
|
<table className={styles.table}>
|
||
|
|
<thead className={styles.thead}>
|
||
|
|
<tr>
|
||
|
|
<th className={styles.th} style={{ width: 32 }} />
|
||
|
|
<th className={styles.th}>Timestamp</th>
|
||
|
|
<th className={styles.th}>Status</th>
|
||
|
|
<th className={styles.th}>Application</th>
|
||
|
|
<th className={styles.th}>Route</th>
|
||
|
|
<th className={styles.th}>Correlation ID</th>
|
||
|
|
<th className={styles.th}>Duration</th>
|
||
|
|
<th className={styles.th}>Processors</th>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody>
|
||
|
|
{results.map((exec) => {
|
||
|
|
const isExpanded = expandedId === exec.executionId;
|
||
|
|
return (
|
||
|
|
<ResultRow
|
||
|
|
key={exec.executionId}
|
||
|
|
exec={exec}
|
||
|
|
isExpanded={isExpanded}
|
||
|
|
onToggle={() => setExpandedId(isExpanded ? null : exec.executionId)}
|
||
|
|
/>
|
||
|
|
);
|
||
|
|
})}
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
function ResultRow({
|
||
|
|
exec,
|
||
|
|
isExpanded,
|
||
|
|
onToggle,
|
||
|
|
}: {
|
||
|
|
exec: ExecutionSummary;
|
||
|
|
isExpanded: boolean;
|
||
|
|
onToggle: () => void;
|
||
|
|
}) {
|
||
|
|
return (
|
||
|
|
<>
|
||
|
|
<tr
|
||
|
|
className={`${styles.row} ${isExpanded ? styles.expanded : ''}`}
|
||
|
|
onClick={onToggle}
|
||
|
|
>
|
||
|
|
<td className={`${styles.td} ${styles.tdExpand}`}>›</td>
|
||
|
|
<td className={`${styles.td} mono`}>{formatTime(exec.startTime)}</td>
|
||
|
|
<td className={styles.td}>
|
||
|
|
<StatusPill status={exec.status} />
|
||
|
|
</td>
|
||
|
|
<td className={styles.td}>
|
||
|
|
<AppBadge name={exec.agentId} />
|
||
|
|
</td>
|
||
|
|
<td className={`${styles.td} mono text-secondary`}>{exec.routeId}</td>
|
||
|
|
<td className={`${styles.td} mono text-muted ${styles.correlationId}`} title={exec.correlationId ?? ''}>
|
||
|
|
{exec.correlationId ?? '-'}
|
||
|
|
</td>
|
||
|
|
<td className={styles.td}>
|
||
|
|
<DurationBar duration={exec.duration} />
|
||
|
|
</td>
|
||
|
|
<td className={`${styles.td} mono text-muted`}>{exec.processorCount}</td>
|
||
|
|
</tr>
|
||
|
|
{isExpanded && (
|
||
|
|
<tr className={styles.detailRowVisible}>
|
||
|
|
<td className={styles.detailCell} colSpan={8}>
|
||
|
|
<div className={styles.detailContent}>
|
||
|
|
<ProcessorTree executionId={exec.executionId} />
|
||
|
|
<ExchangeDetail execution={exec} />
|
||
|
|
</div>
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
)}
|
||
|
|
</>
|
||
|
|
);
|
||
|
|
}
|