From 79f2dbdaf5b8b858ada39d3bf562a6e5350e2b52 Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Mon, 10 Aug 2026 09:58:05 +0000 Subject: [PATCH] chore: use 'AI spend' and 'approximate' in budget UI --- .../UserDropdown/UserDropdown.stories.tsx | 22 +++++++++---------- .../UserDropdown/UserDropdownAISpend.tsx | 5 ++++- .../GroupMemberBudgetCells.stories.tsx | 2 +- .../GroupsPage/GroupMemberBudgetCells.tsx | 2 +- .../src/pages/GroupsPage/GroupMembersPage.tsx | 4 ++-- .../pages/GroupsPage/GroupPage.stories.tsx | 12 +++++----- .../GroupsPage/GroupsPageView.stories.tsx | 6 ++--- site/src/pages/GroupsPage/GroupsPageView.tsx | 6 ++--- 8 files changed, 31 insertions(+), 28 deletions(-) diff --git a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.stories.tsx b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.stories.tsx index 4577a7817382f..58c518a998be3 100644 --- a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.stories.tsx +++ b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.stories.tsx @@ -18,7 +18,7 @@ const mockAISpend: UserAISpendStatus = { period_end: "2026-07-01T00:00:00Z", }; -const spendPeriodLabel = "Estimated AI spend: June 1 - July 1, 2026"; +const spendPeriodLabel = "Approximate AI spend June 1 - July 1, 2026"; const aiCostControl: { features: FeatureName[] } = { features: ["aibridge"], @@ -71,10 +71,10 @@ export const WithAISpend: Story = { }, play: async ({ canvasElement, step }) => { await step("shows AI spend", async () => { - const menu = await openDropdown(canvasElement); + await openDropdown(canvasElement); await waitFor(() => { expect(document.body).toHaveTextContent("$819 / $1,200 USD"); - expect(menu.getByText(spendPeriodLabel)).toBeVisible(); + expect(document.body).toHaveTextContent(spendPeriodLabel); }); expect( screen.getByRole("progressbar", { name: "AI spend usage" }), @@ -95,10 +95,10 @@ export const AISpendWarning: Story = { }, play: async ({ canvasElement, step }) => { await step("shows the warning marker near the limit", async () => { - const menu = await openDropdown(canvasElement); + await openDropdown(canvasElement); await waitFor(() => { expect(document.body).toHaveTextContent("$1,080 / $1,200 USD"); - expect(menu.getByText(spendPeriodLabel)).toBeVisible(); + expect(document.body).toHaveTextContent(spendPeriodLabel); }); expect( screen.getByRole("progressbar", { name: "AI spend usage" }), @@ -142,10 +142,10 @@ export const AISpendExceeded: Story = { }, play: async ({ canvasElement, step }) => { await step("shows the exceeded marker at the limit", async () => { - const menu = await openDropdown(canvasElement); + await openDropdown(canvasElement); await waitFor(() => { expect(document.body).toHaveTextContent("$1,500 / $1,200 USD"); - expect(menu.getByText(spendPeriodLabel)).toBeVisible(); + expect(document.body).toHaveTextContent(spendPeriodLabel); }); expect( screen.getByRole("progressbar", { name: "AI spend usage" }), @@ -163,10 +163,10 @@ export const AISpendUnlimited: Story = { }, play: async ({ canvasElement, step }) => { await step("shows unlimited spend without a bar", async () => { - const menu = await openDropdown(canvasElement); + await openDropdown(canvasElement); await waitFor(() => { expect(document.body).toHaveTextContent("$819 / Unlimited USD"); - expect(menu.getByText(spendPeriodLabel)).toBeVisible(); + expect(document.body).toHaveTextContent(spendPeriodLabel); }); expect( screen.queryByRole("progressbar", { name: "AI spend usage" }), @@ -274,7 +274,7 @@ export const AISpendHiddenOnInvalidData: Story = { play: async ({ canvasElement, step }) => { await step("hides AI spend on invalid data", async () => { await openDropdown(canvasElement); - expect(screen.queryByText(spendPeriodLabel)).not.toBeInTheDocument(); + expect(document.body).not.toHaveTextContent(spendPeriodLabel); }); }, }; @@ -295,7 +295,7 @@ export const AISpendHiddenOnNegativeLimit: Story = { play: async ({ canvasElement, step }) => { await step("hides AI spend on a negative limit", async () => { await openDropdown(canvasElement); - expect(screen.queryByText(spendPeriodLabel)).not.toBeInTheDocument(); + expect(document.body).not.toHaveTextContent(spendPeriodLabel); }); }, }; diff --git a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownAISpend.tsx b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownAISpend.tsx index 8060e5efd13f0..968d31c053cdd 100644 --- a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownAISpend.tsx +++ b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownAISpend.tsx @@ -39,7 +39,10 @@ export const UserDropdownAISpend: FC = ({ /> )}
- Estimated AI spend: {formatSpendPeriodLabel(periodStart, periodEnd)} + Approximate AI spend{" "} + + {formatSpendPeriodLabel(periodStart, periodEnd)} +
); diff --git a/site/src/pages/GroupsPage/GroupMemberBudgetCells.stories.tsx b/site/src/pages/GroupsPage/GroupMemberBudgetCells.stories.tsx index 758c8b66929a7..2ca857b8e779e 100644 --- a/site/src/pages/GroupsPage/GroupMemberBudgetCells.stories.tsx +++ b/site/src/pages/GroupsPage/GroupMemberBudgetCells.stories.tsx @@ -45,7 +45,7 @@ const meta: Meta = { - AI budget + AI spend Budget group diff --git a/site/src/pages/GroupsPage/GroupMemberBudgetCells.tsx b/site/src/pages/GroupsPage/GroupMemberBudgetCells.tsx index eb6922061622a..a449b966128ee 100644 --- a/site/src/pages/GroupsPage/GroupMemberBudgetCells.tsx +++ b/site/src/pages/GroupsPage/GroupMemberBudgetCells.tsx @@ -17,7 +17,7 @@ const OTHER_ORG_MESSAGE = "This user's AI budget is managed by a group in another organization and isn't visible here."; /** - * The AI budget and Budget group cells for a group member. Spend is scoped to + * The AI spend and Budget group cells for a group member. Spend is scoped to * the viewed group; the limit comes from the member's effective group. */ export const GroupMemberBudgetCells: FC<{ diff --git a/site/src/pages/GroupsPage/GroupMembersPage.tsx b/site/src/pages/GroupsPage/GroupMembersPage.tsx index 33ff7b2237451..48727a29cabb2 100644 --- a/site/src/pages/GroupsPage/GroupMembersPage.tsx +++ b/site/src/pages/GroupsPage/GroupMembersPage.tsx @@ -101,7 +101,7 @@ const GroupMembersPage: FC = () => { }), ); const aiBudgetNote = [ - "Estimated monthly AI spend for this user.", + "Approximate monthly AI spend for this user.", // Spend resets at period_end, rendered in the viewer's local time. aiSpend && `Resets ${dayjs(aiSpend.period_end).format("MMM D, YYYY h:mm A")}.`, @@ -141,7 +141,7 @@ const GroupMembersPage: FC = () => { <>
- AI budget + AI spend {membersSpendQuery.isError ? ( { const canvas = within(canvasElement); - await expect(await canvas.findByText("AI budget")).toBeInTheDocument(); + await expect(await canvas.findByText("AI spend")).toBeInTheDocument(); await expect(await canvas.findByText("Budget group")).toBeInTheDocument(); await expect( await canvas.findByText("AI budget period: June 1 - July 1, 2026"), @@ -358,13 +358,13 @@ export const WithMemberAIBudget: Story = { const body = within(document.body); await userEvent.click( - within(canvas.getByText("AI budget")).getByRole("button", { + within(canvas.getByText("AI spend")).getByRole("button", { name: "More info", }), ); await expect( await body.findByText( - /^Estimated monthly AI spend for this user\. Resets .*The group's default limit is \$7,000 per member\.$/, + /^Approximate monthly AI spend for this user\. Resets .*The group's default limit is \$7,000 per member\.$/, ), ).toBeInTheDocument(); await userEvent.click( @@ -391,7 +391,7 @@ export const WithoutMemberAIBudgetColumn: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); await canvas.findByRole("table", { name: "Group members" }); - expect(canvas.queryByText("AI budget")).not.toBeInTheDocument(); + expect(canvas.queryByText("AI spend")).not.toBeInTheDocument(); expect(canvas.queryByText("Budget group")).not.toBeInTheDocument(); expect(canvas.queryByText(/AI budget period/)).not.toBeInTheDocument(); }, @@ -428,13 +428,13 @@ export const AIBudgetActionDisabledForOtherGroup: Story = { // Without a group default budget, the header note ends at the reset date. await userEvent.click( - within(canvas.getByText("AI budget")).getByRole("button", { + within(canvas.getByText("AI spend")).getByRole("button", { name: "More info", }), ); await expect( await body.findByText( - /^Estimated monthly AI spend for this user\. Resets .*\.$/, + /^Approximate monthly AI spend for this user\. Resets .*\.$/, ), ).toBeInTheDocument(); await userEvent.keyboard("{Escape}"); diff --git a/site/src/pages/GroupsPage/GroupsPageView.stories.tsx b/site/src/pages/GroupsPage/GroupsPageView.stories.tsx index adb97a9b13d96..9d74dddaab89d 100644 --- a/site/src/pages/GroupsPage/GroupsPageView.stories.tsx +++ b/site/src/pages/GroupsPage/GroupsPageView.stories.tsx @@ -171,7 +171,7 @@ export const WithAIBudgetsLoading: Story = { }, }; -// Spend still loading: every AI budget cell falls back to an em dash. +// Spend still loading: every AI spend cell falls back to an em dash. export const WithAIBudgetsSpendLoading: Story = { args: { groups: [aiGroup("ai-loading", "Spend loading")], @@ -223,7 +223,7 @@ export const WithAIBudgetsSpendUnavailable: Story = { }, }; -// AI Bridge hidden: no AI budget column. +// AI Bridge hidden: no AI spend column. export const WithoutAIBudgetColumn: Story = { args: { groups: [aiGroup("ai-hidden", "No AI column")], @@ -233,7 +233,7 @@ export const WithoutAIBudgetColumn: Story = { }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); - expect(canvas.queryByText("AI budget")).not.toBeInTheDocument(); + expect(canvas.queryByText("AI spend")).not.toBeInTheDocument(); }, }; diff --git a/site/src/pages/GroupsPage/GroupsPageView.tsx b/site/src/pages/GroupsPage/GroupsPageView.tsx index 6ae73a1ff096a..2a2bbe3ef55d1 100644 --- a/site/src/pages/GroupsPage/GroupsPageView.tsx +++ b/site/src/pages/GroupsPage/GroupsPageView.tsx @@ -92,7 +92,7 @@ export const GroupsPageView: FC = ({ {showAIBudget && (
- AI budget + AI spend {spendError ? ( = ({ - Estimated AI spend compared to the group's AI budget for - the active period. + Approximate AI spend compared to the group's AI budget + for the active period. } />