1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/402c90f647b6/ Changeset: 402c90f647b6 User: carlfeberhard Date: 2013-10-08 16:47:43 Summary: History panel: better reconciling of hda states within history and hda collection Affected #: 3 files diff -r c8b55344e779e8be93bae5d66f52128addd83003 -r 402c90f647b678688cba952e8a6a9b4f4b1cb320 static/scripts/mvc/history/history-model.js --- a/static/scripts/mvc/history/history-model.js +++ b/static/scripts/mvc/history/history-model.js @@ -48,7 +48,7 @@ /** HDACollection of the HDAs contained in this history. */ this.hdas = new HDACollection(); - + /** the setTimeout id for any updater currently set */ this.updateTimeoutId = null; // if we've got hdas passed in the constructor, load them and set up updates if needed @@ -57,10 +57,14 @@ this.checkForUpdates(); //TODO: don't call if force_history_refresh if( this.hdas.length > 0 ){ - this.updateDisplayApplications(); + this.fetchDisplayApplications(); } } + this.setHdaEventHandlers(); + this.setOwnEventHandlers(); + }, + setHdaEventHandlers : function(){ // if an hda moves into the ready state and has the force_history_refresh flag (often via tool.xml) // then: refresh the panel this.hdas.bind( 'state:ready', function( hda, newState, oldState ){ @@ -68,7 +72,9 @@ this.updateAfterDelay(); } }, this ); + }, + setOwnEventHandlers : function(){ if( this.logger ){ this.bind( 'all', function( event ){ this.log( this + '', arguments ); @@ -88,84 +94,86 @@ updateAfterDelay : function(){ var history = this; this.updateTimeoutId = setTimeout( function(){ + history.updateTimeoutId = null; history.stateUpdater(); }, History.UPDATE_DELAY ); return this.updateTimeoutId; }, - // get the history's state from it's cummulative ds states, delay + update if needed - // events: ready + isRunning : function(){ + var historyState = this.get( 'state' ); + // set up to keep pulling if this history in run/queue state + //note: the state strings btwn history & hda are shared on the server (or a subset of) + return ( ( historyState === HistoryDatasetAssociation.STATES.RUNNING ) + ||( historyState === HistoryDatasetAssociation.STATES.QUEUED ) ); + }, + + isReady : function(){ + return !this.isRunning(); + }, + checkForUpdates : function(){ - // get overall History state from collection, run updater if History has running/queued hdas - // boiling it down on the client to running/not - if( this.hdas.running().length ){ + // set up to keep pulling if this history in run/queue state + if( this.isRunning() ){ this.updateAfterDelay(); + // otherwise, we're now in a 'ready' state (no hdas running) } else { this.trigger( 'ready' ); } return this; }, - // update this history, find any hda's running/queued, update ONLY those that have changed states, - // set up to run this again in some interval of time + findHdasToUpdate : function(){ + var history = this, + state_ids = history.get( 'state_ids' ), + changedIds = []; + + // get a list of hda ids for hdas we need to get more info on + _.each( state_ids, function( list, stateAccrdToHistory ){ + _.each( list, function( id ){ + var hda = history.hdas.get( id ); + // if the id is not in the current hda list + // or the state doesn't match the state rpt. by the history - save that id + if( !hda || hda.get( 'state' ) !== stateAccrdToHistory ){ + changedIds.push( id ); + } + }); + }); + return changedIds; + }, + + // fetch new data for this history, + // compare the state_ids from that with the current list and fetch updates for new or changed hdas + // if the history still has non-ready hdas, set up to run this again in some interval of time // events: ready stateUpdater : function(){ //TODO: we need to get states from one location: history_contents (right now it's both history and contents) var history = this, oldState = this.get( 'state' ), - // state ids is a map of every possible hda state, each containing a list of ids for hdas in that state - oldStateIds = this.get( 'state_ids' ); + historyXhr = this.fetch(); // pull from the history api - //TODO: fetch? - jQuery.ajax( 'api/histories/' + this.get( 'id' ) - - ).success( function( response ){ + historyXhr.done( function( newHistoryModel ){ //this.log( 'historyApiRequest, response:', response ); - history.set( response ); - history.log( 'current history state:', history.get( 'state' ), - '(was)', oldState, + history.set( newHistoryModel ); + history.log( 'current history state:', history.get( 'state' ), '(was)', oldState, 'new size:', history.get( 'nice_size' ) ); - //TODO: revisit this - seems too elaborate, need something straightforward - // for each state, check for the difference between old dataset states and new - // the goal here is to check ONLY those datasets that have changed states (not all datasets) - var changedIds = []; - _.each( _.keys( response.state_ids ), function( state ){ - var diffIds = _.difference( response.state_ids[ state ], oldStateIds[ state ] ); - // aggregate those changed ids - changedIds = changedIds.concat( diffIds ); - }); - // send the changed ids (if any) to dataset collection to have them fetch their own model changes - if( changedIds.length ){ - history.fetchHdaUpdates( changedIds ) - .done( function(){ - furtherUpdatesOrReady( history ); + var hdaIdsToUpdate = history.findHdasToUpdate(); + if( hdaIdsToUpdate.length ){ + // simplify with empty promise when no ids + history.fetchHdaUpdates( hdaIdsToUpdate ) + .done( function( models ){ + history.checkForUpdates(); }); } else { - furtherUpdatesOrReady( history ); + history.checkForUpdates(); } - function furtherUpdatesOrReady( history ){ - var timeout; - // set up to keep pulling if this history in run/queue state - if( ( history.get( 'state' ) === HistoryDatasetAssociation.STATES.RUNNING ) - || ( history.get( 'state' ) === HistoryDatasetAssociation.STATES.QUEUED ) - || ( history.get( 'state' ) === HistoryDatasetAssociation.STATES.SETTING_METADATA )){ - //|| ( history.hdas.running() ) ){ - timeout = history.updateAfterDelay(); - - // otherwise, we're now in a 'ready' state (no hdas running) - } else { - this.updateTimeoutId = null; - history.trigger( 'ready' ); - } - return timeout; - } - - }).error( function( xhr, status, error ){ + }); + historyXhr.fail( function( xhr, status, error ){ //TODO: use ajax.status handlers here // keep rolling on a bad gateway - server restart if( xhr.status === 502 ){ @@ -197,9 +205,7 @@ xhr = jQuery.ajax({ url : this.url() + '/contents?' + jQuery.param({ ids : hdaIds.join(',') }), - /** - * @inner - */ + /** @inner */ error : function( xhr, status, error ){ if( ( xhr.readyState === 0 ) && ( xhr.status === 0 ) ){ return; } @@ -286,11 +292,10 @@ * @param {String[]} ids an array of hda ids to update (optional, defaults to all hdas) * @returns {HistoryDatasetAssociation[]} hda models that were updated */ - updateDisplayApplications : function( ids ){ - this.log( this + 'updateDisplayApplications:', ids ); + fetchDisplayApplications : function( ids ){ + this.log( this + '.fetchDisplayApplications:', ids ); var history = this, - // data = { id: this.get( 'id' ) }; - //if( ids && _.isArray( ids ) ){ data.hda_ids = ids.join( ',' ); } + // if any ids passed place them in the query string data data = ( ids && _.isArray( ids ) )?({ hda_ids : ids.join( ',' ) }):({}); //TODO: hardcoded diff -r c8b55344e779e8be93bae5d66f52128addd83003 -r 402c90f647b678688cba952e8a6a9b4f4b1cb320 static/scripts/packed/mvc/history/history-model.js --- a/static/scripts/packed/mvc/history/history-model.js +++ b/static/scripts/packed/mvc/history/history-model.js @@ -1,1 +1,1 @@ -var History=Backbone.Model.extend(LoggableMixin).extend({defaults:{id:null,name:"Unnamed History",state:"new",diskSize:0,deleted:false},urlRoot:"api/histories/",url:function(){return this.urlRoot+this.get("id")},initialize:function(b,c,a){a=a||null;this.log(this+".initialize:",b,c);this.hdas=new HDACollection();this.updateTimeoutId=null;if(c&&_.isArray(c)){this.hdas.add(c);this.checkForUpdates();if(this.hdas.length>0){this.updateDisplayApplications()}}this.hdas.bind("state:ready",function(e,f,d){if(e.get("force_history_refresh")){this.updateAfterDelay()}},this);if(this.logger){this.bind("all",function(d){this.log(this+"",arguments)},this)}},hdaIdsFromStateIds:function(){return _.reduce(_.values(this.get("state_ids")),function(b,a){return b.concat(a)})},updateAfterDelay:function(){var a=this;this.updateTimeoutId=setTimeout(function(){a.stateUpdater()},History.UPDATE_DELAY);return this.updateTimeoutId},checkForUpdates:function(){if(this.hdas.running().length){this.updateAfterDelay()}else{this.trigger("ready")}return this},stateUpdater:function(){var c=this,a=this.get("state"),b=this.get("state_ids");jQuery.ajax("api/histories/"+this.get("id")).success(function(d){c.set(d);c.log("current history state:",c.get("state"),"(was)",a,"new size:",c.get("nice_size"));var f=[];_.each(_.keys(d.state_ids),function(h){var g=_.difference(d.state_ids[h],b[h]);f=f.concat(g)});if(f.length){c.fetchHdaUpdates(f).done(function(){e(c)})}else{e(c)}function e(h){var g;if((h.get("state")===HistoryDatasetAssociation.STATES.RUNNING)||(h.get("state")===HistoryDatasetAssociation.STATES.QUEUED)||(h.get("state")===HistoryDatasetAssociation.STATES.SETTING_METADATA)){g=h.updateAfterDelay()}else{this.updateTimeoutId=null;h.trigger("ready")}return g}}).error(function(g,d,e){if(g.status===502){setTimeout(function(){c.log("Bad Gateway error. Retrying...");c.stateUpdater()},History.UPDATE_DELAY)}else{if(!((g.readyState===0)&&(g.status===0))){c.log("stateUpdater error:",e,"responseText:",g.responseText);var f=_l("An error occurred while getting updates from the server.")+" "+_l("Please contact a Galaxy administrator if the problem persists.");c.trigger("error",f,g,d,e)}}})},fetchHdaUpdates:function(c){var a=this,b=jQuery.ajax({url:this.url()+"/contents?"+jQuery.param({ids:c.join(",")}),error:function(i,d,e){if((i.readyState===0)&&(i.status===0)){return}var g=JSON.parse(i.responseText);if(_.isArray(g)){var f=_.groupBy(g,function(j){if(_.has(j,"error")){return"errored"}return"ok"});a.log("fetched, errored datasets:",f.errored);a.updateHdas(g)}else{a.log("Error updating hdas from api history contents",c,i,d,e,g);var h=_l("An error occurred while getting dataset details from the server.")+" "+_l("Please contact a Galaxy administrator if the problem persists.");a.trigger("error",h,i,d,e)}},success:function(e,d,f){a.log(a+".fetchHdaUpdates, success:",d,f);a.updateHdas(e)}});return b},updateHdas:function(a){var c=this,b=[];c.log(c+".updateHdas:",a);_.each(a,function(e,f){var d=c.hdas.get(e.id);if(d){c.log("found existing model in list for id "+e.id+", updating...:");d.set(e)}else{c.log("NO existing model for id "+e.id+", creating...:");b.push(e)}});if(b.length){c.addHdas(b)}},addHdas:function(a){var b=this;_.each(a,function(c,d){var e=b.hdas.hidToCollectionIndex(c.hid);c.history_id=b.get("id");b.hdas.add(new HistoryDatasetAssociation(c),{at:e,silent:true})});b.hdas.trigger("add",a)},updateDisplayApplications:function(a){this.log(this+"updateDisplayApplications:",a);var c=this,b=(a&&_.isArray(a))?({hda_ids:a.join(",")}):({});c.log(this+": fetching display application data");jQuery.ajax("history/get_display_application_links",{data:b,success:function(f,d,e){_.each(f,function(h){var g=c.hdas.get(h.id);if(g){g.set(h)}})},error:function(g,d,e){if(!((g.readyState===0)&&(g.status===0))){c.log("Error fetching display applications:",a,g,d,e);var f=_l("An error occurred while getting display applications from the server.")+" "+_l("Please contact a Galaxy administrator if the problem persists.");c.trigger("error",f,g,d,e)}}})},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});History.UPDATE_DELAY=4000;var HistoryCollection=Backbone.Collection.extend(LoggableMixin).extend({model:History,urlRoot:"api/histories"}); \ No newline at end of file +var History=Backbone.Model.extend(LoggableMixin).extend({defaults:{id:null,name:"Unnamed History",state:"new",diskSize:0,deleted:false},urlRoot:"api/histories/",url:function(){return this.urlRoot+this.get("id")},initialize:function(b,c,a){a=a||null;this.log(this+".initialize:",b,c);this.hdas=new HDACollection();this.updateTimeoutId=null;if(c&&_.isArray(c)){this.hdas.add(c);this.checkForUpdates();if(this.hdas.length>0){this.fetchDisplayApplications()}}this.setHdaEventHandlers();this.setOwnEventHandlers()},setHdaEventHandlers:function(){this.hdas.bind("state:ready",function(b,c,a){if(b.get("force_history_refresh")){this.updateAfterDelay()}},this)},setOwnEventHandlers:function(){if(this.logger){this.bind("all",function(a){this.log(this+"",arguments)},this)}},hdaIdsFromStateIds:function(){return _.reduce(_.values(this.get("state_ids")),function(b,a){return b.concat(a)})},updateAfterDelay:function(){var a=this;this.updateTimeoutId=setTimeout(function(){a.updateTimeoutId=null;a.stateUpdater()},History.UPDATE_DELAY);return this.updateTimeoutId},isRunning:function(){var a=this.get("state");return((a===HistoryDatasetAssociation.STATES.RUNNING)||(a===HistoryDatasetAssociation.STATES.QUEUED))},isReady:function(){return !this.isRunning()},checkForUpdates:function(){if(this.isRunning()){this.updateAfterDelay()}else{this.trigger("ready")}return this},findHdasToUpdate:function(){var c=this,a=c.get("state_ids"),b=[];_.each(a,function(d,e){_.each(d,function(g){var f=c.hdas.get(g);if(!f||f.get("state")!==e){b.push(g)}})});return b},stateUpdater:function(){var c=this,a=this.get("state"),b=this.fetch();b.done(function(d){c.set(d);c.log("current history state:",c.get("state"),"(was)",a,"new size:",c.get("nice_size"));var e=c.findHdasToUpdate();if(e.length){c.fetchHdaUpdates(e).done(function(f){c.checkForUpdates()})}else{c.checkForUpdates()}});b.fail(function(g,d,e){if(g.status===502){setTimeout(function(){c.log("Bad Gateway error. Retrying...");c.stateUpdater()},History.UPDATE_DELAY)}else{if(!((g.readyState===0)&&(g.status===0))){c.log("stateUpdater error:",e,"responseText:",g.responseText);var f=_l("An error occurred while getting updates from the server.")+" "+_l("Please contact a Galaxy administrator if the problem persists.");c.trigger("error",f,g,d,e)}}})},fetchHdaUpdates:function(c){var a=this,b=jQuery.ajax({url:this.url()+"/contents?"+jQuery.param({ids:c.join(",")}),error:function(i,d,e){if((i.readyState===0)&&(i.status===0)){return}var g=JSON.parse(i.responseText);if(_.isArray(g)){var f=_.groupBy(g,function(j){if(_.has(j,"error")){return"errored"}return"ok"});a.log("fetched, errored datasets:",f.errored);a.updateHdas(g)}else{a.log("Error updating hdas from api history contents",c,i,d,e,g);var h=_l("An error occurred while getting dataset details from the server.")+" "+_l("Please contact a Galaxy administrator if the problem persists.");a.trigger("error",h,i,d,e)}},success:function(e,d,f){a.log(a+".fetchHdaUpdates, success:",d,f);a.updateHdas(e)}});return b},updateHdas:function(a){var c=this,b=[];c.log(c+".updateHdas:",a);_.each(a,function(e,f){var d=c.hdas.get(e.id);if(d){c.log("found existing model in list for id "+e.id+", updating...:");d.set(e)}else{c.log("NO existing model for id "+e.id+", creating...:");b.push(e)}});if(b.length){c.addHdas(b)}},addHdas:function(a){var b=this;_.each(a,function(c,d){var e=b.hdas.hidToCollectionIndex(c.hid);c.history_id=b.get("id");b.hdas.add(new HistoryDatasetAssociation(c),{at:e,silent:true})});b.hdas.trigger("add",a)},fetchDisplayApplications:function(a){this.log(this+".fetchDisplayApplications:",a);var c=this,b=(a&&_.isArray(a))?({hda_ids:a.join(",")}):({});c.log(this+": fetching display application data");jQuery.ajax("history/get_display_application_links",{data:b,success:function(f,d,e){_.each(f,function(h){var g=c.hdas.get(h.id);if(g){g.set(h)}})},error:function(g,d,e){if(!((g.readyState===0)&&(g.status===0))){c.log("Error fetching display applications:",a,g,d,e);var f=_l("An error occurred while getting display applications from the server.")+" "+_l("Please contact a Galaxy administrator if the problem persists.");c.trigger("error",f,g,d,e)}}})},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});History.UPDATE_DELAY=4000;var HistoryCollection=Backbone.Collection.extend(LoggableMixin).extend({model:History,urlRoot:"api/histories"}); \ No newline at end of file diff -r c8b55344e779e8be93bae5d66f52128addd83003 -r 402c90f647b678688cba952e8a6a9b4f4b1cb320 templates/webapps/galaxy/root/history.mako --- a/templates/webapps/galaxy/root/history.mako +++ b/templates/webapps/galaxy/root/history.mako @@ -198,8 +198,11 @@ // 2. from console: new PersistentStorage( '__history_panel' ).set( 'debugging', true ) // -> history panel and hdas will display console logs in console var debugging = false; - if( jQuery.jStorage.get( '__history_panel' ) ){ + if( sessionStorage.getItem( '__history_panel' ) ){ debugging = new PersistentStorage( '__history_panel' ).get( 'debugging' ); + if( debugging ){ + console.debug( '(debugging)' ); + } } // get the current user (either from the top frame's Galaxy or if in tab via the bootstrap) Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.