From 42873275c0b9cefde014475e8c8ae7ad3726404c Mon Sep 17 00:00:00 2001 From: larsgson <4819617+larsgson@users.noreply.github.com> Date: Thu, 28 Jul 2022 23:21:29 +0200 Subject: [PATCH 1/4] added graph UI (read only - non interactiv) --- package.json | 1 + src/App.css | 14 +++++ src/App.js | 148 ++++++++++++++++++++++++++++++++++++++++++++++++--- yarn.lock | 91 +++++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 5ff716f..e966dec 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "proskomma-react-hooks": "^2.4.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-flow-renderer": "^10.3.12", "react-json-view": "^1.21.3", "react-scripts": "5.0.1", "web-vitals": "^2.1.0", diff --git a/src/App.css b/src/App.css index bf3fd29..c2017d1 100644 --- a/src/App.css +++ b/src/App.css @@ -44,6 +44,20 @@ header { } +.graph-pane-hidden { + display: none; +} + +.react-flow { + width: 100%; + min-height: 40vh; + height: 40vh; +} + +.react-flow__attribution.bottom.right { + display: none; +} + .result-pane { min-width: 69vw; max-width: 69vw; diff --git a/src/App.js b/src/App.js index 07e6183..8cf777b 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,4 @@ -import React, {useState} from 'react'; +import React, {useState,useCallback} from 'react'; import {useProskomma} from 'proskomma-react-hooks'; import deepCopy from 'deep-copy-all'; @@ -8,18 +8,115 @@ import runCallback from "./lib/runCallback"; import DisplayResult from "./components/DisplayResult"; import DisplayIssues from "./components/DisplayIssues"; import LoadSteps from "./components/LoadSteps"; +import ReactFlow, { + addEdge, + Background, + useNodesState, + useEdgesState, +} from 'react-flow-renderer'; import './App.css'; +const graphStyles = { width: "100%", height: "500px" }; + function App() { const [specSteps, setSpecSteps] = useState([]); const [nextStepId, setNextStepId] = useState(1); const [results, setResults] = useState([]); const [runIssues, setRunIssues] = useState([]); const [expandSpecs, setExpandSpecs] = useState(true); + const [showGraph, setShowGraph] = useState(false) + const [flowInstance,setFlowInstance] = useState({}) const {proskomma} = useProskomma({verbose: false}); + const [nodes, setNodes, onNodesChange] = useNodesState([]); + const [edges, setEdges, onEdgesChange] = useEdgesState([]); + const onConnect = useCallback((params) => setEdges((eds) => addEdge(params, eds)), [setEdges]); + const onInit = (reactFlowInstance) => { + console.log('flow loaded:', reactFlowInstance); + setFlowInstance(reactFlowInstance) + } + + const setNodeAndSpecStep = (specs) => { + setSpecSteps(specs) + const stepY = 60; + let sourceY = 0; + let transformY = 0; + let outputY = 0; + let position = {}; + const mappedNodes = specs.map( step => { + let sourcePosition = undefined; + let targetPosition = undefined; + let type = undefined; + let draggable = true; + let colorStr = ""; + if (step.type==='Source') { + sourcePosition = 'right'; + type = 'input'; + draggable = false; + position = { x: 0, y: (sourceY * stepY) }; + sourceY++; + colorStr = 'green'; + } else if (step.type==='Display') { + targetPosition = 'left'; + type = 'output'; + position = { x: 500, y: (outputY * stepY) }; + outputY++; + colorStr = 'blue'; + } else { + sourcePosition = 'right'; + targetPosition = 'left'; + position = { x: 250, y: (transformY * stepY) }; + transformY++; + colorStr = 'red'; + } + return { + ...step, + sourcePosition, + targetPosition, + data: { label: step.title }, + id: step.id.toString(), + draggable, + position, + type, + style: { border: `2px solid ${colorStr}`, padding: 10 }, + } + }) + setNodes(mappedNodes) + const mappedEdges = [] + specs.forEach( step => { + const target = step.id.toString(); + step.inputs && step.inputs.forEach( i => { + const srcIdStr = i.source.match(/\d+/) + const findNode = mappedNodes.filter(n => n.id === srcIdStr[0]) + if (findNode[0]) { + const source = findNode[0].id.toString() + mappedEdges.push({ + id: `e${target}-${source}`, + source, + target + }) + } + }) + if (step.inputSource) { + const srcIdStr = step.inputSource.match(/\d+/) + const findNode = mappedNodes.filter(n => n.id === srcIdStr[0]) + if (findNode[0]) { + const source = findNode[0].id.toString() + mappedEdges.push({ + id: `e${target}-${source}`, + source, + target + }) + } + } + }) + setEdges(mappedEdges) + flowInstance.zoomIn() + flowInstance.fitView() + } + const cleanSteps = steps => { const ret = deepCopy(steps); for (const step of ret) { @@ -43,7 +140,7 @@ function App() { } const addStepCallback = stepType => { - setSpecSteps( + setNodeAndSpecStep( [ ...specSteps, { @@ -75,7 +172,8 @@ function App() { newSpec[key] = newTemplate[key]; } } - setSpecSteps(specSteps.map(v => v.id === newSpec.id ? newSpec : v)); + + setNodeAndSpecStep(specSteps.map(v => v.id === newSpec.id ? newSpec : v)); } const moveCallback = (specPosition, direction) => { @@ -86,17 +184,18 @@ function App() { } else { specs.splice(specPosition + 1, 0, specSteps[specPosition]); } - setSpecSteps(specs); + + setNodeAndSpecStep(specs); } - const deleteCallback = deleteId => setSpecSteps(specSteps.filter(v => v.id !== deleteId)); + const deleteCallback = deleteId => setNodeAndSpecStep(specSteps.filter(v => v.id !== deleteId)); const clearResultsCallback = () => { setResults([]); setRunIssues([]); } - return ( + return (

@@ -116,8 +215,43 @@ function App() {

+
+ { + // To do: might add interactivity features here + // console.log("click", element); + }} + fitView + > + + +
+ {(nodes && nodes.length>0) && ( + + Graph view + + + )}

Build your Pipeline Here @@ -153,7 +287,7 @@ function App() { Load Steps from File diff --git a/yarn.lock b/yarn.lock index e0f1fa1..51207e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1356,6 +1356,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a" + integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.9.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.0.tgz#337eda67401f5b066a6f205a3113d4ac18ba495b" @@ -3540,6 +3547,11 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== +classcat@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/classcat/-/classcat-5.0.3.tgz#38eaa0ec6eb1b10faf101bbcef2afb319c23c17b" + integrity sha512-6dK2ke4VEJZOFx2ZfdDAl5OhEL8lvkl6EHF92IfRePfHxQTqir5NlcNVUv+2idjDqCX2NDc8m8YSAI5NI975ZQ== + clean-css@^5.2.2: version "5.3.1" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.1.tgz#d0610b0b90d125196a2894d35366f734e5d7aa32" @@ -3994,6 +4006,68 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2" integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA== +"d3-color@1 - 3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" + integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== + +"d3-dispatch@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e" + integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== + +"d3-drag@2 - 3", d3-drag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba" + integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg== + dependencies: + d3-dispatch "1 - 3" + d3-selection "3" + +"d3-ease@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" + integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== + +"d3-interpolate@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" + integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== + dependencies: + d3-color "1 - 3" + +"d3-selection@2 - 3", d3-selection@3, d3-selection@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31" + integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== + +"d3-timer@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== + +"d3-transition@2 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f" + 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" + +d3-zoom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3" + 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" + d64@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/d64/-/d64-1.0.0.tgz#4002a87e850cbfc9f9d9706b60fca613a3336e90" @@ -8486,6 +8560,18 @@ react-error-overlay@^6.0.11: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== +react-flow-renderer@^10.3.12: + version "10.3.12" + resolved "https://registry.yarnpkg.com/react-flow-renderer/-/react-flow-renderer-10.3.12.tgz#ed603e7cab298aee7003e325cebc08372a4e2ca0" + integrity sha512-DTaz4HV0rA/qtvY80fjdb/QwIvtZEhqCQ2iAqfzFH08RjWCrLmESX4Nc400EB3CGcCK8/pDn/ta4cOS3udunTw== + dependencies: + "@babel/runtime" "^7.18.9" + classcat "^5.0.3" + d3-drag "^3.0.0" + d3-selection "^3.0.0" + d3-zoom "^3.0.0" + zustand "^3.7.2" + react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -10579,3 +10665,8 @@ zen-observable@0.8.15: version "0.8.15" resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== + +zustand@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.7.2.tgz#7b44c4f4a5bfd7a8296a3957b13e1c346f42514d" + integrity sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA== From 6d76045227f38349117a7928985948307d68d68a Mon Sep 17 00:00:00 2001 From: Mark Howe Date: Fri, 29 Jul 2022 11:02:20 +0200 Subject: [PATCH 2/4] Full screen graph --- src/App.css | 19 +++++++- src/App.js | 130 ++++++++++++++++++++++++++++------------------------ 2 files changed, 89 insertions(+), 60 deletions(-) diff --git a/src/App.css b/src/App.css index 623ea1c..ac25f6d 100644 --- a/src/App.css +++ b/src/App.css @@ -339,4 +339,21 @@ select { button.editor-tab:disabled { border-bottom: 2px solid lime; color: #56c156; -} \ No newline at end of file +} + +.graph-button { + float: left; + background-color: transparent; + color: #AAA; + font-weight: bold; + font-size: large +} + +.opened-graph-button { + float: right; + background-color: transparent; + color: #AAA; + font-weight: bold; + font-size: large +} + diff --git a/src/App.js b/src/App.js index e1358cb..4d6f56a 100644 --- a/src/App.js +++ b/src/App.js @@ -34,7 +34,7 @@ function App() { const [edges, setEdges, onEdgesChange] = useEdgesState([]); const onConnect = useCallback((params) => setEdges((eds) => addEdge(params, eds)), [setEdges]); const onInit = (reactFlowInstance) => { - console.log('flow loaded:', reactFlowInstance); + // console.log('flow loaded:', reactFlowInstance); setFlowInstance(reactFlowInstance) } @@ -216,6 +216,14 @@ function App() {
+
-
-
- {(nodes && nodes.length>0) && ( - - Graph view - - - )} -

+ {!showGraph && + <> +
+
+

Build your Pipeline Here {"Spec "} - + Add a Display Step - + Expand All Steps -

- { - specSteps.map( - (ss, n) => - - ) - } + {(nodes && nodes.length > 0) && ( + + Graph view + + + )} +

+ { + specSteps.map( + (ss, n) => + + ) + } +
-
-
-
-

+
+
+

Run the steps - + See the Results of your Pipeline Here - {"Result "} + {"Result "} - + Delete the results

- { - runIssues.length > 0 && - - } - { - runIssues.length === 0 && - - } - +

+ { + runIssues.length > 0 && + + } + { + runIssues.length === 0 && + + } + +
-

+ + }
); From 0ca6707363fef399003e857fcacd7ce518754cc2 Mon Sep 17 00:00:00 2001 From: Mark Howe Date: Fri, 29 Jul 2022 12:46:59 +0200 Subject: [PATCH 3/4] Make graph full screen --- src/App.css | 5 +++++ src/App.js | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/App.css b/src/App.css index ac25f6d..2923582 100644 --- a/src/App.css +++ b/src/App.css @@ -44,6 +44,11 @@ header { } +.graph-pane, .graph-pane-hidden { + width: 1000px; + height: 800px +} + .graph-pane-hidden { display: none; } diff --git a/src/App.js b/src/App.js index 4d6f56a..68638b4 100644 --- a/src/App.js +++ b/src/App.js @@ -212,18 +212,20 @@ function App() { className="tooltiptext rtooltiptext">It's called Perfidy because... oh never mind - an IDE for PERF + {showGraph && + + }
- Date: Fri, 29 Jul 2022 14:16:17 +0200 Subject: [PATCH 4/4] Remove useless size CSS --- src/App.css | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/App.css b/src/App.css index 2923582..d97fca5 100644 --- a/src/App.css +++ b/src/App.css @@ -44,10 +44,7 @@ header { } -.graph-pane, .graph-pane-hidden { - width: 1000px; - height: 800px -} +.graph-pane, .graph-pane-hidden {} .graph-pane-hidden { display: none;