1 new changeset in galaxy-central: http://bitbucket.org/galaxy/galaxy-central/changeset/70e2b1c95a69/ changeset: 70e2b1c95a69 user: natefoo date: 2011-06-14 18:43:42 summary: Disk space usage accounting: Users can see how much disk a history is consuming. Disk used is also a column on the history grid. Users can also forcibly purge a dataset from their history. Included is a script (scripts/set_dataset_sizes.py) which will set the value of the new total_size column on the dataset table (includes the contents of the extra_files_path and metadata files). affected #: 15 files (10.4 KB) --- a/lib/galaxy/jobs/__init__.py Tue Jun 14 10:29:42 2011 -0400 +++ b/lib/galaxy/jobs/__init__.py Tue Jun 14 12:43:42 2011 -0400 @@ -630,6 +630,10 @@ tool=self.tool, stdout=stdout, stderr=stderr ) job.command_line = self.command_line + # Once datasets are collected, set the total dataset size (includes extra files) + for dataset_assoc in job.output_datasets + job.output_library_datasets: + dataset_assoc.dataset.dataset.set_total_size() + # fix permissions for path in [ dp.real_path for dp in self.get_output_fnames() ]: util.umask_fix_perms( path, self.app.config.umask, 0666, self.app.config.gid ) --- a/lib/galaxy/model/__init__.py Tue Jun 14 10:29:42 2011 -0400 +++ b/lib/galaxy/model/__init__.py Tue Jun 14 12:43:42 2011 -0400 @@ -15,7 +15,10 @@ from galaxy.web.form_builder import * from galaxy.model.item_attrs import UsesAnnotations, APIItem from sqlalchemy.orm import object_session -import os.path, os, errno, codecs, operator, socket, pexpect, logging, time +import os.path, os, errno, codecs, operator, socket, pexpect, logging, time, shutil + +if sys.version_info[:2] < ( 2, 5 ): + from sets import Set as set log = logging.getLogger( __name__ ) @@ -402,6 +405,15 @@ if isinstance(history_name, str): history_name = unicode(history_name, 'utf-8') return history_name + @property + def get_disk_size_bytes( self ): + return self.get_disk_size( nice_size=False ) + def get_disk_size( self, nice_size=False ): + # unique datasets only + rval = sum( [ d.get_total_size() for d in list( set( [ hda.dataset for hda in self.datasets if not hda.purged ] ) ) if not d.purged ] ) + if nice_size: + rval = galaxy.datatypes.data.nice_size( rval ) + return rval class HistoryUserShareAssociation( object ): def __init__( self ): @@ -569,6 +581,22 @@ self.file_size = os.path.getsize( self.file_name ) except OSError: self.file_size = 0 + def get_total_size( self ): + if self.total_size is not None: + return self.total_size + if self.file_size: + # for backwards compatibility, set if unset + self.set_total_size() + db_session = object_session( self ) + db_session.flush() + return self.total_size + return 0 + def set_total_size( self ): + if self.file_size is None: + self.set_size() + self.total_size = self.file_size or 0 + for root, dirs, files in os.walk( self.extra_files_path ): + self.total_size += sum( [ os.path.getsize( os.path.join( root, file ) ) for file in files ] ) def has_data( self ): """Detects whether there is any data""" return self.get_size() > 0 @@ -588,6 +616,19 @@ os.remove(self.data.file_name) except OSError, e: log.critical('%s delete error %s' % (self.__class__.__name__, e)) + @property + def user_can_purge( self ): + return self.purged == False \ + and not bool( self.library_associations ) \ + and len( self.history_associations ) == len( self.purged_history_associations ) + def full_delete( self ): + """Remove the file and extra files, marks deleted and purged""" + os.unlink( self.file_name ) + if os.path.exists( self.extra_files_path ): + shutil.rmtree( self.extra_files_path ) + # TODO: purge metadata files + self.deleted = True + self.purged = True def get_access_roles( self, trans ): roles = [] for dp in self.actions: --- a/lib/galaxy/model/mapping.py Tue Jun 14 10:29:42 2011 -0400 +++ b/lib/galaxy/model/mapping.py Tue Jun 14 12:43:42 2011 -0400 @@ -117,6 +117,7 @@ Column( "parent_id", Integer, ForeignKey( "history_dataset_association.id" ), nullable=True ), Column( "designation", TrimmedString( 255 ) ), Column( "deleted", Boolean, index=True, default=False ), + Column( "purged", Boolean, index=True, default=False ), Column( "visible", Boolean ) ) Dataset.table = Table( "dataset", metadata, @@ -129,7 +130,8 @@ Column( "purgable", Boolean, default=True ), Column( "external_filename" , TEXT ), Column( "_extra_files_path", TEXT ), - Column( 'file_size', Numeric( 15, 0 ) ) ) + Column( 'file_size', Numeric( 15, 0 ) ), + Column( 'total_size', Numeric( 15, 0 ) ) ) HistoryDatasetAssociationDisplayAtAuthorization.table = Table( "history_dataset_association_display_at_authorization", metadata, Column( "id", Integer, primary_key=True ), @@ -1132,7 +1134,10 @@ primaryjoin=( Dataset.table.c.id == HistoryDatasetAssociation.table.c.dataset_id ) ), active_history_associations=relation( HistoryDatasetAssociation, - primaryjoin=( ( Dataset.table.c.id == HistoryDatasetAssociation.table.c.dataset_id ) & ( HistoryDatasetAssociation.table.c.deleted == False ) ) ), + primaryjoin=( ( Dataset.table.c.id == HistoryDatasetAssociation.table.c.dataset_id ) & ( HistoryDatasetAssociation.table.c.deleted == False ) & ( HistoryDatasetAssociation.table.c.purged == False ) ) ), + purged_history_associations=relation( + HistoryDatasetAssociation, + primaryjoin=( ( Dataset.table.c.id == HistoryDatasetAssociation.table.c.dataset_id ) & ( HistoryDatasetAssociation.table.c.purged == True ) ) ), library_associations=relation( LibraryDatasetDatasetAssociation, primaryjoin=( Dataset.table.c.id == LibraryDatasetDatasetAssociation.table.c.dataset_id ) ), --- a/lib/galaxy/web/base/controller.py Tue Jun 14 10:29:42 2011 -0400 +++ b/lib/galaxy/web/base/controller.py Tue Jun 14 12:43:42 2011 -0400 @@ -252,16 +252,18 @@ error( "History not found" ) else: return self.security_check( trans.get_user(), history, check_ownership, check_accessible ) - def get_history_datasets( self, trans, history, show_deleted=False, show_hidden=False): + def get_history_datasets( self, trans, history, show_deleted=False, show_hidden=False, show_purged=False ): """ Returns history's datasets. """ query = trans.sa_session.query( trans.model.HistoryDatasetAssociation ) \ .filter( trans.model.HistoryDatasetAssociation.history == history ) \ .options( eagerload( "children" ) ) \ - .join( "dataset" ).filter( trans.model.Dataset.purged == False ) \ + .join( "dataset" ) \ .options( eagerload_all( "dataset.actions" ) ) \ .order_by( trans.model.HistoryDatasetAssociation.hid ) if not show_deleted: query = query.filter( trans.model.HistoryDatasetAssociation.deleted == False ) + if not show_purged: + query = query.filter( trans.model.Dataset.purged == False ) return query.all() class UsesFormDefinitions: --- a/lib/galaxy/web/controllers/dataset.py Tue Jun 14 10:29:42 2011 -0400 +++ b/lib/galaxy/web/controllers/dataset.py Tue Jun 14 12:43:42 2011 -0400 @@ -694,26 +694,69 @@ return True return False + def _purge( self, trans, id ): + try: + id = int( id ) + except ValueError, e: + return False + hda = trans.sa_session.query( self.app.model.HistoryDatasetAssociation ).get( id ) + # Invalid HDA or not deleted + if not hda or not hda.history or not hda.deleted: + return False + # If the user is anonymous, make sure the HDA is owned by the current session. + if not hda.history.user and trans.galaxy_session.id not in [ s.id for s in hda.history.galaxy_sessions ]: + return False + # If the user is known, make sure the HDA is owned by the current user. + if hda.history.user and hda.history.user != trans.user: + return False + # HDA is purgeable + hda.purged = True + trans.sa_session.add( hda ) + trans.log_event( "HDA id %s has been purged" % hda.id ) + # Don't delete anything if there are active HDAs or any LDDAs, even if + # the LDDAs are deleted. Let the cleanup scripts get it in the latter + # case. + if hda.dataset.user_can_purge: + try: + hda.dataset.full_delete() + trans.log_event( "Dataset id %s has been purged upon the the purge of HDA id %s" % ( hda.dataset.id, hda.id ) ) + trans.sa_session.add( hda.dataset ) + except: + log.exception( 'Unable to purge dataset (%s) on purge of hda (%s):' % ( hda.dataset.id, hda.id ) ) + trans.sa_session.flush() + return True + @web.expose def undelete( self, trans, id ): if self._undelete( trans, id ): return trans.response.send_redirect( web.url_for( controller='root', action='history', show_deleted = True ) ) - raise "Error undeleting" + raise Exception( "Error undeleting" ) @web.expose def unhide( self, trans, id ): if self._unhide( trans, id ): return trans.response.send_redirect( web.url_for( controller='root', action='history', show_hidden = True ) ) - raise "Error unhiding" - + raise Exception( "Error unhiding" ) @web.expose def undelete_async( self, trans, id ): if self._undelete( trans, id ): return "OK" - raise "Error undeleting" + raise Exception( "Error undeleting" ) @web.expose + def purge( self, trans, id ): + if self._purge( trans, id ): + return trans.response.send_redirect( web.url_for( controller='root', action='history', show_deleted = True ) ) + raise Exception( "Error removing disk file" ) + + @web.expose + def purge_async( self, trans, id ): + if self._purge( trans, id ): + return "OK" + raise Exception( "Error removing disk file" ) + + @web.expose def show_params( self, trans, dataset_id=None, from_noframe=None, **kwd ): """ Show the parameters used for an HDA --- a/lib/galaxy/web/controllers/history.py Tue Jun 14 10:29:42 2011 -0400 +++ b/lib/galaxy/web/controllers/history.py Tue Jun 14 12:43:42 2011 -0400 @@ -1,5 +1,6 @@ from galaxy.web.base.controller import * from galaxy.web.framework.helpers import time_ago, iff, grids +from galaxy.datatypes.data import nice_size from galaxy import model, util from galaxy.util.odict import odict from galaxy.model.mapping import desc @@ -51,6 +52,7 @@ grids.IndividualTagsColumn( "Tags", key="tags", model_tag_association_class=model.HistoryTagAssociation, \ filterable="advanced", grid_name="HistoryListGrid" ), grids.SharingStatusColumn( "Sharing", key="sharing", filterable="advanced", sortable=False ), + grids.GridColumn( "Size on Disk", key="get_disk_size_bytes", format=nice_size, sortable=False ), grids.GridColumn( "Created", key="create_time", format=time_ago ), grids.GridColumn( "Last Updated", key="update_time", format=time_ago ), # Columns that are valid for filtering but are not visible. @@ -68,6 +70,7 @@ grids.GridOperation( "Share or Publish", allow_multiple=False, condition=( lambda item: not item.deleted ), async_compatible=False ), grids.GridOperation( "Rename", condition=( lambda item: not item.deleted ), async_compatible=False ), grids.GridOperation( "Delete", condition=( lambda item: not item.deleted ), async_compatible=True ), + grids.GridOperation( "Delete and remove datasets from disk", condition=( lambda item: not item.deleted ), async_compatible=True ), grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ), async_compatible=True ), ] standard_filters = [ @@ -219,8 +222,11 @@ return trans.response.send_redirect( url_for( "/" ) ) else: trans.template_context['refresh_frames'] = ['history'] - elif operation == "delete": - status, message = self._list_delete( trans, histories ) + elif operation in ( "delete", "delete and remove datasets from disk" ): + if operation == "delete and remove datasets from disk": + status, message = self._list_delete( trans, histories, purge=True ) + else: + status, message = self._list_delete( trans, histories ) if current_history in histories: # Deleted the current history, so a new, empty history was # created automatically, and we need to refresh the history frame @@ -245,7 +251,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 ): + def _list_delete( self, trans, histories, purge=False ): """Delete histories""" n_deleted = 0 deleted_current = False @@ -264,8 +270,24 @@ trans.new_history() trans.log_event( "History (%s) marked as deleted" % history.name ) n_deleted += 1 + if purge: + for hda in history.datasets: + hda.purged = True + trans.sa_session.add( hda ) + trans.log_event( "HDA id %s has been purged" % hda.id ) + if hda.dataset.user_can_purge: + try: + hda.dataset.full_delete() + trans.log_event( "Dataset id %s has been purged upon the the purge of HDA id %s" % ( hda.dataset.id, hda.id ) ) + trans.sa_session.add( hda.dataset ) + except: + log.exception( 'Unable to purge dataset (%s) on purge of hda (%s):' % ( hda.dataset.id, hda.id ) ) + trans.sa_session.flush() if n_deleted: - message_parts.append( "Deleted %d %s. " % ( n_deleted, iff( n_deleted != 1, "histories", "history" ) ) ) + part = "Deleted %d %s" % ( n_deleted, iff( n_deleted != 1, "histories", "history" ) ) + if purge: + part += " and removed %s datasets from disk" % iff( n_deleted != 1, "their", "its" ) + message_parts.append( "%s. " % part ) if deleted_current: message_parts.append( "Your active history was deleted, a new empty history is now active. " ) status = INFO --- a/lib/galaxy/web/controllers/root.py Tue Jun 14 10:29:42 2011 -0400 +++ b/lib/galaxy/web/controllers/root.py Tue Jun 14 12:43:42 2011 -0400 @@ -114,9 +114,9 @@ show_deleted=util.string_as_bool( show_deleted ), show_hidden=util.string_as_bool( show_hidden ) ) else: - show_deleted = util.string_as_bool( show_deleted ) + show_deleted = show_purged = util.string_as_bool( show_deleted ) show_hidden = util.string_as_bool( show_hidden ) - datasets = self.get_history_datasets( trans, history, show_deleted, show_hidden ) + datasets = self.get_history_datasets( trans, history, show_deleted, show_hidden, show_purged ) return trans.stream_template_mako( "root/history.mako", history = history, annotation = self.get_item_annotation_str( trans.sa_session, trans.user, history ), @@ -182,6 +182,10 @@ } return rval + @web.json + def history_get_disk_size( self, trans ): + return trans.history.get_disk_size( nice_size=True ) + ## ---- Dataset display / editing ---------------------------------------- @web.expose @@ -498,6 +502,21 @@ self.__delete_dataset( trans, id ) return "OK" + @web.expose + def purge( self, trans, id = None, show_deleted_on_refresh = False, **kwd ): + hda = trans.sa_session.query( self.app.model.HistoryDatasetAssociation ).get( int( id ) ) + if bool( hda.dataset.active_history_associations or hda.dataset.library_associations ): + return trans.show_error_message( "Unable to purge: LDDA(s) or active HDA(s) exist" ) + elif hda.dataset.purged: + return trans.show_error_message( "Unable to purge: dataset is already purged" ) + os.unlink( hda.dataset.file_name ) + if os.path.exists( hda.extra_files_path ): + shutil.rmtree( hda.extra_files_path ) + hda.dataset.purged = True + trans.sa_session.add( hda.dataset ) + trans.sa_session.flush() + return self.history( trans, show_deleted = show_deleted_on_refresh ) + ## ---- History management ----------------------------------------------- @web.expose --- a/static/june_2007_style/base.css.tmpl Tue Jun 14 10:29:42 2011 -0400 +++ b/static/june_2007_style/base.css.tmpl Tue Jun 14 12:43:42 2011 -0400 @@ -829,6 +829,10 @@ -sprite-group: history-buttons; -sprite-image: delete_icon_dark.png; } +.icon-button.delete_disabled { + -sprite-group: history-buttons; + -sprite-image: delete_icon_grey.png; +} .icon-button.edit { -sprite-group: history-buttons; -sprite-image: pencil_icon.png; --- a/static/june_2007_style/blue/base.css Tue Jun 14 10:29:42 2011 -0400 +++ b/static/june_2007_style/blue/base.css Tue Jun 14 12:43:42 2011 -0400 @@ -143,9 +143,10 @@ .icon-button.display_disabled{background:url(history-buttons.png) no-repeat 0px -52px;} .icon-button.delete{background:url(history-buttons.png) no-repeat 0px -78px;} .icon-button.delete:hover{background:url(history-buttons.png) no-repeat 0px -104px;} -.icon-button.edit{background:url(history-buttons.png) no-repeat 0px -130px;} -.icon-button.edit:hover{background:url(history-buttons.png) no-repeat 0px -156px;} -.icon-button.edit_disabled{background:url(history-buttons.png) no-repeat 0px -182px;} +.icon-button.delete_disabled{background:url(history-buttons.png) no-repeat 0px -130px;} +.icon-button.edit{background:url(history-buttons.png) no-repeat 0px -156px;} +.icon-button.edit:hover{background:url(history-buttons.png) no-repeat 0px -182px;} +.icon-button.edit_disabled{background:url(history-buttons.png) no-repeat 0px -208px;} .icon-button.tag{background:url(fugue.png) no-repeat 0px -0px;} .icon-button.tags{background:url(fugue.png) no-repeat 0px -26px;} .icon-button.tag--plus{background:url(fugue.png) no-repeat 0px -52px;} Binary file static/june_2007_style/blue/history-buttons.png has changed --- a/static/june_2007_style/blue/trackster.css Tue Jun 14 10:29:42 2011 -0400 +++ b/static/june_2007_style/blue/trackster.css Tue Jun 14 12:43:42 2011 -0400 @@ -26,7 +26,7 @@ .label-track .track-content{background:white;} .track-tile{background:white;} .track-tile canvas{position:relative;z-index:100;border:solid white;border-width:2px 0px 0px 0px;} -.tile-message {border-bottom:solid 1px red;text-align:center;color:red;background-color:white;} +.tile-message{border-bottom:solid 1px red;text-align:center;color:red;background-color:white;} .track.error .track-content{background-color:#ECB4AF;background-image:none;} .track.nodata .track-content{background-color:#eee;background-image:none;} .track.pending .track-content{background-color:white;background-image:none;} --- a/templates/root/history.mako Tue Jun 14 10:29:42 2011 -0400 +++ b/templates/root/history.mako Tue Jun 14 12:43:42 2011 -0400 @@ -140,6 +140,7 @@ return false; }); }); + // Undelete link $(this).find("a.historyItemUndelete").each( function() { var data_id = this.id.split( "-" )[1]; @@ -158,6 +159,24 @@ }); }); + // Purge link + $(this).find("a.historyItemPurge").each( function() { + var data_id = this.id.split( "-" )[1]; + $(this).click( function() { + $( '#historyItem-' + data_id + " > div.historyItemTitleBar" ).addClass( "spinner" ); + $.ajax({ + url: "${h.url_for( controller='dataset', action='purge_async', id='XXX' )}".replace( 'XXX', data_id ), + error: function() { alert( "Removal from disk failed" ) }, + success: function() { + var to_update = {}; + to_update[data_id] = "none"; + updater( to_update ); + } + }); + return false; + }); + }); + // Show details icon -- Disabled since it often gets stuck, etc /* $(this).find("a.show-details").bind("mouseenter.load-detail", function(e) { var anchor = $(this); @@ -266,7 +285,8 @@ // Build request data var ids = [], states = [], - force_history_refresh = false; + force_history_refresh = false, + check_history_size = false; $.each( tracked_datasets, function ( id, state ) { ids.push( id ); @@ -292,6 +312,8 @@ force_history_refresh = true; } delete tracked_datasets[ parseInt(id) ]; + // When a dataset becomes terminal, check for changes in history disk size + check_history_size = true; } else { tracked_datasets[ parseInt(id) ] = val.state; } @@ -299,6 +321,17 @@ if ( force_history_refresh ) { parent.frames.galaxy_history.location.reload(); } else { + if ( check_history_size ) { + $.ajax( { + type: "POST", + url: "${h.url_for( controller='root', action='history_get_disk_size' )}", + dataType: "json", + success: function( data ) { + $("#history-size").text( data ); + } + }); + check_history_size = false; + } // Keep going (if there are still any items to track) updater( tracked_datasets ); } @@ -378,11 +411,15 @@ <div id="history-name-area" class="historyLinks"> - %if trans.get_user(): <div id="history-name-container"> - <div id="history-name" class="tooltip editable-text" title="Click to rename history">${history.get_display_name() | h}</div> + %if trans.get_user(): + <div id="history-name" class="tooltip editable-text" style="display: inline;" title="Click to rename history">${history.get_display_name() | h}</div> + <div id="history-size" style="display: inline; float: right;">${history.get_disk_size(nice_size=True)}</div> + %else: + <div id="history-size">${history.get_disk_size(nice_size=True)}</div> + %endif </div> - %endif + <div style="clear: both;"></div></div> --- a/templates/root/history_common.mako Tue Jun 14 10:29:42 2011 -0400 +++ b/templates/root/history_common.mako Tue Jun 14 12:43:42 2011 -0400 @@ -10,6 +10,7 @@ else: data_state = data.state current_user_roles = trans.get_current_user_roles() + can_edit = not ( data.deleted or data.purged ) %> %if not trans.user_is_admin() and not trans.app.security_agent.can_access_dataset( current_user_roles, data.dataset ): <div class="historyItemWrapper historyItem historyItem-${data_state} historyItem-noPermission" id="historyItem-${data.id}"> @@ -17,10 +18,14 @@ <div class="historyItemWrapper historyItem historyItem-${data_state}" id="historyItem-${data.id}"> %endif - %if data.deleted: - <div class="warningmessagesmall"> - <strong>This dataset has been deleted. Click <a href="${h.url_for( controller='dataset', action='undelete', id=data.id )}" class="historyItemUndelete" id="historyItemUndeleter-${data.id}" target="galaxy_history">here</a> to undelete.</strong> - </div> + %if data.deleted or data.purged or data.dataset.purged: + <div class="warningmessagesmall"><strong> + %if data.dataset.purged or data.purged: + This dataset has been deleted and removed from disk. + %else: + This dataset has been deleted. Click <a href="${h.url_for( controller='dataset', action='undelete', id=data.id )}" class="historyItemUndelete" id="historyItemUndeleter-${data.id}" target="galaxy_history">here</a> to undelete or <a href="${h.url_for( controller='dataset', action='purge', id=data.id )}" class="historyItemPurge" id="historyItemPurger-${data.id}" target="galaxy_history">here</a> to immediately remove from disk. + %endif + </strong></div> %endif %if data.visible is False: @@ -36,9 +41,9 @@ ## TODO: Make these CSS, just adding a "disabled" class to the normal ## links should be enough. However the number of datasets being uploaded ## at a time is usually small so the impact of these images is also small. - <img title='Display Data' class='icon-button display_disabled' /> + <span title='Display Data' class='icon-button display_disabled tooltip'></span> %if for_editing: - <img title='Edit Attributes' class='icon-button edit_disabled' /> + <span title='Edit Attributes' class='icon-button edit_disabled tooltip'></span> %endif %else: <% @@ -56,17 +61,31 @@ # check user permissions (to the same degree) before displaying. display_url = h.url_for( controller='dataset', action='display', dataset_id=dataset_id, preview=True, filename='' ) %> - <a class="icon-button display tooltip" title="Display data in browser" href="${display_url}" + %if data.purged: + <span class="icon-button display_disabled tooltip" title="Cannoy display datasets removed from disk"></span> + %else: + <a class="icon-button display tooltip" title="Display data in browser" href="${display_url}" + %if for_editing: + target="galaxy_main" + %endif + ></a> + %endif %if for_editing: - target="galaxy_main" - %endif - ></a> - %if for_editing: - <a class="icon-button edit tooltip" title="Edit attributes" href="${h.url_for( controller='root', action='edit', id=data.id )}" target="galaxy_main"></a> + %if data.deleted and not data.purged: + <span title="Undelete dataset to edit attributes" class="icon-button edit_disabled tooltip"></span> + %elif data.purged: + <span title="Cannot edit attributes of datasets removed from disk" class="icon-button edit_disabled tooltip"></span> + %else: + <a class="icon-button edit tooltip" title="Edit attributes" href="${h.url_for( controller='root', action='edit', id=data.id )}" target="galaxy_main"></a> + %endif %endif %endif %if for_editing: - <a class="icon-button delete tooltip" title="Delete" href="${h.url_for( action='delete', id=data.id, show_deleted_on_refresh=show_deleted_on_refresh )}" id="historyItemDeleter-${data.id}"></a> + %if can_edit: + <a class="icon-button delete tooltip" title="Delete" href="${h.url_for( action='delete', id=data.id, show_deleted_on_refresh=show_deleted_on_refresh )}" id="historyItemDeleter-${data.id}"></a> + %else: + <span title="Dataset is already deleted" class="icon-button delete_disabled tooltip"></span> + %endif %endif </div><span class="state-icon"></span> @@ -124,14 +143,17 @@ %elif data_state in [ "ok", "failed_metadata" ]: %if data_state == "failed_metadata": <div class="warningmessagesmall" style="margin: 4px 0 4px 0"> - An error occurred setting the metadata for this dataset. You may be able to <a href="${h.url_for( controller='root', action='edit', id=data.id )}" target="galaxy_main">set it manually or retry auto-detection</a>. + An error occurred setting the metadata for this dataset. + %if can_edit: + You may be able to <a href="${h.url_for( controller='root', action='edit', id=data.id )}" target="galaxy_main">set it manually or retry auto-detection</a>. + %endif </div> %endif <div> ${data.blurb}<br /> format: <span class="${data.ext}">${data.ext}</span>, database: - %if data.dbkey == '?': + %if data.dbkey == '?' and can_edit: <a href="${h.url_for( controller='root', action='edit', id=data.id )}" target="galaxy_main">${_(data.dbkey)}</a> %else: <span class="${data.dbkey}">${_(data.dbkey)}</span> @@ -142,23 +164,25 @@ %endif <div> %if data.has_data(): - ## Check for downloadable metadata files - <% meta_files = [ k for k in data.metadata.spec.keys() if isinstance( data.metadata.spec[k].param, FileParameter ) ] %> - %if meta_files: - <div popupmenu="dataset-${dataset_id}-popup"> - <a class="action-button" href="${h.url_for( controller='dataset', action='display', dataset_id=dataset_id, \ - to_ext=data.ext )}">Download Dataset</a> - <a>Additional Files</a> - %for file_type in meta_files: - <a class="action-button" href="${h.url_for( controller='dataset', action='get_metadata_file', \ - hda_id=dataset_id, metadata_name=file_type )}">Download ${file_type}</a> - %endfor - </div> - <div style="float:left;" class="menubutton split popup" id="dataset-${dataset_id}-popup"> - %endif - <a href="${h.url_for( controller='dataset', action='display', dataset_id=dataset_id, to_ext=data.ext )}" title="Download" class="icon-button disk tooltip"></a> - %if meta_files: - </div> + %if not data.purged: + ## Check for downloadable metadata files + <% meta_files = [ k for k in data.metadata.spec.keys() if isinstance( data.metadata.spec[k].param, FileParameter ) ] %> + %if meta_files: + <div popupmenu="dataset-${dataset_id}-popup"> + <a class="action-button" href="${h.url_for( controller='dataset', action='display', dataset_id=dataset_id, \ + to_ext=data.ext )}">Download Dataset</a> + <a>Additional Files</a> + %for file_type in meta_files: + <a class="action-button" href="${h.url_for( controller='dataset', action='get_metadata_file', \ + hda_id=dataset_id, metadata_type=file_type )}">Download ${file_type}</a> + %endfor + </div> + <div style="float:left;" class="menubutton split popup" id="dataset-${dataset_id}-popup"> + %endif + <a href="${h.url_for( controller='dataset', action='display', dataset_id=dataset_id, to_ext=data.ext )}" title="Download" class="icon-button disk tooltip"></a> + %if meta_files: + </div> + %endif %endif <a href="${h.url_for( controller='dataset', action='show_params', dataset_id=dataset_id )}" target="galaxy_main" title="View Details" class="icon-button information tooltip"></a> 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.