diff --git a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.stories.tsx b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.stories.tsx index 6260b96dc7157..ff48b732541e8 100644 --- a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.stories.tsx +++ b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.stories.tsx @@ -73,7 +73,7 @@ export const WithAISpend: Story = { await waitFor(() => expect(document.body).toHaveTextContent("$819 / $1,200 USD"), ); - expect(document.body).toHaveTextContent("(AI spend/month)"); + expect(document.body).toHaveTextContent("(Estimated AI spend/month)"); expect( screen.getByRole("progressbar", { name: "AI spend usage" }), ).toHaveAttribute("aria-valuenow", "68"); @@ -97,7 +97,7 @@ export const AISpendWarning: Story = { await waitFor(() => expect(document.body).toHaveTextContent("$1,080 / $1,200 USD"), ); - expect(document.body).toHaveTextContent("(AI spend/month)"); + expect(document.body).toHaveTextContent("(Estimated AI spend/month)"); expect( screen.getByRole("progressbar", { name: "AI spend usage" }), ).toHaveAttribute("aria-valuenow", "90"); @@ -144,7 +144,7 @@ export const AISpendExceeded: Story = { await waitFor(() => expect(document.body).toHaveTextContent("$1,500 / $1,200 USD"), ); - expect(document.body).toHaveTextContent("(AI spend/month)"); + expect(document.body).toHaveTextContent("(Estimated AI spend/month)"); expect( screen.getByRole("progressbar", { name: "AI spend usage" }), ).toHaveAttribute("aria-valuenow", "100"); @@ -165,7 +165,7 @@ export const AISpendUnlimited: Story = { await waitFor(() => expect(document.body).toHaveTextContent("$819 / Unlimited USD"), ); - expect(document.body).toHaveTextContent("(AI spend/month)"); + expect(document.body).toHaveTextContent("(Estimated AI spend/month)"); expect( screen.queryByRole("progressbar", { name: "AI spend usage" }), ).not.toBeInTheDocument(); @@ -272,7 +272,7 @@ export const AISpendHiddenOnInvalidData: Story = { play: async ({ canvasElement, step }) => { await step("hides AI spend on invalid data", async () => { await openDropdown(canvasElement); - expect(screen.queryByText("(AI spend/month)")).not.toBeInTheDocument(); + expect(screen.queryByText(/spend\/month/)).not.toBeInTheDocument(); }); }, }; @@ -293,7 +293,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("(AI spend/month)")).not.toBeInTheDocument(); + expect(screen.queryByText(/spend\/month/)).not.toBeInTheDocument(); }); }, }; diff --git a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownAISpend.tsx b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownAISpend.tsx index 2cff36afa4519..17e9816b7bcab 100644 --- a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownAISpend.tsx +++ b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownAISpend.tsx @@ -31,7 +31,7 @@ export const UserDropdownAISpend: FC = ({ /> )}
- (AI spend/month) + (Estimated AI spend/month)
); diff --git a/site/src/pages/GroupsPage/AICostControl.tsx b/site/src/pages/GroupsPage/AICostControl.tsx new file mode 100644 index 0000000000000..31f43623ae447 --- /dev/null +++ b/site/src/pages/GroupsPage/AICostControl.tsx @@ -0,0 +1,13 @@ +import type { FC } from "react"; +import { Link } from "#/components/Link/Link"; +import { docs } from "#/utils/docs"; + +export const SpendEstimateDocsLink: FC = () => ( + + How spend is estimated + +); diff --git a/site/src/pages/GroupsPage/GroupMembersPage.tsx b/site/src/pages/GroupsPage/GroupMembersPage.tsx index 953a87c7cd64e..fa8c1d7808b53 100644 --- a/site/src/pages/GroupsPage/GroupMembersPage.tsx +++ b/site/src/pages/GroupsPage/GroupMembersPage.tsx @@ -52,6 +52,7 @@ import { useFeatureVisibility } from "#/modules/dashboard/useFeatureVisibility"; import { isEveryoneGroup } from "#/modules/groups"; import { cn } from "#/utils/cn"; import { formatBudgetUSD } from "#/utils/currency"; +import { SpendEstimateDocsLink } from "./AICostControl"; import { effectiveBudgetGroup, GroupMemberBudgetCells, @@ -112,7 +113,7 @@ const GroupMembersPage: FC = () => { }), ); const aiBudgetNote = [ - "Monthly AI spend for this user.", + "Estimated 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")}.`, @@ -173,7 +174,13 @@ const GroupMembersPage: FC = () => { message="AI spend couldn't be loaded, so budgets aren't shown." /> ) : ( - + + {aiBudgetNote} + + } + /> )} diff --git a/site/src/pages/GroupsPage/GroupPage.stories.tsx b/site/src/pages/GroupsPage/GroupPage.stories.tsx index 2a42dd04b1676..c8a5e62231ca8 100644 --- a/site/src/pages/GroupsPage/GroupPage.stories.tsx +++ b/site/src/pages/GroupsPage/GroupPage.stories.tsx @@ -365,7 +365,7 @@ export const WithMemberAIBudget: Story = { ); await expect( await body.findByText( - /^Monthly AI spend for this user\. Resets .*The group's default limit is \$7,000 per member\.$/, + /^Estimated monthly AI spend for this user\. Resets .*The group's default limit is \$7,000 per member\.$/, ), ).toBeInTheDocument(); await userEvent.click( @@ -434,7 +434,9 @@ export const AIBudgetActionDisabledForOtherGroup: Story = { }), ); await expect( - await body.findByText(/^Monthly AI spend for this user\. Resets .*\.$/), + await body.findByText( + /^Estimated monthly AI spend for this user\. Resets .*\.$/, + ), ).toBeInTheDocument(); await userEvent.keyboard("{Escape}"); diff --git a/site/src/pages/GroupsPage/GroupsPageView.tsx b/site/src/pages/GroupsPage/GroupsPageView.tsx index f7ed9fffd1dc2..79e44597904ff 100644 --- a/site/src/pages/GroupsPage/GroupsPageView.tsx +++ b/site/src/pages/GroupsPage/GroupsPageView.tsx @@ -25,6 +25,7 @@ import { } from "#/components/TableLoader/TableLoader"; import { useClickableTableRow } from "#/hooks/useClickableTableRow"; import { docs } from "#/utils/docs"; +import { SpendEstimateDocsLink } from "./AICostControl"; import { StatusIconTooltip } from "./StatusIconTooltip"; const EM_DASH = "\u2014"; @@ -94,7 +95,14 @@ export const GroupsPageView: FC = ({ message="AI spend couldn't be loaded, so budgets aren't shown." /> ) : ( - + + Estimated AI spend compared to the group's AI budget for + the active period. + + } + /> )}