Skip to content

Commit c29c15f

Browse files
committed
feat: support internal node in sub flow
1 parent 0c1d0a9 commit c29c15f

22 files changed

Lines changed: 297 additions & 119 deletions
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from 'react'
2+
3+
export function AddNode(props) {
4+
return <div className='node-one-output-add node-add--large' onClick={e => {
5+
e.stopPropagation()
6+
props.data.functions.openNodesExplorer(props)
7+
}}>
8+
<i className='fas fa-plus' />
9+
</div>
10+
}

otoroshi/javascript/src/extensions/workflows/BaseNode.js

Lines changed: 0 additions & 11 deletions
This file was deleted.

otoroshi/javascript/src/extensions/workflows/Flow.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,22 @@ import React from 'react';
33
import { Node } from './Node'
44
import { GroupNode } from './GroupNode'
55
import { CustomEdge } from './CustomEdge'
6-
import { ReactFlow, Background, Controls } from '@xyflow/react';
6+
import { ReactFlow, Background, Controls, useReactFlow } from '@xyflow/react';
77
import '@xyflow/react/dist/style.css';
88

9-
export function Flow({ nodes, onClick, edges, onNodesChange, onEdgesChange, onConnect }) {
9+
export function Flow({ nodes, onClick, edges, onNodesChange, onEdgesChange, onConnect, onConnectEnd, onGroupNodeClick, setRfInstance }) {
1010
return <div style={{ height: 'calc(100vh - 52px)' }} onClick={onClick}>
1111
<ReactFlow
1212
nodes={nodes}
13+
onInit={setRfInstance}
1314
onNodesChange={onNodesChange}
1415
edges={edges}
1516
onEdgesChange={onEdgesChange}
1617
onConnect={onConnect}
18+
onConnectEnd={onConnectEnd}
1719
fitView
1820
fitViewOptions={{
19-
padding: 1.5
21+
padding: .5
2022
}}
2123
nodeTypes={{
2224
simple: Node,
@@ -25,6 +27,7 @@ export function Flow({ nodes, onClick, edges, onNodesChange, onEdgesChange, onCo
2527
edgeTypes={{
2628
customEdge: CustomEdge,
2729
}}
30+
onNodeDoubleClick={(_, group) => onGroupNodeClick(group.data)}
2831
>
2932
<Background />
3033
<Controls orientation='horizontal' showInteractive={false} />
Lines changed: 52 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,56 @@
11
import React, { forwardRef } from "react"
2-
import { Panel } from "@xyflow/react";
3-
import { BaseNode } from "./BaseNode";
4-
5-
export const GroupNodeLabel = forwardRef(
6-
({ children, className, ...props }, ref) => {
7-
return (
8-
<div ref={ref} className="h-full w-full" {...props}>
9-
<div
10-
className={"w-fit bg-gray-200 bg-secondary p-2 text-xs text-card-foreground " + className}>
11-
{children}
12-
</div>
13-
</div>
14-
);
15-
},
16-
);
17-
2+
import { Handle, NodeResizer, Panel, Position, useNodeConnections, useNodes } from "@xyflow/react";
3+
import { Node } from './Node'
4+
import { AddNode } from "./AddNode";
5+
import { NODES } from './models/Functions';
186

197
export const GroupNode = forwardRef(
20-
({ selected, label, position, ...props }, ref) => {
21-
const getLabelClassName = (position) => {
22-
switch (position) {
23-
case "top-left":
24-
return "rounded-br-sm";
25-
case "top-center":
26-
return "rounded-b-sm";
27-
case "top-right":
28-
return "rounded-bl-sm";
29-
case "bottom-left":
30-
return "rounded-tr-sm";
31-
case "bottom-right":
32-
return "rounded-tl-sm";
33-
case "bottom-center":
34-
return "rounded-t-sm";
35-
default:
36-
return "rounded-br-sm";
37-
}
38-
}
39-
40-
return (
41-
<BaseNode
42-
ref={ref}
43-
selected={selected}
44-
className="h-full overflow-hidden rounded-sm bg-white bg-opacity-50 p-0"
45-
{...props}
46-
>
47-
<Panel className={"m-0 p-0"} position={position}>
48-
{props.data.label && (
49-
<GroupNodeLabel className={getLabelClassName(position)}>
50-
{props.data.label}
51-
</GroupNodeLabel>
52-
)}
53-
</Panel>
54-
</BaseNode>
55-
);
56-
},
8+
(props, ref) => {
9+
const { selected, label, position, data, ...rest } = props
10+
11+
// const internalNode = data.workflow.node
12+
// const internalNodeData = internalNode?.kind ? NODES[internalNode.kind.toLowerCase()](internalNode) : {}
13+
14+
const isSelected = false
15+
const isFirst = data.isFirst
16+
const isLast = data.isLast
17+
18+
const connections = useNodeConnections();
19+
20+
const nodes = useNodes()
21+
const hasChild = nodes.find(node => node.parentId === props.id)
22+
23+
// console.log(props.id, hasChild)
24+
25+
return <>
26+
<NodeResizer
27+
color="#ff0071"
28+
isVisible={selected}
29+
minWidth={100}
30+
minHeight={30}
31+
/>
32+
{!isFirst && <Handle type="source" position={Position.Left} />}
33+
<Panel className="m-0 p-2 node-group-label" position={position}>
34+
{data.label} {data.name}
35+
</Panel>
36+
<i className='fas fa-trash node-trash' onClick={e => {
37+
e.stopPropagation()
38+
props.handleDeleteNode ? props.handleDeleteNode() : data.functions.handleDeleteNode(props.id)
39+
}} />
40+
{!hasChild && <AddNode {...props} isInternalNode />}
41+
42+
{!isLast && <Handle type="target" position={Position.Right} id="a" />}
43+
44+
{connections.length < 2 && !isLast &&
45+
<div className='node-one-output-dot' onClick={e => {
46+
e.stopPropagation()
47+
data.functions.openNodesExplorer(props)
48+
}}>
49+
<div className='node-one-output-bar'></div>
50+
<div className='node-one-output-add'>
51+
<i className='fas fa-plus' />
52+
</div>
53+
</div>}
54+
</>
55+
}
5756
)

otoroshi/javascript/src/extensions/workflows/ModalEditor.js

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export function ModalEditor({ node }) {
66
if (!node)
77
return null
88

9+
console.log(node)
10+
911
const [state, setState] = useState()
1012

1113
const schema = {
@@ -16,38 +18,32 @@ export function ModalEditor({ node }) {
1618
},
1719
enabled: {
1820
label: 'Enabled',
19-
type: 'box-bool',
20-
props: {
21-
description: 'Boolean to toggle the node',
22-
},
21+
type: 'bool',
2322
},
2423
result: {
2524
type: 'string',
2625
label: 'Result',
27-
props: {
28-
description: 'Name of memory variable to store output'
29-
}
26+
help: 'Name of memory variable to store output'
27+
3028
},
3129
returned: {
3230
label: 'Returned value',
3331
type: 'string',
34-
props: {
35-
description: 'Immediate result to return from the workflow '
36-
}
32+
help: 'Immediate result to return from the workflow'
3733
},
3834
...node.schema
3935
}
4036
const flow = [
4137
{
4238
type: 'group',
4339
name: 'Informations',
44-
collapsable: false,
45-
fields: ['description', 'enabled', 'result', 'returned'],
40+
// collapsed: true,
41+
fields: ['enabled', 'description'],
4642
},
4743
{
4844
type: 'group',
4945
name: 'Configuration',
50-
fields: node.flow
46+
fields: [...(node.flow || []), 'result', 'returned']
5147
}
5248
]
5349

otoroshi/javascript/src/extensions/workflows/Node.js

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,42 @@
11

22
import React from 'react'
33

4-
import { Handle, Position } from '@xyflow/react';
4+
import { Handle, Position, useNodeConnections } from '@xyflow/react';
55

66
export function Node(props) {
77
const { data } = props
8-
9-
const isSelected = false
108
const isFirst = data.isFirst
119
const isLast = data.isLast
1210

13-
const isTargetConnected = data.edges?.find(f => f.target === props.id)
14-
15-
// console.log(props)
11+
const connections = useNodeConnections();
1612

1713
return (
1814
<>
1915
{!isFirst && <Handle type="source" position={Position.Left} />}
2016

21-
<button
17+
{props.children ? props.children : <button
2218
className={`
2319
d-flex-center m-0 node
24-
${isSelected ? 'node--selected' : ''}
20+
${props.selected ? 'node--selected' : ''}
2521
${isFirst ? 'node--first' : ''}
2622
`}
27-
onDoubleClick={() => {
23+
onDoubleClick={e => {
24+
e.stopPropagation()
2825
data.functions.onDoubleClick(data)
29-
}}>
26+
}}
27+
>
3028
<div className='node-one-output d-flex-center'>
3129
{data.label || data.item?.label}
3230
</div>
33-
<i className='fas fa-trash node-trash' />
34-
</button>
31+
<i className='fas fa-trash node-trash' onClick={e => {
32+
e.stopPropagation()
33+
props.handleDeleteNode ? props.handleDeleteNode() : data.functions.handleDeleteNode(props.id)
34+
}} />
35+
</button>}
3536

3637
{!isLast && <Handle type="target" position={Position.Right} id="a" />}
3738

38-
{!isTargetConnected && !isLast &&
39+
{connections.length < 2 && !isLast && !isFirst &&
3940
<div className='node-one-output-dot'>
4041
<div className='node-one-output-bar'></div>
4142
<div className='node-one-output-add' onClick={e => {

otoroshi/javascript/src/extensions/workflows/NodesExplorer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ export function NodesExplorer({ isOpen, isEdition, node, handleSelectNode }) {
1010

1111
{isEdition && <ModalEditor node={node} />}
1212

13-
{!isEdition && <WhatsNext handleSelectNode={handleSelectNode} isOpen={isOpen} />}
13+
{!isEdition && <WhatsNext handleSelectNode={handleSelectNode} isOpen={isOpen} node={node}/>}
1414
</div>
1515
}

0 commit comments

Comments
 (0)