From aee8b48d2ff46f8e5149e1725837d273c3045ad4 Mon Sep 17 00:00:00 2001 From: balibabu Date: Sun, 28 Apr 2024 19:03:54 +0800 Subject: [PATCH] feat: add FlowCanvas (#593) ### What problem does this PR solve? feat: handle operator drag feat: add FlowCanvas #592 ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- web/package-lock.json | 557 ++++++++++++++++++++++ web/package.json | 1 + web/src/pages/flow/canvas/index.tsx | 92 ++++ web/src/pages/flow/canvas/node/index.less | 12 + web/src/pages/flow/canvas/node/index.tsx | 41 ++ web/src/pages/flow/flow-sider/index.less | 14 + web/src/pages/flow/flow-sider/index.tsx | 48 ++ web/src/pages/flow/hooks.ts | 47 ++ web/src/pages/flow/index.tsx | 20 + web/src/pages/flow/mock.tsx | 11 + web/src/routes.ts | 4 + 11 files changed, 847 insertions(+) create mode 100644 web/src/pages/flow/canvas/index.tsx create mode 100644 web/src/pages/flow/canvas/node/index.less create mode 100644 web/src/pages/flow/canvas/node/index.tsx create mode 100644 web/src/pages/flow/flow-sider/index.less create mode 100644 web/src/pages/flow/flow-sider/index.tsx create mode 100644 web/src/pages/flow/hooks.ts create mode 100644 web/src/pages/flow/index.tsx create mode 100644 web/src/pages/flow/mock.tsx diff --git a/web/package-lock.json b/web/package-lock.json index 82f228491..439b21e4e 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -27,6 +27,7 @@ "react-pdf-highlighter": "^6.1.0", "react-string-replace": "^1.1.1", "react-syntax-highlighter": "^15.5.0", + "reactflow": "^11.11.2", "recharts": "^2.12.4", "remark-gfm": "^4.0.0", "umi": "^4.0.90", @@ -2420,6 +2421,306 @@ "node": ">=12.0.0" } }, + "node_modules/@reactflow/background": { + "version": "11.3.12", + "resolved": "https://registry.npmmirror.com/@reactflow/background/-/background-11.3.12.tgz", + "integrity": "sha512-jBuWVb43JQy5h4WOS7G0PU8voGTEJNA+qDmx8/jyBtrjbasTesLNfQvboTGjnQYYiJco6mw5vrtQItAJDNoIqw==", + "dependencies": { + "@reactflow/core": "11.11.2", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/background/node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmmirror.com/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "optional": true, + "peer": true + }, + "node_modules/@reactflow/background/node_modules/zustand": { + "version": "4.5.2", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.5.2.tgz", + "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "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 + } + } + }, + "node_modules/@reactflow/controls": { + "version": "11.2.12", + "resolved": "https://registry.npmmirror.com/@reactflow/controls/-/controls-11.2.12.tgz", + "integrity": "sha512-L9F3+avFRShoprdT+5oOijm5gVsz2rqWCXBzOAgD923L1XFGIspdiHLLf8IlPGsT+mfl0GxbptZhaEeEzl1e3g==", + "dependencies": { + "@reactflow/core": "11.11.2", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/controls/node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmmirror.com/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "optional": true, + "peer": true + }, + "node_modules/@reactflow/controls/node_modules/zustand": { + "version": "4.5.2", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.5.2.tgz", + "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "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 + } + } + }, + "node_modules/@reactflow/core": { + "version": "11.11.2", + "resolved": "https://registry.npmmirror.com/@reactflow/core/-/core-11.11.2.tgz", + "integrity": "sha512-+GfgyskweL1PsgRSguUwfrT2eDotlFgaKfDLm7x0brdzzPJY2qbCzVetaxedaiJmIli3817iYbILvE9qLKwbRA==", + "dependencies": { + "@types/d3": "^7.4.0", + "@types/d3-drag": "^3.0.1", + "@types/d3-selection": "^3.0.3", + "@types/d3-zoom": "^3.0.1", + "classcat": "^5.0.3", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/core/node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmmirror.com/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "optional": true, + "peer": true + }, + "node_modules/@reactflow/core/node_modules/zustand": { + "version": "4.5.2", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.5.2.tgz", + "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "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 + } + } + }, + "node_modules/@reactflow/minimap": { + "version": "11.7.12", + "resolved": "https://registry.npmmirror.com/@reactflow/minimap/-/minimap-11.7.12.tgz", + "integrity": "sha512-SRDU77c2PCF54PV/MQfkz7VOW46q7V1LZNOQlXAp7dkNyAOI6R+tb9qBUtUJOvILB+TCN6pRfD9fQ+2T99bW3Q==", + "dependencies": { + "@reactflow/core": "11.11.2", + "@types/d3-selection": "^3.0.3", + "@types/d3-zoom": "^3.0.1", + "classcat": "^5.0.3", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/minimap/node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmmirror.com/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "optional": true, + "peer": true + }, + "node_modules/@reactflow/minimap/node_modules/zustand": { + "version": "4.5.2", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.5.2.tgz", + "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "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 + } + } + }, + "node_modules/@reactflow/node-resizer": { + "version": "2.2.12", + "resolved": "https://registry.npmmirror.com/@reactflow/node-resizer/-/node-resizer-2.2.12.tgz", + "integrity": "sha512-6LHJGuI1zHyRrZHw5gGlVLIWnvVxid9WIqw8FMFSg+oF2DuS3pAPwSoZwypy7W22/gDNl9eD1Dcl/OtFtDFQ+w==", + "dependencies": { + "@reactflow/core": "11.11.2", + "classcat": "^5.0.4", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/node-resizer/node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmmirror.com/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "optional": true, + "peer": true + }, + "node_modules/@reactflow/node-resizer/node_modules/zustand": { + "version": "4.5.2", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.5.2.tgz", + "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "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 + } + } + }, + "node_modules/@reactflow/node-toolbar": { + "version": "1.3.12", + "resolved": "https://registry.npmmirror.com/@reactflow/node-toolbar/-/node-toolbar-1.3.12.tgz", + "integrity": "sha512-4kJRvNna/E3y2MZW9/80wTKwkhw4pLJiz3D5eQrD13XcmojSb1rArO9CiwyrI+rMvs5gn6NlCFB4iN1F+Q+lxQ==", + "dependencies": { + "@reactflow/core": "11.11.2", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/node-toolbar/node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmmirror.com/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "optional": true, + "peer": true + }, + "node_modules/@reactflow/node-toolbar/node_modules/zustand": { + "version": "4.5.2", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.5.2.tgz", + "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "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 + } + } + }, "node_modules/@rgrove/parse-xml": { "version": "2.0.4", "resolved": "https://registry.npmmirror.com/@rgrove/parse-xml/-/parse-xml-2.0.4.tgz", @@ -2679,21 +2980,142 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmmirror.com/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, "node_modules/@types/d3-array": { "version": "3.2.1", "resolved": "https://registry.npmmirror.com/@types/d3-array/-/d3-array-3.2.1.tgz", "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==" + }, "node_modules/@types/d3-color": { "version": "3.1.3", "resolved": "https://registry.npmmirror.com/@types/d3-color/-/d3-color-3.1.3.tgz", "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmmirror.com/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz", + "integrity": "sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==" + }, "node_modules/@types/d3-ease": { "version": "3.0.2", "resolved": "https://registry.npmmirror.com/@types/d3-ease/-/d3-ease-3.0.2.tgz", "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.9", + "resolved": "https://registry.npmmirror.com/@types/d3-force/-/d3-force-3.0.9.tgz", + "integrity": "sha512-IKtvyFdb4Q0LWna6ymywQsEYjK/94SGhPrMfEr1TIc5OBeziTi+1jcCvttts8e0UWZIxpasjnQk9MNk/3iS+kA==" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmmirror.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==" + }, "node_modules/@types/d3-interpolate": { "version": "3.0.4", "resolved": "https://registry.npmmirror.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", @@ -2707,6 +3129,21 @@ "resolved": "https://registry.npmmirror.com/@types/d3-path/-/d3-path-3.1.0.tgz", "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==" + }, "node_modules/@types/d3-scale": { "version": "4.0.8", "resolved": "https://registry.npmmirror.com/@types/d3-scale/-/d3-scale-4.0.8.tgz", @@ -2715,6 +3152,16 @@ "@types/d3-time": "*" } }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.3.tgz", + "integrity": "sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.10", + "resolved": "https://registry.npmmirror.com/@types/d3-selection/-/d3-selection-3.0.10.tgz", + "integrity": "sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==" + }, "node_modules/@types/d3-shape": { "version": "3.1.6", "resolved": "https://registry.npmmirror.com/@types/d3-shape/-/d3-shape-3.1.6.tgz", @@ -2728,11 +3175,33 @@ "resolved": "https://registry.npmmirror.com/@types/d3-time/-/d3-time-3.0.3.tgz", "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==" + }, "node_modules/@types/d3-timer": { "version": "3.0.2", "resolved": "https://registry.npmmirror.com/@types/d3-timer/-/d3-timer-3.0.2.tgz", "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" }, + "node_modules/@types/d3-transition": { + "version": "3.0.8", + "resolved": "https://registry.npmmirror.com/@types/d3-transition/-/d3-transition-3.0.8.tgz", + "integrity": "sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmmirror.com/@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/debug": { "version": "4.1.12", "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.12.tgz", @@ -2774,6 +3243,11 @@ "@types/estree": "*" } }, + "node_modules/@types/geojson": { + "version": "7946.0.14", + "resolved": "https://registry.npmmirror.com/@types/geojson/-/geojson-7946.0.14.tgz", + "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" + }, "node_modules/@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmmirror.com/@types/glob/-/glob-7.2.0.tgz", @@ -5834,6 +6308,11 @@ "node": ">= 0.4" } }, + "node_modules/classcat": { + "version": "5.0.5", + "resolved": "https://registry.npmmirror.com/classcat/-/classcat-5.0.5.tgz", + "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==" + }, "node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmmirror.com/classnames/-/classnames-2.5.1.tgz", @@ -6722,6 +7201,26 @@ "node": ">=12" } }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/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.npmmirror.com/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.npmmirror.com/d3-ease/-/d3-ease-3.0.1.tgz", @@ -6788,6 +7287,14 @@ "node": ">=12" } }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, "node_modules/d3-shape": { "version": "3.2.0", "resolved": "https://registry.npmmirror.com/d3-shape/-/d3-shape-3.2.0.tgz", @@ -6840,6 +7347,39 @@ "node": ">=12" } }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/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.npmmirror.com/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/data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", @@ -15248,6 +15788,23 @@ "lodash": "^4.0.1" } }, + "node_modules/reactflow": { + "version": "11.11.2", + "resolved": "https://registry.npmmirror.com/reactflow/-/reactflow-11.11.2.tgz", + "integrity": "sha512-o1fT3stSdhzW+SedCGNSmEvZvULZygZIMLyW67NcWNZrgwx1wuJfzLg5fuQ0Nzf389wItumZX/zP3zdaPX7lEw==", + "dependencies": { + "@reactflow/background": "11.3.12", + "@reactflow/controls": "11.2.12", + "@reactflow/core": "11.11.2", + "@reactflow/minimap": "11.7.12", + "@reactflow/node-resizer": "2.2.12", + "@reactflow/node-toolbar": "1.3.12" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmmirror.com/read-pkg/-/read-pkg-5.2.0.tgz", diff --git a/web/package.json b/web/package.json index 861d96b17..6e5adebe2 100644 --- a/web/package.json +++ b/web/package.json @@ -31,6 +31,7 @@ "react-pdf-highlighter": "^6.1.0", "react-string-replace": "^1.1.1", "react-syntax-highlighter": "^15.5.0", + "reactflow": "^11.11.2", "recharts": "^2.12.4", "remark-gfm": "^4.0.0", "umi": "^4.0.90", diff --git a/web/src/pages/flow/canvas/index.tsx b/web/src/pages/flow/canvas/index.tsx new file mode 100644 index 000000000..1ad3226a1 --- /dev/null +++ b/web/src/pages/flow/canvas/index.tsx @@ -0,0 +1,92 @@ +import { useCallback, useEffect, useState } from 'react'; +import ReactFlow, { + Background, + Controls, + Edge, + Node, + OnConnect, + OnEdgesChange, + OnNodesChange, + addEdge, + applyEdgeChanges, + applyNodeChanges, +} from 'reactflow'; +import 'reactflow/dist/style.css'; + +import { useHandleDrop } from '../hooks'; +import { TextUpdaterNode } from './node'; + +const nodeTypes = { textUpdater: TextUpdaterNode }; + +const initialNodes = [ + { + id: 'node-1', + type: 'textUpdater', + position: { x: 200, y: 50 }, + data: { value: 123 }, + }, + { + id: '1', + data: { label: 'Hello' }, + position: { x: 0, y: 0 }, + type: 'input', + }, + { + id: '2', + data: { label: 'World' }, + position: { x: 100, y: 100 }, + }, +]; + +const initialEdges = [ + { id: '1-2', source: '1', target: '2', label: 'to the', type: 'step' }, +]; + +function FlowCanvas() { + const [nodes, setNodes] = useState(initialNodes); + const [edges, setEdges] = useState(initialEdges); + + const onNodesChange: OnNodesChange = useCallback( + (changes) => setNodes((nds) => applyNodeChanges(changes, nds)), + [], + ); + const onEdgesChange: OnEdgesChange = useCallback( + (changes) => setEdges((eds) => applyEdgeChanges(changes, eds)), + [], + ); + + const onConnect: OnConnect = useCallback( + (params) => setEdges((eds) => addEdge(params, eds)), + [], + ); + + const { handleDrop, allowDrop } = useHandleDrop(setNodes); + + useEffect(() => { + console.info('nodes:', nodes); + console.info('edges:', edges); + }, [nodes, edges]); + + return ( +
+ + + + +
+ ); +} + +export default FlowCanvas; diff --git a/web/src/pages/flow/canvas/node/index.less b/web/src/pages/flow/canvas/node/index.less new file mode 100644 index 000000000..afd79e51a --- /dev/null +++ b/web/src/pages/flow/canvas/node/index.less @@ -0,0 +1,12 @@ +.textUpdaterNode { + height: 50px; + border: 1px solid #eee; + padding: 5px; + border-radius: 5px; + background: white; + label { + display: block; + color: #777; + font-size: 12px; + } +} diff --git a/web/src/pages/flow/canvas/node/index.tsx b/web/src/pages/flow/canvas/node/index.tsx new file mode 100644 index 000000000..f22006bcc --- /dev/null +++ b/web/src/pages/flow/canvas/node/index.tsx @@ -0,0 +1,41 @@ +import { useCallback } from 'react'; +import { Handle, NodeProps, Position } from 'reactflow'; + +import styles from './index.less'; + +const handleStyle = { left: 10 }; + +export function TextUpdaterNode({ + data, + isConnectable = true, +}: NodeProps<{ value: number }>) { + const onChange = useCallback((evt) => { + console.log(evt.target.value); + }, []); + + return ( +
+ + +
+ + +
+ {/* */} +
+ ); +} diff --git a/web/src/pages/flow/flow-sider/index.less b/web/src/pages/flow/flow-sider/index.less new file mode 100644 index 000000000..fcc738224 --- /dev/null +++ b/web/src/pages/flow/flow-sider/index.less @@ -0,0 +1,14 @@ +.operatorCard { + :global(.ant-card-body) { + padding: 10px; + } + .cubeIcon { + &:hover { + cursor: pointer; + } + } +} + +.siderContent { + padding: 10px 4px; +} diff --git a/web/src/pages/flow/flow-sider/index.tsx b/web/src/pages/flow/flow-sider/index.tsx new file mode 100644 index 000000000..439c1265a --- /dev/null +++ b/web/src/pages/flow/flow-sider/index.tsx @@ -0,0 +1,48 @@ +import { Avatar, Card, Flex, Layout, Space } from 'antd'; +import classNames from 'classnames'; +import { useState } from 'react'; +import { componentList } from '../mock'; + +import { useHandleDrag } from '../hooks'; +import styles from './index.less'; + +const { Sider } = Layout; + +const FlowSider = () => { + const [collapsed, setCollapsed] = useState(true); + const { handleDrag } = useHandleDrag(); + + return ( + setCollapsed(value)} + > + + {componentList.map((x) => ( + + + + +
+ {x.name} +
{x.description}
+
+
+
+
+ ))} +
+
+ ); +}; + +export default FlowSider; diff --git a/web/src/pages/flow/hooks.ts b/web/src/pages/flow/hooks.ts new file mode 100644 index 000000000..3fde00654 --- /dev/null +++ b/web/src/pages/flow/hooks.ts @@ -0,0 +1,47 @@ +import React, { Dispatch, SetStateAction, useCallback } from 'react'; +import { Node } from 'reactflow'; + +export const useHandleDrag = () => { + const handleDrag = useCallback( + (operatorId: string) => (ev: React.DragEvent) => { + console.info(ev.clientX, ev.pageY); + ev.dataTransfer.setData('operatorId', operatorId); + ev.dataTransfer.setData('startClientX', ev.clientX.toString()); + ev.dataTransfer.setData('startClientY', ev.clientY.toString()); + }, + [], + ); + + return { handleDrag }; +}; + +export const useHandleDrop = (setNodes: Dispatch>) => { + const allowDrop = (ev: React.DragEvent) => { + ev.preventDefault(); + }; + + const handleDrop = useCallback( + (ev: React.DragEvent) => { + ev.preventDefault(); + const operatorId = ev.dataTransfer.getData('operatorId'); + const startClientX = ev.dataTransfer.getData('startClientX'); + const startClientY = ev.dataTransfer.getData('startClientY'); + console.info(operatorId); + console.info(ev.pageX, ev.pageY); + console.info(ev.clientX, ev.clientY); + console.info(ev.movementX, ev.movementY); + const x = ev.clientX - 200; + const y = ev.clientY - 72; + setNodes((pre) => { + return pre.concat({ + id: operatorId, + position: { x, y }, + data: { label: operatorId }, + }); + }); + }, + [setNodes], + ); + + return { handleDrop, allowDrop }; +}; diff --git a/web/src/pages/flow/index.tsx b/web/src/pages/flow/index.tsx new file mode 100644 index 000000000..d4c7b653f --- /dev/null +++ b/web/src/pages/flow/index.tsx @@ -0,0 +1,20 @@ +import { Layout } from 'antd'; +import FlowCanvas from './canvas'; +import Sider from './flow-sider'; + +const { Content } = Layout; + +function RagFlow() { + return ( + + + + + + + + + ); +} + +export default RagFlow; diff --git a/web/src/pages/flow/mock.tsx b/web/src/pages/flow/mock.tsx new file mode 100644 index 000000000..b27aca08b --- /dev/null +++ b/web/src/pages/flow/mock.tsx @@ -0,0 +1,11 @@ +import { + MergeCellsOutlined, + RocketOutlined, + SendOutlined, +} from '@ant-design/icons'; + +export const componentList = [ + { name: 'Begin', icon: , description: '' }, + { name: 'Retrieval', icon: , description: '' }, + { name: 'Generate', icon: , description: '' }, +]; diff --git a/web/src/routes.ts b/web/src/routes.ts index 5900f9895..fcf051248 100644 --- a/web/src/routes.ts +++ b/web/src/routes.ts @@ -84,6 +84,10 @@ const routes = [ path: '/file', component: '@/pages/file-manager', }, + { + path: '/flow', + component: '@/pages/flow', + }, ], }, {