diff --git a/app/static/app/js/components/EditTaskPanel.jsx b/app/static/app/js/components/EditTaskPanel.jsx index 039af122..aa7fe95f 100644 --- a/app/static/app/js/components/EditTaskPanel.jsx +++ b/app/static/app/js/components/EditTaskPanel.jsx @@ -1,5 +1,6 @@ import '../css/EditTaskPanel.scss'; import React from 'react'; +import ProcessingNodeOption from './ProcessingNodeOption'; class EditTaskPanel extends React.Component { constructor(){ @@ -9,66 +10,198 @@ class EditTaskPanel extends React.Component { this.state = { name: "", - advancedOptions: false + advancedOptions: false, + loadedProcessingNodes: false, + selectedNode: null, + processingNodes: [], + editing: true }; + // Refs to ProcessingNodeOption components + this.options = {}; + this.handleNameChange = this.handleNameChange.bind(this); this.setAdvancedOptions = this.setAdvancedOptions.bind(this); + this.handleSelectNode = this.handleSelectNode.bind(this); + this.setOptionRef = this.setOptionRef.bind(this); this.save = this.save.bind(this); + this.edit = this.edit.bind(this); + } + + componentDidMount(){ + // Load projects from API + const loadProcessingNodes = () => { + function failed(){ + // Try again + setTimeout(loadProcessingNodes, 1000); + } + + this.nodesRequest = $.getJSON("/api/processingnodes/", json => { + if (Array.isArray(json)){ + + let nodes = json.map(node => { + return { + id: node.id, + key: node.id, + label: `${node.hostname}:${node.port} (queue: ${node.queue_count})`, + options: node.available_options + }; + }); + + // Find a node with lowest queue count + let minQueueCount = Math.min(...json.map(node => node.queue_count)); + let minQueueCountnodes = json.filter(node => node.queue_count === minQueueCount); + + // Choose at random + let autoNode = minQueueCountnodes[~~(Math.random() * minQueueCountnodes.length)]; + + nodes.unshift({ + id: autoNode.id, + key: "auto", + label: "Auto", + options: autoNode.available_options + }); + + this.setState({ + selectedNode: nodes[0], + processingNodes: nodes, + loadedProcessingNodes: true + }); + }else{ + console.error("Got invalid json response for processing nodes", json); + failed(); + } + }) + .fail((jqXHR, textStatus, errorThrown) => { + // I don't expect this to fail, unless it's a development error or connection error. + // in which case we don't need to notify the user directly. + console.error("Error retrieving processing nodes", jqXHR, textStatus); + failed(); + }); + } + loadProcessingNodes(); + } + + componentWillUnmount(){ + this.nodesRequest.abort(); } handleNameChange(e){ this.setState({name: e.target.value}); } + handleSelectNode(e){ + this.options = {}; + this.setState({selectedNode: this.state.processingNodes.find(node => node.key == e.target.value)}); + } + setAdvancedOptions(flag){ return () => { this.setState({advancedOptions: flag}); }; } - save(){ + setOptionRef(optionName){ + return (component) => { + if (component) this.options[optionName] = component; + } + } + getOptions(){ + return Object.values(this.options) + .map(option => { + return { + name: option.props.name, + value: option.getValue() + }; + }) + .filter(option => option.value !== undefined); + } + + save(e){ + e.preventDefault(); + // console.log(this.getOptions()); + // console.log(this.state.selectedNode); + // console.log(this.state.name || this.namePlaceholder); + this.setState({editing: false}); + } + + edit(e){ + e.preventDefault(); + this.setState({editing: true}); } render() { - return ( -