1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/changeset/e598a3e78079/ changeset: e598a3e78079 user: greg date: 2012-07-09 20:49:31 summary: Apply a category grid whose search feature searches valid repository names and descriptions when browsing a tool shed from Galaxy. affected #: 12 files diff -r f33269063dab72e84f1ba7cb1ebc509ee73651e8 -r e598a3e78079064fcde5b709fac17bf58153d82a lib/galaxy/web/controllers/admin_toolshed.py --- a/lib/galaxy/web/controllers/admin_toolshed.py +++ b/lib/galaxy/web/controllers/admin_toolshed.py @@ -366,7 +366,7 @@ def browse_tool_shed( self, trans, **kwd ): tool_shed_url = kwd[ 'tool_shed_url' ] galaxy_url = url_for( '/', qualified=True ) - url = '%srepository/browse_valid_repositories?galaxy_url=%s&webapp=galaxy&no_reset=true' % ( tool_shed_url, galaxy_url ) + url = '%srepository/browse_valid_categories?galaxy_url=%s&webapp=galaxy&no_reset=true' % ( tool_shed_url, galaxy_url ) return trans.response.send_redirect( url ) @web.expose @web.require_admin diff -r f33269063dab72e84f1ba7cb1ebc509ee73651e8 -r e598a3e78079064fcde5b709fac17bf58153d82a lib/galaxy/webapps/community/controllers/common.py --- a/lib/galaxy/webapps/community/controllers/common.py +++ b/lib/galaxy/webapps/community/controllers/common.py @@ -501,6 +501,9 @@ def get_category( trans, id ): """Get a category from the database""" return trans.sa_session.query( trans.model.Category ).get( trans.security.decode_id( id ) ) +def get_category_by_name( trans, name ): + """Get a category from the database via name""" + return trans.sa_session.query( trans.model.Category ).filter_by( name=name ).one() def get_categories( trans ): """Get all categories from the database""" return trans.sa_session.query( trans.model.Category ) \ diff -r f33269063dab72e84f1ba7cb1ebc509ee73651e8 -r e598a3e78079064fcde5b709fac17bf58153d82a lib/galaxy/webapps/community/controllers/repository.py --- a/lib/galaxy/webapps/community/controllers/repository.py +++ b/lib/galaxy/webapps/community/controllers/repository.py @@ -52,8 +52,46 @@ DescriptionColumn( "Description", key="Category.description", attach_popup=False ), + RepositoriesColumn( "Repositories", + model_class=model.Repository, + attach_popup=False ) + ] + # Override these + default_filter = {} + global_actions = [] + operations = [] + standard_filters = [] + num_rows_per_page = 50 + preserve_state = False + use_paging = True + +class ValidCategoryListGrid( CategoryListGrid ): + class RepositoriesColumn( grids.TextColumn ): + def get_value( self, trans, grid, category ): + if category.repositories: + viewable_repositories = 0 + for rca in category.repositories: + repository = rca.repository + if repository.downloadable_revisions: + viewable_repositories += 1 + return viewable_repositories + return 0 + + # Grid definition + title = "Categories of valid repositories" + model_class = model.Category + template='/webapps/community/category/valid_grid.mako' + default_sort_key = "name" + columns = [ + CategoryListGrid.NameColumn( "Name", + key="Category.name", + link=( lambda item: dict( operation="valid_repositories_by_category", id=item.id, webapp="galaxy" ) ), + attach_popup=False ), + CategoryListGrid.DescriptionColumn( "Description", + key="Category.description", + attach_popup=False ), # Columns that are valid for filtering but are not visible. - RepositoriesColumn( "Repositories", + RepositoriesColumn( "Valid repositories", model_class=model.Repository, attach_popup=False ) ] @@ -208,14 +246,28 @@ ] class ValidRepositoryListGrid( RepositoryListGrid ): + class CategoryColumn( grids.TextColumn ): + def get_value( self, trans, grid, repository ): + rval = '<ul>' + if repository.categories: + for rca in repository.categories: + rval += '<li><a href="browse_repositories?operation=valid_repositories_by_category&id=%s&webapp=galaxy">%s</a></li>' \ + % ( trans.security.encode_id( rca.category.id ), rca.category.name ) + else: + rval += '<li>not set</li>' + rval += '</ul>' + return rval + class RepositoryCategoryColumn( grids.GridColumn ): + def filter( self, trans, user, query, column_filter ): + """Modify query to filter by category.""" + if column_filter == "All": + return query + return query.filter( model.Category.name == column_filter ) class RevisionColumn( grids.GridColumn ): def __init__( self, col_name ): grids.GridColumn.__init__( self, col_name ) def get_value( self, trans, grid, repository ): - """ - Display a SelectField whose options are the changeset_revision - strings of all download-able revisions of this repository. - """ + """Display a SelectField whose options are the changeset_revision strings of all download-able revisions of this repository.""" select_field = build_changeset_revision_select_field( trans, repository ) if len( select_field.options ) > 1: return select_field.get_html() @@ -231,19 +283,35 @@ RevisionColumn( "Revision" ), RepositoryListGrid.UserColumn( "Owner", model_class=model.User, - attach_popup=False, - key="User.username" ) + attach_popup=False ), + # Columns that are valid for filtering but are not visible. + RepositoryCategoryColumn( "Category", + model_class=model.Category, + key="Category.name", + visible=False ) ] - columns.append( grids.MulticolFilterColumn( "Search repository name, description, owner", + columns.append( grids.MulticolFilterColumn( "Search repository name, description", cols_to_filter=[ columns[0], columns[1] ], key="free-text-search", visible=False, filterable="standard" ) ) operations = [] def build_initial_query( self, trans, **kwd ): + if 'id' in kwd: + # The user is browsing categories of valid repositories, so filter the request by the received id, which is a category id. + return trans.sa_session.query( self.model_class ) \ + .join( model.RepositoryMetadata.table ) \ + .join( model.User.table ) \ + .join( model.RepositoryCategoryAssociation.table ) \ + .join( model.Category.table ) \ + .filter( and_( model.Category.table.c.id == trans.security.decode_id( kwd[ 'id' ] ), + model.RepositoryMetadata.table.c.downloadable == True ) ) + # The user performed a free text search on the ValidCategoryListGrid. return trans.sa_session.query( self.model_class ) \ .join( model.RepositoryMetadata.table ) \ .join( model.User.table ) \ + .outerjoin( model.RepositoryCategoryAssociation.table ) \ + .outerjoin( model.Category.table ) \ .filter( model.RepositoryMetadata.table.c.downloadable == True ) class MatchedRepositoryListGrid( grids.Grid ): @@ -323,6 +391,7 @@ repository_list_grid = RepositoryListGrid() email_alerts_repository_list_grid = EmailAlertsRepositoryListGrid() category_list_grid = CategoryListGrid() + valid_category_list_grid = ValidCategoryListGrid() def __add_hgweb_config_entry( self, trans, repository, repository_path ): # Add an entry in the hgweb.config file for a new repository. An entry looks something like: @@ -346,14 +415,13 @@ shutil.move( tmp_fname, os.path.abspath( hgweb_config ) ) @web.expose def browse_categories( self, trans, **kwd ): + # The request came from the tool shed. if 'f-free-text-search' in kwd: - # Trick to enable searching repository name, description from the CategoryListGrid. - # What we've done is rendered the search box for the RepositoryListGrid on the grid.mako - # template for the CategoryListGrid. See ~/templates/webapps/community/category/grid.mako. - # Since we are searching repositories and not categories, redirect to browse_repositories(). + # Trick to enable searching repository name, description from the CategoryListGrid. What we've done is rendered the search box for the + # RepositoryListGrid on the grid.mako template for the CategoryListGrid. See ~/templates/webapps/community/category/grid.mako. Since we + # are searching repositories and not categories, redirect to browse_repositories(). if 'id' in kwd and 'f-free-text-search' in kwd and kwd[ 'id' ] == kwd[ 'f-free-text-search' ]: - # The value of 'id' has been set to the search string, which is a repository name. - # We'll try to get the desired encoded repository id to pass on. + # The value of 'id' has been set to the search string, which is a repository name. We'll try to get the desired encoded repository id to pass on. try: repository = get_repository_by_name( trans, kwd[ 'id' ] ) kwd[ 'id' ] = trans.security.encode_id( repository.id ) @@ -408,11 +476,10 @@ status=status ) @web.expose def browse_repositories( self, trans, **kwd ): - # We add params to the keyword dict in this method in order to rename the param - # with an "f-" prefix, simulating filtering by clicking a search link. We have - # to take this approach because the "-" character is illegal in HTTP requests. + # We add params to the keyword dict in this method in order to rename the param with an "f-" prefix, simulating filtering by clicking a search + # link. We have to take this approach because the "-" character is illegal in HTTP requests. if 'webapp' not in kwd: - kwd[ 'webapp' ] = 'community' + kwd[ 'webapp' ] = get_webapp( trans, **kwd ) if 'operation' in kwd: operation = kwd['operation'].lower() if operation == "view_or_manage_repository": @@ -441,8 +508,7 @@ kwd[ 'f-email' ] = user.email del kwd[ 'user_id' ] else: - # The received id is the repository id, so we need to get the id of the user - # that uploaded the repository. + # The received id is the repository id, so we need to get the id of the user that uploaded the repository. repository_id = kwd.get( 'id', None ) repository = get_repository( trans, repository_id ) kwd[ 'f-email' ] = repository.user.email @@ -509,27 +575,73 @@ message=message, status=status ) @web.expose + def browse_valid_categories( self, trans, **kwd ): + # The request came from Galaxy, so restrict category links to display only valid repository changeset revisions. + galaxy_url = kwd.get( 'galaxy_url', None ) + if galaxy_url: + trans.set_cookie( galaxy_url, name='toolshedgalaxyurl' ) + if 'f-free-text-search' in kwd: + if kwd[ 'f-free-text-search' ] == 'All': + # The user performed a search, then clicked the "x" to eliminate the search criteria. + new_kwd = dict( webapp='galaxy', no_reset='true' ) + return self.valid_category_list_grid( trans, **new_kwd ) + # Since we are searching valid repositories and not categories, redirect to browse_valid_repositories(). + if 'id' in kwd and 'f-free-text-search' in kwd and kwd[ 'id' ] == kwd[ 'f-free-text-search' ]: + # The value of 'id' has been set to the search string, which is a repository name. + # We'll try to get the desired encoded repository id to pass on. + try: + repository = get_repository_by_name( trans, kwd[ 'id' ] ) + kwd[ 'id' ] = trans.security.encode_id( repository.id ) + except: + pass + return self.browse_valid_repositories( trans, **kwd ) + if 'operation' in kwd: + operation = kwd['operation'].lower() + if operation in [ "valid_repositories_by_category", "valid_repositories_by_user" ]: + # Eliminate the current filters if any exist. + for k, v in kwd.items(): + if k.startswith( 'f-' ): + del kwd[ k ] + return trans.response.send_redirect( web.url_for( controller='repository', + action='browse_valid_repositories', + **kwd ) ) + return self.valid_category_list_grid( trans, **kwd ) + @web.expose def browse_valid_repositories( self, trans, **kwd ): webapp = get_webapp( trans, **kwd ) galaxy_url = kwd.get( 'galaxy_url', None ) + if 'f-free-text-search' in kwd: + if 'f-Category.name' in kwd: + # The user browsed to a category and then entered a search string, so get the category associated with it's value. + category_name = kwd[ 'f-Category.name' ] + category = get_category_by_name( trans, category_name ) + # Set the id value in kwd since it is required by the ValidRepositoryListGrid.build_initial_query method. + kwd[ 'id' ] = trans.security.encode_id( category.id ) if galaxy_url: trans.set_cookie( galaxy_url, name='toolshedgalaxyurl' ) - repository_id = kwd.get( 'id', None ) if 'operation' in kwd: operation = kwd[ 'operation' ].lower() if operation == "preview_tools_in_changeset": + repository_id = kwd.get( 'id', None ) repository = get_repository( trans, repository_id ) return trans.response.send_redirect( web.url_for( controller='repository', action='preview_tools_in_changeset', webapp=webapp, repository_id=repository_id, changeset_revision=repository.tip ) ) - # 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. + elif operation == "valid_repositories_by_category": + # Eliminate the current filters if any exist. + for k, v in kwd.items(): + if k.startswith( 'f-' ): + del kwd[ k ] + category_id = kwd.get( 'id', None ) + category = get_category( trans, category_id ) + kwd[ 'f-Category.name' ] = category.name + # The changeset_revision_select_field in the ValidRepositoryListGrid 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. + repository_id = None for k, v in kwd.items(): changset_revision_str = 'changeset_revision_' if k.startswith( changset_revision_str ): @@ -901,7 +1013,7 @@ if webapp == 'galaxy': # Our initial request originated from a Galaxy instance. global_actions = [ grids.GridAction( "Browse valid repositories", - dict( controller='repository', action='browse_valid_repositories', webapp=webapp ) ), + dict( controller='repository', action='browse_valid_categories', webapp=webapp ) ), grids.GridAction( "Search for valid tools", dict( controller='repository', action='find_tools', webapp=webapp ) ), grids.GridAction( "Search for workflows", diff -r f33269063dab72e84f1ba7cb1ebc509ee73651e8 -r e598a3e78079064fcde5b709fac17bf58153d82a templates/webapps/community/category/grid.mako --- a/templates/webapps/community/category/grid.mako +++ b/templates/webapps/community/category/grid.mako @@ -4,6 +4,7 @@ <%inherit file="/grid_base.mako" /> ## Render grid header. +## TODO: This is very similar to this directory's valid_grid.mako, so see if we can re-use this code in a better way. <%def name="render_grid_header( grid, repo_grid, render_title=True)"><div class="grid-header"> %if render_title: diff -r f33269063dab72e84f1ba7cb1ebc509ee73651e8 -r e598a3e78079064fcde5b709fac17bf58153d82a templates/webapps/community/category/valid_grid.mako --- /dev/null +++ b/templates/webapps/community/category/valid_grid.mako @@ -0,0 +1,63 @@ +<%namespace file="/display_common.mako" import="render_message" /> +<%namespace file="/grid_base.mako" import="*" /> +<%namespace file="/grid_common.mako" import="*" /> +<%inherit file="/grid_base.mako" /> + +## Render grid header. +<%def name="render_grid_header( grid, repo_grid, render_title=True)"> + <div class="grid-header"> + %if render_title: + ${grid_title()} + %endif + %if grid.global_actions: + <ul class="manage-table-actions"> + %if len( grid.global_actions ) < 4: + %for action in grid.global_actions: + <li><a class="action-button" href="${h.url_for( **action.url_args )}">${action.label}</a></li> + %endfor + %else: + <li><a class="action-button" id="action-8675309-popup" class="menubutton">Actions</a></li> + <div popupmenu="action-8675309-popup"> + %for action in grid.global_actions: + <a class="action-button" href="${h.url_for( **action.url_args )}">${action.label}</a> + %endfor + </div> + %endif + </ul> + %endif + ${render_grid_filters( repo_grid, render_advanced_search=False )} + </div> +</%def> + +<%def name="make_grid( grid, repo_grid )"> + <div class="loading-elt-overlay"></div> + <table> + <tr> + <td width="75%">${self.render_grid_header( grid, repo_grid )}</td> + <td></td> + <td></td> + </tr> + <tr> + <td width="100%" id="grid-message" valign="top">${render_message( message, status )}</td> + <td></td> + <td></td> + </tr> + </table> + ${render_grid_table( grid, show_item_checkboxes )} +</%def> + +<%def name="grid_body( grid )"> + <% + from galaxy.webapps.community.controllers.repository import ValidRepositoryListGrid + repo_grid = ValidRepositoryListGrid() + %> + ${self.make_grid( grid, repo_grid )} +</%def> + +<%def name="center_panel()"> + <div style="overflow: auto; height: 100%"> + <div class="page-container" style="padding: 10px;"> + ${self.grid_body( grid )} + </div> + </div> +</%def> diff -r f33269063dab72e84f1ba7cb1ebc509ee73651e8 -r e598a3e78079064fcde5b709fac17bf58153d82a templates/webapps/community/repository/find_tools.mako --- a/templates/webapps/community/repository/find_tools.mako +++ b/templates/webapps/community/repository/find_tools.mako @@ -13,7 +13,7 @@ %if webapp == 'galaxy': <br/><br/><ul class="manage-table-actions"> - <li><a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_repositories', webapp=webapp )}">Browse valid repositories</a></li> + <li><a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_categories', webapp=webapp )}">Browse valid repositories</a></li><li><a class="action-button" href="${h.url_for( controller='repository', action='find_workflows', webapp=webapp )}">Search for workflows</a></li></ul> %endif diff -r f33269063dab72e84f1ba7cb1ebc509ee73651e8 -r e598a3e78079064fcde5b709fac17bf58153d82a templates/webapps/community/repository/find_workflows.mako --- a/templates/webapps/community/repository/find_workflows.mako +++ b/templates/webapps/community/repository/find_workflows.mako @@ -13,7 +13,7 @@ %if webapp == 'galaxy': <br/><br/><ul class="manage-table-actions"> - <li><a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_repositories', webapp=webapp )}">Browse valid repositories</a></li> + <li><a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_categories', webapp=webapp )}">Browse valid repositories</a></li><a class="action-button" href="${h.url_for( controller='repository', action='find_tools', webapp=webapp )}">Search for valid tools</a></ul> %endif diff -r f33269063dab72e84f1ba7cb1ebc509ee73651e8 -r e598a3e78079064fcde5b709fac17bf58153d82a templates/webapps/community/repository/preview_tools_in_changeset.mako --- a/templates/webapps/community/repository/preview_tools_in_changeset.mako +++ b/templates/webapps/community/repository/preview_tools_in_changeset.mako @@ -67,7 +67,7 @@ <li><a class="action-button" href="${h.url_for( controller='repository', action='install_repositories_by_revision', repository_ids=trans.security.encode_id( repository.id ), webapp=webapp, changeset_revisions=changeset_revision )}">Install to local Galaxy</a></li><li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Tool Shed Actions</a></li><div popupmenu="repository-${repository.id}-popup"> - <a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_repositories', webapp=webapp )}">Browse valid repositories</a> + <a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_categories', webapp=webapp )}">Browse valid repositories</a><a class="action-button" href="${h.url_for( controller='repository', action='find_tools', webapp=webapp )}">Search for valid tools</a><a class="action-button" href="${h.url_for( controller='repository', action='find_workflows', webapp=webapp )}">Search for workflows</a></div> diff -r f33269063dab72e84f1ba7cb1ebc509ee73651e8 -r e598a3e78079064fcde5b709fac17bf58153d82a templates/webapps/community/repository/tool_form.mako --- a/templates/webapps/community/repository/tool_form.mako +++ b/templates/webapps/community/repository/tool_form.mako @@ -128,7 +128,7 @@ </div><li><a class="action-button" id="tool_shed-${repository.id}-popup" class="menubutton">Tool Shed Actions</a></li><div popupmenu="tool_shed-${repository.id}-popup"> - <a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_repositories', webapp=webapp )}">Browse valid repositories</a> + <a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_categories', webapp=webapp )}">Browse valid repositories</a><a class="action-button" href="${h.url_for( controller='repository', action='find_tools', webapp=webapp )}">Search for valid tools</a><a class="action-button" href="${h.url_for( controller='repository', action='find_workflows', webapp=webapp )}">Search for workflows</a></div> diff -r f33269063dab72e84f1ba7cb1ebc509ee73651e8 -r e598a3e78079064fcde5b709fac17bf58153d82a templates/webapps/community/repository/view_repository.mako --- a/templates/webapps/community/repository/view_repository.mako +++ b/templates/webapps/community/repository/view_repository.mako @@ -97,7 +97,7 @@ <li><a class="action-button" href="${h.url_for( controller='repository', action='install_repositories_by_revision', repository_ids=trans.security.encode_id( repository.id ), webapp=webapp, changeset_revisions=changeset_revision )}">Install to local Galaxy</a></li><li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Tool Shed Actions</a></li><div popupmenu="repository-${repository.id}-popup"> - <a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_repositories', webapp=webapp )}">Browse valid repositories</a> + <a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_categories', webapp=webapp )}">Browse valid repositories</a><a class="action-button" href="${h.url_for( controller='repository', action='find_tools', webapp=webapp )}">Search for valid tools</a><a class="action-button" href="${h.url_for( controller='repository', action='find_workflows', webapp=webapp )}">Search for workflows</a></div> diff -r f33269063dab72e84f1ba7cb1ebc509ee73651e8 -r e598a3e78079064fcde5b709fac17bf58153d82a templates/webapps/community/repository/view_tool_metadata.mako --- a/templates/webapps/community/repository/view_tool_metadata.mako +++ b/templates/webapps/community/repository/view_tool_metadata.mako @@ -41,7 +41,7 @@ </div><li><a class="action-button" id="tool_shed-${repository.id}-popup" class="menubutton">Tool Shed Actions</a></li><div popupmenu="tool_shed-${repository.id}-popup"> - <a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_repositories', webapp=webapp )}">Browse valid repositories</a> + <a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_categories', webapp=webapp )}">Browse valid repositories</a><a class="action-button" href="${h.url_for( controller='repository', action='find_tools', webapp=webapp )}">Search for valid tools</a><a class="action-button" href="${h.url_for( controller='repository', action='find_workflows', webapp=webapp )}">Search for workflows</a></div> diff -r f33269063dab72e84f1ba7cb1ebc509ee73651e8 -r e598a3e78079064fcde5b709fac17bf58153d82a templates/webapps/community/repository/view_workflow.mako --- a/templates/webapps/community/repository/view_workflow.mako +++ b/templates/webapps/community/repository/view_workflow.mako @@ -81,7 +81,7 @@ </div><li><a class="action-button" id="toolshed-${repository.id}-popup" class="menubutton">Tool Shed Actions</a></li><div popupmenu="toolshed-${repository.id}-popup"> - <a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_repositories', webapp=webapp )}">Browse valid repositories</a> + <a class="action-button" href="${h.url_for( controller='repository', action='browse_valid_categories', webapp=webapp )}">Browse valid repositories</a><a class="action-button" href="${h.url_for( controller='repository', action='find_tools', webapp=webapp )}">Search for valid tools</a><a class="action-button" href="${h.url_for( controller='repository', action='find_workflows', webapp=webapp )}">Search for workflows</a></div> 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.