Implements the bottom detail panel with processor header bar, tab bar (Info, Headers, Input, Output, Error, Config, Timeline), and all tab content components. Info shows processor/exchange metadata in a grid, Headers fetches per-processor snapshots for side-by-side display, Input/Output render formatted code blocks, Error extracts exception types, Config is a placeholder, and Timeline renders a Gantt chart. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
116 lines
3.8 KiB
TypeScript
116 lines
3.8 KiB
TypeScript
import type { ProcessorNode, ExecutionDetail } from '../types';
|
|
import styles from '../ExecutionDiagram.module.css';
|
|
|
|
interface InfoTabProps {
|
|
processor: ProcessorNode | null;
|
|
executionDetail: ExecutionDetail;
|
|
}
|
|
|
|
function formatTime(iso: string | undefined): string {
|
|
if (!iso) return '-';
|
|
try {
|
|
const d = new Date(iso);
|
|
const h = String(d.getHours()).padStart(2, '0');
|
|
const m = String(d.getMinutes()).padStart(2, '0');
|
|
const s = String(d.getSeconds()).padStart(2, '0');
|
|
const ms = String(d.getMilliseconds()).padStart(3, '0');
|
|
return `${h}:${m}:${s}.${ms}`;
|
|
} catch {
|
|
return iso;
|
|
}
|
|
}
|
|
|
|
function formatDuration(ms: number | undefined): string {
|
|
if (ms === undefined || ms === null) return '-';
|
|
if (ms < 1000) return `${ms}ms`;
|
|
return `${(ms / 1000).toFixed(1)}s`;
|
|
}
|
|
|
|
function statusClass(status: string): string {
|
|
const s = status?.toUpperCase();
|
|
if (s === 'COMPLETED') return styles.statusCompleted;
|
|
if (s === 'FAILED') return styles.statusFailed;
|
|
return '';
|
|
}
|
|
|
|
function Field({ label, value, mono }: { label: string; value: string; mono?: boolean }) {
|
|
return (
|
|
<div>
|
|
<div className={styles.fieldLabel}>{label}</div>
|
|
<div className={mono ? styles.fieldValueMono : styles.fieldValue}>{value || '-'}</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function Attributes({ attrs }: { attrs: Record<string, string> | undefined }) {
|
|
if (!attrs) return null;
|
|
const entries = Object.entries(attrs);
|
|
if (entries.length === 0) return null;
|
|
|
|
return (
|
|
<div className={styles.attributesSection}>
|
|
<div className={styles.attributesLabel}>Attributes</div>
|
|
<div className={styles.attributesList}>
|
|
{entries.map(([k, v]) => (
|
|
<span key={k} className={styles.attributePill}>
|
|
{k}: {v}
|
|
</span>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function InfoTab({ processor, executionDetail }: InfoTabProps) {
|
|
if (processor) {
|
|
return (
|
|
<div>
|
|
<div className={styles.infoGrid}>
|
|
<Field label="Processor ID" value={processor.processorId} mono />
|
|
<Field label="Type" value={processor.processorType} />
|
|
<div>
|
|
<div className={styles.fieldLabel}>Status</div>
|
|
<span className={`${styles.statusBadge} ${statusClass(processor.status)}`}>
|
|
{processor.status}
|
|
</span>
|
|
</div>
|
|
|
|
<Field label="Start Time" value={formatTime(processor.startTime)} mono />
|
|
<Field label="End Time" value={formatTime(processor.endTime)} mono />
|
|
<Field label="Duration" value={formatDuration(processor.durationMs)} mono />
|
|
|
|
<Field label="Endpoint URI" value={processor.processorType} />
|
|
<Field label="Resolved URI" value="-" />
|
|
<div />
|
|
</div>
|
|
<Attributes attrs={processor.attributes} />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Exchange-level view
|
|
return (
|
|
<div>
|
|
<div className={styles.infoGrid}>
|
|
<Field label="Execution ID" value={executionDetail.executionId} mono />
|
|
<Field label="Correlation ID" value={executionDetail.correlationId} mono />
|
|
<Field label="Exchange ID" value={executionDetail.exchangeId} mono />
|
|
|
|
<Field label="Application" value={executionDetail.applicationName} />
|
|
<Field label="Route ID" value={executionDetail.routeId} />
|
|
<div>
|
|
<div className={styles.fieldLabel}>Status</div>
|
|
<span className={`${styles.statusBadge} ${statusClass(executionDetail.status)}`}>
|
|
{executionDetail.status}
|
|
</span>
|
|
</div>
|
|
|
|
<Field label="Start Time" value={formatTime(executionDetail.startTime)} mono />
|
|
<Field label="End Time" value={formatTime(executionDetail.endTime)} mono />
|
|
<Field label="Duration" value={formatDuration(executionDetail.durationMs)} mono />
|
|
</div>
|
|
<Attributes attrs={executionDetail.attributes} />
|
|
</div>
|
|
);
|
|
}
|