diff --git a/messages/en/bigScreen.json b/messages/en/bigScreen.json index a6eeadd56..6e24be785 100644 --- a/messages/en/bigScreen.json +++ b/messages/en/bigScreen.json @@ -32,5 +32,10 @@ "status": { "normal": "System Normal", "lastUpdate": "Last Update" + }, + "chart": { + "requestUnit": "requests", + "countLabel": "Count", + "switchLocale": "Switch language: {locale}" } } diff --git a/messages/en/dashboard.json b/messages/en/dashboard.json index 084d29071..15195b0c5 100644 --- a/messages/en/dashboard.json +++ b/messages/en/dashboard.json @@ -790,6 +790,12 @@ }, "keyListHeader": { "todayUsage": "Today's Usage", + "userStatus": { + "disabled": "Disabled", + "expired": "Expired", + "expiringSoon": "Expiring soon", + "active": "Enabled" + }, "allowedModels": { "label": "Allowed Models", "noRestrictions": "Allowed Models: No restrictions" diff --git a/messages/en/settings/providers/batchEdit.json b/messages/en/settings/providers/batchEdit.json index c1bc48a12..24fc6ec90 100644 --- a/messages/en/settings/providers/batchEdit.json +++ b/messages/en/settings/providers/batchEdit.json @@ -64,6 +64,7 @@ "description": "Review changes before applying to {count} providers", "providerHeader": "{name}", "fieldChanged": "{field}: {before} -> {after}", + "nullValue": "null", "fieldSkipped": "{field}: Skipped ({reason})", "excludeProvider": "Exclude", "summary": "{providerCount} providers, {fieldCount} changes, {skipCount} skipped", diff --git a/messages/en/settings/providers/form/common.json b/messages/en/settings/providers/form/common.json index 36534463d..ab4c7b067 100644 --- a/messages/en/settings/providers/form/common.json +++ b/messages/en/settings/providers/form/common.json @@ -5,6 +5,7 @@ "routing": "Routing", "limits": "Limits", "network": "Network", - "testing": "Testing" + "testing": "Testing", + "stepProgress": "Step progress" } } diff --git a/messages/en/settings/providers/form/sections.json b/messages/en/settings/providers/form/sections.json index 315d2b860..59548820e 100644 --- a/messages/en/settings/providers/form/sections.json +++ b/messages/en/settings/providers/form/sections.json @@ -306,6 +306,9 @@ "title": "Model Allowlist" }, "clientRestrictions": { + "toggleLabel": "Enable Client Restrictions", + "toggleDesc": "Clients are not restricted by default. Enable to configure allowlist/blocklist rules.", + "priorityNote": "Blocklist takes precedence over allowlist.", "allowedLabel": "Allowed Clients", "allowedPlaceholder": "e.g. claude-code-cli", "blockedLabel": "Blocked Clients", diff --git a/messages/ja/bigScreen.json b/messages/ja/bigScreen.json index 6ecfd9d74..f28eeb53e 100644 --- a/messages/ja/bigScreen.json +++ b/messages/ja/bigScreen.json @@ -32,5 +32,10 @@ "status": { "normal": "システム正常", "lastUpdate": "データ更新" + }, + "chart": { + "requestUnit": "リクエスト", + "countLabel": "件数", + "switchLocale": "言語を切り替え: {locale}" } } diff --git a/messages/ja/dashboard.json b/messages/ja/dashboard.json index d6776bb09..1555e52af 100644 --- a/messages/ja/dashboard.json +++ b/messages/ja/dashboard.json @@ -782,6 +782,12 @@ }, "keyListHeader": { "todayUsage": "本日の使用量", + "userStatus": { + "disabled": "無効", + "expired": "期限切れ", + "expiringSoon": "まもなく期限切れ", + "active": "有効" + }, "allowedModels": { "label": "許可モデル", "noRestrictions": "許可されたクライアント:制限なし" diff --git a/messages/ja/settings/providers/batchEdit.json b/messages/ja/settings/providers/batchEdit.json index 8feb4f198..166fa5d68 100644 --- a/messages/ja/settings/providers/batchEdit.json +++ b/messages/ja/settings/providers/batchEdit.json @@ -64,6 +64,7 @@ "description": "{count} 件のプロバイダーに適用する前に変更内容を確認してください", "providerHeader": "{name}", "fieldChanged": "{field}: {before} -> {after}", + "nullValue": "なし", "fieldSkipped": "{field}: スキップ ({reason})", "excludeProvider": "除外", "summary": "{providerCount} 件のプロバイダー, {fieldCount} 件の変更, {skipCount} 件スキップ", diff --git a/messages/ja/settings/providers/form/common.json b/messages/ja/settings/providers/form/common.json index d1cb1da2c..fe766439c 100644 --- a/messages/ja/settings/providers/form/common.json +++ b/messages/ja/settings/providers/form/common.json @@ -5,6 +5,7 @@ "routing": "ルーティング", "limits": "制限", "network": "ネットワーク", - "testing": "テスト" + "testing": "テスト", + "stepProgress": "ステップ進捗" } } diff --git a/messages/ja/settings/providers/form/sections.json b/messages/ja/settings/providers/form/sections.json index d7d23a3c2..619801caf 100644 --- a/messages/ja/settings/providers/form/sections.json +++ b/messages/ja/settings/providers/form/sections.json @@ -307,6 +307,9 @@ "title": "モデル許可リスト" }, "clientRestrictions": { + "toggleLabel": "クライアント制限を有効化", + "toggleDesc": "既定ではクライアントを制限しません。有効化すると許可/拒否リストを設定できます。", + "priorityNote": "拒否リストは許可リストより優先されます。", "allowedLabel": "許可クライアント", "allowedPlaceholder": "例: claude-code-cli", "blockedLabel": "ブロッククライアント", diff --git a/messages/ru/bigScreen.json b/messages/ru/bigScreen.json index 33b2a9090..e13aaf30e 100644 --- a/messages/ru/bigScreen.json +++ b/messages/ru/bigScreen.json @@ -32,5 +32,10 @@ "status": { "normal": "Система в норме", "lastUpdate": "Последнее обновление" + }, + "chart": { + "requestUnit": "запросов", + "countLabel": "Кол-во", + "switchLocale": "Переключить язык: {locale}" } } diff --git a/messages/ru/dashboard.json b/messages/ru/dashboard.json index c98716709..64a2c8211 100644 --- a/messages/ru/dashboard.json +++ b/messages/ru/dashboard.json @@ -785,6 +785,12 @@ }, "keyListHeader": { "todayUsage": "Использование сегодня", + "userStatus": { + "disabled": "Отключен", + "expired": "Истек", + "expiringSoon": "Скоро истечет", + "active": "Активен" + }, "allowedModels": { "label": "Разрешённые модели", "noRestrictions": "Разрешённые модели: без ограничений" diff --git a/messages/ru/settings/providers/batchEdit.json b/messages/ru/settings/providers/batchEdit.json index 9a620bf1b..b601c8b87 100644 --- a/messages/ru/settings/providers/batchEdit.json +++ b/messages/ru/settings/providers/batchEdit.json @@ -64,6 +64,7 @@ "description": "Проверьте изменения перед применением к {count} поставщикам", "providerHeader": "{name}", "fieldChanged": "{field}: {before} -> {after}", + "nullValue": "null", "fieldSkipped": "{field}: Пропущено ({reason})", "excludeProvider": "Исключить", "summary": "{providerCount} поставщиков, {fieldCount} изменений, {skipCount} пропущено", diff --git a/messages/ru/settings/providers/form/common.json b/messages/ru/settings/providers/form/common.json index fadb3569f..a294a3792 100644 --- a/messages/ru/settings/providers/form/common.json +++ b/messages/ru/settings/providers/form/common.json @@ -5,6 +5,7 @@ "routing": "Маршрутизация", "limits": "Лимиты", "network": "Сеть", - "testing": "Тестирование" + "testing": "Тестирование", + "stepProgress": "Прогресс шагов" } } diff --git a/messages/ru/settings/providers/form/sections.json b/messages/ru/settings/providers/form/sections.json index aac6a6fea..30367befc 100644 --- a/messages/ru/settings/providers/form/sections.json +++ b/messages/ru/settings/providers/form/sections.json @@ -307,6 +307,9 @@ "title": "Список разрешённых моделей" }, "clientRestrictions": { + "toggleLabel": "Включить ограничения клиентов", + "toggleDesc": "По умолчанию клиенты не ограничиваются. Включите, чтобы настроить правила белого/чёрного списка.", + "priorityNote": "Чёрный список имеет приоритет над белым списком.", "allowedLabel": "Разрешённые клиенты", "allowedPlaceholder": "напр. claude-code-cli", "blockedLabel": "Заблокированные клиенты", diff --git a/messages/zh-CN/bigScreen.json b/messages/zh-CN/bigScreen.json index c750dce83..aa9fcfa26 100644 --- a/messages/zh-CN/bigScreen.json +++ b/messages/zh-CN/bigScreen.json @@ -32,5 +32,10 @@ "status": { "normal": "系统正常", "lastUpdate": "数据更新" + }, + "chart": { + "requestUnit": "请求", + "countLabel": "数量", + "switchLocale": "切换语言: {locale}" } } diff --git a/messages/zh-CN/dashboard.json b/messages/zh-CN/dashboard.json index 740766f85..6743b6857 100644 --- a/messages/zh-CN/dashboard.json +++ b/messages/zh-CN/dashboard.json @@ -791,6 +791,12 @@ }, "keyListHeader": { "todayUsage": "今日用量", + "userStatus": { + "disabled": "已禁用", + "expired": "已过期", + "expiringSoon": "即将过期", + "active": "已启用" + }, "allowedModels": { "label": "允许的模型", "noRestrictions": "允许的模型:无限制" diff --git a/messages/zh-CN/settings/providers/batchEdit.json b/messages/zh-CN/settings/providers/batchEdit.json index 49d938805..64ce1ad86 100644 --- a/messages/zh-CN/settings/providers/batchEdit.json +++ b/messages/zh-CN/settings/providers/batchEdit.json @@ -64,6 +64,7 @@ "description": "将变更应用到 {count} 个供应商前请先确认", "providerHeader": "{name}", "fieldChanged": "{field}: {before} -> {after}", + "nullValue": "空", "fieldSkipped": "{field}: 已跳过 ({reason})", "excludeProvider": "排除", "summary": "{providerCount} 个供应商, {fieldCount} 项变更, {skipCount} 项跳过", diff --git a/messages/zh-CN/settings/providers/form/common.json b/messages/zh-CN/settings/providers/form/common.json index 88808dc1f..ea5277908 100644 --- a/messages/zh-CN/settings/providers/form/common.json +++ b/messages/zh-CN/settings/providers/form/common.json @@ -5,6 +5,7 @@ "routing": "路由", "limits": "限制", "network": "网络", - "testing": "测试" + "testing": "测试", + "stepProgress": "步骤进度" } } diff --git a/messages/zh-CN/settings/providers/form/sections.json b/messages/zh-CN/settings/providers/form/sections.json index 59ecf6d46..efc9d7c8d 100644 --- a/messages/zh-CN/settings/providers/form/sections.json +++ b/messages/zh-CN/settings/providers/form/sections.json @@ -50,6 +50,9 @@ "moreModels": "+{count} 更多" }, "clientRestrictions": { + "toggleLabel": "启用客户端限制", + "toggleDesc": "默认不限制客户端。启用后可配置白名单/黑名单。", + "priorityNote": "黑名单优先级高于白名单。", "allowedLabel": "白名单客户端", "allowedPlaceholder": "例如 claude-code-cli", "blockedLabel": "黑名单客户端", diff --git a/messages/zh-TW/bigScreen.json b/messages/zh-TW/bigScreen.json index 9f256e205..7727998a4 100644 --- a/messages/zh-TW/bigScreen.json +++ b/messages/zh-TW/bigScreen.json @@ -32,5 +32,10 @@ "status": { "normal": "系統正常", "lastUpdate": "資料更新" + }, + "chart": { + "requestUnit": "請求", + "countLabel": "數量", + "switchLocale": "切換語言: {locale}" } } diff --git a/messages/zh-TW/dashboard.json b/messages/zh-TW/dashboard.json index 96e47b627..e28e8eb07 100644 --- a/messages/zh-TW/dashboard.json +++ b/messages/zh-TW/dashboard.json @@ -782,6 +782,12 @@ }, "keyListHeader": { "todayUsage": "今日使用量", + "userStatus": { + "disabled": "已禁用", + "expired": "已過期", + "expiringSoon": "即將過期", + "active": "已啟用" + }, "allowedModels": { "label": "允許的模型", "noRestrictions": "允許的模型:無限制" diff --git a/messages/zh-TW/settings/providers/batchEdit.json b/messages/zh-TW/settings/providers/batchEdit.json index b8541e6e1..664a23a52 100644 --- a/messages/zh-TW/settings/providers/batchEdit.json +++ b/messages/zh-TW/settings/providers/batchEdit.json @@ -64,6 +64,7 @@ "description": "將變更應用到 {count} 個供應商前請先確認", "providerHeader": "{name}", "fieldChanged": "{field}: {before} -> {after}", + "nullValue": "空", "fieldSkipped": "{field}: 已跳過 ({reason})", "excludeProvider": "排除", "summary": "{providerCount} 個供應商, {fieldCount} 項變更, {skipCount} 項跳過", diff --git a/messages/zh-TW/settings/providers/form/common.json b/messages/zh-TW/settings/providers/form/common.json index 89489e20e..246f543fd 100644 --- a/messages/zh-TW/settings/providers/form/common.json +++ b/messages/zh-TW/settings/providers/form/common.json @@ -5,6 +5,7 @@ "routing": "路由", "limits": "限制", "network": "網路", - "testing": "測試" + "testing": "測試", + "stepProgress": "步驟進度" } } diff --git a/messages/zh-TW/settings/providers/form/sections.json b/messages/zh-TW/settings/providers/form/sections.json index 70cd5707e..e8c4333f7 100644 --- a/messages/zh-TW/settings/providers/form/sections.json +++ b/messages/zh-TW/settings/providers/form/sections.json @@ -307,6 +307,9 @@ "title": "模型允許清單" }, "clientRestrictions": { + "toggleLabel": "啟用用戶端限制", + "toggleDesc": "預設不限制用戶端。啟用後可設定白名單/黑名單。", + "priorityNote": "黑名單優先於白名單。", "allowedLabel": "白名單客戶端", "allowedPlaceholder": "例如 claude-code-cli", "blockedLabel": "黑名單客戶端", diff --git a/scripts/copy-version-to-standalone.cjs b/scripts/copy-version-to-standalone.cjs index a8776bdcc..7147dcd9a 100644 --- a/scripts/copy-version-to-standalone.cjs +++ b/scripts/copy-version-to-standalone.cjs @@ -1,6 +1,17 @@ const fs = require("node:fs"); const path = require("node:path"); +function copyDirIfExists(srcDir, dstDir) { + if (!fs.existsSync(srcDir)) { + console.warn(`[copy-standalone] Skip missing dir: ${srcDir}`); + return; + } + + fs.mkdirSync(path.dirname(dstDir), { recursive: true }); + fs.cpSync(srcDir, dstDir, { recursive: true, force: true }); + console.log(`[copy-standalone] Copied ${srcDir} -> ${dstDir}`); +} + const src = path.resolve(process.cwd(), "VERSION"); const dstDir = path.resolve(process.cwd(), ".next", "standalone"); const dst = path.join(dstDir, "VERSION"); @@ -13,3 +24,11 @@ if (!fs.existsSync(src)) { fs.mkdirSync(dstDir, { recursive: true }); fs.copyFileSync(src, dst); console.log(`[copy-version] Copied VERSION -> ${dst}`); + +// Make standalone output self-contained for local `node .next/standalone/server.js` runs. +// Next.js standalone requires `.next/static` and `public` to exist next to `server.js`. +copyDirIfExists( + path.resolve(process.cwd(), ".next", "static"), + path.resolve(dstDir, ".next", "static") +); +copyDirIfExists(path.resolve(process.cwd(), "public"), path.resolve(dstDir, "public")); diff --git a/src/app/[locale]/dashboard/_components/bento/statistics-chart-card.tsx b/src/app/[locale]/dashboard/_components/bento/statistics-chart-card.tsx index 35c7ee3f6..0d67f4b42 100644 --- a/src/app/[locale]/dashboard/_components/bento/statistics-chart-card.tsx +++ b/src/app/[locale]/dashboard/_components/bento/statistics-chart-card.tsx @@ -168,7 +168,12 @@ export function StatisticsChartCard({ }; return ( - + {/* Header */}
diff --git a/src/app/[locale]/dashboard/_components/dashboard-main.tsx b/src/app/[locale]/dashboard/_components/dashboard-main.tsx index 43de60b5e..4c67a41d8 100644 --- a/src/app/[locale]/dashboard/_components/dashboard-main.tsx +++ b/src/app/[locale]/dashboard/_components/dashboard-main.tsx @@ -20,7 +20,11 @@ export function DashboardMain({ children }: DashboardMainProps) { normalizedPathname.includes("/dashboard/sessions/") && normalizedPathname.endsWith("/messages"); if (isSessionMessagesPage) { - return
{children}
; + return ( +
+ {children} +
+ ); } return
{children}
; diff --git a/src/app/[locale]/dashboard/_components/user/add-key-dialog.tsx b/src/app/[locale]/dashboard/_components/user/add-key-dialog.tsx index f1afa32db..746c412d8 100644 --- a/src/app/[locale]/dashboard/_components/user/add-key-dialog.tsx +++ b/src/app/[locale]/dashboard/_components/user/add-key-dialog.tsx @@ -70,7 +70,7 @@ export function AddKeyDialog({ return ( - + {generatedKey ? ( <> diff --git a/src/app/[locale]/dashboard/_components/user/add-user-dialog.tsx b/src/app/[locale]/dashboard/_components/user/add-user-dialog.tsx index c91c1fa74..168560aec 100644 --- a/src/app/[locale]/dashboard/_components/user/add-user-dialog.tsx +++ b/src/app/[locale]/dashboard/_components/user/add-user-dialog.tsx @@ -34,7 +34,7 @@ export function AddUserDialog({ {t("addUser")} - + setOpen(false)} currentUser={currentUser} /> diff --git a/src/app/[locale]/dashboard/_components/user/batch-edit/batch-edit-dialog.tsx b/src/app/[locale]/dashboard/_components/user/batch-edit/batch-edit-dialog.tsx index 22f7e2667..d466a2dde 100644 --- a/src/app/[locale]/dashboard/_components/user/batch-edit/batch-edit-dialog.tsx +++ b/src/app/[locale]/dashboard/_components/user/batch-edit/batch-edit-dialog.tsx @@ -443,7 +443,7 @@ function BatchEditDialogInner({ -
+
{selectedUsersCount > 0 ? ( +
diff --git a/src/app/[locale]/dashboard/_components/user/edit-key-dialog.tsx b/src/app/[locale]/dashboard/_components/user/edit-key-dialog.tsx index ea543338f..0a9d6827d 100644 --- a/src/app/[locale]/dashboard/_components/user/edit-key-dialog.tsx +++ b/src/app/[locale]/dashboard/_components/user/edit-key-dialog.tsx @@ -52,7 +52,7 @@ export function EditKeyDialog({ return ( - + {t("title")} {t("description")} diff --git a/src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx b/src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx index 2a73c239b..5a0fcf9bb 100644 --- a/src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx +++ b/src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx @@ -244,7 +244,7 @@ function EditUserDialogInner({ onOpenChange, user, onSuccess }: EditUserDialogPr }; return ( - +
diff --git a/src/app/[locale]/dashboard/_components/user/key-actions.tsx b/src/app/[locale]/dashboard/_components/user/key-actions.tsx index 610ae7b65..ade599c7c 100644 --- a/src/app/[locale]/dashboard/_components/user/key-actions.tsx +++ b/src/app/[locale]/dashboard/_components/user/key-actions.tsx @@ -50,7 +50,7 @@ export function KeyActions({ - + - + setOpenDelete(false)} /> diff --git a/src/app/[locale]/dashboard/_components/user/key-list-header.tsx b/src/app/[locale]/dashboard/_components/user/key-list-header.tsx index 84efc15b1..f40ffce9e 100644 --- a/src/app/[locale]/dashboard/_components/user/key-list-header.tsx +++ b/src/app/[locale]/dashboard/_components/user/key-list-header.tsx @@ -27,6 +27,15 @@ import { UserActions } from "./user-actions"; const PROXY_STATUS_REFRESH_INTERVAL = 2000; +type UserStatusCode = "disabled" | "expired" | "expiringSoon" | "active"; + +const USER_STATUS_LABEL_KEYS: Record = { + disabled: "userStatus.disabled", + expired: "userStatus.expired", + expiringSoon: "userStatus.expiringSoon", + active: "userStatus.active", +}; + async function fetchProxyStatus(): Promise { const result = await getProxyStatus(); if (result.ok) { @@ -123,19 +132,18 @@ export function KeyListHeader({ const exp = activeUser.expiresAt ? new Date(activeUser.expiresAt).getTime() : null; let status: { - code: string; - badge: string; + code: UserStatusCode; variant: "default" | "secondary" | "destructive" | "outline"; }; if (!activeUser.isEnabled) { - status = { code: "disabled", badge: "已禁用", variant: "secondary" }; + status = { code: "disabled", variant: "secondary" }; } else if (exp && exp <= now) { - status = { code: "expired", badge: "已过期", variant: "destructive" }; + status = { code: "expired", variant: "destructive" }; } else if (exp && exp - now <= 72 * 60 * 60 * 1000) { - status = { code: "expiringSoon", badge: "即将过期", variant: "outline" }; + status = { code: "expiringSoon", variant: "outline" }; } else { - status = { code: "active", badge: "已启用", variant: "default" }; + status = { code: "active", variant: "default" }; } const expiryText = activeUser.expiresAt @@ -255,7 +263,7 @@ export function KeyListHeader({ {activeUser ? activeUser.name : "-"} {activeUser && userStatusInfo && ( - {userStatusInfo.status.badge} + {t(USER_STATUS_LABEL_KEYS[userStatusInfo.status.code])} )} {activeUser && } @@ -318,7 +326,7 @@ export function KeyListHeader({ {t("addKey")} - + - + setOpenEdit(false)} currentUser={currentUser} /> diff --git a/src/app/[locale]/dashboard/_components/user/user-list.tsx b/src/app/[locale]/dashboard/_components/user/user-list.tsx index fa6da22d2..cb64c5bd6 100644 --- a/src/app/[locale]/dashboard/_components/user/user-list.tsx +++ b/src/app/[locale]/dashboard/_components/user/user-list.tsx @@ -388,7 +388,7 @@ export function UserList({ users, activeUserId, onUserSelect, currentUser }: Use if (!open) setEditUser(null); }} > - + {editUser ? ( +
{children} diff --git a/src/app/[locale]/dashboard/logs/_components/usage-logs-view-virtualized.tsx b/src/app/[locale]/dashboard/logs/_components/usage-logs-view-virtualized.tsx index 1d64e0e61..ffaadca05 100644 --- a/src/app/[locale]/dashboard/logs/_components/usage-logs-view-virtualized.tsx +++ b/src/app/[locale]/dashboard/logs/_components/usage-logs-view-virtualized.tsx @@ -476,7 +476,7 @@ function UsageLogsViewContent({ hideStatusBar={true} hideScrollToTop={true} hiddenColumns={hideProviderColumn ? ["provider"] : undefined} - bodyClassName="h-[calc(100vh-56px-32px-40px)]" + bodyClassName="h-[calc(var(--cch-viewport-height,100vh)_-_56px_-_32px_-_40px)]" />
diff --git a/src/app/[locale]/dashboard/quotas/keys/_components/edit-key-quota-dialog.tsx b/src/app/[locale]/dashboard/quotas/keys/_components/edit-key-quota-dialog.tsx index abe61ebbc..1d8335c46 100644 --- a/src/app/[locale]/dashboard/quotas/keys/_components/edit-key-quota-dialog.tsx +++ b/src/app/[locale]/dashboard/quotas/keys/_components/edit-key-quota-dialog.tsx @@ -149,7 +149,7 @@ export function EditKeyQuotaDialog({ )} - + {t("title")} {t("description", { keyName, userName })} diff --git a/src/app/[locale]/dashboard/quotas/keys/_components/edit-user-quota-dialog.tsx b/src/app/[locale]/dashboard/quotas/keys/_components/edit-user-quota-dialog.tsx index be54a92d0..3967c2f97 100644 --- a/src/app/[locale]/dashboard/quotas/keys/_components/edit-user-quota-dialog.tsx +++ b/src/app/[locale]/dashboard/quotas/keys/_components/edit-user-quota-dialog.tsx @@ -87,7 +87,7 @@ export function EditUserQuotaDialog({ )} - + {t("title")} {t("description", { userName })} diff --git a/src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-details-tabs.tsx b/src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-details-tabs.tsx index 25654969b..6cd4b0fcd 100644 --- a/src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-details-tabs.tsx +++ b/src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-details-tabs.tsx @@ -68,7 +68,7 @@ export function SessionMessagesDetailsTabs({ isResponseCopied, }: SessionMessagesDetailsTabsProps) { const t = useTranslations("dashboard.sessions"); - const codeExpandedMaxHeight = "calc(100vh - 260px)"; + const codeExpandedMaxHeight = "calc(var(--cch-viewport-height, 100vh) - 260px)"; // 后端已根据 STORE_SESSION_MESSAGES 配置进行脱敏,前端直接显示 const requestBodyContent = useMemo(() => { diff --git a/src/app/[locale]/dashboard/sessions/_components/session-messages-dialog.tsx b/src/app/[locale]/dashboard/sessions/_components/session-messages-dialog.tsx index b26143ee4..d5cae7334 100644 --- a/src/app/[locale]/dashboard/sessions/_components/session-messages-dialog.tsx +++ b/src/app/[locale]/dashboard/sessions/_components/session-messages-dialog.tsx @@ -67,7 +67,7 @@ export function SessionMessagesDialog({ sessionId }: SessionMessagesDialogProps) {t("actions.view")} - + {t("details.title")} {sessionId} diff --git a/src/app/[locale]/internal/dashboard/big-screen/loading.tsx b/src/app/[locale]/internal/dashboard/big-screen/loading.tsx index 33e7040e9..60947d22e 100644 --- a/src/app/[locale]/internal/dashboard/big-screen/loading.tsx +++ b/src/app/[locale]/internal/dashboard/big-screen/loading.tsx @@ -3,7 +3,7 @@ import { Skeleton } from "@/components/ui/skeleton"; export default function BigScreenLoading() { return ( -
+
{Array.from({ length: 4 }).map((_, index) => ( diff --git a/src/app/[locale]/internal/dashboard/big-screen/page.tsx b/src/app/[locale]/internal/dashboard/big-screen/page.tsx index 2d0dab8ee..1036f01c0 100644 --- a/src/app/[locale]/internal/dashboard/big-screen/page.tsx +++ b/src/app/[locale]/internal/dashboard/big-screen/page.tsx @@ -606,7 +606,10 @@ const TrafficTrend = ({ }} itemStyle={{ color: "#fff" }} labelFormatter={(value) => `${value}:00`} - formatter={(value) => [`${value ?? 0} 请求`, "数量"]} + formatter={(value) => [ + `${value ?? 0} ${t("chart.requestUnit")}`, + t("chart.countLabel"), + ]} /> @@ -815,7 +818,7 @@ export default function BigScreenPage() { - + {t("errorRules.dialog.addTitle")} diff --git a/src/app/[locale]/settings/error-rules/_components/edit-rule-dialog.tsx b/src/app/[locale]/settings/error-rules/_components/edit-rule-dialog.tsx index c171215b4..6b28b099d 100644 --- a/src/app/[locale]/settings/error-rules/_components/edit-rule-dialog.tsx +++ b/src/app/[locale]/settings/error-rules/_components/edit-rule-dialog.tsx @@ -139,7 +139,7 @@ export function EditRuleDialog({ rule, open, onOpenChange }: EditRuleDialogProps return ( - + {t("errorRules.dialog.editTitle")} diff --git a/src/app/[locale]/settings/layout.tsx b/src/app/[locale]/settings/layout.tsx index 55a633e56..034e072dd 100644 --- a/src/app/[locale]/settings/layout.tsx +++ b/src/app/[locale]/settings/layout.tsx @@ -31,7 +31,7 @@ export default async function SettingsLayout({ const translatedNavItems = await getTranslatedNavItems(); return ( -
+
diff --git a/src/app/[locale]/settings/notifications/_components/binding-selector.tsx b/src/app/[locale]/settings/notifications/_components/binding-selector.tsx index f6ed4a2a4..e7bb8eb43 100644 --- a/src/app/[locale]/settings/notifications/_components/binding-selector.tsx +++ b/src/app/[locale]/settings/notifications/_components/binding-selector.tsx @@ -336,7 +336,7 @@ export function BindingSelector({ type, targets, bindings, onSave }: BindingSele open={templateDialogOpen} onOpenChange={(open) => (open ? setTemplateDialogOpen(true) : closeTemplateDialog())} > - + {t("notifications.bindings.templateOverrideTitle")} diff --git a/src/app/[locale]/settings/notifications/_components/webhook-target-dialog.tsx b/src/app/[locale]/settings/notifications/_components/webhook-target-dialog.tsx index 5fcbb7a30..2932da38e 100644 --- a/src/app/[locale]/settings/notifications/_components/webhook-target-dialog.tsx +++ b/src/app/[locale]/settings/notifications/_components/webhook-target-dialog.tsx @@ -228,7 +228,7 @@ export function WebhookTargetDialog({ return ( - + {mode === "create" diff --git a/src/app/[locale]/settings/prices/_components/sync-conflict-dialog.tsx b/src/app/[locale]/settings/prices/_components/sync-conflict-dialog.tsx index 2940ba240..ecda7790f 100644 --- a/src/app/[locale]/settings/prices/_components/sync-conflict-dialog.tsx +++ b/src/app/[locale]/settings/prices/_components/sync-conflict-dialog.tsx @@ -251,7 +251,7 @@ export function SyncConflictDialog({ return ( - + diff --git a/src/app/[locale]/settings/providers/_components/adaptive-thinking-editor.tsx b/src/app/[locale]/settings/providers/_components/adaptive-thinking-editor.tsx index f7537553c..bbae95bc4 100644 --- a/src/app/[locale]/settings/providers/_components/adaptive-thinking-editor.tsx +++ b/src/app/[locale]/settings/providers/_components/adaptive-thinking-editor.tsx @@ -81,7 +81,7 @@ export function AdaptiveThinkingEditor({ } disabled={disabled} > - + @@ -118,7 +118,7 @@ export function AdaptiveThinkingEditor({ } disabled={disabled} > - + diff --git a/src/app/[locale]/settings/providers/_components/add-provider-dialog.tsx b/src/app/[locale]/settings/providers/_components/add-provider-dialog.tsx index 917d30a05..f11ab9676 100644 --- a/src/app/[locale]/settings/providers/_components/add-provider-dialog.tsx +++ b/src/app/[locale]/settings/providers/_components/add-provider-dialog.tsx @@ -22,7 +22,7 @@ export function AddProviderDialog({ enableMultiProviderTypes }: AddProviderDialo {t("addProvider")} - + {t("addProvider")} diff --git a/src/app/[locale]/settings/providers/_components/auto-sort-priority-dialog.tsx b/src/app/[locale]/settings/providers/_components/auto-sort-priority-dialog.tsx index eaebd4992..13b2d9db6 100644 --- a/src/app/[locale]/settings/providers/_components/auto-sort-priority-dialog.tsx +++ b/src/app/[locale]/settings/providers/_components/auto-sort-priority-dialog.tsx @@ -136,7 +136,7 @@ export function AutoSortPriorityDialog() { {t("button")} - + {t("dialogTitle")} {t("dialogDescription")} diff --git a/src/app/[locale]/settings/providers/_components/batch-edit/provider-batch-dialog.tsx b/src/app/[locale]/settings/providers/_components/batch-edit/provider-batch-dialog.tsx index f55ac2ae7..6920c1888 100644 --- a/src/app/[locale]/settings/providers/_components/batch-edit/provider-batch-dialog.tsx +++ b/src/app/[locale]/settings/providers/_components/batch-edit/provider-batch-dialog.tsx @@ -119,7 +119,7 @@ function BatchEditDialog({ return ( - + {/* Provider groups */} -
+
{grouped.map((group) => { const excluded = excludedProviderIds.has(group.providerId); return ( @@ -148,8 +148,8 @@ export function ProviderBatchPreviewStep({ {row.status === "changed" ? t("preview.fieldChanged", { field: getFieldLabel(row.field), - before: formatValue(row.before), - after: formatValue(row.after), + before: formatValue(row.before, t), + after: formatValue(row.after, t), }) : t("preview.fieldSkipped", { field: getFieldLabel(row.field), @@ -170,8 +170,8 @@ export function ProviderBatchPreviewStep({ // Helpers // --------------------------------------------------------------------------- -function formatValue(value: unknown): string { - if (value === null || value === undefined) return "null"; +function formatValue(value: unknown, t: (key: string) => string): string { + if (value === null || value === undefined) return t("preview.nullValue"); if (typeof value === "boolean") return String(value); if (typeof value === "number") return String(value); if (typeof value === "string") return value; diff --git a/src/app/[locale]/settings/providers/_components/forms/provider-form/components/form-tab-nav.tsx b/src/app/[locale]/settings/providers/_components/forms/provider-form/components/form-tab-nav.tsx index f0af08497..6f4a51f23 100644 --- a/src/app/[locale]/settings/providers/_components/forms/provider-form/components/form-tab-nav.tsx +++ b/src/app/[locale]/settings/providers/_components/forms/provider-form/components/form-tab-nav.tsx @@ -42,6 +42,10 @@ export function FormTabNav({ } }; + const activeTabIndex = TAB_CONFIG.findIndex((tab) => tab.id === activeTab); + const stepNumber = activeTabIndex >= 0 ? activeTabIndex + 1 : 0; + const stepProgressWidth = `${(stepNumber / TAB_CONFIG.length) * 100}%`; + if (layout === "horizontal") { return ( {/* Mobile: Bottom Navigation */} -