e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
133 lines
3.7 KiB
TypeScript
133 lines
3.7 KiB
TypeScript
"use client";
|
|
|
|
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
import {
|
|
BarChart,
|
|
Bar,
|
|
LineChart,
|
|
Line,
|
|
PieChart,
|
|
Pie,
|
|
Cell,
|
|
XAxis,
|
|
YAxis,
|
|
CartesianGrid,
|
|
Tooltip,
|
|
Legend,
|
|
ResponsiveContainer,
|
|
} from "recharts";
|
|
import { Loader2Icon } from "lucide-react";
|
|
|
|
type ChartArgs = {
|
|
title: string;
|
|
type: "bar" | "line" | "pie";
|
|
data: Array<Record<string, string | number>>;
|
|
xKey: string;
|
|
dataKeys: string[];
|
|
};
|
|
|
|
type ChartResult = {
|
|
success: boolean;
|
|
};
|
|
|
|
const COLORS = [
|
|
"oklch(0.646 0.222 41.116)",
|
|
"oklch(0.6 0.118 184.704)",
|
|
"oklch(0.398 0.07 227.392)",
|
|
"oklch(0.828 0.189 84.429)",
|
|
"oklch(0.769 0.188 70.08)",
|
|
];
|
|
|
|
export const ChartToolUI: ToolCallMessagePartComponent<ChartArgs, ChartResult> =
|
|
function ChartUI({ args, status }) {
|
|
if (status.type === "running" && !args.data?.length) {
|
|
return (
|
|
<div className="flex items-center gap-2 rounded-lg border p-4">
|
|
<Loader2Icon className="text-muted-foreground size-4 animate-spin" />
|
|
<span className="text-muted-foreground text-sm">
|
|
Generating chart...
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const { title, type, data, xKey, dataKeys } = args;
|
|
if (!data?.length || !dataKeys?.length) return null;
|
|
|
|
return (
|
|
<div className="my-2 rounded-lg border p-4">
|
|
<h3 className="mb-3 text-center text-sm font-semibold">{title}</h3>
|
|
<div className="h-[280px] w-full">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
{type === "bar" ? (
|
|
<BarChart data={data}>
|
|
<CartesianGrid strokeDasharray="3 3" vertical={false} />
|
|
<XAxis
|
|
dataKey={xKey}
|
|
tickLine={false}
|
|
axisLine={false}
|
|
fontSize={12}
|
|
/>
|
|
<YAxis tickLine={false} axisLine={false} fontSize={12} />
|
|
<Tooltip />
|
|
<Legend />
|
|
{dataKeys.map((key, i) => (
|
|
<Bar
|
|
key={key}
|
|
dataKey={key}
|
|
fill={COLORS[i % COLORS.length]}
|
|
radius={[4, 4, 0, 0]}
|
|
/>
|
|
))}
|
|
</BarChart>
|
|
) : type === "line" ? (
|
|
<LineChart data={data}>
|
|
<CartesianGrid strokeDasharray="3 3" vertical={false} />
|
|
<XAxis
|
|
dataKey={xKey}
|
|
tickLine={false}
|
|
axisLine={false}
|
|
fontSize={12}
|
|
/>
|
|
<YAxis tickLine={false} axisLine={false} fontSize={12} />
|
|
<Tooltip />
|
|
<Legend />
|
|
{dataKeys.map((key, i) => (
|
|
<Line
|
|
key={key}
|
|
type="monotone"
|
|
dataKey={key}
|
|
stroke={COLORS[i % COLORS.length] ?? "#8884d8"}
|
|
strokeWidth={2}
|
|
dot={false}
|
|
/>
|
|
))}
|
|
</LineChart>
|
|
) : (
|
|
<PieChart>
|
|
<Tooltip />
|
|
<Legend />
|
|
<Pie
|
|
data={data}
|
|
dataKey={dataKeys[0]!}
|
|
nameKey={xKey}
|
|
cx="50%"
|
|
cy="50%"
|
|
outerRadius={80}
|
|
label
|
|
>
|
|
{data.map((_, i) => (
|
|
<Cell
|
|
key={i}
|
|
fill={COLORS[i % COLORS.length] ?? "#8884d8"}
|
|
/>
|
|
))}
|
|
</Pie>
|
|
</PieChart>
|
|
)}
|
|
</ResponsiveContainer>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|