GUI -- augmented hash parsing to include flags (after '?'), which are passed into view callbacks as a boolean map.
- moved event test files into sub directories
- prepared topo2.js for scenario choice via hash context and 'local' (and 'debug') flag.
- added 'simple' scenario: 2 switches, 1 link, and 2 hosts.
- augmented topo event dispatch for yet-to-be-implemented event handlers.
- implemented addHost() event handler.
Change-Id: I06b032684fd4d5f85262d13d58ad10edae23b3ed
diff --git a/web/gui/src/main/webapp/index2.html b/web/gui/src/main/webapp/index2.html
index 6168271..9688522 100644
--- a/web/gui/src/main/webapp/index2.html
+++ b/web/gui/src/main/webapp/index2.html
@@ -90,6 +90,7 @@
<script src="sampleAlt2.js"></script>
<script src="sampleRadio.js"></script>
<script src="sampleKeys.js"></script>
+ <script src="sampleHash.js"></script>
<!-- Contributed (application) views injected here -->
<!-- TODO: replace with template marker and inject refs server-side -->
diff --git a/web/gui/src/main/webapp/json/intent/ev_1_ui.json b/web/gui/src/main/webapp/json/ev/intent/ev_1_ui.json
similarity index 100%
rename from web/gui/src/main/webapp/json/intent/ev_1_ui.json
rename to web/gui/src/main/webapp/json/ev/intent/ev_1_ui.json
diff --git a/web/gui/src/main/webapp/json/intent/ev_2_onos.json b/web/gui/src/main/webapp/json/ev/intent/ev_2_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/intent/ev_2_onos.json
rename to web/gui/src/main/webapp/json/ev/intent/ev_2_onos.json
diff --git a/web/gui/src/main/webapp/json/intent/ev_3_ui.json b/web/gui/src/main/webapp/json/ev/intent/ev_3_ui.json
similarity index 100%
rename from web/gui/src/main/webapp/json/intent/ev_3_ui.json
rename to web/gui/src/main/webapp/json/ev/intent/ev_3_ui.json
diff --git a/web/gui/src/main/webapp/json/intent/ev_4_onos.json b/web/gui/src/main/webapp/json/ev/intent/ev_4_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/intent/ev_4_onos.json
rename to web/gui/src/main/webapp/json/ev/intent/ev_4_onos.json
diff --git a/web/gui/src/main/webapp/json/intent/ev_5_onos.json b/web/gui/src/main/webapp/json/ev/intent/ev_5_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/intent/ev_5_onos.json
rename to web/gui/src/main/webapp/json/ev/intent/ev_5_onos.json
diff --git a/web/gui/src/main/webapp/json/intent/ev_6_onos.json b/web/gui/src/main/webapp/json/ev/intent/ev_6_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/intent/ev_6_onos.json
rename to web/gui/src/main/webapp/json/ev/intent/ev_6_onos.json
diff --git a/web/gui/src/main/webapp/json/intent/ev_7_ui.json b/web/gui/src/main/webapp/json/ev/intent/ev_7_ui.json
similarity index 100%
rename from web/gui/src/main/webapp/json/intent/ev_7_ui.json
rename to web/gui/src/main/webapp/json/ev/intent/ev_7_ui.json
diff --git a/web/gui/src/main/webapp/json/ev/intent/scenario.json b/web/gui/src/main/webapp/json/ev/intent/scenario.json
new file mode 100644
index 0000000..136d027
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/intent/scenario.json
@@ -0,0 +1,9 @@
+{
+ "comments": [
+ "This scenario steps through adding a host intent."
+ ],
+ "title": "Host Intent Scenario",
+ "params": {
+ "lastAuto": 0
+ }
+}
\ No newline at end of file
diff --git a/web/gui/src/main/webapp/json/ev/simple/ev_1_onos.json b/web/gui/src/main/webapp/json/ev/simple/ev_1_onos.json
new file mode 100644
index 0000000..1776f94
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/simple/ev_1_onos.json
@@ -0,0 +1,17 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:0000ffffffff0008",
+ "type": "switch",
+ "online": false,
+ "labels": [
+ "0000ffffffff0008",
+ "FF:FF:FF:FF:00:08",
+ "sw-8"
+ ],
+ "metaUi": {
+ "x": 400,
+ "y": 280
+ }
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/simple/ev_2_onos.json b/web/gui/src/main/webapp/json/ev/simple/ev_2_onos.json
new file mode 100644
index 0000000..4f9b32a
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/simple/ev_2_onos.json
@@ -0,0 +1,17 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:0000ffffffff0003",
+ "type": "switch",
+ "online": false,
+ "labels": [
+ "0000ffffffff0003",
+ "FF:FF:FF:FF:00:03",
+ "sw-3"
+ ],
+ "metaUi": {
+ "x": 800,
+ "y": 280
+ }
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/simple/ev_3_onos.json b/web/gui/src/main/webapp/json/ev/simple/ev_3_onos.json
new file mode 100644
index 0000000..3312682
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/simple/ev_3_onos.json
@@ -0,0 +1,14 @@
+{
+ "event": "addLink",
+ "payload": {
+ "src": "of:0000ffffffff0003",
+ "srcPort": "21",
+ "dst": "of:0000ffffffff0008",
+ "dstPort": "20",
+ "type": "infra",
+ "linkWidth": 2,
+ "props" : {
+ "BW": "70 G"
+ }
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/simple/ev_4_onos.json b/web/gui/src/main/webapp/json/ev/simple/ev_4_onos.json
new file mode 100644
index 0000000..51fdb8c
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/simple/ev_4_onos.json
@@ -0,0 +1,16 @@
+{
+ "event": "addHost",
+ "payload": {
+ "id": "00:00:00:00:00:03/-1",
+ "cp": {
+ "device": "of:0000ffffffff0003",
+ "port": 1
+ },
+ "labels": [
+ "10.0.0.3",
+ "00:00:00:00:00:03"
+ ],
+ "metaUi": {
+ }
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/simple/ev_5_onos.json b/web/gui/src/main/webapp/json/ev/simple/ev_5_onos.json
new file mode 100644
index 0000000..a6489b2
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/simple/ev_5_onos.json
@@ -0,0 +1,16 @@
+{
+ "event": "addHost",
+ "payload": {
+ "id": "00:00:00:00:00:08/-1",
+ "cp": {
+ "device": "of:0000ffffffff0008",
+ "port": 1
+ },
+ "labels": [
+ "10.0.0.8",
+ "00:00:00:00:00:08"
+ ],
+ "metaUi": {
+ }
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/simple/scenario.json b/web/gui/src/main/webapp/json/ev/simple/scenario.json
new file mode 100644
index 0000000..d24626f
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/simple/scenario.json
@@ -0,0 +1,9 @@
+{
+ "comments": [
+ "Add two devices and one link (auto), and two hosts."
+ ],
+ "title": "Simple Startup Scenario",
+ "params": {
+ "lastAuto": 0
+ }
+}
\ No newline at end of file
diff --git a/web/gui/src/main/webapp/json/eventTest_10.json b/web/gui/src/main/webapp/json/ev/startup/ev_10_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_10.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_10_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_11.json b/web/gui/src/main/webapp/json/ev/startup/ev_11_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_11.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_11_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_12.json b/web/gui/src/main/webapp/json/ev/startup/ev_12_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_12.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_12_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_13.json b/web/gui/src/main/webapp/json/ev/startup/ev_13_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_13.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_13_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_14.json b/web/gui/src/main/webapp/json/ev/startup/ev_14_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_14.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_14_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_15.json b/web/gui/src/main/webapp/json/ev/startup/ev_15_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_15.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_15_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_16.json b/web/gui/src/main/webapp/json/ev/startup/ev_16_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_16.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_16_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_17.json b/web/gui/src/main/webapp/json/ev/startup/ev_17_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_17.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_17_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_18.json b/web/gui/src/main/webapp/json/ev/startup/ev_18_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_18.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_18_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_19.json b/web/gui/src/main/webapp/json/ev/startup/ev_19_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_19.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_19_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_1.json b/web/gui/src/main/webapp/json/ev/startup/ev_1_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_1.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_1_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_20.json b/web/gui/src/main/webapp/json/ev/startup/ev_20_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_20.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_20_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_21.json b/web/gui/src/main/webapp/json/ev/startup/ev_21_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_21.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_21_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_22.json b/web/gui/src/main/webapp/json/ev/startup/ev_22_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_22.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_22_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_23.json b/web/gui/src/main/webapp/json/ev/startup/ev_23_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_23.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_23_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_24.json b/web/gui/src/main/webapp/json/ev/startup/ev_24_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_24.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_24_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_25.json b/web/gui/src/main/webapp/json/ev/startup/ev_25_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_25.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_25_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_26.json b/web/gui/src/main/webapp/json/ev/startup/ev_26_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_26.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_26_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_27.json b/web/gui/src/main/webapp/json/ev/startup/ev_27_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_27.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_27_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_28.json b/web/gui/src/main/webapp/json/ev/startup/ev_28_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_28.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_28_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_29.json b/web/gui/src/main/webapp/json/ev/startup/ev_29_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_29.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_29_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_2.json b/web/gui/src/main/webapp/json/ev/startup/ev_2_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_2.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_2_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_30.json b/web/gui/src/main/webapp/json/ev/startup/ev_30_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_30.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_30_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_31.json b/web/gui/src/main/webapp/json/ev/startup/ev_31_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_31.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_31_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_32.json b/web/gui/src/main/webapp/json/ev/startup/ev_32_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_32.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_32_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_33.json b/web/gui/src/main/webapp/json/ev/startup/ev_33_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_33.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_33_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_34.json b/web/gui/src/main/webapp/json/ev/startup/ev_34_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_34.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_34_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_35.json b/web/gui/src/main/webapp/json/ev/startup/ev_35_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_35.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_35_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_3.json b/web/gui/src/main/webapp/json/ev/startup/ev_3_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_3.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_3_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_4.json b/web/gui/src/main/webapp/json/ev/startup/ev_4_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_4.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_4_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_5.json b/web/gui/src/main/webapp/json/ev/startup/ev_5_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_5.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_5_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_6.json b/web/gui/src/main/webapp/json/ev/startup/ev_6_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_6.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_6_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_7.json b/web/gui/src/main/webapp/json/ev/startup/ev_7_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_7.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_7_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_8.json b/web/gui/src/main/webapp/json/ev/startup/ev_8_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_8.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_8_onos.json
diff --git a/web/gui/src/main/webapp/json/eventTest_9.json b/web/gui/src/main/webapp/json/ev/startup/ev_9_onos.json
similarity index 100%
rename from web/gui/src/main/webapp/json/eventTest_9.json
rename to web/gui/src/main/webapp/json/ev/startup/ev_9_onos.json
diff --git a/web/gui/src/main/webapp/json/ev/startup/scenario.json b/web/gui/src/main/webapp/json/ev/startup/scenario.json
new file mode 100644
index 0000000..37939ca0
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/startup/scenario.json
@@ -0,0 +1,10 @@
+{
+ "comments": [
+ "This scenario steps through adding devices and links.",
+ "(Typical 'start-ip' of the view.)"
+ ],
+ "title": "Startup Scenario",
+ "params": {
+ "lastAuto": 32
+ }
+}
\ No newline at end of file
diff --git a/web/gui/src/main/webapp/onos2.js b/web/gui/src/main/webapp/onos2.js
index 4aeb23e..a0276df 100644
--- a/web/gui/src/main/webapp/onos2.js
+++ b/web/gui/src/main/webapp/onos2.js
@@ -52,6 +52,7 @@
current = {
view: null,
ctx: '',
+ flags: {},
theme: settings.theme
},
built = false,
@@ -110,6 +111,7 @@
function doError(msg) {
errorCount++;
console.error(msg);
+ doAlert(msg);
}
function trace(msg) {
@@ -140,7 +142,7 @@
t = parseHash(hash);
if (!t || !t.vid) {
- doError('Unable to parse target hash: ' + hash);
+ doError('Unable to parse target hash: "' + hash + '"');
}
view = views[t.vid];
@@ -160,33 +162,72 @@
function parseHash(s) {
// extract navigation coordinates from the supplied string
- // "vid,ctx" --> { vid:vid, ctx:ctx }
+ // "vid,ctx?flag1,flag2" --> { vid:vid, ctx:ctx, flags:{...} }
traceFn('parseHash', s);
- var m = /^[#]{0,1}(\S+),(\S*)$/.exec(s);
+ // look for use of flags, first
+ var vidctx,
+ vid,
+ ctx,
+ flags,
+ flagMap,
+ m;
+
+ // RE that includes flags ('?flag1,flag2')
+ m = /^[#]{0,1}(.+)\?(.+)$/.exec(s);
if (m) {
- return { vid: m[1], ctx: m[2] };
+ vidctx = m[1];
+ flags = m[2];
+ flagMap = {};
+ } else {
+ // no flags
+ m = /^[#]{0,1}((.+)(,.+)*)$/.exec(s);
+ if (m) {
+ vidctx = m[1];
+ } else {
+ // bad hash
+ return null;
+ }
}
- m = /^[#]{0,1}(\S+)$/.exec(s);
- return m ? { vid: m[1] } : null;
+ vidctx = vidctx.split(',');
+ vid = vidctx[0];
+ ctx = vidctx[1];
+ if (flags) {
+ flags.split(',').forEach(function (f) {
+ flagMap[f.trim()] = true;
+ });
+ }
+
+ return {
+ vid: vid.trim(),
+ ctx: ctx ? ctx.trim() : '',
+ flags: flagMap
+ };
+
}
- function makeHash(t, ctx) {
+ function makeHash(t, ctx, flags) {
traceFn('makeHash');
- // make a hash string from the given navigation coordinates.
+ // make a hash string from the given navigation coordinates,
+ // and optional flags map.
// if t is not an object, then it is a vid
var h = t,
- c = ctx || '';
+ c = ctx || '',
+ f = $.isPlainObject(flags) ? flags : null;
if ($.isPlainObject(t)) {
h = t.vid;
c = t.ctx || '';
+ f = t.flags || null;
}
if (c) {
h += ',' + c;
}
+ if (f) {
+ h += '?' + d3.map(f).keys().join(',');
+ }
trace('hash = "' + h + '"');
return h;
}
@@ -244,6 +285,9 @@
// set the specified view as current, while invoking the
// appropriate life-cycle callbacks
+ // first, we'll start by closing the alerts pane, if open
+ closeAlerts();
+
// if there is a current view, and it is not the same as
// the incoming view, then unload it...
if (current.view && (current.view.vid !== view.vid)) {
@@ -258,10 +302,11 @@
// cache new view and context
current.view = view;
current.ctx = t.ctx || '';
+ current.flags = t.flags || {};
// preload is called only once, after the view is in the DOM
if (!view.preloaded) {
- view.preload(current.ctx);
+ view.preload(current.ctx, current.flags);
view.preloaded = true;
}
@@ -269,7 +314,7 @@
view.reset();
// load the view
- view.load(current.ctx);
+ view.load(current.ctx, current.flags);
}
// generate 'unique' id by prefixing view id
@@ -454,7 +499,7 @@
d3.selectAll('.onosView').call(setViewDimensions);
// allow current view to react to resize event...
if (current.view) {
- current.view.resize(current.ctx);
+ current.view.resize(current.ctx, current.flags);
}
}
@@ -521,13 +566,13 @@
}
},
- preload: function (ctx) {
+ preload: function (ctx, flags) {
var c = ctx || '',
fn = isF(this.cb.preload);
traceFn('View.preload', this.vid + ', ' + c);
if (fn) {
trace('PRELOAD cb for ' + this.vid);
- fn(this.token(), c);
+ fn(this.token(), c, flags);
}
},
@@ -544,15 +589,14 @@
}
},
- load: function (ctx) {
+ load: function (ctx, flags) {
var c = ctx || '',
fn = isF(this.cb.load);
traceFn('View.load', this.vid + ', ' + c);
this.$div.classed('currentView', true);
- // TODO: add radio button set, if needed
if (fn) {
trace('LOAD cb for ' + this.vid);
- fn(this.token(), c);
+ fn(this.token(), c, flags);
}
},
@@ -560,14 +604,13 @@
var fn = isF(this.cb.unload);
traceFn('View.unload', this.vid);
this.$div.classed('currentView', false);
- // TODO: remove radio button set, if needed
if (fn) {
trace('UNLOAD cb for ' + this.vid);
fn(this.token());
}
},
- resize: function (ctx) {
+ resize: function (ctx, flags) {
var c = ctx || '',
fn = isF(this.cb.resize),
w = this.width(),
@@ -576,7 +619,7 @@
' [' + w + 'x' + h + ']');
if (fn) {
trace('RESIZE cb for ' + this.vid);
- fn(this.token(), c);
+ fn(this.token(), c, flags);
}
},
diff --git a/web/gui/src/main/webapp/preamble.js b/web/gui/src/main/webapp/preamble.js
index 8ee8e45..b6a8c02 100644
--- a/web/gui/src/main/webapp/preamble.js
+++ b/web/gui/src/main/webapp/preamble.js
@@ -21,12 +21,17 @@
*/
(function () {
+
+ // NOTE: DON'T Want to do this.. we want to be able to
+ // use the parameter section, for example:
+ // #viewId,context?flag1,flag2,flag3
+
// Check if the URL in the address bar contains a parameter section
// (delineated by '?'). If this is the case, rewrite using '#' instead.
- var m = /([^?]*)\?(.*)/.exec(window.location.href);
- if (m) {
- window.location.href = m[1] + '#' + m[2];
- }
+ //var m = /([^?]*)\?(.*)/.exec(window.location.href);
+ //if (m) {
+ // window.location.href = m[1] + '#' + m[2];
+ //}
}());
diff --git a/web/gui/src/main/webapp/sampleHash.js b/web/gui/src/main/webapp/sampleHash.js
new file mode 100644
index 0000000..c94ebb8
--- /dev/null
+++ b/web/gui/src/main/webapp/sampleHash.js
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ Sample view to illustrate hash formats.
+
+ @author Simon Hunt
+ */
+
+(function (onos) {
+ 'use strict';
+
+ var intro = "Try using the following hashes in the address bar:",
+ hashPrefix = '#sampleHash',
+ suffixes = [
+ '',
+ ',one',
+ ',two',
+ ',context,ignored',
+ ',context,ignored?a,b,c',
+ ',two?foo',
+ ',three?foo,bar'
+ ],
+ $d;
+
+ function note(txt) {
+ $d.append('p')
+ .text(txt)
+ .style({
+ 'font-size': '10pt',
+ color: 'darkorange',
+ padding: '0 20px',
+ margin: 0
+ });
+ }
+
+ function para(txt, color) {
+ var c = color || 'black';
+ $d.append('p')
+ .text(txt)
+ .style({
+ padding: '2px 8px',
+ color: c
+ });
+ }
+
+ function load(view, ctx, flags) {
+ var c = ctx || '(undefined)',
+ f = flags ? d3.map(flags).keys() : [];
+
+ $d = view.$div;
+
+ para(intro);
+
+ suffixes.forEach(function (s) {
+ note(hashPrefix + s);
+ });
+
+ para('View ID: ' + view.vid, 'blue');
+ para('Context: ' + c, 'blue');
+ para('Flags: { ' + f.join(', ') + ' }', 'magenta');
+ }
+
+ // == register the view here, with links to lifecycle callbacks
+
+ onos.ui.addView('sampleHash', {
+ reset: true, // empty the div on reset
+ load: load
+ });
+
+}(ONOS));
diff --git a/web/gui/src/main/webapp/topo2.css b/web/gui/src/main/webapp/topo2.css
index c4d9a2d..2602f6f 100644
--- a/web/gui/src/main/webapp/topo2.css
+++ b/web/gui/src/main/webapp/topo2.css
@@ -20,55 +20,59 @@
@author Simon Hunt
*/
-svg #topo-bg {
+#topo svg #topo-bg {
opacity: 0.5;
}
/* NODES */
-svg .node.device {
+#topo svg .node.device {
stroke: none;
stroke-width: 1.5px;
cursor: pointer;
}
-svg .node.device rect {
+#topo svg .node.device rect {
stroke-width: 1.5px;
}
-svg .node.device.fixed rect {
+#topo svg .node.device.fixed rect {
stroke-width: 1.5;
stroke: #ccc;
}
-svg .node.device.switch {
+#topo svg .node.device.switch {
fill: #17f;
}
-svg .node.device.roadm {
+#topo svg .node.device.roadm {
fill: #03c;
}
-svg .node text {
+#topo svg .node.host {
+ fill: #846;
+}
+
+#topo svg .node text {
stroke: none;
fill: white;
font: 10pt sans-serif;
pointer-events: none;
}
-svg .node.selected rect,
-svg .node.selected circle {
+#topo svg .node.selected rect,
+#topo svg .node.selected circle {
filter: url(#blue-glow);
}
/* LINKS */
-svg .link {
+#topo svg .link {
opacity: .7;
}
/* for debugging */
-svg .node circle.debug {
+#topo svg .node circle.debug {
fill: white;
stroke: red;
}
diff --git a/web/gui/src/main/webapp/topo2.js b/web/gui/src/main/webapp/topo2.js
index acd2464..75fb99b 100644
--- a/web/gui/src/main/webapp/topo2.js
+++ b/web/gui/src/main/webapp/topo2.js
@@ -132,8 +132,21 @@
links: [],
lookup: {}
},
+ scenario = {
+ evDir: 'json/ev/',
+ evScenario: '/scenario.json',
+ evPrefix: '/ev_',
+ evOnos: '_onos.json',
+ evUi: '_ui.json',
+ ctx: null,
+ params: {},
+ evNumber: 0,
+ view: null,
+ debug: false
+ },
webSock,
- labelIdx = 0,
+ deviceLabelIndex = 0,
+ hostLabelIndex = 0,
selectOrder = [],
selections = {},
@@ -155,10 +168,6 @@
// ==============================
// For Debugging / Development
- var eventPrefix = 'json/eventTest_',
- eventNumber = 0,
- alertNumber = 0;
-
function note(label, msg) {
console.log('NOTE: ' + label + ': ' + msg);
}
@@ -175,32 +184,71 @@
view.alert('test');
}
- function injectTestEvent(view) {
+ function abortIfLive() {
if (config.useLiveData) {
- view.alert("Sorry, currently using live data..");
- return;
+ scenario.view.alert("Sorry, currently using live data..");
+ return true;
}
+ return false;
+ }
- eventNumber++;
- var eventUrl = eventPrefix + eventNumber + '.json';
+ function testDebug(msg) {
+ if (scenario.debug) {
+ scenario.view.alert(msg);
+ }
+ }
- d3.json(eventUrl, function(err, data) {
+ function injectTestEvent(view) {
+ if (abortIfLive()) { return; }
+ var sc = scenario,
+ evn = ++sc.evNumber,
+ pfx = sc.evDir + sc.ctx + sc.evPrefix + evn,
+ onosUrl = pfx + sc.evOnos,
+ uiUrl = pfx + sc.evUi;
+
+ tryOnosEvent(onosUrl, uiUrl);
+ }
+
+ // TODO: tryOnosEvent/tryUiEvent folded into recursive function.
+ function tryOnosEvent(onosUrl, uiUrl) {
+ var v = scenario.view;
+ d3.json(onosUrl, function(err, data) {
if (err) {
- view.dataLoadError(err, eventUrl);
+ if (err.status === 404) {
+ tryUiEvent(uiUrl);
+ } else {
+ v.alert('non-404 error:\n\n' + onosUrl + '\n\n' + err);
+ }
} else {
+ testDebug('loaded: ' + onosUrl);
handleServerEvent(data);
}
});
}
- function injectStartupEvents(view) {
- if (config.useLiveData) {
- view.alert("Sorry, currently using live data..");
- return;
- }
+ function tryUiEvent(uiUrl) {
+ var v = scenario.view;
+ d3.json(uiUrl, function(err, data) {
+ if (err) {
+ v.alert('Error:\n\n' + uiUrl + '\n\n' +
+ err.status + ': ' + err.statusText);
+ } else {
+ testDebug('loaded: ' + uiUrl);
+ handleUiEvent(data);
+ }
+ });
+ }
- var lastStartupEvent = 32;
- while (eventNumber < lastStartupEvent) {
+ function handleUiEvent(data) {
+ testDebug('handleUiEvent(): ' + data.event);
+ // TODO:
+ }
+
+ function injectStartupEvents(view) {
+ var last = scenario.params.lastAuto || 0;
+ if (abortIfLive()) { return; }
+
+ while (scenario.evNumber < last) {
injectTestEvent(view);
}
}
@@ -211,14 +259,16 @@
}
function cycleLabels() {
- labelIdx = (labelIdx === network.deviceLabelCount - 1) ? 0 : labelIdx + 1;
+ deviceLabelIndex = (deviceLabelIndex === network.deviceLabelCount - 1) ? 0 : deviceLabelIndex + 1;
function niceLabel(label) {
return (label && label.trim()) ? label : '.';
}
network.nodes.forEach(function (d) {
- var idx = (labelIdx < d.labels.length) ? labelIdx : 0,
+ if (d.class !== 'device') { return; }
+
+ var idx = (deviceLabelIndex < d.labels.length) ? deviceLabelIndex : 0,
node = d3.select('#' + safeId(d.id)),
box;
@@ -303,9 +353,14 @@
var eventDispatch = {
addDevice: addDevice,
- updateDevice: updateDevice,
- removeDevice: removeDevice,
+ updateDevice: stillToImplement,
+ removeDevice: stillToImplement,
addLink: addLink,
+ updateLink: stillToImplement,
+ removeLink: stillToImplement,
+ addHost: addHost,
+ updateHost: stillToImplement,
+ removeHost: stillToImplement,
showPath: showPath
};
@@ -320,18 +375,6 @@
network.force.start();
}
- function updateDevice(data) {
- var device = data.payload;
- note('updateDevice', device.id);
-
- }
-
- function removeDevice(data) {
- var device = data.payload;
- note('removeDevice', device.id);
-
- }
-
function addLink(data) {
var link = data.payload,
lnk = createLink(link);
@@ -345,11 +388,35 @@
}
}
+ function addHost(data) {
+ var host = data.payload,
+ node = createHostNode(host),
+ lnk;
+
+ note('addHost', node.id);
+ network.nodes.push(node);
+ network.lookup[host.id] = node;
+ updateNodes();
+
+ lnk = createHostLink(host);
+ if (lnk) {
+ network.links.push(lnk);
+ updateLinks();
+ }
+ network.force.start();
+ }
+
function showPath(data) {
network.view.alert(data.event + "\n" + data.payload.links.length);
}
- // ....
+ // ...............................
+
+ function stillToImplement(data) {
+ var p = data.payload;
+ note(data.event, p.id);
+ network.view.alert('Not yet implemented: "' + data.event + '"');
+ }
function unknownEvent(data) {
network.view.alert('Unknown event type: "' + data.event + '"');
@@ -367,6 +434,35 @@
return 'translate(' + x + ',' + y + ')';
}
+ function createHostLink(host) {
+ var src = host.id,
+ dst = host.cp.device,
+ srcNode = network.lookup[src],
+ dstNode = network.lookup[dst],
+ lnk;
+
+ if (!dstNode) {
+ // TODO: send warning message back to server on websocket
+ network.view.alert('switch not on map for link\n\n' +
+ 'src = ' + src + '\ndst = ' + dst);
+ return null;
+ }
+
+ lnk = {
+ id: safeId(src) + '~' + safeId(dst),
+ source: srcNode,
+ target: dstNode,
+ class: 'link',
+ svgClass: 'link hostLink',
+ x1: srcNode.x,
+ y1: srcNode.y,
+ x2: dstNode.x,
+ y2: dstNode.y,
+ width: 1
+ };
+ return lnk;
+ }
+
function createLink(link) {
var type = link.type,
src = link.src,
@@ -451,6 +547,22 @@
return node;
}
+ function createHostNode(host) {
+ // start with the object as is
+ var node = host;
+
+ // Augment as needed...
+ node.class = 'host';
+ node.svgClass = 'node host';
+ // TODO: consider placing near its switch, if [x,y] not defined
+ positionNode(node);
+
+ // cache label array length
+ network.hostLabelCount = host.labels.length;
+
+ return node;
+ }
+
function positionNode(node) {
var meta = node.metaUi,
x = 0,
@@ -525,7 +637,7 @@
entering.filter('.device').each(function (d) {
var node = d3.select(this),
icon = iconUrl(d),
- idx = (labelIdx < d.labels.length) ? labelIdx : 0,
+ idx = (deviceLabelIndex < d.labels.length) ? deviceLabelIndex : 0,
box;
node.append('rect')
@@ -568,6 +680,32 @@
}
});
+ // augment host nodes...
+ entering.filter('.host').each(function (d) {
+ var node = d3.select(this),
+ idx = (hostLabelIndex < d.labels.length) ? hostLabelIndex : 0,
+ box;
+
+ node.append('circle')
+ .attr('r', 8); // TODO: define host circle radius
+
+ // TODO: are we attaching labels to hosts?
+ node.append('text')
+ .text(d.labels[idx])
+ .attr('dy', '1.1em');
+
+ // debug function to show the modelled x,y coordinates of nodes...
+ if (debug('showNodeXY')) {
+ node.select('circle').attr('fill-opacity', 0.5);
+ node.append('circle')
+ .attr({
+ class: 'debug',
+ cx: 0,
+ cy: 0,
+ r: '3px'
+ });
+ }
+ });
// operate on both existing and new nodes, if necessary
//node .foo() .bar() ...
@@ -643,7 +781,7 @@
if (webSock.ws) {
webSock.ws.send(message);
} else {
- network.view.alert('no web socket open');
+ network.view.alert('no web socket open\n\n' + message);
}
}
@@ -714,7 +852,7 @@
//flyinPane(null);
}
-
+ // TODO: this click handler does not get unloaded when the view does
$('#view').on('click', function(e) {
if (!$(e.target).closest('.node').length) {
if (!e.metaKey) {
@@ -723,6 +861,33 @@
}
});
+
+ function prepareScenario(view, ctx, dbg) {
+ var sc = scenario,
+ urlSc = sc.evDir + ctx + sc.evScenario;
+
+ if (!ctx) {
+ view.alert("No scenario specified (null ctx)");
+ return;
+ }
+
+ sc.view = view;
+ sc.ctx = ctx;
+ sc.debug = dbg;
+ sc.evNumber = 0;
+
+ d3.json(urlSc, function(err, data) {
+ var p = data && data.params || {};
+ if (err) {
+ view.alert('No scenario found:\n\n' + urlSc + '\n\n' + err);
+ } else {
+ sc.params = p;
+ view.alert("Scenario loaded: " + ctx + '\n\n' + data.title);
+ }
+ });
+
+ }
+
// ==============================
// View life-cycle callbacks
@@ -781,14 +946,11 @@
}
function atDragEnd(d, self) {
- // once we've finished moving, pin the node in position,
- // if it is a device (not a host)
- if (d.class === 'device') {
- d.fixed = true;
- d3.select(self).classed('fixed', true);
- if (config.useLiveData) {
- tellServerCoords(d);
- }
+ // once we've finished moving, pin the node in position
+ d.fixed = true;
+ d3.select(self).classed('fixed', true);
+ if (config.useLiveData) {
+ tellServerCoords(d);
}
}
@@ -814,9 +976,14 @@
network.drag = d3u.createDragBehavior(network.force, selectCb, atDragEnd);
}
- function load(view, ctx) {
+ function load(view, ctx, flags) {
// cache the view token, so network topo functions can access it
network.view = view;
+ config.useLiveData = !flags.local;
+
+ if (!config.useLiveData) {
+ prepareScenario(view, ctx, flags.debug);
+ }
// set our radio buttons and key bindings
view.setRadio(btnSet);