Fix UI types to match actual backend API
Validated against live OpenAPI spec at /api/v1/api-docs. Fixes: - duration → durationMs (all models) - Remove processorCount (not in ExecutionSummary) - Remove ProcessorNode.index and .uri (not in backend) - ProcessorSnapshot is Record<string,string>, not structured object - Add missing fields: endTime, diagramContentHash, exchangeId, etc. - Save openapi.json from live server Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1071
ui/src/api/openapi.json
Normal file
1071
ui/src/api/openapi.json
Normal file
File diff suppressed because it is too large
Load Diff
41
ui/src/api/schema.d.ts
vendored
41
ui/src/api/schema.d.ts
vendored
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Hand-written OpenAPI types matching the cameleer3 server REST API.
|
||||
* Will be replaced by openapi-typescript codegen once backend is running.
|
||||
* Types matching the cameleer3 server REST API (validated against live OpenAPI spec).
|
||||
* Generated from: GET /api/v1/api-docs
|
||||
*/
|
||||
|
||||
export interface paths {
|
||||
@@ -88,7 +88,7 @@ export interface paths {
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
'application/json': ExchangeSnapshot;
|
||||
'application/json': ProcessorSnapshot;
|
||||
};
|
||||
};
|
||||
404: { content: { 'application/json': { message: string } } };
|
||||
@@ -137,45 +137,46 @@ export interface ExecutionSummary {
|
||||
executionId: string;
|
||||
routeId: string;
|
||||
agentId: string;
|
||||
status: 'COMPLETED' | 'FAILED' | 'RUNNING';
|
||||
status: string;
|
||||
startTime: string;
|
||||
duration: number;
|
||||
processorCount: number;
|
||||
endTime: string | null;
|
||||
durationMs: number;
|
||||
correlationId: string | null;
|
||||
errorMessage: string | null;
|
||||
diagramContentHash: string | null;
|
||||
}
|
||||
|
||||
export interface ExecutionDetail {
|
||||
executionId: string;
|
||||
routeId: string;
|
||||
agentId: string;
|
||||
status: 'COMPLETED' | 'FAILED' | 'RUNNING';
|
||||
status: string;
|
||||
startTime: string;
|
||||
duration: number;
|
||||
endTime: string | null;
|
||||
durationMs: number;
|
||||
correlationId: string | null;
|
||||
exchangeId: string | null;
|
||||
errorMessage: string | null;
|
||||
errorStackTrace: string | null;
|
||||
diagramContentHash: string | null;
|
||||
processors: ProcessorNode[];
|
||||
}
|
||||
|
||||
export interface ProcessorNode {
|
||||
index: number;
|
||||
processorId: string;
|
||||
processorType: string;
|
||||
uri: string | null;
|
||||
status: 'COMPLETED' | 'FAILED' | 'RUNNING';
|
||||
duration: number;
|
||||
status: string;
|
||||
startTime: string;
|
||||
endTime: string | null;
|
||||
durationMs: number;
|
||||
diagramNodeId: string | null;
|
||||
errorMessage: string | null;
|
||||
errorStackTrace: string | null;
|
||||
children: ProcessorNode[];
|
||||
}
|
||||
|
||||
export interface ExchangeSnapshot {
|
||||
exchangeId: string;
|
||||
correlationId: string | null;
|
||||
bodyType: string | null;
|
||||
body: string | null;
|
||||
headers: Record<string, string> | null;
|
||||
properties: Record<string, string> | null;
|
||||
}
|
||||
/** Processor snapshot is a flat key-value map (Map<String, String> in Java) */
|
||||
export type ProcessorSnapshot = Record<string, string>;
|
||||
|
||||
export interface AgentInstance {
|
||||
agentId: string;
|
||||
|
||||
@@ -7,14 +7,16 @@ interface ExchangeDetailProps {
|
||||
}
|
||||
|
||||
export function ExchangeDetail({ execution }: ExchangeDetailProps) {
|
||||
// Fetch the first processor's snapshot (index 0) for body preview
|
||||
// Fetch the first processor's snapshot (index 0) — returns Record<string, string>
|
||||
const { data: snapshot } = useProcessorSnapshot(execution.executionId, 0);
|
||||
|
||||
const body = snapshot?.['body'];
|
||||
|
||||
return (
|
||||
<div className={styles.sidebar}>
|
||||
<h4 className={styles.title}>Exchange Details</h4>
|
||||
<dl className={styles.kv}>
|
||||
<dt className={styles.kvKey}>Exchange ID</dt>
|
||||
<dt className={styles.kvKey}>Execution ID</dt>
|
||||
<dd className={styles.kvValue}>{execution.executionId}</dd>
|
||||
<dt className={styles.kvKey}>Correlation</dt>
|
||||
<dd className={styles.kvValue}>{execution.correlationId ?? '-'}</dd>
|
||||
@@ -25,15 +27,13 @@ export function ExchangeDetail({ execution }: ExchangeDetailProps) {
|
||||
<dt className={styles.kvKey}>Timestamp</dt>
|
||||
<dd className={styles.kvValue}>{new Date(execution.startTime).toISOString()}</dd>
|
||||
<dt className={styles.kvKey}>Duration</dt>
|
||||
<dd className={styles.kvValue}>{execution.duration}ms</dd>
|
||||
<dt className={styles.kvKey}>Processors</dt>
|
||||
<dd className={styles.kvValue}>{execution.processorCount}</dd>
|
||||
<dd className={styles.kvValue}>{execution.durationMs}ms</dd>
|
||||
</dl>
|
||||
|
||||
{snapshot?.body && (
|
||||
{body && (
|
||||
<div className={styles.bodyPreview}>
|
||||
<span className={styles.bodyLabel}>Input Body</span>
|
||||
{snapshot.body}
|
||||
{body}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ export function ExecutionExplorer() {
|
||||
// Derive stats from current search results
|
||||
const failedCount = results.filter((r) => r.status === 'FAILED').length;
|
||||
const avgDuration = results.length > 0
|
||||
? Math.round(results.reduce((sum, r) => sum + r.duration, 0) / results.length)
|
||||
? Math.round(results.reduce((sum, r) => sum + r.durationMs, 0) / results.length)
|
||||
: 0;
|
||||
|
||||
const showFrom = total > 0 ? offset + 1 : 0;
|
||||
|
||||
@@ -35,8 +35,8 @@ export function ProcessorTree({ executionId }: { executionId: string }) {
|
||||
return (
|
||||
<div className={styles.tree}>
|
||||
<h4 className={styles.title}>Processor Execution Tree</h4>
|
||||
{data.processors.map((proc) => (
|
||||
<ProcessorNodeView key={proc.index} node={proc} />
|
||||
{data.processors.map((proc, i) => (
|
||||
<ProcessorNodeView key={proc.processorId ?? i} node={proc} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
@@ -52,16 +52,15 @@ function ProcessorNodeView({ node }: { node: ProcessorNodeType }) {
|
||||
<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>
|
||||
<span className={styles.procDuration}>{node.durationMs}ms</span>
|
||||
</div>
|
||||
</div>
|
||||
{node.children.length > 0 && (
|
||||
<div className={styles.nested}>
|
||||
{node.children.map((child) => (
|
||||
<ProcessorNodeView key={child.index} node={child} />
|
||||
{node.children.map((child, i) => (
|
||||
<ProcessorNodeView key={child.processorId ?? i} node={child} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -52,7 +52,6 @@ export function ResultsTable({ results, loading }: ResultsTableProps) {
|
||||
<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>
|
||||
@@ -101,13 +100,12 @@ function ResultRow({
|
||||
{exec.correlationId ?? '-'}
|
||||
</td>
|
||||
<td className={styles.td}>
|
||||
<DurationBar duration={exec.duration} />
|
||||
<DurationBar duration={exec.durationMs} />
|
||||
</td>
|
||||
<td className={`${styles.td} mono text-muted`}>{exec.processorCount}</td>
|
||||
</tr>
|
||||
{isExpanded && (
|
||||
<tr className={styles.detailRowVisible}>
|
||||
<td className={styles.detailCell} colSpan={8}>
|
||||
<td className={styles.detailCell} colSpan={7}>
|
||||
<div className={styles.detailContent}>
|
||||
<ProcessorTree executionId={exec.executionId} />
|
||||
<ExchangeDetail execution={exec} />
|
||||
|
||||
Reference in New Issue
Block a user