| import { TaskExecutorHeartbeatItem } from '@/interfaces/database/user-setting'; | |
| import { Divider, Flex } from 'antd'; | |
| import { | |
| Bar, | |
| BarChart, | |
| CartesianGrid, | |
| Legend, | |
| Rectangle, | |
| ResponsiveContainer, | |
| Tooltip, | |
| XAxis, | |
| } from 'recharts'; | |
| import { formatDate, formatTime } from '@/utils/date'; | |
| import dayjs from 'dayjs'; | |
| import { get } from 'lodash'; | |
| import JsonView from 'react18-json-view'; | |
| import 'react18-json-view/src/style.css'; | |
| import styles from './index.less'; | |
| interface IProps { | |
| data: Record<string, TaskExecutorHeartbeatItem[]>; | |
| } | |
| const CustomTooltip = ({ active, payload, ...restProps }: any) => { | |
| if (active && payload && payload.length) { | |
| const taskExecutorHeartbeatItem: TaskExecutorHeartbeatItem = get( | |
| payload, | |
| '0.payload', | |
| {}, | |
| ); | |
| return ( | |
| <div className="custom-tooltip"> | |
| <div className="bg-slate-50 p-2 rounded-md border border-indigo-100"> | |
| <div className="font-semibold text-lg"> | |
| {formatDate(restProps.label)} | |
| </div> | |
| <JsonView | |
| src={taskExecutorHeartbeatItem} | |
| displaySize={30} | |
| className="w-full max-h-[300px] break-words overflow-auto" | |
| /> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| return null; | |
| }; | |
| const TaskBarChat = ({ data }: IProps) => { | |
| return Object.entries(data).map(([key, val]) => { | |
| const data = val.map((x) => ({ | |
| ...x, | |
| now: dayjs(x.now).valueOf(), | |
| })); | |
| const firstItem = data[0]; | |
| const lastItem = data[data.length - 1]; | |
| const domain = [firstItem?.now, lastItem?.now]; | |
| return ( | |
| <Flex key={key} className={styles.taskBar} vertical> | |
| <div className="flex gap-8"> | |
| <b className={styles.taskBarTitle}>ID: {key}</b> | |
| <b className={styles.taskBarTitle}>Lag: {lastItem?.lag}</b> | |
| <b className={styles.taskBarTitle}>Pending: {lastItem?.pending}</b> | |
| </div> | |
| <ResponsiveContainer> | |
| <BarChart data={data}> | |
| <XAxis | |
| dataKey="now" | |
| type="number" | |
| scale={'time'} | |
| domain={domain} | |
| tickFormatter={(x) => formatTime(x)} | |
| allowDataOverflow | |
| angle={60} | |
| padding={{ left: 20, right: 20 }} | |
| tickMargin={20} | |
| /> | |
| <CartesianGrid strokeDasharray="3 3" /> | |
| <Tooltip | |
| wrapperStyle={{ pointerEvents: 'auto' }} | |
| content={<CustomTooltip></CustomTooltip>} | |
| trigger="click" | |
| /> | |
| <Legend wrapperStyle={{ bottom: -22 }} /> | |
| <Bar | |
| dataKey="done" | |
| fill="#2fe235" | |
| activeBar={<Rectangle fill="pink" stroke="blue" />} | |
| /> | |
| <Bar | |
| dataKey="failed" | |
| fill="#ef3b74" | |
| activeBar={<Rectangle fill="gold" stroke="purple" />} | |
| /> | |
| </BarChart> | |
| </ResponsiveContainer> | |
| <Divider></Divider> | |
| </Flex> | |
| ); | |
| }); | |
| }; | |
| export default TaskBarChat; | |