feat: 创建节点
This commit is contained in:
parent
f42a2583c1
commit
9ab6726e17
|
|
@ -9,6 +9,7 @@
|
|||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@ant-design/pro-components": "^2.8.10",
|
||||
"@xyflow/react": "^12.8.4",
|
||||
"antd": "^5.27.1",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
|
|
@ -1909,6 +1910,49 @@
|
|||
"@babel/types": "^7.28.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-color": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
|
||||
"integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="
|
||||
},
|
||||
"node_modules/@types/d3-drag": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz",
|
||||
"integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==",
|
||||
"dependencies": {
|
||||
"@types/d3-selection": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-interpolate": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
|
||||
"integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
|
||||
"dependencies": {
|
||||
"@types/d3-color": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-selection": {
|
||||
"version": "3.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz",
|
||||
"integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w=="
|
||||
},
|
||||
"node_modules/@types/d3-transition": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz",
|
||||
"integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==",
|
||||
"dependencies": {
|
||||
"@types/d3-selection": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-zoom": {
|
||||
"version": "3.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz",
|
||||
"integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==",
|
||||
"dependencies": {
|
||||
"@types/d3-interpolate": "*",
|
||||
"@types/d3-selection": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
|
|
@ -1925,7 +1969,7 @@
|
|||
"version": "19.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.11.tgz",
|
||||
"integrity": "sha512-lr3jdBw/BGj49Eps7EvqlUaoeA0xpj3pc0RoJkHpYaCHkVK7i28dKyImLQb3JVlqs3aYSXf7qYuWOW/fgZnTXQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
|
|
@ -1974,6 +2018,36 @@
|
|||
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@xyflow/react": {
|
||||
"version": "12.8.4",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.8.4.tgz",
|
||||
"integrity": "sha512-bqUu4T5QSHiCFPkoH+b+LROKwQJdLvcjhGbNW9c1dLafCBRjmH1IYz0zPE+lRDXCtQ9kRyFxz3tG19+8VORJ1w==",
|
||||
"dependencies": {
|
||||
"@xyflow/system": "0.0.68",
|
||||
"classcat": "^5.0.3",
|
||||
"zustand": "^4.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=17",
|
||||
"react-dom": ">=17"
|
||||
}
|
||||
},
|
||||
"node_modules/@xyflow/system": {
|
||||
"version": "0.0.68",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.68.tgz",
|
||||
"integrity": "sha512-QDG2wxIG4qX+uF8yzm1ULVZrcXX3MxPBoxv7O52FWsX87qIImOqifUhfa/TwsvLdzn7ic2DDBH1uI8TKbdNTYA==",
|
||||
"dependencies": {
|
||||
"@types/d3-drag": "^3.0.7",
|
||||
"@types/d3-interpolate": "^3.0.4",
|
||||
"@types/d3-selection": "^3.0.10",
|
||||
"@types/d3-transition": "^3.0.8",
|
||||
"@types/d3-zoom": "^3.0.8",
|
||||
"d3-drag": "^3.0.0",
|
||||
"d3-interpolate": "^3.0.1",
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-zoom": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
|
|
@ -2199,6 +2273,11 @@
|
|||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/classcat": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz",
|
||||
"integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w=="
|
||||
},
|
||||
"node_modules/classnames": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||
|
|
@ -2277,6 +2356,102 @@
|
|||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||
},
|
||||
"node_modules/d3-color": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
|
||||
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-dispatch": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
|
||||
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-drag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
|
||||
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
|
||||
"dependencies": {
|
||||
"d3-dispatch": "1 - 3",
|
||||
"d3-selection": "3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-ease": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
|
||||
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-interpolate": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
|
||||
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
|
||||
"dependencies": {
|
||||
"d3-color": "1 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-selection": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-timer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
|
||||
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-transition": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
|
||||
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
|
||||
"dependencies": {
|
||||
"d3-color": "1 - 3",
|
||||
"d3-dispatch": "1 - 3",
|
||||
"d3-ease": "1 - 3",
|
||||
"d3-interpolate": "1 - 3",
|
||||
"d3-timer": "1 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"d3-selection": "2 - 3"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-zoom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
|
||||
"integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
|
||||
"dependencies": {
|
||||
"d3-dispatch": "1 - 3",
|
||||
"d3-drag": "2 - 3",
|
||||
"d3-interpolate": "1 - 3",
|
||||
"d3-selection": "2 - 3",
|
||||
"d3-transition": "2 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.14",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.14.tgz",
|
||||
|
|
@ -4212,6 +4387,33 @@
|
|||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zustand": {
|
||||
"version": "4.5.7",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz",
|
||||
"integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==",
|
||||
"dependencies": {
|
||||
"use-sync-external-store": "^1.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.7.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.8",
|
||||
"immer": ">=9.0.6",
|
||||
"react": ">=16.8"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"immer": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@ant-design/pro-components": "^2.8.10",
|
||||
"@xyflow/react": "^12.8.4",
|
||||
"antd": "^5.27.1",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
.flow-detail-right .node {
|
||||
cursor: pointer;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 8px;
|
||||
padding: 16px 8px;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
import { Button, Card, Col, Row, Typography } from "antd"
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useCallback } from 'react';
|
||||
import {
|
||||
ReactFlow,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Background,
|
||||
useNodesState,
|
||||
useEdgesState,
|
||||
addEdge,
|
||||
Position,
|
||||
} from '@xyflow/react';
|
||||
import '@xyflow/react/dist/style.css';
|
||||
|
||||
const COLORS = {
|
||||
input: "#89A8B2",
|
||||
git: "#B3C8CF",
|
||||
cmd: "#E5E1DA",
|
||||
status: "#F1F0E8"
|
||||
}
|
||||
|
||||
const initialNodes = [
|
||||
{
|
||||
id: '1',
|
||||
position: { x: 0, y: 0 },
|
||||
data: { label: '开始' },
|
||||
sourcePosition: 'right',
|
||||
targetPosition: 'left',
|
||||
type: 'input',
|
||||
style: {
|
||||
backgroundColor: COLORS["input"],
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
position: { x: 200, y: 0 },
|
||||
data: { label: '2' },
|
||||
sourcePosition: 'right',
|
||||
targetPosition: 'left',
|
||||
},
|
||||
];
|
||||
const initialEdges = [{ id: 'e1-2', source: '1', target: '2' }];
|
||||
|
||||
|
||||
|
||||
const FlowDetail = () => {
|
||||
const navigate = useNavigate();
|
||||
const backButton = <Button onClick={() => navigate("/flow")}>返回</Button>
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||
const onConnect = useCallback((params) => setEdges((eds) => addEdge(params, eds)), [setEdges]);
|
||||
const onBeforeDelete = async (params) => {
|
||||
if (params?.nodes?.find(e => e.type === "input")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return <Row gutter={[16, 0]}>
|
||||
<Col span={18} >
|
||||
<Card title="工作" extra={backButton}>
|
||||
<div style={{ height: 'calc(100vh - 220px)', width: '100%' }}>
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
onBeforeDelete={onBeforeDelete}
|
||||
edges={edges}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
onConnect={onConnect}
|
||||
fitView
|
||||
defaultViewport={{ zoom: 0.1, x: 0, y: 0}}
|
||||
style={{ background: '#f2f3f5' }}
|
||||
position={Position.Right}
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background />
|
||||
</ReactFlow>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<RightCard />
|
||||
</Col>
|
||||
</Row>
|
||||
}
|
||||
|
||||
const RightCard = ({ onCreate}) => {
|
||||
const nodes = [{ title: 'Git' }, {title: "Cmd"}, {title: "Status"}];
|
||||
return <Card title="节点" className="flow-detail-right">
|
||||
{nodes?.map((e, i) =>
|
||||
<div
|
||||
className="node"
|
||||
style={{ backgroundColor: COLORS[e.title.toLowerCase()] }}
|
||||
onClick={() => {
|
||||
onCreate && onCreate(e.title.toLowerCase());
|
||||
}}
|
||||
>
|
||||
<Typography.Text>
|
||||
{e.title}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
}
|
||||
|
||||
export default FlowDetail;
|
||||
|
|
@ -4,11 +4,14 @@ import { useAuth } from "../../context/AuthContext";
|
|||
import { LoadingOutlined } from "@ant-design/icons";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { tableList, flowRun, flowStop } from "../../api/flow";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import './Detail.css';
|
||||
|
||||
export default () => {
|
||||
const { user, logout } = useAuth();
|
||||
const [status, setStatus] = useState({});
|
||||
const eventSourceRef = useRef(null);
|
||||
const navigate = useNavigate();
|
||||
const needReload = useRef(false);
|
||||
const pageInit = useRef(false);
|
||||
const actionRef = useRef(null);
|
||||
|
|
@ -80,7 +83,7 @@ export default () => {
|
|||
dataIndex: 'last_status',
|
||||
title: '最后执行结果',
|
||||
valueType: 'select',
|
||||
fieldProps: {
|
||||
fieldProps: {
|
||||
options: [
|
||||
{ value: 'RUNNING', "label": "执行中" },
|
||||
{ value: 'SUCCESS', "label": "成功" },
|
||||
|
|
@ -106,7 +109,9 @@ export default () => {
|
|||
<Button type="link" danger style={{ padding: '0 0', border: 'none' }}>暂停</Button>
|
||||
</Popconfirm>
|
||||
),
|
||||
user?.level === 0 && <Button key='2' type="link" style={{ padding: '0 0', border: 'none' }}>编辑</Button>,
|
||||
user?.level === 0 && <Button key='2' type="link" style={{ padding: '0 0', border: 'none' }} onClick={() => {
|
||||
navigate("/flow/detail/" + record.uuid);
|
||||
}}>编辑</Button>,
|
||||
user?.level === 0 && <Button key='3' type="link" danger style={{ padding: '0 0', border: 'none' }}>删除</Button>,
|
||||
]
|
||||
}
|
||||
|
|
@ -179,36 +184,4 @@ export default () => {
|
|||
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
const RunningStatus = ({record, status}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const current = record?.content?.findIndex(e => status?.[e.uuid]);
|
||||
|
||||
console.log(status, current);
|
||||
|
||||
return <>
|
||||
<a onClick={() => setOpen(true)}>
|
||||
<Space>
|
||||
<LoadingOutlined />
|
||||
执行中
|
||||
</Space>
|
||||
</a>
|
||||
<Modal
|
||||
title={record?.title || `#${record?.id} 执行状态`}
|
||||
closable={false}
|
||||
maskClosable={false}
|
||||
open={open}
|
||||
onCancel={() => setOpen(false)}
|
||||
footer={[<Button key="cancel" onClick={() => setOpen(false)}>关闭</Button>]}
|
||||
>
|
||||
<Steps
|
||||
progressDot
|
||||
current={current}
|
||||
direction="vertical"
|
||||
items={record?.content}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import Login from "./pages/Login";
|
|||
import User from "./pages/User";
|
||||
import Profile from "./pages/User/Profile";
|
||||
import Flow from "./pages/Flow";
|
||||
import FlowDetail from "./pages/Flow/Detail";
|
||||
import LayoutPage from "./pages/Layout";
|
||||
|
||||
|
||||
|
|
@ -28,6 +29,7 @@ const routes = [
|
|||
element: <LayoutPage />,
|
||||
children: [
|
||||
{ path: "/flow", element: <Flow /> },
|
||||
{ path: "/flow/detail/:work_uuid", element: <FlowDetail /> },
|
||||
{ path: "/user", element: <User /> },
|
||||
{ path: "/user/detail", element: <Profile /> }
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in New Issue