diff --git a/web/default/src/features/keys/components/api-keys-mutate-drawer.tsx b/web/default/src/features/keys/components/api-keys-mutate-drawer.tsx index ed128e574b3..e3f8d55646f 100644 --- a/web/default/src/features/keys/components/api-keys-mutate-drawer.tsx +++ b/web/default/src/features/keys/components/api-keys-mutate-drawer.tsx @@ -17,7 +17,7 @@ along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import { useEffect, useState, type ReactNode } from 'react' -import { useForm } from 'react-hook-form' +import { useForm, type SubmitErrorHandler } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { useQuery } from '@tanstack/react-query' import { @@ -65,7 +65,7 @@ import { MultiSelect } from '@/components/multi-select' import { createApiKey, updateApiKey, getApiKey } from '../api' import { ERROR_MESSAGES, SUCCESS_MESSAGES } from '../constants' import { - apiKeyFormSchema, + getApiKeyFormSchema, type ApiKeyFormValues, getApiKeyFormDefaultValues, transformFormDataToPayload, @@ -152,9 +152,10 @@ export function ApiKeysMutateDrawer({ }) ) const backendHasAuto = groups.some((g) => g.value === 'auto') + const schema = getApiKeyFormSchema(t) const form = useForm({ - resolver: zodResolver(apiKeyFormSchema), + resolver: zodResolver(schema), defaultValues: getApiKeyFormDefaultValues(defaultUseAutoGroup), }) @@ -239,6 +240,10 @@ export function ApiKeysMutateDrawer({ } } + const onInvalid: SubmitErrorHandler = () => { + toast.error(t('Please fix the highlighted fields before saving')) + } + const handleSetExpiry = (months: number, days: number, hours: number) => { if (months === 0 && days === 0 && hours === 0) { form.setValue('expired_time', undefined) @@ -291,7 +296,7 @@ export function ApiKeysMutateDrawer({
. For commercial licensing, please contact support@quantumnous.com */ import { z } from 'zod' +import type { TFunction } from 'i18next' import { parseQuotaFromDollars, quotaUnitsToDollars } from '@/lib/format' import { DEFAULT_GROUP } from '../constants' import { type ApiKeyFormData, type ApiKey } from '../types' @@ -25,19 +26,40 @@ import { type ApiKeyFormData, type ApiKey } from '../types' // Form Schema // ============================================================================ -export const apiKeyFormSchema = z.object({ - name: z.string().min(1, 'Name is required'), - remain_quota_dollars: z.number().min(0).optional(), - expired_time: z.date().optional(), - unlimited_quota: z.boolean(), - model_limits: z.array(z.string()), - allow_ips: z.string().optional(), - group: z.string().optional(), - cross_group_retry: z.boolean().optional(), - tokenCount: z.number().min(1).optional(), -}) +export function getApiKeyFormSchema(t: TFunction) { + return z + .object({ + name: z.string().min(1, t('Please enter a name')), + remain_quota_dollars: z.number().optional(), + expired_time: z.date().optional(), + unlimited_quota: z.boolean(), + model_limits: z.array(z.string()), + allow_ips: z.string().optional(), + group: z.string().optional(), + cross_group_retry: z.boolean().optional(), + tokenCount: z.number().min(1).optional(), + }) + .superRefine((data, ctx) => { + if (data.unlimited_quota) { + return + } -export type ApiKeyFormValues = z.infer + if ( + data.remain_quota_dollars === undefined || + data.remain_quota_dollars < 0 + ) { + ctx.addIssue({ + code: 'custom', + path: ['remain_quota_dollars'], + message: t('Quota must be zero or greater'), + }) + } + }) +} + +export type ApiKeyFormValues = z.infer< + ReturnType +> // ============================================================================ // Form Defaults @@ -100,7 +122,9 @@ export function transformApiKeyToFormDefaults( ): ApiKeyFormValues { return { name: apiKey.name, - remain_quota_dollars: quotaUnitsToDollars(apiKey.remain_quota), + remain_quota_dollars: apiKey.unlimited_quota + ? 0 + : quotaUnitsToDollars(apiKey.remain_quota), expired_time: apiKey.expired_time > 0 ? new Date(apiKey.expired_time * 1000) diff --git a/web/default/src/features/keys/lib/index.ts b/web/default/src/features/keys/lib/index.ts index 6892ec7579b..4f904acbc55 100644 --- a/web/default/src/features/keys/lib/index.ts +++ b/web/default/src/features/keys/lib/index.ts @@ -20,7 +20,7 @@ For commercial licensing, please contact support@quantumnous.com // Form Utilities // ============================================================================ export { - apiKeyFormSchema, + getApiKeyFormSchema, type ApiKeyFormValues, API_KEY_FORM_DEFAULT_VALUES, getApiKeyFormDefaultValues, diff --git a/web/default/src/i18n/locales/en.json b/web/default/src/i18n/locales/en.json index 7e34ec0a352..a2a8118a9fc 100644 --- a/web/default/src/i18n/locales/en.json +++ b/web/default/src/i18n/locales/en.json @@ -2921,6 +2921,7 @@ "Please enter your verification code": "Please enter your verification code", "Please enter your verification code or backup code": "Please enter your verification code or backup code", "Please fix JSON errors before saving": "Please fix JSON errors before saving", + "Please fix the highlighted fields before saving": "Please fix the highlighted fields before saving", "Please log in with the appropriate credentials": "Please log in with the appropriate credentials", "Please manually copy and open the authorization link": "Please manually copy and open the authorization link", "Please select a container": "Please select a container", @@ -3097,6 +3098,7 @@ "Quota given to invited users": "Quota given to invited users", "Quota given to users who invite others": "Quota given to users who invite others", "Quota must be a positive number": "Quota must be a positive number", + "Quota must be zero or greater": "Quota must be zero or greater", "Quota Per Unit": "Quota Per Unit", "Quota reminder (tokens)": "Quota reminder (tokens)", "Quota Reset": "Quota Reset", diff --git a/web/default/src/i18n/locales/fr.json b/web/default/src/i18n/locales/fr.json index 0a682ccbb98..7af7e215a90 100644 --- a/web/default/src/i18n/locales/fr.json +++ b/web/default/src/i18n/locales/fr.json @@ -2921,6 +2921,7 @@ "Please enter your verification code": "Veuillez saisir votre code de vérification", "Please enter your verification code or backup code": "Veuillez saisir votre code de vérification ou votre code de secours", "Please fix JSON errors before saving": "Veuillez corriger les erreurs JSON avant d’enregistrer", + "Please fix the highlighted fields before saving": "Veuillez corriger les champs en surbrillance avant d’enregistrer", "Please log in with the appropriate credentials": "Veuillez vous connecter avec les identifiants appropriés", "Please manually copy and open the authorization link": "Veuillez copier et ouvrir manuellement le lien d'autorisation", "Please select a container": "Veuillez sélectionner un conteneur", @@ -3097,6 +3098,7 @@ "Quota given to invited users": "Quota attribué aux utilisateurs invités", "Quota given to users who invite others": "Quota attribué aux utilisateurs qui invitent d'autres personnes", "Quota must be a positive number": "Le quota doit être un nombre positif", + "Quota must be zero or greater": "Le quota ne peut pas être négatif", "Quota Per Unit": "Quota par unité", "Quota reminder (tokens)": "Rappel de quota (jetons)", "Quota Reset": "Réinitialisation du quota", diff --git a/web/default/src/i18n/locales/ja.json b/web/default/src/i18n/locales/ja.json index bbacbda5a58..9fe97f0d7fc 100644 --- a/web/default/src/i18n/locales/ja.json +++ b/web/default/src/i18n/locales/ja.json @@ -2921,6 +2921,7 @@ "Please enter your verification code": "認証コードを入力してください", "Please enter your verification code or backup code": "認証コードまたはバックアップコードを入力してください", "Please fix JSON errors before saving": "保存する前に JSON エラーを直してください", + "Please fix the highlighted fields before saving": "保存する前に強調表示された項目を修正してください", "Please log in with the appropriate credentials": "適切な認証情報でログインしてください", "Please manually copy and open the authorization link": "認証リンクを手動でコピーして開いてください", "Please select a container": "コンテナを選択してください", @@ -3097,6 +3098,7 @@ "Quota given to invited users": "招待されたユーザーに付与されるクォータ", "Quota given to users who invite others": "他のユーザーを招待したユーザーに付与されるクォータ", "Quota must be a positive number": "クォータは正の数である必要があります", + "Quota must be zero or greater": "クォータは負の値にできません", "Quota Per Unit": "ユニットあたりのクォータ", "Quota reminder (tokens)": "クォータリマインダー (トークン)", "Quota Reset": "クォータリセット", diff --git a/web/default/src/i18n/locales/ru.json b/web/default/src/i18n/locales/ru.json index 2022e562467..261414426e1 100644 --- a/web/default/src/i18n/locales/ru.json +++ b/web/default/src/i18n/locales/ru.json @@ -2921,6 +2921,7 @@ "Please enter your verification code": "Пожалуйста, введите код подтверждения", "Please enter your verification code or backup code": "Пожалуйста, введите код подтверждения или резервный код", "Please fix JSON errors before saving": "Исправьте ошибки JSON перед сохранением", + "Please fix the highlighted fields before saving": "Исправьте выделенные поля перед сохранением", "Please log in with the appropriate credentials": "Пожалуйста, войдите с соответствующими учетными данными", "Please manually copy and open the authorization link": "Скопируйте и откройте ссылку авторизации вручную", "Please select a container": "Пожалуйста, выберите контейнер", @@ -3097,6 +3098,7 @@ "Quota given to invited users": "Квота, предоставляемая приглашенным пользователям", "Quota given to users who invite others": "Квота, предоставляемая пользователям, которые приглашают других", "Quota must be a positive number": "Квота должна быть положительным числом", + "Quota must be zero or greater": "Квота не может быть отрицательной", "Quota Per Unit": "Квота на единицу", "Quota reminder (tokens)": "Напоминание о квоте (токены)", "Quota Reset": "Сброс квоты", diff --git a/web/default/src/i18n/locales/vi.json b/web/default/src/i18n/locales/vi.json index 66f458f31e8..c610bc9eddb 100644 --- a/web/default/src/i18n/locales/vi.json +++ b/web/default/src/i18n/locales/vi.json @@ -2921,6 +2921,7 @@ "Please enter your verification code": "Vui lòng nhập mã xác thực của bạn", "Please enter your verification code or backup code": "Vui lòng nhập mã xác thực hoặc mã dự phòng của bạn", "Please fix JSON errors before saving": "Vui lòng sửa lỗi JSON trước khi lưu", + "Please fix the highlighted fields before saving": "Vui lòng sửa các trường được đánh dấu trước khi lưu", "Please log in with the appropriate credentials": "Vui lòng đăng nhập bằng thông tin xác thực phù hợp", "Please manually copy and open the authorization link": "Vui lòng tự sao chép và mở liên kết ủy quyền", "Please select a container": "Vui lòng chọn một container", @@ -3097,6 +3098,7 @@ "Quota given to invited users": "Hạn mức được cấp cho người dùng được mời", "Quota given to users who invite others": "Limit for users inviting others", "Quota must be a positive number": "Hạn mức phải là một số dương", + "Quota must be zero or greater": "Hạn mức không được âm", "Quota Per Unit": "Định mức mỗi đơn vị", "Quota reminder (tokens)": "Nhắc nhở hạn mức (token)", "Quota Reset": "Đặt lại hạn mức", diff --git a/web/default/src/i18n/locales/zh.json b/web/default/src/i18n/locales/zh.json index 1d2e86754fa..a136144680e 100644 --- a/web/default/src/i18n/locales/zh.json +++ b/web/default/src/i18n/locales/zh.json @@ -2921,6 +2921,7 @@ "Please enter your verification code": "请输入您的验证码", "Please enter your verification code or backup code": "请输入您的验证码或备用码", "Please fix JSON errors before saving": "请先修复 JSON 错误再保存", + "Please fix the highlighted fields before saving": "请先修复高亮字段后再保存", "Please log in with the appropriate credentials": "请使用适当的凭据登录", "Please manually copy and open the authorization link": "请手动复制并打开授权链接", "Please select a container": "请选择一个容器", @@ -3097,6 +3098,7 @@ "Quota given to invited users": "授予被邀请用户的配额", "Quota given to users who invite others": "授予邀请其他用户的配额", "Quota must be a positive number": "配额必须是正数", + "Quota must be zero or greater": "额度不能为负数", "Quota Per Unit": "每单位配额", "Quota reminder (tokens)": "配额提醒(token)", "Quota Reset": "额度重置",