feat(datasource): Database connection Renewal (#2359)

Co-authored-by: aries_ckt <916701291@qq.com>
Co-authored-by: Fangyin Cheng <staneyffer@gmail.com>
Co-authored-by: ‘yanzhiyonggit config --global user.email git config --global user.name ‘yanzhiyong <zhiyong.yan@clife.cn>
This commit is contained in:
云锋
2025-02-22 18:44:21 +08:00
committed by GitHub
parent e4b329ee21
commit 94b51284e0
132 changed files with 689 additions and 501 deletions

View File

@@ -1,11 +1,12 @@
import { apiInterceptors, createModel, getSupportModels } from '@/client/api';
import { renderModelIcon } from '@/components/chat/header/model-selector';
import { StartModelParams, SupportModel, SupportModelParams } from '@/types/model';
import { ConfigurableParams } from '@/types/common';
import { StartModelParams, SupportModel } from '@/types/model';
import { AutoComplete, Button, Form, Select, Tooltip, message } from 'antd';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import ReactMarkdown from 'react-markdown';
import ModelParams from './model-params';
import ConfigurableForm from '../common/configurable-form';
const { Option } = Select;
const FormItem = Form.Item;
@@ -18,7 +19,7 @@ function ModelForm({ onCancel, onSuccess }: { onCancel: () => void; onSuccess: (
const [_, setModels] = useState<Array<SupportModel> | null>([]);
const [selectedWorkerType, setSelectedWorkerType] = useState<string>();
const [selectedProvider, setSelectedProvider] = useState<string>();
const [params, setParams] = useState<Array<SupportModelParams> | null>(null);
const [params, setParams] = useState<Array<ConfigurableParams> | null>(null);
const [loading, setLoading] = useState<boolean>(false);
const [form] = Form.useForm();
@@ -215,7 +216,7 @@ function ModelForm({ onCancel, onSuccess }: { onCancel: () => void; onSuccess: (
/>
</FormItem>
<ModelParams params={params.filter(p => p.param_name !== 'name')} form={form} />
<ConfigurableForm params={params.filter(p => p.param_name !== 'name')} form={form} />
</>
)}

View File

@@ -1,125 +0,0 @@
import { SupportModelParams } from '@/types/model';
import { Checkbox, Form, FormInstance, Input, InputNumber, Select } from 'antd';
import { useEffect } from 'react';
import NestedFormFields from './nested-form-fields';
interface ParamValues {
[key: string]: string | number | boolean | Record<string, any>;
}
function ModelParams({ params, form }: { params: Array<SupportModelParams> | null; form: FormInstance<any> }) {
useEffect(() => {
if (params) {
const initialValues: ParamValues = {};
params.forEach(param => {
if (!param.nested_fields) {
// Only set default value when the field has not been modified by the user
const currentValue = form.getFieldValue(param.param_name);
if (currentValue === undefined) {
initialValues[param.param_name] = param.default_value;
}
}
});
form.setFieldsValue(initialValues);
}
}, [params, form]);
if (!params || params?.length < 1) {
return null;
}
// Transform data structure before form submission
const normalizeFormValues = (values: any) => {
const normalized = { ...values };
params?.forEach(param => {
if (param.nested_fields && normalized[param.param_name]) {
const nestedValue = normalized[param.param_name];
if (nestedValue.type) {
// Keep all field values instead of just type
const nestedFields = param.nested_fields[nestedValue.type] || [];
const fieldValues = {};
nestedFields.forEach(field => {
if (nestedValue[field.param_name] !== undefined) {
fieldValues[field.param_name] = nestedValue[field.param_name];
}
});
normalized[param.param_name] = {
type: nestedValue.type,
...fieldValues,
};
}
}
});
return normalized;
};
// Override the original submit method of the form
const originalSubmit = form.submit;
form.submit = () => {
const values = form.getFieldsValue();
const normalizedValues = normalizeFormValues(values);
form.setFieldsValue(normalizedValues);
originalSubmit.call(form);
};
function renderItem(param: SupportModelParams) {
if (param.nested_fields) {
return (
<NestedFormFields
parentName={param.param_name}
fields={param.nested_fields as Record<string, SupportModelParams[]>}
form={form}
/>
);
}
const type = param.param_type.toLowerCase();
const isFixed = param.ext_metadata?.tags?.includes('fixed');
if (type === 'str' || type === 'string') {
if (param.valid_values) {
return (
<Select disabled={isFixed}>
{param.valid_values.map(value => (
<Select.Option key={value} value={value}>
{value}
</Select.Option>
))}
</Select>
);
}
return <Input disabled={isFixed} />;
}
if (type === 'int' || type === 'integer' || type === 'number' || type === 'float') {
return <InputNumber className='w-full' disabled={isFixed} />;
}
if (type === 'bool' || type === 'boolean') {
return <Checkbox disabled={isFixed} />;
}
return <Input disabled={isFixed} />;
}
return (
<div className='space-y-4'>
{params?.map((param: SupportModelParams) => (
<Form.Item
key={param.param_name}
label={<p className='whitespace-normal overflow-wrap-break-word'>{param.label || param.param_name}</p>}
name={param.param_name}
initialValue={param.default_value}
valuePropName={
param.param_type.toLowerCase() === 'bool' || param.param_type.toLowerCase() === 'boolean'
? 'checked'
: 'value'
}
tooltip={param.description}
rules={param.required ? [{ required: true, message: `Please input ${param.param_name}` }] : []}
>
{renderItem(param)}
</Form.Item>
))}
</div>
);
}
export default ModelParams;

View File

@@ -1,105 +0,0 @@
import { SupportModelParams } from '@/types/model';
import { Checkbox, Form, FormInstance, Input, InputNumber, Select } from 'antd';
import React, { useEffect, useState } from 'react';
interface NestedFormFieldsProps {
parentName: string;
fields: Record<string, SupportModelParams[]>;
form: FormInstance;
}
const NestedFormFields: React.FC<NestedFormFieldsProps> = ({ parentName, fields, form }) => {
const [selectedType, setSelectedType] = useState<string | null>(null);
useEffect(() => {
const currentValue = form.getFieldValue(parentName);
if (currentValue?.type && !selectedType) {
setSelectedType(currentValue.type);
}
}, [form, parentName]);
const handleTypeChange = (value: string) => {
setSelectedType(value);
// Get all field configurations for the current type
const typeFields = fields[value] || [];
// Create an object containing default values for all fields
const defaultValues = {
type: value,
};
// Set default values for each field
typeFields.forEach(field => {
defaultValues[field.param_name] = field.default_value;
});
// Set the entire object as the value of the form field
form.setFieldsValue({
[parentName]: defaultValues,
});
};
const renderFormItem = (param: SupportModelParams) => {
const type = param.param_type.toLowerCase();
// Use the complete field path
const fieldPath = [parentName, param.param_name];
let control;
if (type === 'str' || type === 'string') {
if (param.valid_values) {
control = (
<Select>
{param.valid_values.map(value => (
<Select.Option key={value} value={value}>
{value}
</Select.Option>
))}
</Select>
);
} else {
control = <Input />;
}
} else if (type === 'int' || type === 'integer' || type === 'number' || type === 'float') {
control = <InputNumber className='w-full' />;
} else if (type === 'bool' || type === 'boolean') {
control = <Checkbox />;
} else {
control = <Input />;
}
return (
<Form.Item
key={param.param_name}
label={param.label || param.param_name}
name={fieldPath}
valuePropName={type === 'bool' || type === 'boolean' ? 'checked' : 'value'}
tooltip={param.description}
rules={selectedType && param.required ? [{ required: true, message: `Please input ${param.param_name}` }] : []}
>
{control}
</Form.Item>
);
};
return (
<div className='space-y-4 border rounded-md p-4'>
<Form.Item label='Type' name={[parentName, 'type']}>
<Select onChange={handleTypeChange} placeholder='Select a type'>
{Object.keys(fields).map(type => (
<Select.Option key={type} value={type}>
{type}
</Select.Option>
))}
</Select>
</Form.Item>
{selectedType && fields[selectedType] && (
<div className='mt-4'>
<h4 className='mb-4 text-base font-medium'>{selectedType} Configuration</h4>
<div className='space-y-4'>{fields[selectedType].map(param => renderFormItem(param))}</div>
</div>
)}
</div>
);
};
export default NestedFormFields;