Skip to content

Commit 43b2fb0

Browse files
committed
🤖 refactor: remove VerticalTokenMeter component
Now that we have the context usage indicator in the chat area, the VerticalTokenMeter in the right sidebar is no longer needed. Removed: - VerticalTokenMeter.tsx component - ChatMetaSidebar.tsx (only existed to show the meter when collapsed) - Related imports and usage in RightSidebar.tsx -229 lines
1 parent b98b323 commit 43b2fb0

File tree

5 files changed

+27
-294
lines changed

5 files changed

+27
-294
lines changed

src/browser/components/AIView.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,6 @@ const AIViewInner: React.FC<AIViewProps> = ({
797797
key={workspaceId}
798798
workspaceId={workspaceId}
799799
workspacePath={namedWorkspacePath}
800-
chatAreaRef={chatAreaRef}
801800
width={sidebarWidth}
802801
onStartResize={startResize}
803802
isResizing={isResizing}

src/browser/components/ChatMetaSidebar.tsx

Lines changed: 0 additions & 84 deletions
This file was deleted.

src/browser/components/RightSidebar.tsx

Lines changed: 24 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,11 @@ import React from "react";
22
import { RIGHT_SIDEBAR_TAB_KEY, RIGHT_SIDEBAR_COLLAPSED_KEY } from "@/common/constants/storage";
33
import { usePersistedState } from "@/browser/hooks/usePersistedState";
44
import { useWorkspaceUsage, useWorkspaceStatsSnapshot } from "@/browser/stores/WorkspaceStore";
5-
import { useProviderOptions } from "@/browser/hooks/useProviderOptions";
6-
import { useResizeObserver } from "@/browser/hooks/useResizeObserver";
75
import { useFeatureFlags } from "@/browser/contexts/FeatureFlagsContext";
8-
import { useAutoCompactionSettings } from "@/browser/hooks/useAutoCompactionSettings";
96
import { ErrorBoundary } from "./ErrorBoundary";
107
import { CostsTab } from "./RightSidebar/CostsTab";
118
import { StatsTab } from "./RightSidebar/StatsTab";
12-
import { VerticalTokenMeter } from "./RightSidebar/VerticalTokenMeter";
139
import { ReviewPanel } from "./RightSidebar/CodeReview/ReviewPanel";
14-
import { calculateTokenMeterData } from "@/common/utils/tokens/tokenMeterUtils";
1510
import { sumUsageHistory, type ChatUsageDisplay } from "@/common/utils/tokens/usageAggregator";
1611
import { matchesKeybind, KEYBINDS, formatKeybind } from "@/browser/utils/ui/keybinds";
1712
import { Tooltip, TooltipTrigger, TooltipContent } from "./ui/tooltip";
@@ -34,7 +29,7 @@ function formatTabDuration(ms: number): string {
3429
}
3530

3631
interface SidebarContainerProps {
37-
collapsed: boolean;
32+
collapsed?: boolean;
3833
wide?: boolean;
3934
/** Custom width from drag-resize (persisted per-tab by AIView) */
4035
customWidth?: number;
@@ -49,7 +44,7 @@ interface SidebarContainerProps {
4944
* SidebarContainer - Main sidebar wrapper with dynamic width
5045
*
5146
* Width priority (first match wins):
52-
* 1. collapsed (20px) - Shows vertical token meter only
47+
* 1. collapsed (20px) - Manual collapse via toggle
5348
* 2. customWidth - From drag-resize (persisted per-tab)
5449
* 3. wide - Auto-calculated max width for Review tab (when not drag-resizing)
5550
* 4. default (300px) - Costs tab when no customWidth saved
@@ -64,7 +59,7 @@ const SidebarContainer: React.FC<SidebarContainerProps> = ({
6459
"aria-label": ariaLabel,
6560
}) => {
6661
const width = collapsed
67-
? "20px"
62+
? "32px" // Match left sidebar collapsed width (w-8 = 32px)
6863
: customWidth
6964
? `${customWidth}px`
7065
: wide
@@ -76,8 +71,6 @@ const SidebarContainer: React.FC<SidebarContainerProps> = ({
7671
className={cn(
7772
"bg-sidebar border-l border-border-light flex flex-col overflow-hidden flex-shrink-0",
7873
!isResizing && "transition-[width] duration-200",
79-
collapsed && "sticky right-0 z-10 shadow-[-2px_0_4px_rgba(0,0,0,0.2)]",
80-
// Mobile: Show vertical meter when collapsed (20px), full width when expanded
8174
"max-md:border-l-0 max-md:border-t max-md:border-border-light",
8275
!collapsed && "max-md:w-full max-md:relative max-md:max-h-[50vh]"
8376
)}
@@ -97,7 +90,6 @@ export type { TabType };
9790
interface RightSidebarProps {
9891
workspaceId: string;
9992
workspacePath: string;
100-
chatAreaRef: React.RefObject<HTMLDivElement>;
10193
/** Custom width in pixels (persisted per-tab, provided by AIView) */
10294
width?: number;
10395
/** Drag start handler for resize */
@@ -113,7 +105,6 @@ interface RightSidebarProps {
113105
const RightSidebarComponent: React.FC<RightSidebarProps> = ({
114106
workspaceId,
115107
workspacePath,
116-
chatAreaRef,
117108
width,
118109
onStartResize,
119110
isResizing = false,
@@ -123,6 +114,9 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
123114
// Global tab preference (not per-workspace)
124115
const [selectedTab, setSelectedTab] = usePersistedState<TabType>(RIGHT_SIDEBAR_TAB_KEY, "costs");
125116

117+
// Manual collapse state (persisted globally)
118+
const [collapsed, setCollapsed] = usePersistedState<boolean>(RIGHT_SIDEBAR_COLLAPSED_KEY, false);
119+
126120
const { statsTabState } = useFeatureFlags();
127121
const statsTabEnabled = Boolean(statsTabState?.enabled);
128122

@@ -160,10 +154,6 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
160154

161155
const usage = useWorkspaceUsage(workspaceId);
162156

163-
const { options } = useProviderOptions();
164-
const use1M = options.anthropic?.use1MContext ?? false;
165-
const chatAreaSize = useResizeObserver(chatAreaRef);
166-
167157
const baseId = `right-sidebar-${workspaceId}`;
168158
const costsTabId = `${baseId}-tab-costs`;
169159
const statsTabId = `${baseId}-tab-stats`;
@@ -172,10 +162,6 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
172162
const statsPanelId = `${baseId}-panel-stats`;
173163
const reviewPanelId = `${baseId}-panel-review`;
174164

175-
// Use lastContextUsage for context window display (last step = actual context size)
176-
const lastUsage = usage?.liveUsage ?? usage?.lastContextUsage;
177-
const model = lastUsage?.model ?? null;
178-
179165
// Calculate session cost for tab display
180166
const sessionCost = React.useMemo(() => {
181167
const parts: ChatUsageDisplay[] = [];
@@ -206,90 +192,17 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
206192
return total > 0 ? total : null;
207193
})();
208194

209-
// Auto-compaction settings: threshold per-model
210-
const { threshold: autoCompactThreshold, setThreshold: setAutoCompactThreshold } =
211-
useAutoCompactionSettings(workspaceId, model);
212-
213-
// Memoize vertical meter data calculation to prevent unnecessary re-renders
214-
const verticalMeterData = React.useMemo(() => {
215-
return lastUsage
216-
? calculateTokenMeterData(lastUsage, model ?? "unknown", use1M, true)
217-
: { segments: [], totalTokens: 0, totalPercentage: 0 };
218-
}, [lastUsage, model, use1M]);
219-
220-
// Calculate if we should show collapsed view with hysteresis
221-
// Strategy: Observe ChatArea width directly (independent of sidebar width)
222-
// - ChatArea has min-width: 750px and flex: 1
223-
// - Use hysteresis to prevent oscillation:
224-
// * Collapse when chatAreaWidth <= 800px (tight space)
225-
// * Expand when chatAreaWidth >= 1100px (lots of space)
226-
// * Between 800-1100: maintain current state (dead zone)
227-
const COLLAPSE_THRESHOLD = 800; // Collapse below this
228-
const EXPAND_THRESHOLD = 1100; // Expand above this
229-
const chatAreaWidth = chatAreaSize?.width ?? 1000; // Default to large to avoid flash
230-
231-
// Persist collapsed state globally (not per-workspace) since chat area width is shared
232-
// This prevents animation flash when switching workspaces - sidebar maintains its state
233-
const [showCollapsed, setShowCollapsed] = usePersistedState<boolean>(
234-
RIGHT_SIDEBAR_COLLAPSED_KEY,
235-
false
236-
);
237-
238-
React.useEffect(() => {
239-
// Never collapse when Review tab is active - code review needs space
240-
if (selectedTab === "review") {
241-
if (showCollapsed) {
242-
setShowCollapsed(false);
243-
}
244-
return;
245-
}
246-
247-
// If the sidebar is custom-resized (wider than the default Costs width),
248-
// auto-collapse based on chatAreaWidth can oscillate between expanded and
249-
// collapsed states (because collapsed is 20px but expanded can be much wider),
250-
// which looks like a constant flash. In that case, keep it expanded and let
251-
// the user resize manually.
252-
if (width !== undefined && width > 300) {
253-
if (showCollapsed) {
254-
setShowCollapsed(false);
255-
}
256-
return;
257-
}
258-
259-
// Normal hysteresis for Costs/Tools tabs
260-
if (chatAreaWidth <= COLLAPSE_THRESHOLD) {
261-
setShowCollapsed(true);
262-
} else if (chatAreaWidth >= EXPAND_THRESHOLD) {
263-
setShowCollapsed(false);
264-
}
265-
// Between thresholds: maintain current state (no change)
266-
}, [chatAreaWidth, selectedTab, showCollapsed, setShowCollapsed, width]);
267-
268-
// Single render point for VerticalTokenMeter
269-
// Shows when: (1) collapsed, OR (2) Review tab is active
270-
const showMeter = showCollapsed || selectedTab === "review";
271-
const autoCompactionProps = React.useMemo(
272-
() => ({
273-
threshold: autoCompactThreshold,
274-
setThreshold: setAutoCompactThreshold,
275-
}),
276-
[autoCompactThreshold, setAutoCompactThreshold]
277-
);
278-
const verticalMeter = showMeter ? (
279-
<VerticalTokenMeter data={verticalMeterData} autoCompaction={autoCompactionProps} />
280-
) : null;
281-
282195
return (
283196
<SidebarContainer
284-
collapsed={showCollapsed}
197+
collapsed={collapsed}
285198
wide={selectedTab === "review" && !width} // Auto-wide only if not drag-resizing
286199
customWidth={width} // Per-tab resized width from AIView
287200
isResizing={isResizing}
288201
role="complementary"
289202
aria-label="Workspace insights"
290203
>
291204
{/* Full view when not collapsed */}
292-
<div className={cn("flex-row h-full", !showCollapsed ? "flex" : "hidden")}>
205+
<div className={cn("flex h-full flex-row", collapsed && "hidden")}>
293206
{/* Resize handle (left edge) */}
294207
{onStartResize && (
295208
<div
@@ -301,11 +214,6 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
301214
/>
302215
)}
303216

304-
{/* Render meter when Review tab is active */}
305-
{selectedTab === "review" && (
306-
<div className="bg-sidebar flex w-5 shrink-0 flex-col">{verticalMeter}</div>
307-
)}
308-
309217
<div className="flex min-w-0 flex-1 flex-col">
310218
<div
311219
className="border-border-light flex gap-1 border-b px-2 py-1.5"
@@ -442,8 +350,22 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
442350
</div>
443351
</div>
444352
</div>
445-
{/* Render meter in collapsed view when sidebar is collapsed */}
446-
<div className={cn("h-full", showCollapsed ? "flex" : "hidden")}>{verticalMeter}</div>
353+
354+
{/* Collapse/expand toggle at bottom - matches left sidebar pattern */}
355+
<Tooltip>
356+
<TooltipTrigger asChild>
357+
<button
358+
onClick={() => setCollapsed(!collapsed)}
359+
aria-label={collapsed ? "Expand sidebar" : "Collapse sidebar"}
360+
className="text-muted border-dark hover:bg-hover hover:text-foreground mt-auto flex h-9 w-full cursor-pointer items-center justify-center border-t border-none bg-transparent p-0 text-sm transition-all duration-200"
361+
>
362+
{collapsed ? "«" : "»"}
363+
</button>
364+
</TooltipTrigger>
365+
<TooltipContent align="center">
366+
{collapsed ? "Expand sidebar" : "Collapse sidebar"}
367+
</TooltipContent>
368+
</Tooltip>
447369
</SidebarContainer>
448370
);
449371
};

0 commit comments

Comments
 (0)