-
Notifications
You must be signed in to change notification settings - Fork 670
feat(usage): add account usage filter and indicators in provider workspace (#1063) #1083
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,20 +8,27 @@ import QuotaBars from "../QuotaBars"; | |
| import type { WorkspaceItem } from "../../provider-workspace/catalog"; | ||
| import { formatRelativeTime, relativeTimeLabelsFromT, formatRequestCount, formatTokenCount, formatCostUsd } from "../../provider-workspace/usage"; | ||
| import { accountQuotaFromReport, formatQuotaSourceLabel, type ProviderQuotaReportView } from "../../provider-workspace/report"; | ||
| import type { ProviderUsageTotals, ProviderModelUsageRow } from "./types"; | ||
| import type { ProviderUsageTotals, ProviderModelUsageRow, OAuthAccountRow } from "./types"; | ||
|
|
||
| export default function ProviderUsage({ item, usageTotals, quotaReport, modelUsage }: { | ||
| export default function ProviderUsage({ item, usageTotals, quotaReport, modelUsage, accounts }: { | ||
| item: WorkspaceItem; | ||
| usageTotals?: ProviderUsageTotals; | ||
| quotaReport?: ProviderQuotaReportView; | ||
| modelUsage?: ProviderModelUsageRow[]; | ||
| accounts?: OAuthAccountRow[]; | ||
| }) { | ||
| const t = useT(); | ||
| const { locale } = useI18n(); | ||
| const timeLabels = relativeTimeLabelsFromT(t); | ||
| const hasUsage = usageTotals?.requests !== undefined; | ||
| const quota = accountQuotaFromReport(quotaReport); | ||
| const [expandedModel, setExpandedModel] = useState<string | null>(null); | ||
| const [selectedAccountId, setSelectedAccountId] = useState<string>("all"); | ||
|
|
||
| const selectedAccount = useMemo(() => { | ||
| if (!accounts?.length || selectedAccountId === "all") return null; | ||
| return accounts.find(a => a.id === selectedAccountId) ?? null; | ||
| }, [accounts, selectedAccountId]); | ||
| void item; | ||
|
|
||
| const sortedModels = useMemo(() => { | ||
|
|
@@ -45,7 +52,37 @@ export default function ProviderUsage({ item, usageTotals, quotaReport, modelUsa | |
| return ( | ||
| <div className="pws-section"> | ||
| <div className="pws-usage-block"> | ||
| <h3 className="pws-section-title">{t("pws.usageLast30d")}</h3> | ||
| <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 12 }}> | ||
| <h3 className="pws-section-title" style={{ margin: 0 }}>{t("pws.usageLast30d")}</h3> | ||
| {accounts && accounts.length > 0 && ( | ||
| <div style={{ display: "flex", alignItems: "center", gap: 8 }}> | ||
| <label htmlFor="pws-account-filter" className="muted faint" style={{ fontSize: 13 }}> | ||
| {t("pws.usageAccountSelector")}: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This introduces a new user-facing workflow under Providers → Usage, but the commit does not update AGENTS.md reference: gui/AGENTS.md:L36-L36 Useful? React with 👍 / 👎. |
||
| </label> | ||
| <select | ||
| id="pws-account-filter" | ||
| className="select select-sm" | ||
| value={selectedAccountId} | ||
| onChange={e => setSelectedAccountId(e.target.value)} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a multi-account provider user selects an individual account, this handler only changes AGENTS.md reference: gui/AGENTS.md:L9-L10 Useful? React with 👍 / 👎. |
||
| > | ||
| <option value="all">{t("pws.allAccountsCombined")}</option> | ||
| {accounts.map(acc => ( | ||
| <option key={acc.id} value={acc.id}> | ||
| {acc.email ?? acc.alias ?? acc.id} {acc.active ? `(${t("prov.accountActive")})` : ""} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When an OAuth account has neither an email nor an alias, this option renders the complete raw AGENTS.md reference: gui/AGENTS.md:L9-L9 Useful? React with 👍 / 👎. |
||
| </option> | ||
| ))} | ||
| </select> | ||
| </div> | ||
| )} | ||
| </div> | ||
| {selectedAccount && ( | ||
| <div style={{ marginTop: 8 }}> | ||
| <span className="badge badge-primary"> | ||
| {selectedAccount.email ?? selectedAccount.alias ?? selectedAccount.id} | ||
| {selectedAccount.active ? ` · ${t("prov.accountActive")}` : ""} | ||
| </span> | ||
| </div> | ||
| )} | ||
| {hasUsage ? ( | ||
| <> | ||
| <div className="pws-usage-metrics pws-usage-metrics-3" role="group" aria-label={t("pws.usageLast30d")}> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Account selector changes the badge but not the displayed usage numbers.
selectedAccountIdandselectedAccount(lines 26-31) are only read to render the badge (lines 78-85). The cost/requests/tokens metrics (lines 88-101) and the model breakdown table useproviderCostandsortedModels, both derived solely from theusageTotals/modelUsageprops, which stay fixed at the combined provider totals regardless ofselectedAccountId.Concretely: pick an individual account from the dropdown, and the badge shows that account's email, but "Estimated cost", "requests", "tokens", and the "Model breakdown" table below are unchanged — they still show the provider-wide combined figures. This means the selector currently misleads users into thinking they are looking at per-account numbers.
Issue
#1063(linked in the PR objectives) explicitly requires that selecting an account shows "30-day request count, token usage, and estimated cost" for that account, and that "The interface should clearly indicate whether displayed statistics represent overall provider usage or the selected account's usage." As implemented, the interface never shows account-specific statistics — only account-specific identity.Since
OAuthAccountRow(intypes.ts) carries no usage/cost fields, the fix needs either:accountUsageTotals?: Record<string, ProviderUsageTotals>(or similar) passed down fromProviderDetails, keyed by account id, so the metrics block can pickaccountUsageTotals[selectedAccountId] ?? usageTotalsandsortedModelscan filter/aggregate model usage per account, or🐛 Minimal fix if per-account data is not yet wired
{hasUsage ? ( <> - <div className="pws-usage-metrics pws-usage-metrics-3" role="group" aria-label={t("pws.usageLast30d")}> + <div className="pws-usage-metrics pws-usage-metrics-3" role="group" aria-label={t("pws.usageLast30d")}> + {selectedAccount && ( + <p className="muted pws-cost-disclaimer">{t("pws.accountUsageUnavailable")}</p> + )} <div className="pws-usage-metric">Do you want me to draft the per-account data plumbing through
ProviderDetailsif the management API already exposes per-account usage?Also applies to: 55-106
🤖 Prompt for AI Agents