fix: custom apikey

This commit is contained in:
jialin
2026-04-14 20:42:01 +08:00
committed by jialin
parent c667de90ed
commit 46b9855c87
11 changed files with 113 additions and 82 deletions
+4 -2
View File
@@ -19,7 +19,9 @@ export default {
'apikeys.models.selected': 'Allowed models', 'apikeys.models.selected': 'Allowed models',
'apikeys.models.noModelsFound': 'No models found', 'apikeys.models.noModelsFound': 'No models found',
'apikeys.accessScope.all': 'All', 'apikeys.accessScope.all': 'All',
'apikeys.accessScope.management': 'Management APIs', 'apikeys.accessScope.management': 'Platform Management',
'apikeys.accessScope.inference': 'Inference APIs', 'apikeys.accessScope.inference': 'Inference APIs',
'apikeys.access.permissions': 'Access Permissions' 'apikeys.access.permissions': 'Access Permissions',
'apikeys.type.auto': 'Auto-generated',
'apikeys.type.custom': 'Custom'
}; };
+4 -2
View File
@@ -19,9 +19,11 @@ export default {
'apikeys.models.selected': 'Allowed models', 'apikeys.models.selected': 'Allowed models',
'apikeys.models.noModelsFound': 'No models found', 'apikeys.models.noModelsFound': 'No models found',
'apikeys.accessScope.all': 'All', 'apikeys.accessScope.all': 'All',
'apikeys.accessScope.management': 'Management APIs', 'apikeys.accessScope.management': 'Platform Management',
'apikeys.accessScope.inference': 'Inference APIs', 'apikeys.accessScope.inference': 'Inference APIs',
'apikeys.access.permissions': 'Access Permissions' 'apikeys.access.permissions': 'Access Permissions',
'apikeys.type.auto': 'Auto-generated',
'apikeys.type.custom': 'Custom'
}; };
// ========== To-Do: Translate Keys (Remove After Translation) ========== // ========== To-Do: Translate Keys (Remove After Translation) ==========
+4 -2
View File
@@ -19,9 +19,11 @@ export default {
'apikeys.models.selected': 'Разрешенные модели', 'apikeys.models.selected': 'Разрешенные модели',
'apikeys.models.noModelsFound': 'Модели не найдены', 'apikeys.models.noModelsFound': 'Модели не найдены',
'apikeys.accessScope.all': 'All', 'apikeys.accessScope.all': 'All',
'apikeys.accessScope.management': 'Management APIs', 'apikeys.accessScope.management': 'Platform Management',
'apikeys.accessScope.inference': 'Inference APIs', 'apikeys.accessScope.inference': 'Inference APIs',
'apikeys.access.permissions': 'Access Permissions' 'apikeys.access.permissions': 'Access Permissions',
'apikeys.type.auto': 'Auto-generated',
'apikeys.type.custom': 'Custom'
}; };
// ========== To-Do: Translate Keys (Remove After Translation) ========== // ========== To-Do: Translate Keys (Remove After Translation) ==========
+4 -2
View File
@@ -19,7 +19,9 @@ export default {
'apikeys.models.selected': 'İzin verilen modeller', 'apikeys.models.selected': 'İzin verilen modeller',
'apikeys.models.noModelsFound': 'Model bulunamadı', 'apikeys.models.noModelsFound': 'Model bulunamadı',
'apikeys.accessScope.all': 'All', 'apikeys.accessScope.all': 'All',
'apikeys.accessScope.management': 'Management APIs', 'apikeys.accessScope.management': 'Platform Management',
'apikeys.accessScope.inference': 'Inference APIs', 'apikeys.accessScope.inference': 'Inference APIs',
'apikeys.access.permissions': 'Access Permissions' 'apikeys.access.permissions': 'Access Permissions',
'apikeys.type.auto': 'Auto-generated',
'apikeys.type.custom': 'Custom'
}; };
+4 -2
View File
@@ -18,7 +18,9 @@ export default {
'apikeys.models.selected': '指定模型', 'apikeys.models.selected': '指定模型',
'apikeys.models.noModelsFound': '未找到模型', 'apikeys.models.noModelsFound': '未找到模型',
'apikeys.accessScope.all': '全部', 'apikeys.accessScope.all': '全部',
'apikeys.accessScope.management': '管理接口', 'apikeys.accessScope.management': '平台管理',
'apikeys.accessScope.inference': '推理接口', 'apikeys.accessScope.inference': '推理接口',
'apikeys.access.permissions': '访问权限' 'apikeys.access.permissions': '访问权限',
'apikeys.type.auto': '自动生成',
'apikeys.type.custom': '自定义'
}; };
@@ -32,13 +32,12 @@ const AllowModelsForm: React.FC<{
const [modelList, setModelList] = useState<{ key: string; title: string }[]>( const [modelList, setModelList] = useState<{ key: string; title: string }[]>(
[] []
); );
const [queryParams, setQueryParams] = useState<Global.SearchParams>({
page: -1
});
const getModelList = async () => { const getModelList = async () => {
try { try {
const res = await queryMyModels(queryParams); const res = await queryMyModels({
page: -1
});
const options = res.items.map((item) => item.name); const options = res.items.map((item) => item.name);
if (action === PageAction.EDIT && currentData) { if (action === PageAction.EDIT && currentData) {
const list = new Set([ const list = new Set([
@@ -57,6 +56,11 @@ const AllowModelsForm: React.FC<{
const handleAllowTypeChange = (e: any) => { const handleAllowTypeChange = (e: any) => {
const value = e.target.value; const value = e.target.value;
onValuesChange?.({ allowed_type: value }, form.getFieldsValue()); onValuesChange?.({ allowed_type: value }, form.getFieldsValue());
if (value === 'management') {
form.setFieldsValue({ scope: ['management'] });
} else {
form.setFieldsValue({ scope: ['inference'] });
}
}; };
useEffect(() => { useEffect(() => {
@@ -66,7 +70,7 @@ const AllowModelsForm: React.FC<{
return ( return (
<div> <div>
<Divider></Divider> <Divider></Divider>
<Label>{intl.formatMessage({ id: 'apikeys.table.bindModels' })}</Label> <Label>{intl.formatMessage({ id: 'apikeys.access.permissions' })}</Label>
<Form.Item <Form.Item
name="allowed_type" name="allowed_type"
initialValue="all" initialValue="all"
@@ -75,6 +79,12 @@ const AllowModelsForm: React.FC<{
<Radio.Group <Radio.Group
onChange={handleAllowTypeChange} onChange={handleAllowTypeChange}
options={[ options={[
{
label: intl.formatMessage({
id: 'apikeys.accessScope.management'
}),
value: 'management'
},
{ {
label: intl.formatMessage({ id: 'apikeys.models.all' }), label: intl.formatMessage({ id: 'apikeys.models.all' }),
value: 'all' value: 'all'
@@ -88,7 +98,7 @@ const AllowModelsForm: React.FC<{
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="allowed_model_names" name="allowed_model_names"
hidden={allowedType === 'all'} hidden={allowedType === 'all' || allowedType === 'management'}
rules={[ rules={[
{ {
required: allowedType === 'custom', required: allowedType === 'custom',
@@ -16,17 +16,7 @@ const APIKeyForm: React.FC<{
onValuesChange?: (changedValues: any, allValues: any) => void; onValuesChange?: (changedValues: any, allValues: any) => void;
}> = ({ action, currentData, onValuesChange }) => { }> = ({ action, currentData, onValuesChange }) => {
const intl = useIntl(); const intl = useIntl();
const keyType = Form.useWatch('key_type') as FormData['key_type'];
const optionRender = (option: any) => {
return (
<span className="flex-center gap-4">
{option.label}
{option.data.description && (
<span className="text-tertiary">[{option.data.description}]</span>
)}
</span>
);
};
return ( return (
<> <>
@@ -51,28 +41,7 @@ const APIKeyForm: React.FC<{
required required
></SealInput.Input> ></SealInput.Input>
</Form.Item> </Form.Item>
{action === PageAction.CREATE && (
<Form.Item<FormData> name="custom">
<Password
trim
autoComplete="new-password"
label={intl.formatMessage({ id: 'playground.params.custom' })}
></Password>
</Form.Item>
)}
<Form.Item<FormData>
name="scope"
normalize={(value) => (value ? [value] : [])}
getValueProps={(value) => ({
value: Array.isArray(value) ? value[0] : value
})}
>
<SealSelect
optionRender={optionRender}
options={accessScopeOptions}
label={intl.formatMessage({ id: 'models.table.accessScope' })}
></SealSelect>
</Form.Item>
<Form.Item<FormData> <Form.Item<FormData>
name="expires_in" name="expires_in"
rules={[ rules={[
@@ -102,6 +71,63 @@ const APIKeyForm: React.FC<{
label={intl.formatMessage({ id: 'common.table.description' })} label={intl.formatMessage({ id: 'common.table.description' })}
></SealInput.TextArea> ></SealInput.TextArea>
</Form.Item> </Form.Item>
{action === PageAction.CREATE && (
<>
<Form.Item<FormData> name="key_type" initialValue="auto">
<SealSelect
options={[
{
label: intl.formatMessage({ id: 'apikeys.type.auto' }),
value: 'auto'
},
{
label: intl.formatMessage({ id: 'apikeys.type.custom' }),
value: 'custom'
}
]}
label={intl.formatMessage({ id: 'common.table.type' })}
></SealSelect>
</Form.Item>
{keyType === 'custom' && (
<Form.Item<FormData>
name="custom"
rules={[
{
required: true,
message: intl.formatMessage(
{ id: 'common.form.rule.input' },
{
name: intl.formatMessage({
id: 'apikeys.table.key'
})
}
)
}
]}
>
<Password
trim
required
autoComplete="new-password"
label={intl.formatMessage({ id: 'apikeys.table.key' })}
></Password>
</Form.Item>
)}
</>
)}
<Form.Item<FormData>
name="scope"
hidden
normalize={(value) => (value ? [value] : [])}
getValueProps={(value) => ({
value: Array.isArray(value) ? value[0] : value
})}
>
<SealSelect
options={accessScopeOptions}
label={intl.formatMessage({ id: 'models.table.accessScope' })}
></SealSelect>
</Form.Item>
<AllowModelsForm <AllowModelsForm
currentData={currentData} currentData={currentData}
action={action} action={action}
@@ -113,12 +113,12 @@ const AddModal: React.FC<AddModalProps> = ({
const handleOnOk = async (formdata: FormData) => { const handleOnOk = async (formdata: FormData) => {
try { try {
console.log('formdata=========', formdata);
setLoading(true); setLoading(true);
const data = { const data = {
..._.omit(formdata, ['allowed_type']), ..._.omit(formdata, ['allowed_type']),
allowed_model_names: allowed_model_names:
formdata.allowed_type === 'all' formdata.allowed_type === 'all' ||
formdata.allowed_type === 'management'
? [] ? []
: formdata.allowed_model_names || [] : formdata.allowed_model_names || []
}; };
@@ -183,9 +183,12 @@ const AddModal: React.FC<AddModalProps> = ({
form.setFieldsValue({ form.setFieldsValue({
name: currentData.name, name: currentData.name,
description: currentData.description, description: currentData.description,
scope: currentData.scope,
allowed_type: currentData.allowed_model_names?.length allowed_type: currentData.allowed_model_names?.length
? 'custom' ? 'custom'
: 'all', : currentData.scope?.includes('management')
? 'management'
: 'all',
expires_in: parseExpireValue(currentData as ListItem), expires_in: parseExpireValue(currentData as ListItem),
allowed_model_names: currentData.allowed_model_names || [] allowed_model_names: currentData.allowed_model_names || []
}); });
@@ -269,7 +272,7 @@ const AddModal: React.FC<AddModalProps> = ({
onFinish={handleOnOk} onFinish={handleOnOk}
preserve={false} preserve={false}
initialValues={{ initialValues={{
scope: ['*'] scope: ['inference']
}} }}
> >
{!showKey && ( {!showKey && (
+2 -7
View File
@@ -27,18 +27,13 @@ export const expirationOptions = [
export const accessScopeOptions = [ export const accessScopeOptions = [
{ {
label: 'apikeys.accessScope.all', label: 'management',
value: '*',
locale: true
},
{
label: 'apikeys.accessScope.management',
value: 'management', value: 'management',
description: 'v2/', description: 'v2/',
locale: true locale: true
}, },
{ {
label: 'apikeys.accessScope.inference', label: 'inference',
value: 'inference', value: 'inference',
description: 'v1/', description: 'v1/',
locale: true locale: true
+2 -1
View File
@@ -13,7 +13,8 @@ export interface ListItem {
export interface FormData { export interface FormData {
name: string; name: string;
allowed_type: 'all' | 'custom'; allowed_type: 'all' | 'custom' | 'management';
key_type: 'auto' | 'custom';
description: string; description: string;
allowed_model_names: string[]; allowed_model_names: string[];
expires_in: number | null; expires_in: number | null;
+7 -21
View File
@@ -110,27 +110,13 @@ const useModelsColumns = ({
showTitle: false showTitle: false
}, },
render: (text: string[], record: ListItem) => ( render: (text: string[], record: ListItem) => (
<div <AutoTooltip ghost>
style={{ {record.scope?.[0] === 'management'
display: 'grid', ? intl.formatMessage({ id: 'apikeys.accessScope.management' })
gridTemplateColumns: 'max-content 1fr', : record.allowed_model_names?.length
gap: 8, ? record.allowed_model_names.join(', ')
alignItems: 'center' : intl.formatMessage({ id: 'apikeys.models.all' })}
}} </AutoTooltip>
>
<span className="text-primary">APIs:</span>
<AutoTooltip ghost>{renderAPIs(record)}</AutoTooltip>
<span className="text-primary">
{intl.formatMessage({ id: 'models.title' })}:
</span>
<AutoTooltip ghost>
<span>
{text?.length
? text?.join(', ')
: intl.formatMessage({ id: 'common.select.option' })}
</span>
</AutoTooltip>
</div>
) )
}, },
{ {