Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
8a10dedb
authored
May 16, 2026
by
yyhhyyyyyy
Committed by
GitHub
May 16, 2026
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(web): handle unlimited API key quota validation (#4881)
parent
554defe4
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
59 additions
and
18 deletions
+59
-18
web/default/src/features/keys/components/api-keys-mutate-drawer.tsx
+9
-4
web/default/src/features/keys/lib/api-key-form.ts
+37
-13
web/default/src/features/keys/lib/index.ts
+1
-1
web/default/src/i18n/locales/en.json
+2
-0
web/default/src/i18n/locales/fr.json
+2
-0
web/default/src/i18n/locales/ja.json
+2
-0
web/default/src/i18n/locales/ru.json
+2
-0
web/default/src/i18n/locales/vi.json
+2
-0
web/default/src/i18n/locales/zh.json
+2
-0
No files found.
web/default/src/features/keys/components/api-keys-mutate-drawer.tsx
View file @
8a10dedb
...
...
@@ -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
{
...
...
@@ -65,7 +65,7 @@ import { MultiSelect } from '@/components/multi-select'
import
{
createApiKey
,
updateApiKey
,
getApiKey
}
from
'../api'
import
{
ERROR_MESSAGES
,
SUCCESS_MESSAGES
}
from
'../constants'
import
{
a
piKeyFormSchema
,
getA
piKeyFormSchema
,
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
<
ApiKeyFormValues
>
({
resolver
:
zodResolver
(
apiKeyFormS
chema
),
resolver
:
zodResolver
(
s
chema
),
defaultValues
:
getApiKeyFormDefaultValues
(
defaultUseAutoGroup
),
})
...
...
@@ -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
)
...
...
@@ -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
...
...
web/default/src/features/keys/lib/api-key-form.ts
View file @
8a10dedb
...
...
@@ -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'
...
...
@@ -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
...
...
@@ -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
)
...
...
web/default/src/features/keys/lib/index.ts
View file @
8a10dedb
...
...
@@ -20,7 +20,7 @@ For commercial licensing, please contact support@quantumnous.com
// Form Utilities
// ============================================================================
export
{
a
piKeyFormSchema
,
getA
piKeyFormSchema
,
type
ApiKeyFormValues
,
API_KEY_FORM_DEFAULT_VALUES
,
getApiKeyFormDefaultValues
,
...
...
web/default/src/i18n/locales/en.json
View file @
8a10dedb
...
...
@@ -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"
,
...
...
web/default/src/i18n/locales/fr.json
View file @
8a10dedb
...
...
@@ -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"
,
...
...
web/default/src/i18n/locales/ja.json
View file @
8a10dedb
...
...
@@ -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"
:
"クォータリセット"
,
...
...
web/default/src/i18n/locales/ru.json
View file @
8a10dedb
...
...
@@ -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"
:
"Сброс квоты"
,
...
...
web/default/src/i18n/locales/vi.json
View file @
8a10dedb
...
...
@@ -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"
,
...
...
web/default/src/i18n/locales/zh.json
View file @
8a10dedb
...
...
@@ -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"
:
"额度重置"
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment