You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2016/02/01 18:52:10 UTC

[37/50] [abbrv] brooklyn-ui git commit: Added filter for non-empty keys and polished up JS formatting, including fixing policy refresh Allow table updates without resetting current place in pagination state for all tabs

Added filter for non-empty keys and polished up JS formatting, including fixing policy refresh
Allow table updates without resetting current place in pagination state for all tabs


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-ui/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-ui/commit/ae337df7
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-ui/tree/ae337df7
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-ui/diff/ae337df7

Branch: refs/heads/0.5.0
Commit: ae337df78cbbc82645eb5de312fe7160a3d9fd88
Parents: bd8e9aa
Author: Andrew Kennedy <an...@cloudsoftcorp.com>
Authored: Tue Feb 19 16:29:33 2013 +0000
Committer: Andrew Kennedy <an...@cloudsoftcorp.com>
Committed: Thu Feb 28 13:13:32 2013 +0000

----------------------------------------------------------------------
 usage/jsgui/src/main/webapp/assets/js/config.js |  29 ++-
 .../js/libs/dataTables.fnStandingRedraw.js      |  16 ++
 .../main/webapp/assets/js/view/entity-config.js |  75 +++---
 .../webapp/assets/js/view/entity-policies.js    | 244 ++++++++++---------
 .../webapp/assets/js/view/entity-sensors.js     |  57 +++--
 .../assets/js/view/policy-config-invoke.js      |  38 +--
 .../src/main/webapp/assets/js/view/viewutils.js |  83 +++----
 .../main/webapp/assets/tpl/apps/activities.html |   2 +-
 .../src/main/webapp/assets/tpl/apps/config.html |   2 +-
 .../main/webapp/assets/tpl/apps/effector.html   |   2 +-
 .../assets/tpl/apps/policy-config-modal.html    |  10 +-
 .../src/main/webapp/assets/tpl/apps/policy.html |   6 +-
 .../main/webapp/assets/tpl/apps/sensors.html    |   2 +-
 usage/jsgui/src/test/javascript/config.txt      |  18 +-
 14 files changed, 311 insertions(+), 273 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/main/webapp/assets/js/config.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/config.js b/usage/jsgui/src/main/webapp/assets/js/config.js
index e9fe7bc..57f7e70 100644
--- a/usage/jsgui/src/main/webapp/assets/js/config.js
+++ b/usage/jsgui/src/main/webapp/assets/js/config.js
@@ -1,44 +1,47 @@
-// set the require.js configuration for your application
+/*
+ * set the require.js configuration for your application
+ */
 require.config({
 
+    /* Libraries */
     baseUrl:"assets/js",
-
     paths:{
-        // libraries
         "jquery":"libs/jquery",
         "underscore":"libs/underscore",
         "backbone":"libs/backbone",
         "bootstrap":"libs/bootstrap",
         "formatJson":"libs/json-formatter",
         "jquery-form":"libs/jquery.form",
-        "tablesorter":"libs/jquery.dataTables",
+        "jquery-datatables":"libs/jquery.dataTables",
         "async":"libs/async",
         "jquery-slideto":"libs/jquery.slideto.min",
         "jquery-wiggle":"libs/jquery.wiggle.min",
         "jquery-ba-bbq":"libs/jquery.ba-bbq.min",
         "handlebars":"libs/handlebars-1.0.rc.1",
         "brooklyn-utils":"libs/brooklyn-utils",
-
+        "datatables-fnstandingredraw":"libs/dataTables.fnStandingRedraw",
         "googlemaps":"view/googlemaps",
         "text":"libs/text",
         "tpl":"../tpl"
     },
-
     shim:{
-        underscore:{
+        "underscore":{
             exports:"_"
         },
-        formatJson:{
+        "formatJson":{
             exports:"FormatJSON"
         },
-        backbone:{
-            deps:[ "underscore", "jquery"],
+        "backbone":{
+            deps:[ "underscore", "jquery" ],
             exports:"Backbone"
+        },
+        "datatables-fnstandingredraw":{
+            deps:[ "jquery", "jquery-datatables" ]
         }
     }
-})
+});
 
-/**
+/*
  * Main application entry point.
  */
 require([
@@ -46,4 +49,4 @@ require([
 ], function (Backbone, Router) {
     var router = new Router();
     Backbone.history.start();
-})
+});

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/main/webapp/assets/js/libs/dataTables.fnStandingRedraw.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/libs/dataTables.fnStandingRedraw.js b/usage/jsgui/src/main/webapp/assets/js/libs/dataTables.fnStandingRedraw.js
new file mode 100644
index 0000000..cbd8191
--- /dev/null
+++ b/usage/jsgui/src/main/webapp/assets/js/libs/dataTables.fnStandingRedraw.js
@@ -0,0 +1,16 @@
+/*
+ * jQuery DataTables fnStandingRedraw plug-in.
+ *
+ * http://www.datatables.net/plug-ins/api#fnStandingRedraw
+ */
+$.fn.dataTableExt.oApi.fnStandingRedraw = function(oSettings) {
+    if (oSettings.oFeatures.bServerSide === false) {
+        var before = oSettings._iDisplayStart;
+        oSettings.oApi._fnReDraw(oSettings);
+        // iDisplayStart has been reset to zero - so lets change it back
+        oSettings._iDisplayStart = before;
+        oSettings.oApi._fnCalculateEnd(oSettings);
+    }
+    // draw the 'current' page
+    oSettings.oApi._fnDraw(oSettings);
+};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/main/webapp/assets/js/view/entity-config.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/view/entity-config.js b/usage/jsgui/src/main/webapp/assets/js/view/entity-config.js
index 0a79bc8..394ef6a 100644
--- a/usage/jsgui/src/main/webapp/assets/js/view/entity-config.js
+++ b/usage/jsgui/src/main/webapp/assets/js/view/entity-config.js
@@ -4,8 +4,9 @@
  * @type {*}
  */
 define([
-    "underscore", "jquery", "backbone", "view/viewutils", "model/config-summary", "text!tpl/apps/config.html",
-    "text!tpl/apps/config-row.html", "tablesorter"
+    "underscore", "jquery", "backbone",
+    "view/viewutils", "model/config-summary", "text!tpl/apps/config.html", "text!tpl/apps/config-row.html",
+    "jquery-datatables", "datatables-fnstandingredraw"
 ], function (_, $, Backbone, ViewUtils, ConfigSummary, ConfigHtml, ConfigRowHtml) {
 
     var EntityConfigView = Backbone.View.extend({
@@ -16,33 +17,34 @@ define([
             'click .filterEmpty':'toggleFilterEmpty'
         },
         initialize:function () {
-            this.$el.html(this.template({}));
+        	this.$el.html(this.template({ }));
+            $.ajaxSetup({ async:false });
             var that = this,
                 configCollection = new ConfigSummary.Collection,
-                $table = $('#config-table'),
-                $tableBody = $('tbody').empty();
-            ViewUtils.myDataTable($table);
-            configCollection.url = this.model.getLinkByName('config');
-            var success = function () {
+                $table = this.$('#config-table'),
+                $tbody = this.$('tbody').empty();
+            configCollection.url = that.model.getLinkByName('config');
+            configCollection.fetch({ success:function () {
                 configCollection.each(function (config) {
-                    $tableBody.append(that.configTemplate({
+                    $tbody.append(that.configTemplate({
                         name:config.get("name"),
                         description:config.get("description"),
-                        value:'',
+                        value:'', // will be set later
                         type:config.get("type")
                     }));
                 });
-                that.updateConfigPeriodically();
-                // TODO tooltip doesn't work on 'i' elements in table (bottom left toolbar)
-                $table.find('*[rel="tooltip"]').tooltip();
-            };
-            configCollection.fetch({ async:false, success:success });
-            this.toggleFilterEmpty();
+                $tbody.find('*[rel="tooltip"]').tooltip();
+                that.updateConfigPeriodically(that);
+                ViewUtils.myDataTable($table);
+                $table.dataTable().fnAdjustColumnSizing();
+            }});
+            that.toggleFilterEmpty();
         },
         render:function () {
-            return this
+            this.updateConfigNow(this);
+            return this;
         },
-        toggleFilterEmpty: function() {
+        toggleFilterEmpty:function () {
             ViewUtils.toggleFilterEmpty(this.$('#config-table'), 1);
         },
         refreshConfig:function () {
@@ -51,24 +53,27 @@ define([
         // register a callback to update the sensors
         updateConfigPeriodically:function (that) {
             var self = this;
-            that.updateConfigNow(that)
-            that.callPeriodically("entity-config", function() { self.updateConfigNow(that) }, 3000)
+            that.updateConfigNow(that);
+            that.callPeriodically("entity-config", function() {
+                self.updateConfigNow(that);
+            }, 3000);
         },
         updateConfigNow:function (that) {
             // NB: this won't add new dynamic config
-            var $table = this.$('#config-table');
             var url = that.model.getConfigUpdateUrl(),
-            $rows = that.$("tr.config-row")
-                $.get(url, function (data) {
-                    // iterate over the config table and update each value
-                    $rows.each(function (index,row) {
-                        var key = $(this).find(".config-name").text()
-                        var v = data[key]
-                        if (v === undefined) v = ''
-                        $table.dataTable().fnUpdate(_.escape(v), row, 1)
-                    })
-                })
-            }
-        })
-    return EntityConfigView
-})
+                $table = that.$('#config-table'),
+                $rows = that.$("tr.config-row");
+            $.get(url, function (data) {
+                // iterate over the config table and update each value
+                $rows.each(function (index, row) {
+                    var key = $(this).find(".config-name").text();
+                    var v = data[key];
+                    if (v === undefined) v = '';
+                    $table.dataTable().fnUpdate(_.escape(v), row, 1, false);
+                });
+            });
+            $table.dataTable().fnStandingRedraw();
+        }
+    });
+    return EntityConfigView;
+});

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/main/webapp/assets/js/view/entity-policies.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/view/entity-policies.js b/usage/jsgui/src/main/webapp/assets/js/view/entity-policies.js
index b41e9de..e126b6b 100644
--- a/usage/jsgui/src/main/webapp/assets/js/view/entity-policies.js
+++ b/usage/jsgui/src/main/webapp/assets/js/view/entity-policies.js
@@ -5,28 +5,17 @@
  * @type {*}
  */
 define([
-            "underscore", "jquery", "backbone",
-            "model/policy-summary",
-            "model/policy-config-summary",
-            "view/policy-config-invoke",
-            "text!tpl/apps/policy.html",
-            "text!tpl/apps/policy-row.html",
-            "text!tpl/apps/policy-config-row.html",
-            "bootstrap"
-], function (
-                _, $, Backbone,
-                PolicySummary,
-                PolicyConfigSummary,
-                PolicyConfigInvokeView,
-                PolicyHtml,
-                PolicyRowHtml,
-                PolicyConfigRowHtml
-        ) {
+    "underscore", "jquery", "backbone",
+    "model/policy-summary", "model/policy-config-summary", "view/viewutils", "view/policy-config-invoke", "text!tpl/apps/policy.html", "text!tpl/apps/policy-row.html", "text!tpl/apps/policy-config-row.html",
+    "jquery-datatables", "datatables-fnstandingredraw"
+], function (_, $, Backbone, PolicySummary, PolicyConfigSummary, ViewUtils, PolicyConfigInvokeView, PolicyHtml, PolicyRowHtml, PolicyConfigRowHtml) {
 
     var EntityPoliciesView = Backbone.View.extend({
         template:_.template(PolicyHtml),
         policyRow:_.template(PolicyRowHtml),
         events:{
+            'click .refresh':'refreshPolicyConfigNow',
+            'click .filterEmpty':'toggleFilterEmpty',
             "click #policies-table tr":"rowClick",
             "click .policy-start":"callStart",
             "click .policy-stop":"callStop",
@@ -34,141 +23,154 @@ define([
             "click .show-policy-config-modal":"showPolicyConfigModal",
         },
         initialize:function () {
-            this.$el.html(this.template({}))
-            var that = this
-            this._policies = new PolicySummary.Collection()
+            this.$el.html(this.template({ }));
+            $.ajaxSetup({ async:false });
+            var that = this;
             // fetch the list of policies and create a view for each one
-            this._policies.url = this.model.getLinkByName("policies")
-            this.refresh()
+            that._policies = new PolicySummary.Collection();
+            that._policies.url = that.model.getLinkByName("policies");
+            that.render();
+            that.callPeriodically("entity-policies", function() {
+                that.refresh();
+            }, 3000);
         },
-        refresh: function() {
-            var that = this
-            this._policies.fetch({success:function () {
-                that.render()
-            }})
+        refresh:function() {
+            var that = this;
+            that._policies.fetch({ success:function () {
+                that.render();
+            }});
         },
         render:function () {
             var that = this,
-                $tbody = this.$('#policies-table tbody').empty()
-            if (this._policies.length==0) {
-                this.$(".has-no-policies").show();
-                this.$("#policy-config").hide()
-                this.$("#policy-config-none-selected").hide()
+                $tbody = $('#policies-table tbody').empty();
+            if (that._policies.length==0) {
+                $(".has-no-policies").show();
+                $("#policy-config").hide();
+                $("#policy-config-none-selected").hide();
             } else {
-                this.$(".has-no-policies").hide();
-                this._policies.each(function (policy) {
+                $(".has-no-policies").hide();
+                that._policies.each(function (policy) {
                     $tbody.append(that.policyRow({
                         cid:policy.get("id"),
                         name:policy.get("name"),
                         state:policy.get("state"),
                         summary:policy
-                    }))
-                if (that.activePolicy) {
-                    $("#policies-table tr[id='"+that.activePolicy+"']").addClass("selected")
-                    that.showPolicyConfig(that.activePolicy)
-                } else {
-                    this.$("#policy-config").hide()
-                    this.$("#policy-config-none-selected").show()
-                }
-            })
+                    }));
+                    if (that.activePolicy) {
+                        $("#policies-table tr[id='"+that.activePolicy+"']").addClass("selected");
+                        that.showPolicyConfig(that.activePolicy);
+                        that.refreshPolicyConfig(that);
+                    } else {
+                        $("#policy-config").hide();
+                        $("#policy-config-none-selected").show();
+                    }
+                });
             }
-            return this
+            return that;
+        },
+        toggleFilterEmpty:function() {
+            ViewUtils.toggleFilterEmpty($('#policy-config-table'), 2);
         },
-        rowClick: function(evt) {
-            var row = $(evt.currentTarget).closest("tr")
-            var id = row.attr("id")
-            $("#policies-table tr").removeClass("selected")
+        refreshPolicyConfigNow:function () {
+            this.refreshPolicyConfig(this);  
+        },
+        rowClick:function(evt) {
+            var row = $(evt.currentTarget).closest("tr"),
+                id = row.attr("id"),
+                policy = this._policies.get(id);
+            $("#policies-table tr").removeClass("selected");
             if (this.activePolicy == id) {
                 // deselected
-                this.activePolicy = null
-                this.$("#policy-config").hide(100)
-                this.$("#policy-config-none-selected").show(100)
+            	this.activePolicy = null;
+                this._config = null;
+                $("#policy-config-table").dataTable().fnDestroy();
+                $("#policy-config").hide(100);
+                $("#policy-config-none-selected").show(100);
             } else {
-                row.addClass("selected")
-                var that = this
-                this.activePolicy = id
+                row.addClass("selected");
+                var that = this;
                 // fetch the list of policy config entries
-                var policy = this._policies.get(id)
-                this._config = new PolicyConfigSummary.Collection()
-                this._config.url = policy.getLinkByName("config")
-                this._config.fetch({success:function () {
-                    that.showPolicyConfig()
-                }})
+                that._config = new PolicyConfigSummary.Collection();
+                that._config.url = policy.getLinkByName("config");
+                that._config.fetch({ success:function () {
+                    that.showPolicyConfig(id);
+                }});
             }
         },
-        showPolicyConfig:function () {
-            var that = this
-            this.$("#policy-config-none-selected").hide(100)
-            var $tc = this.$('#policy-config-table tbody').empty()
-            if (this._config.length==0) {
-                this.$(".has-no-policy-config").show();
-            } else {
-                this.$(".has-no-policy-config").hide();
-                var policyConfigRow = _.template(PolicyConfigRowHtml)
-                this._config.each(function (config) {
-                    $tc.append(policyConfigRow({
-                        cid:config.cid,
-                        name:config.get("name"),
-                        description:config.get("description"),
-                        type:config.get("type"),
-                        reconfigurable:config.get("reconfigurable"),
-                        link:config.getLinkByName('self'),
-                        value:"" // config.get("defaultValue"), /* will be re-set later */
-                    }))
-                    // TODO tooltip doesn't work on 'i' elements in table (bottom left toolbar)
-                    $tc.find('*[rel="tooltip"]').tooltip()
-                })
+        showPolicyConfig:function (activePolicyId) {
+            var that = this;
+            if (activePolicyId != null && that.activePolicy != activePolicyId) {
+                var $table = $('#policy-config-table'),
+                    $tbody = $('#policy-config-table tbody').empty();
+                $("#policy-config-none-selected").hide(100);
+                if (that._config.length==0) {
+                    $(".has-no-policy-config").show();
+                } else {
+                    $(".has-no-policy-config").hide();
+                    that.activePolicy = activePolicyId;
+                    var policyConfigRow = _.template(PolicyConfigRowHtml);
+                    that._config.each(function (config) {
+                        $tbody.append(policyConfigRow({
+                            cid:config.cid,
+                            name:config.get("name"),
+                            description:config.get("description"),
+                            type:config.get("type"),
+                            reconfigurable:config.get("reconfigurable"),
+                            link:config.getLinkByName('self'),
+                            value:'' // will be set later
+                        }));
+                        $tbody.find('*[rel="tooltip"]').tooltip();
+                    });
+                    that.currentStateUrl = that._policies.get(that.activePolicy).getLinkByName("config") + "/current-state";
+                    $("#policy-config").show(100);
+                    $table.show(100);
+                    ViewUtils.myDataTable($table);
+                    $table.dataTable().fnAdjustColumnSizing();
+                }
             }
-            this.$("#policy-config").show(100)
-            this.$("#policy-config-table").dataTable().show(100)
-            var currentStateUrl = this._policies.get(that.activePolicy).getLinkByName("config") + "/current-state"
-            that.refreshPolicyConfig(currentStateUrl)
-            this.callPeriodically("entity-policy-config", function() {
-                that.refreshPolicyConfig(currentStateUrl)
-            }, 3000)
+            that.refreshPolicyConfig(that);
+            that.callPeriodically("entity-policy-config", function() {
+                that.refreshPolicyConfig(that);
+            }, 3000);
         },
-        refreshPolicyConfig:function (currentStateUrl) {
-            var that = this,
-                $table = that.$('#policy-config-table'),
-                $rows = that.$("tr.policy-config-row")
-            $.get(currentStateUrl, function (data) {
-                    // iterate over the sensors table and update each sensor
-                    $rows.each(function (index, row) {
-                        var key = $(this).find(".policy-config-name").text()
-                        var v = data[key]
-                        if (v === undefined) v = ""
-                        $table.dataTable().fnUpdate(_.escape(v), row, 1)
-                        that._config.at(index).set("value", v)
-                    })
-                })
+        refreshPolicyConfig:function (that) {
+            var $table = that.$('#policy-config-table').dataTable(),
+                $rows = that.$("tr.policy-config-row");
+            $.get(that.currentStateUrl, function (data) {
+                // iterate over the sensors table and update each sensor
+                $rows.each(function (index, row) {
+                    var key = $(this).find(".policy-config-name").text();
+                    var v = data[key];
+                    if (v === undefined) v = "";
+                    $table.fnUpdate(_.escape(v), row, 1, false);
+                });
+            });
+            $table.dataTable().fnStandingRedraw();
         },
         showPolicyConfigModal:function (evt) {
             // get the model that we need to show, create its view and show it
-            var cid = $(evt.currentTarget).attr("id")
+            var cid = $(evt.currentTarget).attr("id");
             this._modal = new PolicyConfigInvokeView({
                 el:"#policy-config-modal",
                 model:this._config.getByCid(cid),
                 policy:this.model,
-            })
-            var a = this._modal.render()
-            a.$el.show()
-            a.$el.modal('show')
+            });
+            this._modal.render().$el.modal('show');
         },
-        callStart:function(event) { this.doPost(event, "start") },
-        callStop:function(event) { this.doPost(event, "stop") },
-        callDestroy:function(event) { this.doPost(event, "destroy") },
+        callStart:function(event) { this.doPost(event, "start"); },
+        callStop:function(event) { this.doPost(event, "stop"); },
+        callDestroy:function(event) { this.doPost(event, "destroy"); },
         doPost:function(event, linkname) {
-            var that = this
-            var url = $(event.currentTarget).attr("link");
-            // trigger the event by ajax with attached parameters
+            var that = this,
+                url = $(event.currentTarget).attr("link");
             $.ajax({
                 type:"POST",
                 url:url,
-                success: function() {
-                    that.refresh()
-                }})
+                success:function() {
+                    that.refresh();
+                }
+            });
         }
-    })
-
-    return EntityPoliciesView
-})
\ No newline at end of file
+    });
+    return EntityPoliciesView;
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/main/webapp/assets/js/view/entity-sensors.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/view/entity-sensors.js b/usage/jsgui/src/main/webapp/assets/js/view/entity-sensors.js
index 044c10c..91ee9e2 100644
--- a/usage/jsgui/src/main/webapp/assets/js/view/entity-sensors.js
+++ b/usage/jsgui/src/main/webapp/assets/js/view/entity-sensors.js
@@ -4,8 +4,9 @@
  * @type {*}
  */
 define([
-    "underscore", "jquery", "backbone", "view/viewutils", "model/sensor-summary", "text!tpl/apps/sensors.html",
-    "text!tpl/apps/sensor-row.html", "tablesorter", "brooklyn-utils"
+    "underscore", "jquery", "backbone",
+    "view/viewutils", "model/sensor-summary", "text!tpl/apps/sensors.html", "text!tpl/apps/sensor-row.html",
+    "jquery-datatables", "datatables-fnstandingredraw"
 ], function (_, $, Backbone, ViewUtils, SensorSummary, SensorsHtml, SensorRowHtml) {
 
     var EntitySensorsView = Backbone.View.extend({
@@ -17,13 +18,13 @@ define([
         },
         initialize:function () {
             this.$el.html(this.template({ }));
+            $.ajaxSetup({ async:false });
             var that = this,
                 sensorsCollection = new SensorSummary.Collection,
-                $table = $('#sensors-table'),
-                $tableBody = $('tbody').empty();
-            ViewUtils.myDataTable($table);
+                $table = this.$('#sensors-table'),
+                $tbody = this.$('tbody').empty();
             sensorsCollection.url = that.model.getLinkByName('sensors');
-            var success = function () {
+            sensorsCollection.fetch({ success:function () {
                 sensorsCollection.each(function (sensor) {
                     var actions = {};
                     _.each(sensor.get("links"), function(v,k) {
@@ -31,52 +32,54 @@ define([
                             actions[k.slice(7)] = v;
                         }
                     });
-                    $tableBody.append(that.sensorTemplate({
+                    $tbody.append(that.sensorTemplate({
                         name:sensor.get("name"),
                         description:sensor.get("description"),
                         actions:actions,
                         type:sensor.get("type"),
-                        value:'' /* will be set later */
+                        value:'' // will be set later
                     }));
                 });
+                $tbody.find('*[rel="tooltip"]').tooltip();
                 that.updateSensorsPeriodically(that);
-                // TODO tooltip doesn't work on 'i' elements in table (bottom left toolbar)
-                $table.find('*[rel="tooltip"]').tooltip();
-            };
-            sensorsCollection.fetch({ async:false, success:success });
-            this.toggleFilterEmpty();
+                ViewUtils.myDataTable($table);
+                $table.dataTable().fnAdjustColumnSizing();
+            }});
+            that.toggleFilterEmpty();
         },
         render:function () {
+            this.updateSensorsNow(this);
             return this;
         },
-        toggleFilterEmpty:function() {
-            ViewUtils.toggleFilterEmpty($('#sensors-table'), 2);
+        toggleFilterEmpty:function () {
+            ViewUtils.toggleFilterEmpty(this.$('#sensors-table'), 2);
         },
         refreshSensors:function () {
             this.updateSensorsNow(this);  
         },
         // register a callback to update the sensors
         updateSensorsPeriodically:function (that) {
-            var that = this;
+            var self = this;
             that.updateSensorsNow(that);
             that.callPeriodically("entity-sensors", function() {
-                that.updateSensorsNow(that);
+                self.updateSensorsNow(that);
             }, 3000);
         },
         updateSensorsNow:function (that) {
             // NB: this won't add new dynamic sensors
-            var $table = this.$('#sensors-table');
             var url = that.model.getSensorUpdateUrl(),
-                $rows = that.$("tr.sensor-row")
+                $table = that.$('#sensors-table'),
+                $rows = that.$("tr.sensor-row");
             $.get(url, function (data) {
-                    // iterate over the sensors table and update each sensor
-                    $rows.each(function (index,row) {
-                        var key = $(this).find(".sensor-name").text()
-                        var v = data[key]
-                        if (v === undefined) v = ''
-                        $table.dataTable().fnUpdate(_.escape(v), row, 2)
-                    })
-                })
+                // iterate over the sensors table and update each sensor
+                $rows.each(function (index, row) {
+                    var key = $(this).find(".sensor-name").text();
+                    var v = data[key];
+                    if (v === undefined) v = '';
+                    $table.dataTable().fnUpdate(_.escape(v), row, 2, false);
+                });
+            });
+            $table.dataTable().fnStandingRedraw();
         }
     });
     return EntitySensorsView;

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/main/webapp/assets/js/view/policy-config-invoke.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/view/policy-config-invoke.js b/usage/jsgui/src/main/webapp/assets/js/view/policy-config-invoke.js
index be38f67..b1c40b9 100644
--- a/usage/jsgui/src/main/webapp/assets/js/view/policy-config-invoke.js
+++ b/usage/jsgui/src/main/webapp/assets/js/view/policy-config-invoke.js
@@ -1,5 +1,5 @@
 /**
- * Render a policy configuration key as a modal.
+ * Render a policy configuration key as a modal for reconfiguring.
  */
 define([
     "underscore", "jquery", "backbone", "text!tpl/apps/policy-config-modal.html", "bootstrap"
@@ -13,43 +13,43 @@ define([
         },
         render:function () {
             var that = this,
-            	configUrl = this.model.getLinkByName("self")
+                configUrl = that.model.getLinkByName("self");
             $.get(configUrl, function (data) { 
-            	that.$el.html(that.template({
+                that.$el.html(that.template({
                     name:that.model.get("name"),
                     description:that.model.get("description"),
                     type:that.model.get("type"),
                     value:data,
                     policyName:that.options.policy.get("name"),
-                }))
-            })
-            return this
+                }));
+            });
+            that.model = this.model;
+            return that;
         },
-        unfade: function() {
+        unfade:function() {
             this.$el.fadeTo(500,1);
         },
         savePolicyConfig:function () {
             var that = this,
-                url = this.model.getLinkByName("self") + "/set",
-                val = this.$("#policy-config-value").val()
-            this.$el.fadeTo(500,0.5);
+                url = that.model.getLinkByName("self") + "/set",
+                val = that.$("#policy-config-value").val();
+            that.$el.fadeTo(500,0.5);
             $.ajax({
                 type:"POST",
                 url:url+"?value="+val,
                 success:function (data) {
-                    that.$el.modal("hide")
+                    that.$el.modal("hide");
                     that.$el.fadeTo(500,1);
                 },
                 error:function(data) {
                     that.$el.fadeTo(100,1).delay(200).fadeTo(200,0.2).delay(200).fadeTo(200,1);
                     // TODO render the error better than poor-man's flashing
-                    // (would just be connection error -- with timeout=0 we get a task even for invalid input)
-                    log("ERROR setting config")
-                    log(data)
-                }})
+                    log("ERROR setting config");
+                    log(data);
+                }});
             // un-delegate events
-            this.undelegateEvents()
+            that.undelegateEvents();
         }
-    })
-    return PolicyConfigInvokeView
-})
+    });
+    return PolicyConfigInvokeView;
+});

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/main/webapp/assets/js/view/viewutils.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/view/viewutils.js b/usage/jsgui/src/main/webapp/assets/js/view/viewutils.js
index 7572ffd..8b879f7 100644
--- a/usage/jsgui/src/main/webapp/assets/js/view/viewutils.js
+++ b/usage/jsgui/src/main/webapp/assets/js/view/viewutils.js
@@ -1,15 +1,15 @@
 define([
         "underscore", "jquery", "backbone"
-        ], function (_, $, Backbone) {
+], function (_, $, Backbone) {
 
     var ViewUtils = {
-
         myDataTable:function($table) {
             $table.dataTable({
+                "bDestroy": true,
                 "iDisplayLength": 25,
                 "sPaginationType": "full_numbers",
-                "sDom":"f<'brook-db-top-toolbar'>t<'brook-db-bot-toolbar'>ilp",
-                "oLanguage":{
+                "sDom": "f<'brook-db-top-toolbar'>t<'brook-db-bot-toolbar'>ilp",
+                "oLanguage": {
                     "sSearch": "",
                     "sInfo": "_START_ - _END_ of _TOTAL_ ",
                     "sInfoEmpty": "<i>No data</i> ",
@@ -22,68 +22,69 @@ define([
                         "sLast": "&gt;&gt;"
                     },
                     "sInfoFiltered": "(of _MAX_)",
-                    "sLengthMenu":'( <select>' +
-                    '<option value="25">25</option>' +
-                    '<option value="50">50</option>' +
-                    '<option value="-1">all</option>' +
-                    '</select> / page )'
+                    "sLengthMenu": '( <select>' +
+                                        '<option value="25">25</option>' +
+                                        '<option value="50">50</option>' +
+                                        '<option value="-1">all</option>' +
+                                    '</select> / page )'
                 }
-            })
+            });
             $('.brook-db-bot-toolbar', $table.parent().parent()).html(
-                    '<i class="refresh icon-refresh handy" rel="tooltip" title="Reload immediately."></i>'+'&nbsp;&nbsp;'+
+                    '<i class="refresh icon-refresh handy" rel="tooltip" title="Reload immediately."></i>' +
+                    '&nbsp;&nbsp;' +
                     '<i class="filterEmpty icon-eye-open handy" rel="tooltip" title="Show/hide empty records"></i>'
             );
         },
         toggleFilterEmpty: function($table, column) {
-            var hideEmpties = $('.filterEmpty', $table.parent().parent()).
-                toggleClass('icon-eye-open icon-eye-close').hasClass('icon-eye-close')
-            if (hideEmpties) $table.dataTable().fnFilter('.+', column, true);
-            else $table.dataTable().fnFilter('.*', column, true);
+            var hideEmpties = $('.filterEmpty', $table.parent().parent()).toggleClass('icon-eye-open icon-eye-close').hasClass('icon-eye-close');
+            if (hideEmpties) {
+                $table.dataTable().fnFilter('.+', column, true);
+            } else {
+                $table.dataTable().fnFilter('.*', column, true);
+            }
         },
 
         attachToggler: function($scope) {
             var $togglers;
-            if ($scope === undefined) $togglers = $(".toggler-header")
-            else $togglers = $(".toggler-header", $scope);
-            $togglers.click(this.onTogglerClick)
+            if ($scope === undefined) {
+                $togglers = $(".toggler-header");
+            } else {
+                $togglers = $(".toggler-header", $scope);
+            }
+            $togglers.click(this.onTogglerClick);
         },
         onTogglerClick: function(event) {
             var root = $(event.currentTarget).closest(".toggler-header");
             root.toggleClass("user-hidden");
-            $(".toggler-icon", root).
-                toggleClass("icon-chevron-left").
-                toggleClass("icon-chevron-down");
-                
+            $(".toggler-icon", root).toggleClass("icon-chevron-left").toggleClass("icon-chevron-down");
             var next = root.next();
-            if (root.hasClass("user-hidden")) 
+            if (root.hasClass("user-hidden")) {
                 next.hide('fast');
-            else 
-                next.show('fast')
+            } else {
+                next.show('fast');
+            }
         },
-        
         updateTextareaWithData: function($div, data, alwaysShow, minPx, maxPx) {
-            var $ta = $("textarea", $div)
-            var show = alwaysShow
+            var $ta = $("textarea", $div);
+            var show = alwaysShow;
             if (data !== undefined) {
-                $ta.val(data)
-                show = true
+                $ta.val(data);
+                show = true;
             } else {
-                $ta.val("")
+                $ta.val("");
             }
             if (show) {
-                $div.show(100)
+                $div.show(100);
                 $ta.css("height", minPx);
                 // scrollHeight prop works sometimes (e.g. groovy page) but not others (e.g. summary)
-                var height = $ta.prop("scrollHeight")
-                height = Math.min(height, maxPx)
-                height = Math.max(height, minPx)
+                var height = $ta.prop("scrollHeight");
+                height = Math.min(height, maxPx);
+                height = Math.max(height, minPx);
                 $ta.css("height", height);
             } else {
-                $div.hide()
+                $div.hide();
             }
         }
-
-    }
-    
-    return ViewUtils
-})
\ No newline at end of file
+    };
+    return ViewUtils;
+});

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/main/webapp/assets/tpl/apps/activities.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/apps/activities.html b/usage/jsgui/src/main/webapp/assets/tpl/apps/activities.html
index d894035..a854421 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/apps/activities.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/apps/activities.html
@@ -1,4 +1,4 @@
-<table id="activities-table" class="table table-striped table-condensed nonDatatables">
+<table id="activities-table" class="table table-striped table-condensed nonDatatables" style="width: 100%;">
     <thead>
     <tr>
         <th width="40%">Task</th>

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/main/webapp/assets/tpl/apps/config.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/apps/config.html b/usage/jsgui/src/main/webapp/assets/tpl/apps/config.html
index be79099..7c47018 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/apps/config.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/apps/config.html
@@ -1,4 +1,4 @@
-<table id="config-table">
+<table id="config-table" style="width: 554px;">
     <thead>
     <tr>
         <th>Name</th>

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/main/webapp/assets/tpl/apps/effector.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/apps/effector.html b/usage/jsgui/src/main/webapp/assets/tpl/apps/effector.html
index a4bed9d..33d8821 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/apps/effector.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/apps/effector.html
@@ -1,4 +1,4 @@
-<table id="effectors-table" class="table table-striped table-condensed nonDatatables">
+<table id="effectors-table" class="table table-striped table-condensed nonDatatables" style="width: 100%;">
     <thead>
     <tr>
         <th>Name</th>

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/main/webapp/assets/tpl/apps/policy-config-modal.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/apps/policy-config-modal.html b/usage/jsgui/src/main/webapp/assets/tpl/apps/policy-config-modal.html
index 1e70918..325da72 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/apps/policy-config-modal.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/apps/policy-config-modal.html
@@ -2,12 +2,16 @@
 
 <div class="modal-header">
     <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
-    <h3><%= policyName %> <%= name %></h3>
-
-    <p><%= description %></p>
+    <h3>Reconfigure <%= policyName %></h3>
 </div>
 
 <div class="modal-body">
+    <p>
+        <strong>Update the value for <%= name %></strong>
+    </p>
+    <p>
+        <%= description %>
+    </p>
     <input id="policy-config-value" type="text" class="input-medium" name="value" value="<%= value %>">
 </div>
 

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/main/webapp/assets/tpl/apps/policy.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/apps/policy.html b/usage/jsgui/src/main/webapp/assets/tpl/apps/policy.html
index a294f0d..f100da7 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/apps/policy.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/apps/policy.html
@@ -1,4 +1,4 @@
-<table id="policies-table" class="table table-striped table-condensed nonDatatables">
+<table id="policies-table" class="table table-striped table-condensed nonDatatables" style="width: 100%;">
     <thead>
     <tr>
         <th width="50%">Name</th>
@@ -12,8 +12,8 @@
     <i>No policies currently attached to this entity</i>
 </div>
 
-<div id="policy-config">
-    <table id="policy-config-table" class="table table-striped table-condensed nonDatatables">
+<div id="policy-config" class="hide">
+    <table id="policy-config-table" style="width: 554px;">
         <thead>
         <tr>
             <th width="35%">Name</th>

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/main/webapp/assets/tpl/apps/sensors.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/apps/sensors.html b/usage/jsgui/src/main/webapp/assets/tpl/apps/sensors.html
index 4477901..845adb4 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/apps/sensors.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/apps/sensors.html
@@ -1,4 +1,4 @@
-<table id="sensors-table">
+<table id="sensors-table" style="width: 554px;">
     <thead>
     <tr>
         <th>Name</th>

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/ae337df7/usage/jsgui/src/test/javascript/config.txt
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/test/javascript/config.txt b/usage/jsgui/src/test/javascript/config.txt
index a7aaf6d..de97031 100644
--- a/usage/jsgui/src/test/javascript/config.txt
+++ b/usage/jsgui/src/test/javascript/config.txt
@@ -1,32 +1,36 @@
+
+    /* Libraries */
     paths:{
-        // libraries
         "jquery":"js/libs/jquery",
         "underscore":"js/libs/underscore",
         "backbone":"js/libs/backbone",
         "bootstrap":"js/libs/bootstrap",
         "formatJson":"js/libs/json-formatter",
         "jquery-form":"js/libs/jquery.form",
-        "tablesorter":"js/libs/jquery.dataTables",
+        "jquery-datatables":"js/libs/jquery.dataTables",
         "jquery-slideto":"js/libs/jquery.slideto.min",
         "jquery-wiggle":"js/libs/jquery.wiggle.min",
         "jquery-ba-bbq":"js/libs/jquery.ba-bbq.min",
         "handlebars":"js/libs/handlebars-1.0.rc.1",
         "brooklyn-utils":"js/libs/brooklyn-utils",
+        "datatables-fnstandingredraw":"js/libs/dataTables.fnStandingRedraw",
         "text":"js/libs/text",
         "model":"js/model",
         "view":"js/view",
         "router":"js/router"
     },
-
     shim:{
-        underscore:{
+        "underscore":{
             exports:"_"
         },
-        formatJson:{
+        "formatJson":{
             exports:"FormatJSON"
         },
-        backbone:{
-            deps:[ "underscore", "jquery"],
+        "backbone":{
+            deps:[ "underscore", "jquery" ],
             exports:"Backbone"
+        },
+        "datatables-fnstandingredraw":{
+            deps:[ "jquery", "jquery-datatables" ]
         }
     }