Skip to content

Commit 11f2792

Browse files
committed
fix(skills): chart skill TPR trend by time
Replace skill detail token trend with TPR (tokens per run) time series and update tooltip/axis formatting so hourly and daily ranges show normalized token intensity.
1 parent f279cc0 commit 11f2792

File tree

1 file changed

+50
-22
lines changed

1 file changed

+50
-22
lines changed

frontend/src/components/SkillsPanel.jsx

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ const formatCost = (cost) => {
1717

1818
const formatPercent = (value) => `${Number(value || 0).toFixed(1)}%`
1919

20+
const formatTpr = (value) => {
21+
if (value === undefined || value === null || Number.isNaN(value)) return '0.0'
22+
return Number(value).toLocaleString('en-US', { minimumFractionDigits: 1, maximumFractionDigits: 1 })
23+
}
24+
25+
const formatTprAxis = (value) => {
26+
if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`
27+
if (value >= 1_000) return `${(value / 1_000).toFixed(1)}K`
28+
return Math.round(value).toLocaleString('en-US')
29+
}
30+
2031
const getStatus = (status) => status === 'failure' ? 'failure' : 'success'
2132
const getSkillLabel = (value) => value || 'Unknown'
2233
const getProjectLabel = (value) => value || 'Unknown Project'
@@ -468,8 +479,18 @@ function SkillsPanel({ skillRuns = [], skillDailyStats = [], dateRange, customRa
468479
}
469480
}, [activeSkillName, rangeBoundaries])
470481
const detailTrendSeries = trendTime === 'hour' ? detailHourlySeries : detailDailySeries
471-
const detailHasTokenSignal = detailTrendSeries.some(p => (p.input_tokens || 0) > 0 || (p.output_tokens || 0) > 0)
472-
const detailUseRunFallbackSeries = detailTrendSeries.length > 0 && !detailHasTokenSignal
482+
const detailTprSeries = useMemo(() => {
483+
return detailTrendSeries.map(point => {
484+
const totalTokens = (point.input_tokens || 0) + (point.output_tokens || 0)
485+
const runCount = point.run_count || 0
486+
const tpr = runCount > 0 ? totalTokens / runCount : 0
487+
return {
488+
...point,
489+
total_tokens: totalTokens,
490+
tpr,
491+
}
492+
})
493+
}, [detailTrendSeries])
473494

474495
const detailProjectRows = useMemo(() => aggregateDimensionRows(detailRuns, 'project'), [detailRuns])
475496
const detailDeviceRows = useMemo(() => aggregateDimensionRows(detailRuns, 'machine'), [detailRuns])
@@ -814,47 +835,54 @@ function SkillsPanel({ skillRuns = [], skillDailyStats = [], dateRange, customRa
814835

815836
<div className="chart-card chart-full">
816837
<div className="chart-header">
817-
<h3>Token Trend</h3>
838+
<h3>TPR Trend (Tokens per Run)</h3>
818839
</div>
819840
<div className="chart-body chart-body-dark">
820-
{detailTrendSeries.length > 0 ? (
841+
{detailTprSeries.length > 0 ? (
821842
<ResponsiveContainer width="100%" height={260}>
822-
<AreaChart data={detailTrendSeries} margin={{ top: 10, right: 10, left: 0, bottom: 0 }}>
843+
<AreaChart data={detailTprSeries} margin={{ top: 10, right: 10, left: 0, bottom: 0 }}>
823844
<defs>
824-
<linearGradient id="gradSkillDetailTokens" x1="0" y1="0" x2="0" y2="1">
825-
<stop offset="0%" stopColor="#3b82f6" stopOpacity={0.4} />
826-
<stop offset="100%" stopColor="#3b82f6" stopOpacity={0} />
845+
<linearGradient id="gradSkillDetailTpr" x1="0" y1="0" x2="0" y2="1">
846+
<stop offset="0%" stopColor="#22c55e" stopOpacity={0.4} />
847+
<stop offset="100%" stopColor="#22c55e" stopOpacity={0} />
827848
</linearGradient>
828849
</defs>
829850
<CartesianGrid strokeDasharray="4 4" stroke={isDarkMode ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.06)'} />
830851
<XAxis dataKey="label" stroke={isDarkMode ? '#6e7681' : '#57606a'} tick={CHART_TYPOGRAPHY.axisTick} axisLine={false} tickLine={false} />
831-
<YAxis stroke={isDarkMode ? '#6e7681' : '#57606a'} tick={CHART_TYPOGRAPHY.axisTick} axisLine={false} tickLine={false} tickFormatter={(v) => v >= 1_000_000 ? `${(v / 1_000_000).toFixed(1)}M` : v.toLocaleString()} />
852+
<YAxis
853+
stroke={isDarkMode ? '#6e7681' : '#57606a'}
854+
tick={CHART_TYPOGRAPHY.axisTick}
855+
axisLine={false}
856+
tickLine={false}
857+
tickFormatter={formatTprAxis}
858+
/>
832859
<Tooltip content={({ active, payload, label }) => {
833860
if (!active || !payload?.length) return null
834861
const item = payload[0].payload
835862
return (
836863
<div style={{ padding: '8px 10px', background: isDarkMode ? 'rgba(15,23,42,0.95)' : 'white', border: `1px solid ${isDarkMode ? 'rgba(255,255,255,0.08)' : '#e2e8f0'}`, borderRadius: 8 }}>
837864
<div style={{ ...CHART_TYPOGRAPHY.tooltipLabel, marginBottom: 4 }}>{label}</div>
838-
<div style={CHART_TYPOGRAPHY.tooltipItem}>Attempts: {(item.run_count || 0).toLocaleString()}</div>
839-
<div style={CHART_TYPOGRAPHY.tooltipItem}>Input: {formatNumber(item.input_tokens)}</div>
840-
<div style={CHART_TYPOGRAPHY.tooltipItem}>Output: {formatNumber(item.output_tokens)}</div>
841-
{detailUseRunFallbackSeries && <div style={CHART_TYPOGRAPHY.tooltipItem}>Runs: {formatNumber(item.run_count)}</div>}
865+
<div style={{ ...CHART_TYPOGRAPHY.tooltipItem, color: '#22c55e' }}>TPR: {formatTpr(item.tpr)} tokens/run</div>
866+
<div style={CHART_TYPOGRAPHY.tooltipItem}>Runs: {formatNumber(item.run_count || 0)}</div>
867+
<div style={CHART_TYPOGRAPHY.tooltipItem}>Total tokens: {formatNumber(item.total_tokens || 0)}</div>
868+
<div style={CHART_TYPOGRAPHY.tooltipItem}>Input: {formatNumber(item.input_tokens || 0)}</div>
869+
<div style={CHART_TYPOGRAPHY.tooltipItem}>Output: {formatNumber(item.output_tokens || 0)}</div>
842870
<div style={{ ...CHART_TYPOGRAPHY.tooltipItem, color: '#10b981' }}>Cost: {formatCost(item.estimated_cost)}</div>
843871
</div>
844872
)
845873
}} />
846-
{detailUseRunFallbackSeries ? (
847-
<Area type="monotone" dataKey="run_count" name="Runs" stroke="#f59e0b" fillOpacity={0.25} fill="#f59e0b" strokeWidth={2} />
848-
) : (
849-
<>
850-
<Area type="monotone" dataKey="input_tokens" name="Input" stroke="#3b82f6" fill="url(#gradSkillDetailTokens)" strokeWidth={2} />
851-
<Area type="monotone" dataKey="output_tokens" name="Output" stroke="#8b5cf6" fillOpacity={0.2} fill="#8b5cf6" strokeWidth={2} />
852-
</>
853-
)}
874+
<Area
875+
type="monotone"
876+
dataKey="tpr"
877+
name="TPR"
878+
stroke="#22c55e"
879+
fill="url(#gradSkillDetailTpr)"
880+
strokeWidth={2}
881+
/>
854882
</AreaChart>
855883
</ResponsiveContainer>
856884
) : (
857-
<div className="empty-state">No trend data for this skill</div>
885+
<div className="empty-state">No TPR trend data for this skill</div>
858886
)}
859887
</div>
860888
</div>

0 commit comments

Comments
 (0)