my-plugins.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import { apiInterceptors, postAgentMy, postAgentUninstall, postAgentUpload } from '@/client/api';
  2. import { IMyPlugin } from '@/types/agent';
  3. import { ClearOutlined, LoadingOutlined, UploadOutlined } from '@ant-design/icons';
  4. import { useRequest } from 'ahooks';
  5. import { Button, Card, Spin, Tag, Tooltip, Upload, UploadProps, message } from 'antd';
  6. import { useCallback, useState } from 'react';
  7. import { useTranslation } from 'react-i18next';
  8. import MyEmpty from '../common/MyEmpty';
  9. function MyPlugins() {
  10. const { t } = useTranslation();
  11. const [messageApi, contextHolder] = message.useMessage();
  12. const [uploading, setUploading] = useState(false);
  13. const [isError, setIsError] = useState(false);
  14. const [actionIndex, setActionIndex] = useState<number | undefined>();
  15. const {
  16. data = [],
  17. loading,
  18. refresh,
  19. } = useRequest(async () => {
  20. const [err, res] = await apiInterceptors(postAgentMy());
  21. setIsError(!!err);
  22. return res ?? [];
  23. });
  24. const uninstall = async (name: string, index: number) => {
  25. if (actionIndex) return;
  26. setActionIndex(index);
  27. const [err] = await apiInterceptors(postAgentUninstall(name));
  28. message[err ? 'error' : 'success'](err ? 'failed' : 'success');
  29. !err && refresh();
  30. setActionIndex(undefined);
  31. };
  32. const renderAction = useCallback(
  33. (item: IMyPlugin, index: number) => {
  34. if (index === actionIndex) {
  35. return <LoadingOutlined />;
  36. }
  37. return (
  38. <Tooltip title='Uninstall'>
  39. <div
  40. className='w-full h-full'
  41. onClick={() => {
  42. uninstall(item.name, index);
  43. }}
  44. >
  45. <ClearOutlined />
  46. </div>
  47. </Tooltip>
  48. );
  49. },
  50. [actionIndex],
  51. );
  52. const onChange: UploadProps['onChange'] = async info => {
  53. if (!info) {
  54. message.error('Please select the *.zip,*.rar file');
  55. return;
  56. }
  57. try {
  58. const file = info.file;
  59. setUploading(true);
  60. const formData = new FormData();
  61. formData.append('doc_file', file as any);
  62. messageApi.open({ content: `Uploading ${file.name}`, type: 'loading', duration: 0 });
  63. const [err] = await apiInterceptors(postAgentUpload(undefined, formData, { timeout: 60000 }));
  64. if (err) return;
  65. message.success('success');
  66. refresh();
  67. } catch (e: any) {
  68. message.error(e?.message || 'Upload Error');
  69. } finally {
  70. setUploading(false);
  71. messageApi.destroy();
  72. }
  73. };
  74. return (
  75. <Spin spinning={loading}>
  76. {contextHolder}
  77. <div>
  78. <Upload
  79. disabled={loading}
  80. className='mr-1'
  81. beforeUpload={() => false}
  82. name='file'
  83. accept='.zip,.rar'
  84. multiple={false}
  85. onChange={onChange}
  86. showUploadList={{
  87. showDownloadIcon: false,
  88. showPreviewIcon: false,
  89. showRemoveIcon: false,
  90. }}
  91. itemRender={() => <></>}
  92. >
  93. <Button loading={uploading} type='primary' icon={<UploadOutlined />}>
  94. {t('Upload')}
  95. </Button>
  96. </Upload>
  97. </div>
  98. {!data.length && !loading && <MyEmpty error={isError} refresh={refresh} />}
  99. <div className='flex gap-2 md:gap-4'>
  100. {data.map((item, index) => (
  101. <Card className='w-full md:w-1/2 lg:w-1/3 xl:w-1/4' key={item.id} actions={[renderAction(item, index)]}>
  102. <Tooltip title={item.name}>
  103. <h2 className='mb-2 text-base font-semibold line-clamp-1'>{item.name}</h2>
  104. </Tooltip>
  105. {item.version && <Tag>v{item.version}</Tag>}
  106. {item.type && <Tag>Type {item.type}</Tag>}
  107. <Tooltip title={item.description}>
  108. <p className='mt-2 line-clamp-2 text-gray-400 text-sm'>{item.description}</p>
  109. </Tooltip>
  110. </Card>
  111. ))}
  112. </div>
  113. </Spin>
  114. );
  115. }
  116. export default MyPlugins;