+ ?
+ {/*
*/}
diff --git a/web/src/views/ApplicationConfig/components/FunConfig/FileUploadSettingModal.tsx b/web/src/views/ApplicationConfig/components/FunConfig/FileUploadSettingModal.tsx
new file mode 100644
index 00000000..3d114600
--- /dev/null
+++ b/web/src/views/ApplicationConfig/components/FunConfig/FileUploadSettingModal.tsx
@@ -0,0 +1,182 @@
+/*
+ * @Author: ZhaoYing
+ * @Date: 2026-03-05
+ * @Last Modified by: ZhaoYing
+ * @Last Modified time: 2026-03-11 15:42:13
+ */
+import { forwardRef, useImperativeHandle, useState } from 'react';
+import { Form, Radio, InputNumber, Flex, Switch, Row, Col } from 'antd';
+import { useTranslation } from 'react-i18next';
+import clsx from 'clsx';
+
+import RbModal from '@/components/RbModal';
+import type { FunConfigForm } from '../../types'
+
+interface FileUploadSettingModalRef {
+ handleOpen: (values?: FileUploadSettings) => void;
+ handleClose: () => void;
+}
+
+interface FileUploadSettings extends Omit
{}
+
+interface FileUploadSettingModalProps {
+ onSave: (values: FileUploadSettings) => void;
+}
+
+const fileTypeOptions = [
+ {
+ type: 'document',
+ icon: ,
+ formats: 'TXT, MD, MDX, MARKDOWN, PDF, DOC, DOCX',
+ defaultMaxCount: 1,
+ defaultMaxSize: 2
+ },
+ {
+ type: 'image',
+ icon: ,
+ formats: 'JPG, JPEG, PNG, GIF, WEBP, SVG',
+ defaultMaxCount: 1,
+ defaultMaxSize: 2
+ },
+ {
+ type: 'audio',
+ icon: ,
+ formats: 'MP3, M4A, WAV, AMR, MPGA',
+ defaultMaxCount: 1,
+ defaultMaxSize: 2
+ },
+ {
+ type: 'video',
+ icon: ,
+ formats: 'MP4, MOV, MPEG, WEBM',
+ defaultMaxCount: 1,
+ defaultMaxSize: 2
+ },
+];
+
+const FileUploadSettingModal = forwardRef(({
+ onSave,
+}, ref) => {
+ const { t } = useTranslation();
+ const [visible, setVisible] = useState(false);
+ const [form] = Form.useForm();
+ const values = Form.useWatch([], form)
+
+ const handleClose = () => {
+ setVisible(false);
+ form.resetFields();
+ };
+
+ const handleOpen = (values?: FileUploadSettings) => {
+ setVisible(true);
+ // if (values) {
+ // form.setFieldsValue(values);
+ // }
+ };
+
+ const handleSave = async () => {
+ const values = await form.validateFields();
+ onSave(values);
+ handleClose();
+ };
+
+ useImperativeHandle(ref, () => ({
+ handleOpen,
+ handleClose
+ }));
+
+
+ return (
+
+
+
+ {t('application.local')}
+ URL
+ {t('application.both')}
+
+
+ {t('application.maxCount')}
+
+
+
+
+
+
+ {(fields) => (
+
+ {fields.map((field, index) => {
+ const option = fileTypeOptions[index];
+ const isEnabled = values?.fileTypes?.[index]?.enabled;
+
+ return (
+
+
+
+ {option.icon}
+
+
+
+
+ {t(`application.${option.type}`)}
+ {option.formats}
+
+
+
+
+
+
+
+ {isEnabled && (
+
+ {t('application.singleMaxSize')}:
+
+
+
+
+ )}
+
+
+
+
+ );
+ })}
+
+ )}
+
+
+
+
+ );
+});
+
+export default FileUploadSettingModal;
diff --git a/web/src/views/ApplicationConfig/components/FunConfig/FunConfigModal.tsx b/web/src/views/ApplicationConfig/components/FunConfig/FunConfigModal.tsx
new file mode 100644
index 00000000..affa4e63
--- /dev/null
+++ b/web/src/views/ApplicationConfig/components/FunConfig/FunConfigModal.tsx
@@ -0,0 +1,140 @@
+/*
+ * @Author: ZhaoYing
+ * @Date: 2026-02-03 16:27:56
+ * @Last Modified by: ZhaoYing
+ * @Last Modified time: 2026-03-13 17:20:30
+ */
+/**
+ * Copy Application Modal
+ * Allows users to duplicate an existing application with a new name
+ */
+
+import { forwardRef, useImperativeHandle, useState, useRef } from 'react';
+import { Form, Button, Flex } from 'antd';
+import { useTranslation } from 'react-i18next';
+
+import type { FunConfigModalRef } from '../../types'
+import RbModal from '@/components/RbModal'
+import type { FunConfigForm } from '../../types'
+import SwitchFormItem from '@/components/FormItem/SwitchFormItem'
+import FileUploadSettingModal from './FileUploadSettingModal'
+
+const FormItem = Form.Item;
+
+interface FunConfigModalProps {
+ refresh: (value: FunConfigForm) => void;
+}
+
+/**
+ * Modal for copying applications
+ */
+const FunConfigModal = forwardRef(({
+ refresh,
+}, ref) => {
+ const { t } = useTranslation();
+ const [visible, setVisible] = useState(false);
+ const [form] = Form.useForm();
+ const [loading, setLoading] = useState(false)
+ const values = Form.useWatch([], form)
+ const fileUploadSettingModalRef = useRef(null)
+
+ /** Close modal and reset form */
+ const handleClose = () => {
+ setVisible(false);
+ form.resetFields();
+ setLoading(false)
+ };
+
+ /** Open modal */
+ const handleOpen = (initValue: FunConfigForm) => {
+ setVisible(true);
+ form.setFieldsValue(initValue)
+ };
+ /** Copy application with new name */
+ const handleSave = () => {
+ setVisible(false);
+ setLoading(true)
+ const values = form.getFieldsValue()
+ refresh(values)
+ }
+
+ const handleOpenSettings = () => {
+ fileUploadSettingModalRef.current?.handleOpen(values)
+ }
+
+ const handleSaveSettings = (settings: any) => {
+ form.setFieldsValue(settings)
+ }
+
+ /** Expose methods to parent component */
+ useImperativeHandle(ref, () => ({
+ handleOpen,
+ handleClose
+ }));
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+});
+
+export default FunConfigModal;
\ No newline at end of file
diff --git a/web/src/views/ApplicationConfig/components/FunConfig/index.tsx b/web/src/views/ApplicationConfig/components/FunConfig/index.tsx
new file mode 100644
index 00000000..7242acee
--- /dev/null
+++ b/web/src/views/ApplicationConfig/components/FunConfig/index.tsx
@@ -0,0 +1,50 @@
+/*
+ * @Author: ZhaoYing
+ * @Date: 2026-03-13 17:20:21
+ * @Last Modified by: ZhaoYing
+ * @Last Modified time: 2026-03-13 17:20:21
+ */
+import { type FC, useRef } from 'react';
+import { useTranslation } from 'react-i18next';
+import { Button } from 'antd';
+
+import FunConfigModal from './FunConfigModal'
+import type { FunConfigModalRef, FunConfigForm } from '../../types'
+
+/** Props for the FunConfig component */
+interface FunConfigProps {
+ /** Current feature configuration values */
+ value: FunConfigForm;
+ /** Callback to propagate updated config back to the parent */
+ refresh: (value: FunConfigForm) => void;
+}
+
+const FunConfig: FC = ({
+ value,
+ refresh
+}) => {
+ const { t } = useTranslation();
+ // Ref used to imperatively open the config modal
+ const funConfigModalRef = useRef(null)
+
+ /** Open the feature config modal pre-populated with the current values */
+ const handleFunConfig = () => {
+ console.log('funConfig', value)
+ funConfigModalRef.current?.handleOpen(value)
+ }
+
+ return (
+ <>
+ {/* Button that triggers the feature configuration modal */}
+
+
+ {/* Modal for editing feature settings; calls refresh on save */}
+
+ >
+ )
+}
+
+export default FunConfig
diff --git a/web/src/views/ApplicationConfig/index.tsx b/web/src/views/ApplicationConfig/index.tsx
index df5dbd59..fb6c7b54 100644
--- a/web/src/views/ApplicationConfig/index.tsx
+++ b/web/src/views/ApplicationConfig/index.tsx
@@ -1,22 +1,24 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 16:29:37
- * @Last Modified by: ZhaoYing
- * @Last Modified time: 2026-02-03 16:29:37
+ * @Last Modified by: ZhaoYing
+ * @Last Modified time: 2026-03-12 10:23:18
*/
import React, { useEffect, useState, useRef } from 'react';
import { useParams } from 'react-router-dom';
import ConfigHeader from './components/ConfigHeader'
-import type { AgentRef, ClusterRef, WorkflowRef } from './types'
+import type { AgentRef, ClusterRef, WorkflowRef, Config } from './types'
import type { Application } from '@/views/ApplicationManagement/types'
import Agent from './Agent'
import Api from './Api'
import ReleasePage from './ReleasePage'
import Cluster from './Cluster'
-import { getApplication } from '@/api/application'
+import { getApplication, getApplicationConfig, getMultiAgentConfig, getWorkflowConfig } from '@/api/application'
import Workflow from '@/views/Workflow';
import Statistics from './Statistics'
+import TestChat from './TestChat'
+import type { WorkflowConfig } from '@/views/Workflow/types';
/**
* Application configuration page component
@@ -25,7 +27,7 @@ import Statistics from './Statistics'
*/
const ApplicationConfig: React.FC = () => {
// Hooks
- const { id } = useParams();
+ const { id, source } = useParams();
// Refs for different application types
const agentRef = useRef(null)
@@ -36,6 +38,31 @@ const ApplicationConfig: React.FC = () => {
const [application, setApplication] = useState(null);
const [activeTab, setActiveTab] = useState('arrangement');
+ useEffect(() => {
+ setActiveTab(source === 'sharing' ? 'test' : 'arrangement')
+ }, [source])
+
+ const [config, setConfig] = useState(null)
+ useEffect(() => {
+ if (source === 'sharing' && application?.type) {
+ getAppConfig()
+ }
+ }, [source, application?.type])
+
+ const getAppConfig = () => {
+ if (!id || !source || !application?.type) {
+ return
+ }
+ const request = application?.type === 'agent'
+ ? getApplicationConfig
+ : application?.type === 'multi_agent'
+ ? getMultiAgentConfig
+ : getWorkflowConfig
+ request(id as string).then(res => {
+ setConfig(res as Config | WorkflowConfig | null)
+ })
+ }
+
/**
* Handle tab change with auto-save for arrangement tab
* @param key - New tab key
@@ -94,6 +121,7 @@ const ApplicationConfig: React.FC = () => {
{activeTab === 'api' && }
{activeTab === 'release' && }
{activeTab === 'statistics' && }
+ {activeTab === 'test' && }
>
);
};
diff --git a/web/src/views/ApplicationConfig/types.ts b/web/src/views/ApplicationConfig/types.ts
index 36d40a40..859d6fdf 100644
--- a/web/src/views/ApplicationConfig/types.ts
+++ b/web/src/views/ApplicationConfig/types.ts
@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:29:49
* @Last Modified by: ZhaoYing
- * @Last Modified time: 2026-02-28 16:40:30
+ * @Last Modified time: 2026-03-13 17:01:04
*/
import type { KnowledgeConfig } from './components/Knowledge/types'
import type { Variable } from './components/VariableList/types'
@@ -77,6 +77,8 @@ export interface Config extends MultiAgentConfig {
/** Last update timestamp */
updated_at: number;
skills?: SkillConfigForm | null;
+
+ funConfig?: FunConfigForm;
}
/**
@@ -127,6 +129,8 @@ export interface AgentRef {
* @param flag - Whether to show success message
*/
handleSave: (flag?: boolean) => Promise;
+ funConfig: Config['funConfig'];
+ handleSaveFunConfig?: (value: FunConfigForm) => void;
}
/**
@@ -138,6 +142,8 @@ export interface ClusterRef {
* @param flag - Whether to show success message
*/
handleSave: (flag?: boolean) => Promise;
+ funConfig: Config['funConfig'];
+ handleSaveFunConfig?: (value: FunConfigForm) => void;
}
/**
@@ -156,6 +162,8 @@ export interface WorkflowRef {
/** Add variable */
addVariable: () => void;
config: WorkflowConfig | null;
+ funConfig: WorkflowConfig['funConfig'];
+ handleSaveFunConfig?: (value: FunConfigForm) => void;
}
/**
@@ -400,4 +408,34 @@ export interface StatisticsData {
total_api_calls: number;
/** Total tokens used */
total_tokens: number;
+}
+
+export interface FileTypeConfig {
+ type: string;
+ enabled: boolean;
+ maxCount: number;
+ maxSize: number;
+}
+export interface FunConfigForm {
+ enabled: boolean;
+ fileTypes: FileTypeConfig[]
+ uploadType: 'local' | 'url' | 'both';
+}
+/**
+ * Function config modal ref methods
+ */
+export interface FunConfigModalRef {
+ /** Open function config modal */
+ handleOpen: (value: FunConfigForm) => void;
+}
+
+/**
+ * App sharing modal ref methods
+ */
+export interface AppSharingModalRef {
+ handleOpen: () => void;
+}
+export interface AppSharingForm {
+ target_workspace_ids: string[];
+ permission: 'readonly' | 'editable'
}
\ No newline at end of file
diff --git a/web/src/views/ApplicationManagement/MySharing.tsx b/web/src/views/ApplicationManagement/MySharing.tsx
new file mode 100644
index 00000000..54e501ca
--- /dev/null
+++ b/web/src/views/ApplicationManagement/MySharing.tsx
@@ -0,0 +1,158 @@
+/*
+ * @Author: ZhaoYing
+ * @Date: 2026-02-03 16:34:12
+ * @Last Modified by: ZhaoYing
+ * @Last Modified time: 2026-03-13 17:36:16
+ */
+import React, { useState, useEffect, useMemo } from 'react';
+import { useTranslation } from 'react-i18next';
+import { Button, App, Flex, Row, Col, Collapse } from 'antd';
+import clsx from 'clsx';
+
+import type { MySharedOutItem } from './types';
+import { mySharedOutList, cancelShare, cancelSpaceShare } from '@/api/application'
+
+const MySharing: React.FC = () => {
+ const { t } = useTranslation();
+ const { modal } = App.useApp();
+ const [data, setData] = useState([])
+
+ useEffect(() => { getList() }, [])
+
+ const getList = () => {
+ mySharedOutList().then(res => setData(res as MySharedOutItem[]))
+ }
+
+ /** Group items by target_workspace_id */
+ const grouped = useMemo(() => {
+ const map = new Map, items: MySharedOutItem[] }>();
+ data.forEach(item => {
+ if (!map.has(item.target_workspace_id)) {
+ map.set(item.target_workspace_id, {
+ workspace: {
+ target_workspace_id: item.target_workspace_id,
+ target_workspace_name: item.target_workspace_name,
+ target_workspace_icon: item.target_workspace_icon,
+ },
+ items: [],
+ });
+ }
+ map.get(item.target_workspace_id)!.items.push(item);
+ });
+ return Array.from(map.values());
+ }, [data]);
+
+ const handleAllCancel = (workspace: { target_workspace_name: string; target_workspace_id: string; }) => {
+ modal.confirm({
+ title: t('application.confirmWorkspaceCancelShareDesc', { workspace: workspace.target_workspace_name }),
+ okText: t('common.confirm'),
+ cancelText: t('common.cancel'),
+ okType: 'danger',
+ onOk: () => {
+ cancelSpaceShare(workspace.target_workspace_id)
+ .then(() => {
+ getList();
+ })
+ }
+ });
+ };
+
+ const handleCancelOne = (item: MySharedOutItem) => {
+ modal.confirm({
+ title: t('application.confirmAppCancelShareDesc', { app: item.source_app_name, workspace: item.target_workspace_name }),
+ okText: t('common.confirm'),
+ cancelText: t('common.cancel'),
+ okType: 'danger',
+ onOk: () => {
+ cancelShare(item.source_app_id, item.target_workspace_id)
+ .then(() => {
+ getList();
+ })
+ }
+ });
+ };
+
+ return (
+
+ {grouped.map(({ workspace, items }) => (
+
+ {workspace.target_workspace_icon
+ ?
+ :
+ {workspace.target_workspace_name[0]}
+
+ }
+
+
{workspace.target_workspace_name}
+
{t('application.appCount', { count: items.length })}
+
+
+ ),
+ extra: (
+
+ ),
+ children: (
+
+ {items.map(item => (
+
+ handleCancelOne(item)}
+ />
+
+
+ {item.source_app_name[0]}
+
+ {item.source_app_name}
+
+
+
+ {t('application.type')}
+
+ {t(`application.${item.source_app_type}`)}
+
+
+
+ {t('application.version')}
+ {item.source_app_version}
+
+
+ {t('application.permission')}
+
+ {t(`application.${item.permission}`)}
+
+
+
+ {t('application.souceStatus')}
+ {item.source_app_is_active ? t('application.sourceActive') : t('application.sourceInactive')}
+
+
+
+ ))}
+
+ ),
+ }]}
+ />
+ ))}
+
+ );
+};
+
+export default MySharing;
diff --git a/web/src/views/ApplicationManagement/components/UploadModal.tsx b/web/src/views/ApplicationManagement/components/UploadModal.tsx
index f354c145..a7acc093 100644
--- a/web/src/views/ApplicationManagement/components/UploadModal.tsx
+++ b/web/src/views/ApplicationManagement/components/UploadModal.tsx
@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-28 14:08:14
* @Last Modified by: ZhaoYing
- * @Last Modified time: 2026-03-06 12:05:46
+ * @Last Modified time: 2026-03-12 17:19:46
*/
/**
* UploadModal Component
@@ -63,6 +63,7 @@ const UploadModal = forwardRef
(({
* Resets all states and form fields
*/
const handleClose = () => {
+ refresh()
setVisible(false);
form.resetFields();
setCurrent(0);
@@ -211,7 +212,6 @@ const UploadModal = forwardRef(({
fileSize={100}
maxCount={1}
fileType={['yml']}
- draggerHeight={200}
/>
diff --git a/web/src/views/ApplicationManagement/components/UploadWorkflowModal.tsx b/web/src/views/ApplicationManagement/components/UploadWorkflowModal.tsx
index e1353843..a4adf0c5 100644
--- a/web/src/views/ApplicationManagement/components/UploadWorkflowModal.tsx
+++ b/web/src/views/ApplicationManagement/components/UploadWorkflowModal.tsx
@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-28 14:08:14
* @Last Modified by: ZhaoYing
- * @Last Modified time: 2026-03-06 12:05:46
+ * @Last Modified time: 2026-03-12 17:19:33
*/
/**
* UploadWorkflowModal Component
@@ -72,6 +72,7 @@ const UploadWorkflowModal = forwardRef {
const { t } = useTranslation();
const { modal } = App.useApp();
const [searchParams] = useSearchParams()
- const [query, setQuery] = useState({} as Query);
const applicationModalRef = useRef(null);
const scrollListRef = useRef(null)
const uploadWorkflowModalRef = useRef(null);
const uploadModalRef = useRef(null);
+ const [form] = Form.useForm()
+ const query = Form.useWatch([], form)
+ const [activeTab, setActiveTab] = useState('apps');
useEffect(() => {
// Convert URLSearchParams to a plain object for easier access
const data = Object.fromEntries(searchParams)
const { type } = data
- setQuery(prev => ({
- ...prev,
- type: type || undefined
- }))
+ form.setFieldValue('type', type || undefined)
}, [searchParams])
/** Refresh application list */
@@ -61,7 +64,11 @@ const ApplicationManagement: React.FC = () => {
}
/** Navigate to application configuration page */
const handleEdit = (item: Application) => {
- window.open(`/#/application/config/${item.id}`);
+ let url = `/#/application/config/${item.id}`
+ if (item.is_shared) {
+ url += `/${activeTab}`
+ }
+ window.open(url);
}
/** Delete application with confirmation */
const handleDelete = (item: Application) => {
@@ -81,9 +88,6 @@ const ApplicationManagement: React.FC = () => {
}
})
}
- const handleChangeType = (value?: string) => {
- setQuery(prev => ({...prev, type: value}))
- }
const handleImport = () => {
uploadWorkflowModalRef.current?.handleOpen()
@@ -97,90 +101,137 @@ const ApplicationManagement: React.FC = () => {
uploadModalRef.current?.handleOpen()
}
}
+ const formatTabItems = useMemo(() => {
+ return tabKeys.map(value => ({
+ value,
+ label: t(`application.${value}`),
+ }))
+ }, [tabKeys, t])
+ /** Handle tab change */
+ const handleChangeTab = (value: SegmentedProps['value']) => {
+ setActiveTab(value as string);
+ form.resetFields()
+ }
+ const handleCopy = (item: Application) => {
+ modal.confirm({
+ title: t('application.confirmCopyDesc', { app: item.name }),
+ okText: t('common.copy'),
+ cancelText: t('common.cancel'),
+ onOk: () => {
+ copyApplication(item.id)
+ .then(() => {
+ setActiveTab('apps')
+ })
+ }
+ });
+ }
return (
<>
-
-
-
+ }
>
-
-
-
-
-
-
-
-
- ref={scrollListRef}
- url={getApplicationListUrl}
- query={query}
- renderItem={(item) => (
-
- {item.name[0]}
-
- }
- >
- {['type', 'source', 'created_at'].map((key, index) => (
-
-
{t(`application.${key}`)}
-
(
+
- {key === 'source' && item.is_shared
- ? t('application.shared')
- : key === 'source' && !item.is_shared
- ? t('application.configuration')
- : key === 'created_at'
- ? formatDateTime(item.created_at, 'YYYY-MM-DD HH:mm:ss')
- : t(`application.${item[key as keyof Application]}`)
- }
-
-
- ))}
+ {t(`application.${key}`)}
+
+ {key === 'source' && item.is_shared
+ ? item.source_workspace_name
+ : key === 'source' && !item.is_shared
+ ? t('application.configuration')
+ : key === 'created_at'
+ ? formatDateTime(item.created_at, 'YYYY-MM-DD HH:mm:ss')
+ : t(`application.${item[key as keyof Application]}`)
+ }
+
+
+ ))}
-
-
- } onClick={() => handleDelete(item)}>
-
-
- )}
- />
+ {item.is_shared
+ ?
+
+ {item.share_permission === 'editable' && }
+
+ :
+
+ } onClick={() => handleDelete(item)}>
+
+ }
+
+ )}
+ />
+ }
+ {activeTab === 'myShare' &&
}
+
void;
+}
+export interface MySharedOutItem {
+ id: string;
+ source_app_id: string;
+ source_workspace_id: string;
+ target_workspace_id: string;
+ shared_by: string;
+ permission: 'readonly' | 'editable';
+ created_at: number;
+ updated_at: number;
+ source_app_name: string;
+ source_app_type: string;
+ source_app_version: string;
+ source_app_is_active: boolean;
+ target_workspace_name: string;
+ target_workspace_icon: string;
}
\ No newline at end of file
diff --git a/web/src/views/ToolManagement/Market.tsx b/web/src/views/ToolManagement/Market.tsx
index 351ae8b7..310637d7 100644
--- a/web/src/views/ToolManagement/Market.tsx
+++ b/web/src/views/ToolManagement/Market.tsx
@@ -255,6 +255,7 @@ const Market: React.FC<{ getStatusTag?: (status: string) => ReactNode }> = () =>
if (!source) return;
try {
const config: any = await getMarketConfig(sourceId);
+ console.log('获取到的配置数据:', config);
marketConfigModalRef.current?.handleOpen({
...source,
connected: config?.status === 1,
@@ -306,20 +307,8 @@ const Market: React.FC<{ getStatusTag?: (status: string) => ReactNode }> = () =>
}));
setConfigIdMap(prev => ({ ...prev, [sourceId]: configId }));
- // 用 configId 获取第一页 MCP 列表
- try {
- const res: any = await getMarketMCPs({ mcp_market_config_id: configId, page: 1, pagesize: pageSize });
- if (res?.items && Array.isArray(res.items)) {
- setMcpCache(prev => ({ ...prev, [sourceId]: res.items }));
- }
- if (res?.page) {
- setMcpTotal(res.page.total || 0);
- setHasMore(!!res.page.has_next);
- setCurrentPage(1);
- }
- } catch (error) {
- console.error('获取 MCP 列表失败:', error);
- }
+ // 使用 fetchMcpList 获取完整的 MCP 列表(包含激活状态和入库状态)
+ await fetchMcpList(sourceId, 1);
};
const handleRefreshAfterAdd = async () => {
@@ -431,7 +420,7 @@ const Market: React.FC<{ getStatusTag?: (status: string) => ReactNode }> = () =>
dataLength={mcpList.length}
next={loadMore}
hasMore={hasMore}
- loader={}
+ loader={null}
scrollableTarget="mcpScrollableDiv"
>
(null);
const [showApiKey, setShowApiKey] = useState(false);
+ const [initialValues, setInitialValues] = useState<{ token: string }>({ token: '' });
+ const formValues = Form.useWatch([], form);
const handleClose = () => {
setVisible(false);
@@ -44,16 +46,29 @@ const MarketConfigModal = forwardRef
{
+ console.log('Modal 接收到的数据:', source);
setCurrentSource(source);
- form.setFieldsValue({
- token: source.token || '',
- });
+ setInitialValues({ token: source.token || '' });
setVisible(true);
};
+ const handleAfterOpenChange = (open: boolean) => {
+ if (open && currentSource) {
+ // Modal 完全打开后再设置表单值,使用 setTimeout 确保在下一个事件循环
+ setTimeout(() => {
+ form.setFieldsValue({
+ token: currentSource.token || '',
+ });
+ console.log('Modal 打开后设置表单值:', { token: currentSource.token || '' });
+ console.log('当前表单所有值:', form.getFieldsValue());
+ }, 100);
+ }
+ };
+
const handleSave = () => {
form
.validateFields()
@@ -101,6 +116,9 @@ const MarketConfigModal = forwardRef 0;
+
useImperativeHandle(ref, () => ({
handleOpen,
handleClose
@@ -113,9 +131,11 @@ const MarketConfigModal = forwardRef
@@ -147,8 +167,10 @@ const MarketConfigModal = forwardRef