mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-04-19 22:58:39 +00:00
fix: fix model deployment style issues, lint problems, and i18n gaps. (#2556)
* fix: fix model deployment style issues, lint problems, and i18n gaps. * fix: adjust the key not to be displayed on the frontend, tested via the backend. * fix: adjust the sidebar configuration logic to use the default configuration items if they are not defined.
This commit is contained in:
@@ -34,27 +34,21 @@ import {
|
||||
TextArea,
|
||||
Switch,
|
||||
} from '@douyinfe/semi-ui';
|
||||
import {
|
||||
FaCog,
|
||||
import {
|
||||
FaCog,
|
||||
FaDocker,
|
||||
FaKey,
|
||||
FaTerminal,
|
||||
FaNetworkWired,
|
||||
FaExclamationTriangle,
|
||||
FaPlus,
|
||||
FaMinus
|
||||
FaMinus,
|
||||
} from 'react-icons/fa';
|
||||
import { API, showError, showSuccess } from '../../../../helpers';
|
||||
|
||||
const { Text, Title } = Typography;
|
||||
|
||||
const UpdateConfigModal = ({
|
||||
visible,
|
||||
onCancel,
|
||||
deployment,
|
||||
onSuccess,
|
||||
t
|
||||
}) => {
|
||||
const UpdateConfigModal = ({ visible, onCancel, deployment, onSuccess, t }) => {
|
||||
const formRef = useRef(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [envVars, setEnvVars] = useState([]);
|
||||
@@ -72,18 +66,21 @@ const UpdateConfigModal = ({
|
||||
registry_secret: '',
|
||||
command: '',
|
||||
};
|
||||
|
||||
|
||||
if (formRef.current) {
|
||||
formRef.current.setValues(initialValues);
|
||||
}
|
||||
|
||||
|
||||
// Initialize environment variables
|
||||
const envVarsList = deployment.container_config?.env_variables
|
||||
? Object.entries(deployment.container_config.env_variables).map(([key, value]) => ({
|
||||
key, value: String(value)
|
||||
}))
|
||||
const envVarsList = deployment.container_config?.env_variables
|
||||
? Object.entries(deployment.container_config.env_variables).map(
|
||||
([key, value]) => ({
|
||||
key,
|
||||
value: String(value),
|
||||
}),
|
||||
)
|
||||
: [];
|
||||
|
||||
|
||||
setEnvVars(envVarsList);
|
||||
setSecretEnvVars([]);
|
||||
}
|
||||
@@ -91,23 +88,30 @@ const UpdateConfigModal = ({
|
||||
|
||||
const handleUpdate = async () => {
|
||||
try {
|
||||
const formValues = formRef.current ? await formRef.current.validate() : {};
|
||||
const formValues = formRef.current
|
||||
? await formRef.current.validate()
|
||||
: {};
|
||||
setLoading(true);
|
||||
|
||||
// Prepare the update payload
|
||||
const payload = {};
|
||||
|
||||
|
||||
if (formValues.image_url) payload.image_url = formValues.image_url;
|
||||
if (formValues.traffic_port) payload.traffic_port = formValues.traffic_port;
|
||||
if (formValues.registry_username) payload.registry_username = formValues.registry_username;
|
||||
if (formValues.registry_secret) payload.registry_secret = formValues.registry_secret;
|
||||
if (formValues.traffic_port)
|
||||
payload.traffic_port = formValues.traffic_port;
|
||||
if (formValues.registry_username)
|
||||
payload.registry_username = formValues.registry_username;
|
||||
if (formValues.registry_secret)
|
||||
payload.registry_secret = formValues.registry_secret;
|
||||
if (formValues.command) payload.command = formValues.command;
|
||||
|
||||
|
||||
// Process entrypoint
|
||||
if (formValues.entrypoint) {
|
||||
payload.entrypoint = formValues.entrypoint.split(' ').filter(cmd => cmd.trim());
|
||||
payload.entrypoint = formValues.entrypoint
|
||||
.split(' ')
|
||||
.filter((cmd) => cmd.trim());
|
||||
}
|
||||
|
||||
|
||||
// Process environment variables
|
||||
if (envVars.length > 0) {
|
||||
payload.env_variables = envVars.reduce((acc, env) => {
|
||||
@@ -117,7 +121,7 @@ const UpdateConfigModal = ({
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
|
||||
// Process secret environment variables
|
||||
if (secretEnvVars.length > 0) {
|
||||
payload.secret_env_variables = secretEnvVars.reduce((acc, env) => {
|
||||
@@ -128,7 +132,10 @@ const UpdateConfigModal = ({
|
||||
}, {});
|
||||
}
|
||||
|
||||
const response = await API.put(`/api/deployments/${deployment.id}`, payload);
|
||||
const response = await API.put(
|
||||
`/api/deployments/${deployment.id}`,
|
||||
payload,
|
||||
);
|
||||
|
||||
if (response.data.success) {
|
||||
showSuccess(t('容器配置更新成功'));
|
||||
@@ -136,7 +143,11 @@ const UpdateConfigModal = ({
|
||||
handleCancel();
|
||||
}
|
||||
} catch (error) {
|
||||
showError(t('更新配置失败') + ': ' + (error.response?.data?.message || error.message));
|
||||
showError(
|
||||
t('更新配置失败') +
|
||||
': ' +
|
||||
(error.response?.data?.message || error.message),
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -184,8 +195,8 @@ const UpdateConfigModal = ({
|
||||
return (
|
||||
<Modal
|
||||
title={
|
||||
<div className="flex items-center gap-2">
|
||||
<FaCog className="text-blue-500" />
|
||||
<div className='flex items-center gap-2'>
|
||||
<FaCog className='text-blue-500' />
|
||||
<span>{t('更新容器配置')}</span>
|
||||
</div>
|
||||
}
|
||||
@@ -196,130 +207,131 @@ const UpdateConfigModal = ({
|
||||
cancelText={t('取消')}
|
||||
confirmLoading={loading}
|
||||
width={700}
|
||||
className="update-config-modal"
|
||||
className='update-config-modal'
|
||||
>
|
||||
<div className="space-y-4 max-h-[600px] overflow-y-auto">
|
||||
<div className='space-y-4 max-h-[600px] overflow-y-auto'>
|
||||
{/* Container Info */}
|
||||
<Card className="border-0 bg-gray-50">
|
||||
<div className="flex items-center justify-between">
|
||||
<Card className='border-0 bg-gray-50'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<div>
|
||||
<Text strong className="text-base">
|
||||
<Text strong className='text-base'>
|
||||
{deployment?.container_name}
|
||||
</Text>
|
||||
<div className="mt-1">
|
||||
<Text type="secondary" size="small">
|
||||
<div className='mt-1'>
|
||||
<Text type='secondary' size='small'>
|
||||
ID: {deployment?.id}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
<Tag color="blue">{deployment?.status}</Tag>
|
||||
<Tag color='blue'>{deployment?.status}</Tag>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Warning Banner */}
|
||||
<Banner
|
||||
type="warning"
|
||||
type='warning'
|
||||
icon={<FaExclamationTriangle />}
|
||||
title={t('重要提醒')}
|
||||
description={
|
||||
<div className="space-y-2">
|
||||
<p>{t('更新容器配置可能会导致容器重启,请确保在合适的时间进行此操作。')}</p>
|
||||
<div className='space-y-2'>
|
||||
<p>
|
||||
{t(
|
||||
'更新容器配置可能会导致容器重启,请确保在合适的时间进行此操作。',
|
||||
)}
|
||||
</p>
|
||||
<p>{t('某些配置更改可能需要几分钟才能生效。')}</p>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<Form
|
||||
getFormApi={(api) => (formRef.current = api)}
|
||||
layout="vertical"
|
||||
>
|
||||
<Form getFormApi={(api) => (formRef.current = api)} layout='vertical'>
|
||||
<Collapse defaultActiveKey={['docker']}>
|
||||
{/* Docker Configuration */}
|
||||
<Collapse.Panel
|
||||
<Collapse.Panel
|
||||
header={
|
||||
<div className="flex items-center gap-2">
|
||||
<FaDocker className="text-blue-600" />
|
||||
<span>{t('Docker 配置')}</span>
|
||||
<div className='flex items-center gap-2'>
|
||||
<FaDocker className='text-blue-600' />
|
||||
<span>{t('镜像配置')}</span>
|
||||
</div>
|
||||
}
|
||||
itemKey="docker"
|
||||
itemKey='docker'
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<div className='space-y-4'>
|
||||
<Form.Input
|
||||
field="image_url"
|
||||
field='image_url'
|
||||
label={t('镜像地址')}
|
||||
placeholder={t('例如: nginx:latest')}
|
||||
rules={[
|
||||
{
|
||||
{
|
||||
type: 'string',
|
||||
message: t('请输入有效的镜像地址')
|
||||
}
|
||||
message: t('请输入有效的镜像地址'),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Form.Input
|
||||
field="registry_username"
|
||||
field='registry_username'
|
||||
label={t('镜像仓库用户名')}
|
||||
placeholder={t('如果镜像为私有,请填写用户名')}
|
||||
/>
|
||||
|
||||
<Form.Input
|
||||
field="registry_secret"
|
||||
field='registry_secret'
|
||||
label={t('镜像仓库密码')}
|
||||
mode="password"
|
||||
mode='password'
|
||||
placeholder={t('如果镜像为私有,请填写密码或Token')}
|
||||
/>
|
||||
</div>
|
||||
</Collapse.Panel>
|
||||
|
||||
{/* Network Configuration */}
|
||||
<Collapse.Panel
|
||||
<Collapse.Panel
|
||||
header={
|
||||
<div className="flex items-center gap-2">
|
||||
<FaNetworkWired className="text-green-600" />
|
||||
<div className='flex items-center gap-2'>
|
||||
<FaNetworkWired className='text-green-600' />
|
||||
<span>{t('网络配置')}</span>
|
||||
</div>
|
||||
}
|
||||
itemKey="network"
|
||||
itemKey='network'
|
||||
>
|
||||
<Form.InputNumber
|
||||
field="traffic_port"
|
||||
field='traffic_port'
|
||||
label={t('流量端口')}
|
||||
placeholder={t('容器对外暴露的端口')}
|
||||
min={1}
|
||||
max={65535}
|
||||
style={{ width: '100%' }}
|
||||
rules={[
|
||||
{
|
||||
{
|
||||
type: 'number',
|
||||
min: 1,
|
||||
max: 65535,
|
||||
message: t('端口号必须在1-65535之间')
|
||||
}
|
||||
message: t('端口号必须在1-65535之间'),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Collapse.Panel>
|
||||
|
||||
{/* Startup Configuration */}
|
||||
<Collapse.Panel
|
||||
<Collapse.Panel
|
||||
header={
|
||||
<div className="flex items-center gap-2">
|
||||
<FaTerminal className="text-purple-600" />
|
||||
<div className='flex items-center gap-2'>
|
||||
<FaTerminal className='text-purple-600' />
|
||||
<span>{t('启动配置')}</span>
|
||||
</div>
|
||||
}
|
||||
itemKey="startup"
|
||||
itemKey='startup'
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<div className='space-y-4'>
|
||||
<Form.Input
|
||||
field="entrypoint"
|
||||
field='entrypoint'
|
||||
label={t('启动命令 (Entrypoint)')}
|
||||
placeholder={t('例如: /bin/bash -c "python app.py"')}
|
||||
helpText={t('多个命令用空格分隔')}
|
||||
/>
|
||||
|
||||
<Form.Input
|
||||
field="command"
|
||||
field='command'
|
||||
label={t('运行命令 (Command)')}
|
||||
placeholder={t('容器启动后执行的命令')}
|
||||
/>
|
||||
@@ -327,34 +339,34 @@ const UpdateConfigModal = ({
|
||||
</Collapse.Panel>
|
||||
|
||||
{/* Environment Variables */}
|
||||
<Collapse.Panel
|
||||
<Collapse.Panel
|
||||
header={
|
||||
<div className="flex items-center gap-2">
|
||||
<FaKey className="text-orange-600" />
|
||||
<div className='flex items-center gap-2'>
|
||||
<FaKey className='text-orange-600' />
|
||||
<span>{t('环境变量')}</span>
|
||||
<Tag size="small">{envVars.length}</Tag>
|
||||
<Tag size='small'>{envVars.length}</Tag>
|
||||
</div>
|
||||
}
|
||||
itemKey="env"
|
||||
itemKey='env'
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<div className='space-y-4'>
|
||||
{/* Regular Environment Variables */}
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className='flex items-center justify-between mb-3'>
|
||||
<Text strong>{t('普通环境变量')}</Text>
|
||||
<Button
|
||||
size="small"
|
||||
size='small'
|
||||
icon={<FaPlus />}
|
||||
onClick={addEnvVar}
|
||||
theme="borderless"
|
||||
type="primary"
|
||||
theme='borderless'
|
||||
type='primary'
|
||||
>
|
||||
{t('添加')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
||||
{envVars.map((envVar, index) => (
|
||||
<div key={index} className="flex items-end gap-2 mb-2">
|
||||
<div key={index} className='flex items-end gap-2 mb-2'>
|
||||
<Input
|
||||
placeholder={t('变量名')}
|
||||
value={envVar.key}
|
||||
@@ -365,22 +377,24 @@ const UpdateConfigModal = ({
|
||||
<Input
|
||||
placeholder={t('变量值')}
|
||||
value={envVar.value}
|
||||
onChange={(value) => updateEnvVar(index, 'value', value)}
|
||||
onChange={(value) =>
|
||||
updateEnvVar(index, 'value', value)
|
||||
}
|
||||
style={{ flex: 2 }}
|
||||
/>
|
||||
<Button
|
||||
size="small"
|
||||
size='small'
|
||||
icon={<FaMinus />}
|
||||
onClick={() => removeEnvVar(index)}
|
||||
theme="borderless"
|
||||
type="danger"
|
||||
theme='borderless'
|
||||
type='danger'
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
|
||||
{envVars.length === 0 && (
|
||||
<div className="text-center text-gray-500 py-4 border-2 border-dashed border-gray-300 rounded-lg">
|
||||
<Text type="secondary">{t('暂无环境变量')}</Text>
|
||||
<div className='text-center text-gray-500 py-4 border-2 border-dashed border-gray-300 rounded-lg'>
|
||||
<Text type='secondary'>{t('暂无环境变量')}</Text>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -389,61 +403,67 @@ const UpdateConfigModal = ({
|
||||
|
||||
{/* Secret Environment Variables */}
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className='flex items-center justify-between mb-3'>
|
||||
<div className='flex items-center gap-2'>
|
||||
<Text strong>{t('机密环境变量')}</Text>
|
||||
<Tag size="small" type="danger">
|
||||
<Tag size='small' type='danger'>
|
||||
{t('加密存储')}
|
||||
</Tag>
|
||||
</div>
|
||||
<Button
|
||||
size="small"
|
||||
size='small'
|
||||
icon={<FaPlus />}
|
||||
onClick={addSecretEnvVar}
|
||||
theme="borderless"
|
||||
type="danger"
|
||||
theme='borderless'
|
||||
type='danger'
|
||||
>
|
||||
{t('添加')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
||||
{secretEnvVars.map((envVar, index) => (
|
||||
<div key={index} className="flex items-end gap-2 mb-2">
|
||||
<div key={index} className='flex items-end gap-2 mb-2'>
|
||||
<Input
|
||||
placeholder={t('变量名')}
|
||||
value={envVar.key}
|
||||
onChange={(value) => updateSecretEnvVar(index, 'key', value)}
|
||||
onChange={(value) =>
|
||||
updateSecretEnvVar(index, 'key', value)
|
||||
}
|
||||
style={{ flex: 1 }}
|
||||
/>
|
||||
<Text>=</Text>
|
||||
<Input
|
||||
mode="password"
|
||||
mode='password'
|
||||
placeholder={t('变量值')}
|
||||
value={envVar.value}
|
||||
onChange={(value) => updateSecretEnvVar(index, 'value', value)}
|
||||
onChange={(value) =>
|
||||
updateSecretEnvVar(index, 'value', value)
|
||||
}
|
||||
style={{ flex: 2 }}
|
||||
/>
|
||||
<Button
|
||||
size="small"
|
||||
size='small'
|
||||
icon={<FaMinus />}
|
||||
onClick={() => removeSecretEnvVar(index)}
|
||||
theme="borderless"
|
||||
type="danger"
|
||||
theme='borderless'
|
||||
type='danger'
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
|
||||
{secretEnvVars.length === 0 && (
|
||||
<div className="text-center text-gray-500 py-4 border-2 border-dashed border-red-200 rounded-lg bg-red-50">
|
||||
<Text type="secondary">{t('暂无机密环境变量')}</Text>
|
||||
<div className='text-center text-gray-500 py-4 border-2 border-dashed border-red-200 rounded-lg bg-red-50'>
|
||||
<Text type='secondary'>{t('暂无机密环境变量')}</Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
<Banner
|
||||
type="info"
|
||||
type='info'
|
||||
title={t('机密环境变量说明')}
|
||||
description={t('机密环境变量将被加密存储,适用于存储密码、API密钥等敏感信息。')}
|
||||
size="small"
|
||||
description={t(
|
||||
'机密环境变量将被加密存储,适用于存储密码、API密钥等敏感信息。',
|
||||
)}
|
||||
size='small'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -452,16 +472,18 @@ const UpdateConfigModal = ({
|
||||
</Form>
|
||||
|
||||
{/* Final Warning */}
|
||||
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-3">
|
||||
<div className="flex items-start gap-2">
|
||||
<FaExclamationTriangle className="text-yellow-600 mt-0.5" />
|
||||
<div className='bg-yellow-50 border border-yellow-200 rounded-lg p-3'>
|
||||
<div className='flex items-start gap-2'>
|
||||
<FaExclamationTriangle className='text-yellow-600 mt-0.5' />
|
||||
<div>
|
||||
<Text strong className="text-yellow-800">
|
||||
<Text strong className='text-yellow-800'>
|
||||
{t('配置更新确认')}
|
||||
</Text>
|
||||
<div className="mt-1">
|
||||
<Text size="small" className="text-yellow-700">
|
||||
{t('更新配置后,容器可能需要重启以应用新的设置。请确保您了解这些更改的影响。')}
|
||||
<div className='mt-1'>
|
||||
<Text size='small' className='text-yellow-700'>
|
||||
{t(
|
||||
'更新配置后,容器可能需要重启以应用新的设置。请确保您了解这些更改的影响。',
|
||||
)}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
@@ -472,4 +494,4 @@ const UpdateConfigModal = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateConfigModal;
|
||||
export default UpdateConfigModal;
|
||||
|
||||
Reference in New Issue
Block a user