feat: ExternalToolEditor 支持 JSON 全量编辑与双向同步
parent
f1553be178
commit
49b48df182
|
|
@ -1,5 +1,5 @@
|
||||||
import { CopyOutlined, DownOutlined, MinusCircleOutlined, PlusOutlined, RightOutlined } from '@ant-design/icons';
|
import { CopyOutlined, DownOutlined, MinusCircleOutlined, PlusOutlined, RightOutlined } from '@ant-design/icons';
|
||||||
import { App as AntApp, Button, Card, Form, Input, Modal, Select, Space } from 'antd';
|
import { App as AntApp, Button, Card, Form, Input, Modal, Select, Space, Tabs } from 'antd';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { AgentAPI, ExternalToolApi, ExternalToolApiRouting, ExternalToolPlugin, ExternalToolPluginPayload } from '../api';
|
import { AgentAPI, ExternalToolApi, ExternalToolApiRouting, ExternalToolPlugin, ExternalToolPluginPayload } from '../api';
|
||||||
|
|
||||||
|
|
@ -150,9 +150,19 @@ export default function ExternalToolEditor({ open, agentId, plugin, onClose, onS
|
||||||
const [form] = Form.useForm<ToolPluginFormValue>();
|
const [form] = Form.useForm<ToolPluginFormValue>();
|
||||||
const isEditing = Boolean(plugin);
|
const isEditing = Boolean(plugin);
|
||||||
const apis = Form.useWatch('apis', form) || [];
|
const apis = Form.useWatch('apis', form) || [];
|
||||||
|
const allValues = Form.useWatch([], form);
|
||||||
const [expandedApiIndexes, setExpandedApiIndexes] = useState<number[]>([]);
|
const [expandedApiIndexes, setExpandedApiIndexes] = useState<number[]>([]);
|
||||||
|
const [jsonContent, setJsonContent] = useState('');
|
||||||
|
const [activeTab, setActiveTab] = useState('visual');
|
||||||
|
const [isSyncing, setIsSyncing] = useState(false);
|
||||||
const previousApiCountRef = useRef(0);
|
const previousApiCountRef = useRef(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (allValues && !isSyncing) {
|
||||||
|
setJsonContent(JSON.stringify(allValues, null, 2));
|
||||||
|
}
|
||||||
|
}, [allValues, isSyncing]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
previousApiCountRef.current = 0;
|
previousApiCountRef.current = 0;
|
||||||
|
|
@ -181,6 +191,21 @@ export default function ExternalToolEditor({ open, agentId, plugin, onClose, onS
|
||||||
previousApiCountRef.current = apiCount;
|
previousApiCountRef.current = apiCount;
|
||||||
}, [apis.length, open]);
|
}, [apis.length, open]);
|
||||||
|
|
||||||
|
const handleJsonChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
|
const val = e.target.value;
|
||||||
|
setJsonContent(val);
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(val);
|
||||||
|
if (parsed && typeof parsed === 'object') {
|
||||||
|
setIsSyncing(true);
|
||||||
|
form.setFieldsValue(parsed);
|
||||||
|
setTimeout(() => setIsSyncing(false), 0);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 格式不正确时不更新表单
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const toggleApiCard = (index: number) => {
|
const toggleApiCard = (index: number) => {
|
||||||
setExpandedApiIndexes((current) =>
|
setExpandedApiIndexes((current) =>
|
||||||
current.includes(index) ? current.filter((item) => item !== index) : [...current, index],
|
current.includes(index) ? current.filter((item) => item !== index) : [...current, index],
|
||||||
|
|
@ -280,7 +305,16 @@ export default function ExternalToolEditor({ open, agentId, plugin, onClose, onS
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Form form={form} layout="vertical" requiredMark="optional">
|
<Form form={form} layout="vertical" requiredMark="optional" preserve={true}>
|
||||||
|
<Tabs
|
||||||
|
activeKey={activeTab}
|
||||||
|
onChange={setActiveTab}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
key: 'visual',
|
||||||
|
label: '可视化编辑',
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
<div className="agent-editor-tool-grid">
|
<div className="agent-editor-tool-grid">
|
||||||
<Form.Item label="工具集名称" name="name" rules={[{ required: true, message: '请输入工具集名称' }]}>
|
<Form.Item label="工具集名称" name="name" rules={[{ required: true, message: '请输入工具集名称' }]}>
|
||||||
<Input placeholder="例如:Hoyidata 工具集" />
|
<Input placeholder="例如:Hoyidata 工具集" />
|
||||||
|
|
@ -539,6 +573,30 @@ export default function ExternalToolEditor({ open, agentId, plugin, onClose, onS
|
||||||
</Space>
|
</Space>
|
||||||
)}
|
)}
|
||||||
</Form.List>
|
</Form.List>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'json',
|
||||||
|
label: 'JSON 编辑',
|
||||||
|
children: (
|
||||||
|
<div style={{ padding: '4px 0 16px' }}>
|
||||||
|
<div style={{ marginBottom: 8, color: '#666', fontSize: 12 }}>
|
||||||
|
提示:您可以直接编辑下方 JSON 内容,可视化表单将自动同步更新。
|
||||||
|
</div>
|
||||||
|
<Input.TextArea
|
||||||
|
value={jsonContent}
|
||||||
|
onChange={handleJsonChange}
|
||||||
|
rows={25}
|
||||||
|
className="agent-editor-code-input"
|
||||||
|
placeholder="请输入完整的工具集配置 JSON"
|
||||||
|
style={{ fontFamily: 'monospace' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue