1 new changeset in galaxy-central: http://bitbucket.org/galaxy/galaxy-central/changeset/5ce088df9264/ changeset: 5ce088df9264 user: greg date: 2011-08-17 17:15:05 summary: Add the ability for tool shed users to select repository revisions whose tools can all be successfully loaded into a Galaxy instance in order to view / preview / download various tool versions from a specified repository. affected #: 6 files (9.5 KB) --- a/lib/galaxy/webapps/community/controllers/admin.py Wed Aug 17 08:59:56 2011 -0400 +++ b/lib/galaxy/webapps/community/controllers/admin.py Wed Aug 17 11:15:05 2011 -0400 @@ -3,9 +3,11 @@ from galaxy.model.orm import * from galaxy.web.framework.helpers import time_ago, iff, grids from galaxy.util import inflector -from common import get_category, get_repository, get_repository_metadata_by_id +from common import * from repository import RepositoryListGrid, CategoryListGrid +from mercurial import hg import logging + log = logging.getLogger( __name__ ) class UserListGrid( grids.Grid ): @@ -299,11 +301,11 @@ class AdminRepositoryListGrid( RepositoryListGrid ): operations = [ operation for operation in RepositoryListGrid.operations ] operations.append( grids.GridOperation( "Delete", - allow_multiple=True, + allow_multiple=False, condition=( lambda item: not item.deleted ), async_compatible=False ) ) operations.append( grids.GridOperation( "Undelete", - allow_multiple=True, + allow_multiple=False, condition=( lambda item: item.deleted ), async_compatible=False ) ) standard_filters = [] @@ -312,12 +314,15 @@ class IdColumn( grids.IntegerColumn ): def get_value( self, trans, grid, repository_metadata ): return repository_metadata.id - class RepositoryIdColumn( grids.IntegerColumn ): + class NameColumn( grids.TextColumn ): def get_value( self, trans, grid, repository_metadata ): - return repository_metadata.repository_id - class ChangesetRevisionColumn( grids.TextColumn ): + return repository_metadata.repository.name + class RevisionColumn( grids.TextColumn ): def get_value( self, trans, grid, repository_metadata ): - return repository_metadata.changeset_revision + repository = repository_metadata.repository + repo = hg.repository( get_configured_ui(), repository.repo_path ) + ctx = get_changectx_for_changeset( trans, repo, repository_metadata.changeset_revision ) + return "%s:%s" % ( str( ctx.rev() ), repository_metadata.changeset_revision ) class MetadataColumn( grids.TextColumn ): def get_value( self, trans, grid, repository_metadata ): metadata_str = '' @@ -347,25 +352,33 @@ IdColumn( "Id", visible=False, attach_popup=False ), - RepositoryIdColumn( "Repository Id", - key="repository_id", - attach_popup=False ), - ChangesetRevisionColumn( "Revision", - attach_popup=False ), + NameColumn( "Name", + key="name", + model_class=model.Repository, + link=( lambda item: dict( operation="view_or_manage_repository", + id=item.repository.id, + webapp="community" ) ), + attach_popup=True ), + RevisionColumn( "Revision", + attach_popup=False ), MetadataColumn( "Metadata", attach_popup=False ), MaliciousColumn( "Malicious", attach_popup=False ) ] operations = [ grids.GridOperation( "Delete", - allow_multiple=True ) ] + allow_multiple=False, + allow_popup=True, + async_compatible=False, + confirm="Repository metadata records cannot be recovered after they are deleted. Click OK to delete the selected items." ) ] standard_filters = [] default_filter = {} num_rows_per_page = 50 preserve_state = False use_paging = True def build_initial_query( self, trans, **kwd ): - return trans.sa_session.query( self.model_class ) + return trans.sa_session.query( self.model_class ) \ + .join( model.Repository.table ) class AdminController( BaseController, Admin ): @@ -383,12 +396,15 @@ operation = kwd[ 'operation' ].lower() if operation == "delete": return self.delete_repository_metadata( trans, **kwd ) + if operation == "view_or_manage_repository": + return trans.response.send_redirect( web.url_for( controller='repository', + action='browse_repositories', + **kwd ) ) # Render the list view return self.repository_metadata_list_grid( trans, **kwd ) @web.expose @web.require_admin def delete_repository_metadata( self, trans, **kwd ): - # TODO: Add a javascript confirm before this method executes.... params = util.Params( kwd ) message = util.restore_text( params.get( 'message', '' ) ) status = params.get( 'status', 'done' ) @@ -460,6 +476,23 @@ return self.mark_repository_deleted( trans, **kwd ) elif operation == "undelete": return self.undelete_repository( trans, **kwd ) + # The changeset_revision_select_field in the RepositoryListGrid performs a refresh_on_change + # which sends in request parameters like changeset_revison_1, changeset_revision_2, etc. One + # of the many select fields on the grid performed the refresh_on_change, so we loop through + # all of the received values to see which value is not the repository tip. If we find it, we + # know the refresh_on_change occurred, and we have the necessary repository id and change set + # revision to pass on. + for k, v in kwd.items(): + changset_revision_str = 'changeset_revision_' + if k.startswith( changset_revision_str ): + repository_id = trans.security.encode_id( int( k.lstrip( changset_revision_str ) ) ) + repository = get_repository( trans, repository_id ) + if repository.tip != v: + return trans.response.send_redirect( web.url_for( controller='repository', + action='browse_repositories', + operation='view_or_manage_repository', + id=trans.security.encode_id( repository.id ), + changeset_revision=v ) ) # Render the list view return self.repository_list_grid( trans, **kwd ) @web.expose --- a/lib/galaxy/webapps/community/controllers/common.py Wed Aug 17 08:59:56 2011 -0400 +++ b/lib/galaxy/webapps/community/controllers/common.py Wed Aug 17 11:15:05 2011 -0400 @@ -190,9 +190,9 @@ repository = get_repository( trans, id ) repo_dir = repository.repo_path repo = hg.repository( get_configured_ui(), repo_dir ) - change_set = get_change_set( trans, repo, change_set_revision ) invalid_files = [] - if change_set is not None: + ctx = get_changectx_for_changeset( trans, repo, change_set_revision ) + if ctx is not None: metadata_dict = {} for root, dirs, files in os.walk( repo_dir ): if not root.find( '.hg' ) >= 0 and not root.find( 'hgrc' ) >= 0: @@ -284,8 +284,8 @@ def get_repository_by_name( trans, name ): """Get a repository from the database via name""" return trans.sa_session.query( app.model.Repository ).filter_by( name=name ).one() -def get_change_set( trans, repo, change_set_revision, **kwd ): - """Retrieve a specified change set from a repository""" +def get_changectx_for_changeset( trans, repo, change_set_revision, **kwd ): + """Retrieve a specified changectx from a repository""" for changeset in repo.changelog: ctx = repo.changectx( changeset ) if str( ctx ) == change_set_revision: @@ -430,3 +430,28 @@ ToolClass = Tool return ToolClass( config_file, root, trans.app ) return None +def build_changeset_revision_select_field( trans, repository, selected_value=None, add_id_to_name=True ): + """ + Build a SelectField whose options are the changeset_revision + strings of all downloadable_revisions of the received repository. + """ + repo = hg.repository( get_configured_ui(), repository.repo_path ) + options = [] + refresh_on_change_values = [] + for repository_metadata in repository.downloadable_revisions: + changeset_revision = repository_metadata.changeset_revision + ctx = get_changectx_for_changeset( trans, repo, changeset_revision ) + revision_label = "%s:%s" % ( str( ctx.rev() ), changeset_revision ) + options.append( ( revision_label, changeset_revision ) ) + refresh_on_change_values.append( changeset_revision ) + if add_id_to_name: + name = 'changeset_revision_%d' % repository.id + else: + name = 'changeset_revision' + select_field = SelectField( name=name, + refresh_on_change=True, + refresh_on_change_values=refresh_on_change_values ) + for option_tup in options: + selected = selected_value and option_tup[1] == selected_value + select_field.add_option( option_tup[0], option_tup[1], selected=selected ) + return select_field --- a/lib/galaxy/webapps/community/controllers/repository.py Wed Aug 17 08:59:56 2011 -0400 +++ b/lib/galaxy/webapps/community/controllers/repository.py Wed Aug 17 11:15:05 2011 -0400 @@ -74,9 +74,16 @@ class NameColumn( grids.TextColumn ): def get_value( self, trans, grid, repository ): return repository.name - class RevisionColumn( grids.TextColumn ): + class RevisionColumn( grids.GridColumn ): + def __init__( self, col_name ): + grids.GridColumn.__init__( self, col_name ) def get_value( self, trans, grid, repository ): - return repository.revision + """ + Display a SelectField whose options are the changeset_revision + strings of all downloadable_revisions of this repository. + """ + select_field = build_changeset_revision_select_field( trans, repository ) + return select_field.get_html() class DescriptionColumn( grids.TextColumn ): def get_value( self, trans, grid, repository ): return repository.description @@ -121,13 +128,14 @@ columns = [ NameColumn( "Name", key="name", - link=( lambda item: dict( operation="view_or_manage_repository", id=item.id, webapp="community" ) ), - attach_popup=False ), + link=( lambda item: dict( operation="view_or_manage_repository", + id=item.id, + webapp="community" ) ), + attach_popup=True ), DescriptionColumn( "Synopsis", key="description", attach_popup=False ), - RevisionColumn( "Revision", - attach_popup=False ), + RevisionColumn( "Revision" ), CategoryColumn( "Category", model_class=model.Category, key="Category.name", @@ -159,7 +167,7 @@ visible=False, filterable="standard" ) ) operations = [ grids.GridOperation( "Receive email alerts", - allow_multiple=True, + allow_multiple=False, condition=( lambda item: not item.deleted ), async_compatible=False ) ] standard_filters = [] @@ -257,12 +265,32 @@ category = get_category( trans, category_id ) kwd[ 'f-Category.name' ] = category.name elif operation == "receive email alerts": - if kwd[ 'id' ]: + if trans.user: + if kwd[ 'id' ]: + return trans.response.send_redirect( web.url_for( controller='repository', + action='set_email_alerts', + **kwd ) ) + else: + kwd[ 'message' ] = 'You must be logged in to set email alerts.' + kwd[ 'status' ] = 'error' + del kwd[ 'operation' ] + # The changeset_revision_select_field in the RepositoryListGrid performs a refresh_on_change + # which sends in request parameters like changeset_revison_1, changeset_revision_2, etc. One + # of the many select fields on the grid performed the refresh_on_change, so we loop through + # all of the received values to see which value is not the repository tip. If we find it, we + # know the refresh_on_change occurred, and we have the necessary repository id and change set + # revision to pass on. + for k, v in kwd.items(): + changset_revision_str = 'changeset_revision_' + if k.startswith( changset_revision_str ): + repository_id = trans.security.encode_id( int( k.lstrip( changset_revision_str ) ) ) + repository = get_repository( trans, repository_id ) + if repository.tip != v: return trans.response.send_redirect( web.url_for( controller='repository', - action='set_email_alerts', - **kwd ) ) - else: - del kwd[ 'operation' ] + action='browse_repositories', + operation='view_or_manage_repository', + id=trans.security.encode_id( repository.id ), + changeset_revision=v ) ) # Render the list view return self.repository_list_grid( trans, **kwd ) @web.expose @@ -524,6 +552,7 @@ repository = get_repository( trans, id ) repo = hg.repository( get_configured_ui(), repository.repo_path ) avg_rating, num_ratings = self.get_ave_item_rating_data( trans.sa_session, repository, webapp_model=trans.model ) + changeset_revision = util.restore_text( params.get( 'changeset_revision', repository.tip ) ) display_reviews = util.string_as_bool( params.get( 'display_reviews', False ) ) alerts = params.get( 'alerts', '' ) alerts_checked = CheckboxField.is_checked( alerts ) @@ -549,7 +578,13 @@ trans.sa_session.flush() checked = alerts_checked or ( user and user.email in email_alerts ) alerts_check_box = CheckboxField( 'alerts', checked=checked ) - repository_metadata = get_repository_metadata_by_changeset_revision( trans, id, repository.tip ) + changeset_revision_select_field = build_changeset_revision_select_field( trans, + repository, + selected_value=changeset_revision, + add_id_to_name=False ) + ctx = get_changectx_for_changeset( trans, repo, changeset_revision ) + revision_label = "%s:%s" % ( str( ctx.rev() ), changeset_revision ) + repository_metadata = get_repository_metadata_by_changeset_revision( trans, id, changeset_revision ) if repository_metadata: metadata = repository_metadata.metadata else: @@ -569,6 +604,9 @@ display_reviews=display_reviews, num_ratings=num_ratings, alerts_check_box=alerts_check_box, + changeset_revision=changeset_revision, + changeset_revision_select_field=changeset_revision_select_field, + revision_label=revision_label, is_malicious=is_malicious, message=message, status=status ) @@ -582,6 +620,7 @@ repo_dir = repository.repo_path repo = hg.repository( get_configured_ui(), repo_dir ) repo_name = util.restore_text( params.get( 'repo_name', repository.name ) ) + changeset_revision = util.restore_text( params.get( 'changeset_revision', repository.tip ) ) description = util.restore_text( params.get( 'description', repository.description ) ) long_description = util.restore_text( params.get( 'long_description', repository.long_description ) ) avg_rating, num_ratings = self.get_ave_item_rating_data( trans.sa_session, repository, webapp_model=trans.model ) @@ -678,7 +717,13 @@ allow_push_select_field = self.__build_allow_push_select_field( trans, current_allow_push_list ) checked = alerts_checked or user.email in email_alerts alerts_check_box = CheckboxField( 'alerts', checked=checked ) - repository_metadata = get_repository_metadata_by_changeset_revision( trans, id, repository.tip ) + changeset_revision_select_field = build_changeset_revision_select_field( trans, + repository, + selected_value=changeset_revision, + add_id_to_name=False ) + ctx = get_changectx_for_changeset( trans, repo, changeset_revision ) + revision_label = "%s:%s" % ( str( ctx.rev() ), changeset_revision ) + repository_metadata = get_repository_metadata_by_changeset_revision( trans, id, changeset_revision ) if repository_metadata: metadata = repository_metadata.metadata is_malicious = repository_metadata.malicious @@ -702,6 +747,9 @@ allow_push_select_field=allow_push_select_field, repo=repo, repository=repository, + changeset_revision=changeset_revision, + changeset_revision_select_field=changeset_revision_select_field, + revision_label=revision_label, selected_categories=selected_categories, categories=categories, metadata=metadata, @@ -750,7 +798,7 @@ status = params.get( 'status', 'done' ) repository = get_repository( trans, id ) repo = hg.repository( get_configured_ui(), repository.repo_path ) - ctx = get_change_set( trans, repo, ctx_str ) + ctx = get_changectx_for_changeset( trans, repo, ctx_str ) if ctx is None: message = "Repository does not include changeset revision '%s'." % str( ctx_str ) status = 'error' @@ -878,6 +926,7 @@ return trans.response.send_redirect( web.url_for( controller='repository', action='manage_repository', id=id, + changeset_revision=ctx_str, malicious=malicious, message=message, status=status ) ) @@ -1034,7 +1083,7 @@ message=message, status=status ) @web.expose - def download( self, trans, repository_id, file_type, **kwd ): + def download( self, trans, repository_id, changeset_revision, file_type, **kwd ): # Download an archive of the repository files compressed as zip, gz or bz2. params = util.Params( kwd ) repository = get_repository( trans, repository_id ) @@ -1043,11 +1092,11 @@ # [web] # allow_archive = bz2, gz, zip if file_type == 'zip': - file_type_str = 'tip.zip' + file_type_str = '%s.zip' % changeset_revision elif file_type == 'bz2': - file_type_str = 'tip.tar.bz2' + file_type_str = '%s.tar.bz2' % changeset_revision elif file_type == 'gz': - file_type_str = 'tip.tar.gz' + file_type_str = '%s.tar.gz' % changeset_revision repository.times_downloaded += 1 trans.sa_session.add( repository ) trans.sa_session.flush() @@ -1081,7 +1130,6 @@ def print_ticks( d ): pass cmd = "ls -p '%s'" % folder_path - # Handle the authentication message if keys are not set - the message is output = pexpect.run( cmd, events={ pexpect.TIMEOUT : print_ticks }, timeout=10 ) --- a/lib/galaxy/webapps/community/model/mapping.py Wed Aug 17 08:59:56 2011 -0400 +++ b/lib/galaxy/webapps/community/model/mapping.py Wed Aug 17 11:15:05 2011 -0400 @@ -193,7 +193,8 @@ properties = dict( categories=relation( RepositoryCategoryAssociation ), ratings=relation( RepositoryRatingAssociation, order_by=desc( RepositoryRatingAssociation.table.c.update_time ), backref="repositories" ), - user=relation( User.mapper ) ) ) + user=relation( User.mapper ), + downloadable_revisions=relation( RepositoryMetadata, order_by=desc( RepositoryMetadata.table.c.update_time ) ) ) ) assign_mapper( context, RepositoryMetadata, RepositoryMetadata.table, properties=dict( repository=relation( Repository ) ) ) --- a/templates/webapps/community/repository/manage_repository.mako Wed Aug 17 08:59:56 2011 -0400 +++ b/templates/webapps/community/repository/manage_repository.mako Wed Aug 17 11:15:05 2011 -0400 @@ -85,9 +85,9 @@ <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">${browse_label}</a> %endif %if can_download: - <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='gz' )}">Download as a .tar.gz file</a> - <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='bz2' )}">Download as a .tar.bz2 file</a> - <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='zip' )}">Download as a zip file</a> + <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='gz' )}">Download as a .tar.gz file</a> + <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='bz2' )}">Download as a .tar.bz2 file</a> + <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='zip' )}">Download as a zip file</a> %endif </div> %endif @@ -98,6 +98,26 @@ %endif <div class="toolForm"> + <div class="toolFormTitle">Revision</div> + <div class="toolFormBody"> + <form name="change_revision" id="change_revision" action="${h.url_for( controller='repository', action='manage_repository', id=trans.security.encode_id( repository.id ) )}" method="post" > + <div class="form-row"> + <% + if changeset_revision == repository.tip: + tip_str = 'repository tip' + else: + tip_str = '' + %> + ${changeset_revision_select_field.get_html()} <i>${tip_str}</i> + <div class="toolParamHelp" style="clear: both;"> + Select a revision to preview download-able versions of tools from this repository. + </div> + </div> + </form> + </div> +</div> +<p/> +<div class="toolForm"><div class="toolFormTitle">${repository.name}</div><div class="toolFormBody"><form name="edit_repository" id="edit_repository" action="${h.url_for( controller='repository', action='manage_repository', id=trans.security.encode_id( repository.id ) )}" method="post" > @@ -129,9 +149,9 @@ <div class="form-row"><label>Revision:</label> %if can_view_change_log: - <a href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">${repository.revision}</a> + <a href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">${revision_label}</a> %else: - ${repository.revision} + ${revision_label} %endif </div><div class="form-row"> @@ -190,7 +210,7 @@ </a></div><div popupmenu="tool-${tool_dict[ 'id' ].replace( ' ', '_' )}-popup"> - <a class="action-button" href="${h.url_for( controller='repository', action='view_tool_metadata', repository_id=trans.security.encode_id( repository.id ), changeset_revision=repository.tip, tool_id=tool_dict[ 'id' ] )}">View all metadata for this tool</a> + <a class="action-button" href="${h.url_for( controller='repository', action='view_tool_metadata', repository_id=trans.security.encode_id( repository.id ), changeset_revision=changeset_revision, tool_id=tool_dict[ 'id' ] )}">View all metadata for this tool</a></div></td><td>${tool_dict[ 'description' ]}</td> @@ -249,7 +269,7 @@ <div style="clear: both"></div> %endif %endif - <form name="set_metadata" action="${h.url_for( controller='repository', action='set_metadata', id=trans.security.encode_id( repository.id ), ctx_str=repository.tip )}" method="post"> + <form name="set_metadata" action="${h.url_for( controller='repository', action='set_metadata', id=trans.security.encode_id( repository.id ), ctx_str=changeset_revision )}" method="post"><div class="form-row"><div style="float: left; width: 250px; margin-right: 10px;"><input type="submit" name="set_metadata_button" value="Reset metadata"/> @@ -406,7 +426,7 @@ <div class="toolForm"><div class="toolFormTitle">Malicious repository tip</div><div class="toolFormBody"> - <form name="malicious" id="malicious" action="${h.url_for( controller='repository', action='set_metadata', id=trans.security.encode_id( repository.id ), ctx_str=repository.tip )}" method="post"> + <form name="malicious" id="malicious" action="${h.url_for( controller='repository', action='set_metadata', id=trans.security.encode_id( repository.id ), ctx_str=changeset_revision )}" method="post"><div class="form-row"><label>Define repository tip as malicious:</label> ${malicious_check_box.get_html()} --- a/templates/webapps/community/repository/view_repository.mako Wed Aug 17 08:59:56 2011 -0400 +++ b/templates/webapps/community/repository/view_repository.mako Wed Aug 17 11:15:05 2011 -0400 @@ -82,9 +82,9 @@ <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">${browse_label}</a> %endif %if can_download: - <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='gz' )}">Download as a .tar.gz file</a> - <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='bz2' )}">Download as a .tar.bz2 file</a> - <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='zip' )}">Download as a zip file</a> + <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='gz' )}">Download as a .tar.gz file</a> + <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='bz2' )}">Download as a .tar.bz2 file</a> + <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='zip' )}">Download as a zip file</a> %endif </div> %endif @@ -95,6 +95,26 @@ %endif <div class="toolForm"> + <div class="toolFormTitle">Revision</div> + <div class="toolFormBody"> + <form name="change_revision" id="change_revision" action="${h.url_for( controller='repository', action='view_repository', id=trans.security.encode_id( repository.id ) )}" method="post" > + <div class="form-row"> + <% + if changeset_revision == repository.tip: + tip_str = 'repository tip' + else: + tip_str = '' + %> + ${changeset_revision_select_field.get_html()} <i>${tip_str}</i> + <div class="toolParamHelp" style="clear: both;"> + Select a revision to preview download-able versions of tools from this repository. + </div> + </div> + </form> + </div> +</div> +<p/> +<div class="toolForm"><div class="toolFormTitle">${repository.name}</div><div class="toolFormBody"> %if can_download: @@ -125,9 +145,9 @@ <div class="form-row"><label>Revision:</label> %if can_view_change_log: - <a href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">${repository.revision}</a> + <a href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">${revision_label}</a> %else: - ${repository.revision} + ${revision_label} %endif </div><div class="form-row"> @@ -181,7 +201,7 @@ </a></div><div popupmenu="tool-${tool_dict[ 'id' ].replace( ' ', '_' )}-popup"> - <a class="action-button" href="${h.url_for( controller='repository', action='view_tool_metadata', repository_id=trans.security.encode_id( repository.id ), changeset_revision=repository.tip, tool_id=tool_dict[ 'id' ] )}">View all metadata for this tool</a> + <a class="action-button" href="${h.url_for( controller='repository', action='view_tool_metadata', repository_id=trans.security.encode_id( repository.id ), changeset_revision=changeset_revision, tool_id=tool_dict[ 'id' ] )}">View all metadata for this tool</a></div></td><td>${tool_dict[ 'description' ]}</td> 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.