({
stats,
allTimeStats,
dateRange,
isLoading,
}: {
stats: ClaudeCodeStats;
allTimeStats: ClaudeCodeStats;
dateRange: StatsDateRange;
isLoading: boolean;
})
| 265 | } |
| 266 | |
| 267 | function OverviewTab({ |
| 268 | stats, |
| 269 | allTimeStats, |
| 270 | dateRange, |
| 271 | isLoading, |
| 272 | }: { |
| 273 | stats: ClaudeCodeStats; |
| 274 | allTimeStats: ClaudeCodeStats; |
| 275 | dateRange: StatsDateRange; |
| 276 | isLoading: boolean; |
| 277 | }): React.ReactNode { |
| 278 | const { columns: terminalWidth } = useTerminalSize(); |
| 279 | |
| 280 | // Calculate favorite model and total tokens |
| 281 | const modelEntries = Object.entries(stats.modelUsage).sort( |
| 282 | ([, a], [, b]) => b.inputTokens + b.outputTokens - (a.inputTokens + a.outputTokens), |
| 283 | ); |
| 284 | const favoriteModel = modelEntries[0]; |
| 285 | const totalTokens = modelEntries.reduce((sum, [, usage]) => sum + usage.inputTokens + usage.outputTokens, 0); |
| 286 | |
| 287 | // Memoize the factoid so it doesn't change when switching tabs |
| 288 | const factoid = useMemo(() => generateFunFactoid(stats, totalTokens), [stats, totalTokens]); |
| 289 | |
| 290 | // Calculate range days based on selected date range |
| 291 | const rangeDays = dateRange === '7d' ? 7 : dateRange === '30d' ? 30 : stats.totalDays; |
| 292 | |
| 293 | // Compute shot stats data (ant-only, gated by feature flag) |
| 294 | let shotStatsData: { |
| 295 | avgShots: string; |
| 296 | buckets: { label: string; count: number; pct: number }[]; |
| 297 | } | null = null; |
| 298 | if (feature('SHOT_STATS') && stats.shotDistribution) { |
| 299 | const dist = stats.shotDistribution; |
| 300 | const total = Object.values(dist).reduce((s, n) => s + n, 0); |
| 301 | if (total > 0) { |
| 302 | const totalShots = Object.entries(dist).reduce((s, [count, sessions]) => s + parseInt(count, 10) * sessions, 0); |
| 303 | const bucket = (min: number, max?: number) => |
| 304 | Object.entries(dist) |
| 305 | .filter(([k]) => { |
| 306 | const n = parseInt(k, 10); |
| 307 | return n >= min && (max === undefined || n <= max); |
| 308 | }) |
| 309 | .reduce((s, [, v]) => s + v, 0); |
| 310 | const pct = (n: number) => Math.round((n / total) * 100); |
| 311 | const b1 = bucket(1, 1); |
| 312 | const b2_5 = bucket(2, 5); |
| 313 | const b6_10 = bucket(6, 10); |
| 314 | const b11 = bucket(11); |
| 315 | shotStatsData = { |
| 316 | avgShots: (totalShots / total).toFixed(1), |
| 317 | buckets: [ |
| 318 | { label: '1-shot', count: b1, pct: pct(b1) }, |
| 319 | { label: '2\u20135 shot', count: b2_5, pct: pct(b2_5) }, |
| 320 | { label: '6\u201310 shot', count: b6_10, pct: pct(b6_10) }, |
| 321 | { label: '11+ shot', count: b11, pct: pct(b11) }, |
| 322 | ], |
| 323 | }; |
| 324 | } |
nothing calls this directly
no test coverage detected