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 |
+
};
|