index.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import {
  2. apiInterceptors,
  3. postAgentHubUpdate,
  4. postAgentInstall,
  5. postAgentMy,
  6. postAgentQuery,
  7. postAgentUninstall,
  8. } from '@/client/api';
  9. import BlurredCard, { ChatButton } from '@/new-components/common/blurredCard';
  10. import ConstructLayout from '@/new-components/layout/Construct';
  11. import { IAgentPlugin, PostAgentQueryParams } from '@/types/agent';
  12. import { ClearOutlined, DownloadOutlined, SyncOutlined } from '@ant-design/icons';
  13. import { useRequest } from 'ahooks';
  14. import { Button, Segmented, SegmentedProps, Spin, Tag, message } from 'antd';
  15. import cls from 'classnames';
  16. import moment from 'moment';
  17. import { useCallback, useEffect, useMemo, useState } from 'react';
  18. import { useTranslation } from 'react-i18next';
  19. // import MyPlugins from '@/components/agent/my-plugins';
  20. // import MarketPlugins from '@/components/agent/market-plugins';
  21. function Agent() {
  22. const { t } = useTranslation();
  23. const [searchValue] = useState('');
  24. const [activeKey, setActiveKey] = useState<string>('market');
  25. const [uploading, setUploading] = useState(false);
  26. const [_, setIsError] = useState(false);
  27. const [actionIndex, setActionIndex] = useState<number | undefined>();
  28. const pagination = useMemo<{ pageNo: number; pageSize: number }>(
  29. () => ({
  30. pageNo: 1,
  31. pageSize: 20,
  32. }),
  33. [],
  34. );
  35. const {
  36. data: agents = [],
  37. loading,
  38. refresh,
  39. } = useRequest<IAgentPlugin[], []>(
  40. async () => {
  41. if (activeKey === 'my') {
  42. const [err, res] = await apiInterceptors(postAgentMy());
  43. setIsError(!!err);
  44. return res ?? [];
  45. }
  46. const queryParams: PostAgentQueryParams = {
  47. page_index: pagination.pageNo,
  48. page_size: pagination.pageSize,
  49. filter: {
  50. name: searchValue || undefined,
  51. },
  52. };
  53. const [err, res] = await apiInterceptors(postAgentQuery(queryParams));
  54. setIsError(!!err);
  55. return res?.datas ?? [];
  56. },
  57. {
  58. manual: true,
  59. },
  60. );
  61. const updateFromGithub = async () => {
  62. try {
  63. setUploading(true);
  64. const [err] = await apiInterceptors(postAgentHubUpdate());
  65. if (err) return;
  66. message.success('success');
  67. refresh();
  68. } finally {
  69. setUploading(false);
  70. }
  71. };
  72. useEffect(() => {
  73. refresh();
  74. }, [activeKey]);
  75. const pluginAction = useCallback(
  76. async (name: string, index: number, isInstall: boolean) => {
  77. if (actionIndex) return;
  78. setActionIndex(index);
  79. const [err] = await apiInterceptors((isInstall ? postAgentInstall : postAgentUninstall)(name));
  80. if (!err) {
  81. message.success('success');
  82. refresh();
  83. }
  84. setActionIndex(undefined);
  85. },
  86. [actionIndex, refresh],
  87. );
  88. const items: SegmentedProps['options'] = [
  89. {
  90. value: 'market',
  91. label: t('Market_Plugins'),
  92. },
  93. {
  94. value: 'my',
  95. label: t('My_Plugins'),
  96. },
  97. ];
  98. return (
  99. <ConstructLayout>
  100. <div className='px-6'>
  101. <Spin spinning={loading}>
  102. <div className='flex justify-between items-center mb-6'>
  103. <div className='flex items-center gap-4'>
  104. <Segmented
  105. className='backdrop-filter backdrop-blur-lg bg-white bg-opacity-30 border-2 border-white rounded-lg shadow p-1 dark:border-[#6f7f95] dark:bg-[#6f7f95] dark:bg-opacity-60'
  106. options={items}
  107. onChange={key => {
  108. setActiveKey(key as string);
  109. }}
  110. value={activeKey}
  111. />
  112. {/* <Input
  113. variant="filled"
  114. prefix={<SearchOutlined />}
  115. placeholder={t('please_enter_the_keywords')}
  116. value={searchValue}
  117. onChange={(e) => setSearchValue(e.target.value)}
  118. onPressEnter={refresh}
  119. allowClear
  120. className="w-[230px] h-[40px] border-1 border-white backdrop-filter backdrop-blur-lg bg-white bg-opacity-30 dark:border-[#6f7f95] dark:bg-[#6f7f95] dark:bg-opacity-60"
  121. /> */}
  122. </div>
  123. <div className='flex items-center gap-4'>
  124. <Button
  125. className={cls('border-none text-white bg-button-gradient h-full', {
  126. 'opacity-40': false,
  127. })}
  128. loading={uploading}
  129. icon={<SyncOutlined />}
  130. onClick={updateFromGithub}
  131. >
  132. {t('Update_From_Github')}
  133. </Button>
  134. </div>
  135. </div>
  136. {agents.map((agent, index) => (
  137. <BlurredCard
  138. logo='/pictures/agent.png'
  139. onClick={() => {
  140. if (agent.storage_url) window.open(agent.storage_url, '_blank');
  141. }}
  142. description={agent.description}
  143. name={agent.name}
  144. key={agent.id}
  145. Tags={
  146. <div>
  147. {agent.author && <Tag>{agent.author}</Tag>}
  148. {agent.version && <Tag>v{agent.version}</Tag>}
  149. {agent.type && <Tag>Type {agent.type}</Tag>}
  150. {agent.storage_channel && <Tag>{agent.storage_channel}</Tag>}
  151. </div>
  152. }
  153. LeftBottom={
  154. <div className='flex gap-2'>
  155. {agent.author && <span>{agent.author}</span>}
  156. {agent.author && <span>•</span>}
  157. {agent?.gmt_created && <span>{moment(agent?.gmt_created).fromNow() + ' ' + t('update')}</span>}
  158. </div>
  159. }
  160. RightBottom={
  161. agent.installed || activeKey == 'my' ? (
  162. <ChatButton
  163. Icon={<ClearOutlined />}
  164. text='Uninstall'
  165. onClick={() => {
  166. pluginAction(agent.name, index, false);
  167. }}
  168. />
  169. ) : (
  170. <ChatButton
  171. Icon={<DownloadOutlined />}
  172. text='Install'
  173. onClick={() => {
  174. pluginAction(agent.name, index, true);
  175. }}
  176. />
  177. )
  178. }
  179. />
  180. ))}
  181. {/* {activeKey !== 'market' ? <MyPlugins /> : <MarketPlugins />} */}
  182. </Spin>
  183. </div>
  184. </ConstructLayout>
  185. );
  186. }
  187. export default Agent;