import { apiInterceptors, getDbList, getDbSupportType, postDbDelete, postDbRefresh } from '@/client/api'; import GPTCard from '@/components/common/gpt-card'; import MuiLoading from '@/components/common/loading'; import FormDialog from '@/components/database/form-dialog'; import ConstructLayout from '@/new-components/layout/Construct'; import { DBOption, DBType, DbListResponse, DbSupportTypeResponse } from '@/types/db'; import { dbMapper } from '@/utils'; import { DeleteFilled, EditFilled, PlusOutlined, RedoOutlined } from '@ant-design/icons'; import { useAsyncEffect } from 'ahooks'; import { Badge, Button, Card, Drawer, Empty, Modal, Spin, message } from 'antd'; import { useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; type DBItem = DbListResponse[0]; export function isFileDb(dbTypeList: DBOption[], dbType: DBType) { return dbTypeList.find(item => item.value === dbType)?.isFileDb; } let getFromRenderData: any = []; function Database() { // const { setCurrentDialogInfo } = useContext(ChatContext); // unused // const router = useRouter(); // unused const { t } = useTranslation(); const [dbList, setDbList] = useState([]); const [dbSupportList, setDbSupportList] = useState([]); const [loading, setLoading] = useState(false); const [modal, setModal] = useState<{ open: boolean; info?: string; dbType?: DBType; dbTypeData?: any[]; description?: string; }>({ open: false }); const [draw, setDraw] = useState<{ open: boolean; dbList?: DbListResponse; name?: string; type?: DBType; }>({ open: false }); const [refreshLoading, setRefreshLoading] = useState(false); const getDbSupportList = async () => { const [, data] = await apiInterceptors(getDbSupportType()); setDbSupportList(data?.types ?? []); }; const refreshDbList = async () => { setLoading(true); const [, data] = await apiInterceptors(getDbList()); setDbList(data ?? []); setLoading(false); }; const dbTypeList = useMemo(() => { const supportDbList = dbSupportList.map(item => { const db_type = item?.name; return { ...dbMapper[db_type], value: db_type, isFileDb: true, parameters: item.parameters }; }) as DBOption[]; const unSupportDbList = Object.keys(dbMapper) .filter(item => !supportDbList.some(db => db.value === item)) .map(item => ({ ...dbMapper[item], value: dbMapper[item].label, disabled: true, })) as DBOption[]; return [...supportDbList, ...unSupportDbList]; }, [dbSupportList]); const onModify = (item: DBItem) => { for (let index = 0; index < getFromRenderData.length; index++) { const element = getFromRenderData[index]; if (item.params[element.param_name]) { element.default_value = item.params[element.param_name]; } } setModal({ open: true, info: item.id, dbType: item.type, description: item.description }); }; const onDelete = (item: DBItem) => { Modal.confirm({ title: 'Tips', content: `Do you Want to delete the database connection?`, onOk() { return new Promise((resolve, reject) => { handleDelete(item.id, resolve, reject); }); }, }); }; const handleDelete = async (id: string, resolve: () => void, reject: () => void) => { try { const [err] = await apiInterceptors(postDbDelete(id)); if (err) { message.error(err.message); reject(); return; } message.success('success'); refreshDbList(); resolve(); } catch { reject(); } }; const dbListByType = useMemo(() => { const mapper = dbTypeList.reduce( (acc, item) => { acc[item.value] = dbList.filter(dbConn => dbConn?.type.toLowerCase() === item.value.toLowerCase()); return acc; }, {} as Record, ); return mapper; }, [dbList, dbTypeList]); useAsyncEffect(async () => { await refreshDbList(); await getDbSupportList(); }, []); const handleDbTypeClick = (info: DBOption) => { const dbItems = dbList.filter(item => item.type === info.value); getFromRenderData = info?.parameters; setDraw({ open: true, dbList: dbItems, name: info.label, type: info.value, }); }; const onRefresh = async (item: DBItem) => { setRefreshLoading(true); const [, res] = await apiInterceptors(postDbRefresh({ id: item.id })); if (res) message.success(t('refreshSuccess')); setRefreshLoading(false); }; const getFileName = (path: string) => { if (!path) return ''; // Handle Windows and Unix style paths const parts = path.split(/[/\\]/); return parts[parts.length - 1]; }; return (
{dbTypeList.map(item => { return ( { if (item.disabled) return; handleDbTypeClick(item); }} /> ); })}
item.params.database)} onSuccess={() => { setModal({ open: false }); refreshDbList(); }} onClose={() => { setModal({ open: false }); }} /> { setDraw({ open: false }); }} open={draw.open} > {draw.type && dbListByType[draw.type] && dbListByType[draw.type].length ? ( {dbListByType[draw.type].map(item => ( { onRefresh(item); }} /> { onModify(item); }} /> { onDelete(item); }} /> } className='mb-4' > <> {['host', 'port', 'path', 'user', 'database', 'schema'] // Just handle these keys .filter(key => Object.prototype.hasOwnProperty.call(item.params, key)) .map(key => (

{key}: {key === 'path' ? getFileName(item.params[key]) : item.params[key]}

))}

{t('description')}: {item.description}

))}
) : ( )}
); } export default Database;