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
72 changes: 66 additions & 6 deletions ui/app/workspace/dashboard/components/charts/chartCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Card } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import type { ReactNode } from "react";

Expand All @@ -13,10 +14,21 @@ interface ChartCardProps {
className?: string;
total?: ReactNode;
totalLabel?: string;
totalTooltip?: ReactNode;
}

function TotalChip({ total, totalLabel, testId }: { total: ReactNode; totalLabel?: string; testId?: string }) {
return (
function TotalChip({
total,
totalLabel,
totalTooltip,
testId,
}: {
total: ReactNode;
totalLabel?: string;
totalTooltip?: ReactNode;
testId?: string;
}) {
const chip = (
<span
className="text-muted-foreground flex shrink-0 items-baseline gap-1 pl-2 text-xs"
data-testid={testId ? `${testId}-total` : undefined}
Expand All @@ -25,6 +37,21 @@ function TotalChip({ total, totalLabel, testId }: { total: ReactNode; totalLabel
<span className="text-primary text-sm font-semibold tabular-nums">{total}</span>
</span>
);

if (totalTooltip === undefined || totalTooltip === null) {
return chip;
}

return (
<Tooltip>
<TooltipTrigger asChild>
<span tabIndex={0} data-testid={testId ? `${testId}-total-trigger` : undefined}>
{chip}
</span>
</TooltipTrigger>
<TooltipContent data-testid={testId ? `${testId}-total-tooltip` : undefined}>{totalTooltip}</TooltipContent>
</Tooltip>
);
}

function Header({
Expand All @@ -33,13 +60,15 @@ function Header({
legend,
total,
totalLabel,
totalTooltip,
testId,
}: {
title: string;
controls?: ReactNode;
legend?: ReactNode;
total?: ReactNode;
totalLabel?: string;
totalTooltip?: ReactNode;
testId?: string;
}) {
const hasTotal = total !== undefined && total !== null;
Expand All @@ -51,7 +80,11 @@ function Header({
</div>
{hasActionRow && (
<div className="flex h-7 w-full min-w-0 items-center justify-between gap-3" data-testid={testId ? `${testId}-actions` : undefined}>
{hasTotal ? <TotalChip total={total} totalLabel={totalLabel} testId={testId} /> : <span className="shrink-0" />}
{hasTotal ? (
<TotalChip total={total} totalLabel={totalLabel} totalTooltip={totalTooltip} testId={testId} />
) : (
<span className="shrink-0" />
)}
{controls && <div className="flex shrink-0 items-center gap-2">{controls}</div>}
</div>
)}
Expand All @@ -60,11 +93,30 @@ function Header({
);
}

export function ChartCard({ title, children, controls, legend, loading, testId, className, total, totalLabel }: ChartCardProps) {
export function ChartCard({
title,
children,
controls,
legend,
loading,
testId,
className,
total,
totalLabel,
totalTooltip,
}: ChartCardProps) {
if (loading) {
return (
<Card className={cn("min-w-0 rounded-sm p-2 shadow-none h-[330px]", className)} data-testid={testId}>
<Header title={title} controls={controls} legend={legend} total={total} totalLabel={totalLabel} testId={testId} />
<Header
title={title}
controls={controls}
legend={legend}
total={total}
totalLabel={totalLabel}
totalTooltip={totalTooltip}
testId={testId}
/>
<div className="grow" data-testid={testId ? `${testId}-chart-skeleton` : undefined}>
<Skeleton className="h-full w-full" />
</div>
Expand All @@ -74,7 +126,15 @@ export function ChartCard({ title, children, controls, legend, loading, testId,

return (
<Card className={cn("min-w-0 rounded-sm p-2 shadow-none h-[330px]", className)} data-testid={testId}>
<Header title={title} controls={controls} legend={legend} total={total} totalLabel={totalLabel} testId={testId} />
<Header
title={title}
controls={controls}
legend={legend}
total={total}
totalLabel={totalLabel}
totalTooltip={totalTooltip}
testId={testId}
/>
<div className="grow">{children}</div>
</Card>
);
Expand Down
5 changes: 3 additions & 2 deletions ui/app/workspace/dashboard/components/charts/costChart.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { CostHistogramResponse } from "@/lib/types/logs";
import { formatCurrencyNumber } from "@/lib/utils/numbers";
import { memo, useMemo } from "react";
import { Area, AreaChart, Bar, BarChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
import {
Expand Down Expand Up @@ -136,7 +137,7 @@ function CostChartImpl({ data, chartType, startTime, endTime, selectedModel }: C
tickLine={false}
axisLine={false}
width={50}
tickFormatter={(v) => formatCost(v)}
tickFormatter={(v) => formatCurrencyNumber(v)}
domain={[0, (dataMax: number) => Math.max(dataMax, 0.01)]}
allowDataOverflow={false}
/>
Expand Down Expand Up @@ -172,7 +173,7 @@ function CostChartImpl({ data, chartType, startTime, endTime, selectedModel }: C
tickLine={false}
axisLine={false}
width={50}
tickFormatter={(v) => formatCost(v)}
tickFormatter={(v) => formatCurrencyNumber(v)}
domain={[0, (dataMax: number) => Math.max(dataMax, 0.01)]}
allowDataOverflow={false}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import type { TokenHistogramResponse } from "@/lib/types/logs";
import { formatCompactNumber } from "@/lib/utils/numbers";
import { Info } from "lucide-react";
import { memo, useMemo } from "react";
import { Cell, Pie, PieChart, ResponsiveContainer } from "recharts";
Expand All @@ -12,12 +13,6 @@ interface ExternalCacheTokenMeterChartProps {

const METER_COLORS = { cached: "#06b6d4", input: "#3b82f6" };

const formatTokenCount = (count: number): string => {
if (count >= 1000000) return `${(count / 1000000).toFixed(1)}M`;
if (count >= 1000) return `${(count / 1000).toFixed(1)}K`;
return count.toLocaleString();
};

function ExternalCacheTokenMeterChartImpl({ data }: ExternalCacheTokenMeterChartProps) {
const { ref, width, height } = useGaugeSize();

Expand Down Expand Up @@ -101,11 +96,11 @@ function ExternalCacheTokenMeterChartImpl({ data }: ExternalCacheTokenMeterChart
<div className="flex shrink-0 flex-wrap items-center justify-center gap-x-4 gap-y-1 pt-2 text-[11px] leading-none">
<span className="flex items-center gap-1.5">
<span className="h-2 w-2 rounded-full" style={{ backgroundColor: METER_COLORS.cached }} />
<span className="text-primary">Cached: {formatTokenCount(totalCachedRead)}</span>
<span className="text-primary">Cached: {formatCompactNumber(totalCachedRead)}</span>
</span>
<span className="flex items-center gap-1.5">
<span className="h-2 w-2 rounded-full" style={{ backgroundColor: METER_COLORS.input }} />
<span className="text-muted-foreground">Input: {formatTokenCount(totalPromptTokens)}</span>
<span className="text-muted-foreground">Input: {formatCompactNumber(totalPromptTokens)}</span>
</span>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { LogsHistogramResponse } from "@/lib/types/logs";
import { memo, useMemo } from "react";
import { Area, AreaChart, Bar, BarChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
import { CHART_COLORS, formatFullTimestamp, formatTimestamp, formatTokens } from "../../utils/chartUtils";
import { formatCompactNumber } from "@/lib/utils/numbers";
import { CHART_COLORS, formatFullTimestamp, formatTimestamp } from "../../utils/chartUtils";
import { ChartErrorBoundary } from "./chartErrorBoundary";
import type { ChartType } from "./chartTypeToggle";

Expand Down Expand Up @@ -98,7 +99,7 @@ function LogVolumeChartImpl({ data, chartType, startTime, endTime }: LogVolumeCh
tickLine={false}
axisLine={false}
width={44}
tickFormatter={formatTokens}
tickFormatter={(v) => formatCompactNumber(v)}
domain={[0, (dataMax: number) => Math.max(dataMax, 1)]}
allowDataOverflow={false}
/>
Expand Down Expand Up @@ -140,7 +141,7 @@ function LogVolumeChartImpl({ data, chartType, startTime, endTime }: LogVolumeCh
tickLine={false}
axisLine={false}
width={44}
tickFormatter={formatTokens}
tickFormatter={(v) => formatCompactNumber(v)}
domain={[0, (dataMax: number) => Math.max(dataMax, 1)]}
allowDataOverflow={false}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { MCPTopToolsResponse } from "@/lib/types/logs";
import { memo, useMemo } from "react";
import { Bar, BarChart, CartesianGrid, Cell, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
import { formatCost, formatTokens, getModelColor } from "../../utils/chartUtils";
import { formatCompactNumber } from "@/lib/utils/numbers";
import { formatCost, getModelColor } from "../../utils/chartUtils";
import { ChartErrorBoundary } from "./chartErrorBoundary";

interface MCPTopToolsChartProps {
Expand Down Expand Up @@ -54,7 +55,7 @@ function MCPTopToolsChartImpl({ data }: MCPTopToolsChartProps) {
tick={{ fontSize: 11, className: "fill-zinc-500" }}
tickLine={false}
axisLine={false}
tickFormatter={formatTokens}
tickFormatter={(v) => formatCompactNumber(v)}
domain={[0, (dataMax: number) => Math.max(dataMax, 1)]}
allowDataOverflow={false}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { MCPHistogramResponse } from "@/lib/types/logs";
import { memo, useMemo } from "react";
import { Area, AreaChart, Bar, BarChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
import { CHART_COLORS, formatFullTimestamp, formatTimestamp, formatTokens } from "../../utils/chartUtils";
import { formatCompactNumber } from "@/lib/utils/numbers";
import { CHART_COLORS, formatFullTimestamp, formatTimestamp } from "../../utils/chartUtils";
import { ChartErrorBoundary } from "./chartErrorBoundary";
import type { ChartType } from "./chartTypeToggle";

Expand Down Expand Up @@ -88,7 +89,7 @@ function MCPVolumeChartImpl({ data, chartType, startTime, endTime }: MCPVolumeCh
tickLine={false}
axisLine={false}
width={44}
tickFormatter={formatTokens}
tickFormatter={(v) => formatCompactNumber(v)}
domain={[0, (dataMax: number) => Math.max(dataMax, 1)]}
allowDataOverflow={false}
/>
Expand Down Expand Up @@ -130,7 +131,7 @@ function MCPVolumeChartImpl({ data, chartType, startTime, endTime }: MCPVolumeCh
tickLine={false}
axisLine={false}
width={44}
tickFormatter={formatTokens}
tickFormatter={(v) => formatCompactNumber(v)}
domain={[0, (dataMax: number) => Math.max(dataMax, 1)]}
allowDataOverflow={false}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { ModelHistogramResponse } from "@/lib/types/logs";
import { formatCompactNumber } from "@/lib/utils/numbers";
import { memo, useMemo } from "react";
import { Area, AreaChart, Bar, BarChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
import {
CHART_COLORS,
formatFullTimestamp,
formatTimestamp,
formatTokens,
getModelColor,
OTHER_SERIES_COLOR,
OTHER_SERIES_KEY,
Expand Down Expand Up @@ -163,7 +163,7 @@ function ModelUsageChartImpl({ data, chartType, startTime, endTime, selectedMode
tickLine={false}
axisLine={false}
width={44}
tickFormatter={formatTokens}
tickFormatter={(v) => formatCompactNumber(v)}
domain={[0, (dataMax: number) => Math.max(dataMax, 1)]}
allowDataOverflow={false}
/>
Expand Down Expand Up @@ -222,7 +222,7 @@ function ModelUsageChartImpl({ data, chartType, startTime, endTime, selectedMode
tickLine={false}
axisLine={false}
width={44}
tickFormatter={formatTokens}
tickFormatter={(v) => formatCompactNumber(v)}
domain={[0, (dataMax: number) => Math.max(dataMax, 1)]}
allowDataOverflow={false}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ProviderCostHistogramResponse } from "@/lib/types/logs";
import { formatCurrencyNumber } from "@/lib/utils/numbers";
import { memo, useMemo } from "react";
import { Area, AreaChart, Bar, BarChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
import {
Expand Down Expand Up @@ -138,7 +139,7 @@ function ProviderCostChartImpl({ data, chartType, startTime, endTime, selectedPr
tickLine={false}
axisLine={false}
width={50}
tickFormatter={(v) => formatCost(v)}
tickFormatter={(v) => formatCurrencyNumber(v)}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
domain={[0, (dataMax: number) => Math.max(dataMax, 0.01)]}
allowDataOverflow={false}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { ProviderTokenHistogramResponse } from "@/lib/types/logs";
import { formatCompactNumber } from "@/lib/utils/numbers";
import { memo, useMemo } from "react";
import { Area, AreaChart, Bar, BarChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
import {
CHART_COLORS,
formatFullTimestamp,
formatTimestamp,
formatTokens,
getModelColor,
OTHER_SERIES_COLOR,
OTHER_SERIES_KEY,
Expand Down Expand Up @@ -43,7 +43,7 @@ function AllProvidersTooltip({ active, payload, displayProviders }: any) {
<span className="h-2 w-2 rounded-full" style={{ backgroundColor: isOther ? OTHER_SERIES_COLOR : getModelColor(idx) }} />
<span className="max-w-[120px] truncate text-zinc-600 dark:text-zinc-400">{isOther ? OTHER_SERIES_LABEL : provider}</span>
</span>
<span className="font-medium">{formatTokens(tokens)}</span>
<span className="font-medium">{formatCompactNumber(tokens)}</span>
</div>
);
})}
Expand All @@ -70,18 +70,18 @@ function SingleProviderTooltip({ active, payload, provider }: any) {
<span className="h-2 w-2 rounded-full" style={{ backgroundColor: CHART_COLORS.promptTokens }} />
<span className="text-zinc-600 dark:text-zinc-400">Input</span>
</span>
<span className="font-medium">{formatTokens(stats.prompt_tokens || 0)}</span>
<span className="font-medium">{formatCompactNumber(stats.prompt_tokens || 0)}</span>
</div>
<div className="flex items-center justify-between gap-4">
<span className="flex items-center gap-1.5">
<span className="h-2 w-2 rounded-full" style={{ backgroundColor: CHART_COLORS.completionTokens }} />
<span className="text-zinc-600 dark:text-zinc-400">Output</span>
</span>
<span className="font-medium">{formatTokens(stats.completion_tokens || 0)}</span>
<span className="font-medium">{formatCompactNumber(stats.completion_tokens || 0)}</span>
</div>
<div className="flex items-center justify-between gap-4 border-t border-zinc-200 pt-1 dark:border-zinc-700">
<span className="text-zinc-600 dark:text-zinc-400">Total</span>
<span className="font-medium">{formatTokens(stats.total_tokens || 0)}</span>
<span className="font-medium">{formatCompactNumber(stats.total_tokens || 0)}</span>
</div>
</div>
</div>
Expand Down Expand Up @@ -167,7 +167,7 @@ function ProviderTokenChartImpl({ data, chartType, startTime, endTime, selectedP
tickLine={false}
axisLine={false}
width={50}
tickFormatter={formatTokens}
tickFormatter={(v) => formatCompactNumber(v)}
domain={[0, (dataMax: number) => Math.max(dataMax, 1)]}
allowDataOverflow={false}
/>
Expand Down Expand Up @@ -232,7 +232,7 @@ function ProviderTokenChartImpl({ data, chartType, startTime, endTime, selectedP
tickLine={false}
axisLine={false}
width={50}
tickFormatter={formatTokens}
tickFormatter={(v) => formatCompactNumber(v)}
domain={[0, (dataMax: number) => Math.max(dataMax, 1)]}
allowDataOverflow={false}
/>
Expand Down
Loading
Loading