From a303fc7174407b3589eeb7f539bfead4c7f0d6b2 Mon Sep 17 00:00:00 2001 From: iamtoruk Date: Sun, 19 Apr 2026 05:41:10 -0700 Subject: [PATCH] feat(compare): integrate into dashboard with c shortcut --- src/compare.tsx | 2 +- src/dashboard.tsx | 27 +++++++++++++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/compare.tsx b/src/compare.tsx index 68c1afea..f9200538 100644 --- a/src/compare.tsx +++ b/src/compare.tsx @@ -201,7 +201,7 @@ type CompareViewProps = { onBack: () => void } -function CompareView({ projects, onBack }: CompareViewProps) { +export function CompareView({ projects, onBack }: CompareViewProps) { const { exit } = useApp() const [phase, setPhase] = useState<'select' | 'loading' | 'results'>('select') const [models] = useState(() => aggregateModelStats(projects)) diff --git a/src/dashboard.tsx b/src/dashboard.tsx index 99163aac..75b92821 100644 --- a/src/dashboard.tsx +++ b/src/dashboard.tsx @@ -10,10 +10,11 @@ import { getAllProviders } from './providers/index.js' import { scanAndDetect, type WasteFinding, type WasteAction, type OptimizeResult } from './optimize.js' import { estimateContextBudget, discoverProjectCwd, type ContextBudget } from './context-budget.js' import { dateKey } from './day-aggregator.js' +import { CompareView } from './compare.js' import { join } from 'path' type Period = 'today' | 'week' | '30days' | 'month' | 'all' -type View = 'dashboard' | 'optimize' +type View = 'dashboard' | 'optimize' | 'compare' const PERIODS: Period[] = ['today', 'week', '30days', 'month', 'all'] const PERIOD_LABELS: Record = { @@ -526,7 +527,7 @@ function OptimizeView({ findings, costRate, projects, label, width, healthScore, ) } -function StatusBar({ width, showProvider, view, findingCount, optimizeAvailable }: { width: number; showProvider?: boolean; view?: View; findingCount?: number; optimizeAvailable?: boolean }) { +function StatusBar({ width, showProvider, view, findingCount, optimizeAvailable, compareAvailable }: { width: number; showProvider?: boolean; view?: View; findingCount?: number; optimizeAvailable?: boolean; compareAvailable?: boolean }) { const isOptimize = view === 'optimize' return ( @@ -543,6 +544,9 @@ function StatusBar({ width, showProvider, view, findingCount, optimizeAvailable {!isOptimize && optimizeAvailable && findingCount != null && findingCount > 0 && ( <> o optimize ({findingCount}) )} + {!isOptimize && view !== 'compare' && compareAvailable && ( + <> c compare + )} {showProvider && (<> p provider)} @@ -596,6 +600,10 @@ function InteractiveDashboard({ initialProjects, initialPeriod, initialProvider, const { dashWidth } = getLayout(columns) const multipleProviders = detectedProviders.length > 1 const optimizeAvailable = activeProvider === 'all' || activeProvider === 'claude' + const modelCount = new Set( + projects.flatMap(p => p.sessions.flatMap(s => Object.keys(s.modelBreakdown))) + ).size + const compareAvailable = modelCount >= 2 const debounceRef = useRef | null>(null) const findingCount = optimizeResult?.findings.length ?? 0 @@ -671,7 +679,8 @@ function InteractiveDashboard({ initialProjects, initialPeriod, initialProvider, useInput((input, key) => { if (input === 'q') { exit(); return } if (input === 'o' && findingCount > 0 && view === 'dashboard' && optimizeAvailable) { setView('optimize'); return } - if ((input === 'b' || key.escape) && view === 'optimize') { setView('dashboard'); return } + if ((input === 'b' || key.escape) && (view === 'optimize' || view === 'compare')) { setView('dashboard'); return } + if (input === 'c' && compareAvailable && view === 'dashboard') { setView('compare'); return } if (input === 'p' && multipleProviders) { const opts = ['all', ...detectedProviders]; const next = opts[(opts.indexOf(activeProvider) + 1) % opts.length] setActiveProvider(next); setView('dashboard') @@ -693,7 +702,7 @@ function InteractiveDashboard({ initialProjects, initialPeriod, initialProvider, Loading {PERIOD_LABELS[period]}... - + ) } @@ -701,10 +710,12 @@ function InteractiveDashboard({ initialProjects, initialPeriod, initialProvider, return ( - {view === 'optimize' && optimizeResult - ? - : } - + {view === 'compare' + ? setView('dashboard')} /> + : view === 'optimize' && optimizeResult + ? + : } + ) }