Streamline sidebar usage and stacked sheet interactions (#5805)

* feat(app): streamline sidebar usage and stacked sheets

* fix(app): restore compact sidebar navigation clicks

The close button container emitted box-none through Unistyles as invalid CSS and intercepted New workspace clicks. Let React Native apply click-through behavior at the view boundary. Keep the import journey on its existing New workspace screen and assert only the visible transcript.

* fix(app): cap menu sheets at eighty percent height

Keep long sidebar usage reports recognizably sheet-sized while allowing the content to scroll. Short menu sheets retain dynamic sizing.
This commit is contained in:
Mohamed Boudra
2026-10-01 04:55:17 +01:00
committed by GitHub
parent 15f1431416
commit e939dd4c7a
65 changed files with 1292 additions and 527 deletions
@@ -307,6 +307,38 @@ describe("Claude usage source scoped weekly limits", () => {
);
});
it("summarizes the session and weekly windows by default, not scoped ones", async () => {
const { provider } = claudeProvider({
five_hour: { utilization: 6, resets_at: "2026-06-01T21:00:00Z" },
seven_day: { utilization: 23, resets_at: "2026-06-04T00:00:00Z" },
limits: [fableLimit()],
});
const usage = await provider.fetchUsage();
expect(usage.windows.map((window) => [window.id, window.summary ?? false])).toEqual([
["five_hour", true],
["weekly", true],
["weekly_model_fable", false],
]);
});
it("gives every window a short label for tight spaces", async () => {
const { provider } = claudeProvider({
five_hour: { utilization: 6, resets_at: "2026-06-01T21:00:00Z" },
seven_day: { utilization: 23, resets_at: "2026-06-04T00:00:00Z" },
limits: [fableLimit()],
});
const usage = await provider.fetchUsage();
expect(usage.windows.map((window) => [window.id, window.shortLabel])).toEqual([
["five_hour", "5h"],
["weekly", "wk"],
["weekly_model_fable", "wk Fable"],
]);
});
it("renders a scoped window that is at zero and inactive", async () => {
const { provider } = claudeProvider({
seven_day: { utilization: 23, resets_at: "2026-06-04T00:00:00Z" },
+7 -2
View File
@@ -112,9 +112,11 @@ const UNSCOPED_WINDOWS: ReadonlyArray<{
field: "five_hour" | "seven_day";
id: string;
label: string;
shortLabel: string;
summary: boolean;
}> = [
{ field: "five_hour", id: "five_hour", label: "Session" },
{ field: "seven_day", id: "weekly", label: "Weekly" },
{ field: "five_hour", id: "five_hour", label: "Session", shortLabel: "5h", summary: true },
{ field: "seven_day", id: "weekly", label: "Weekly", shortLabel: "wk", summary: true },
];
// Scoped windows from before `limits[]` existed. Declaring the dimension here is what
@@ -253,6 +255,8 @@ function unscopedWindows(resp: ClaudeUsageResponse): UsageWindow[] {
windowFromUsedPct({
id: spec.id,
label: spec.label,
shortLabel: spec.shortLabel,
summary: spec.summary,
utilizationPct: window.utilization,
resetsAt: window.resets_at ?? null,
tone: toneFromUsedPct(window.utilization),
@@ -272,6 +276,7 @@ function scopedWindows(limits: ScopedLimit[]): UsageWindow[] {
return windowFromUsedPct({
id,
label: `Weekly \u00b7 ${limit.name}`,
shortLabel: `wk ${limit.name}`,
utilizationPct: limit.usedPct,
resetsAt: limit.resetsAt,
tone: toneFromUsedPct(limit.usedPct),
@@ -103,7 +103,31 @@ test("coerces credit balance and marks a 96 percent window dangerous", async ()
expect.objectContaining({ id: "weekly", tone: "danger" }),
]),
);
expect(report.balances).toEqual([expect.objectContaining({ remaining: 0, tone: "danger" })]);
expect(report.balances).toEqual([
expect.objectContaining({ remaining: 0, unit: "credits", tone: "danger" }),
]);
});
test("summarizes the session and weekly windows by default, not code review", async () => {
const report = await fetchUsage(
{},
async () =>
new Response(
JSON.stringify({
rate_limit: {
primary_window: { used_percent: 12 },
secondary_window: { used_percent: 40 },
},
code_review_rate_limit: { primary_window: { used_percent: 5 } },
}),
{ status: 200 },
),
);
expect(report.windows.map((window) => [window.id, window.summary ?? false])).toEqual([
["session", true],
["weekly", true],
["code_review", false],
]);
});
test("HTML usage body is unavailable", async () => {
+15 -8
View File
@@ -57,15 +57,13 @@ export async function readAuth(
}
function usageWindow(
id: string,
label: string,
spec: { id: string; label: string; shortLabel: string; summary?: boolean },
value: z.infer<typeof windowSchema> | null | undefined,
): UsageWindow | null {
if (!value) return null;
const usedPct = value.used_percent ?? 0;
return windowFromUsedPct({
id,
label,
...spec,
utilizationPct: usedPct,
resetsAt: value.reset_at != null ? new Date(value.reset_at * 1000).toISOString() : null,
tone: toneFromUsedPct(usedPct),
@@ -95,9 +93,18 @@ export async function fetchUsage(
if (text.trim().startsWith("<")) return { status: "unavailable", windows: [] };
const usage = responseSchema.parse(JSON.parse(text));
const windows = [
usageWindow("session", "Session", usage.rate_limit?.primary_window),
usageWindow("weekly", "Weekly", usage.rate_limit?.secondary_window),
usageWindow("code_review", "Code review", usage.code_review_rate_limit?.primary_window),
usageWindow(
{ id: "session", label: "Session", shortLabel: "5h", summary: true },
usage.rate_limit?.primary_window,
),
usageWindow(
{ id: "weekly", label: "Weekly", shortLabel: "wk", summary: true },
usage.rate_limit?.secondary_window,
),
usageWindow(
{ id: "code_review", label: "Code review", shortLabel: "review" },
usage.code_review_rate_limit?.primary_window,
),
].filter((window): window is UsageWindow => window !== null);
const balance = usage.credits?.balance;
return {
@@ -112,7 +119,7 @@ export async function fetchUsage(
id: "credits",
label: "Credits",
remaining: balance,
unit: "usd",
unit: "credits",
tone: balanceToneFromRemaining(balance),
},
],
@@ -98,6 +98,7 @@ function grokUsageWindow(response: z.infer<typeof GrokUsageResponseSchema>): Usa
return windowFromUsedPct({
id: weekly ? "weekly" : "monthly",
label: weekly ? "Weekly" : "Monthly",
shortLabel: weekly ? "wk" : "mo",
utilizationPct: percent,
resetsAt: period?.end ?? null,
tone: toneFromUsedPct(percent),
+4
View File
@@ -78,6 +78,8 @@ export class Usage {
windowFromUsedPct({
id: "five_hour",
label: `${usage.window.windowDurationMins / 60} hours`,
shortLabel: `${usage.window.windowDurationMins / 60}h`,
summary: true,
utilizationPct: usage.window.usedPercent,
resetsAt: new Date(usage.window.resetsAtMs).toISOString(),
tone: toneFromUsedPct(usage.window.usedPercent),
@@ -85,6 +87,8 @@ export class Usage {
windowFromUsedPct({
id: "weekly",
label: "Weekly",
shortLabel: "wk",
summary: true,
utilizationPct: usage.weekly.usedPercent,
resetsAt: new Date(usage.weekly.resetsAtMs).toISOString(),
tone: toneFromUsedPct(usage.weekly.usedPercent),
@@ -59,6 +59,8 @@ test("discovers and fetches the default key from read-only auth.json", async ()
["weekly", 42, "2026-09-28T00:00:00.000Z"],
["monthly", 100, "2026-10-01T00:00:00.000Z"],
]);
// The rolling window's length is not reported, so its percent stands without a name.
expect(report.windows.map((window) => window.shortLabel)).toEqual(["", "wk", "mo"]);
// The current upstream endpoint returns windows only; do not invent balances.
expect(report.balances).toBeUndefined();
expect(await readFile(path, "utf8")).toBe(content);
@@ -65,14 +65,16 @@ export async function fetchUsage(
const data = responseSchema.parse(await response.json());
const windows = (
[
["rolling", "Rolling", data.usage.rolling],
["weekly", "Weekly", data.usage.weekly],
["monthly", "Monthly", data.usage.monthly],
// The rolling window's length is not reported, so its percent stands without a name.
["rolling", "Rolling", "", data.usage.rolling],
["weekly", "Weekly", "wk", data.usage.weekly],
["monthly", "Monthly", "mo", data.usage.monthly],
] as const
).map(([id, label, value]) =>
).map(([id, label, shortLabel, value]) =>
windowFromUsedPct({
id,
label,
shortLabel,
utilizationPct: value.percent,
resetsAt: value.resetsAt,
tone: toneFromUsedPct(value.percent),