Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions frontend/src/components/charts/backtest-folds-chart.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Legend, Cell } from 'recharts'
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Cell } from 'recharts'
import {
ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from '@/components/ui/chart'
Expand Down Expand Up @@ -76,10 +78,11 @@ export function BacktestFoldsChart({
<XAxis dataKey="foldLabel" tickLine={false} axisLine={false} />
<YAxis tickLine={false} axisLine={false} />
<ChartTooltip content={<ChartTooltipContent />} />
<Legend />
<ChartLegend content={<ChartLegendContent />} />
<Bar
dataKey={metricKey}
name={metricLabels[metricKey]}
fill={metricColors[metricKey]}
radius={[4, 4, 0, 0]}
>
{formattedData.map((_, index) => (
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/charts/kpi-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,16 @@ export function KPICard({
{Icon && <Icon className="h-4 w-4 text-muted-foreground" />}
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{value}</div>
<div className="text-3xl font-bold tracking-tight tabular-nums">{value}</div>
<div className="flex items-center gap-2 text-xs text-muted-foreground">
{trend && (
<span
className={cn(
'font-medium',
trend.value > 0
? 'text-green-600 dark:text-green-400'
? 'text-success'
: trend.value < 0
? 'text-red-600 dark:text-red-400'
? 'text-destructive'
: ''
)}
>
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/charts/time-series-chart.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Area, CartesianGrid, ComposedChart, Legend, Line, XAxis, YAxis } from 'recharts'
import { Area, CartesianGrid, ComposedChart, Line, XAxis, YAxis } from 'recharts'
import {
ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from '@/components/ui/chart'
Expand Down Expand Up @@ -88,7 +90,7 @@ export function TimeSeriesChart({
/>
<YAxis tickLine={false} axisLine={false} />
<ChartTooltip content={<ChartTooltipContent />} />
<Legend />
<ChartLegend content={<ChartLegendContent />} />
{/* Prediction-interval band — drawn first so the forecast line sits
on top. A function dataKey returns the [lower, upper] tuple
recharts renders as a range area. */}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/chat/chat-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export function ApprovalPrompt({
isLoading = false,
}: ApprovalPromptProps) {
return (
<div className="mx-4 my-2 p-4 border rounded-lg bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-800">
<div className="mx-4 my-2 p-4 border border-warning/30 rounded-lg bg-warning/10">
<p className="font-medium text-sm mb-2">Approval Required</p>
<p className="text-sm text-muted-foreground mb-3">
The agent wants to perform: <strong>{action}</strong>
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/components/chat/tool-call-display.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ export function ToolCallDisplay({ toolCall, className }: ToolCallDisplayProps) {

const statusIcon = {
pending: <Loader2 className="h-3 w-3 animate-spin text-muted-foreground" />,
running: <Loader2 className="h-3 w-3 animate-spin text-blue-500" />,
completed: <CheckCircle2 className="h-3 w-3 text-green-500" />,
failed: <XCircle className="h-3 w-3 text-red-500" />,
running: <Loader2 className="h-3 w-3 animate-spin text-info" />,
completed: <CheckCircle2 className="h-3 w-3 text-success" />,
failed: <XCircle className="h-3 w-3 text-destructive" />,
}

return (
Expand Down Expand Up @@ -77,9 +77,9 @@ export function ToolCallProgress({ toolName, status }: ToolCallProgressProps) {
{status === 'running' || status === 'starting' ? (
<Loader2 className="h-3 w-3 animate-spin" />
) : status === 'completed' ? (
<CheckCircle2 className="h-3 w-3 text-green-500" />
<CheckCircle2 className="h-3 w-3 text-success" />
) : (
<XCircle className="h-3 w-3 text-red-500" />
<XCircle className="h-3 w-3 text-destructive" />
)}
<Wrench className="h-3 w-3" />
<span>
Expand Down
49 changes: 46 additions & 3 deletions frontend/src/components/common/json-block.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,57 @@
import type { ReactNode } from 'react'
import { cn } from '@/lib/utils'

interface JsonBlockProps {
value: unknown
className?: string
}

// Matches a JSON string (group 1) with an optional key colon (group 2), a
// literal (group 3), or a number (group 4) in pretty-printed JSON.
const JSON_TOKEN =
/("(?:\\.|[^"\\])*")(\s*:)?|\b(true|false|null)\b|(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)/g

/**
* Tokenises pretty-printed JSON into syntax-highlighted spans. Token colours use
* the semantic status tokens — each verified to clear WCAG AA on the muted block
* background in both light and dark themes.
*/
function highlightJson(json: string): ReactNode[] {
const out: ReactNode[] = []
let lastIndex = 0
let key = 0
let match: RegExpExecArray | null
JSON_TOKEN.lastIndex = 0
while ((match = JSON_TOKEN.exec(json)) !== null) {
if (match.index > lastIndex) {
out.push(json.slice(lastIndex, match.index))
}
const [token, str, colon, literal, num] = match
let className = ''
if (str !== undefined) {
className = colon ? 'text-info' : 'text-success'
} else if (literal !== undefined) {
className = 'text-destructive'
} else if (num !== undefined) {
className = 'text-warning'
}
out.push(
<span key={key++} className={className}>
{token}
</span>,
)
lastIndex = match.index + token.length
}
if (lastIndex < json.length) {
out.push(json.slice(lastIndex))
}
return out
}

/**
* Read-only formatted-JSON viewer. Renders a muted em-dash for null/undefined,
* otherwise a scrollable, pretty-printed <pre> block. Intentionally has no
* syntax-highlighter dependency — it surfaces run/job JSONB payloads as-is.
* otherwise a scrollable, syntax-highlighted <pre> block surfacing run/job
* JSONB payloads.
*/
export function JsonBlock({ value, className }: JsonBlockProps) {
if (value === null || value === undefined) {
Expand All @@ -22,7 +65,7 @@ export function JsonBlock({ value, className }: JsonBlockProps) {
className,
)}
>
{JSON.stringify(value, null, 2)}
{highlightJson(JSON.stringify(value, null, 2))}
</pre>
)
}
10 changes: 5 additions & 5 deletions frontend/src/components/common/status-badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ const statusBadgeVariants = cva(
variants: {
variant: {
default: 'bg-secondary text-secondary-foreground',
success: 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400',
warning: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400',
error: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400',
info: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400',
pending: 'bg-gray-100 text-gray-800 dark:bg-gray-700/30 dark:text-gray-400',
success: 'bg-success text-success-foreground',
warning: 'bg-warning text-warning-foreground',
error: 'bg-destructive text-destructive-foreground',
info: 'bg-info text-info-foreground',
pending: 'bg-muted text-muted-foreground',
},
},
defaultVariants: {
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/data-table/data-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ export function DataTable<TData, TValue>({
<DataTableViewOptions table={table} />
</div>
)}
<div className="rounded-md border">
{/* Light: elevated white panel. dark: overrides keep the existing
borderless-on-canvas look unchanged. */}
<div className="rounded-md border bg-card shadow-card overflow-hidden dark:bg-transparent dark:shadow-none">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/components/demo/demo-step-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ const STATUS_GLYPH: Record<DemoStepUiStatus, string> = {
// Left-border accent colour per status.
const STATUS_ACCENT: Record<DemoStepUiStatus, string> = {
idle: 'border-l-border',
running: 'border-l-blue-500',
pass: 'border-l-green-500',
fail: 'border-l-red-500',
running: 'border-l-info',
pass: 'border-l-success',
fail: 'border-l-destructive',
skip: 'border-l-muted-foreground/40',
warn: 'border-l-yellow-500',
warn: 'border-l-warning',
}

function formatDuration(ms: number): string {
Expand Down Expand Up @@ -50,7 +50,7 @@ function BacktestBreakdown({ data }: { data: Record<string, unknown> }) {
className={cn(
'flex items-center justify-between rounded-md px-2 py-1 text-xs',
row.model === winner
? 'bg-green-100 font-semibold dark:bg-green-900/30'
? 'bg-success/10 font-semibold'
: 'bg-muted'
)}
>
Expand Down
12 changes: 8 additions & 4 deletions frontend/src/components/layout/top-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ export function TopNav() {
to={subItem.href}
className={cn(
'block select-none rounded-md p-2 text-sm leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground',
isActive(subItem.href) && 'bg-accent/50'
isActive(subItem.href) &&
'bg-accent font-medium text-accent-foreground'
)}
>
{subItem.label}
Expand All @@ -75,7 +76,8 @@ export function TopNav() {
to={item.href}
className={cn(
navigationMenuTriggerStyle(),
isActive(item.href) && 'bg-accent/50'
isActive(item.href) &&
'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground'
)}
>
{item.label}
Expand Down Expand Up @@ -121,7 +123,8 @@ export function TopNav() {
onClick={() => setMobileMenuOpen(false)}
className={cn(
'block rounded-md px-2 py-1.5 text-sm hover:bg-accent',
isActive(subItem.href) && 'bg-accent/50 font-medium'
isActive(subItem.href) &&
'bg-accent font-medium text-accent-foreground'
)}
>
{subItem.label}
Expand All @@ -135,7 +138,8 @@ export function TopNav() {
onClick={() => setMobileMenuOpen(false)}
className={cn(
'block rounded-md px-2 py-1.5 text-sm font-medium hover:bg-accent',
isActive(item.href) && 'bg-accent/50'
isActive(item.href) &&
'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground'
)}
>
{item.label}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ui/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
<div
data-slot="card"
className={cn(
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-card",
className
)}
{...props}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ui/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
return (
<thead
data-slot="table-header"
className={cn("[&_tr]:border-b", className)}
className={cn("bg-(--table-header) [&_tr]:border-b", className)}
{...props}
/>
)
Expand Down
Loading