Skip to content

Commit

Permalink
Merge branch 'master' into dev/diego
Browse files Browse the repository at this point in the history
  • Loading branch information
Diego Struk committed May 7, 2020
2 parents 6a454b0 + 3903abf commit 8106e2e
Show file tree
Hide file tree
Showing 71 changed files with 218 additions and 48 deletions.
24 changes: 24 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.git
.vscode

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ jobs:
run: |
python3 -m pip install --upgrade pip
pip3 install pipenv
cd back-end
pipenv install
pipenv run echo "SECRET_KEY='TEMPORARY SECRET KEY'" > vp/.environment
Expand Down Expand Up @@ -61,4 +62,3 @@ jobs:
with:
collection: Postman/Visual\ Programming-Tests.postman_collection.json
environment: Postman/Local\ Testing.postman_environment.json

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
19 changes: 19 additions & 0 deletions back-end/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM python:3.8

WORKDIR /visual-programming/back-end

COPY Pipfile Pipfile.lock ./
COPY CLI/ ./CLI/
COPY pyworkflow/ ./pyworkflow/

RUN pip install pipenv
RUN pipenv install --dev --ignore-pipfile

COPY vp/ ./vp
RUN echo "SECRET_KEY=tmp" > vp/.environment

EXPOSE 8000

WORKDIR /visual-programming/back-end/vp

CMD pipenv run python manage.py runserver 0.0.0.0:8000
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def get_execution_options(self, workflow, flow_nodes):

if key in flow_nodes:
replacement_value = flow_nodes[key].get_replacement_value()
option.set_value(replacement_value)
else:
replacement_value = option.get_value()

Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ class IntegerNode(FlowNode):
Allows for Strings to replace 'string' fields in Nodes
"""
name = "Integer Input"
num_in = 1
num_out = 1
num_in = 0
num_out = 0
color = 'purple'

OPTIONS = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ class StringNode(FlowNode):
Allows for Strings to replace 'string' fields in Nodes
"""
name = "String Input"
num_in = 1
num_out = 1
num_in = 0
num_out = 0
color = 'purple'

OPTIONS = {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def get_all_flow_var_options(self, node_id):
for predecessor_id in self.get_node_predecessors(node_id):
node = self.get_node(predecessor_id)

if node.node_type == 'FlowNode':
if node.node_type == 'flow_control':
flow_variables.append(node.to_json())

return flow_variables
Expand Down Expand Up @@ -314,7 +314,7 @@ def execute(self, node_id):
except NodeException as e:
raise e

if node_to_execute.data is None:
if node_to_execute.data is None and node_to_execute.node_type != "flow_control":
raise WorkflowException('execute', 'There was a problem saving node output.')

return node_to_execute
Expand Down Expand Up @@ -384,7 +384,7 @@ def load_input_data(self, node_id):
if node_to_retrieve is None:
raise WorkflowException('retrieve node data', 'The workflow does not contain node %s' % predecessor_id)

if node_to_retrieve.node_type != 'FlowNode':
if node_to_retrieve.node_type != 'flow_control':
input_data.append(self.retrieve_node_data(node_to_retrieve))

except WorkflowException:
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
9 changes: 7 additions & 2 deletions vp/vp/settings.py → back-end/vp/vp/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []
ALLOWED_HOSTS = ['back-end:8000',
'back-end',
'localhost',
'127.0.0.1',
'0.0.0.0',
'[::1]']


# Application definition
Expand Down Expand Up @@ -81,7 +86,7 @@

# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
### Not yet setup
# Not yet setup
DATABASES = {}

MEDIA_ROOT = '/tmp'
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: "3.3"
services:
back-end:
build: ./back-end
ports:
- "8000:8000"
command: bash -c "pipenv run python manage.py runserver 0.0.0.0:8000"
environment:
- DJANGO_ENV=development
front-end:
build: ./front-end
stdin_open: true
ports:
- "3000:3000"
environment:
- NODE_ENV=development
depends_on:
- back-end
links:
- back-end
command: npm start
14 changes: 14 additions & 0 deletions front-end/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM node:14-alpine

WORKDIR /visual-programming/front-end

COPY package.json .

RUN npm install

COPY src/ ./src/
COPY public/ ./public/

EXPOSE 3000

CMD npm start
2 changes: 1 addition & 1 deletion front-end/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"last 1 safari version"
]
},
"proxy": "http://localhost:8000",
"proxy": "http://back-end:8000",
"devDependencies": {
"@babel/preset-env": "^7.9.5",
"@babel/preset-react": "^7.9.4",
Expand Down
10 changes: 10 additions & 0 deletions front-end/src/API.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ function fetchWrapper(endpoint, options = {}) {
}


/**
* Retrieve node info from server side workflow
* @param {string} nodeId - ID of node to retrieve
* @returns {Promise<Object>} - server response (node info and flow variables)
*/
export async function getNode(nodeId) {
return fetchWrapper(`/node/${nodeId}`);
}


/**
* Add node to server-side workflow
* @param {CustomNodeModel} node - JS node to add
Expand Down
18 changes: 18 additions & 0 deletions front-end/src/components/CustomNode/CustomNodeModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@ export default class CustomNodeModel extends NodeModel {
this.configParams = options.option_types;
this.options.status = options.status || "unconfigured";

// add flow control input port
this.addPort(
new VPPortModel({
in: true,
type: 'vp-port',
name: 'flow-in'
})
);
// if flow node, add flow control output port
if (this.options.node_type === "flow_control") {
this.addPort(
new VPPortModel({
in: false,
type: 'vp-port',
name: 'flow-out'
})
);
}
const nIn = options.num_in === undefined ? 1 : options.num_in;
const nOut = options.num_out === undefined ? 1 : options.num_out;
// setup in and out ports
Expand Down
45 changes: 30 additions & 15 deletions front-end/src/components/CustomNode/CustomNodeWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,30 @@ export default class CustomNodeWidget extends React.Component {

render() {
const engine = this.props.engine;
const ports = _.values(this.props.node.getPorts());
const allPorts = _.values(this.props.node.getPorts());
const ports = allPorts.filter(p => !p.options.name.includes("flow"));
const flowInPort = allPorts.find(p => p.options.name === "flow-in");
const flowOutPort = allPorts.find(p => p.options.name === "flow-out");
// group ports by type (in/out)
const sortedPorts = _.groupBy(ports, p => p.options.in === true ? "in" : "out");
// create PortWidget array for each type
const portWidgets = {};
for (let portType in sortedPorts) {
portWidgets[portType] = sortedPorts[portType].map(port =>
<PortWidget engine={engine} port={port} key={port.getID()}>
<div className="triangle-port" />
<div className="triangle-port" />
</PortWidget>
);
}

const flowPortWidgets = [flowInPort, flowOutPort].filter(p => p).map(port =>
<PortWidget engine={engine} port={port} key={port.getID()}
className={`flow-port-div flow-port-div-${port.options.in ? "in" : "out"}`}>
<div className="flow-port" />
</PortWidget>
);


let graphView;
let width = 40;
if (this.props.node.options.node_type !== "flow_control") {
Expand All @@ -75,19 +86,23 @@ export default class CustomNodeWidget extends React.Component {
<div className="custom-node-wrapper">
<div className="custom-node-name">{this.props.node.options.name}</div>
<div className="custom-node" style={{ borderColor: this.props.node.options.color, width: width }}>
<div className="custom-node-configure" onClick={this.toggleConfig}>{String.fromCharCode(this.icon)}</div>
<NodeConfig node={this.props.node}
globals={this.props.engine.model.globals || []}
show={this.state.showConfig}
toggleShow={this.toggleConfig}
onDelete={this.handleDelete}
onSubmit={this.acceptConfiguration} />
{graphView}
<GraphView node={this.props.node}
show={this.state.showGraph}
toggleShow={this.toggleGraph}
onDelete={this.handleDelete}
onSubmit={this.acceptConfiguration} />
<div className="custom-node-icons">
<div className="custom-node-configure" onClick={this.toggleConfig}>
{String.fromCharCode(this.icon)}
</div>
<NodeConfig node={this.props.node}
show={this.state.showConfig}
toggleShow={this.toggleConfig}
onDelete={this.handleDelete}
onSubmit={this.acceptConfiguration} />
{graphView}
<GraphView node={this.props.node}
show={this.state.showGraph}
toggleShow={this.toggleGraph}
onDelete={this.handleDelete}
onSubmit={this.acceptConfiguration} />
</div>
{flowPortWidgets}
<div className="port-col port-col-in">
{ portWidgets["in"] }
</div>
Expand Down
28 changes: 20 additions & 8 deletions front-end/src/components/CustomNode/NodeConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,25 @@ export default class NodeConfig extends React.Component {
this.state = {
disabled: false,
data: {},
flowData: {}
flowData: {},
flowNodes: []
};
this.updateData = this.updateData.bind(this);
this.handleDelete = this.handleDelete.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}

getFlowNodes() {
if (!this.props.node) return;
API.getNode(this.props.node.options.id)
.then(node => this.setState({flowNodes: node.flow_variables}))
.catch(err => console.log(err));
}

componentDidUpdate(prevProps) {
if (!prevProps.show && this.props.show) this.getFlowNodes();
}

// callback to update form data in state;
// resulting state will be sent to node config callback
updateData(key, value, flow = false) {
Expand Down Expand Up @@ -82,7 +94,7 @@ export default class NodeConfig extends React.Component {
value={this.props.node.config[key]}
flowValue={this.props.node.options.option_replace ?
this.props.node.options.option_replace[key] : null}
globals={this.props.globals}
flowNodes={this.state.flowNodes}
disableFunc={(v) => this.setState({disabled: v})}/>
)}
<Form.Group>
Expand Down Expand Up @@ -149,7 +161,7 @@ function OptionInput(props) {
}

const hideFlow = props.node.options.is_global
|| props.type === "file" || props.globals.length === 0
|| props.type === "file" || props.flowNodes.length === 0;
return (
<Form.Group>
<Form.Label>{props.label}</Form.Label>
Expand All @@ -159,7 +171,7 @@ function OptionInput(props) {
{hideFlow ? null :
<FlowVariableOverride keyName={props.keyName}
flowValue={props.flowValue || {}}
flowNodes={props.globals || []}
flowNodes={props.flowNodes || []}
checked={isFlow}
onFlowCheck={handleFlowCheck}
onChange={handleFlowVariable} />
Expand Down Expand Up @@ -290,7 +302,7 @@ function FlowVariableOverride(props) {

const handleSelect = (event) => {
const uuid = event.target.value;
const flow = props.flowNodes.find(d => d.id === uuid);
const flow = props.flowNodes.find(d => d.node_id === uuid);
const obj = {
node_id: uuid,
is_global: flow.is_global
Expand All @@ -308,9 +320,9 @@ function FlowVariableOverride(props) {
<Form.Control as="select" name={props.keyName} onChange={handleSelect}
value={props.flowValue.node_id}>
<option/>
{props.flowNodes.map(gfv =>
<option key={gfv.id} value={gfv.id}>
{gfv.options.var_name}
{props.flowNodes.map(fv =>
<option key={fv.node_id} value={fv.node_id}>
{fv.options ? fv.options.var_name : fv.option_values.var_name}
</option>
)}
</Form.Control>
Expand Down
4 changes: 2 additions & 2 deletions front-end/src/components/VPLink/VPLinkModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ export default class VPLinkModel extends DefaultLinkModel {
constructor() {
super({
type: 'default',
width: 5,
color: 'orange'
width: 2,
color: 'black'
});
this.registerListener({
targetPortChanged: event => {
Expand Down
Loading

0 comments on commit 8106e2e

Please sign in to comment.