diff options
Diffstat (limited to 'web')
-rw-r--r-- | web/css/nms.css | 9 | ||||
-rw-r--r-- | web/index.html | 16 | ||||
-rw-r--r-- | web/js/nms-info-box.js | 259 | ||||
-rw-r--r-- | web/js/nms-types.js | 14 | ||||
-rw-r--r-- | web/js/nms-ui-boxes.js | 9 | ||||
-rw-r--r-- | web/js/nms-ui-switch.js | 167 |
6 files changed, 137 insertions, 337 deletions
diff --git a/web/css/nms.css b/web/css/nms.css index 32f302c..8f59488 100644 --- a/web/css/nms.css +++ b/web/css/nms.css @@ -9,9 +9,6 @@ canvas { -webkit-tap-highlight-color: rgba(255, 255, 255, 0); /* mobile webkit */ } -#info-box-container { - max-width: 700px; -} #info-box-container #edit-output { word-wrap: break-word; padding: 20px; @@ -133,11 +130,7 @@ div.map-mode-legend button { .graph { max-width: 100%; width: 100%; - height: 240px; -} -.genericBox { - position: absolute; - z-index: 120; + height: 10px; } button,input { diff --git a/web/index.html b/web/index.html index 05fd582..23431b1 100644 --- a/web/index.html +++ b/web/index.html @@ -47,13 +47,12 @@ </a> <ul class="dropdown-menu" role="menu"> <li class="gondul-is-private dropdown-header">Switches</li> - <li class="gondul-is-private"><a href="#" onclick="nmsInfoBox.showWindow('addSwitch')">Add switch</a></li> - <li class="gondul-is-private"><a href="#" onclick="nmsInfoBox.showWindow('addNetwork')">Add network</a></li> - <li class="gondul-is-private"><a href="#" onclick="nmsInfoBox.showWindow('listNetwork')">List networks</a></li> - <li class="gondul-is-private"><a href="#" onclick="nmsMap.moveSet(true);">Enable switch moving</a></li> - <li class="gondul-is-private"><a href="#" onclick="nmsMap.moveSet(false);">Disable switch moving</a></li> - <li class="gondul-is-private divider"> </li> - <li class="divider"> </li> + <li class="gondul-is-private"><a href="#" onclick="new nmsNewSwitch().show();">Add switch</a></li> + <li class="gondul-is-private"><a href="#" onclick="new nmsNewNet().show();">Add network</a></li> + <li class="gondul-is-private"><a href="#" onclick="nmsInfoBox.showWindow('listNetwork')">List networks</a></li> + <li class="gondul-is-private"><a href="#" onclick="nmsMap.moveSet(true);">Enable switch moving</a></li> + <li class="gondul-is-private"><a href="#" onclick="nmsMap.moveSet(false);">Disable switch moving</a></li> + <li class="gondul-is-private divider"> </li> <li class="dropdown-header">Time</li> <li><a href="#" onclick="toggleLayer('nowPickerBox');nmsTime.startNowPicker();">Travel in time</a></li> <li><a href="#" onclick="nmsTime.replayEvent();" title="Replay from opening 120 minutes per second">Replay event</a></li> @@ -276,7 +275,8 @@ </div> </div> </div> - <div id="info-box-container" class="col-sm-8 col-md-6 col-lg-5 hidden" style="position: absolute; z-index: 120;"> + <div id="genericPanelContainer" style="ma-width: 60%; position: absolute; display: grid; grid-template-coumns: repeat(auto-fit,minmax(30%,100%));grid-gap: 10px; z-index: 120;"> + <div id="info-box-container" class="hidden" style="grid-column: 1 / auto; max-width: 700px; min-width: 500px;"> </div> </div> </div> diff --git a/web/js/nms-info-box.js b/web/js/nms-info-box.js index 6915b03..8990bdb 100644 --- a/web/js/nms-info-box.js +++ b/web/js/nms-info-box.js @@ -145,7 +145,6 @@ nmsInfoBox.showWindow = function (windowName,argument) { this._sw = argument; this._windowHandler.showWindow(windowName,argument) - this._container.style.display = "block"; $(this._windowHandler.getTitleObj()).on('mousedown', function(e) { var cont = $(nmsInfoBox._container); @@ -789,44 +788,6 @@ var searchResultsPanel = function() { nmsInfoBox.addPanelType("searchResults",searchResultsPanel); /* - * Panel type: Add switch - * - * Lets you add a new switch using the switch-add api - * - */ -var switchAddPanel = function() { - nmsInfoPanel.call(this,"switchAdd"); - this.refresh = function(reason) { - var domObj = document.createElement("div"); - domObj.innerHTML = '<input type="text" class="form-control" id="create-sysname" placeholder="Space-seaprated list of system names"></br><button class="btn btn-default" onclick="nmsInfoBox._windowHandler.doInPanel(\'' + this.id +'\',\'save\');">Add switch</button>' - this._render(domObj); - }; - this.save = function () { - var sysname = document.getElementById('create-sysname').value.split(" "); - var myData = []; - for (var v in sysname) { - myData.push({"sysname":sysname[v]}); - } - var myData = JSON.stringify(myData); - $.ajax({ - type: "POST", - url: "/api/write/switches", - dataType: "text", - data:myData, - success: function (data, textStatus, jqXHR) { - var result = JSON.parse(data); - if(result.switches_addded.length > 0) { // FIXME unresolved variable switches_addded - nmsInfoBox.hide(); - } - nmsData.invalidate("switches"); - nmsData.invalidate("smanagement"); - } - }); - }; -}; -nmsInfoBox.addPanelType("switchAdd",switchAddPanel); - -/* * Panel type: Edit switch * * Lets you edit basic switch and switch management data through the switch-update api @@ -915,7 +876,7 @@ var switchLatencyPanel = function() { var latency = document.createElement("canvas"); latency.id = this.sw+'latency_chart'; latency.width = 500; - latency.height = 250; + latency.height = 50; drawLatency(this.sw+'latency_chart',this.sw, false, function(chart) { latencyChart = chart; }); topper.appendChild(latency); this._render(topper); @@ -992,44 +953,6 @@ var switchLinks = function() { }; }; nmsInfoBox.addPanelType("switchLinks",switchLinks); -/* -* Panel type: Add network -* -* Lets you add a new network using the network-add api -* -*/ -var networkAddPanel = function() { - nmsInfoPanel.call(this,"networkAdd"); - this.refresh = function(reason) { - var domObj = document.createElement("div"); - domObj.innerHTML = '<input type="text" class="form-control" id="create-network-name" placeholder="Space-seaprated list of networks"><button class="btn btn-default" onclick="nmsInfoBox._windowHandler.doInPanel(\'' + this.id +'\',\'save\');">Add network</button>' - this._render(domObj); - }; - this.save = function () { - var name = document.getElementById('create-network-name').value.split(" "); - var myData = []; - for (var v in name) { - myData.push({"name":name[v]}); - } - var myData = JSON.stringify(myData); - $.ajax({ - type: "POST", - url: "/api/write/networks", - dataType: "text", - data:myData, - success: function (data, textStatus, jqXHR) { - var result = JSON.parse(data); - if(result.networks_added.length > 0) { // FIXME unresolved variable switches_addded - nmsInfoBox.hide(); - } - nmsData.invalidate("switches"); - nmsData.invalidate("smanagement"); - nmsData.invalidate("networks"); - } - }); - }; -}; -nmsInfoBox.addPanelType("networkAdd",networkAddPanel); /* * List networks @@ -1076,161 +999,6 @@ var networkSummaryPanel = function() { nmsInfoBox.addPanelType("networkSummary",networkSummaryPanel); /* -* Panel type: Edit networki -* -* Lets you edit basic networks data through the network-update api -* -*/ -var networkEditPanel = function() { - nmsInfoPanel.call(this,"networkEdit"); - this.refresh = function(reason) { - var net = []; - try { - net = nmsData.networks.networks[this.sw]; - } catch(e) {} - - - var domObj = document.createElement("div"); - var template = {}; - - nmsInfoBox._editValues = {}; - var place; - var tags; - for (var v in net) { - /* - * Tags needs to be sent and edited - * as plain JSON... - */ - if (v == "tags") { - tags = JSON.stringify(net[v]); - template[v] = tags; - continue; - } - template[v] = nmsInfoBox._nullBlank(net[v]); - } - var content = []; - for (v in template) { - var tmpsw = '\'' + this.sw + '\''; - var tmpv = '\'' + v + '\''; - var tmphandler = '"nmsInfoBox._editChange(' + tmpsw + ',' + tmpv + ');"'; - var html = '<input type="text" class="form-control" value="' + template[v] + '" id="edit-' + this.sw + '-' + v + '" onchange=' + tmphandler + ' oninput=' + tmphandler + ' ' + (v == 'name' ? "readonly" : "") + '>'; - if (v == "placement") { - v = "placement <a onclick='var _x = document.getElementById(\"edit-" + this.sw + "-placement\"); _x.value = \"\\\"reset\\\"\"; _x.oninput();' class='pull-right'>Reset</a>"; - } - content.push([v, html]); - } - - content.sort(); - - var table = nmsInfoBox._makeTable(content); - domObj.appendChild(table); - - var outputCont = document.createElement("div"); - outputCont.id = "edit-output-cont"; - outputCont.classList.add("collapse"); - outputCont.innerHTML = "<h5>Request preview</h5>"; - var output = document.createElement("output"); - output.id = "edit-output"; - outputCont.appendChild(output); - domObj.appendChild(outputCont); - - var nav = document.createElement("nav"); - nav.classList.add("nav","nav-pills"); - - var submit = document.createElement("button"); - submit.innerHTML = "Save changes"; - submit.classList.add("btn", "btn-primary"); - submit.id = "edit-submit-" + this.sw; - submit.setAttribute("onclick","nmsInfoBox._windowHandler.doInPanel('" + this.id + "','save');"); - nav.appendChild(submit); - - var toggleDetails = document.createElement("button"); - toggleDetails.innerHTML = '<span class="glyphicon glyphicon-menu-hamburger" aria-hidden="true"></span>'; - toggleDetails.classList.add("btn", "btn-default", "pull-right"); - toggleDetails.dataset.toggle = "collapse"; - toggleDetails.dataset.target = "#edit-output-cont"; - toggleDetails.title = "Show request preview"; - toggleDetails.id = "edit-toggle-details-" + this.sw; - nav.appendChild(toggleDetails); - - domObj.appendChild(nav); - - this._render(domObj); - if (place) { - var pval = document.getElementById("edit-" + this.sw + "-placement"); - if (pval) { - pval.value = place; - } - } - if (tags) { - var ptags = document.getElementById("edit-" + this.sw + "-tags"); - if (ptags) { - ptags.value = tags; - } - } - - }; - this.save = function () { - var myData = nmsInfoBox._editStringify(this.sw,"name"); - $.ajax({ - type: "POST", - url: "/api/write/networks", - dataType: "text", - data:myData, - success: function (data, textStatus, jqXHR) { - var result = JSON.parse(data); - if(result.switches_updated.length > 0) { // FIXME unresolved variable switches_addded - nmsInfoBox.hide(); - } - nmsData.invalidate("switches"); - nmsData.invalidate("networks"); - nmsData.invalidate("smanagement"); - } - }); - }; -}; -nmsInfoBox.addPanelType("networkEdit",networkEditPanel); - - -/* - * General-purpose table-maker? - * - * Takes an array of arrays as input, and an optional caption. - * - * E.g.: _makeTable([["name","Kjell"],["Age","five"]], "Age list"); - */ -nmsInfoBox._makeTable = function(content, caption) { - var table = document.createElement("table"); - var tr; - var td1; - var td2; - table.className = "table"; - table.classList.add("table"); - table.classList.add("table-condensed"); - if (caption != undefined) { - var cap = document.createElement("caption"); - cap.textContent = caption; - table.appendChild(cap); - } - for (var v in content) { - tr = table.insertRow(-1); - tr.className = content[v][0].toLowerCase().replace(/[^a-z0-9_]/g,""); - td1 = tr.insertCell(0); - td1.classList.add("left"); - td2 = tr.insertCell(1); - td1.innerHTML = content[v][0]; - td2.innerHTML = content[v][1]; - } - return table; -}; - -nmsInfoBox._nullBlank = function(x) { - if (x == null || x == false || x == undefined) - return ""; - return x; -}; - -/* * Provide common defaults for graph renders. * * Kept on the URL to avoid having to manage templates since we need to @@ -1267,28 +1035,3 @@ nmsInfoBox._graphDefaults = function(title) { return base; } } - -nmsInfoBox._editChange = function(sw, v) { - var el = document.getElementById("edit-" + sw + "-" + v); - var val = el.value; - if (v == "placement") { - try { - val = JSON.parse(val); - el.parentElement.classList.remove("has-error"); - el.parentElement.classList.add("has-success"); - } catch (e) { - el.parentElement.classList.add("has-error"); - return; - } - } - nmsInfoBox._editValues[v] = val; - el.classList.add("has-warning"); - var myData = nmsInfoBox._editStringify(sw); - var out = document.getElementById("edit-output"); - out.value = myData; -}; - -nmsInfoBox._editStringify = function(sw, sysname='sysname') { - nmsInfoBox._editValues[sysname] = sw; - return JSON.stringify([nmsInfoBox._editValues]); -}; diff --git a/web/js/nms-types.js b/web/js/nms-types.js index c6471f5..769bd32 100644 --- a/web/js/nms-types.js +++ b/web/js/nms-types.js @@ -44,7 +44,7 @@ class nmsType { } } initial(v) { - this.value = v; + this._value = this._valueParse(v); if(this.priority == nmsPriority.newOnly) { this.ro = true; } @@ -161,6 +161,18 @@ class nmsTypeSysname extends nmsType { get _defaultPriority() { return nmsPriority.newOnly; } + validate(input) { + if (this.ro) { + throw "Trying to validate a r/o field" + } + var x = testTree(nmsData,["switches","switches",input]) + if (x) { + this.validationReason = "Switch already exists" + } else { + this.validationReason = "OK: " + input + } + return !x; + } } class nmsTypeSysnameReference extends nmsType { get _defaultPriority() { diff --git a/web/js/nms-ui-boxes.js b/web/js/nms-ui-boxes.js index 3de8ff2..ee4dc98 100644 --- a/web/js/nms-ui-boxes.js +++ b/web/js/nms-ui-boxes.js @@ -247,7 +247,7 @@ class nmsTable extends nmsBox { */ class nmsPanel extends nmsBox{ constructor(title){ - super("div",{html: { className: "col-sm-8 col-md-6 col-lg-5 genericBox"}}); + super("div",{html:{style:{gridColumn: 2}}}); this._topBox = new nmsBox("div",{ html: { className: "panel panel-default"}}); this._body = new nmsBox("div",{html:{className: "panel-body"}}); this.nav = new nmsBox("div",{html:{className: "panel-body"}}); @@ -256,7 +256,12 @@ class nmsPanel extends nmsBox{ this._topBox.add(this._body); super.add(this._topBox); } - attach(root = document.getElementById("metaContainer")) { + attach(root = document.getElementById("genericPanelContainer")) { + try { + var x = parseInt(root.lastElementChild.style.gridColumnStart); + this.html.style.gridColumnStart = x+1; + } catch(e) { + } super.attach(root) } show() { diff --git a/web/js/nms-ui-switch.js b/web/js/nms-ui-switch.js index 7887656..507a3a9 100644 --- a/web/js/nms-ui-switch.js +++ b/web/js/nms-ui-switch.js @@ -10,17 +10,27 @@ * it to avoid complicating things. * */ -class nmsModSwitch extends nmsBox { - constructor(sw) { - var title; - if (sw == undefined) { - title = "Add new switch" - } else { - title = "Edit " + sw; - } + +class nmsNewSwitch extends nmsPanel { + constructor() { + super("Add new switch") + this.add(new nmsModSwitch(undefined)) + } +} +class nmsNewNet extends nmsPanel { + constructor() { + super("Add new network") + this.add(new nmsModNet(undefined)) + } +} + +class nmsModThing extends nmsBox { + constructor(data) { super("div",{html:{className: "panel-body"}}); - this._sw = sw; - //this.nav.add(new nmsString("Adding and editing stuff has immediate effects and blah blah blah, insert sensible help-text here.")); + this.identifier = data.identifier; + this.invalidate = data.invalidate; + this.api = data.api; + this.item = data.item; this.generateBaseTemplate() this.populate() var save = new nmsButton("Save","btn-primary"); @@ -35,7 +45,7 @@ class nmsModSwitch extends nmsBox { commit(data) { $.ajax({ type: "POST", - url: "/api/write/switches", + url: this.api, dataType: "text", nmsBox:this, data:JSON.stringify(data), @@ -45,15 +55,16 @@ class nmsModSwitch extends nmsBox { msg.show() this.nmsBox.destroy() //nmsInfoBox.hide(); - nmsData.invalidate("switches"); - nmsData.invalidate("smanagement"); + for (var x of this.nmsBox.invalidate) { + nmsData.invalidate(x); + } } }); } del(e) { - if(confirm("This will delete the switch: " + this.nmsBox.panel._sw)) { - this.nmsBox.panel.commit([{'sysname': this.nmsBox.panel._sw, 'deleted': true}]); + if(confirm("This will delete the " + this.typeName + ":" + this.nmsBox.panel.item)) { + this.nmsBox.panel.commit([{'sysname': this.nmsBox.panel.item, 'deleted': true}]); }; } save(e) { @@ -86,51 +97,9 @@ class nmsModSwitch extends nmsBox { * * Which means bugs. */ - generateBaseTemplate() { - this._template = { - sysname: new nmsTypeSysname("Unique systemname/switch name. Only required field. Read/only on existing equipment." ), - mgmt_v4_addr: new nmsTypeIP("Management address IPv4"), - mgmt_v6_addr: new nmsTypeIP("Management address IPv6"), - mgmt_vlan: new nmsTypeNetwork("Management VLAN"), - traffic_vlan: new nmsTypeNetwork("Traffic VLAN"), - distro_name: new nmsTypeSysnameReference("Distro switch upstream of this system. Required for provisioning."), - distro_phy_port: new nmsTypePort("Name of port we connect to at the distro switch. Used for provisioning, among other things."), - poll_frequency: new nmsTypeInterval("Poll frequency for SNMP (will use default from backend)"), - community: new nmsTypeSecret("SNMP community (will use default from backend)"), - placement: new nmsTypePlace("Map placement (If following a regular naming scheme, the backend will place it poperly, otherwise a random place will be chose)"), - tags: new nmsTypeTags("Additional tags in JSON text array format. Can be anything. Used to provide a simple escape hatch mechanism to tag systems.") - } - } - _populateTemplate(sw) { - var swi = []; - var swm = []; - try { - swi = nmsData.switches["switches"][this._sw]; - } catch(e) {} - try { - swm = nmsData.smanagement.switches[this._sw]; - } catch(e) {} - - var template = {} - for (var v in swi) { - console.assert(this._template[v] instanceof nmsType) - if (swi[v] != null) { - this._template[v].initial(swi[v]); - } - } - for (var v in swm) { - if (v == "last_updated") { - continue; - } - console.assert(this._template[v] instanceof nmsType) - if (swm[v] != null) { - this._template[v].initial(swm[v]); - } - } - } populate() { - if (this._sw != undefined) { - this._populateTemplate(this._sw); + if (this.item != undefined) { + this._populateTemplate(this.item); } this.table = new nmsTable(); this.rows = {} @@ -163,7 +132,7 @@ class nmsModSwitch extends nmsBox { if (!changed) { return undefined; } - ret["sysname"] = this.rows["sysname"].value; + ret[this.identifier] = this.rows[this.identifier].value; return ret; } } @@ -268,3 +237,81 @@ class nmsEditRow extends nmsBox { this.parent.changed(this) } } +class nmsModSwitch extends nmsModThing { + constructor(sw) { + super({item: sw, identifier: "sysname", invalidate: ["switches","smanagement"], api: "/api/write/switches"}) + } + generateBaseTemplate() { + this._template = { + sysname: new nmsTypeSysname("Unique systemname/switch name. Only required field. Read/only on existing equipment." ), + mgmt_v4_addr: new nmsTypeIP("Management address IPv4"), + mgmt_v6_addr: new nmsTypeIP("Management address IPv6"), + mgmt_vlan: new nmsTypeNetwork("Management VLAN"), + traffic_vlan: new nmsTypeNetwork("Traffic VLAN"), + distro_name: new nmsTypeSysnameReference("Distro switch upstream of this system. Required for provisioning."), + distro_phy_port: new nmsTypePort("Name of port we connect to at the distro switch. Used for provisioning, among other things."), + poll_frequency: new nmsTypeInterval("Poll frequency for SNMP (will use default from backend)"), + community: new nmsTypeSecret("SNMP community (will use default from backend)"), + placement: new nmsTypePlace("Map placement (If following a regular naming scheme, the backend will place it poperly, otherwise a random place will be chose)"), + tags: new nmsTypeTags("Additional tags in JSON text array format. Can be anything. Used to provide a simple escape hatch mechanism to tag systems.") + } + } + _populateTemplate(sw) { + var swi = []; + var swm = []; + try { + swi = nmsData.switches["switches"][sw]; + swm = nmsData.smanagement.switches[sw]; + } catch(e) {} + + var template = {} + for (var v in swi) { + console.assert(this._template[v] instanceof nmsType) + if (swi[v] != null) { + this._template[v].initial(swi[v]); + } + } + for (var v in swm) { + if (v == "last_updated") { + continue; + } + console.assert(this._template[v] instanceof nmsType) + if (swm[v] != null) { + this._template[v].initial(swm[v]); + } + } + } +} + +class nmsModNet extends nmsModThing { + constructor(net) { + super({item: net, identifier: "name", invalidate: ["networks","smanagement"], api: "/api/write/networks"}) + } + generateBaseTemplate() { + this._template = { + name: new nmsTypeNetwork("Unique networkname. Only required field. Read/only on existing nets."), + gw4: new nmsTypeIP("Gateway address, IPv4"), + gw6: new nmsTypeIP("Gateway address, IPv6"), + subnet4: new nmsTypeIP("Subnet, IPv4"), + subnet6: new nmsTypeIP("Subnet, IPv6"), + router: new nmsTypeSysnameReference("Router where net is terminated. E.g.: r1.noc for floor traffic nets"), + tags: new nmsTypeTags("Additional tags in JSON text array format. Can be anything. Used to provide a simple escape hatch mechanism to tag systems.") + } + } + _populateTemplate(net) { + var nets = []; + try { + nets = nmsData.networks["networks"][net]; + } catch(e) {} + + var template = {} + for (var v in nets) { + console.assert(this._template[v] instanceof nmsType) + if (nets[v] != null) { + this._template[v].initial(nets[v]); + } + } + } +} + + |