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
3 changes: 3 additions & 0 deletions messages/en/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@
"keys": "Key Rankings",
"userRanking": "User Rankings",
"providerRanking": "Provider Rankings",
"providerCacheHitRateRanking": "Provider Cache Hit Rate",
"modelRanking": "Model Rankings",
"dailyRanking": "Today",
"weeklyRanking": "This Week",
Expand All @@ -266,6 +267,7 @@
"provider": "Provider",
"model": "Model",
"cost": "Cost",
"cacheHitRate": "Cache Hit Rate",
"successRate": "Success Rate",
"avgResponseTime": "Avg Response Time"
},
Expand Down Expand Up @@ -1120,6 +1122,7 @@
"note": "Note",
"tags": "Tags",
"limit5h": "5h Limit (USD)",
"limitDaily": "Daily Limit (USD)",
"limitWeekly": "Weekly Limit (USD)",
"limitMonthly": "Monthly Limit (USD)"
},
Expand Down
3 changes: 3 additions & 0 deletions messages/ja/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@
"keys": "キー ランキング",
"userRanking": "ユーザーランキング",
"providerRanking": "プロバイダーランキング",
"providerCacheHitRateRanking": "プロバイダーキャッシュ命中率",
"modelRanking": "モデルランキング",
"dailyRanking": "今日",
"weeklyRanking": "今週",
Expand All @@ -265,6 +266,7 @@
"provider": "プロバイダー",
"model": "モデル",
"cost": "コスト",
"cacheHitRate": "キャッシュ命中率",
"successRate": "成功率",
"avgResponseTime": "平均応答時間"
},
Expand Down Expand Up @@ -1081,6 +1083,7 @@
"note": "メモ",
"tags": "タグ",
"limit5h": "5時間上限 (USD)",
"limitDaily": "日次上限 (USD)",
"limitWeekly": "週間上限 (USD)",
"limitMonthly": "月間上限 (USD)"
},
Expand Down
3 changes: 3 additions & 0 deletions messages/ru/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@
"keys": "Рейтинг ключей",
"userRanking": "Рейтинг пользователей",
"providerRanking": "Рейтинг поставщиков",
"providerCacheHitRateRanking": "Рейтинг по попаданиям в кэш",
"modelRanking": "Рейтинг моделей",
"dailyRanking": "Сегодня",
"weeklyRanking": "Эта неделя",
Expand All @@ -265,6 +266,7 @@
"provider": "Поставщик",
"model": "Модель",
"cost": "Стоимость",
"cacheHitRate": "Попадания в кэш",
"successRate": "Процент успеха",
"avgResponseTime": "Среднее время ответа"
},
Expand Down Expand Up @@ -1092,6 +1094,7 @@
"note": "Заметка",
"tags": "Теги",
"limit5h": "Лимит за 5 часов (USD)",
"limitDaily": "Дневной лимит (USD)",
"limitWeekly": "Недельный лимит (USD)",
"limitMonthly": "Месячный лимит (USD)"
},
Expand Down
27 changes: 15 additions & 12 deletions messages/zh-CN/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -239,12 +239,13 @@
"users": "用户排行",
"keys": "密钥排行",
"userRanking": "用户排行",
"providerRanking": "供应商排行",
"modelRanking": "模型排行",
"dailyRanking": "今日",
"weeklyRanking": "本周",
"monthlyRanking": "本月",
"allTimeRanking": "全部"
"providerRanking": "供应商排行",
"providerCacheHitRateRanking": "供应商缓存命中率排行",
"modelRanking": "模型排行",
"dailyRanking": "今日",
"weeklyRanking": "本周",
"monthlyRanking": "本月",
"allTimeRanking": "全部"
Comment on lines +242 to +248
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The indentation in this block has changed from 6 spaces to 4 spaces. While this isn't a functional issue, it creates noise in the diff and suggests inconsistent formatting practices. Please ensure consistent formatting is applied across the file and project to improve readability and maintainability. It seems other JSON files in this PR also have similar indentation changes. It would be best to either format all files consistently or revert the unrelated formatting changes.

},
"dateRange": {
"to": "至",
Expand All @@ -263,12 +264,13 @@
"requests": "请求数",
"tokens": "Token 数",
"consumedAmount": "消耗金额",
"provider": "供应商",
"model": "模型",
"cost": "成本",
"successRate": "成功率",
"avgResponseTime": "平均响应时间"
},
"provider": "供应商",
"model": "模型",
"cost": "成本",
"cacheHitRate": "缓存命中率",
"successRate": "成功率",
"avgResponseTime": "平均响应时间"
},
"states": {
"loading": "加载中...",
"noData": "暂无数据",
Expand Down Expand Up @@ -1186,6 +1188,7 @@
"note": "备注",
"tags": "标签",
"limit5h": "5h 限额 (USD)",
"limitDaily": "每日限额 (USD)",
"limitWeekly": "周限额 (USD)",
"limitMonthly": "月限额 (USD)"
},
Expand Down
3 changes: 3 additions & 0 deletions messages/zh-TW/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@
"keys": "密鑰排名",
"userRanking": "使用者排名",
"providerRanking": "供應商排名",
"providerCacheHitRateRanking": "供應商快取命中率排行",
"modelRanking": "模型排名",
"dailyRanking": "今日",
"weeklyRanking": "本週",
Expand All @@ -266,6 +267,7 @@
"provider": "供應商",
"model": "模型",
"cost": "成本",
"cacheHitRate": "快取命中率",
"successRate": "成功率",
"avgResponseTime": "平均回覆時間"
},
Expand Down Expand Up @@ -1093,6 +1095,7 @@
"note": "備註",
"tags": "標籤",
"limit5h": "5h 限額 (USD)",
"limitDaily": "每日限額 (USD)",
"limitWeekly": "週限額 (USD)",
"limitMonthly": "月限額 (USD)"
},
Expand Down
5 changes: 5 additions & 0 deletions src/actions/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export interface BatchUpdateUsersParams {
updates: {
note?: string;
tags?: string[];
dailyQuota?: number | null;
limit5hUsd?: number | null;
limitWeeklyUsd?: number | null;
limitMonthlyUsd?: number | null;
Expand Down Expand Up @@ -485,6 +486,7 @@ export async function batchUpdateUsers(
const updatesSchema = UpdateUserSchema.pick({
note: true,
tags: true,
dailyQuota: true,
limit5hUsd: true,
limitWeeklyUsd: true,
limitMonthlyUsd: true,
Expand Down Expand Up @@ -526,6 +528,9 @@ export async function batchUpdateUsers(

if (updates.note !== undefined) dbUpdates.description = updates.note;
if (updates.tags !== undefined) dbUpdates.tags = updates.tags;
if (updates.dailyQuota !== undefined)
dbUpdates.dailyLimitUsd =
updates.dailyQuota === null ? null : updates.dailyQuota.toString();
if (updates.limit5hUsd !== undefined)
dbUpdates.limit5hUsd = updates.limit5hUsd === null ? null : updates.limit5hUsd.toString();
if (updates.limitWeeklyUsd !== undefined)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type UserFieldLabels = {
note: string;
tags: string;
limit5h: string;
limitDaily: string;
limitWeekly: string;
limitMonthly: string;
};
Expand All @@ -68,6 +69,8 @@ const INITIAL_USER_STATE: BatchUserSectionState = {
tags: [],
limit5hUsdEnabled: false,
limit5hUsd: "",
dailyQuotaEnabled: false,
dailyQuota: "",
limitWeeklyUsdEnabled: false,
limitWeeklyUsd: "",
limitMonthlyUsdEnabled: false,
Expand Down Expand Up @@ -126,6 +129,10 @@ function buildUserUpdates(
updates.limit5hUsd = parseNumberOrNull(state.limit5hUsd, args.validationMessages);
enabledFields.push(args.fieldLabels.limit5h);
}
if (state.dailyQuotaEnabled) {
updates.dailyQuota = parseNumberOrNull(state.dailyQuota, args.validationMessages);
enabledFields.push(args.fieldLabels.limitDaily);
}
if (state.limitWeeklyUsdEnabled) {
updates.limitWeeklyUsd = parseNumberOrNull(state.limitWeeklyUsd, args.validationMessages);
enabledFields.push(args.fieldLabels.limitWeekly);
Expand Down Expand Up @@ -223,6 +230,7 @@ function BatchEditDialogInner({
note: t("user.fields.note"),
tags: t("user.fields.tags"),
limit5h: t("user.fields.limit5h"),
limitDaily: t("user.fields.limitDaily"),
limitWeekly: t("user.fields.limitWeekly"),
limitMonthly: t("user.fields.limitMonthly"),
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export interface BatchUserSectionState {
tags: string[];
limit5hUsdEnabled: boolean;
limit5hUsd: string;
dailyQuotaEnabled: boolean;
dailyQuota: string;
limitWeeklyUsdEnabled: boolean;
limitWeeklyUsd: string;
limitMonthlyUsdEnabled: boolean;
Expand All @@ -30,6 +32,7 @@ export interface BatchUserSectionProps {
note: string;
tags: string;
limit5h: string;
limitDaily: string;
limitWeekly: string;
limitMonthly: string;
};
Expand Down Expand Up @@ -101,6 +104,22 @@ export function BatchUserSection({
/>
</FieldCard>

<FieldCard
title={translations.fields.limitDaily}
enabled={state.dailyQuotaEnabled}
onEnabledChange={(enabled) => onChange({ dailyQuotaEnabled: enabled })}
enableFieldAria={translations.enableFieldAria}
>
<Input
type="number"
inputMode="decimal"
value={state.dailyQuota}
onChange={(e) => onChange({ dailyQuota: e.target.value })}
disabled={!state.dailyQuotaEnabled}
placeholder={translations.placeholders.emptyNoLimit}
/>
</FieldCard>

<FieldCard
title={translations.fields.limitWeekly}
enabled={state.limitWeeklyUsdEnabled}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,16 @@ export function KeyEditSection({
() => normalizeGroupList(keyData.providerGroup),
[keyData.providerGroup]
);
const keyGroupOptions = useMemo(() => {
if (!normalizedKeyProviderGroup) return [];
return normalizedKeyProviderGroup.split(",").filter(Boolean);
}, [normalizedKeyProviderGroup]);
const extraKeyGroupOption = useMemo(() => {
if (!normalizedKeyProviderGroup) return null;
if (normalizedKeyProviderGroup === normalizedUserProviderGroup) return null;
if (userGroups.includes(normalizedKeyProviderGroup)) return null;
return normalizedKeyProviderGroup;
}, [normalizedKeyProviderGroup, normalizedUserProviderGroup, userGroups]);

return (
<div ref={scrollRef} className="space-y-3 scroll-mt-24">
Expand Down Expand Up @@ -424,6 +434,17 @@ export function KeyEditSection({
<SelectValue placeholder={translations.fields.providerGroup.placeholder} />
</SelectTrigger>
<SelectContent>
{extraKeyGroupOption ? (
<SelectItem value={extraKeyGroupOption}>
<Badge
variant="secondary"
className="text-xs font-mono max-w-[280px] truncate"
title={extraKeyGroupOption}
>
{extraKeyGroupOption}
</Badge>
</SelectItem>
) : null}
{userGroups.map((group) => (
<SelectItem key={group} value={group}>
<Badge variant="outline" className="text-xs">
Expand All @@ -444,6 +465,25 @@ export function KeyEditSection({
: translations.fields.providerGroup.selectHint || "选择此 Key 可使用的供应商分组"}
</p>
</div>
) : keyGroupOptions.length > 0 ? (
<div className="space-y-2">
<Label>{translations.fields.providerGroup.label}</Label>
<div className="flex flex-wrap gap-2">
{keyGroupOptions.map((group) => (
<Badge
key={group}
variant="secondary"
className="text-xs font-mono max-w-[280px] truncate"
title={group}
>
{group}
</Badge>
))}
</div>
<p className="text-xs text-muted-foreground">
{translations.fields.providerGroup.editHint || "已有密钥的分组不可修改"}
</p>
</div>
) : (
<div className="text-sm text-muted-foreground">
{translations.fields.providerGroup.noGroupHint || "您没有分组限制,可以访问所有供应商"}
Expand Down
Loading
Loading