Skip to content

Commit 96b5f06

Browse files
author
昔梦
committed
feat:xflow日志面板新增自定义功能
1 parent 9bc96e9 commit 96b5f06

File tree

11 files changed

+344
-32
lines changed

11 files changed

+344
-32
lines changed

docs/xflow/api.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,21 +105,28 @@ Handle 配置继承自 React Flow 的 Handle 配置,用于控制节点连接
105105

106106
| 属性 | 描述 | 类型 | 默认值 |
107107
| --------- | ------------------- | ----------------------------- | ------ |
108-
| logList | 日志面板数据 | [TLogListItem](#tloglistitem) | |
108+
| logList | 日志面板数据 | Array<[TLogListItem](#tloglistitem)>| |
109109
| loading | 日志面板loading效果 | `boolean` | false |
110110
| logWidget | 自定义日志面板展示 | `string` | |
111111
| width | 日志面板宽度 | `number` | 400 |
112+
| tabsProps | 内置日志面板,详情和追踪选项卡切换组件,antd的tabs配置透传 | [TabsProps](https://ant.design/components/tabs-cn#tabs) | |
113+
| detailLogWidget | 内置日志面板详情tab,自定义组件会渲染在code面板下方。组件接收参数为:`data`(当前日志详情数据)、`logList`(日志面板数据)、`currentStatus`(当前节点状态)、`logPanel`(日志面板配置) | `string` | |
114+
115+
112116

113117

114118
## TLogListItem
115119

116120
日志面板数据格式
117121

118122
| 属性 | 描述 | 类型 | 默认值 |
119-
| ----------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------ |
120-
| statusPanel | 日志面板数据,isBadge是否以badge形式展示状态 | `{status: Array<{ label: string; value?: string; isBadge?: boolean }>;extra?: string \| ReactNode}` | |
121-
| codePanel | 代码面板数据渲染,如果没有 codePanel,则不渲染代码面板。title:代码面板标题,code:代码面板数据 | `Array<{ title: string; code: string }>` | |
122-
| nodeId | 节点ID,必填 | `string` | |
123+
| ------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------ |
124+
| statusPanel | 日志面板数据,isBadge是否以badge形式展示状态。非必填,不传statusPanel字段不渲染状态面板。 | `{status: Array<{ label: string; value?: string; isBadge?: boolean }>;extra?: string \| ReactNode}` | |
125+
| codePanel | 代码面板数据渲染,如果没有 codePanel,则不渲染代码面板。title:代码面板标题,code:代码面板数据 | `Array<{ title: string; code: string }>` | |
126+
| nodeId | 节点ID,必填。如果`logList`中有多个相同的nodeId,会自动合并相同nodeId的statusPanel、codePanel数据,并以数组的形式渲染 | `string` | |
127+
| groupTitle |当有多个相同的nodeId,每个板块的分组名称,不传不渲染。可以传入字符串,或者传入`widgets`自定义组件名称,自定义渲染组件 | `string` | |
128+
| showDetailLogWidget |是否展示`detailLogWidget`组件 | `boolean` | true |
129+
123130

124131

125132

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from 'react';
2+
import { Tag } from 'antd';
3+
4+
const CustomGroupTitle = ({ logData }) => {
5+
return (
6+
<div className="log-detail-panel-title" style={{ justifyContent: 'space-between' }}>
7+
<div style={{ display: 'flex', alignItems: 'center' }}>
8+
<span className="log-detail-panel-title-text">
9+
{logData?.groupTitle}
10+
</span>
11+
<Tag color="blue" style={{ marginLeft: 8 }}>自定义分组标题</Tag>
12+
</div>
13+
<div className="log-detail-panel-title-line" />
14+
</div>
15+
);
16+
};
17+
18+
export default CustomGroupTitle;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React from 'react';
2+
import { Card, Typography, Space, Tag } from 'antd';
3+
4+
const { Text } = Typography;
5+
6+
interface DetailLogWidgetProps {
7+
data: any;
8+
logList: any[];
9+
currentStatus: string;
10+
logPanel: any;
11+
}
12+
13+
const DetailLogWidget: React.FC<DetailLogWidgetProps> = ({
14+
data,
15+
logList,
16+
currentStatus,
17+
logPanel
18+
}) => {
19+
return (
20+
<Card size="small" title="自定义组件部分" style={{ marginTop: 16 }}>
21+
<Space direction="vertical" style={{ width: '100%' }}>
22+
<div>
23+
<Text type="secondary">当前节点状态: </Text>
24+
<Tag color={currentStatus === 'success' ? 'green' : 'orange'}>
25+
{currentStatus}
26+
</Tag>
27+
</div>
28+
29+
<div>
30+
<Text type="secondary">节点ID: </Text>
31+
<Text>{data.nodeId}</Text>
32+
</div>
33+
34+
{data.statusPanel?.extra && (
35+
<div>
36+
<Text type="secondary">额外信息: </Text>
37+
<Text>{data.statusPanel.extra}</Text>
38+
</div>
39+
)}
40+
</Space>
41+
</Card>
42+
);
43+
};
44+
45+
export default DetailLogWidget;

docs/xflow/demo/log/buildIn-log/index.tsx

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import XFlow from '@xrenders/xflow';
22
import React,{ useState } from 'react';
33
import settings from './setting';
4+
import { Button } from 'antd';
5+
import CustomGroupTitle from './CustomGroupTittle';
6+
import DetailLogWidget from './DetailLogWidget';
47

58
export default () => {
69
const [logList, setLogList] = useState<any>([
710
{
8-
nodeId:'mcelcsg6pinydoy7',
11+
nodeId: 'mcelcsg6pinydoy7',
12+
groupTitle:"日志分组1",
913
statusPanel: {
1014
status: [
1115
{
@@ -36,8 +40,120 @@ export default () => {
3640
},
3741
],
3842
},
43+
{
44+
nodeId: 'mcelcsg6pinydoy7',
45+
groupTitle: "customGroupTitle",// 自定义分组标题组件
46+
statusPanel: {
47+
status: [
48+
{
49+
label: '状态',
50+
isBadge: true,
51+
// value:"失败"
52+
},
53+
{
54+
label: '执行时间',
55+
value: '0.01s',
56+
},
57+
{
58+
label: '总token数',
59+
value: '0tokens',
60+
},
61+
],
62+
// extra: <span>哈哈哈哈哈哈哈哈</span>,
63+
extra: '测试测试',
64+
},
65+
codePanel: [
66+
{
67+
title: '输出数据',
68+
code: "{'target_language':'english','query':'string'}",
69+
},
70+
{
71+
title: '报错信息',
72+
code: "{'target_language':'english','query':'string'}",
73+
},
74+
],
75+
},
76+
{
77+
nodeId: 'w4be9edh4bhdlokm',
78+
statusPanel: {
79+
status: [
80+
{
81+
label: '状态',
82+
isBadge: true,
83+
// value:"失败"
84+
},
85+
{
86+
label: '执行时间',
87+
value: '0.01s',
88+
},
89+
{
90+
label: '总token数',
91+
value: '0tokens',
92+
},
93+
],
94+
// extra: <span>哈哈
95+
// 哈哈哈哈哈哈</span>,
96+
extra: '测试测试',
97+
},
98+
codePanel: [
99+
{
100+
title: '输出数据',
101+
code: "{'target_language':'english','query':'string'}",
102+
},
103+
{
104+
title: '报错信息',
105+
code: "{'target_language':'english','query':'string'}",
106+
},
107+
],
108+
showDetailLogWidget:false,// 是否展示自定义详情tab组件
109+
},
110+
{
111+
nodeId: '4m9tee00n819nyyy',
112+
statusPanel: {
113+
status: [
114+
{
115+
label: '状态',
116+
isBadge: true,
117+
// value:"失败"
118+
},
119+
{
120+
label: '执行时间',
121+
value: '0.01s',
122+
},
123+
{
124+
label: '总token数',
125+
value: '0tokens',
126+
},
127+
],
128+
extra: '测试测试',
129+
},
130+
showDetailLogWidget: false,// 是否展示自定义详情tab组件
131+
},
132+
{
133+
nodeId: '3qloq2p1x3wcwbzg',
134+
statusPanel: {
135+
status: [
136+
{
137+
label: '状态',
138+
isBadge: true,
139+
// value:"失败"
140+
},
141+
{
142+
label: '执行时间',
143+
value: '0.01s',
144+
},
145+
{
146+
label: '总token数',
147+
value: '0tokens',
148+
},
149+
],
150+
extra: '测试测试',
151+
},
152+
showDetailLogWidget: false,// 是否展示自定义详情tab组件
153+
}
39154
]);
40155
const [loading, setLoading] = useState<boolean>(false);
156+
const [activeKey, setActiveKey] = useState<string>('detail');
41157
const nodes = [
42158
{
43159
id: 'mcelcsg6pinydoy7',
@@ -156,10 +272,21 @@ export default () => {
156272
nodeSelector={{
157273
showSearch: true,
158274
}}
275+
widgets={{
276+
customGroupTitle: CustomGroupTitle,
277+
DetailLogWidget
278+
}}
159279
logPanel={{
160280
// 日志面板
161281
logList, // 日志面板接受的数据
162282
loading, // 日志面板loading
283+
tabsProps: {
284+
tabBarExtraContent:activeKey === 'detail' ? <Button type='primary' size='small'>自定义按钮</Button> : null,
285+
onChange: (activeKey)=>{
286+
setActiveKey(activeKey);
287+
},
288+
},
289+
detailLogWidget: 'DetailLogWidget',//自定义详情tab组件
163290
}}
164291
globalConfig={{
165292
nodeView: {

docs/xflow/log.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ group:
6969
logList, // 日志面板数据
7070
loading, // 日志面板loading
7171
logWidget:'CustomLogPanel'// 自定义日志面板
72+
tabsProps,// 日志面板,详情和追踪选项卡切换组件,antd的tabs配置透传
7273
}}
7374
```
7475
### 内置节点日志面板
@@ -82,6 +83,8 @@ group:
8283
};
8384
codePanel?: Array<{ title: string; code: string }>;
8485
nodeId: string;// 节点ID
86+
groupTitle:string;// 当有多个相同的nodeId,每个板块的分组名称
87+
showDetailLogWidget:boolean;// 是否展示detailLogWidget组件
8588
}>;
8689

8790
```
Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,55 @@
1+
import classNames from 'classnames';
12
import { isEmpty, isObject } from 'lodash-es';
2-
import React, { memo, useState } from 'react';
3+
import React, { memo, useContext, useState } from 'react';
4+
import { ConfigContext } from '../../../models/context';
5+
import '../index.less';
36
import CodePanel from './CodePanel';
47
import StatusPanel from './StatusPanel';
5-
import classNames from 'classnames';
68

79
export default memo((props: any) => {
810
const { detailData, currentStatus } = props;
911
const isRenderStatus =
1012
isObject(detailData?.statusPanel) && !isEmpty(detailData?.statusPanel);
1113
const [isFullScreen, setIsFullScreen] = useState(false);
14+
const { widgets, logPanel } = useContext(ConfigContext);
15+
const CustomTitleWidget = widgets[detailData?.groupTitle]; // 自定义标题组件
16+
const DetailLogWidget = widgets[logPanel?.detailLogWidget]; // 自定义组件
17+
const isShowDetailLogWidget =Boolean(detailData?.showDetailLogWidget!==false)&&Boolean(DetailLogWidget);
1218

1319
return (
14-
<div className={classNames("log-detail-panel", { ['log-detail-panel-code-full']: isFullScreen })}>
15-
{isRenderStatus && (
20+
<div
21+
className={classNames('log-detail-panel', {
22+
['log-detail-panel-code-full']: isFullScreen,
23+
})}
24+
>
25+
{Boolean(CustomTitleWidget) ? (
26+
<CustomTitleWidget logData={detailData} currentStatus={currentStatus} />
27+
) : (
28+
detailData?.groupTitle && (
29+
<div className="log-detail-panel-title">
30+
<span className="log-detail-panel-title-text">
31+
{detailData.groupTitle}
32+
</span>
33+
<div className="log-detail-panel-title-line" />
34+
</div>
35+
)
36+
)}
37+
{Boolean(isRenderStatus) && (
1638
<StatusPanel
1739
currentStatus={currentStatus}
1840
statusPanelData={detailData?.statusPanel}
1941
/>
2042
)}
2143
{(detailData?.codePanel || [])?.map((item, index) => (
22-
<CodePanel codeData={item} key={index} onFullScreenChange={(isFullScreen) => {
23-
setIsFullScreen(isFullScreen)
24-
} } />
44+
<CodePanel
45+
codeData={item}
46+
key={index}
47+
onFullScreenChange={isFullScreen => {
48+
setIsFullScreen(isFullScreen);
49+
}}
50+
/>
2551
))}
52+
{Boolean(isShowDetailLogWidget) && <DetailLogWidget data={detailData} logList={logPanel?.logList} currentStatus={currentStatus} logPanel={logPanel} />}
2653
</div>
2754
);
2855
});

packages/x-flow/src/components/NodeLogPanel/components/TrackNodeItem.tsx

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ export default memo((props: ITrackNodeItemProps) => {
3030
} = globalConfig;
3131
const statusObj = transformNodeStatus(status || []);
3232
const statusData = statusObj[nodeStatus];
33-
const SVGWidget = widgets[nodeSetting?.iconSvg]
34-
33+
const SVGWidget = widgets[nodeSetting?.iconSvg];
3534

3635
return (
3736
<div className="log-track-node">
@@ -88,9 +87,36 @@ export default memo((props: ITrackNodeItemProps) => {
8887
)
8988
}
9089
>
91-
{logTrackList?.length ? (
90+
{Boolean(logTrackList?.length) ? (
9291
(logTrackList || [])?.map((item, index) => (
93-
<CodePanel codeData={item} key={index} isShowFullScreen={false} />
92+
<div key={index}>
93+
{Boolean(item?.groupTitle) && (
94+
<div
95+
className="log-detail-panel-title"
96+
style={{ marginTop: 10 }}
97+
>
98+
<span className="log-detail-panel-title-text">
99+
{item?.groupTitle}
100+
</span>
101+
<div className="log-detail-panel-title-line" />
102+
</div>
103+
)}
104+
{Boolean((item?.codePanel || [])?.length) ? (
105+
(item?.codePanel || [])?.map((codeItem, codeIndex) => (
106+
<CodePanel
107+
codeData={codeItem}
108+
key={codeIndex}
109+
isShowFullScreen={false}
110+
/>
111+
))
112+
) : (
113+
<Empty
114+
image={Empty.PRESENTED_IMAGE_SIMPLE}
115+
description="暂无日志信息"
116+
style={{ fontSize: '12px' }}
117+
/>
118+
)}
119+
</div>
94120
))
95121
) : (
96122
<Empty

packages/x-flow/src/components/NodeLogPanel/components/TrackPanel.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ export default memo((props: any) => {
2020
isTruthy(item?.data?._status)
2121
);
2222
const trackList = (statusNode || [])?.map(node => {
23-
const logTrackList = logList?.find(item => item?.nodeId == node?.id);
24-
return { ...node, logTrackList: logTrackList?.codePanel || [] };
23+
const logTrackList = logList?.filter(item => item?.nodeId == node?.id)||[];
24+
return { ...node, logTrackList };
2525
});
2626

2727
return (

0 commit comments

Comments
 (0)