verbosity: fixes split verbosity level 1 in 2 levels
[src/app-framework-binder.git] / test / monitoring / monitor.js
index 6926260..22d7182 100644 (file)
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2017 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * 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.
+ */
 
 var afb;
 var ws;
@@ -8,10 +24,13 @@ var t_logmsg;
 var t_traceevent;
 var t_verbosity;
 var t_trace;
+var t_separator;
+
 var apis = {};
 var events = [];
 var inhibit = false;
 var msgs = false;
+var autoscroll = false;
 
 var root_node;
 var connected_node;
@@ -28,34 +47,38 @@ _.templateSettings = { interpolate: /\{\{(.+?)\}\}/g };
 
 function untrace_all() {
        do_call("monitor/trace", {drop: true});
-       for_all_nodes(null, ".trace-item input[type=radio]", function(n){n.checked = n.value == "no";});
 }
 
-function disconnect() {
-       untrace_all();
-       apis = {};
-       apis_node.innerHTML = "";
-       root_node.className = "off";
+function disconnect(status) {
+       class_toggle(root_node, { on: "off" }, "off");
        connected_node.innerHTML = "Connection Closed";
-       connected_node.className = "ok";
-       ws && ws.close();
-       afb = null;
+       connected_node.className = status;
+       if (ws) {
+               untrace_all();
+               ws.onclose = ws.onabort = null;
+               ws.close();
+       }
        ws = null;
+       if (afb)
+               at("param-token").value = afb.context.token;
+       afb = null;
 }
 
-function connect(args) {
-       drop_all_trace_events();
-       drop_all_logmsgs();
-       ws && ws.close();
-       afb = new AFB(args);
-       ws = new afb.ws(onopen, onabort);
+function on_disconnect() {
+       disconnect("ok");
 }
 
-function on_connect(evt) {
-       connect({
+function connect() {
+       ws && ws.close();
+       afb = new AFB({
                host: at("param-host").value + ":" + at("param-port").value,
                token: at("param-token").value
        });
+       ws = new afb.ws(onopen, onabort);
+}
+
+function on_connect(evt) {
+       connect();
 }
 
 function init() {
@@ -66,6 +89,7 @@ function init() {
        t_traceevent = at("t-traceevent").content.firstElementChild;
        t_verbosity = at("t-verbosity").content.firstElementChild;
        t_trace = at("t-trace").content.firstElementChild;
+       t_separator = at("t-separator").content.firstElementChild;
 
        root_node = at("root");
        connected_node = at("connected");
@@ -83,13 +107,24 @@ function init() {
        for_all_nodes(root_node, ".opclo ~ :not(.closedoff)", function(n){n.onclick = on_toggle_opclo});
        for_all_nodes(root_node, ".verbosity select", function(n){n.onchange = set_verbosity});
        for_all_nodes(root_node, ".trace-item input", function(n){n.onchange = on_trace_change});
-       at("disconnect").onclick = disconnect;
+       at("disconnect").onclick = on_disconnect;
        at("connect").onclick = on_connect;
        at("droptracevts").onclick = drop_all_trace_events;
        at("dropmsgs").onclick = drop_all_logmsgs;
        at("stopmsgs").onclick = toggle_logmsgs;
        start_logmsgs(false);
        trace_events_node.onclick = on_toggle_traceevent;
+       at("autoscroll").onclick = toggle_autoscroll;
+       start_autoscroll(true);
+       at("addsep").onclick = add_separator;
+       at("experts").onclick = toggle_experts;
+
+       at("param-host").value = document.location.hostname;
+       at("param-port").value = document.location.port;
+       var args = new URLSearchParams(document.location.search.substring(1));
+       at("param-token").value = args.get("x-afb-token") || args.get("token") || "hello";
+
+       document.onbeforeunload = on_disconnect;
 
        connect();
 }
@@ -114,17 +149,39 @@ function plug(target, sel, node) {
 }
 
 function onopen() {
-       root_node.className = "on";
+       class_toggle(root_node, { off: "on" }, "on");
        connected_node.innerHTML = "Connected " + ws.url;
        connected_node.className = "ok";
        ws.onevent("*", gotevent);
        ws.onclose = onabort;
+       untrace_all();
+       for_all_nodes(all_node, ".trace-box", update_trace_box);
        do_call("monitor/get", {apis:true,verbosity:true}, on_got_apis, on_error_apis);
 }
+
 function onabort() {
-       root_node.className = "off";
-       connected_node.innerHTML = "Connection Closed";
-       connected_node.className = "error";
+       disconnect("error");
+}
+
+function start_autoscroll(val) {
+       at("autoscroll").textContent = (autoscroll = val) ? "Stop scroll" : "Start scroll";
+}
+
+function toggle_autoscroll() {
+       start_autoscroll(!autoscroll);
+}
+
+function add_separator() {
+       var x = document.importNode(t_separator, true);
+       trace_events_node.append(x);
+       if (autoscroll)
+               x.scrollIntoView();
+       if (msgs) {
+               x = document.importNode(t_separator, true);
+               logmsgs_node.append(x);
+               if (autoscroll)
+                       x.scrollIntoView();
+       }
 }
 
 function start_logmsgs(val) {
@@ -151,7 +208,9 @@ function add_logmsg(tag, content, add) {
        get(".close", x).onclick = function(evt){x.remove();};
        if (add)
                x.className = x.className + " " + add;
-       logmsgs_node.prepend(x);
+       logmsgs_node.append(x);
+       if (autoscroll)
+               x.scrollIntoView();
 }
 
 function add_error(tag, obj) {
@@ -209,10 +268,14 @@ function set_verbosity(evt) {
 /* show all apis */
 function on_got_apis(obj) {
        inhibit = true;
+       var saved_apis = apis;
+       apis = {};
+       apis_node.innerHTML = "";
        _.each(obj.response.apis, function(api_desc, api_name){
                if (api_name == "monitor") return;
-               var api = apis[api_name];
+               var api = saved_apis[api_name];
                if (!api) {
+                       /* create the node */
                        api = {
                                node: document.importNode(t_api, true),
                                verbs: {},
@@ -221,13 +284,22 @@ function on_got_apis(obj) {
                        api.node.API = api;
                        api.node.dataset.api = api_name;
                        api.vnode = get(".verbs", api.node);
-                       apis[api_name] = api;
                        get(".name", api.node).textContent = api_name;
-                       get(".desc", api.node).textContent = api_desc.info.description || "";
+                       var s = get(".verbosity select", api.node);
+                       s.API = api;
+                       s.onchange = set_verbosity;
                        for_all_nodes(api.node, ".opclo", function(n){n.onclick = on_toggle_opclo});
                        for_all_nodes(api.node, ".opclo ~ :not(.closedoff)", function(n){n.onclick = on_toggle_opclo});
                        for_all_nodes(api.node, ".trace-item input", function(n){n.onchange = on_trace_change});
-                       apis_node.append(api.node);
+               } else {
+                       /* reactivate the expected traces */
+                       for_all_nodes(api.node, ".trace-box", update_trace_box);
+               }
+               apis[api_name] = api;
+               if (api_desc == null) {
+                       get(".desc", api.node).textContent = "?? unrecoverable ??";
+               } else {
+                       get(".desc", api.node).textContent = api_desc.info.description || "";
                        _.each(api_desc.paths, function(verb_desc, path_name){
                                var verb_name = path_name.substring(1);
                                var verb = api.verbs[verb_name];
@@ -253,10 +325,8 @@ function on_got_apis(obj) {
                                        api.vnode.append(verb.node);
                                }
                        });
-                       var s = get(".verbosity select", api.node);
-                       s.API = api;
-                       s.onchange = set_verbosity;
                }
+               apis_node.append(api.node);
        });
        inhibit = false;
        on_got_verbosities(obj);
@@ -266,37 +336,42 @@ function on_toggle_opclo(evt) {
        toggle_opened_closed(evt.target.parentElement);
 }
 
-function on_trace_change(evt) {
-       var obj = evt.target;
-       var tra = obj.parentElement;
-       while (tra && !tra.dataset.trace)
-               tra = tra.parentElement;
-       var api = tra;
+function toggle_experts(evt) {
+       toggle_opened_closed(evt.target);
+}
+
+function update_trace_box(node) {
+       set_trace_box(node, false);
+}
+
+function set_trace_box(node, clear) {
+       var api = node;
        while (api && !api.dataset.api)
                api = api.parentElement;
-       var tag = api.dataset.api + "/" + tra.dataset.trace;
-       if (tra) {
-               var drop = false;
-               for_all_nodes(tra, "input", function(n){
-                       if (n.checked) {
-                               n.checked = false;
-                               if (n != obj && n.value != "no")
-                                       drop = true;
-                       }
-               });
-               if (drop)
-                       do_call("monitor/trace", {drop: {tag: tag}});
-               obj.checked = true;
-               if (obj.value != "no") {
-                       var spec = {tag: tag, name: "trace"};
-                       spec[tra.dataset.trace] = obj.value;
-                       if (api.dataset.api != "*")
-                               spec.api = api.dataset.api;
-                       do_call("monitor/trace", {add: spec});
-               }
+       var tag = api.dataset.api + "/" + node.dataset.trace;
+       var value = false;
+       for_all_nodes(node, "input", function(n){ if (n.checked) value = n.value; });
+       if (clear)
+               do_call("monitor/trace", {drop: {tag: tag}});
+       if (value != "no") {
+               var spec = {tag: tag, name: "trace"};
+               spec[node.dataset.trace] = value;
+               if (api.dataset.api != "*")
+                       spec.api = api.dataset.api;
+               do_call("monitor/trace", {add: spec});
        }
 }
 
+function on_trace_change(evt) {
+       var obj = evt.target;
+       var box = obj.parentElement;
+       while (box && !box.dataset.trace)
+               box = box.parentElement;
+       for_all_nodes(box, "input", function(n){n.checked = false;});
+       obj.checked = true;
+       set_trace_box(box, true);
+}
+
 function makecontent(node, deep, val) {
        if (--deep > 0) {
                if (_.isObject(val)) {
@@ -308,7 +383,7 @@ function makecontent(node, deep, val) {
                        return;
                }
        }
-       node.innerHTML = obj2html(val);
+       node.innerHTML = '<pre>' + obj2html(val) + '</pre>';
 }
 
 function makearritem(tbl, deep, val) {
@@ -358,7 +433,7 @@ function gotevent(obj) {
 
 function gottraceevent(obj) {
        var data = obj.data;
-       var type = _.find(["request", "service", "daemon", "event"],function(x){return x in data;});
+       var type = data.type;
        var desc = data[type];
        if (!show_monitor_events) {
                if (type == "event" ? desc.name.startsWith("monitor/") : desc.api == "monitor")
@@ -374,31 +449,36 @@ function gottraceevent(obj) {
                service: function(r) { return r.api + "@" + r.action; },
                daemon: function(r) { return r.api + ":" + r.action; },
                event: function(r) { return r.name + "!" + r.action; },
+               global: function(r) { return "$" + r.action; },
                })[type](desc);
        var tab = makeobj(desc, 4);
        if ("data" in data)
                makeobjitem(tab, 2, "data", data.data);
        get(".content", x).append(tab);
        trace_events_node.append(x);
+       if (autoscroll)
+               x.scrollIntoView();
 }
 
-function toggle_opened_closed(node, defval) {
+function class_toggle(node, assoc, defval) {
        var matched = false;
        var cs = node.className.split(" ").map(
                function(x){
-                       if (!matched) {
-                               switch(x) {
-                               case "closed": matched = true; return "opened";
-                               case "opened": matched = true; return "closed";
-                               }
+                       if (!matched && (x in assoc)) {
+                               matched = true;
+                               return assoc[x];
                        }
-                       return x;
+                       return x == defval ? "" : x;
                }).join(" ");
-       if (!matched)
-               cs = cs + " " + (defval || "closed");
+       if (!matched && defval)
+               cs = cs + " " + defval;
        node.className = cs;
 }
 
+function toggle_opened_closed(node, defval) {
+       class_toggle(node, { closed: "opened", opened: "closed" }, defval);
+}
+
 function on_toggle_traceevent(evt) {
        if (getSelection() != "") return;
        var node = evt.target;