commit/galaxy-central: carlfeberhard: history panel: load display applications via ajax, update on force_history_refresh instead of reloading frame
1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/375abd0dad7e/ Changeset: 375abd0dad7e User: carlfeberhard Date: 2013-04-01 17:10:08 Summary: history panel: load display applications via ajax, update on force_history_refresh instead of reloading frame Affected #: 10 files diff -r 15a5683a73457b6adf81651f32e2d5605c81c0e3 -r 375abd0dad7e9e52c9ca2f94cd37b6da96b4156b lib/galaxy/web/base/controller.py --- a/lib/galaxy/web/base/controller.py +++ b/lib/galaxy/web/base/controller.py @@ -364,8 +364,8 @@ if meta_files: hda_dict[ 'meta_files' ] = meta_files - hda_dict[ 'display_types' ] = self.get_old_display_applications( trans, hda ) - hda_dict[ 'display_apps' ] = self.get_display_apps( trans, hda ) + #hda_dict[ 'display_types' ] = self.get_old_display_applications( trans, hda ) + #hda_dict[ 'display_apps' ] = self.get_display_apps( trans, hda ) hda_dict[ 'visualizations' ] = hda.get_visualizations() # ---- return here if deleted @@ -899,8 +899,6 @@ hda_dicts = [] for hda_tuple in query.all(): hda_dict = dict( zip( column_keys, hda_tuple ) ) - #if hda_dict[ 'job_state' ] not in [ None, 'ok' ]: - # print hda_dict[ 'hid' ], hda_dict[ 'name' ], hda_dict[ 'job_state' ] hda_dict[ 'history_id' ] = history.id trans.security.encode_dict_ids( hda_dict ) hda_dicts.append( hda_dict ) diff -r 15a5683a73457b6adf81651f32e2d5605c81c0e3 -r 375abd0dad7e9e52c9ca2f94cd37b6da96b4156b lib/galaxy/webapps/galaxy/api/history_contents.py --- a/lib/galaxy/webapps/galaxy/api/history_contents.py +++ b/lib/galaxy/webapps/galaxy/api/history_contents.py @@ -55,7 +55,11 @@ if encoded_hda_id in ids: #TODO: share code with show try: - rval.append( self.get_hda_dict( trans, hda ) ) + hda_dict = self.get_hda_dict( trans, hda ) + hda_dict[ 'display_types' ] = self.get_old_display_applications( trans, hda ) + hda_dict[ 'display_apps' ] = self.get_display_apps( trans, hda ) + #rval.append( self.get_hda_dict( trans, hda ) ) + rval.append( hda_dict ) except Exception, exc: # don't fail entire list if hda err's, record and move on diff -r 15a5683a73457b6adf81651f32e2d5605c81c0e3 -r 375abd0dad7e9e52c9ca2f94cd37b6da96b4156b lib/galaxy/webapps/galaxy/controllers/history.py --- a/lib/galaxy/webapps/galaxy/controllers/history.py +++ b/lib/galaxy/webapps/galaxy/controllers/history.py @@ -24,6 +24,7 @@ return history.get_display_name() class HistoryListGrid( grids.Grid ): + # Custom column types class DatasetsByStateColumn( grids.GridColumn, UsesHistoryMixin ): def get_value( self, trans, grid, history ): @@ -56,6 +57,7 @@ elif history.deleted: return "deleted" return "" + def sort( self, trans, query, ascending, column_name=None ): if ascending: query = query.order_by( self.model_class.table.c.purged.asc(), self.model_class.table.c.update_time.desc() ) @@ -63,7 +65,6 @@ query = query.order_by( self.model_class.table.c.purged.desc(), self.model_class.table.c.update_time.desc() ) return query - # Grid definition title = "Saved Histories" model_class = model.History @@ -105,12 +106,15 @@ preserve_state = False use_async = True use_paging = True + def get_current_item( self, trans, **kwargs ): return trans.get_history() + def apply_query_filter( self, trans, query, **kwargs ): return query.filter_by( user=trans.user, importing=False ) class SharedHistoryListGrid( grids.Grid ): + # Custom column types class DatasetsByStateColumn( grids.GridColumn ): def get_value( self, trans, grid, history ): @@ -122,9 +126,11 @@ else: rval.append( '' ) return rval + class SharedByColumn( grids.GridColumn ): def get_value( self, trans, grid, history ): return history.user.email + # Grid definition title = "Histories shared with you by others" model_class = model.History @@ -143,8 +149,10 @@ grids.GridOperation( "Unshare" ) ] standard_filters = [] + def build_initial_query( self, trans, **kwargs ): return trans.sa_session.query( self.model_class ).join( 'users_shared_with' ) + def apply_query_filter( self, trans, query, **kwargs ): return query.filter( model.HistoryUserShareAssociation.user == trans.user ) @@ -172,17 +180,21 @@ key="free-text-search", visible=False, filterable="standard" ) ) operations = [] + def build_initial_query( self, trans, **kwargs ): # Join so that searching history.user makes sense. return trans.sa_session.query( self.model_class ).join( model.User.table ) + def apply_query_filter( self, trans, query, **kwargs ): # A public history is published, has a slug, and is not deleted. return query.filter( self.model_class.published == True ).filter( self.model_class.slug != None ).filter( self.model_class.deleted == False ) -class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesItemRatings, UsesHistoryMixin ): +class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesItemRatings, + UsesHistoryMixin, UsesHistoryDatasetAssociationMixin ): @web.expose def index( self, trans ): return "" + @web.expose def list_as_xml( self, trans ): """XML history list for functional tests""" @@ -282,6 +294,7 @@ trans.sa_session.flush() # Render the list view return self.stored_list_grid( trans, status=status, message=message, **kwargs ) + def _list_delete( self, trans, histories, purge=False ): """Delete histories""" n_deleted = 0 @@ -331,6 +344,7 @@ message_parts.append( "Your active history was deleted, a new empty history is now active. " ) status = INFO return ( status, " ".join( message_parts ) ) + def _list_undelete( self, trans, histories ): """Undelete histories""" n_undeleted = 0 @@ -359,6 +373,7 @@ message_parts.append( "%d histories have already been purged and cannot be undeleted." % n_already_purged ) status = WARNING return status, "".join( message_parts ) + def _list_switch( self, trans, histories ): """Switch to a new different history""" new_history = histories[0] @@ -1062,6 +1077,7 @@ elif history not in histories_for_sharing[ send_to_user ]: histories_for_sharing[ send_to_user ].append( history ) return self._share_histories( trans, user, send_to_err, histories=histories_for_sharing ) + def _get_histories_and_users( self, trans, user, id, email ): if not id: # Default to the current history @@ -1087,6 +1103,7 @@ else: send_to_err += "%s is not a valid Galaxy user. " % email_address return histories, send_to_users, send_to_err + def _populate( self, trans, histories_for_sharing, other, send_to_err ): # This method will populate the histories_for_sharing dictionary with the users and # histories in other, eliminating histories that have already been shared with the @@ -1110,6 +1127,7 @@ elif history not in histories_for_sharing[ send_to_user ]: histories_for_sharing[ send_to_user ].append( history ) return histories_for_sharing, send_to_err + def _populate_restricted( self, trans, user, histories, send_to_users, action, send_to_err, unique=False ): # The user may be attempting to share histories whose datasets cannot all be accessed by other users. # If this is the case, the user sharing the histories can: @@ -1196,6 +1214,7 @@ else: cannot_change[ send_to_user ][ history ].append( hda ) return can_change, cannot_change, no_change_needed, unique_no_change_needed, send_to_err + def _share_histories( self, trans, user, send_to_err, histories={} ): # histories looks like: { userA: [ historyX, historyY ], userB: [ historyY ] } msg = "" @@ -1314,3 +1333,47 @@ def get_item( self, trans, id ): return self.get_history( trans, id ) + + @web.json + def get_display_application_links( self, trans, hda_ids=None ): + """Returns external display application JSON data for all/given + HDAs within the current history. + """ + try: + history = trans.get_history() + #TODO: allow id for more flexibility? (the following doesn't work if anonymous...) + #history = self.get_history( trans, id, check_ownership=True, check_accessible=True, deleted=None ) + if hda_ids: + unencoded_hda_ids = [ trans.security.decode_id( hda_id ) for hda_id in util.listify( hda_ids ) ] + #TODO: this gets all - should narrow query by using hda_ids here - no way with this current method + hdas = self.get_history_datasets( trans, history, show_deleted=False, show_hidden=True, show_purged=False ) + + except Exception, exc: + log.error( 'Error get_display_application_links (%s): %s', hda_ids, str( exc ) ) + trans.response.status = 500 + return str( exc ) + + hda_display_links = [] + for hda in hdas: + # only get requested hdas + if hda_ids and hda.id not in unencoded_hda_ids: + continue + + hda_link_data = { 'id': trans.security.encode_id( hda.id ) } + # don't bail on entire list if one hda has an error; record and move on + try: + # 'old style': must be enabled in config (see universe_wsgi.ini) + if trans.app.config.enable_old_display_applications: + hda_link_data[ 'display_types' ] = self.get_old_display_applications( trans, hda ) + + # 'new style' + hda_link_data[ 'display_apps' ] = self.get_display_apps( trans, hda ) + + except Exception, exc: + log.error( 'Error getting display applications, hda (%s): %s', hda_link_data[ 'id' ], str( exc ) ) + hda_link_data[ 'error' ] = str( exc ) + + hda_display_links.append( hda_link_data ) + + trans.response.set_content_type( 'application/json' ) + return hda_display_links diff -r 15a5683a73457b6adf81651f32e2d5605c81c0e3 -r 375abd0dad7e9e52c9ca2f94cd37b6da96b4156b lib/galaxy/webapps/galaxy/controllers/root.py --- a/lib/galaxy/webapps/galaxy/controllers/root.py +++ b/lib/galaxy/webapps/galaxy/controllers/root.py @@ -98,8 +98,8 @@ @web.expose def history( self, trans, as_xml=False, show_deleted=None, show_hidden=None, hda_id=None, **kwd ): - """ - Display the current history, creating a new history if necessary. + """Display the current history, creating a new history if necessary. + NOTE: No longer accepts "id" or "template" options for security reasons. """ params = util.Params( kwd ) @@ -165,6 +165,7 @@ datasets = hda_dictionaries return trans.stream_template_mako( history_panel_template, + #return trans.fill_template_mako( history_panel_template, history = history, annotation = self.get_item_annotation_str( trans.sa_session, trans.user, history ), datasets = datasets, diff -r 15a5683a73457b6adf81651f32e2d5605c81c0e3 -r 375abd0dad7e9e52c9ca2f94cd37b6da96b4156b static/scripts/mvc/dataset/hda-base.js --- a/static/scripts/mvc/dataset/hda-base.js +++ b/static/scripts/mvc/dataset/hda-base.js @@ -1,6 +1,8 @@ //define([ // "../mvc/base-mvc" //], function(){ + +/* global BaseView, LoggableMixin, HistoryDatasetAssociation, HDABaseView */ //============================================================================== /** @class Read only view for HistoryDatasetAssociation. * @name HDABaseView @@ -44,7 +46,21 @@ this.expanded = attributes.expanded || false; // re-render the entire view on any model change - this.model.bind( 'change', this.render , this ); + //this.model.bind( 'change', this.render , this ); + this.model.bind( 'change', function( event, changed ){ + //var withoutDisplayApps = _.omit( changed, [ 'display_apps', 'display_types' ] ); + var nonDisplayAppChanges = _.without( _.keys( changed.changes ), [ 'display_apps', 'display_types' ] ); + + if( nonDisplayAppChanges.length ){ + this.render(); + + //TODO: need a better handler for these sorts of rendering exceptions + } else { + if( this.expanded ){ + this._render_displayApps(); + } + } + }, this ); //this.bind( 'all', function( event ){ // this.log( event ); @@ -291,28 +307,38 @@ }, // ......................................................................... other elements - /** Render links to external genome display applications (igb, gbrowse, etc.). + /** Render the area for display application links. * @returns {jQuery} rendered DOM */ + _render_displayAppArea : function(){ + return $( '<div/>' ).addClass( 'display-apps' ); + }, + + /** Render links to external genome display applications (igb, gbrowse, etc.). + * @param {jQuery} $parent the jq node to search for .display-apps and render into to (defaults to this.$el) + */ //TODO: not a fan of the style on these - _render_displayApps : function(){ - if( !this.model.hasData() ){ return null; } - - var displayAppsDiv = $( '<div/>' ).addClass( 'display-apps' ); - if( !_.isEmpty( this.model.get( 'display_types' ) ) ){ + _render_displayApps : function( $parent ){ + $parent = $parent || this.$el; + var $displayAppsDiv = $parent.find( 'div.display-apps' ), + display_types = this.model.get( 'display_types' ), + display_apps = this.model.get( 'display_apps' ); + + if( ( !this.model.hasData() ) + || ( !$parent || !$parent.length ) + || ( !$displayAppsDiv.length ) ){ + return; + } + + $displayAppsDiv.html( null ); + if( !_.isEmpty( display_types ) ){ //this.log( this + 'display_types:', this.model.get( 'urls' ).display_types ); - //TODO:?? does this ever get used? - displayAppsDiv.append( - HDABaseView.templates.displayApps({ displayApps : this.model.get( 'display_types' ) }) - ); + $displayAppsDiv.append( HDABaseView.templates.displayApps({ displayApps : display_types }) ); } - if( !_.isEmpty( this.model.get( 'display_apps' ) ) ){ + if( !_.isEmpty( display_apps ) ){ //this.log( this + 'display_apps:', this.model.get( 'urls' ).display_apps ); - displayAppsDiv.append( - HDABaseView.templates.displayApps({ displayApps : this.model.get( 'display_apps' ) }) - ); + $displayAppsDiv.append( HDABaseView.templates.displayApps({ displayApps : display_apps }) ); } - return displayAppsDiv; }, /** Render the data peek. @@ -526,7 +552,8 @@ ])); parent.append( '<div class="clear"/>' ); - parent.append( this._render_displayApps() ); + parent.append( this._render_displayAppArea() ); + this._render_displayApps( parent ); parent.append( this._render_peek() ); }, diff -r 15a5683a73457b6adf81651f32e2d5605c81c0e3 -r 375abd0dad7e9e52c9ca2f94cd37b6da96b4156b static/scripts/mvc/dataset/hda-edit.js --- a/static/scripts/mvc/dataset/hda-edit.js +++ b/static/scripts/mvc/dataset/hda-edit.js @@ -404,6 +404,7 @@ * @see HDABaseView#_render_body_ok */ _render_body_ok : function( parent ){ + //TODO: should call super somehow and insert the needed... // most common state renderer and the most complicated parent.append( this._render_hdaSummary() ); @@ -434,7 +435,8 @@ parent.append( this._render_tagArea() ); parent.append( this._render_annotationArea() ); - parent.append( this._render_displayApps() ); + parent.append( this._render_displayAppArea() ); + this._render_displayApps( parent ); parent.append( this._render_peek() ); }, diff -r 15a5683a73457b6adf81651f32e2d5605c81c0e3 -r 375abd0dad7e9e52c9ca2f94cd37b6da96b4156b static/scripts/mvc/dataset/hda-model.js --- a/static/scripts/mvc/dataset/hda-model.js +++ b/static/scripts/mvc/dataset/hda-model.js @@ -152,9 +152,9 @@ toString : function(){ var nameAndId = this.get( 'id' ) || ''; if( this.get( 'name' ) ){ - nameAndId += ':"' + this.get( 'name' ) + '"'; + nameAndId = this.get( 'hid' ) + ' :"' + this.get( 'name' ) + '",' + nameAndId; } - return 'HistoryDatasetAssociation(' + nameAndId + ')'; + return 'HDA(' + nameAndId + ')'; } }); @@ -300,8 +300,25 @@ return idList; }, + /** Set ea + * Precondition: each data_array object must have an id + * @param {Object[]} data_array an array of attribute objects to update the models with + * @see HistoryDatasetAssociation#set + */ + set : function( data_array ){ + var collection = this; + if( !data_array || !_.isArray( data_array ) ){ return; } + + //TODO: remove when updated backbone >= 1.0 + data_array.forEach( function( hda_data ){ + var model = collection.get( hda_data.id ); + if( model ){ + model.set( hda_data ); + } + }); + }, + /** Update (fetch) the data of the hdas with the given ids. - * @param {String} historyId the id of the history containing this collection * @param {String[]} ids an array of hda ids to update * @returns {HistoryDatasetAssociation[]} hda models that were updated * @see HistoryDatasetAssociation#fetch diff -r 15a5683a73457b6adf81651f32e2d5605c81c0e3 -r 375abd0dad7e9e52c9ca2f94cd37b6da96b4156b static/scripts/mvc/history/history-model.js --- a/static/scripts/mvc/history/history-model.js +++ b/static/scripts/mvc/history/history-model.js @@ -59,6 +59,8 @@ if( _.isArray( initialHdas ) ){ this.hdas.reset( initialHdas ); this.checkForUpdates(); + //TODO: don't call if force_history_refresh + this.updateDisplayApplications(); // handle errors in initialHdas //TODO: errors from the api shouldn't be plain strings... @@ -68,6 +70,18 @@ } } + // 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 ){ + if( hda.get( 'force_history_refresh' ) ){ + //TODO: could poll jobs here... + var history = this; + setTimeout( function(){ + history.stateUpdater(); + }, History.UPDATE_DELAY ); + } + }, this ); + // events //this.on( 'change', function( currModel, changedList ){ // this.log( this + ' has changed:', currModel, changedList ); @@ -290,6 +304,35 @@ history.hdas.trigger( 'add', hdaDataList ); }, + /** Update (from controller) the display application link data of the hdas with the given ids. + * @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 ); + var history = this, + // data = { id: this.get( 'id' ) }; + //if( ids && _.isArray( ids ) ){ data.hda_ids = ids.join( ',' ); } + data = ( ids && _.isArray( ids ) )?({ hda_ids : ids.join( ',' ) }):({}); + + //TODO: hardcoded + history.log( this + ': fetching display application data' ); + jQuery.ajax( 'history/get_display_application_links', { + data : data, + success : function( data, status, xhr ){ + history.hdas.set( data ); + }, + error : function( xhr, status, error ){ + if( !( ( xhr.readyState === 0 ) && ( xhr.status === 0 ) ) ){ + var msg = 'Error fetching display applications, ' + ids + ':' + ( xhr.responseText || error ); + Galaxy.show_modal( 'History panel error', + msg, { 'Ok': function(){ Galaxy.hide_modal(); } }); + this.log( msg ); + } + } + }); + }, + toString : function(){ var nameString = ( this.get( 'name' ) )? ( ',' + this.get( 'name' ) ) : ( '' ); diff -r 15a5683a73457b6adf81651f32e2d5605c81c0e3 -r 375abd0dad7e9e52c9ca2f94cd37b6da96b4156b static/scripts/mvc/history/history-panel.js --- a/static/scripts/mvc/history/history-panel.js +++ b/static/scripts/mvc/history/history-panel.js @@ -126,14 +126,6 @@ } }, this ); - // if an hda moves into the ready state and has the force_history_refresh flag (often via tool.xml) - // then: refresh the panel - this.model.hdas.bind( 'state:ready', function( hda, newState, oldState ){ - if( hda.get( 'force_history_refresh' ) ){ - window.location.reload(); - } - }, this ); - //this.bind( 'all', function(){ // this.log( arguments ); //}, this ); diff -r 15a5683a73457b6adf81651f32e2d5605c81c0e3 -r 375abd0dad7e9e52c9ca2f94cd37b6da96b4156b templates/webapps/galaxy/root/alternate_history.mako --- a/templates/webapps/galaxy/root/alternate_history.mako +++ b/templates/webapps/galaxy/root/alternate_history.mako @@ -285,6 +285,9 @@ top.Galaxy.$rightPanel = top.Galaxy.$rightPanel || $( top.document ).find( 'div#right' ); //modals + top.Galaxy.show_modal = top.show_modal; + top.Galaxy.hide_modal = top.hide_modal; + // other base functions // global backbone models 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.
participants (1)
-
commits-noreply@bitbucket.org