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
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -152,9 +152,10 @@ export function ApiKeysMutateDrawer({
})
)
const backendHasAuto = groups.some((g) => g.value === 'auto')
const schema = getApiKeyFormSchema(t)

const form = useForm<ApiKeyFormValues>({
resolver: zodResolver(apiKeyFormSchema),
resolver: zodResolver(schema),
defaultValues: getApiKeyFormDefaultValues(defaultUseAutoGroup),
})

Expand Down Expand Up @@ -239,6 +240,10 @@ export function ApiKeysMutateDrawer({
}
}

const onInvalid: SubmitErrorHandler<ApiKeyFormValues> = () => {
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)
Expand Down Expand Up @@ -291,7 +296,7 @@ export function ApiKeysMutateDrawer({
<Form {...form}>
<form
id='api-key-form'
onSubmit={form.handleSubmit(onSubmit)}
onSubmit={form.handleSubmit(onSubmit, onInvalid)}
className='min-h-0 flex-1 space-y-3 overflow-y-auto overscroll-contain px-3 py-3 sm:space-y-4 sm:px-4 sm:py-4'
>
<ApiKeyFormSection
Expand Down
50 changes: 37 additions & 13 deletions web/default/src/features/keys/lib/api-key-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
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'
Expand All @@ -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<typeof apiKeyFormSchema>
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<typeof getApiKeyFormSchema>
>

// ============================================================================
// Form Defaults
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion web/default/src/features/keys/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions web/default/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions web/default/src/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions web/default/src/i18n/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "コンテナを選択してください",
Expand Down Expand Up @@ -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": "クォータリセット",
Expand Down
2 changes: 2 additions & 0 deletions web/default/src/i18n/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "Пожалуйста, выберите контейнер",
Expand Down Expand Up @@ -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": "Сброс квоты",
Expand Down
2 changes: 2 additions & 0 deletions web/default/src/i18n/locales/vi.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions web/default/src/i18n/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "请选择一个容器",
Expand Down Expand Up @@ -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": "额度重置",
Expand Down