FN-5929: track hidden usage windows by instance

Store hidden usage windows with per-instance identities while keeping legacy labels restorable.

- persist hidden usage windows with an index-qualified identity instead of label-only keys
- treat legacy label-only entries as matches for restore/show-hidden behavior
- guard hidden-window counts when provider windows are empty or undefined
- add regression coverage for duplicate labels, multiple hidden windows, and legacy persistence

Files changed:
 packages/dashboard/app/components/UsageIndicator.tsx    |  71 +++++++++----
 packages/dashboard/app/components/__tests__/UsageIndicator.test.tsx   | 113 ++++++++++++++++++++-
 2 files changed, 159 insertions(+), 25 deletions(-)

Fusion-Task-Id: FN-5929

Fusion-Task-Lineage: eb48988e-80b8-4d6c-90b9-0d324564f1aa
This commit is contained in:
gsxdsm
2026-06-02 22:46:12 -07:00
parent fab2377fd1
commit 669a6ecfdc
2 changed files with 159 additions and 25 deletions

View File

@@ -162,39 +162,62 @@ function setProviderOrder(names: string[], projectId: string | undefined): void
setScopedItem(PROVIDER_ORDER_KEY, JSON.stringify(names), projectId);
}
const WINDOW_IDENTITY_DELIMITER = "::";
function getWindowIdentity(windowLabel: string, windowIndex: number): string {
return `${windowIndex}${WINDOW_IDENTITY_DELIMITER}${windowLabel}`;
}
function matchesHiddenWindowEntry(
persistedEntry: string,
windowLabel: string,
windowIndex: number
): boolean {
return (
persistedEntry === getWindowIdentity(windowLabel, windowIndex) ||
persistedEntry === windowLabel
);
}
function isWindowHidden(
providerName: string,
windowLabel: string,
windowIndex: number,
hidden: Record<string, string[]>
): boolean {
return hidden[providerName]?.includes(windowLabel) ?? false;
return (hidden[providerName] ?? []).some((persistedEntry) =>
matchesHiddenWindowEntry(persistedEntry, windowLabel, windowIndex)
);
}
function getRenderedHiddenWindowCount(
providerName: string,
windows: UsageWindow[],
windows: UsageWindow[] | undefined,
hidden: Record<string, string[]>
): number {
return windows.reduce((count, window) => {
return count + (isWindowHidden(providerName, window.label, hidden) ? 1 : 0);
return (windows ?? []).reduce((count, window, windowIndex) => {
return count + (isWindowHidden(providerName, window.label, windowIndex, hidden) ? 1 : 0);
}, 0);
}
function getRestorableHiddenWindowCount(
providerName: string,
windows: UsageWindow[],
windows: UsageWindow[] | undefined,
hidden: Record<string, string[]>
): number {
const renderedHiddenCount = getRenderedHiddenWindowCount(providerName, windows, hidden);
const persistedHiddenLabels = hidden[providerName] ?? [];
const liveWindows = windows ?? [];
const renderedHiddenCount = getRenderedHiddenWindowCount(providerName, liveWindows, hidden);
const persistedHiddenEntries = hidden[providerName] ?? [];
if (persistedHiddenLabels.length === 0) {
if (persistedHiddenEntries.length === 0) {
return renderedHiddenCount;
}
const liveWindowLabels = new Set(windows.map((window) => window.label));
const orphanedHiddenCount = persistedHiddenLabels.reduce((count, label) => {
return count + (liveWindowLabels.has(label) ? 0 : 1);
const orphanedHiddenCount = persistedHiddenEntries.reduce((count, persistedEntry) => {
const matchesLiveWindow = liveWindows.some((window, windowIndex) =>
matchesHiddenWindowEntry(persistedEntry, window.label, windowIndex)
);
return count + (matchesLiveWindow ? 0 : 1);
}, 0);
return renderedHiddenCount + orphanedHiddenCount;
@@ -349,7 +372,7 @@ interface ProviderCardProps {
provider: ProviderUsage;
viewMode: 'used' | 'remaining';
hiddenWindows: Record<string, string[]>;
onToggleWindow: (providerName: string, windowLabel: string) => void;
onToggleWindow: (providerName: string, windowLabel: string, windowIndex: number) => void;
onShowAllHidden: (providerName: string) => void;
isDragging: boolean;
isDragOver: boolean;
@@ -434,7 +457,8 @@ function ProviderCard({
onMoveUp,
onMoveDown,
}: ProviderCardProps) {
const hiddenCount = getRestorableHiddenWindowCount(provider.name, provider.windows, hiddenWindows);
const providerWindows = provider.windows ?? [];
const hiddenCount = getRestorableHiddenWindowCount(provider.name, providerWindows, hiddenWindows);
const getStatusBadge = () => {
switch (provider.status) {
case "ok":
@@ -526,10 +550,10 @@ function ProviderCard({
</div>
)}
{provider.windows.length > 0 ? (
{providerWindows.length > 0 ? (
<div className="usage-provider-windows">
{provider.windows.map((window, index) => {
const hidden = isWindowHidden(provider.name, window.label, hiddenWindows);
{providerWindows.map((window, index) => {
const hidden = isWindowHidden(provider.name, window.label, index, hiddenWindows);
return (
<UsageWindowRow
@@ -537,7 +561,7 @@ function ProviderCard({
window={window}
viewMode={viewMode}
isHidden={hidden}
onToggleHidden={() => onToggleWindow(provider.name, window.label)}
onToggleHidden={() => onToggleWindow(provider.name, window.label, index)}
/>
);
})}
@@ -694,10 +718,15 @@ export function UsageIndicator({ isOpen, onClose, projectId, anchorRect }: Usage
setHiddenWindows(hiddenWindows, projectId);
}, [hiddenWindows, projectId]);
const handleToggleWindow = useCallback((providerName: string, windowLabel: string) => {
const handleToggleWindow = useCallback((providerName: string, windowLabel: string, windowIndex: number) => {
setHiddenWindowsState((previous) => {
if (isWindowHidden(providerName, windowLabel, previous)) {
const remaining = (previous[providerName] ?? []).filter((label) => label !== windowLabel);
const windowIdentity = getWindowIdentity(windowLabel, windowIndex);
const providerHiddenWindows = previous[providerName] ?? [];
if (isWindowHidden(providerName, windowLabel, windowIndex, previous)) {
const remaining = providerHiddenWindows.filter(
(persistedEntry) => !matchesHiddenWindowEntry(persistedEntry, windowLabel, windowIndex)
);
if (remaining.length === 0) {
const { [providerName]: _removed, ...rest } = previous;
return rest;
@@ -711,7 +740,7 @@ export function UsageIndicator({ isOpen, onClose, projectId, anchorRect }: Usage
return {
...previous,
[providerName]: [...(previous[providerName] ?? []), windowLabel],
[providerName]: [...providerHiddenWindows, windowIdentity],
};
});
}, []);

View File

@@ -45,6 +45,10 @@ const USAGE_VIEW_MODE_KEY = scopedKey("kb-usage-view-mode", TEST_PROJECT_ID);
const USAGE_HIDDEN_WINDOWS_KEY = scopedKey("kb-usage-hidden-windows", TEST_PROJECT_ID);
const USAGE_PROVIDER_ORDER_KEY = scopedKey("kb-usage-provider-order", TEST_PROJECT_ID);
function getWindowIdentity(label: string, index: number): string {
return `${index}::${label}`;
}
describe("UsageIndicator", () => {
const mockOnClose = vi.fn();
const mockRefresh = vi.fn();
@@ -913,11 +917,11 @@ describe("UsageIndicator", () => {
fireEvent.click(screen.getByRole("button", { name: "Hide Session (5h)" }));
expect(localStorage.getItem(USAGE_HIDDEN_WINDOWS_KEY)).toBe(
JSON.stringify({ Anthropic: ["Session (5h)"] })
JSON.stringify({ Anthropic: [getWindowIdentity("Session (5h)", 0)] })
);
});
it("restores hidden windows from localStorage on mount", () => {
it("restores hidden windows from legacy label-only localStorage on mount", () => {
localStorage.setItem(
USAGE_HIDDEN_WINDOWS_KEY,
JSON.stringify({ Anthropic: ["Session (5h)"] })
@@ -1028,7 +1032,56 @@ describe("UsageIndicator", () => {
expect(screen.getByTestId("usage-show-hidden-btn")).toHaveTextContent("Show hidden (2)");
});
it("counts currently rendered hidden rows when persisted labels match duplicate live windows", () => {
it("hiding one duplicate-labeled MiniMax window only hides that instance", () => {
mockUseUsageData.mockReturnValue(createUsageDataState({
providers: [
{
name: "MiniMax",
icon: "🧠",
status: "ok",
windows: [
{
label: "Daily",
percentUsed: 20,
percentLeft: 80,
resetText: "resets in 1h",
resetMs: 3600000,
},
{
label: "Daily",
percentUsed: 60,
percentLeft: 40,
resetText: "resets in 4h",
resetMs: 14400000,
},
],
},
],
loading: false,
error: null,
lastUpdated: new Date(),
refresh: mockRefresh,
}));
render(<UsageIndicator isOpen={true} onClose={mockOnClose} projectId={TEST_PROJECT_ID} />);
fireEvent.click(screen.getAllByRole("button", { name: "Hide Daily" })[1]);
const hiddenRows = Array.from(document.querySelectorAll(".usage-window--hidden"));
expect(hiddenRows).toHaveLength(1);
expect(hiddenRows[0]).toHaveTextContent("Daily");
expect(localStorage.getItem(USAGE_HIDDEN_WINDOWS_KEY)).toBe(
JSON.stringify({ MiniMax: [getWindowIdentity("Daily", 1)] })
);
expect(screen.getByTestId("usage-show-hidden-btn")).toHaveTextContent("Show hidden (1)");
fireEvent.click(screen.getByTestId("usage-show-hidden-btn"));
expect(document.querySelectorAll(".usage-window--hidden")).toHaveLength(0);
expect(screen.queryByTestId("usage-show-hidden-btn")).not.toBeInTheDocument();
});
it("counts currently rendered hidden rows when legacy persisted labels match duplicate live windows", () => {
localStorage.setItem(
USAGE_HIDDEN_WINDOWS_KEY,
JSON.stringify({ Anthropic: ["Daily"] })
@@ -1132,7 +1185,7 @@ describe("UsageIndicator", () => {
fireEvent.click(screen.getByRole("button", { name: "Hide Session (5h)" }));
expect(localStorage.getItem(USAGE_HIDDEN_WINDOWS_KEY)).toBe(
JSON.stringify({ Anthropic: ["Session (5h)"] })
JSON.stringify({ Anthropic: [getWindowIdentity("Session (5h)", 0)] })
);
fireEvent.click(screen.getByTestId("usage-show-hidden-btn"));
@@ -1151,6 +1204,32 @@ describe("UsageIndicator", () => {
expect(screen.getByText("Session (5h)").closest(".usage-window")).not.toHaveClass("usage-window--hidden");
});
it("tracks multiple distinct hidden Anthropic windows per instance", () => {
mockUseUsageData.mockReturnValue(createUsageDataState({
providers: mockProviders,
loading: false,
error: null,
lastUpdated: new Date(),
refresh: mockRefresh,
}));
render(<UsageIndicator isOpen={true} onClose={mockOnClose} projectId={TEST_PROJECT_ID} />);
fireEvent.click(screen.getByRole("button", { name: "Hide Session (5h)" }));
fireEvent.click(screen.getByRole("button", { name: "Hide Weekly" }));
expect(document.querySelectorAll(".usage-window--hidden")).toHaveLength(2);
expect(screen.getByTestId("usage-show-hidden-btn")).toHaveTextContent("Show hidden (2)");
expect(localStorage.getItem(USAGE_HIDDEN_WINDOWS_KEY)).toBe(
JSON.stringify({
Anthropic: [
getWindowIdentity("Session (5h)", 0),
getWindowIdentity("Weekly", 1),
],
})
);
});
it("does not show provider-level show hidden button when no windows are hidden", () => {
mockUseUsageData.mockReturnValue(createUsageDataState({
providers: mockProviders,
@@ -1165,6 +1244,32 @@ describe("UsageIndicator", () => {
expect(screen.queryByTestId("usage-show-hidden-btn")).not.toBeInTheDocument();
});
it("does not crash or show hidden controls when provider windows are empty or undefined", () => {
mockUseUsageData.mockReturnValue(createUsageDataState({
providers: [
{ name: "Anthropic", icon: "🅰️", status: "ok", windows: [] },
{ name: "MiniMax", icon: "🧠", status: "ok", windows: undefined as unknown as ProviderUsage["windows"] },
],
loading: false,
error: null,
lastUpdated: new Date(),
refresh: mockRefresh,
}));
render(
<UsageIndicator
isOpen={true}
onClose={mockOnClose}
projectId={TEST_PROJECT_ID}
anchorRect={createAnchorRect()}
/>
);
expect(screen.getByText("Anthropic")).toBeInTheDocument();
expect(screen.getByText("MiniMax")).toBeInTheDocument();
expect(screen.queryByTestId("usage-show-hidden-btn")).not.toBeInTheDocument();
});
// ProviderIcon integration tests
it("renders SVG provider icons instead of emoji", () => {