From 87428d30fdca5797a09f8326d1d07539255485f1 Mon Sep 17 00:00:00 2001 From: agentHits Date: Thu, 6 Aug 2026 01:08:51 +0300 Subject: [PATCH] feat(usage): add account usage filter and indicators in provider workspace (#1063) --- .../provider-workspace/ProviderDetails.tsx | 2 +- .../provider-workspace/ProviderUsage.tsx | 43 +++++++++++++++++-- gui/src/i18n/de.ts | 6 +++ gui/src/i18n/en.ts | 6 +++ gui/src/i18n/ja.ts | 6 +++ gui/src/i18n/ko.ts | 6 +++ gui/src/i18n/ru.ts | 6 +++ gui/src/i18n/zh.ts | 6 +++ 8 files changed, 77 insertions(+), 4 deletions(-) diff --git a/gui/src/components/provider-workspace/ProviderDetails.tsx b/gui/src/components/provider-workspace/ProviderDetails.tsx index 155a762ef9..c9a14d0528 100644 --- a/gui/src/components/provider-workspace/ProviderDetails.tsx +++ b/gui/src/components/provider-workspace/ProviderDetails.tsx @@ -269,7 +269,7 @@ export default function ProviderDetails({ /> )} {tab === "usage" && ( - + )} {tab === "accounts" && ( (null); + const [selectedAccountId, setSelectedAccountId] = useState("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 (
-

{t("pws.usageLast30d")}

+
+

{t("pws.usageLast30d")}

+ {accounts && accounts.length > 0 && ( +
+ + +
+ )} +
+ {selectedAccount && ( +
+ + {selectedAccount.email ?? selectedAccount.alias ?? selectedAccount.id} + {selectedAccount.active ? ` · ${t("prov.accountActive")}` : ""} + +
+ )} {hasUsage ? ( <>
diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 46d78faceb..77206ddbab 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -1454,6 +1454,12 @@ export const de: Record = { "pws.noModelMatch": "Keine Modelle entsprechen dem Filter.", "pws.adapterBaseRequired": "Adapter und Basis-URL sind erforderlich.", "pws.addAccount": "Konto hinzufügen", + "pws.importJson": "JSON importieren", + "pws.importJsonCockpit": "JSON importieren (Cockpit)", + "pws.importResultSummary": "{imported} Konto/en importiert, {failed} fehlgeschlagen.", + "pws.usageAccountSelector": "Kontonutzungsfilter", + "pws.allAccountsCombined": "Alle Konten (Kombiniert)", + "prov.expiresAt": "Läuft ab: {date}", "pws.addKey": "API-Schlüssel hinzufügen", "pws.apiKeys": "API-Schlüssel", "pws.authMode": "Auth-Modus", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index 8389a237a2..22872fe3c7 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -1005,6 +1005,12 @@ export const en = { "pws.noModelMatch": "No models match the filter.", "pws.adapterBaseRequired": "Adapter and base URL are required.", "pws.addAccount": "Add account", + "pws.importJson": "Import JSON", + "pws.importJsonCockpit": "Import JSON (Cockpit)", + "pws.importResultSummary": "Imported {imported} account(s), {failed} failed.", + "pws.usageAccountSelector": "Account Usage Filter", + "pws.allAccountsCombined": "All Accounts (Combined)", + "prov.expiresAt": "Expires: {date}", "pws.addKey": "Add API key", "pws.apiKeys": "API Keys", "pws.authMode": "Auth mode", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 77aaa0dd82..151f397d42 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -953,6 +953,12 @@ export const ja: Record = { "pws.noModelMatch": "フィルタに一致するモデルがありません。", "pws.adapterBaseRequired": "アダプターとベース URL は必須です。", "pws.addAccount": "アカウントを追加", + "pws.importJson": "JSON をインポート", + "pws.importJsonCockpit": "JSON をインポート (Cockpit)", + "pws.importResultSummary": "{imported} 件のアカウントをインポートしました(失敗: {failed} 件)。", + "pws.usageAccountSelector": "アカウント利用フィルター", + "pws.allAccountsCombined": "全アカウント(合計)", + "prov.expiresAt": "有効期限: {date}", "pws.addKey": "API キーを追加", "pws.apiKeys": "API キー", "pws.authMode": "認証モード", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index 93e03755ec..0c05bc4a49 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -1481,6 +1481,12 @@ export const ko: Record = { "pws.noModelMatch": "필터와 일치하는 모델이 없습니다.", "pws.adapterBaseRequired": "어댑터와 기본 URL은 필수입니다.", "pws.addAccount": "계정 추가", + "pws.importJson": "JSON 가져오기", + "pws.importJsonCockpit": "JSON 가져오기 (Cockpit)", + "pws.importResultSummary": "{imported}개 계정을 가져왔습니다 ({failed}개 실패).", + "pws.usageAccountSelector": "계정 사용 필터", + "pws.allAccountsCombined": "모든 계정 (합계)", + "prov.expiresAt": "만료일: {date}", "pws.addKey": "API 키 추가", "pws.apiKeys": "API 키", "pws.authMode": "인증 방식", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index 48e9149b63..6d08101b20 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -995,6 +995,12 @@ export const ru: Record = { "pws.noModelMatch": "Нет моделей, соответствующих фильтру.", "pws.adapterBaseRequired": "Укажите адаптер и базовый URL.", "pws.addAccount": "Добавить аккаунт", + "pws.importJson": "Импортировать JSON", + "pws.importJsonCockpit": "Импорт JSON (Cockpit)", + "pws.importResultSummary": "Импортировано аккаунтов: {imported}, ошибок: {failed}.", + "pws.usageAccountSelector": "Фильтр использования по аккаунту", + "pws.allAccountsCombined": "Все аккаунты (суммарно)", + "prov.expiresAt": "Истекает: {date}", "pws.addKey": "Добавить API-ключ", "pws.apiKeys": "API-ключи", "pws.authMode": "Режим аутентификации", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index 15e6053b33..11b1263cb4 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -1474,6 +1474,12 @@ export const zh: Record = { "pws.noModelMatch": "没有匹配筛选的模型。", "pws.adapterBaseRequired": "适配器和基本 URL 为必填项。", "pws.addAccount": "添加账户", + "pws.importJson": "导入 JSON", + "pws.importJsonCockpit": "导入 JSON (Cockpit)", + "pws.importResultSummary": "已导入 {imported} 个账户,{failed} 个失败。", + "pws.usageAccountSelector": "账户使用筛选", + "pws.allAccountsCombined": "所有账户(汇总)", + "prov.expiresAt": "到期时间: {date}", "pws.addKey": "添加 API 密钥", "pws.apiKeys": "API 密钥", "pws.authMode": "认证方式",