diff --git a/front-end/package-lock.json b/front-end/package-lock.json
index a5eccc8..4288ba8 100644
--- a/front-end/package-lock.json
+++ b/front-end/package-lock.json
@@ -11563,6 +11563,14 @@
}
}
},
+ "react-spinners-css": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/react-spinners-css/-/react-spinners-css-1.1.7.tgz",
+ "integrity": "sha512-wcnFtGXCgFbIDsPr9CDoDU+F01uojf+ot/jJi4DUfHJ9S/zVRE7lIfSbsSHtIeDltclr3Dq9rHnAUdYaOt4SIg==",
+ "requires": {
+ "prop-types": "^15.7.2"
+ }
+ },
"react-test-renderer": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.13.1.tgz",
diff --git a/front-end/package.json b/front-end/package.json
index 7b0b6ce..c5a94d7 100644
--- a/front-end/package.json
+++ b/front-end/package.json
@@ -22,6 +22,7 @@
"react-bootstrap": "^1.0.0-beta.17",
"react-dom": "^16.13.0",
"react-scripts": "3.4.1",
+ "react-spinners-css": "^1.1.7",
"react-window": "^1.8.5",
"regenerator-runtime": "^0.13.5",
"resize-observer-polyfill": "^1.5.1"
diff --git a/front-end/src/API.js b/front-end/src/API.js
index ef08f75..94790cd 100644
--- a/front-end/src/API.js
+++ b/front-end/src/API.js
@@ -144,9 +144,18 @@ export async function uploadWorkflow(formData) {
async function handleEdge(link, method) {
const sourceId = link.getSourcePort().getNode().options.id;
const targetId = link.getTargetPort().getNode().options.id;
- return fetchWrapper(
- `/node/edge/${sourceId}/${targetId}`,
- {method: method});
+
+ let endpoint;
+
+ if (link.getSourcePort().options.in) {
+ // If edge goes from IN port -> OUT port, reverse the ports
+ endpoint = `/node/edge/${targetId}/${sourceId}`;
+ } else {
+ // Otherwise, keep source -> target edge
+ endpoint = `/node/edge/${sourceId}/${targetId}`;
+ }
+
+ return fetchWrapper(endpoint, {method: method});
}
diff --git a/front-end/src/components/CustomNode/CustomNodeWidget.js b/front-end/src/components/CustomNode/CustomNodeWidget.js
index f042588..3cf8cbc 100644
--- a/front-end/src/components/CustomNode/CustomNodeWidget.js
+++ b/front-end/src/components/CustomNode/CustomNodeWidget.js
@@ -59,19 +59,29 @@ export default class CustomNodeWidget extends React.Component {
);
}
+
+ let graphView;
+ let width = 40;
+ if (this.props.node.options.node_type !== "flow_control") {
+ graphView = (
+
+
+
+ );
+ width = 80;
+ }
+
return (
{this.props.node.options.name}
-
+
{String.fromCharCode(this.icon)}
-
-
-
+ {graphView}
{
return 10 * this.state.widths[index];
- }
+ };
rowHeights = () => new Array(765)
.fill(true)
@@ -32,109 +33,127 @@ export default class GraphView extends React.Component {
this.props.toggleShow();
};
- computeWidths = (columnCount, rowCount, json) => {
- const widths = new Array(columnCount);
- const keys = Object.keys(json);
- for (let index = 0; index < columnCount; index++) {
- const key = keys[index];
- widths[index] = key.length;
- for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
- const value = json[key][rowIndex.toString()];
- if (value != null && value.length > widths[index]) {
- widths[index] = value.length;
- }
+ /**
+ * Compute width of grid columns.
+ *
+ * Width is based on the maximum-length cell contained within the JSON data.
+ *
+ * @param {Object} columns The column information from the data
+ * @param {int} rowCount Number of rows in the data
+ * @param {Object} data The raw data from Node execution
+ * @returns {any[]}
+ */
+ computeWidths = (columns, rowCount, data) => {
+ const columnCount = columns.length;
+ const widths = new Array(columnCount);
+ let maxWidth = this.state.maxWidth;
+
+ for (let index = 0; index < columnCount; index++) {
+ const column = columns[index];
+ widths[index] = column.length;
+
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
+ const row = data[column][rowIndex.toString()];
+
+ if (row != null && row.length > widths[index]) {
+ widths[index] = row.length;
+ }
+
+ maxWidth += widths[index] * 10;
+ }
}
- }
- return widths;
- }
+ this.setState({maxWidth: maxWidth});
+ return widths;
+ };
load = async () => {
- this.setState({loading: true})
- API.retrieveData(this.key_id)
+ this.setState({loading: true});
+
+ API.retrieveData(this.key_id)
.then(json => {
- const keys = Object.keys(json);
- const columnCount = keys.length;
- const rows = Object.keys(json[keys[0]]);
- const rowCount = rows.length;
- const widths = this.computeWidths(columnCount, rowCount, json);
- this.setState({ data: json,
- keys: keys,
- columnCount: columnCount,
- rowCount: rowCount,
- loading: false,
- widths: widths});
- }).catch(err => console.log(err));
- }
+ const columns = Object.keys(json);
+ const rows = Object.keys(json[columns[0]]);
+ const widths = this.computeWidths(columns, rows.length, json);
+
+ this.setState({
+ data: json,
+ columns: columns,
+ rows: rows,
+ loading: false,
+ widths: widths
+ });
+ })
+ .catch(err => console.error(err));
+ };
Cell = ({ columnIndex, rowIndex, style }) => {
- const className = columnIndex % 2
- ? rowIndex % 2 === 0
- ? 'GridItemOdd'
- : 'GridItemEven'
- : rowIndex % 2
- ? 'GridItemOdd'
- : 'GridItemEven';
-
- if (rowIndex === 0) {
- return (
-
- {this.state.keys[columnIndex]}
-
- );
- }
+ const className = (rowIndex % 2 === 0) ? 'GridItemEven' : 'GridItemOdd';
+ const column = this.state.columns[columnIndex];
return (
- {this.state.data[this.state.keys[columnIndex]][rowIndex.toString()] }
+ {(rowIndex === 0) ? column : this.state.data[column][rowIndex.toString()]}
);
- }
+ };
render() {
+ let body;
+ let footer;
+
if (this.state.loading) {
- return (Loading data...
);
+ // Print loading spinner
+ body = ();
+ } else if (this.state.data.length < 1) {
+ // Print instructions about loading
+ body = "Loading the data might take a while depending on how big the data is.";
+ footer = (
+
+
+
+
+ );
+ } else {
+ // Display the grid
+ let displayHeight = this.state.rows.length * 20;
+ let displayWidth = this.state.maxWidth;
+
+ body = (
+ this.columnWidths(index)}
+ height={displayHeight < 600 ? displayHeight + 5 : 600}
+ rowCount={this.state.rows.length}
+ rowHeight={index => 20}
+ width={displayWidth < 900 ? displayWidth : 900}
+ >
+ {this.Cell}
+
+ );
}
- if (this.state.columnCount < 1) {
- return (
- e.stopPropagation()}>
-
- {this.props.node.options.name} View
+ return (
+ e.stopPropagation()}
+ >
+
+ {this.props.node.options.name} View
- Loading the data might take a while depending on how big the data is.
+ {body}
-
-
-
-
-
- );
- }
-
- return (
- e.stopPropagation()}>
-
- {this.props.node.options.name} View
-
-
- this.columnWidths(index)}
- height={150}
- rowCount={this.state.rowCount}
- rowHeight={index => 20}
- width={480}
- >
- {this.Cell}
-
-
+ {footer}
);
}
@@ -145,4 +164,4 @@ GraphView.propTypes = {
show: propTypes.bool,
toggleShow: propTypes.func,
onClose: propTypes.func,
-}
+};
diff --git a/front-end/src/styles/GraphView.css b/front-end/src/styles/GraphView.css
index 8c4e7a5..4648200 100644
--- a/front-end/src/styles/GraphView.css
+++ b/front-end/src/styles/GraphView.css
@@ -1,14 +1,21 @@
.Grid {
border: 1px solid #d9dddd;
width: auto;
+ margin: auto;
}
.GridItemEven, .GridItemOdd {
display: flex;
align-items: center;
justify-content: center;
+ border-right: 1px solid grey;
+ border-bottom: 1px solid grey;
}
.GridItemEven {
background-color: #f8f8f0;
}
+
+.GraphView {
+ max-width: 925px;
+}
\ No newline at end of file