aboutsummaryrefslogtreecommitdiffstats
path: root/src/templates/resource/steps
diff options
context:
space:
mode:
authorParker Berberian <pberberian@iol.unh.edu>2018-10-10 16:06:47 -0400
committerParker Berberian <pberberian@iol.unh.edu>2018-10-15 13:16:11 -0400
commit1f3a770d2547848590f39e9d9b9bdffeb94eec14 (patch)
tree97222e5facd1a242d951c38482315057b5790d51 /src/templates/resource/steps
parent6d4019e59eda897384e9c00d1daf8b2ce87d128f (diff)
Lab as a Service 2.0
See changes here: https://wiki.opnfv.org/display/INF/Pharos+Laas Change-Id: I59ada5f98e70a28d7f8c14eab3239597e236ca26 Signed-off-by: Sawyer Bergeron <sbergeron@iol.unh.edu> Signed-off-by: Parker Berberian <pberberian@iol.unh.edu>
Diffstat (limited to 'src/templates/resource/steps')
-rw-r--r--src/templates/resource/steps/define_hardware.html37
-rw-r--r--src/templates/resource/steps/host_info.html43
-rw-r--r--src/templates/resource/steps/pod_definition.html653
3 files changed, 733 insertions, 0 deletions
diff --git a/src/templates/resource/steps/define_hardware.html b/src/templates/resource/steps/define_hardware.html
new file mode 100644
index 0000000..933b4ab
--- /dev/null
+++ b/src/templates/resource/steps/define_hardware.html
@@ -0,0 +1,37 @@
+{% extends "workflow/viewport-element.html" %}
+{% load staticfiles %}
+
+{% load bootstrap3 %}
+
+{% block content %}
+<p>Note that not all labs host every kind of machine.
+As you make your selections, labs and hosts that are not compatible
+with your current configuration will become unavailable.</p>
+<h4>NOTE: Only PTL's are able to create multi-node PODs. See <a href="https://google.com">here</a>
+ for more details</h4>
+<form id="define_hardware_form" action="/wf/workflow/" method="post">
+ {% csrf_token %}
+ {{form.filter_field|default:"<p>No Form</p>"}}
+</form>
+{% endblock content %}
+{% block onleave %}
+var normalize = function(data){
+ //converts the top level keys in data to map to lists
+ var normalized = {}
+ for( var key in data ){
+ normalized[key] = [];
+ for( var subkey in data[key] ){
+ normalized[key].push(data[key][subkey]);
+ }
+ }
+ return normalized;
+}
+var data = normalize(result);
+data = JSON.stringify(data);
+document.getElementById("filter_field").value = data;
+var formData = $("#define_hardware_form").serialize();
+req = new XMLHttpRequest();
+req.open('POST', '/wf/workflow/', false);
+req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+req.send(formData);
+{% endblock %}
diff --git a/src/templates/resource/steps/host_info.html b/src/templates/resource/steps/host_info.html
new file mode 100644
index 0000000..0275727
--- /dev/null
+++ b/src/templates/resource/steps/host_info.html
@@ -0,0 +1,43 @@
+{% extends "workflow/viewport-element.html" %}
+{% load staticfiles %}
+
+{% load bootstrap3 %}
+
+{% block content %}
+
+{% if error %}
+<p>{{error}}</p>
+{% else %}
+
+
+<form id="host_meta_form" method="post" action="/wf/workflow/">
+ {% csrf_token %}
+ <table>
+ <thead>
+ <tr>
+ <th>Type</th>
+ <th>Name</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for form in formset %}
+ <tr>
+ {% for field in form %}
+ <td>{{field}}</td>
+ {% endfor %}
+ </tr>
+ {% endfor %}
+ </table>
+ {{formset.management_form}}
+</form>
+{% endif %}
+{% endblock content %}
+
+{% block onleave %}
+var formData = $("#host_meta_form").serialize();
+var req = new XMLHttpRequest();
+req.open("POST", "/wf/workflow/", false);
+req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+req.onerror = function() { alert("There was a problem submitting the form"); }
+req.send(formData);
+{% endblock %}
diff --git a/src/templates/resource/steps/pod_definition.html b/src/templates/resource/steps/pod_definition.html
new file mode 100644
index 0000000..ab9dfb3
--- /dev/null
+++ b/src/templates/resource/steps/pod_definition.html
@@ -0,0 +1,653 @@
+{% extends "workflow/viewport-element.html" %}
+{% block extrahead %}
+<link href="/static/css/graph_common.css" rel="stylesheet">
+<title>Pod Definition Prototype</title>
+
+<!-- Loads and initializes the library -->
+<script>
+ var mxLoadStylesheets = false;
+</script>
+<script type="text/javascript" src="/static/js/mxClient.min.js" ></script>
+<style>
+p {
+ word-break: normal;
+ white-space: normal;
+}
+</style>
+<script type="text/javascript">
+var currentWindow;
+var currentGraph;
+var netCount = 0;
+var netColors = ['red', 'blue', 'purple', 'green', 'orange', '#8CCDF5', '#1E9BAC'];
+var hostCount = 0;
+var lastHostBottom = 100;
+var networks = new Set([]);
+var network_names = new Set([]);
+var has_public_net = false;
+var vlans = {{vlans|default:'null'}};
+var vlan_string = "";
+
+function main(graphContainer, overviewContainer, toolbarContainer) {
+ if(vlans){
+ for(var i=0; i<vlans.length-1; i++){
+ vlan_string += vlans[i] + ", ";
+ }
+ if(vlans.length > 0){
+ vlan_string += vlans[vlans.length-1];
+ }
+
+ var str = "Available vlans for your POD: " + vlan_string;
+ document.getElementById("vlan_notice").innerHTML = str;
+ }
+ //check if the browser is supported
+ if (!mxClient.isBrowserSupported()) {
+ mxUtils.error('Browser is not supported', 200, false);
+ return null;
+ }
+
+ // Workaround for Internet Explorer ignoring certain styles
+ if (mxClient.IS_QUIRKS) {
+ document.body.style.overflow = 'hidden';
+ new mxDivResizer(graphContainer);
+ }
+ var editor = new mxEditor();
+ var graph = editor.graph;
+ var model = graph.getModel();
+ editor.setGraphContainer(graphContainer);
+
+ {% if debug %}
+ editor.addAction('printXML', function(editor, cell) {
+ mxLog.write(encodeGraph(graph));
+ mxLog.show();
+ });
+ {% endif %}
+
+
+ doGlobalConfig(graph);
+ currentGraph = graph;
+
+ {% if xml %}
+ restoreFromXml('{{xml|safe}}', editor);
+ {% elif hosts %}
+ {% for host in hosts %}
+
+ var host = {{host|safe}};
+ makeHost(host);
+ {% endfor %}
+ {% endif %}
+ {% if added_hosts %}
+ {% for host in added_hosts %}
+ var host = {{host|safe}}
+ makeHost(host);
+ {% endfor %}
+ updateHosts([]);
+ {% endif %}
+
+ addToolbarButton(editor, toolbarContainer, 'zoomIn', '', "/static/img/mxgraph/zoom_in.png", true);
+ addToolbarButton(editor, toolbarContainer, 'zoomOut', '', "/static/img/mxgraph/zoom_out.png", true);
+ addToolbarButton(editor, toolbarContainer, 'printXML', '', '/static/img/mxgraph/fit_to_size.png', true);
+ var outline = new mxOutline(graph, overviewContainer);
+
+
+ var checkAllowed = function(edge, terminal, source) {
+ //check if other terminal is null, and that they are different
+ otherTerminal = edge.getTerminal(!source);
+ if(terminal != null && otherTerminal != null) {
+ if( terminal.getParent().getId().split('_')[0] == //'host' or 'network'
+ otherTerminal.getParent().getId().split('_')[0] ) {
+ //not allowed
+ graph.removeCells([edge]);
+ return false;
+ }
+ }
+ return true;
+ };
+
+ var colorEdge = function(edge, terminal, source) {
+ if(terminal.getParent().getId().indexOf('network') >= 0) {
+ styles = terminal.getParent().getStyle().split(';');
+ color = 'black';
+ for(var i=0; i<styles.length; i++){
+ kvp = styles[i].split('=');
+ if(kvp[0] == "fillColor"){
+ color = kvp[1];
+ }
+ }
+ edge.setStyle('strokeColor=' + color);
+ }
+ };
+
+ var alertVlan = function(edge, terminal, source) {
+ if( terminal == null || edge.getTerminal(!source) == null) {
+ return;
+ }
+ var vlanHTML = '<form> <input type="radio" name="tagged" value="True" checked> Tagged<br>'
+ vlanHTML += '<input type="radio" name="tagged" value="False"> Untagged </form>'
+ vlanHTML += '<button onclick=parseVlanWindow(' + edge.getId() + ');>Okay</button>'
+ vlanHTML += '<button onclick=deleteVlanWindow(' + edge.getId() + ');>Cancel</button>'
+ content = document.createElement('div');
+ content.innerHTML = vlanHTML;
+ showWindow(graph, "Vlan Selection", content, 200, 200);
+ }
+
+ //sets the edge color to be the same as the network
+ graph.addListener(mxEvent.CELL_CONNECTED, function(sender, event){
+ edge = event.getProperty('edge');
+ terminal = event.getProperty('terminal')
+ source = event.getProperty('source');
+ if(checkAllowed(edge, terminal, source)) {
+ colorEdge(edge, terminal, source);
+ alertVlan(edge, terminal, source);
+ }
+ });
+
+ graph.dblClick = function(evt, cell) {
+
+ if( cell != null ){
+ if( cell.getParent() != null && cell.getParent().getId().indexOf("network") > -1) {
+ cell = cell.getParent();
+ }
+ if( cell.isEdge() || cell.getId().indexOf("network") > -1 ) {
+ var content = document.createElement('div');
+ var innerHTML = "<button onclick=deleteCell('" + cell.getId() + "');>Remove</button>"
+ innerHTML += "<button onclick='currentWindow.destroy();'>Cancel</button>"
+ content.innerHTML = innerHTML;
+ showWindow(this, 'Delete?', content, 200, 200);
+ }
+ else {
+ showDetailWindow(cell);
+ }
+ }
+ };
+ graph.setCellsSelectable(false);
+ graph.setCellsMovable(false);
+
+ updateHosts({{ removed_hosts|default:"[]"|safe }});
+ if(!has_public_net){
+ addPublicNetwork();
+ }
+}
+
+function showDetailWindow(cell) {
+ var info = JSON.parse(cell.getValue());
+ var content = document.createElement("div");
+ var inner = "<pre>Name: " + info.name + "\n";
+ inner += "Description:\n" + info.description + "</pre>";
+ inner += '<button onclick="currentWindow.destroy();">Okay</button>'
+ content.innerHTML = inner
+ showWindow(currentGraph, 'Details', content, 400, 400);
+}
+
+function restoreFromXml(xml, editor) {
+ var doc = mxUtils.parseXml(xml);
+ var node = doc.documentElement;
+ editor.readGraphModel(node);
+
+ //Iterate over all children, and parse the networks to add them to the sidebar
+ var root = currentGraph.getDefaultParent();
+ for( var i=0; i<root.getChildCount(); i++) {
+ var cell = root.getChildAt(i);
+ if(cell.getId().indexOf("network") > -1) {
+ var info = JSON.parse(cell.getValue());
+ var vlan_id = info['vlan_id'];
+ networks.add(vlan_id);
+ var name = info['name'];
+ network_names.add(name);
+ var styles = cell.getStyle().split(";");
+ var color = null;
+ for(var j=0; j< styles.length; j++){
+ var kvp = styles[j].split('=');
+ if(kvp[0] == "fillColor") {
+ color = kvp[1];
+ break;
+ }
+ }
+ if(info.public){
+ vlan_id = "";
+ has_public_net = true;
+ }
+ netCount++;
+ makeSidebarNetwork(name, vlan_id, color, cell.getId());
+ }
+ }
+}
+
+function deleteCell(cellId) {
+ var cell = currentGraph.getModel().getCell(cellId);
+ if( cellId.indexOf("network") > -1 ) {
+ elem = document.getElementById(cellId);
+ elem.parentElement.removeChild(elem);
+ }
+ currentGraph.removeCells([cell]);
+ currentWindow.destroy();
+
+}
+
+function newNetworkWindow() {
+ var innerHtml = 'Name: <input type="text" name="net_name" id="net_name_input" style="margin:5px;"><br>';
+ innerHtml += 'Vlan: <input type="number" step="1" name="vlan_id" id="vlan_id_input" style="margin:5px;"><br>';
+ innerHtml += '<button type="button" onclick="parseNetworkWindow()">Okay</button>';
+ innerHtml += '<button type="button" onclick="currentWindow.destroy();">Cancel</button><br>';
+ innerHtml += '<div id="current_window_vlans"/>';
+ innerHtml += '<div id="current_window_errors"/>';
+ var content = document.createElement("div");
+ content.innerHTML = innerHtml;
+
+ showWindow(currentGraph, "Network Creation", content, 300, 300);
+
+ if(vlans){
+ vlan_notice = document.getElementById("current_window_vlans");
+ vlan_notice.appendChild(document.createTextNode("Available Vlans: " + vlan_string));
+ }
+}
+
+function parseNetworkWindow() {
+ var net_name = document.getElementById("net_name_input").value
+ var vlan_id = document.getElementById("vlan_id_input").value
+ var error_div = document.getElementById("current_window_errors");
+ var vlan_valid = Number.isInteger(Number(vlan_id)) && (vlan_id < 4095) && (vlan_id > 1)
+ if(vlans){
+ vlan_valid = vlan_valid & vlans.indexOf(Number(vlan_id)) >= 0;
+ }
+ if( !vlan_valid)
+ {
+ error_div.innerHTML = "Please only enter an integer in the valid range (default 1-4095) for the VLAN ID";
+ return;
+ }
+ if( networks.has(vlan_id))
+ {
+ error_div.innerHTML = "All VLAN IDs must be unique";
+ return;
+ }
+ if( network_names.has(net_name) ){
+ error_div.innerHTML = "All network names must be unique";
+ return;
+ }
+ addNetwork(net_name, vlan_id);
+ currentWindow.destroy();
+}
+
+function addToolbarButton(editor, toolbar, action, label, image, isTransparent)
+{
+ var button = document.createElement('button');
+ button.style.fontSize = '10';
+ if (image != null)
+ {
+ var img = document.createElement('img');
+ img.setAttribute('src', image);
+ img.style.width = '16px';
+ img.style.height = '16px';
+ img.style.verticalAlign = 'middle';
+ img.style.marginRight = '2px';
+ button.appendChild(img);
+ }
+ if (isTransparent)
+ {
+ button.style.background = 'transparent';
+ button.style.color = '#FFFFFF';
+ button.style.border = 'none';
+ }
+ mxEvent.addListener(button, 'click', function(evt)
+ {
+ editor.execute(action);
+ });
+ mxUtils.write(button, label);
+ toolbar.appendChild(button);
+};
+
+function encodeGraph(graph) {
+ var encoder = new mxCodec();
+ var xml = encoder.encode(graph.getModel());
+ return mxUtils.getXml(xml);
+}
+
+function doGlobalConfig(graph) {
+ //general graph stuff
+ graph.setMultigraph(false);
+
+ //edge behavior
+ graph.setConnectable(true);
+ graph.setAllowDanglingEdges(false);
+ mxEdgeHandler.prototype.snapToTerminals = true;
+ mxConstants.MIN_HOTSPOT_SIZE = 16;
+ mxConstants.DEFAULT_HOTSPOT = 1;
+ //edge 'style' (still affects behavior greatly)
+ style = graph.getStylesheet().getDefaultEdgeStyle();
+ style[mxConstants.STYLE_EDGE] = mxConstants.EDGESTYLE_ELBOW;
+ style[mxConstants.STYLE_ENDARROW] = mxConstants.NONE;
+ style[mxConstants.STYLE_ROUNDED] = true;
+ style[mxConstants.STYLE_FONTCOLOR] = 'black';
+ style[mxConstants.STYLE_STROKECOLOR] = 'red';
+
+ style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = '#FFFFFF';
+ style[mxConstants.STYLE_STROKEWIDTH] = '3';
+ style[mxConstants.STYLE_ROUNDED] = true;
+ style[mxConstants.STYLE_EDGE] = mxEdgeStyle.EntityRelation;
+
+ // TODO: Proper override
+ graph.convertValueToString = function(cell) {
+ try{
+ //changes value for edges with xml value
+ if(cell.isEdge()) {
+ if(JSON.parse(cell.getValue())["tagged"]) {
+ return "tagged";
+ }
+ return "untagged";
+ } else{
+ return JSON.parse(cell.getValue())['name'];
+ }
+ }
+ catch(e){
+ return cell.getValue();
+ }
+ };
+}
+
+function showWindow(graph, title, content, width, height) {
+ //create transparent black background
+ var background = document.createElement('div');
+ background.style.position = 'absolute';
+ background.style.left = '0px';
+ background.style.top = '0px';
+ background.style.right = '0px';
+ background.style.bottom = '0px';
+ background.style.background = 'black';
+ mxUtils.setOpacity(background, 50);
+ document.body.appendChild(background);
+
+ //deal with IE quirk
+ if (mxClient.IS_IE) {
+ new mxDivResizer(background);
+ }
+
+ var x = Math.max(0, document.body.scrollWidth/2-width/2);
+ var y = Math.max(10, (document.body.scrollHeight ||
+ document.documentElement.scrollHeight)/2-height*2/3);
+
+ var wnd = new mxWindow(title, content, x, y, width, height, false, true);
+ wnd.setClosable(false);
+
+ wnd.addListener(mxEvent.DESTROY, function(evt) {
+ graph.setEnabled(true);
+ mxEffects.fadeOut(background, 50, true, 10, 30, true);
+ });
+ currentWindow = wnd;
+
+ graph.setEnabled(false);
+ wnd.setVisible(true);
+};
+
+function closeWindow() {
+ //allows the current window to be destroyed
+ currentWindow.destroy();
+};
+
+function othersUntagged(edgeID) {
+ var edge = currentGraph.getModel().getCell(edgeID);
+ var end1 = edge.getTerminal(true);
+ var end2 = edge.getTerminal(false);
+
+ if( end1.getParent().getId().split('_')[0] == 'host' )
+ {
+ var netint = end1;
+ }
+ else
+ {
+ var netint = end2;
+ }
+
+ var edges = netint.edges;
+
+ for( var i=0; i < edges.length; i++ )
+ {
+ if( edges[i].getValue() )
+ {
+ var tagged = JSON.parse(edges[i].getValue()).tagged;
+ }
+ else
+ {
+ var tagged = true;
+ }
+ if( !tagged )
+ {
+ return true;
+ }
+ }
+ return false;
+};
+
+
+function deleteVlanWindow(edgeID) {
+ var cell = currentGraph.getModel().getCell(edgeID);
+ currentGraph.removeCells([cell]);
+ currentWindow.destroy();
+}
+
+function parseVlanWindow(edgeID) {
+ //do parsing and data manipulation
+ var radios = document.getElementsByName("tagged");
+ edge = currentGraph.getModel().getCell(edgeID);
+
+ for(var i=0; i<radios.length; i++) {
+ if(radios[i].checked) {
+ //set edge to be tagged or untagged
+ //cellValue.setAttribute("tagged", radios[i].value);
+ if( radios[i].value == "False")
+ {
+ if( othersUntagged(edgeID) )
+ {
+ alert("Only one untagged VLAN is allowed per interface");
+ return;
+ }
+ }
+ edgeVal = Object();
+ edgeVal['tagged'] = radios[i].value == "True";
+ edge.setValue(JSON.stringify(edgeVal));
+ break;
+ }
+ }
+ //edge.setValue(cellValue);
+ currentGraph.refresh(edge);
+ closeWindow();
+}
+
+function makeMxNetwork(vlan_id, net_name) {
+ model = currentGraph.getModel();
+ width = 10;
+ height = 1700;
+ xoff = 400 + (30 * netCount);
+ yoff = -10;
+ var color = netColors[netCount];
+ if( netCount > (netColors.length - 1)) {
+ color = Math.floor(Math.random() * 16777215); //int in possible color space
+ color = '#' + color.toString(16).toUpperCase(); //convert to hex
+ //alert(color);
+ }
+ var net_val = Object();
+ net_val['vlan_id'] = vlan_id;
+ net_val['name'] = net_name;
+ net_val['public'] = vlan_id < 0;
+ net = currentGraph.insertVertex(
+ currentGraph.getDefaultParent(),
+ 'network_' + netCount,
+ JSON.stringify(net_val),
+ xoff,
+ yoff,
+ width,
+ height,
+ 'fillColor=' + color,
+ false
+ );
+ var num_ports = 45;
+ for(var i=0; i<num_ports; i++){
+ port = currentGraph.insertVertex(
+ net,
+ null,
+ '',
+ 0,
+ (1/num_ports) * i,
+ 10,
+ height / num_ports,
+ 'fillColor=black;opacity=0',
+ true
+ );
+ }
+
+ var retVal = Object();
+ retVal['color'] = color;
+ retVal['element_id'] = "network_" + netCount;
+
+ netCount++;
+ return retVal;
+}
+
+function addPublicNetwork() {
+ var net = makeMxNetwork(-1, "public");
+ makeSidebarNetwork("public", "", net['color'], net['element_id']);
+}
+
+function addNetwork(net_name, vlan_id) {
+ var ret = makeMxNetwork(vlan_id, net_name);
+ var color = ret['color'];
+ var net_id = ret['element_id'];
+ networks.add(vlan_id);
+ network_names.add(net_name);
+ makeSidebarNetwork(net_name, vlan_id, color, net_id);
+}
+
+function updateHosts(removed) {
+ for(var i=0; i < removed.length; i++)
+ {
+ var hoststring = removed[i];
+ var hostid = "host_" + hoststring.split("*")[0];
+ var cell = currentGraph.getModel().getCell(hostid);
+ currentGraph.removeCells([cell]);
+ }
+
+ var hosts = currentGraph.getChildVertices(currentGraph.getDefaultParent());
+ var topdist = 100;
+ for(var i=0; i<hosts.length; i++)
+ {
+ var host = hosts[i];
+ if(!host.id.startsWith("host_"))
+ {
+ continue;
+ }
+ var geometry = host.getGeometry();
+ geometry.y = topdist + 50;
+ topdist = geometry.y + geometry.height;
+ host.setGeometry(geometry);
+ }
+}
+
+function makeSidebarNetwork(net_name, vlan_id, color, net_id){
+ var newNet = document.createElement("li");
+ newNet.id = net_id;
+ var text = net_name;
+ if(vlan_id){
+ text += " : " + vlan_id;
+ }
+ var newNetValue = document.createTextNode(text);
+ newNet.appendChild(newNetValue);
+ newNet.style['background'] = color;
+ document.getElementById("network_list").appendChild(newNet);
+}
+
+function makeHost(hostInfo) {
+ value = JSON.stringify(hostInfo['value']);
+ interfaces = hostInfo['interfaces'];
+ graph = currentGraph;
+ width = 100;
+ height = (25 * interfaces.length) + 10;
+ xoff = 75;
+ yoff = lastHostBottom + 50;
+ lastHostBottom = yoff + height;
+ host = graph.insertVertex(
+ graph.getDefaultParent(),
+ 'host_' + hostInfo['id'],
+ value,
+ xoff,
+ yoff,
+ width,
+ height,
+ 'editable=0',
+ false
+ );
+ host.setConnectable(false);
+ hostCount++;
+
+ for(var i=0; i<interfaces.length; i++) {
+ port = graph.insertVertex(
+ host,
+ null,
+ JSON.stringify(interfaces[i]),
+ 90,
+ (i * 25) + 5,
+ 20,
+ 20,
+ 'fillColor=blue;editable=0',
+ false
+ );
+ }
+}
+
+function submitForm() {
+ var form = document.getElementById("xml_form");
+ var input_elem = document.getElementById("hidden_xml_input");
+ var s = encodeGraph(currentGraph);
+ input_elem.value = s;
+ //form.submit();
+ req = new XMLHttpRequest();
+ req.open("POST", "/wf/workflow/", false);
+ req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+ req.onerror = function() { alert("problem with form submission"); }
+ var formData = $("#xml_form").serialize();
+ req.send(formData);
+}
+</script>
+{% endblock extrahead %}
+
+<!-- Calls the main function after the page has loaded. Container is dynamically created. -->
+{% block content %}
+ <div id="graphParent"
+ style="position:absolute;overflow:hidden;top:0px;bottom:0px;width:65%;left:0px;">
+ <div id="graphContainer"
+ style="position:relative;overflow:hidden;top:36px;bottom:0px;left:0px;right:0px;background-image:url('/static/img/mxgraph/grid.gif');cursor:default;">
+ </div>
+
+
+ <!-- Creates a container for the sidebar -->
+ <div id="toolbarContainer"
+ style="position:absolute;white-space:nowrap;overflow:hidden;top:0px;left:0px;max-height:24px;height:36px;right:0px;padding:6px;background-image:url('/static/img/mxgraph/toolbar_bg.gif');">
+ </div>
+
+ <!-- Creates a container for the outline -->
+ <div id="outlineContainer"
+ style="position:absolute;overflow:hidden;top:36px;right:0px;width:200px;height:140px;background:transparent;border-style:solid;border-color:black;">
+ </div>
+ </div>
+
+ <div id="network_select" style="position:absolute;top:0px;bottom:0px;width:35%;right:0px;left:auto;background:grey">
+ <button type="button" onclick="newNetworkWindow();">Add Network</button>
+ <ul id="network_list">
+ </ul>
+ <p id="vlan_notice"></p>
+ <button type="button" style="display: none" onclick="submitForm();">Submit</button>
+ </div>
+ <form id="xml_form" method="post" action="/wf/workflow/">
+ {% csrf_token %}
+ <input type="hidden" id="hidden_xml_input" name="xml" />
+ </form>
+
+<script>
+ main(
+ document.getElementById('graphContainer'),
+ document.getElementById('outlineContainer'),
+ document.getElementById('toolbarContainer'),
+ document.getElementById('sidebarContainer')
+ )
+</script>
+{% endblock content %}
+{% block onleave %}
+submitForm();
+{% endblock %}