From 9cf888fd6345642e47d750e1872aa82ad32985a8 Mon Sep 17 00:00:00 2001 From: Kristian Lyngstol Date: Sat, 12 Jan 2019 21:23:46 +0100 Subject: front: Implement new network/switch and more Fixes #183 References #182 It's now possible to add new networks and switches, and it's also possible to edit networks, but since I haven't exposed it in the UI yet, I can't really close the bug. This is also a major step in stripping nms-info-box apart. Next up is listing existing networks, possibly linking to them. I think that might be a decent first-step towards a new core nms-info-box since it doesn't alreay exist. --- web/js/nms-info-box.js | 259 +----------------------------------------------- web/js/nms-types.js | 14 ++- web/js/nms-ui-boxes.js | 9 +- web/js/nms-ui-switch.js | 167 ++++++++++++++++++++----------- 4 files changed, 128 insertions(+), 321 deletions(-) (limited to 'web/js') 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); @@ -788,44 +787,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 = '
' - 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 * @@ -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 = '' - 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 @@ -1075,161 +998,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 = ''; - if (v == "placement") { - v = "placement Reset"; - } - 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 = "
Request preview
"; - 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 = ''; - 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. * @@ -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]); + } + } + } +} + + -- cgit v1.2.3