1 new changeset in galaxy-central: http://bitbucket.org/galaxy/galaxy-central/changeset/29a8fa81b603/ changeset: 29a8fa81b603 user: greg date: 2011-09-02 20:59:31 summary: Add the ability for a Galaxy administrator to automatically install tools from a configured Galaxy tool shed into their local Galaxy installation. Documentation will be available in the tool shed wiki shortly. affected #: 9 files (44.9 KB) --- a/lib/galaxy/web/base/controller.py Fri Sep 02 14:57:33 2011 -0400 +++ b/lib/galaxy/web/base/controller.py Fri Sep 02 14:59:31 2011 -0400 @@ -1,8 +1,9 @@ """ Contains functionality needed in every web interface """ -import os, time, logging, re, string, sys, glob -from datetime import datetime, timedelta +import os, time, logging, re, string, sys, glob, shutil, tempfile, subprocess +from datetime import * +from time import strftime from galaxy import config, tools, web, util from galaxy.web import error, form, url_for from galaxy.model.orm import * @@ -15,6 +16,10 @@ from Cheetah.Template import Template + +pkg_resources.require( 'elementtree' ) +from elementtree import ElementTree, ElementInclude + log = logging.getLogger( __name__ ) # States for passing messages @@ -1153,22 +1158,14 @@ params = util.Params( kwd ) message = util.restore_text( params.get( 'message', '' ) ) status = params.get( 'status', 'done' ) + toolbox = self.app.toolbox + if params.get( 'reload_tool_button', False ): + tool_id = params.tool_id + message, status = toolbox.reload_tool_by_id( tool_id ) return trans.fill_template( '/admin/reload_tool.mako', - toolbox=self.app.toolbox, + toolbox=toolbox, message=message, status=status ) - @web.expose - @web.require_admin - def tool_reload( self, trans, tool_version=None, **kwd ): - params = util.Params( kwd ) - tool_id = params.tool_id - self.app.toolbox.reload( tool_id ) - message = 'Reloaded tool: ' + tool_id - return trans.fill_template( '/admin/reload_tool.mako', - toolbox=self.app.toolbox, - message=message, - status='done' ) - # Galaxy Role Stuff @web.expose @web.require_admin @@ -2693,9 +2690,268 @@ msg = msg, status = status, job_lock = trans.app.job_manager.job_queue.job_lock ) + @web.expose + @web.require_admin + def browse_tool_shed( self, trans, **kwd ): + tool_shed_name = kwd[ 'tool_shed_name' ] + tool_shed_url = kwd[ 'tool_shed_url' ] + galaxy_url = trans.request.host + url = '%s/repository/browse_downloadable_repositories?tool_shed_name=%s&galaxy_url=%s&webapp=community' % ( tool_shed_url, tool_shed_name, galaxy_url ) + return trans.response.send_redirect( url ) + @web.expose + @web.require_admin + def install_tool_shed_repository( self, trans, **kwd ): + params = util.Params( kwd ) + message = util.restore_text( params.get( 'message', '' ) ) + status = params.get( 'status', 'done' ) + tool_shed_url = kwd[ 'tool_shed_url' ] + repository_name = kwd[ 'repository_name' ] + changeset_revision = kwd[ 'changeset_revision' ] + repository_clone_url = kwd[ 'repository_clone_url' ] + if kwd.get( 'select_tool_panel_section_button', False ): + shed_tool_conf = kwd[ 'shed_tool_conf' ] + # Get the tool path. + for k, tool_path in trans.app.toolbox.shed_tool_confs.items(): + if k == shed_tool_conf: + break + if 'tool_panel_section' in kwd: + section_key = 'section_%s' % kwd[ 'tool_panel_section' ] + tool_section = trans.app.toolbox.tool_panel[ section_key ] + # Clone the repository to the configured location. + current_working_dir = os.getcwd() + clone_dir = os.path.join( tool_path, self.__generate_tool_path( repository_clone_url, changeset_revision ) ) + if os.path.exists( clone_dir ): + # Repository and revision has already been cloned. + # TODO: implement the ability to re-install or revert an existing repository. + message = 'Revision <b>%s</b> of repository <b>%s</b> has already been installed. Updating an existing repository is not yet supported.' % \ + ( changeset_revision, repository_name ) + status = 'error' + else: + os.makedirs( clone_dir ) + cmd = 'hg clone %s' % repository_clone_url + log.debug( 'Cloning: %s' % repository_clone_url ) + tmp_name = tempfile.NamedTemporaryFile().name + tmp_stderr = open( tmp_name, 'wb' ) + os.chdir( clone_dir ) + proc = subprocess.Popen( args=cmd, shell=True, stderr=tmp_stderr.fileno() ) + returncode = proc.wait() + os.chdir( current_working_dir ) + tmp_stderr.close() + if returncode == 0: + repo_files_dir = os.path.join( clone_dir, repository_name ) + log.debug( 'Updating cloned repository to revision: %s' % changeset_revision ) + cmd = 'hg update -r %s' % changeset_revision + tmp_name = tempfile.NamedTemporaryFile().name + tmp_stderr = open( tmp_name, 'wb' ) + os.chdir( repo_files_dir ) + proc = subprocess.Popen( cmd, shell=True, stderr=tmp_stderr.fileno() ) + returncode = proc.wait() + os.chdir( current_working_dir ) + tmp_stderr.close() + if returncode == 0: + # The repository_tools_tups list contains tuples of ( relative_path_to_tool_config, tool ) pairs + repository_tools_tups = [] + for root, dirs, files in os.walk( repo_files_dir ): + if not root.find( '.hg' ) >= 0 and not root.find( 'hgrc' ) >= 0: + if '.hg' in dirs: + # Don't visit .hg directories - should be impossible since we don't + # allow uploaded archives that contain .hg dirs, but just in case... + dirs.remove( '.hg' ) + if 'hgrc' in files: + # Don't include hgrc files in commit. + files.remove( 'hgrc' ) + for name in files: + # Find all tool configs. + if name.endswith( '.xml' ): + relative_path = os.path.join( root, name ) + full_path = os.path.abspath( os.path.join( root, name ) ) + try: + repository_tool = trans.app.toolbox.load_tool( full_path ) + if repository_tool: + repository_tools_tups.append( ( relative_path.lstrip( '%s/' % tool_path ), repository_tool ) ) + except Exception, e: + # We have an inavlid .xml file, so not a tool config. + log.debug("Ignoring invalid tool config (%s)." % str( relative_path )) + if repository_tools_tups: + # Generate an in-memory tool conf section that includes the new tools. + new_tool_section = self.__generate_tool_panel_section( repository_name, + repository_clone_url, + changeset_revision, + tool_section, + repository_tools_tups ) + # Create a temporary file to persist the in-memory tool section + # TODO: Figure out how to do this in-memory using xml.etree. + tmp_name = tempfile.NamedTemporaryFile().name + persisted_new_tool_section = open( tmp_name, 'wb' ) + persisted_new_tool_section.write( new_tool_section ) + persisted_new_tool_section.close() + # Parse the persisted tool panel section + tree = ElementTree.parse( tmp_name ) + root = tree.getroot() + ElementInclude.include( root ) + # Load the tools in the section into the tool panel. + trans.app.toolbox.load_section_tag_set( root, trans.app.toolbox.tool_panel, tool_path ) + # Remove the temporary file + try: + os.unlink( tmp_name ) + except: + pass + # Append the new section to the shed_tool_config file. + self.__add_shed_tool_conf_entry( trans, shed_tool_conf, new_tool_section ) + message = 'Revision <b>%s</b> of repository <b>%s</b> has been installed in tool panel section <b>%s</b>.' % \ + ( changeset_revision, repository_name, tool_section.name ) + return trans.show_ok_message( message ) + else: + tmp_stderr = open( tmp_name, 'rb' ) + message = tmp_stderr.read() + tmp_stderr.close() + status = 'error' + else: + tmp_stderr = open( tmp_name, 'rb' ) + message = tmp_stderr.read() + tmp_stderr.close() + status = 'error' + else: + message = 'Choose the section in your tool panel to contain the installed tools.' + status = 'error' + if len( trans.app.toolbox.shed_tool_confs.keys() ) > 1: + shed_tool_conf_select_field = build_shed_tool_conf_select_field( trans ) + shed_tool_conf = None + else: + shed_tool_conf = trans.app.toolbox.shed_tool_confs.keys()[0].lstrip( './' ) + shed_tool_conf_select_field = None + tool_panel_section_select_field = build_tool_panel_section_select_field( trans ) + return trans.fill_template( '/admin/select_tool_panel_section.mako', + tool_shed_url=tool_shed_url, + repository_name=repository_name, + changeset_revision=changeset_revision, + repository_clone_url=repository_clone_url, + shed_tool_conf=shed_tool_conf, + shed_tool_conf_select_field=shed_tool_conf_select_field, + tool_panel_section_select_field=tool_panel_section_select_field, + message=message, + status=status ) + def __add_shed_tool_conf_entry( self, trans, shed_tool_conf, new_tool_section ): + # Add an entry in the shed_tool_conf file. An entry looks something like: + # <section name="Filter and Sort" id="filter"> + # <tool file="filter/filtering.xml" guid="toolshed.g2.bx.psu.edu/repos/test/filter/1.0.2"/> + # </section> + # Make a backup of the hgweb.config file since we're going to be changing it. + if not os.path.exists( shed_tool_conf ): + output = open( shed_tool_conf, 'w' ) + output.write( '<?xml version="1.0"?>\n' ) + output.write( '<toolbox tool_path="%s">\n' % tool_path ) + output.write( '</toolbox>\n' ) + output.close() + self.__make_shed_tool_conf_copy( trans, shed_tool_conf ) + tmp_fd, tmp_fname = tempfile.mkstemp() + new_shed_tool_conf = open( tmp_fname, 'wb' ) + for i, line in enumerate( open( shed_tool_conf ) ): + if line.startswith( '</toolbox>' ): + # We're at the end of the original config file, so add our entry. + new_shed_tool_conf.write( new_tool_section ) + new_shed_tool_conf.write( line ) + else: + new_shed_tool_conf.write( line ) + new_shed_tool_conf.close() + shutil.move( tmp_fname, os.path.abspath( shed_tool_conf ) ) + def __make_shed_tool_conf_copy( self, trans, shed_tool_conf ): + # Make a backup of the shed_tool_conf file. + today = date.today() + backup_date = today.strftime( "%Y_%m_%d" ) + shed_tool_conf_copy = '%s/%s_%s_backup' % ( trans.app.config.root, shed_tool_conf, backup_date ) + shutil.copy( os.path.abspath( shed_tool_conf ), os.path.abspath( shed_tool_conf_copy ) ) + def __clean_tool_shed_url( self, tool_shed_url ): + if tool_shed_url.find( ':' ) > 0: + # Eliminate the port, if any, since it will result in an invalid directory name. + return tool_shed_url.split( ':' )[ 0 ] + return tool_shed_url + def __clean_repository_clone_url( self, repository_clone_url ): + if repository_clone_url.find( '@' ) > 0: + # We have an url that includes an authenticated user, something like: + # http://test@bx.psu.edu:9009/repos/some_username/column + items = repository_clone_url.split( '@' ) + tmp_url = items[ 1 ] + elif repository_clone_url.find( '\/\/' ) > 0: + # We have an url that includes only a protocol, something like: + # http://bx.psu.edu:9009/repos/some_username/column + items = repository_clone_url.split( '\/\/' ) + tmp_url = items[ 1 ] + else: + tmp_url = repository_clone_url + return tmp_url + def __get_repository_owner( self, cleaned_repository_url ): + items = cleaned_repository_url.split( 'repos' ) + repo_path = items[ 1 ] + return repo_path.lstrip( '/' ).split( '/' )[ 0 ] + def __generate_tool_path( self, repository_clone_url, changeset_revision ): + """ + Generate a tool path that guarantees repositories with the same name will always be installed + in different directories. The tool path will be of the form: + <tool shed url>/repos/<repository owner>/<repository name>/<changeset revision> + http://test@gvk.bx.psu.edu:9009/repos/test/filter + """ + tmp_url = self.__clean_repository_clone_url( repository_clone_url ) + # Now tmp_url is something like: bx.psu.edu:9009/repos/some_username/column + items = tmp_url.split( 'repos' ) + tool_shed_url = items[ 0 ] + repo_path = items[ 1 ] + tool_shed_url = self.__clean_tool_shed_url( tool_shed_url ) + return '%s/repos%s/%s' % ( tool_shed_url, repo_path, changeset_revision ) + def __generate_tool_guid( self, repository_clone_url, tool ): + """ + Generate a guid for the installed tool. It is critical that this guid matches the guid for + the tool in the Galaxy tool shed from which it is being installed. The form of the guid is + <tool shed host>/repos/<repository owner>/<repository name>/<tool id>/<tool version> + """ + tmp_url = self.__clean_repository_clone_url( repository_clone_url ) + return '%s/%s/%s' % ( tmp_url, tool.id, tool.version ) + def __generate_tool_panel_section( self, repository_name, repository_clone_url, changeset_revision, tool_section, repository_tools_tups ): + """ + Write an in-memory tool panel section so we can load it into the tool panel and then + append it to the appropriate shed tool config. + """ + tmp_url = self.__clean_repository_clone_url( repository_clone_url ) + section_str = '' + section_str += ' <section name="%s" id="%s">\n' % ( tool_section.name, tool_section.id ) + for repository_tool_tup in repository_tools_tups: + tool_file_path, tool = repository_tool_tup + guid = self.__generate_tool_guid( repository_clone_url, tool ) + section_str += ' <tool file="%s" guid="%s">\n' % ( tool_file_path, guid ) + section_str += ' <tool_shed>%s</tool_shed>\n' % tmp_url.split( 'repos' )[ 0 ].rstrip( '/' ) + section_str += ' <repository_name>%s</repository_name>\n' % repository_name + section_str += ' <repository_owner>%s</repository_owner>\n' % self.__get_repository_owner( tmp_url ) + section_str += ' <changeset_revision>%s</changeset_revision>\n' % changeset_revision + section_str += ' <id>%s</id>\n' % tool.id + section_str += ' <version>%s</version>\n' % tool.version + section_str += ' </tool>\n' + section_str += ' </section>\n' + return section_str ## ---- Utility methods ------------------------------------------------------- +def build_shed_tool_conf_select_field( trans ): + """ + Build a SelectField whose options are the keys in trans.app.toolbox.shed_tool_confs. + """ + options = [] + for shed_tool_conf_filename, tool_path in trans.app.toolbox.shed_tool_confs.items(): + options.append( ( shed_tool_conf_filename.lstrip( './' ), shed_tool_conf_filename ) ) + select_field = SelectField( name='shed_tool_conf' ) + for option_tup in options: + select_field.add_option( option_tup[0], option_tup[1] ) + return select_field +def build_tool_panel_section_select_field( trans ): + """ + Build a SelectField whose options are the sections of the current in-memory toolbox. + """ + options = [] + for k, tool_section in trans.app.toolbox.tool_panel.items(): + options.append( ( tool_section.name, tool_section.id ) ) + select_field = SelectField( name='tool_panel_section', display='radio' ) + for option_tup in options: + select_field.add_option( option_tup[0], option_tup[1] ) + return select_field def get_user( trans, id ): """Get a User from the database by id.""" # Load user from database --- a/lib/galaxy/webapps/community/controllers/common.py Fri Sep 02 14:57:33 2011 -0400 +++ b/lib/galaxy/webapps/community/controllers/common.py Fri Sep 02 14:59:31 2011 -0400 @@ -145,6 +145,14 @@ # The received metadata_dict includes no metadata for workflows, so a new repository_metadata table # record is not needed. return False +def generate_clone_url( trans, repository_id ): + repository = get_repository( trans, repository_id ) + protocol, base = trans.request.base.split( '://' ) + if trans.user: + username = '%s@' % trans.user.username + else: + username = '' + return '%s://%s%s/repos/%s/%s' % ( protocol, username, base, repository.user.username, repository.name ) def generate_tool_guid( trans, repository, tool ): """ Generate a guid for the received tool. The form of the guid is @@ -478,7 +486,7 @@ 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 ): +def build_changeset_revision_select_field( trans, repository, selected_value=None, add_id_to_name=True, galaxy_url=None ): """ Build a SelectField whose options are the changeset_revision strings of all downloadable_revisions of the received repository. @@ -492,9 +500,15 @@ options.append( ( revision_label, changeset_revision ) ) refresh_on_change_values.append( changeset_revision ) if add_id_to_name: - name = 'changeset_revision_%d' % repository.id + if galaxy_url: + name = '%s_changeset_revision_%d' % ( galaxy_url, repository.id ) + else: + name = 'changeset_revision_%d' % repository.id else: - name = 'changeset_revision' + if galaxy_url: + name = '%s_changeset_revision' % galaxy_url + else: + name = 'changeset_revision' select_field = SelectField( name=name, refresh_on_change=True, refresh_on_change_values=refresh_on_change_values ) --- a/lib/galaxy/webapps/community/controllers/repository.py Fri Sep 02 14:57:33 2011 -0400 +++ b/lib/galaxy/webapps/community/controllers/repository.py Fri Sep 02 14:59:31 2011 -0400 @@ -123,6 +123,7 @@ return 'yes' return '' # Grid definition + galaxy_url = None title = "Repositories" model_class = model.Repository template='/webapps/community/repository/grid.mako' @@ -183,8 +184,48 @@ .outerjoin( model.RepositoryCategoryAssociation.table ) \ .outerjoin( model.Category.table ) +class DownloadableRepositoryListGrid( RepositoryListGrid ): + 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 downloadable_revisions of this repository. + """ + select_field = build_changeset_revision_select_field( trans, + repository, + galaxy_url=grid.galaxy_url ) + if len( select_field.options ) > 1: + return select_field.get_html() + return repository.revision + columns = [ + RepositoryListGrid.NameColumn( "Name", + key="name", + attach_popup=True ), + RepositoryListGrid.DescriptionColumn( "Synopsis", + key="description", + attach_popup=False ), + RevisionColumn( "Revision" ), + RepositoryListGrid.UserColumn( "Owner", + model_class=model.User, + attach_popup=False, + key="User.username" ) + ] + 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 ): + return trans.sa_session.query( self.model_class ) \ + .join( model.RepositoryMetadata.table ) \ + .join( model.User.table ) + class RepositoryController( BaseController, ItemRatings ): + downloadable_repository_list_grid = DownloadableRepositoryListGrid() repository_list_grid = RepositoryListGrid() category_list_grid = CategoryListGrid() @@ -215,6 +256,111 @@ # Render the list view return self.category_list_grid( trans, **kwd ) @web.expose + def browse_downloadable_repositories( self, trans, **kwd ): + tool_shed_name = kwd.get( 'tool_shed_name', None ) + repository_id = kwd.get( 'id', None ) + galaxy_url = kwd.get( 'galaxy_url', None ) + if 'operation' in kwd: + operation = kwd[ 'operation' ].lower() + if operation == "preview_tools_in_changeset": + repository = get_repository( trans, repository_id ) + return trans.response.send_redirect( web.url_for( controller='repository', + action='preview_tools_in_changeset', + repository_id=repository_id, + changeset_revision=repository.tip, + galaxy_url=galaxy_url ) ) + + # 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='preview_tools_in_changeset', + repository_id=trans.security.encode_id( repository.id ), + changeset_revision=v, + galaxy_url=galaxy_url ) ) + elif k.find( changset_revision_str ) > 0: + # Keys look like: 'localhost:8763_changeset_revision_3' and values: '4ef2cf631604'. + items = k.split( '_%s' % changset_revision_str ) + galaxy_url = items[0] + repository_id = trans.security.encode_id( int( items[1] ) ) + repository = get_repository( trans, repository_id ) + if repository.tip != v: + return trans.response.send_redirect( web.url_for( controller='repository', + action='preview_tools_in_changeset', + repository_id=trans.security.encode_id( repository.id ), + changeset_revision=v, + galaxy_url=galaxy_url ) ) + + if tool_shed_name: + title = "%s downloadable repositories" % tool_shed_name + else: + title = "Downloadable repositories" + self.downloadable_repository_list_grid.title = title + self.downloadable_repository_list_grid.galaxy_url = galaxy_url + url_args = dict( action='browse_downloadable_repositories', + operation='preview_tools_in_changeset', + repository_id=repository_id, + galaxy_url=galaxy_url ) + self.downloadable_repository_list_grid.operations = [ grids.GridOperation( "Preview and install tools", + url_args=url_args, + allow_multiple=False, + async_compatible=False ) ] + + # Render the list view + return self.downloadable_repository_list_grid( trans, **kwd ) + @web.expose + def preview_tools_in_changeset( self, trans, repository_id, **kwd ): + params = util.Params( kwd ) + message = util.restore_text( params.get( 'message', '' ) ) + status = params.get( 'status', 'done' ) + galaxy_url = util.restore_text( params.get( 'galaxy_url', '' ) ) + repository = get_repository( trans, repository_id ) + changeset_revision = util.restore_text( params.get( 'changeset_revision', repository.tip ) ) + repository_metadata = get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision ) + if repository_metadata: + metadata = repository_metadata.metadata + else: + metadata = None + revision_label = get_revision_label( trans, repository, changeset_revision ) + changeset_revision_select_field = build_changeset_revision_select_field( trans, + repository, + selected_value=changeset_revision, + add_id_to_name=False ) + return trans.fill_template( '/webapps/community/repository/preview_tools_in_changeset.mako', + repository=repository, + changeset_revision=changeset_revision, + revision_label=revision_label, + changeset_revision_select_field=changeset_revision_select_field, + metadata=metadata, + galaxy_url=galaxy_url, + display_for_install=True, + message=message, + status=status ) + @web.expose + def install_repository_revision( self, trans, repository_id, **kwd ): + params = util.Params( kwd ) + message = util.restore_text( params.get( 'message', '' ) ) + status = params.get( 'status', 'done' ) + galaxy_url = util.restore_text( params.get( 'galaxy_url', '' ) ) + repository = get_repository( trans, repository_id ) + changeset_revision = util.restore_text( params.get( 'changeset_revision', repository.tip ) ) + # Redirect back to local Galaxy to perform install. + tool_shed_url = trans.request.host + repository_clone_url = generate_clone_url( trans, repository_id ) + # TODO: support https in the following url. + url = 'http://%s/admin/install_tool_shed_repository?tool_shed_url=%s&repository_name=%s&repository_clone_url=%s&changeset_revision=%s' % \ + ( galaxy_url, tool_shed_url, repository.name, repository_clone_url, changeset_revision ) + return trans.response.send_redirect( url ) + @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 @@ -1079,45 +1225,57 @@ params = util.Params( kwd ) message = util.restore_text( params.get( 'message', '' ) ) status = params.get( 'status', 'done' ) + galaxy_url = util.restore_text( params.get( 'galaxy_url', '' ) ) + display_for_install = util.string_as_bool( params.get( 'display_for_install', False ) ) repository = get_repository( trans, repository_id ) - old_version_msg = "The path to your selected version of this tool does not exist in the repository tip, " + \ - "so it cannot be previewed, but you can inspect the tool version's metadata using it's pop-up menu " + \ - "and you can download your selected version of this tool from the <b>Repository Actions</b> menu." + repo = hg.repository( get_configured_ui(), repository.repo_path ) try: - tool = load_tool( trans, os.path.abspath( tool_config ) ) - can_preview = True - if changeset_revision != repository.tip: - # See if we are attempting to preview an old version of a tool. - # TODO: Previewing an old version of a tool is not currently supported because - # the received tool_config is a file on the file system. We need to implement - # an enhancement here to look at the repository manifest files if previewing an - # old version of a tool. - repo_changeset_repository_metadata = get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision ) - repo_changeset_metadata = repo_changeset_repository_metadata.metadata - if 'tools' in repo_changeset_metadata: - for tool_metadata_dict in repo_changeset_metadata[ 'tools' ]: - if tool_metadata_dict[ 'id' ] == tool.id: - if tool_metadata_dict[ 'version' ] != tool.version: - can_preview = False - message = old_version_msg - if can_preview: - tool_state = self.__new_state( trans ) - is_malicious = change_set_is_malicious( trans, repository_id, repository.tip ) - return trans.fill_template( "/webapps/community/repository/tool_form.mako", - repository=repository, - tool=tool, - tool_state=tool_state, - is_malicious=is_malicious, - message=message, - status=status ) + if changeset_revision == repository.tip: + # Get the tool config from the file system we use for browsing. + tool = load_tool( trans, os.path.abspath( tool_config ) ) + else: + # Get the tool config file name from the hgweb url, something like: + # /repos/test/convert_chars1/file/e58dcf0026c7/convert_characters.xml + old_tool_config_file_name = tool_config.split( '/' )[ -1 ] + ctx = get_changectx_for_changeset( trans, repo, changeset_revision ) + for filename in ctx: + if filename == old_tool_config_file_name: + fctx = ctx[ filename ] + break + # Write the contents of the old tool config to a temporary file. + fh = tempfile.NamedTemporaryFile( 'w' ) + tmp_filename = fh.name + fh.close() + fh = open( tmp_filename, 'w' ) + fh.write( fctx.data() ) + fh.close() + tool = load_tool( trans, tmp_filename ) + try: + os.unlink( tmp_filename ) + except: + pass + tool_state = self.__new_state( trans ) + is_malicious = change_set_is_malicious( trans, repository_id, repository.tip ) + return trans.fill_template( "/webapps/community/repository/tool_form.mako", + repository=repository, + changeset_revision=changeset_revision, + tool=tool, + tool_state=tool_state, + is_malicious=is_malicious, + display_for_install=display_for_install, + galaxy_url=galaxy_url, + message=message, + status=status ) except Exception, e: - # TODO: enhance this to check the repository manifest for the files and - # display the tool using them. - exception_str = str( e ) - if exception_str.find( 'No such file or directory' ) >= 0: - message = old_version_msg - else: - message = "Error loading tool: %s. Click <b>Reset metadata</b> to correct this error." % exception_str + message = "Error loading tool: %s. Click <b>Reset metadata</b> to correct this error." % str( e ) + if display_for_install: + return trans.response.send_redirect( web.url_for( controller='repository', + action='preview_tools_in_changeset', + repository_id=repository_id, + changeset_revision=changeset_revision, + galaxy_url=galaxy_url, + message=message, + status='error' ) ) return trans.response.send_redirect( web.url_for( controller='repository', action='browse_repositories', operation='view_or_manage_repository', --- a/templates/webapps/community/repository/common.mako Fri Sep 02 14:57:33 2011 -0400 +++ b/templates/webapps/community/repository/common.mako Fri Sep 02 14:59:31 2011 -0400 @@ -77,12 +77,121 @@ <%def name="render_clone_str( repository )"><% - protocol, base = trans.request.base.split( '://' ) - if trans.user: - username = '%s@' % trans.user.username - else: - username = '' - clone_str = '%s://%s%s/repos/%s/%s' % ( protocol, username, base, repository.user.username, repository.name ) + from galaxy.webapps.community.controllers.common import generate_clone_url + clone_str = generate_clone_url( trans, trans.security.encode_id( repository.id ) ) %> hg clone <a href="${clone_str}">${clone_str}</a></%def> + +<%def name="render_repository_tools_and_workflows( metadata, can_set_metadata=False, display_for_install=False, galaxy_url=None )"> + %if metadata or can_set_metadata: + <p/> + <div class="toolForm"> + <div class="toolFormTitle">Preview tools and inspect metadata by tool version</div> + <div class="toolFormBody"> + %if metadata: + %if 'tools' in metadata: + <div class="form-row"> + <table width="100%"> + <tr bgcolor="#D8D8D8" width="100%"> + <td><b>Tools</b><i> - click the name to preview the tool and use the pop-up menu to inspect all metadata</i></td> + </tr> + </table> + </div> + <div class="form-row"> + <% tool_dicts = metadata[ 'tools' ] %> + <table class="grid"> + <tr> + <td><b>name</b></td> + <td><b>description</b></td> + <td><b>version</b></td> + <td><b>requirements</b></td> + </tr> + %for tool_dict in tool_dicts: + <tr> + <td> + <div style="float: left; margin-left: 1px;" class="menubutton split popup" id="tool-${tool_dict[ 'id' ].replace( ' ', '_' )}-popup"> + <a class="view-info" href="${h.url_for( controller='repository', action='display_tool', repository_id=trans.security.encode_id( repository.id ), tool_config=tool_dict[ 'tool_config' ], changeset_revision=changeset_revision, display_for_install=display_for_install, galaxy_url=galaxy_url )}"> + ${tool_dict[ 'name' ]} + </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=changeset_revision, tool_id=tool_dict[ 'id' ], display_for_install=display_for_install, galaxy_url=galaxy_url )}">View tool metadata</a> + </div> + </td> + <td>${tool_dict[ 'description' ]}</td> + <td>${tool_dict[ 'version' ]}</td> + <td> + <% + if 'requirements' in tool_dict: + requirements = tool_dict[ 'requirements' ] + else: + requirements = None + %> + %if requirements: + <% + requirements_str = '' + for requirement_dict in tool_dict[ 'requirements' ]: + requirements_str += '%s (%s), ' % ( requirement_dict[ 'name' ], requirement_dict[ 'type' ] ) + requirements_str = requirements_str.rstrip( ', ' ) + %> + ${requirements_str} + %else: + none + %endif + </td> + </tr> + %endfor + </table> + </div> + <div style="clear: both"></div> + %endif + %if 'workflows' in metadata: + <div class="form-row"> + <table width="100%"> + <tr bgcolor="#D8D8D8" width="100%"> + <td><b>Workflows</b></td> + </tr> + </table> + </div> + <div style="clear: both"></div> + <div class="form-row"> + <% workflow_dicts = metadata[ 'workflows' ] %> + <table class="grid"> + <tr> + <td><b>name</b></td> + <td><b>format-version</b></td> + <td><b>annotation</b></td> + </tr> + %for workflow_dict in workflow_dicts: + <tr> + <td>${workflow_dict[ 'name' ]}</td> + <td>${workflow_dict[ 'format-version' ]}</td> + <td>${workflow_dict[ 'annotation' ]}</td> + </tr> + %endfor + </table> + </div> + <div style="clear: both"></div> + %endif + %endif + %if can_set_metadata: + %if repository.tip == changeset_revision: + ## TODO: when we support previewing older versions of tools, we + ## should allow resetting metadata on the older versions as well. + <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"/> + </div> + <div class="toolParamHelp" style="clear: both;"> + Inspect the repository and reset the above attributes for the repository tip. + </div> + </div> + </form> + %endif + %endif + </div> + </div> + %endif +</%def> --- a/templates/webapps/community/repository/manage_repository.mako Fri Sep 02 14:57:33 2011 -0400 +++ b/templates/webapps/community/repository/manage_repository.mako Fri Sep 02 14:59:31 2011 -0400 @@ -184,114 +184,7 @@ </form></div></div> -%if can_set_metadata: - <p/> - <div class="toolForm"> - <div class="toolFormTitle">Preview tools in repository tip and inspect metadata by tool version</div> - <div class="toolFormBody"> - %if metadata: - %if 'tools' in metadata: - <div class="form-row"> - <table width="100%"> - <tr bgcolor="#D8D8D8" width="100%"> - <td><b>Tools</b><i> - click the name to preview the tool and use the pop-up menu to inspect all metadata</i></td> - </tr> - </table> - </div> - <div class="form-row"> - <% tool_dicts = metadata[ 'tools' ] %> - <table class="grid"> - <tr> - <td><b>name</b></td> - <td><b>description</b></td> - <td><b>version</b></td> - <td><b>requirements</b></td> - </tr> - %for tool_dict in tool_dicts: - <tr> - <td> - <div style="float: left; margin-left: 1px;" class="menubutton split popup" id="tool-${tool_dict[ 'id' ].replace( ' ', '_' )}-popup"> - <a class="view-info" href="${h.url_for( controller='repository', action='display_tool', repository_id=trans.security.encode_id( repository.id ), tool_config=tool_dict[ 'tool_config' ], changeset_revision=changeset_revision )}"> - ${tool_dict[ 'name' ]} - </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=changeset_revision, tool_id=tool_dict[ 'id' ] )}">View tool metadata</a> - </div> - </td> - <td>${tool_dict[ 'description' ]}</td> - <td>${tool_dict[ 'version' ]}</td> - <td> - <% - if 'requirements' in tool_dict: - requirements = tool_dict[ 'requirements' ] - else: - requirements = None - %> - %if requirements: - <% - requirements_str = '' - for requirement_dict in tool_dict[ 'requirements' ]: - requirements_str += '%s (%s), ' % ( requirement_dict[ 'name' ], requirement_dict[ 'type' ] ) - requirements_str = requirements_str.rstrip( ', ' ) - %> - ${requirements_str} - %else: - none - %endif - </td> - </tr> - %endfor - </table> - </div> - <div style="clear: both"></div> - %endif - %if 'workflows' in metadata: - <div class="form-row"> - <table width="100%"> - <tr bgcolor="#D8D8D8" width="100%"> - <td><b>Workflows</b></td> - </tr> - </table> - </div> - <div style="clear: both"></div> - <div class="form-row"> - <% workflow_dicts = metadata[ 'workflows' ] %> - <table class="grid"> - <tr> - <td><b>name</b></td> - <td><b>format-version</b></td> - <td><b>annotation</b></td> - </tr> - %for workflow_dict in workflow_dicts: - <tr> - <td>${workflow_dict[ 'name' ]}</td> - <td>${workflow_dict[ 'format-version' ]}</td> - <td>${workflow_dict[ 'annotation' ]}</td> - </tr> - %endfor - </table> - </div> - <div style="clear: both"></div> - %endif - %endif - %if repository.tip == changeset_revision: - ## TODO: when we support previewing older versions of tools, we - ## should allow resetting metadata on the older versions as well. - <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"/> - </div> - <div class="toolParamHelp" style="clear: both;"> - Inspect the repository and reset the above attributes for the repository tip. - </div> - </div> - </form> - %endif - </div> - </div> -%endif +${render_repository_tools_and_workflows( metadata, can_set_metadata=True )} <p/><div class="toolForm"><div class="toolFormTitle">Manage categories</div> --- a/templates/webapps/community/repository/tool_form.mako Fri Sep 02 14:57:33 2011 -0400 +++ b/templates/webapps/community/repository/tool_form.mako Fri Sep 02 14:59:31 2011 -0400 @@ -25,7 +25,7 @@ <html><head> - <title>Galaxy tool display</title> + <title>Galaxy tool preview</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> ${h.css( "base" )} </head> @@ -110,37 +110,41 @@ <br/><br/><ul class="manage-table-actions"> - %if is_new: - <a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ), webapp='community' )}">Upload files to repository</a> + %if display_for_install: + <a class="action-button" href="${h.url_for( controller='repository', action='install_repository_revision', repository_id=trans.security.encode_id( repository.id ), webapp='community', changeset_revision=changeset_revision, galaxy_url=galaxy_url )}">Install to local Galaxy</a> %else: - <li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Repository Actions</a></li> - <div popupmenu="repository-${repository.id}-popup"> - %if can_manage: - <a class="action-button" href="${h.url_for( controller='repository', action='manage_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=repository.tip )}">Manage repository</a> - %else: - <a class="action-button" href="${h.url_for( controller='repository', action='view_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=repository.tip )}">View repository</a> - %endif - %if can_upload: - <a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ), webapp='community' )}">Upload files to repository</a> - %endif - %if can_view_change_log: - <a class="action-button" href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">View change log</a> - %endif - %if can_browse_contents: - <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_rate: - <a class="action-button" href="${h.url_for( controller='repository', action='rate_repository', id=trans.app.security.encode_id( repository.id ) )}">Rate repository</a> - %endif - %if can_contact_owner: - <a class="action-button" href="${h.url_for( controller='repository', action='contact_owner', id=trans.security.encode_id( repository.id ), webapp='community' )}">Contact repository owner</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 ), changeset_revision=repository.tip, 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=repository.tip, 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=repository.tip, file_type='zip' )}">Download as a zip file</a> - %endif - </div> + %if is_new: + <a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ), webapp='community' )}">Upload files to repository</a> + %else: + <li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Repository Actions</a></li> + <div popupmenu="repository-${repository.id}-popup"> + %if can_manage: + <a class="action-button" href="${h.url_for( controller='repository', action='manage_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage repository</a> + %else: + <a class="action-button" href="${h.url_for( controller='repository', action='view_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">View repository</a> + %endif + %if can_upload: + <a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ), webapp='community' )}">Upload files to repository</a> + %endif + %if can_view_change_log: + <a class="action-button" href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">View change log</a> + %endif + %if can_browse_contents: + <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_rate: + <a class="action-button" href="${h.url_for( controller='repository', action='rate_repository', id=trans.app.security.encode_id( repository.id ) )}">Rate repository</a> + %endif + %if can_contact_owner: + <a class="action-button" href="${h.url_for( controller='repository', action='contact_owner', id=trans.security.encode_id( repository.id ), webapp='community' )}">Contact repository owner</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 ), 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 %endif </ul> @@ -149,7 +153,7 @@ %endif <div class="toolForm" id="${tool.id}"> - <div class="toolFormTitle">${tool.name} ${tool.version}</div> + <div class="toolFormTitle">${tool.name} (version ${tool.version})</div><div class="toolFormBody"><form id="tool_form" name="tool_form" action="" method="get"><input type="hidden" name="tool_state" value="${util.object_to_string( tool_state.encode( tool, app ) )}"> --- a/templates/webapps/community/repository/view_repository.mako Fri Sep 02 14:57:33 2011 -0400 +++ b/templates/webapps/community/repository/view_repository.mako Fri Sep 02 14:59:31 2011 -0400 @@ -176,98 +176,7 @@ %endif </div></div> -%if metadata: - <p/> - <div class="toolForm"> - <div class="toolFormTitle">Preview tools in repository tip and inspect metadata by tool version</div> - <div class="toolFormBody"> - %if 'tools' in metadata: - <div class="form-row"> - <table width="100%"> - <tr bgcolor="#D8D8D8" width="100%"> - <td><b>Tools</b><i> - click the name to preview the tool and use the pop-up menu to inspect all metadata</i></td> - </tr> - </table> - </div> - <div class="form-row"> - <% tool_dicts = metadata[ 'tools' ] %> - <table class="grid"> - <tr> - <td><b>name</b></td> - <td><b>description</b></td> - <td><b>version</b></td> - <td><b>requirements</b></td> - </tr> - %for tool_dict in tool_dicts: - <tr> - <td> - <div style="float: left; margin-left: 1px;" class="menubutton split popup" id="tool-${tool_dict[ 'id' ].replace( ' ', '_' )}-popup"> - <a class="view-info" href="${h.url_for( controller='repository', action='display_tool', repository_id=trans.security.encode_id( repository.id ), tool_config=tool_dict[ 'tool_config' ], changeset_revision=changeset_revision )}"> - ${tool_dict[ 'name' ]} - </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=changeset_revision, tool_id=tool_dict[ 'id' ] )}">View tool metadata</a> - </div> - </td> - <td>${tool_dict[ 'description' ]}</td> - <td>${tool_dict[ 'version' ]}</td> - <td> - <% - if 'requirements' in tool_dict: - requirements = tool_dict[ 'requirements' ] - else: - requirements = None - %> - %if requirements: - <% - requirements_str = '' - for requirement_dict in tool_dict[ 'requirements' ]: - requirements_str += '%s (%s), ' % ( requirement_dict[ 'name' ], requirement_dict[ 'type' ] ) - requirements_str = requirements_str.rstrip( ', ' ) - %> - ${requirements_str} - %else: - none - %endif - </td> - </tr> - %endfor - </table> - </div> - <div style="clear: both"></div> - %endif - %if 'workflows' in metadata: - <div class="form-row"> - <table width="100%"> - <tr bgcolor="#D8D8D8" width="100%"> - <td><b>Workflows</b></td> - </tr> - </table> - </div> - <div style="clear: both"></div> - <div class="form-row"> - <% workflow_dicts = metadata[ 'workflows' ] %> - <table class="grid"> - <tr> - <td><b>name</b></td> - <td><b>format-version</b></td> - <td><b>annotation</b></td> - </tr> - %for workflow_dict in workflow_dicts: - <tr> - <td>${workflow_dict[ 'name' ]}</td> - <td>${workflow_dict[ 'format-version' ]}</td> - <td>${workflow_dict[ 'annotation' ]}</td> - </tr> - %endfor - </table> - </div> - <div style="clear: both"></div> - %endif - </div> - </div> -%endif +${render_repository_tools_and_workflows( metadata )} %if repository.categories: <p/><div class="toolForm"> --- a/templates/webapps/galaxy/admin/index.mako Fri Sep 02 14:57:33 2011 -0400 +++ b/templates/webapps/galaxy/admin/index.mako Fri Sep 02 14:59:31 2011 -0400 @@ -39,57 +39,59 @@ <div class="page-container" style="padding: 10px;"><div class="toolMenu"><div class="toolSectionList"> - <div class="toolSectionTitle"> - Security - </div> + <div class="toolSectionTitle">Security</div><div class="toolSectionBody"> - <div class="toolSectionBg"> - <div class="toolTitle"><a href="${h.url_for( controller='admin', action='users', webapp=webapp )}" target="galaxy_main">Manage users</a></div> - <div class="toolTitle"><a href="${h.url_for( controller='admin', action='groups', webapp=webapp )}" target="galaxy_main">Manage groups</a></div> - <div class="toolTitle"><a href="${h.url_for( controller='admin', action='roles', webapp=webapp )}" target="galaxy_main">Manage roles</a></div> - </div> + <div class="toolSectionBg"> + <div class="toolTitle"><a href="${h.url_for( controller='admin', action='users', webapp=webapp )}" target="galaxy_main">Manage users</a></div> + <div class="toolTitle"><a href="${h.url_for( controller='admin', action='groups', webapp=webapp )}" target="galaxy_main">Manage groups</a></div> + <div class="toolTitle"><a href="${h.url_for( controller='admin', action='roles', webapp=webapp )}" target="galaxy_main">Manage roles</a></div> + </div></div><div class="toolSectionPad"></div> - <div class="toolSectionTitle"> - Data - </div> + <div class="toolSectionTitle">Data</div><div class="toolSectionBody"> - <div class="toolSectionBg"> - <div class="toolTitle"><a href="${h.url_for( controller='admin', action='quotas', webapp=webapp )}" target="galaxy_main">Manage quotas</a></div> - <div class="toolTitle"><a href="${h.url_for( controller='library_admin', action='browse_libraries' )}" target="galaxy_main">Manage data libraries</a></div> - </div> + <div class="toolSectionBg"> + <div class="toolTitle"><a href="${h.url_for( controller='admin', action='quotas', webapp=webapp )}" target="galaxy_main">Manage quotas</a></div> + <div class="toolTitle"><a href="${h.url_for( controller='library_admin', action='browse_libraries' )}" target="galaxy_main">Manage data libraries</a></div> + </div></div><div class="toolSectionPad"></div> - <div class="toolSectionTitle"> - Server + <div class="toolSectionTitle">Server</div> + <div class="toolSectionBody"> + <div class="toolSectionBg"> + <div class="toolTitle"><a href="${h.url_for( controller='admin', action='reload_tool' )}" target="galaxy_main">Reload a tool's configuration</a></div> + <div class="toolTitle"><a href="${h.url_for( controller='admin', action='memdump' )}" target="galaxy_main">Profile memory usage</a></div> + <div class="toolTitle"><a href="${h.url_for( controller='admin', action='jobs' )}" target="galaxy_main">Manage jobs</a></div> + </div></div> + %if trans.app.tool_shed_registry and trans.app.tool_shed_registry.tool_sheds: + <div class="toolSectionPad"></div> + <div class="toolSectionTitle">Tool sheds</div> + <div class="toolSectionBody"> + <div class="toolSectionBg"> + %for name, url in trans.app.tool_shed_registry.tool_sheds.items(): + <div class="toolTitle"><a href="${h.url_for( controller='admin', action='browse_tool_shed', tool_shed_name=name, tool_shed_url=url )}" target="galaxy_main">${name}</a></div> + %endfor + </div> + </div> + </div> + %endif + <div class="toolSectionPad"></div> + <div class="toolSectionTitle">Form Definitions</div><div class="toolSectionBody"> - <div class="toolSectionBg"> - <div class="toolTitle"><a href="${h.url_for( controller='admin', action='reload_tool' )}" target="galaxy_main">Reload a tool's configuration</a></div> - <div class="toolTitle"><a href="${h.url_for( controller='admin', action='memdump' )}" target="galaxy_main">Profile memory usage</a></div> - <div class="toolTitle"><a href="${h.url_for( controller='admin', action='jobs' )}" target="galaxy_main">Manage jobs</a></div> - </div> + <div class="toolSectionBg"> + <div class="toolTitle"><a href="${h.url_for( controller='forms', action='browse_form_definitions' )}" target="galaxy_main">Manage form definitions</a></div> + </div></div><div class="toolSectionPad"></div> - <div class="toolSectionTitle"> - Form Definitions - </div> + <div class="toolSectionTitle">Sample Tracking</div><div class="toolSectionBody"> - <div class="toolSectionBg"> - <div class="toolTitle"><a href="${h.url_for( controller='forms', action='browse_form_definitions' )}" target="galaxy_main">Manage form definitions</a></div> - </div> - </div> - <div class="toolSectionPad"></div> - <div class="toolSectionTitle"> - Sample Tracking - </div> - <div class="toolSectionBody"> - <div class="toolSectionBg"> - <div class="toolTitle"><a href="${h.url_for( controller='external_service', action='browse_external_services' )}" target="galaxy_main">Manage sequencers and external services</a></div> - <div class="toolTitle"><a href="${h.url_for( controller='request_type', action='browse_request_types' )}" target="galaxy_main">Manage request types</a></div> - <div class="toolTitle"><a href="${h.url_for( controller='requests_admin', action='browse_requests' )}" target="galaxy_main">Sequencing requests</a></div> - <div class="toolTitle"><a href="${h.url_for( controller='requests_common', action='find_samples', cntrller='requests_admin' )}" target="galaxy_main">Find samples</a></div> - </div> + <div class="toolSectionBg"> + <div class="toolTitle"><a href="${h.url_for( controller='external_service', action='browse_external_services' )}" target="galaxy_main">Manage sequencers and external services</a></div> + <div class="toolTitle"><a href="${h.url_for( controller='request_type', action='browse_request_types' )}" target="galaxy_main">Manage request types</a></div> + <div class="toolTitle"><a href="${h.url_for( controller='requests_admin', action='browse_requests' )}" target="galaxy_main">Sequencing requests</a></div> + <div class="toolTitle"><a href="${h.url_for( controller='requests_common', action='find_samples', cntrller='requests_admin' )}" target="galaxy_main">Find samples</a></div> + </div></div></div></div> @@ -97,8 +99,6 @@ </%def><%def name="center_panel()"> - <% - center_url = h.url_for( action='center', webapp='galaxy' ) - %> + <% center_url = h.url_for( action='center', webapp='galaxy' ) %><iframe name="galaxy_main" id="galaxy_main" frameborder="0" style="position: absolute; width: 100%; height: 100%;" src="${center_url}"></iframe></%def> 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.