aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--web/css/nms.css5
-rw-r--r--web/index.html7
-rw-r--r--web/js/nms-oplog.js44
-rw-r--r--web/js/nms-ui-boxes.js191
-rw-r--r--web/js/nms-ui-switch.js126
5 files changed, 349 insertions, 24 deletions
diff --git a/web/css/nms.css b/web/css/nms.css
index 9c783af..6bf2890 100644
--- a/web/css/nms.css
+++ b/web/css/nms.css
@@ -129,3 +129,8 @@ div.map-mode-legend button {
width: 100%;
height: 240px;
}
+.genericBox {
+ position: absolute;
+ z-index: 120;
+}
+
diff --git a/web/index.html b/web/index.html
index 447772f..3e92dc8 100644
--- a/web/index.html
+++ b/web/index.html
@@ -152,7 +152,7 @@
</div>
<div class="container-fluid" id="map">
<div class="row-fluid">
- <div class="span12">
+ <div class="span12" id="metaContainer">
<div id="aboutKeybindings" class="col-md-4" style="position: absolute; display:none; z-index: 130;">
<div class="panel panel-default">
<div class="panel-heading">
@@ -306,8 +306,7 @@
<canvas id="textCanvas" width="1920" height="1032" style="position: absolute; z-index: 40;"> </canvas>
<canvas id="textInfoCanvas" width="1920" height="1032" style="position: absolute; z-index: 45;"> </canvas>
<canvas id="topCanvas" width="1920" height="1032" style="position: absolute; z-index: 50;"> </canvas>
- <canvas id="inputCanvas" width="1920" height="1032" style="position: absolute; z-index: 60; cursor: pointer;" onmousedown="nmsMap.canvasClick(event)">
- </canvas>
+ <canvas id="inputCanvas" width="1920" height="1032" style="position: absolute; z-index: 60; cursor: pointer;" onmousedown="nmsMap.canvasClick(event)"> </canvas>
<canvas id="hiddenCanvas" width="1000" height="10" style="display: none; position: absolute; z-index: 1000 "></canvas>
<div class="logbook logbook-mini gondul-is-private" style="position: absolute; right: 10px; width: 20%; z-index: 70; float: right;">
<div id="oplog-parent-mini" class="logbook" style="border-color: transparent;">
@@ -337,6 +336,8 @@
<script type="text/javascript" src="js/nms-dhcp.js"></script>
<script type="text/javascript" src="js/nms-template.js"></script>
<script type="text/javascript" src="js/nms-draw-chart.js"></script>
+ <script type="text/javascript" src="js/nms-ui-boxes.js"></script>
+ <script type="text/javascript" src="js/nms-ui-switch.js"></script>
<script src="js/jquery.datetimepicker.full.js" type="text/javascript"></script>
<script type="text/javascript">
initNMS();
diff --git a/web/js/nms-oplog.js b/web/js/nms-oplog.js
index 7ac11c4..cea75ca 100644
--- a/web/js/nms-oplog.js
+++ b/web/js/nms-oplog.js
@@ -1,7 +1,7 @@
"use strict";
var nmsOplog = nmsOplog || {
-
+ table: {}
}
nmsOplog.init = function() {
@@ -78,42 +78,43 @@ nmsOplog.getSwitchLogs = function(sw) {
return logs;
}
+/*
+ * This can be re-written now that it uses nmsBox... That rewrite was just a short
+ * test of nmsBox...
+ */
nmsOplog._updateComments = function(limit,prefix,timefield,cutoff) {
- var table = document.createElement("table");
- var tr;
- var td1;
- var td2;
- var td3;
- table.className = "table";
- table.classList.add("table");
- table.classList.add("table-condensed");
+ var table = new nmsTable([]);
var i = 0;
for (var v in nmsData['oplog']['oplog']) {
if (cutoff && nmsData.oplog.oplog[v]['username'] == "system") {
continue;
}
- tr = table.insertRow(-1);
- td1 = tr.insertCell(0);
- td2 = tr.insertCell(1);
+ var col1;
var date = new Date(nmsData.oplog.oplog[v]['timestamp'].replace(" ","T").replace("+00",""));
if (timefield == "time") {
- td1.textContent = date.toTimeString().replace(/:\d\d .*$/,"");
+ col1 = date.toTimeString().replace(/:\d\d .*$/,"");
} else {
var month = date.getMonth() + 1;
var day = date.getDate();
var tmp = (date.getYear() + 1900) + "-" + (month < 10 ? "0": "") + month + "-" + (day < 10 ? "0" : "") + day + " " + date.toTimeString().replace(/:\d\d .*$/,"");
- td1.textContent = tmp;
+ col1 = tmp;
}
- td1.classList.add("left");
var data = nmsData['oplog']['oplog'][v]['log'];
+ var col2 = new nmsBox("p");
if (cutoff && data.length > cutoff) {
- td2.title = data;
+ col2.html.title = data;
data = data.slice(0,cutoff);
data = data + "(...)";
}
- td2.textContent = nmsData['oplog']['oplog'][v]['systems'] + " [" + nmsData['oplog']['oplog'][v]['username'] + "] " + data;
- td2.hiddenthing = v;
- td2.onclick = function(e){ var x = document.getElementById("searchbox"); var v = e.path[0].hiddenthing; x.value = nmsData['oplog']['oplog'][v]['systems']; x.oninput(); }
+ col2.html.textContent = nmsData['oplog']['oplog'][v]['systems'] + " [" + nmsData['oplog']['oplog'][v]['username'] + "] " + data;
+ col2.html.hiddenthing = v;
+ col2.html.onclick = function(e) {
+ var x = document.getElementById("searchbox");
+ var v = e.path[0].hiddenthing;
+ x.value = nmsData['oplog']['oplog'][v]['systems'];
+ x.oninput();
+ }
+ table.add([col1,col2]);
if (++i == limit)
break;
}
@@ -122,7 +123,8 @@ nmsOplog._updateComments = function(limit,prefix,timefield,cutoff) {
old.parentElement.removeChild(old);
} catch(e) {}
var par = document.getElementById("oplog-parent" + prefix);
- table.id = "oplog-table" + prefix;
- par.appendChild(table);
+ table.html.id = "oplog-table" + prefix;
+ par.appendChild(table.html);
+ nmsOplog.table["x" + prefix] = table;
};
diff --git a/web/js/nms-ui-boxes.js b/web/js/nms-ui-boxes.js
new file mode 100644
index 0000000..3ed65cd
--- /dev/null
+++ b/web/js/nms-ui-boxes.js
@@ -0,0 +1,191 @@
+"use strict";
+
+/*
+ * An attempt at breaking up nms-info-box into something that works better.
+ * The idea is to retain the ability to fiddle with html, but solve common
+ * problems such as "I need to show a box that looks good" and "I need to
+ * update the content of this field in this box when something happens".
+ *
+ * Seeing as how it's 2019, I figured I'd try to use this whole "class"
+ * thing :D
+ *
+ * Eventually, everything in nms-info-box.js should use this, but more over,
+ * if a need to write some code that needs a UI element arises, the general
+ * problem should be solved here, while the implementation: elsewhere.
+ *
+ * Example: Adding a new switch or network should not be closely tied in
+ * here.
+ *
+ * I expect this code to change dramatically as I start using it.
+ */
+
+class nmsBox {
+ constructor(type,settings) {
+ this.type = type;
+ this._boxes = []
+ this.html = document.createElement(type);
+ this.html.nmsBox = this;
+ if (settings) {
+ this.applySettings(settings);
+ }
+ }
+ get value() {
+ var values = [];
+ for (var x in this._boxes) {
+ var tmp = this._boxes[x].value;
+ if (tmp != undefined && !((tmp instanceof Array) && tmp.length == 0)) {
+ values.push(tmp)
+ }
+ }
+ return values;
+ }
+
+ applySettings(settings) {
+ if (settings.html) {
+ for (var x in settings.html) {
+ if (settings.html[x] instanceof Array) {
+ /* If you just sett classList = array it will end up being
+ * classList = "panel,panel-default,foo", instead of
+ * classList = ["panel","panel-default","foo"] ...
+ * Not sure if this applies to all arrays in a html
+ * object, but we'll see.
+ */
+ for (var y in settings.html[x]) {
+ this.html[x].add(settings.html[x][y]);
+ }
+ } else {
+ this.html[x] = settings.html[x];
+ }
+ }
+ }
+ }
+ add(box) {
+ this._boxes.push(box);
+ this.html.appendChild(box.html);
+ }
+ close() {
+ for (var x in this._boxes) {
+ this._boxes[x].close();
+ }
+ if (this.html.parentElement != null) {
+ this.html.parentElement.removeChild(this.html);
+ }
+ }
+ update() {
+ for (var x in this._boxes) {
+ this._boxes[x].update();
+ }
+ }
+};
+
+
+class nmsString extends nmsBox {
+ constructor(content,type) {
+ type = type ? type : "p";
+ super(type,{ html: { textContent: content }})
+ }
+ set value(input) {
+ this.html.textContent = input;
+ }
+ get value() {
+ return this.html.textContent;
+ }
+}
+/*
+ * A general-purpose table. It can be created in one go, or
+ * as-you-go.
+ */
+class nmsTable extends nmsBox {
+ constructor(content, caption) {
+ super("table");
+ this.html.className = "table";
+ this.html.classList.add("table");
+ this.html.classList.add("table-condensed");
+ if (caption != undefined) {
+ var cap = new nmsBox("caption");
+ cap.html.textContent = caption;
+ super.add(cap);
+ }
+ this._tbody = new nmsBox("tbody");
+ super.add(this._tbody);
+ for (var v in content) {
+ this.add(content[v]);
+ }
+ }
+ /* Can take either a single nmsBox-object that will be added as-is,
+ * or an array of items that will be added as individual cells
+ */
+ add(content) {
+ if (content instanceof nmsBox) {
+ this._tbody.add(content)
+ return;
+ }
+ var tr;
+ var td1;
+ var td2;
+ tr = new nmsBox("tr");
+ tr.html.className = content[0].toLowerCase().replace(/[^a-z0-9_]/g,"");
+ for (var x in content) {
+ var td = new nmsBox("td");
+ var child = content[x];
+ if (x == 0) {
+ td.html.classList.add("left");
+ }
+ if (child instanceof nmsBox) {
+ td.add(child);
+ } else {
+ td.add(new nmsString(child));
+ }
+ tr.add(td);
+ }
+ this._tbody.add(tr);
+ }
+}
+
+/*
+ * Basic panel. Rooted at the 'metaContainer' as of now, but that MIGHT CHANGE.
+ * Draws a nice box with a background, title, close-button and whatnot.
+ * Usage:
+ * var myThing = new nmsPanel("initial title");
+ * myThing.add(nmsString("whatever"))
+ * myThing.title = "blah...."
+ */
+class nmsPanel extends nmsBox{
+ constructor(title){
+ super("div",{html: { classList: ["col-sm-8","col-md-6","col-lg-5","genericBox"]}});
+ this._topBox = new nmsBox("div",{ html: { classList: ["panel","panel-default"]}});
+ this._body = new nmsBox("div",{html:{classList: ["panel-body"]}});
+ this.nav = new nmsBox("div",{html:{classList: ["panel-body"]}});
+ this._topBox.add(this.makeHeading(title));
+ this._topBox.add(this.nav);
+ this._topBox.add(this._body);
+ super.add(this._topBox);
+ this._root = document.getElementById("metaContainer");
+ this._root.appendChild(this.html);
+ }
+ /* Mainly just to make the constructor more readable. */
+ makeHeading(title) {
+ var titleObject = new nmsBox("div",{html:{classList: ["panel-heading"]}});
+ this._titleText = new nmsBox("p",{html:{textContent: title}});
+ var closeButton = new nmsBox("button");
+ closeButton.html.className = "close";
+ closeButton.panel = this;
+ closeButton.html.onclick = function() {
+ this.nmsBox.panel.close();
+ }
+ closeButton.html.style = "float: right;";
+ closeButton.add(new nmsString("X","span"));
+ titleObject.add(closeButton);
+ titleObject.add(this._titleText);
+ return titleObject;
+ }
+ add(item) {
+ this._body.add(item)
+ }
+ set title(input) {
+ this._titleText.html.textContent = input;
+ }
+ get title() {
+ this._titleText.html.textContent;
+ }
+}
diff --git a/web/js/nms-ui-switch.js b/web/js/nms-ui-switch.js
new file mode 100644
index 0000000..fe4bbe9
--- /dev/null
+++ b/web/js/nms-ui-switch.js
@@ -0,0 +1,126 @@
+"use strict";
+
+class nmsUiSwitch extends nmsPanel {
+ constructor(sw) {
+ var title;
+ if (sw == undefined) {
+ title = "Add new switch"
+ } else {
+ title = "Edit " + sw;
+ }
+ super(title)
+ this._sw = sw;
+ this.populate()
+ }
+ /*
+ * We really should base this on a backend-API exposing relevant fields...
+ */
+ getTemplate(sw) {
+ if (sw == undefined) {
+ return {
+ mgmt_v4_addr: null,
+ mgmt_v6_addr: null,
+ community: null,
+ placement: null,
+ mgmt_vlan: null,
+ poll_frequency: null,
+ tags: null
+ };
+ }
+ 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) {
+ template[v] = swi[v];
+ }
+ for (var v in swm) {
+ if (v == "last_updated") {
+ continue;
+ }
+ template[v] = swm[v];
+ }
+ return template;
+ }
+ populate() {
+ var template = this.getTemplate(this._sw);
+ this.table = new nmsTable();
+ var first = new Array("sysname","distro_name","distro_phy_port","traffic_vlan")
+ var sorted = new Array();
+ for (var v in template) {
+ if (!first.includes(v)) {
+ sorted.push(v);
+ }
+ }
+ sorted.sort();
+ var finals = first.concat(sorted);
+ this.rows = {}
+ for (var i in finals) {
+ var v = finals[i];
+ this.rows[v] = new nmsEditRow(v, nmsInfoBox._nullBlank(template[v]));
+ this.rows[v].parent = this;
+ this.table.add(this.rows[v]);
+ }
+ this.add(this.table);
+ }
+ changed(row) {
+ this.title = "saw row change on " + row.name + " to " + row.value;
+ }
+ get value() {
+ return this.table.value;
+ }
+}
+
+class nmsEditRow extends nmsBox {
+ constructor(text,value) {
+ super("tr")
+ // This should/could be smarter in the future.
+ if (value instanceof Object) {
+ value = JSON.stringify(value);
+ }
+ this.name = text;
+ this._value = value;
+ this.original = value;
+ var td1 = new nmsBox("td")
+ td1.add(new nmsString(text))
+ this.add(td1);
+
+ var td2 = new nmsBox("td")
+ var input = new nmsBox("input")
+ input.html.value = value;
+ input.html.className = "form-control";
+ input.html.type = "text";
+ input.row = this;
+ input.html.onchange = function() {
+ this.nmsBox.row.value = this.value
+ }
+ input.html.oninput = function() {
+ this.nmsBox.row.value = this.value
+ }
+ this._input = input;
+ this._td2 = td2;
+ td2.add(input)
+ this.add(td2)
+ }
+ get value() {
+ return this._value;
+ }
+ set value(value) {
+ this._value = value;
+ if (this._input.html.value != value) {
+ this._input.html.value = value
+ }
+ if (this._value != this.original) {
+ this._td2.html.classList.add("has-warning");
+ } else {
+ this._td2.html.classList.remove("has-warning");
+ }
+ this.parent.changed(this)
+ }
+}