feat(orchestration): 添加应用编排功能

- 在 ideContainer 中引入 ProjectContainer 组件
- 新增 flowEditor 目录及其相关组件
- 实现基本的流程编辑器功能,包括节点拖拽、连接等
- 添加自定义节点类型 TextUpdaterNode
master
钟良源 5 months ago
parent cceac6bec2
commit b7586b95b8

@ -0,0 +1,94 @@
import React, { useState, useCallback } from 'react';
import {
ReactFlow,
applyNodeChanges,
applyEdgeChanges,
addEdge,
Background,
Controls,
Node,
Edge
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import TextUpdaterNode from './node/textUpdateNode/TextUpdaterNode';
const nodeTypes = {
textUpdater: TextUpdaterNode
};
const initialNodes: Node[] = [
{
id: 'n1',
position: { x: 0, y: 0 },
data: { label: 'Node 1' },
type: 'input'
},
{
id: 'node-1',
type: 'textUpdater',
position: { x: 150, y: 0 },
data: { value: 123 }
},
{
id: 'n2',
position: { x: 100, y: 100 },
data: { label: 'Custom Node' }
}
];
const initialEdges: Edge[] = [
{
id: 'n1-n2',
source: 'n1',
target: 'n2'
},
{
id: 'n1-node-1',
source: 'n1',
target: 'node-1',
targetHandle: 'a'
},
{
id: 'n2-node-1',
source: 'n2',
target: 'node-1',
targetHandle: 'a1'
}
];
const FlowEditor: React.FC = () => {
const [nodes, setNodes] = useState<Node[]>(initialNodes);
const [edges, setEdges] = useState<Edge[]>(initialEdges);
const onNodesChange = useCallback(
(changes: any) => setNodes((nodesSnapshot) => applyNodeChanges(changes, nodesSnapshot)),
[]
);
const onEdgesChange = useCallback(
(changes: any) => setEdges((edgesSnapshot) => applyEdgeChanges(changes, edgesSnapshot)),
[]
);
const onConnect = useCallback(
(params: any) => setEdges((edgesSnapshot) => addEdge(params, edgesSnapshot)),
[]
);
return (
<div style={{ width: '90vw', height: '91vh' }}>
<ReactFlow
nodes={nodes}
edges={edges}
nodeTypes={nodeTypes}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
>
<Background />
<Controls />
</ReactFlow>
</div>
);
};
export default React.memo(FlowEditor);

@ -0,0 +1,14 @@
import React from 'react';
import { Handle, Position } from '@xyflow/react';
const CustomNode = ({ data }) => {
return (
<>
<div style={{ padding: '10px 20px' }}>
{data.label}
</div>
</>
);
};
export default CustomNode;

@ -0,0 +1,8 @@
.text-updater-node {
//width: 150px;
//height: 80px;
padding: 20px;
border-radius: 15px;
border: 1px solid #cccccc;
background-color: #fff;
}

@ -0,0 +1,30 @@
import React, { useCallback } from 'react';
import style from './TextUpdaterNode.module.less';
import { Handle, NodeProps, Position } from '@xyflow/react';
interface TextUpdaterNodeData {
data?: string;
id?: string;
}
const TextUpdaterNode: React.FC<NodeProps> = (props) => {
const onChange = useCallback((evt: React.ChangeEvent<HTMLInputElement>) => {
console.log(evt.target.value);
}, []);
return (
<div className={style['text-updater-node']}>
<div>
<label htmlFor="text">Text:</label>
<input id="text" name="text" onChange={onChange} className="nodrag" />
</div>
<Handle type="target" position={Position.Left} id="a" />
<Handle type="target" position={Position.Bottom} id="a1" />
<Handle type="target" position={Position.Top} id="a2" />
<Handle type="source" position={Position.Right} id="b" />
<Handle type="source" position={Position.Right} style={{ top: 10 }} id="b1" />
<Handle type="source" position={Position.Right} style={{ top: 20 }} id="b2" />
</div>
);
};
export default TextUpdaterNode;

@ -4,6 +4,7 @@ import SideBar from './sideBar';
import LogBar from './logBar';
import RightSideBar from './rightSideBar';
import { getUrlParams } from '@/utils/common';
import ProjectContainer from '@/pages/orchestration/project';
interface Selected {
currentPath?: string;
@ -15,7 +16,6 @@ type UrlParamsOptions = {
[key: string]: string
};
const AppFlowComponent = () => <div style={{ height: '70vh', width: '100%' }}></div>;
const CompListComponent = () => <div style={{ height: '70vh', width: '100%' }}></div>;
const AppInstanceComponent = () => <div style={{ height: '70vh', width: '100%' }}></div>;
const EventComponent = () => <div style={{ height: '70vh', width: '100%' }}></div>;
@ -40,7 +40,7 @@ function IDEContainer() {
const renderContent = () => {
switch (selected.currentPath) {
case 'appFlow':
return <AppFlowComponent />;
return <ProjectContainer />;
case 'compList':
return <CompListComponent />;
case 'appInstance':

@ -0,0 +1,10 @@
import React from 'react';
import FlowEditor from '@/pages/flowEditor/index';
const ProjectContainer = () => {
return (
<FlowEditor />
);
};
export default ProjectContainer;
Loading…
Cancel
Save