mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-07-27 05:47:47 +00:00
Co-authored-by: Fangyin Cheng <staneyffer@gmail.com> Co-authored-by: 谨欣 <echo.cmy@antgroup.com> Co-authored-by: 严志勇 <yanzhiyong@tiansuixiansheng.com> Co-authored-by: yanzhiyong <932374019@qq.com>
125 lines
3.8 KiB
TypeScript
125 lines
3.8 KiB
TypeScript
import { apiInterceptors, postAgentMy, postAgentUninstall, postAgentUpload } from '@/client/api';
|
|
import { IMyPlugin } from '@/types/agent';
|
|
import { ClearOutlined, LoadingOutlined, UploadOutlined } from '@ant-design/icons';
|
|
import { useRequest } from 'ahooks';
|
|
import { Button, Card, Spin, Tag, Tooltip, Upload, UploadProps, message } from 'antd';
|
|
import { useCallback, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import MyEmpty from '../common/MyEmpty';
|
|
|
|
function MyPlugins() {
|
|
const { t } = useTranslation();
|
|
const [messageApi, contextHolder] = message.useMessage();
|
|
|
|
const [uploading, setUploading] = useState(false);
|
|
const [isError, setIsError] = useState(false);
|
|
const [actionIndex, setActionIndex] = useState<number | undefined>();
|
|
|
|
const {
|
|
data = [],
|
|
loading,
|
|
refresh,
|
|
} = useRequest(async () => {
|
|
const [err, res] = await apiInterceptors(postAgentMy());
|
|
setIsError(!!err);
|
|
return res ?? [];
|
|
});
|
|
|
|
const uninstall = async (name: string, index: number) => {
|
|
if (actionIndex) return;
|
|
setActionIndex(index);
|
|
const [err] = await apiInterceptors(postAgentUninstall(name));
|
|
message[err ? 'error' : 'success'](err ? 'failed' : 'success');
|
|
!err && refresh();
|
|
setActionIndex(undefined);
|
|
};
|
|
|
|
const renderAction = useCallback(
|
|
(item: IMyPlugin, index: number) => {
|
|
if (index === actionIndex) {
|
|
return <LoadingOutlined />;
|
|
}
|
|
return (
|
|
<Tooltip title='Uninstall'>
|
|
<div
|
|
className='w-full h-full'
|
|
onClick={() => {
|
|
uninstall(item.name, index);
|
|
}}
|
|
>
|
|
<ClearOutlined />
|
|
</div>
|
|
</Tooltip>
|
|
);
|
|
},
|
|
[actionIndex],
|
|
);
|
|
|
|
const onChange: UploadProps['onChange'] = async info => {
|
|
if (!info) {
|
|
message.error('Please select the *.zip,*.rar file');
|
|
return;
|
|
}
|
|
try {
|
|
const file = info.file;
|
|
setUploading(true);
|
|
const formData = new FormData();
|
|
formData.append('doc_file', file as any);
|
|
messageApi.open({ content: `Uploading ${file.name}`, type: 'loading', duration: 0 });
|
|
const [err] = await apiInterceptors(postAgentUpload(undefined, formData, { timeout: 60000 }));
|
|
if (err) return;
|
|
message.success('success');
|
|
refresh();
|
|
} catch (e: any) {
|
|
message.error(e?.message || 'Upload Error');
|
|
} finally {
|
|
setUploading(false);
|
|
messageApi.destroy();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Spin spinning={loading}>
|
|
{contextHolder}
|
|
<div>
|
|
<Upload
|
|
disabled={loading}
|
|
className='mr-1'
|
|
beforeUpload={() => false}
|
|
name='file'
|
|
accept='.zip,.rar'
|
|
multiple={false}
|
|
onChange={onChange}
|
|
showUploadList={{
|
|
showDownloadIcon: false,
|
|
showPreviewIcon: false,
|
|
showRemoveIcon: false,
|
|
}}
|
|
itemRender={() => <></>}
|
|
>
|
|
<Button loading={uploading} type='primary' icon={<UploadOutlined />}>
|
|
{t('Upload')}
|
|
</Button>
|
|
</Upload>
|
|
</div>
|
|
{!data.length && !loading && <MyEmpty error={isError} refresh={refresh} />}
|
|
<div className='flex gap-2 md:gap-4'>
|
|
{data.map((item, index) => (
|
|
<Card className='w-full md:w-1/2 lg:w-1/3 xl:w-1/4' key={item.id} actions={[renderAction(item, index)]}>
|
|
<Tooltip title={item.name}>
|
|
<h2 className='mb-2 text-base font-semibold line-clamp-1'>{item.name}</h2>
|
|
</Tooltip>
|
|
{item.version && <Tag>v{item.version}</Tag>}
|
|
{item.type && <Tag>Type {item.type}</Tag>}
|
|
<Tooltip title={item.description}>
|
|
<p className='mt-2 line-clamp-2 text-gray-400 text-sm'>{item.description}</p>
|
|
</Tooltip>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
</Spin>
|
|
);
|
|
}
|
|
|
|
export default MyPlugins;
|