balibabu
commited on
Commit
·
78dc980
1
Parent(s):
39b9b55
feat: build react flow nodes and edges from mock data #918 (#919)
Browse files### What problem does this PR solve?
feat: build react flow nodes and edges from mock data #918
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- web/src/interfaces/database/flow.ts +19 -0
- web/src/pages/flow/canvas/index.tsx +11 -5
- web/src/pages/flow/canvas/node/index.less +2 -2
- web/src/pages/flow/canvas/node/index.tsx +4 -21
- web/src/pages/flow/hooks.ts +5 -3
- web/src/pages/flow/interface.ts +4 -0
- web/src/pages/flow/mock.tsx +40 -0
- web/src/pages/flow/utils.ts +44 -0
web/src/interfaces/database/flow.ts
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export type DSLComponents = Record<string, Operator>;
|
2 |
+
|
3 |
+
export interface DSL {
|
4 |
+
components: DSLComponents;
|
5 |
+
history: any[];
|
6 |
+
path: string[];
|
7 |
+
answer: any[];
|
8 |
+
}
|
9 |
+
|
10 |
+
export interface Operator {
|
11 |
+
obj: OperatorNode;
|
12 |
+
downstream: string[];
|
13 |
+
upstream: string[];
|
14 |
+
}
|
15 |
+
|
16 |
+
export interface OperatorNode {
|
17 |
+
component_name: string;
|
18 |
+
params: Record<string, unknown>;
|
19 |
+
}
|
web/src/pages/flow/canvas/index.tsx
CHANGED
@@ -8,6 +8,7 @@ import ReactFlow, {
|
|
8 |
OnConnect,
|
9 |
OnEdgesChange,
|
10 |
OnNodesChange,
|
|
|
11 |
addEdge,
|
12 |
applyEdgeChanges,
|
13 |
applyNodeChanges,
|
@@ -24,21 +25,27 @@ const nodeTypes = { textUpdater: TextUpdaterNode };
|
|
24 |
|
25 |
const initialNodes = [
|
26 |
{
|
|
|
|
|
27 |
id: 'node-1',
|
28 |
type: 'textUpdater',
|
29 |
-
position: { x:
|
30 |
-
data: {
|
31 |
},
|
32 |
{
|
|
|
|
|
33 |
id: '1',
|
34 |
data: { label: 'Hello' },
|
35 |
-
position: { x: 0, y:
|
36 |
type: 'input',
|
37 |
},
|
38 |
{
|
|
|
|
|
39 |
id: '2',
|
40 |
data: { label: 'World' },
|
41 |
-
position: { x:
|
42 |
},
|
43 |
];
|
44 |
|
@@ -48,7 +55,6 @@ const initialEdges = [
|
|
48 |
|
49 |
interface IProps {
|
50 |
sideWidth: number;
|
51 |
-
showDrawer(): void;
|
52 |
}
|
53 |
|
54 |
function FlowCanvas({ sideWidth }: IProps) {
|
|
|
8 |
OnConnect,
|
9 |
OnEdgesChange,
|
10 |
OnNodesChange,
|
11 |
+
Position,
|
12 |
addEdge,
|
13 |
applyEdgeChanges,
|
14 |
applyNodeChanges,
|
|
|
25 |
|
26 |
const initialNodes = [
|
27 |
{
|
28 |
+
sourcePosition: Position.Left,
|
29 |
+
targetPosition: Position.Right,
|
30 |
id: 'node-1',
|
31 |
type: 'textUpdater',
|
32 |
+
position: { x: 400, y: 100 },
|
33 |
+
data: { label: 123 },
|
34 |
},
|
35 |
{
|
36 |
+
sourcePosition: Position.Right,
|
37 |
+
targetPosition: Position.Left,
|
38 |
id: '1',
|
39 |
data: { label: 'Hello' },
|
40 |
+
position: { x: 0, y: 50 },
|
41 |
type: 'input',
|
42 |
},
|
43 |
{
|
44 |
+
sourcePosition: Position.Right,
|
45 |
+
targetPosition: Position.Left,
|
46 |
id: '2',
|
47 |
data: { label: 'World' },
|
48 |
+
position: { x: 200, y: 50 },
|
49 |
},
|
50 |
];
|
51 |
|
|
|
55 |
|
56 |
interface IProps {
|
57 |
sideWidth: number;
|
|
|
58 |
}
|
59 |
|
60 |
function FlowCanvas({ sideWidth }: IProps) {
|
web/src/pages/flow/canvas/node/index.less
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
.textUpdaterNode {
|
2 |
-
height: 50px;
|
3 |
-
border: 1px solid
|
4 |
padding: 5px;
|
5 |
border-radius: 5px;
|
6 |
background: white;
|
|
|
1 |
.textUpdaterNode {
|
2 |
+
// height: 50px;
|
3 |
+
border: 1px solid black;
|
4 |
padding: 5px;
|
5 |
border-radius: 5px;
|
6 |
background: white;
|
web/src/pages/flow/canvas/node/index.tsx
CHANGED
@@ -1,41 +1,24 @@
|
|
1 |
-
import { useCallback } from 'react';
|
2 |
import { Handle, NodeProps, Position } from 'reactflow';
|
3 |
|
4 |
import styles from './index.less';
|
5 |
|
6 |
-
const handleStyle = { left: 10 };
|
7 |
-
|
8 |
export function TextUpdaterNode({
|
9 |
data,
|
10 |
isConnectable = true,
|
11 |
-
}: NodeProps<{
|
12 |
-
const onChange = useCallback((evt) => {
|
13 |
-
console.log(evt.target.value);
|
14 |
-
}, []);
|
15 |
-
|
16 |
return (
|
17 |
<div className={styles.textUpdaterNode}>
|
18 |
<Handle
|
19 |
type="target"
|
20 |
-
position={Position.
|
21 |
isConnectable={isConnectable}
|
22 |
/>
|
23 |
<Handle
|
24 |
type="source"
|
25 |
-
position={Position.
|
26 |
-
// style={handleStyle}
|
27 |
isConnectable={isConnectable}
|
28 |
/>
|
29 |
-
<div>
|
30 |
-
<label htmlFor="text">Text:</label>
|
31 |
-
<input id="text" name="text" onChange={onChange} className="nodrag" />
|
32 |
-
</div>
|
33 |
-
{/* <Handle
|
34 |
-
type="source"
|
35 |
-
position={Position.Bottom}
|
36 |
-
id="b"
|
37 |
-
isConnectable={isConnectable}
|
38 |
-
/> */}
|
39 |
</div>
|
40 |
);
|
41 |
}
|
|
|
|
|
1 |
import { Handle, NodeProps, Position } from 'reactflow';
|
2 |
|
3 |
import styles from './index.less';
|
4 |
|
|
|
|
|
5 |
export function TextUpdaterNode({
|
6 |
data,
|
7 |
isConnectable = true,
|
8 |
+
}: NodeProps<{ label: string }>) {
|
|
|
|
|
|
|
|
|
9 |
return (
|
10 |
<div className={styles.textUpdaterNode}>
|
11 |
<Handle
|
12 |
type="target"
|
13 |
+
position={Position.Left}
|
14 |
isConnectable={isConnectable}
|
15 |
/>
|
16 |
<Handle
|
17 |
type="source"
|
18 |
+
position={Position.Right}
|
|
|
19 |
isConnectable={isConnectable}
|
20 |
/>
|
21 |
+
<div>{data.label}</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
</div>
|
23 |
);
|
24 |
}
|
web/src/pages/flow/hooks.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
import { useSetModalState } from '@/hooks/commonHooks';
|
2 |
import React, { Dispatch, SetStateAction, useCallback, useState } from 'react';
|
3 |
-
import { Node, ReactFlowInstance } from 'reactflow';
|
4 |
import { v4 as uuidv4 } from 'uuid';
|
5 |
|
6 |
export const useHandleDrag = () => {
|
@@ -44,12 +44,14 @@ export const useHandleDrop = (setNodes: Dispatch<SetStateAction<Node[]>>) => {
|
|
44 |
});
|
45 |
const newNode = {
|
46 |
id: uuidv4(),
|
47 |
-
type,
|
48 |
position: position || {
|
49 |
x: 0,
|
50 |
y: 0,
|
51 |
},
|
52 |
-
data: { label: `${type}
|
|
|
|
|
53 |
};
|
54 |
|
55 |
setNodes((nds) => nds.concat(newNode));
|
|
|
1 |
import { useSetModalState } from '@/hooks/commonHooks';
|
2 |
import React, { Dispatch, SetStateAction, useCallback, useState } from 'react';
|
3 |
+
import { Node, Position, ReactFlowInstance } from 'reactflow';
|
4 |
import { v4 as uuidv4 } from 'uuid';
|
5 |
|
6 |
export const useHandleDrag = () => {
|
|
|
44 |
});
|
45 |
const newNode = {
|
46 |
id: uuidv4(),
|
47 |
+
type: 'textUpdater',
|
48 |
position: position || {
|
49 |
x: 0,
|
50 |
y: 0,
|
51 |
},
|
52 |
+
data: { label: `${type}` },
|
53 |
+
sourcePosition: Position.Right,
|
54 |
+
targetPosition: Position.Left,
|
55 |
};
|
56 |
|
57 |
setNodes((nds) => nds.concat(newNode));
|
web/src/pages/flow/interface.ts
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export interface DSLComponentList {
|
2 |
+
id: string;
|
3 |
+
name: string;
|
4 |
+
}
|
web/src/pages/flow/mock.tsx
CHANGED
@@ -9,3 +9,43 @@ export const componentList = [
|
|
9 |
{ name: 'Retrieval', icon: <RocketOutlined />, description: '' },
|
10 |
{ name: 'Generate', icon: <MergeCellsOutlined />, description: '' },
|
11 |
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
{ name: 'Retrieval', icon: <RocketOutlined />, description: '' },
|
10 |
{ name: 'Generate', icon: <MergeCellsOutlined />, description: '' },
|
11 |
];
|
12 |
+
|
13 |
+
export const dsl = {
|
14 |
+
components: {
|
15 |
+
begin: {
|
16 |
+
obj: {
|
17 |
+
component_name: 'Begin',
|
18 |
+
params: {},
|
19 |
+
},
|
20 |
+
downstream: ['Answer:China'],
|
21 |
+
upstream: [],
|
22 |
+
},
|
23 |
+
'Answer:China': {
|
24 |
+
obj: {
|
25 |
+
component_name: 'Answer',
|
26 |
+
params: {},
|
27 |
+
},
|
28 |
+
downstream: ['Retrieval:China'],
|
29 |
+
upstream: ['begin', 'Generate:China'],
|
30 |
+
},
|
31 |
+
'Retrieval:China': {
|
32 |
+
obj: {
|
33 |
+
component_name: 'Retrieval',
|
34 |
+
params: {},
|
35 |
+
},
|
36 |
+
downstream: ['Generate:China'],
|
37 |
+
upstream: ['Answer:China'],
|
38 |
+
},
|
39 |
+
'Generate:China': {
|
40 |
+
obj: {
|
41 |
+
component_name: 'Generate',
|
42 |
+
params: {},
|
43 |
+
},
|
44 |
+
downstream: ['Answer:China'],
|
45 |
+
upstream: ['Retrieval:China'],
|
46 |
+
},
|
47 |
+
},
|
48 |
+
history: [],
|
49 |
+
path: ['begin'],
|
50 |
+
answer: [],
|
51 |
+
};
|
web/src/pages/flow/utils.ts
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { DSLComponents } from '@/interfaces/database/flow';
|
2 |
+
import { Edge, Node, Position } from 'reactflow';
|
3 |
+
import { v4 as uuidv4 } from 'uuid';
|
4 |
+
|
5 |
+
export const buildNodesFromDSLComponents = (data: DSLComponents) => {
|
6 |
+
const nodes: Node[] = [];
|
7 |
+
const edges: Edge[] = [];
|
8 |
+
|
9 |
+
Object.entries(data).forEach(([key, value]) => {
|
10 |
+
const downstream = [...value.downstream];
|
11 |
+
const upstream = [...value.upstream];
|
12 |
+
nodes.push({
|
13 |
+
id: key,
|
14 |
+
type: 'textUpdater',
|
15 |
+
position: { x: 0, y: 0 },
|
16 |
+
data: {
|
17 |
+
label: value.obj.component_name,
|
18 |
+
params: value.obj.params,
|
19 |
+
downstream: downstream,
|
20 |
+
upstream: upstream,
|
21 |
+
},
|
22 |
+
sourcePosition: Position.Left,
|
23 |
+
targetPosition: Position.Right,
|
24 |
+
});
|
25 |
+
|
26 |
+
// intermediate node
|
27 |
+
// The first and last nodes do not need to be considered
|
28 |
+
if (upstream.length > 0 && downstream.length > 0) {
|
29 |
+
for (let i = 0; i < upstream.length; i++) {
|
30 |
+
const up = upstream[i];
|
31 |
+
for (let j = 0; j < downstream.length; j++) {
|
32 |
+
const down = downstream[j];
|
33 |
+
edges.push({
|
34 |
+
id: uuidv4(),
|
35 |
+
label: '',
|
36 |
+
type: 'step',
|
37 |
+
source: up,
|
38 |
+
target: down,
|
39 |
+
});
|
40 |
+
}
|
41 |
+
}
|
42 |
+
}
|
43 |
+
});
|
44 |
+
};
|