fix requirements transitive dependencies, and increase require.js timeout for use on slow links; switch to async page loading, much better on slow links; catch the errors in datatables if we get out of sync, and stop the stale refreshes which caused it to get out of sync; finally fade details pane when it shows stale information, unfade when it becomes current
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-ui/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-ui/commit/59889aee Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-ui/tree/59889aee Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-ui/diff/59889aee Branch: refs/heads/0.6.0 Commit: 59889aeea10d1e19b4cb634822246daf12f182b4 Parents: 98bc439 Author: Alex Heneveld <[email protected]> Authored: Fri Sep 13 13:18:13 2013 +0100 Committer: Alex Heneveld <[email protected]> Committed: Fri Sep 13 13:58:47 2013 +0100 ---------------------------------------------------------------------- usage/jsgui/src/main/dev/info.txt | 3 -- usage/jsgui/src/main/webapp/assets/js/config.js | 12 ++++- usage/jsgui/src/main/webapp/assets/js/router.js | 2 + .../assets/js/view/application-add-wizard.js | 2 +- .../webapp/assets/js/view/application-tree.js | 8 ++- .../webapp/assets/js/view/entity-activities.js | 13 +++-- .../main/webapp/assets/js/view/entity-config.js | 6 ++- .../webapp/assets/js/view/entity-effectors.js | 15 ++++-- .../webapp/assets/js/view/entity-policies.js | 14 ++++- .../webapp/assets/js/view/entity-sensors.js | 5 +- .../src/main/webapp/assets/js/view/viewutils.js | 57 ++++++++++++++++++-- 11 files changed, 115 insertions(+), 22 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/59889aee/usage/jsgui/src/main/dev/info.txt ---------------------------------------------------------------------- diff --git a/usage/jsgui/src/main/dev/info.txt b/usage/jsgui/src/main/dev/info.txt index 628cf3d..b8b4af9 100644 --- a/usage/jsgui/src/main/dev/info.txt +++ b/usage/jsgui/src/main/dev/info.txt @@ -13,6 +13,3 @@ To use non-minimised JS during dev/test/debug install the non-minimised versions But be careful not to git commit the non-minimised js! - - - http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/59889aee/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 5c03a18..79a0314 100644 --- a/usage/jsgui/src/main/webapp/assets/js/config.js +++ b/usage/jsgui/src/main/webapp/assets/js/config.js @@ -2,6 +2,9 @@ * set the require.js configuration for your application */ require.config({ + /* Give 30s (default is 7s) in case it's a very poor slow network */ + waitSeconds:30, + /* Libraries */ baseUrl:"assets/js", paths:{ @@ -25,6 +28,7 @@ require.config({ "text":"libs/text", "tpl":"../tpl" }, + shim:{ "underscore":{ exports:"_" @@ -38,7 +42,13 @@ require.config({ }, "datatables-extensions":{ deps:[ "jquery", "jquery-datatables" ] - } + }, + "jquery-form": { deps: [ "jquery" ] }, + "jquery-slideto": { deps: [ "jquery" ] }, + "jquery-wiggle": { deps: [ "jquery" ] }, + "jquery-ba-bbq": { deps: [ "jquery" ] }, + "handlebars": { deps: [ "jquery" ] }, + "bootstrap": { deps: [ "jquery" ] /* http://stackoverflow.com/questions/9227406/bootstrap-typeerror-undefined-is-not-a-function-has-no-method-tab-when-us */ } } }); http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/59889aee/usage/jsgui/src/main/webapp/assets/js/router.js ---------------------------------------------------------------------- diff --git a/usage/jsgui/src/main/webapp/assets/js/router.js b/usage/jsgui/src/main/webapp/assets/js/router.js index 7a3e4b2..9cc76e0 100644 --- a/usage/jsgui/src/main/webapp/assets/js/router.js +++ b/usage/jsgui/src/main/webapp/assets/js/router.js @@ -11,6 +11,7 @@ define([ // see "close" called below in "showView") Backbone.View.prototype.close = function () { // call user defined close method if exists + this.viewIsClosed = true if (this.beforeClose) { this.beforeClose() } @@ -20,6 +21,7 @@ define([ this.remove() this.unbind() } + Backbone.View.prototype.viewIsClosed = false /** * Registers a callback (cf setInterval) that is unregistered cleanly when the view http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/59889aee/usage/jsgui/src/main/webapp/assets/js/view/application-add-wizard.js ---------------------------------------------------------------------- diff --git a/usage/jsgui/src/main/webapp/assets/js/view/application-add-wizard.js b/usage/jsgui/src/main/webapp/assets/js/view/application-add-wizard.js index 3ba8974..09667d6 100644 --- a/usage/jsgui/src/main/webapp/assets/js/view/application-add-wizard.js +++ b/usage/jsgui/src/main/webapp/assets/js/view/application-add-wizard.js @@ -414,7 +414,7 @@ define([ updateForState: function () { var that = this this.renderName() - this.locations.fetch({async:false, + this.locations.fetch({async:true, success:function () { if (that.model.spec.get("locations").length==0) that.addLocation() http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/59889aee/usage/jsgui/src/main/webapp/assets/js/view/application-tree.js ---------------------------------------------------------------------- diff --git a/usage/jsgui/src/main/webapp/assets/js/view/application-tree.js b/usage/jsgui/src/main/webapp/assets/js/view/application-tree.js index a3bed41..ea5851f 100644 --- a/usage/jsgui/src/main/webapp/assets/js/view/application-tree.js +++ b/usage/jsgui/src/main/webapp/assets/js/view/application-tree.js @@ -151,8 +151,13 @@ define([ app.url = "/v1/applications/" + appName entitySummary.url = "/v1/applications/" + appName + "/entities/" + id; + // in case the server response time is low, fade out while it refreshes + // (since we can't show updated details until we've retrieved app + entity details) + $("div#details").fadeTo(1000, 0.3) + $.when(app.fetch(), entitySummary.fetch()) .done(function() { + $("div#details").stop().fadeTo(200, 1) that.showDetails(app, entitySummary); }) .fail(entityLoadFailed); @@ -179,8 +184,9 @@ define([ this.detailsView.close() } } - if (this.detailsView) + if (this.detailsView) { this.detailsView.close() + } this.detailsView = new EntityDetailsView({ model:entitySummary, application:app http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/59889aee/usage/jsgui/src/main/webapp/assets/js/view/entity-activities.js ---------------------------------------------------------------------- diff --git a/usage/jsgui/src/main/webapp/assets/js/view/entity-activities.js b/usage/jsgui/src/main/webapp/assets/js/view/entity-activities.js index f65314e..4c4f327 100644 --- a/usage/jsgui/src/main/webapp/assets/js/view/entity-activities.js +++ b/usage/jsgui/src/main/webapp/assets/js/view/entity-activities.js @@ -28,7 +28,7 @@ define([ initialize:function () { this.$el.html(this.template({ })); this.$('#activities-root').html(_.template(ActivityTableHtml)) - $.ajaxSetup({ async:false }); + $.ajaxSetup({ async:true }); var that = this, $table = that.$('#activities-root .activity-table'); that.collection.url = that.model.getLinkByName("activities"); @@ -52,7 +52,8 @@ define([ ViewUtils.addAutoRefreshButton(that.table); ViewUtils.addRefreshButton(that.table); - that.collection.on("reset", that.render, that); + ViewUtils.fadeToIndicateInitialLoad($table); + that.collection.on("reset", that.renderOnLoad, that); that.callPeriodically("entity-activities", function () { if (that.refreshActive) that.collection.fetch({reset: true}); @@ -67,7 +68,11 @@ define([ return this; }, beforeClose:function () { - this.collection.off("reset", this.render); + this.collection.off("reset", this.renderOnLoad); + }, + renderOnLoad: function() { + this.render(); + ViewUtils.cancelFadeOnceLoaded(this.table); }, toggleAutoRefresh:function () { ViewUtils.toggleAutoRefresh(this); @@ -81,7 +86,7 @@ define([ }, updateActivitiesNow: function() { var that = this; - if (this.table == null || this.collection.length==0) { + if (this.table == null || this.collection.length==0 || this.viewIsClosed) { // nothing to do } else { var topLevelTasks = [] http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/59889aee/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 59a411c..89a6fe6 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 @@ -20,7 +20,7 @@ define([ }, initialize:function () { this.$el.html(this.template({ })); - $.ajaxSetup({ async:false }); + $.ajaxSetup({ async:true }); var that = this, $table = this.$('#config-table'); that.table = ViewUtils.myDataTable($table, { @@ -120,7 +120,11 @@ define([ updateConfigNow:function (that) { var url = that.model.getConfigUpdateUrl(), $table = that.$('#config-table'); + if (that.viewIsClosed) { + return + } $.get(url, function (data) { + if (that.viewIsClosed) return ViewUtils.updateMyDataTable($table, data, function(value, name) { var metadata = that.configMetadata[name] if (metadata==null) { http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/59889aee/usage/jsgui/src/main/webapp/assets/js/view/entity-effectors.js ---------------------------------------------------------------------- diff --git a/usage/jsgui/src/main/webapp/assets/js/view/entity-effectors.js b/usage/jsgui/src/main/webapp/assets/js/view/entity-effectors.js index b8f9b93..b5b8569 100644 --- a/usage/jsgui/src/main/webapp/assets/js/view/entity-effectors.js +++ b/usage/jsgui/src/main/webapp/assets/js/view/entity-effectors.js @@ -5,9 +5,9 @@ * @type {*} */ define([ - "underscore", "jquery", "backbone", "model/effector-summary", + "underscore", "jquery", "backbone", "view/viewutils", "model/effector-summary", "view/effector-invoke", "text!tpl/apps/effector.html", "text!tpl/apps/effector-row.html", "bootstrap" -], function (_, $, Backbone, EffectorSummary, EffectorInvokeView, EffectorHtml, EffectorRowHtml) { +], function (_, $, Backbone, ViewUtils, EffectorSummary, EffectorInvokeView, EffectorHtml, EffectorRowHtml) { var EntityEffectorsView = Backbone.View.extend({ template:_.template(EffectorHtml), @@ -21,15 +21,24 @@ define([ this._effectors = new EffectorSummary.Collection() // fetch the list of effectors and create a view for each one this._effectors.url = this.model.getLinkByName("effectors") + that.loadedData = false; + ViewUtils.fadeToIndicateInitialLoad(this.$('#effectors-table')); + this.$(".has-no-effectors").hide(); + this._effectors.fetch({success:function () { + that.loadedData = true; that.render() + ViewUtils.cancelFadeOnceLoaded(that.$('#effectors-table')); }}) }, render:function () { + if (this.viewIsClosed) + return; var that = this var $tableBody = this.$('#effectors-table tbody').empty() if (this._effectors.length==0) { - this.$(".has-no-effectors").show(); + if (that.loadedData) + this.$(".has-no-effectors").show(); } else { this.$(".has-no-effectors").hide(); this._effectors.each(function (effector) { http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/59889aee/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 f2ab825..2b01008 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 @@ -24,11 +24,14 @@ define([ }, initialize:function () { this.$el.html(this.template({ })); - $.ajaxSetup({ async:false }); + $.ajaxSetup({ async:true }); var that = this; // fetch the list of policies and create a view for each one that._policies = new PolicySummary.Collection(); that._policies.url = that.model.getLinkByName("policies"); + + this.loadedData = false; + ViewUtils.fadeToIndicateInitialLoad(this.$('#policies-table')); that.callPeriodically("entity-policies", function() { that.refresh(); }, 3000); @@ -39,15 +42,20 @@ define([ var that = this; that.render(); that._policies.fetch({ success:function () { + that.loadedData = true; that.render(); + ViewUtils.cancelFadeOnceLoaded(that.$('#policies-table')); }}); }, render:function () { + if (this.viewIsClosed) + return; var that = this, $tbody = this.$('#policies-table tbody').empty(); if (that._policies.length==0) { - this.$(".has-no-policies").show(); + if (this.loadedData) + this.$(".has-no-policies").show(); this.$("#policy-config").hide(); this.$("#policy-config-none-selected").hide(); } else { @@ -149,9 +157,11 @@ define([ }, refreshPolicyConfig:function (that) { + if (that.viewIsClosed) return; var $table = that.$('#policy-config-table').dataTable(), $rows = that.$("tr.policy-config-row"); $.get(that.currentStateUrl, function (data) { + if (that.viewIsClosed) return; // iterate over the sensors table and update each sensor $rows.each(function (index, row) { var key = $(this).find(".policy-config-name").text(); http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/59889aee/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 2fee8e0..ea24745 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 @@ -149,9 +149,12 @@ define([ $table = this.$('#sensors-table'), that = this; $.get(url, function (data) { + if (that.viewIsClosed) { + return + } ViewUtils.updateMyDataTable($table, data, function(value, name) { var metadata = that.sensorMetadata[name] - if (metadata==null) { + if (metadata==null) { // TODO should reload metadata when this happens (new sensor for which no metadata known) // (currently if we have dynamic sensors, their metadata won't appear // until the page is refreshed; don't think that's a bit problem -- mainly tooltips http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/59889aee/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 8dc0d96..2c551dd 100644 --- a/usage/jsgui/src/main/webapp/assets/js/view/viewutils.js +++ b/usage/jsgui/src/main/webapp/assets/js/view/viewutils.js @@ -4,6 +4,7 @@ define([ var ViewUtils = { myDataTable:function($table, extra) { + $.fn.dataTableExt.sErrMode = 'throw'; var settings = { "bDestroy": true, "iDisplayLength": 25, @@ -31,6 +32,9 @@ define([ } }; _.extend(settings, extra); + + ViewUtils.fadeToIndicateInitialLoad($table); + return $table.dataTable(settings); }, myDataTableToolbarAddHtml: function($table,html) { @@ -56,7 +60,17 @@ define([ */ updateMyDataTable: function(table, collection, fnConvertData) { if (table==null) return; - var oldDisplayDataList = table.dataTable().fnGetData(); + var oldDisplayDataList = [] + try { + oldDisplayDataList = table.dataTable().fnGetData(); + } catch (e) { + // (used to) sometimes get error acessing column 1 of row 0, though table seems empty + // caused by previous attempt to refresh from a closed view + log("WARNING: could not fetch data; clearing") + log(e) + log(e.stack) + table.dataTable().fnClearTable() + } var oldDisplayIndexMap = {} var oldDisplayData = {} for (var idx in oldDisplayDataList) { @@ -88,8 +102,17 @@ define([ var v = rowProps[idx] if (!_.isEqual(v,oldProps[idx])) { // update individual columns as values change -// log("updating "+v+" in "+prop+"["+idx+"]") - table.fnUpdate( v, Number(prop), idx, false, false ) + try { + table.fnUpdate( v, Number(prop), idx, false, false ) + } catch (e) { + // sometimes get async errors + log("WARNING: cannot update row") + log(e) + log(e.stack) + log(v) + log(prop) + log(idx) + } } else { // log("NO CHANGE") } @@ -104,10 +127,26 @@ define([ // and now add new ones for (var prop in newDisplayData) { // log("adding "+newDisplayData[prop]) - table.fnAddData( newDisplayData[prop] ) + try { + table.fnAddData( newDisplayData[prop] ) + } catch (e) { + // errors sometimes if we load async + log("WARNING: cannot add to row") + log(e) + log(e.stack) + log(prop) + log(newDisplayData[prop]) + } } // table.fnAdjustColumnSizing(); - table.fnStandingRedraw(); + try { + table.fnStandingRedraw(); + } catch (e) { + log("WARNING: could not redraw") + log(e) + log(e.stack) + } + ViewUtils.cancelFadeOnceLoaded(table) }, toggleFilterEmpty: function($table, column) { var hideEmpties = $('.filterEmpty', $table.parent().parent()).toggleClass('icon-eye-open icon-eye-close').hasClass('icon-eye-close'); @@ -186,6 +225,14 @@ define([ // but NB if the html is updated the tooltip can remain visible until page refresh processTooltips: function($el) { $el.find('*[rel="tooltip"]').tooltip(); + }, + fadeToIndicateInitialLoad: function($table) { + // in case the server response time is low, fade out while it refreshes + // (since we can't show updated details until we've retrieved app + entity details) + $table.fadeTo(1000, 0.3); + }, + cancelFadeOnceLoaded: function($table) { + $table.stop().fadeTo(200, 1); } }; return ViewUtils;
