Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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");
Expand Down Expand Up @@ -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");
Expand All @@ -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();
Expand Down Expand Up @@ -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();
});
},
};
Expand All @@ -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();
});
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const UserDropdownAISpend: FC<UserDropdownAISpendProps> = ({
/>
)}
<div className="mt-1 text-xs text-content-secondary">
(AI spend/month)
(Estimated AI spend/month)
</div>
</div>
);
Expand Down
13 changes: 13 additions & 0 deletions site/src/pages/GroupsPage/AICostControl.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { FC } from "react";
import { Link } from "#/components/Link/Link";
import { docs } from "#/utils/docs";

export const SpendEstimateDocsLink: FC = () => (
<Link
href={docs("/ai-coder/ai-gateway/cost-controls#how-spend-is-estimated")}
target="_blank"
rel="noreferrer"
>
How spend is estimated
</Link>
);
11 changes: 9 additions & 2 deletions site/src/pages/GroupsPage/GroupMembersPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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")}.`,
Expand Down Expand Up @@ -173,7 +174,13 @@ const GroupMembersPage: FC = () => {
message="AI spend couldn't be loaded, so budgets aren't shown."
/>
) : (
<StatusIconTooltip message={aiBudgetNote} />
<StatusIconTooltip
message={
<>
{aiBudgetNote} <SpendEstimateDocsLink />
</>
}
/>
)}
</div>
</TableHead>
Expand Down
6 changes: 4 additions & 2 deletions site/src/pages/GroupsPage/GroupPage.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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}");

Expand Down
10 changes: 9 additions & 1 deletion site/src/pages/GroupsPage/GroupsPageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -94,7 +95,14 @@ export const GroupsPageView: FC<GroupsPageViewProps> = ({
message="AI spend couldn't be loaded, so budgets aren't shown."
/>
) : (
<StatusIconTooltip message="Current AI spend compared to the group's AI budget for the active period." />
<StatusIconTooltip
message={

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose the message here can take a JSX and not just a string?

Just checked and it does, maybe we need to rename this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point 👍 I didn't change it here in order to avoid further changes, since this is used in some places. Will address this as a follow-up

<>
Estimated AI spend compared to the group's AI budget for
the active period. <SpendEstimateDocsLink />
</>
}
/>
)}
</div>
</TableHead>
Expand Down
Loading