From 140b8c5a9a4059838dfff247c6560d273c0f5064 Mon Sep 17 00:00:00 2001 From: Samir Reddigari Date: Sat, 25 Apr 2020 17:00:57 -0400 Subject: [PATCH 1/6] refactor(ui): move node retrieval to separate method --- front-end/src/components/Workspace.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/front-end/src/components/Workspace.js b/front-end/src/components/Workspace.js index 57c0f32..c5b7a68 100644 --- a/front-end/src/components/Workspace.js +++ b/front-end/src/components/Workspace.js @@ -22,6 +22,7 @@ class Workspace extends React.Component { this.engine.setModel(this.model); this.engine.setMaxNumberPointsPerLink(0); this.state = {nodes: []}; + this.getAvailableNodes = this.getAvailableNodes.bind(this); this.load = this.load.bind(this); this.clear = this.clear.bind(this); this.handleNodeCreation = this.handleNodeCreation.bind(this); @@ -29,10 +30,17 @@ class Workspace extends React.Component { } componentDidMount() { + this.getAvailableNodes(); + API.initWorkflow(this.model).catch(err => console.log(err)); + } + + /** + * Retrieve available nodes from server to display in menu + */ + getAvailableNodes() { API.getNodes() .then(nodes => this.setState({nodes: nodes})) .catch(err => console.log(err)); - API.initWorkflow(this.model).catch(err => console.log(err)); } /** From 7b9b4f399e10b05e666859f6b766f8a4fba8c408 Mon Sep 17 00:00:00 2001 From: Samir Reddigari Date: Sat, 25 Apr 2020 17:01:42 -0400 Subject: [PATCH 2/6] feat(ui): add component to upload custom node definition --- front-end/src/components/CustomNodeUpload.js | 48 ++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 front-end/src/components/CustomNodeUpload.js diff --git a/front-end/src/components/CustomNodeUpload.js b/front-end/src/components/CustomNodeUpload.js new file mode 100644 index 0000000..f9a744b --- /dev/null +++ b/front-end/src/components/CustomNodeUpload.js @@ -0,0 +1,48 @@ +import React, {useRef, useState} from "react"; +import * as API from "../API"; +import {Button} from "react-bootstrap"; + + +export default function CustomNodeUpload({ onUpload }) { + + const input = useRef(null); + const [status, setStatus] = useState("ready"); + + const uploadFile = async file => { + setStatus("loading"); + const fd = new FormData(); + fd.append("file", file); + API.uploadDataFile(fd) + .then(resp => { + onUpload(); + setStatus("ready"); + }).catch(() => { + setStatus("failed"); + }); + input.current.value = null; + }; + const onFileSelect = e => { + e.preventDefault(); + if (!input.current.files) return; + uploadFile(input.current.files[0]); + }; + + let content; + if (status === "loading") { + content =
Uploading file...
; + } else if (status === "failed") { + content = (
Upload failed. Try a new file.
); + } + return ( + <> + + + {content} + + ) +} From 3d92f0b6deffe46b75dc1701300b3c3d08bee7d6 Mon Sep 17 00:00:00 2001 From: Samir Reddigari Date: Sat, 25 Apr 2020 17:02:36 -0400 Subject: [PATCH 3/6] feat(ui): render node upload in menu --- front-end/src/components/NodeMenu.js | 2 ++ front-end/src/components/Workspace.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/front-end/src/components/NodeMenu.js b/front-end/src/components/NodeMenu.js index b84d9c0..9b151c0 100644 --- a/front-end/src/components/NodeMenu.js +++ b/front-end/src/components/NodeMenu.js @@ -1,6 +1,7 @@ import React from 'react'; import * as _ from 'lodash'; import { Col } from 'react-bootstrap'; +import CustomNodeUpload from "./CustomNodeUpload"; export default function NodeMenu(props) { @@ -24,6 +25,7 @@ export default function NodeMenu(props) { )} + ); } diff --git a/front-end/src/components/Workspace.js b/front-end/src/components/Workspace.js index c5b7a68..32e580a 100644 --- a/front-end/src/components/Workspace.js +++ b/front-end/src/components/Workspace.js @@ -115,7 +115,7 @@ class Workspace extends React.Component { - +
this.handleNodeCreation(event)} From 2f630adafcebd6ed751d894de0534104a5ff837e Mon Sep 17 00:00:00 2001 From: Samir Reddigari Date: Sat, 25 Apr 2020 18:58:07 -0400 Subject: [PATCH 4/6] feat(ui): display invalid nodes with error icon --- front-end/src/components/NodeMenu.js | 30 ++++++++++++++++++---------- front-end/src/styles/Workspace.css | 14 ++++++++++--- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/front-end/src/components/NodeMenu.js b/front-end/src/components/NodeMenu.js index 9b151c0..0928804 100644 --- a/front-end/src/components/NodeMenu.js +++ b/front-end/src/components/NodeMenu.js @@ -19,7 +19,8 @@ export default function NodeMenu(props) { const config = data.options; delete data.options; return ( - + )} )} @@ -32,16 +33,23 @@ export default function NodeMenu(props) { function NodeMenuItem(props) { + if (!props.nodeInfo.missing_packages) { + return ( +
  • { + event.dataTransfer.setData( + 'storm-diagram-node', + JSON.stringify(props)); + }} + style={{color: props.nodeInfo.color}}> + {props.nodeInfo.name} +
  • + } else { + return ( +
  • {props.nodeInfo.filename}
  • + ) + } return ( -
  • { - event.dataTransfer.setData( - 'storm-diagram-node', - JSON.stringify(props)); - }} - style={{ color: props.nodeInfo.color }}> - {props.nodeInfo.name} -
  • ) } diff --git a/front-end/src/styles/Workspace.css b/front-end/src/styles/Workspace.css index ee60a27..d448cec 100644 --- a/front-end/src/styles/Workspace.css +++ b/front-end/src/styles/Workspace.css @@ -16,14 +16,22 @@ linear-gradient(to bottom, rgba(54, 169, 231, 0.1) 1px, transparent 1px); } .NodeMenuItem { - cursor: pointer; background-color: white; - border-radius: 5px; margin-bottom: 3px; + box-shadow: 0px 2px 4px gray; +} +.NodeMenuItem[draggable] { + cursor: pointer; } -.NodeMenuItem::before { +.NodeMenuItem[draggable]::before { content: "+"; padding-right: 10px; padding-left: 5px; color: black; } +.NodeMenuItem.invalid::before { + content: "\26a0"; + padding-right: 10px; + padding-left: 5px; + color: red; +} From fe06124506866888654f17710d60017989c36908 Mon Sep 17 00:00:00 2001 From: Samir Reddigari Date: Sat, 25 Apr 2020 18:59:18 -0400 Subject: [PATCH 5/6] feat(ui): add tooltips with node docs or errors --- front-end/src/components/NodeMenu.js | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/front-end/src/components/NodeMenu.js b/front-end/src/components/NodeMenu.js index 0928804..fbdaa68 100644 --- a/front-end/src/components/NodeMenu.js +++ b/front-end/src/components/NodeMenu.js @@ -1,6 +1,6 @@ import React from 'react'; import * as _ from 'lodash'; -import { Col } from 'react-bootstrap'; +import { Col, OverlayTrigger, Tooltip } from 'react-bootstrap'; import CustomNodeUpload from "./CustomNodeUpload"; @@ -34,7 +34,12 @@ export default function NodeMenu(props) { function NodeMenuItem(props) { if (!props.nodeInfo.missing_packages) { + const tooltip = props.nodeInfo.doc || "This node has no documentation." return ( + }>
  • { @@ -45,11 +50,27 @@ function NodeMenuItem(props) { style={{color: props.nodeInfo.color}}> {props.nodeInfo.name}
  • +
    + ) } else { + let tooltip = "These Python modules could not be imported: "; + tooltip += props.nodeInfo.missing_packages.join(", "); return ( + }>
  • {props.nodeInfo.filename}
  • +
    ) } +} + + +// Overlay with props has to use ref forwarding +const NodeTooltip = React.forwardRef((props, ref) => { return ( + {props.message} ) -} +}); + From 7711c398e14ad7f0ca9edc65980579d748028b27 Mon Sep 17 00:00:00 2001 From: Samir Reddigari Date: Sun, 26 Apr 2020 14:04:04 -0400 Subject: [PATCH 6/6] feat(ui): display newlines in docstring tooltips --- front-end/src/components/NodeMenu.js | 30 ++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/front-end/src/components/NodeMenu.js b/front-end/src/components/NodeMenu.js index fbdaa68..ac13fa6 100644 --- a/front-end/src/components/NodeMenu.js +++ b/front-end/src/components/NodeMenu.js @@ -32,9 +32,26 @@ export default function NodeMenu(props) { } +/** + * Format docstring with newlines into tooltip content + * @param string - node docstring + * @returns {array} - array of strings and HTML elements + */ +function formatTooltip(string) { + const split = string.split("\n"); + const out = []; + split.forEach((line, i) => { + out.push(line); + out.push(
    ); + }); + out.pop(); + return out; +} + + function NodeMenuItem(props) { if (!props.nodeInfo.missing_packages) { - const tooltip = props.nodeInfo.doc || "This node has no documentation." + const tooltip = props.nodeInfo.doc ? formatTooltip(props.nodeInfo.doc) : "This node has no documentation." return ( ) } else { - let tooltip = "These Python modules could not be imported: "; - tooltip += props.nodeInfo.missing_packages.join(", "); + let tooltip = "These Python modules could not be imported:\n\n" + + props.nodeInfo.missing_packages.join("\n"); + tooltip = formatTooltip(tooltip); return ( { return ( - {props.message} + +
    + {props.message} +
    +
    ) });