pvl.verkko.hosts: refactor RealtimeHandler to use HostsTable
authorTero Marttila <terom@paivola.fi>
Sun, 10 Feb 2013 13:20:29 +0200
changeset 205 f7658198c224
parent 204 72304d66ecd1
child 206 079bf632442d
pvl.verkko.hosts: refactor RealtimeHandler to use HostsTable
pvl/verkko/hosts.py
static/dhcp/hosts.js
static/dhcp/table.js
--- a/pvl/verkko/hosts.py	Sun Feb 10 13:18:21 2013 +0200
+++ b/pvl/verkko/hosts.py	Sun Feb 10 13:20:29 2013 +0200
@@ -305,6 +305,7 @@
         'http://code.jquery.com/jquery-1.8.2.js',
         'http://code.jquery.com/ui/1.9.0/jquery-ui.js',
         '/static/dhcp/spin.js',
+        '/static/dhcp/table.js',
         '/static/dhcp/hosts.js',
     )
 
@@ -322,8 +323,14 @@
             Either return JSON (if ?t=...), or fetch hosts/t for rendering.
         """
 
-        hosts = self.db.query(Host)
         t = self.request.args.get('t')
+
+        if t :
+            # return json
+            t = ts2dt(int(t))
+
+        # query
+        hosts = self.query()
         
         # always sorted by last_seen
         hosts = hosts.order_by(Host.last_seen.desc())
@@ -331,56 +338,43 @@
         # filter
         self.filters, hosts = self.filter(hosts)
 
-        def host_params (host) :
-            yield 'id', host.id
-
-            for name, title, fvalue in self.COLUMNS :
-                value = fvalue(host)
-
-                if name == 'seen' :
-                    # XXX: hackfix html() rendering
-                    value = unicode(html.div(value))
-
-                yield name, value
-            
-            # special
-            yield 'state_class', host.state_class()
-        
         if t :
             # return json
-            t = ts2dt(int(t))
-
             hosts = hosts.filter(Host.last_seen > t)
             hosts = list(hosts)
             hosts.reverse()
             
             if hosts :
+                # update timestamp to most recent
                 t = hosts[-1].last_seen
-                hosts = [dict(host_params(host)) for host in hosts]
 
-            else :
-                hosts = []
-
+            # json
             data = dict(
                 t       = dt2ts(t),
-                hosts   = hosts,
+                hosts   = [dict(self.table.json(host)) for host in hosts],
             )
 
             return response.json(data)
 
         else :
             # render html
-            hosts = hosts.limit(10)
+            hosts = hosts.limit(self.table.PAGE)
 
             # XXX: testing
             hosts = hosts.offset(1)
 
-            self.hosts = list(hosts)
+            # extract timestamp
+            for host in hosts :
+                self.t = host.last_seen
+
+                break
+
+            else :
+                # no hosts :<
+                self.t = datetime.datetime.now()
             
-            if self.hosts :
-                self.t = self.hosts[0].last_seen
-            else :
-                self.t = datetime.datetime.now()
+            # store
+            self.hosts = hosts
 
     def title (self) :
         if self.filters :
@@ -392,48 +386,27 @@
         """
             Render page HTML and initial <table>, along with bootstrap JS (t0, configuration).
         """
-
-        def column (name, title, fvalue, host) :
-            cls = name
-
-            if name == 'state' :
-                cls = host.state_class()
-
-            return html.td(class_=cls)(fvalue(host))
-
-        params = dict(
-            url     = self.url(),
-            filters = self.filters,
-            t       = dt2ts(self.t),
-            host    = self.url(ItemHandler, id='0'),
-            columns = [name for name, title, fvalue in self.COLUMNS]
-        )
-        params = json.dumps(params)
-        
+    
         return html.div(id='wrapper')(
             html.input(type='submit', id='refresh', value="Refresh"),
             html.input(type='reset', id='pause', value="Pause"),
-            html.table(id='hosts')(
-                html.thead(
-                    html.tr(
-                        html.th('#'),
-                        (
-                            html.th(class_=name)(title) for name, title, fvalue in self.COLUMNS
-                        )
-                    ),
-                ),
-                html.tbody(
-                    html.tr(id=host.id)(
-                        html.td(html.a(href=self.url(ItemHandler, id=host.id))('#')),
-                        (
-                            column(name, title, fvalue, host) for name, title, fvalue in self.COLUMNS
-                        ),
-                    ) for host in self.hosts
+
+            self.table.render(self.hosts)(id='hosts-realtime'),
+
+            html.script(type='text/javascript')(
+                """
+$(document).ready(HostsRealtime(Table($('#hosts-realtime'), {table_params}), {params}));
+                """.format(
+                    table_params = json.dumps(dict(
+                        item_url        = self.url(ItemHandler, id='0'),
+                        columns         = [column.attr for column in self.table.columns],
+                    )),
+                    params = json.dumps(dict(
+                        url     = self.url(),
+                        filters = self.filters,
+                        t       = dt2ts(self.t),
+                    )),
                 )
-            ),
-            html.script(type='text/javascript')("""
-$(document).ready(hosts_realtime({params}));
-""".format(params=params)
             )
         )
 
--- a/static/dhcp/hosts.js	Sun Feb 10 13:18:21 2013 +0200
+++ b/static/dhcp/hosts.js	Sun Feb 10 13:20:29 2013 +0200
@@ -43,33 +43,20 @@
     return this;
 };
 
-function html (tag, params, html) {
-    return $("<" + tag + " />", $.extend({html: html}, params));
-};
-
-function hosts_realtime (params) {
+/*
+ * Initialize the realtime host table.
+ *
+ *  table       - Table to manipulate
+ *  url         - base URL for ?t=...
+ *  filters     - { attr: value } for ?t=...
+ *  t           - ?t=... to poll for
+ *
+ *  $(document).ready(HostsRealtime(Table(...), ...));
+ *
+ */
+function HostsRealtime (table, params) {
     var t = params.t;
     var refreshTimer = Timer(2 * 1000, refresh);
-    var animate = false; // true;
-
-    function render_host (host) {
-        var columns = [
-            html("td", {}, 
-                html("a", { href: params.host.replace('0', host.id) }, "#" )
-            ),
-        ];
-
-        $.each(params.columns, function (i, name) {
-            column = html("td", { class: name }, host[name]);
-
-            if (name == 'state')
-                column.addClass(host['state_class']);
-
-            columns.push(column);
-        });
-
-        return html("tr", {id: host.id}, columns);
-    }
 
     // XXX: refresh > interval?
     function refresh () {
@@ -88,27 +75,12 @@
             console.log("refresh: " + t + " -> " + t1 + ": " + hosts.length);
 
             $.each(hosts, function (i, host) {
-                var item = $('#' + host.id);
-
-                if (item.length) {
-                    if (animate) item.slideUp();
-                } else {
-                    item = render_host(host)
-
-                    if (animate) item.hide();
-                }
-                
-                // move to top
-                item.prependTo($('#hosts tbody'));
-
-                if (animate)
-                    item.slideDown();
-                else
-                    item.effect("highlight", {}, 'slow');
+                table.update(host);
             });
             
             // update
             t = t1;
+
         }).error(function () {
             alert("Error :("); 
 
@@ -123,9 +95,6 @@
 
     return function () {
         // init
-        if (animate)
-            $("#hosts").css('display', 'block');
-
         $("#refresh").click(function () {
             // in case diabled on error
             refreshTimer.enable();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/static/dhcp/table.js	Sun Feb 10 13:20:29 2013 +0200
@@ -0,0 +1,70 @@
+/*
+ * Dynamic pvl.verkko.table frontend.
+ */
+function html (tag, params, html) {
+    return $("<" + tag + " />", $.extend({html: html}, params));
+};
+
+/*
+ *  item_url    - base URL path to /items/0 by id=0
+ *  columns     - [ column_name ]
+ *  animate     - attempt to animate table..
+ */
+function Table (table, params) {
+    var tbody = table.children('tbody');
+    var animate = params.animate || false;
+
+    if (animate)
+        table.css('display', 'block');
+
+    /*
+     * Render <tr> for item.
+     */
+    function render_tr (item) {
+        var columns = [
+            html("th", {}, 
+                html("a", { href: params.item_url.replace('0', item.id) }, "#" )
+            ),
+        ];
+
+        $.each(params.columns, function (i, column) {
+            var col = item[column];
+            var td = html("td", { title: col.title }, col.html);
+
+            $.each(col.css, function (i, css) {
+                td.addClass(css);
+            });
+
+            columns.push(td);
+        });
+
+        return html("tr", { id: item.id }, columns);
+    }
+        
+    return {
+        animate:    animate,
+
+        /*
+         * Update given item into our <table>
+         */
+        update: function (item) {
+            var tr = $('#' + item.id);
+
+            if (tr.length) {
+                if (animate) tr.slideUp();
+            } else {
+                tr = render_tr(item)
+
+                if (animate) tr.hide();
+            }
+            
+            // move to top
+            tr.prependTo(tbody);
+
+            if (animate)
+                tr.slideDown();
+            else
+                tr.effect("highlight", {}, 'slow');
+        }
+    }
+};