Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

popover.tsx 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. import { useFetchFlow } from '@/hooks/flow-hooks';
  2. import get from 'lodash/get';
  3. import React, {
  4. MouseEventHandler,
  5. useCallback,
  6. useMemo,
  7. useState,
  8. } from 'react';
  9. import JsonView from 'react18-json-view';
  10. import 'react18-json-view/src/style.css';
  11. import { useReplaceIdWithText } from '../../hooks';
  12. import {
  13. Popover,
  14. PopoverContent,
  15. PopoverTrigger,
  16. } from '@/components/ui/popover';
  17. import {
  18. Table,
  19. TableBody,
  20. TableCell,
  21. TableHead,
  22. TableHeader,
  23. TableRow,
  24. } from '@/components/ui/table';
  25. import { useTranslate } from '@/hooks/common-hooks';
  26. import {
  27. Button,
  28. Card,
  29. Col,
  30. Input,
  31. Row,
  32. Space,
  33. Tabs,
  34. Typography,
  35. message,
  36. } from 'antd';
  37. import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query';
  38. interface IProps extends React.PropsWithChildren {
  39. nodeId: string;
  40. name?: string;
  41. }
  42. export function NextNodePopover({ children, nodeId, name }: IProps) {
  43. const { t } = useTranslate('flow');
  44. const { data } = useFetchFlow();
  45. console.log(data);
  46. const component = useMemo(() => {
  47. return get(data, ['dsl', 'components', nodeId], {});
  48. }, [nodeId, data]);
  49. const inputs: Array<{ component_id: string; content: string }> = get(
  50. component,
  51. ['obj', 'inputs'],
  52. [],
  53. );
  54. const output = get(component, ['obj', 'output'], {});
  55. const { conf, messages, prompt } = get(
  56. component,
  57. ['obj', 'params', 'infor'],
  58. {},
  59. );
  60. const { replacedOutput } = useReplaceIdWithText(output);
  61. const stopPropagation: MouseEventHandler = useCallback((e) => {
  62. e.stopPropagation();
  63. }, []);
  64. const getLabel = useGetComponentLabelByValue(nodeId);
  65. const [inputPage, setInputPage] = useState(1);
  66. const pageSize = 3;
  67. const pagedInputs = inputs.slice(
  68. (inputPage - 1) * pageSize,
  69. inputPage * pageSize,
  70. );
  71. return (
  72. <Popover>
  73. <PopoverTrigger onClick={stopPropagation} asChild>
  74. {children}
  75. </PopoverTrigger>
  76. <PopoverContent
  77. align={'start'}
  78. side={'right'}
  79. sideOffset={20}
  80. onClick={stopPropagation}
  81. className="w-[800px] p-4"
  82. style={{ maxHeight: 600, overflow: 'auto' }}
  83. >
  84. <Card
  85. bordered={false}
  86. style={{ marginBottom: 16, padding: 0 }}
  87. bodyStyle={{ padding: 0 }}
  88. >
  89. <Typography.Title
  90. level={5}
  91. style={{
  92. marginBottom: 16,
  93. fontWeight: 600,
  94. fontSize: 18,
  95. borderBottom: '1px solid #f0f0f0',
  96. paddingBottom: 8,
  97. }}
  98. >
  99. {name} {t('operationResults')}
  100. </Typography.Title>
  101. </Card>
  102. <Tabs
  103. defaultActiveKey="input"
  104. items={[
  105. {
  106. key: 'input',
  107. label: t('input'),
  108. children: (
  109. <Card
  110. size="small"
  111. className="bg-gray-50 dark:bg-gray-800"
  112. style={{ borderRadius: 8, border: '1px solid #e5e7eb' }}
  113. bodyStyle={{ padding: 16 }}
  114. >
  115. <Table>
  116. <TableHeader>
  117. <TableRow>
  118. <TableHead>{t('componentId')}</TableHead>
  119. <TableHead className="w-[60px]">
  120. {t('content')}
  121. </TableHead>
  122. </TableRow>
  123. </TableHeader>
  124. <TableBody>
  125. {pagedInputs.map((x, idx) => (
  126. <TableRow key={idx + (inputPage - 1) * pageSize}>
  127. <TableCell>{getLabel(x.component_id)}</TableCell>
  128. <TableCell className="truncate">
  129. {x.content}
  130. </TableCell>
  131. </TableRow>
  132. ))}
  133. </TableBody>
  134. </Table>
  135. {/* Pagination */}
  136. {inputs.length > pageSize && (
  137. <Row justify="end" style={{ marginTop: 8 }}>
  138. <Space>
  139. <Button
  140. size="small"
  141. disabled={inputPage === 1}
  142. onClick={() => setInputPage(inputPage - 1)}
  143. >
  144. Prev
  145. </Button>
  146. <span className="mx-2 text-sm">
  147. {inputPage} / {Math.ceil(inputs.length / pageSize)}
  148. </span>
  149. <Button
  150. size="small"
  151. disabled={
  152. inputPage === Math.ceil(inputs.length / pageSize)
  153. }
  154. onClick={() => setInputPage(inputPage + 1)}
  155. >
  156. Next
  157. </Button>
  158. </Space>
  159. </Row>
  160. )}
  161. </Card>
  162. ),
  163. },
  164. {
  165. key: 'output',
  166. label: t('output'),
  167. children: (
  168. <Card
  169. size="small"
  170. className="bg-gray-50 dark:bg-gray-800"
  171. style={{ borderRadius: 8, border: '1px solid #e5e7eb' }}
  172. bodyStyle={{ padding: 16 }}
  173. >
  174. <JsonView
  175. src={replacedOutput}
  176. displaySize={30}
  177. className="w-full max-h-[300px] break-words overflow-auto"
  178. />
  179. </Card>
  180. ),
  181. },
  182. {
  183. key: 'infor',
  184. label: t('infor'),
  185. children: (
  186. <Card
  187. size="small"
  188. className="bg-gray-50 dark:bg-gray-800"
  189. style={{ borderRadius: 8, border: '1px solid #e5e7eb' }}
  190. bodyStyle={{ padding: 16 }}
  191. >
  192. <Row gutter={16}>
  193. <Col span={12}>
  194. {conf && (
  195. <Card
  196. size="small"
  197. bordered={false}
  198. style={{
  199. marginBottom: 16,
  200. background: 'transparent',
  201. }}
  202. bodyStyle={{ padding: 0 }}
  203. >
  204. <Typography.Text
  205. strong
  206. style={{
  207. color: '#888',
  208. marginBottom: 8,
  209. display: 'block',
  210. }}
  211. >
  212. Configuration:
  213. </Typography.Text>
  214. <JsonView
  215. src={conf}
  216. displaySize={30}
  217. className="w-full max-h-[120px] break-words overflow-auto"
  218. />
  219. </Card>
  220. )}
  221. {prompt && (
  222. <Card
  223. size="small"
  224. bordered={false}
  225. style={{ background: 'transparent' }}
  226. bodyStyle={{ padding: 0 }}
  227. >
  228. <Row
  229. align="middle"
  230. justify="space-between"
  231. style={{ marginBottom: 8 }}
  232. >
  233. <Col>
  234. <Typography.Text strong style={{ color: '#888' }}>
  235. Prompt:
  236. </Typography.Text>
  237. </Col>
  238. <Col>
  239. <Button
  240. size="small"
  241. onClick={() => {
  242. const inlineString = prompt
  243. .replace(/\s+/g, ' ')
  244. .trim();
  245. navigator.clipboard.writeText(inlineString);
  246. message.success(
  247. 'Prompt copied as single line!',
  248. );
  249. }}
  250. >
  251. Copy as single line
  252. </Button>
  253. </Col>
  254. </Row>
  255. <Input.TextArea
  256. value={prompt}
  257. readOnly
  258. autoSize={{ minRows: 2, maxRows: 6 }}
  259. className="bg-white dark:bg-gray-900 border-gray-200 dark:border-gray-700"
  260. />
  261. </Card>
  262. )}
  263. </Col>
  264. <Col span={12}>
  265. {messages && (
  266. <Card
  267. size="small"
  268. bordered={false}
  269. style={{
  270. marginBottom: 16,
  271. background: 'transparent',
  272. }}
  273. bodyStyle={{ padding: 0 }}
  274. >
  275. <Typography.Text
  276. strong
  277. style={{
  278. color: '#888',
  279. marginBottom: 8,
  280. display: 'block',
  281. }}
  282. >
  283. Messages:
  284. </Typography.Text>
  285. <div className="max-h-[300px] overflow-auto">
  286. <JsonView
  287. src={messages}
  288. displaySize={30}
  289. className="w-full break-words"
  290. />
  291. </div>
  292. </Card>
  293. )}
  294. </Col>
  295. </Row>
  296. </Card>
  297. ),
  298. },
  299. ]}
  300. />
  301. </PopoverContent>
  302. </Popover>
  303. );
  304. }