diff --git a/frontend/src/pages/OrderDetail.tsx b/frontend/src/pages/OrderDetail.tsx index 4dbb7b5..1c97423 100644 --- a/frontend/src/pages/OrderDetail.tsx +++ b/frontend/src/pages/OrderDetail.tsx @@ -2,6 +2,55 @@ import { useParams } from '@tanstack/react-router'; import { useOrder } from '../api/hooks'; import { StatusBadge, LoadingSpinner, Card } from '../components/ui'; +/** + * Lightweight JSON syntax highlighter for read-only display. + * Returns React elements with colored spans for keys, strings, numbers, booleans, and null. + */ +function highlightJson(json: string): React.ReactNode { + const parts: React.ReactNode[] = []; + // Regex matches JSON tokens: strings, numbers, booleans, null, and structural chars + const tokenRe = /("(?:\\.|[^"\\])*")\s*:|("(?:\\.|[^"\\])*")|(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)|(\btrue\b|\bfalse\b)|(\bnull\b)|([{}[\],])/g; + let lastIndex = 0; + let match: RegExpExecArray | null; + + while ((match = tokenRe.exec(json)) !== null) { + // Add any whitespace/text between tokens + if (match.index > lastIndex) { + parts.push(json.slice(lastIndex, match.index)); + } + + if (match[1]) { + // Key (string followed by colon) + parts.push({match[1]}); + parts.push(':'); + } else if (match[2]) { + // String value + parts.push({match[2]}); + } else if (match[3]) { + // Number + parts.push({match[3]}); + } else if (match[4]) { + // Boolean + parts.push({match[4]}); + } else if (match[5]) { + // Null + parts.push({match[5]}); + } else if (match[6]) { + // Structural characters + parts.push({match[6]}); + } + + lastIndex = match.index + match[0].length; + } + + // Remaining text + if (lastIndex < json.length) { + parts.push(json.slice(lastIndex)); + } + + return <>{parts}>; +} + export function OrderDetailPage() { const { id } = useParams({ from: '/orders/$id' }); const { data: order, isLoading } = useOrder(id); @@ -33,8 +82,8 @@ export function OrderDetailPage() { {order.decision_trace && Object.keys(order.decision_trace).length > 0 && ( Decision Trace - - {JSON.stringify(order.decision_trace, null, 2)} + + {highlightJson(JSON.stringify(order.decision_trace, null, 2))} )}
- {JSON.stringify(order.decision_trace, null, 2)} + + {highlightJson(JSON.stringify(order.decision_trace, null, 2))}
+ {highlightJson(JSON.stringify(order.decision_trace, null, 2))}