galaxy-commits
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
commit/galaxy-central: inithello: Migrated lastz and bowtie tools to the tool shed. Added a target_file feature to the tool dependency installation process.
by Bitbucket 26 Nov '12
by Bitbucket 26 Nov '12
26 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/87828175dfe7/
changeset: 87828175dfe7
user: inithello
date: 2012-11-26 16:18:47
summary: Migrated lastz and bowtie tools to the tool shed. Added a target_file feature to the tool dependency installation process.
affected #: 54 files
Diff too large to display.
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.
1
0
commit/galaxy-central: greg: Improvements in the display of repository dependencies and contents in the tool shed.
by Bitbucket 26 Nov '12
by Bitbucket 26 Nov '12
26 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/519b7df6d72a/
changeset: 519b7df6d72a
user: greg
date: 2012-11-26 16:15:45
summary: Improvements in the display of repository dependencies and contents in the tool shed.
affected #: 14 files
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -1050,23 +1050,6 @@
trans.sa_session.add( tool_dependency )
trans.sa_session.flush()
return removed, error_message
-def to_html_str( text ):
- """Translates the characters in text to an html string"""
- translated = []
- for c in text:
- if c in VALID_CHARS:
- translated.append( c )
- elif c in MAPPED_CHARS:
- translated.append( MAPPED_CHARS[ c ] )
- elif c == ' ':
- translated.append( ' ' )
- elif c == '\t':
- translated.append( ' ' )
- elif c == '\n':
- translated.append( '<br/>' )
- elif c not in [ '\r' ]:
- translated.append( '' )
- return ''.join( translated )
def tool_shed_from_repository_clone_url( repository_clone_url ):
return clean_repository_clone_url( repository_clone_url ).split( 'repos' )[ 0 ].rstrip( '/' )
def translate_string( raw_text, to_html=True ):
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c lib/galaxy/util/shed_util_common.py
--- a/lib/galaxy/util/shed_util_common.py
+++ b/lib/galaxy/util/shed_util_common.py
@@ -1331,6 +1331,23 @@
except:
file_name = fpath
return file_name
+def to_html_str( text ):
+ """Translates the characters in text to an html string"""
+ translated = []
+ for c in text:
+ if c in VALID_CHARS:
+ translated.append( c )
+ elif c in MAPPED_CHARS:
+ translated.append( MAPPED_CHARS[ c ] )
+ elif c == ' ':
+ translated.append( ' ' )
+ elif c == '\t':
+ translated.append( ' ' )
+ elif c == '\n':
+ translated.append( '<br/>' )
+ elif c not in [ '\r' ]:
+ translated.append( '' )
+ return ''.join( translated )
def update_existing_tool_dependency( app, repository, original_dependency_dict, new_dependencies_dict ):
"""
Update an exsiting tool dependency whose definition was updated in a change set pulled by a Galaxy administrator when getting updates
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c lib/galaxy/webapps/community/controllers/common.py
--- a/lib/galaxy/webapps/community/controllers/common.py
+++ b/lib/galaxy/webapps/community/controllers/common.py
@@ -1,11 +1,13 @@
-import os, string, socket, logging, simplejson, binascii, tempfile, filecmp
+import os, string, socket, logging, simplejson, binascii, tempfile, filecmp, threading
from time import strftime
from datetime import *
from galaxy.datatypes.checkers import *
from galaxy.tools import *
+from galaxy.util.odict import odict
from galaxy.util.json import from_json_string, to_json_string
from galaxy.util.hash_util import *
from galaxy.util.shed_util_common import *
+from galaxy.webapps.community.util.container_util import *
from galaxy.web.base.controller import *
from galaxy.web.base.controllers.admin import *
from galaxy.webapps.community import model
@@ -73,9 +75,6 @@
'${host}'
"""
-# String separator
-STRSEP = '__ESEP__'
-
# States for passing messages
SUCCESS, INFO, WARNING, ERROR = "done", "info", "warning", "error"
@@ -105,6 +104,62 @@
trans.sa_session.flush()
return item_rating
+def build_repository_containers( repository, changeset_revision, repository_dependencies, repository_metadata ):
+ containers_dict = dict( datatypes=None,
+ invalid_tools=None,
+ repository_dependencies=None,
+ tool_dependencies=None,
+ valid_tools=None,
+ workflows=None )
+ if repository_metadata:
+ metadata = repository_metadata.metadata
+ lock = threading.Lock()
+ lock.acquire( True )
+ try:
+ folder_id = 0
+ # Datatypes container.
+ if metadata and 'datatypes' in metadata:
+ datatypes = metadata[ 'datatypes' ]
+ folder_id, datatypes_root_folder = build_datatypes_folder( folder_id, datatypes )
+ containers_dict[ 'datatypes' ] = datatypes_root_folder
+ # Invalid tools container.
+ if metadata and 'invalid_tools' in metadata:
+ invalid_tool_configs = metadata[ 'invalid_tools' ]
+ folder_id, invalid_tools_root_folder = build_invalid_tools_folder( folder_id,
+ invalid_tool_configs,
+ repository,
+ changeset_revision,
+ label='Invalid tools' )
+ containers_dict[ 'invalid_tools' ] = invalid_tools_root_folder
+ # Repository dependencies container.
+ folder_id, repository_dependencies_root_folder = build_repository_dependencies_folder( repository,
+ changeset_revision,
+ folder_id,
+ repository_dependencies )
+ if repository_dependencies_root_folder:
+ containers_dict[ 'repository_dependencies' ] = repository_dependencies_root_folder
+ # Tool dependencies container.
+ if metadata and 'tool_dependencies' in metadata:
+ tool_dependencies = metadata[ 'tool_dependencies' ]
+ folder_id, tool_dependencies_root_folder = build_tool_dependencies_folder( folder_id, tool_dependencies )
+ containers_dict[ 'tool_dependencies' ] = tool_dependencies_root_folder
+ # Valid tools container.
+ if metadata and 'tools' in metadata:
+ valid_tools = metadata[ 'tools' ]
+ folder_id, valid_tools_root_folder = build_tools_folder( folder_id, valid_tools, repository, changeset_revision, label='Valid tools' )
+ containers_dict[ 'valid_tools' ] = valid_tools_root_folder
+ # Workflows container.
+ if metadata and 'workflows' in metadata:
+ workflows = metadata[ 'workflows' ]
+ folder_id, workflows_root_folder = build_workflows_folder( folder_id, workflows, repository_metadata, label='Workflows' )
+ containers_dict[ 'workflows' ] = workflows_root_folder
+ except Exception, e:
+ repository_dependencies_root_folder = None
+ tool_dependencies_root_folder = None
+ log.debug( "Exception in build_repository_containers: %s" % str( e ) )
+ finally:
+ lock.release()
+ return containers_dict
def add_tool_versions( trans, id, repository_metadata, changeset_revisions ):
# Build a dictionary of { 'tool id' : 'parent tool id' } pairs for each tool in repository_metadata.
metadata = repository_metadata.metadata
@@ -183,18 +238,6 @@
else:
tmp_filename = None
return tmp_filename
-def copy_file_from_manifest( repo, ctx, filename, dir ):
- """Copy the latest version of the file named filename from the repository manifest to the directory to which dir refers."""
- for changeset in reversed_upper_bounded_changelog( repo, ctx ):
- changeset_ctx = repo.changectx( changeset )
- fctx = get_file_context_from_ctx( changeset_ctx, filename )
- if fctx and fctx not in [ 'DELETED' ]:
- file_path = os.path.join( dir, filename )
- fh = open( file_path, 'wb' )
- fh.write( fctx.data() )
- fh.close()
- return file_path
- return None
def generate_tool_guid( trans, repository, tool ):
"""
Generate a guid for the received tool. The form of the guid is
@@ -285,11 +328,28 @@
fh.close()
return tmp_filename
return None
-def get_previous_downloadable_changset_revision( repository, repo, before_changeset_revision ):
+def get_next_downloadable_changeset_revision( repository, repo, after_changeset_revision ):
"""
- Return the downloadable changeset_revision in the repository changelog just prior to the changeset to which before_changeset_revision
- refers. If there isn't one, return the hash value of an empty repository changlog, INITIAL_CHANGELOG_HASH.
+ Return the installable changeset_revision in the repository changelog after to the changeset to which after_changeset_revision
+ refers. If there isn't one, return None.
"""
+ changeset_revisions = get_ordered_downloadable_changeset_revisions( repository, repo )
+ if len( changeset_revisions ) == 1:
+ changeset_revision = changeset_revisions[ 0 ]
+ if changeset_revision == after_changeset_revision:
+ return None
+ found_after_changeset_revision = False
+ for changeset in repo.changelog:
+ changeset_revision = str( repo.changectx( changeset ) )
+ if found_after_changeset_revision:
+ if changeset_revision in downloadable_changeset_revisions:
+ return changeset_revision
+ elif not found_after_changeset_revision and changeset_revision == after_changeset_revision:
+ # We've found the changeset in the changelog for which we need to get the next downloadable changset.
+ found_after_changeset_revision = True
+ return None
+def get_ordered_downloadable_changeset_revisions( repository, repo ):
+ """Return an ordered list of changeset_revisions defined by a repository changelog."""
changeset_tups = []
for repository_metadata in repository.downloadable_revisions:
changeset_revision = repository_metadata.changeset_revision
@@ -299,24 +359,30 @@
else:
rev = '-1'
changeset_tups.append( ( rev, changeset_revision ) )
- if len( changeset_tups ) == 1:
- changeset_tup = changeset_tups[ 0 ]
- current_changeset_revision = changeset_tup[ 1 ]
- if current_changeset_revision == before_changeset_revision:
+ sorted_changeset_tups = sorted( changeset_tups )
+ sorted_changeset_revisions = [ changeset_tup[ 1 ] for changeset_tup in sorted_changeset_tups ]
+ return sorted_changeset_revisions
+def get_previous_downloadable_changset_revision( repository, repo, before_changeset_revision ):
+ """
+ Return the installable changeset_revision in the repository changelog prior to the changeset to which before_changeset_revision
+ refers. If there isn't one, return the hash value of an empty repository changelog, INITIAL_CHANGELOG_HASH.
+ """
+ changeset_revisions = get_ordered_downloadable_changeset_revisions( repository, repo )
+ if len( changeset_revisions ) == 1:
+ changeset_revision = changeset_revisions[ 0 ]
+ if changeset_revision == before_changeset_revision:
return INITIAL_CHANGELOG_HASH
- return current_changeset_revision
+ return changeset_revision
previous_changeset_revision = None
- current_changeset_revision = None
- for changeset_tup in sorted( changeset_tups ):
- current_changeset_revision = changeset_tup[ 1 ]
- if current_changeset_revision == before_changeset_revision:
+ for changeset_revision in changeset_revisions:
+ if changeset_revision == before_changeset_revision:
if previous_changeset_revision:
return previous_changeset_revision
else:
- # Return the hash value of an empty repository changlog - note that this will not be a valid changset revision.
+ # Return the hash value of an empty repository changelog - note that this will not be a valid changeset revision.
return INITIAL_CHANGELOG_HASH
else:
- previous_changeset_revision = current_changeset_revision
+ previous_changeset_revision = changeset_revision
def get_previous_repository_reviews( trans, repository, changeset_revision ):
"""Return an ordered dictionary of repository reviews up to and including the received changeset revision."""
repo = hg.repository( get_configured_ui(), repository.repo_path( trans.app ) )
@@ -332,6 +398,110 @@
previous_reviews_dict[ previous_changeset_revision ] = dict( changeset_revision_label=previous_changeset_revision_label,
reviews=revision_reviews )
return previous_reviews_dict
+def get_repository_by_name( trans, name ):
+ """Get a repository from the database via name"""
+ return trans.sa_session.query( trans.model.Repository ).filter_by( name=name ).one()
+def get_repository_by_name_and_owner( trans, name, owner ):
+ """Get a repository from the database via name and owner"""
+ user = get_user_by_username( trans, owner )
+ return trans.sa_session.query( trans.model.Repository ) \
+ .filter( and_( trans.model.Repository.table.c.name == name,
+ trans.model.Repository.table.c.user_id == user.id ) ) \
+ .first()
+def get_repository_dependencies_for_changeset_revision( trans, repo, repository, repository_metadata, toolshed_base_url, repository_dependencies=None,
+ all_repository_dependencies=None ):
+ """
+ Return a dictionary of all repositories upon which the contents of the received repository_metadata record depend. The dictionary keys
+ are name-spaced values consisting of tool_shed_base_url/repository_name/repository_owner/changeset_revision and the values are lists of
+ repository_dependency tuples consisting of ( tool_shed_base_url, repository_name, repository_owner, changeset_revision ). This is a
+ recursive method, so it ensures that all required repositories to the nth degree are returned.
+ """
+ if all_repository_dependencies is None:
+ all_repository_dependencies = odict()
+ if repository_dependencies is None:
+ repository_dependencies = []
+ metadata = repository_metadata.metadata
+ if metadata and 'repository_dependencies' in metadata:
+ repository_dependencies_root_key = generate_repository_dependencies_key_for_repository( repository, repository_metadata.changeset_revision )
+ for repository_dependency in metadata[ 'repository_dependencies' ]:
+ if repository_dependency not in repository_dependencies:
+ repository_dependencies.append( repository_dependency )
+ else:
+ repository_dependencies_root_key = None
+ if repository_dependencies:
+ repository_dependency = repository_dependencies.pop( 0 )
+ tool_shed, name, owner, changeset_revision = repository_dependency
+ if repository_dependencies_root_key:
+ if repository_dependencies_root_key in all_repository_dependencies:
+ # See if this repository_dependency is contained in the list associated with the repository_dependencies_root_key.
+ all_repository_dependencies_val = all_repository_dependencies[ repository_dependencies_root_key ]
+ if repository_dependency not in all_repository_dependencies_val:
+ all_repository_dependencies_val.append( repository_dependency )
+ all_repository_dependencies[ repository_dependencies_root_key ] = all_repository_dependencies_val
+ else:
+ # Insert this repository_dependency.
+ all_repository_dependencies[ repository_dependencies_root_key ] = [ repository_dependency ]
+ if tool_shed_is_this_tool_shed( tool_shed ):
+ # The repository is in the current tool shed.
+ required_repository = get_repository_by_name_and_owner( trans, name, owner )
+ required_repository_metadata = get_repository_metadata_by_repository_id_changset_revision( trans,
+ trans.security.encode_id( required_repository.id ),
+ changeset_revision )
+ if required_repository_metadata:
+ required_repo_dir = required_repository.repo_path( trans.app )
+ required_repo = hg.repository( get_configured_ui(), required_repo_dir )
+ else:
+ # The repository changeset_revision is no longer installable, so see if there's been an update.
+ required_repo_dir = required_repository.repo_path( trans.app )
+ required_repo = hg.repository( get_configured_ui(), required_repo_dir )
+ required_repository_metadata = get_next_downloadable_changeset_revision( required_repository, required_repo, changeset_revision )
+ if required_repository_metadata:
+ # The required_repository_metadata changeset_revision is installable.
+ required_metadata = required_repository_metadata.metadata
+ if required_metadata:
+ return get_repository_dependencies_for_changeset_revision( trans=trans,
+ repo=required_repo,
+ repository=required_repository,
+ repository_metadata=required_repository_metadata,
+ toolshed_base_url=tool_shed,
+ repository_dependencies=repository_dependencies,
+ all_repository_dependencies=all_repository_dependencies )
+ else:
+ # The repository is in a different tool shed, so build an url and send a request.
+ raise Exception( "Repository dependencies that refer to repositories in other tool sheds is not yet supported." )
+ return all_repository_dependencies
+def get_repository_metadata_by_id( trans, id ):
+ """Get repository metadata from the database"""
+ return trans.sa_session.query( trans.model.RepositoryMetadata ).get( trans.security.decode_id( id ) )
+def get_repository_metadata_by_repository_id( trans, id ):
+ """Get all metadata records for a specified repository."""
+ return trans.sa_session.query( trans.model.RepositoryMetadata ) \
+ .filter( trans.model.RepositoryMetadata.table.c.repository_id == trans.security.decode_id( id ) )
+def get_repository_metadata_by_repository_id_changset_revision( trans, id, changeset_revision ):
+ """Get a specified metadata record for a specified repository."""
+ return trans.sa_session.query( trans.model.RepositoryMetadata ) \
+ .filter( and_( trans.model.RepositoryMetadata.table.c.repository_id == trans.security.decode_id( id ),
+ trans.model.RepositoryMetadata.table.c.changeset_revision == changeset_revision ) ) \
+ .first()
+def get_repository_metadata_revisions_for_review( repository, reviewed=True ):
+ repository_metadata_revisions = []
+ metadata_changeset_revision_hashes = []
+ if reviewed:
+ for metadata_revision in repository.metadata_revisions:
+ metadata_changeset_revision_hashes.append( metadata_revision.changeset_revision )
+ for review in repository.reviews:
+ if review.changeset_revision in metadata_changeset_revision_hashes:
+ rmcr_hashes = [ rmr.changeset_revision for rmr in repository_metadata_revisions ]
+ if review.changeset_revision not in rmcr_hashes:
+ repository_metadata_revisions.append( review.repository_metadata )
+ else:
+ for review in repository.reviews:
+ if review.changeset_revision not in metadata_changeset_revision_hashes:
+ metadata_changeset_revision_hashes.append( review.changeset_revision )
+ for metadata_revision in repository.metadata_revisions:
+ if metadata_revision.changeset_revision not in metadata_changeset_revision_hashes:
+ repository_metadata_revisions.append( metadata_revision )
+ return repository_metadata_revisions
def get_rev_label_changeset_revision_from_repository_metadata( trans, repository_metadata, repository=None ):
if repository is None:
repository = repository_metadata.repository
@@ -359,42 +529,6 @@
for changeset in repo.changelog:
reversed_changelog.insert( 0, changeset )
return reversed_changelog
-def get_repository_by_name( trans, name ):
- """Get a repository from the database via name"""
- return trans.sa_session.query( trans.model.Repository ).filter_by( name=name ).one()
-def get_repository_by_name_and_owner( trans, name, owner ):
- """Get a repository from the database via name and owner"""
- user = get_user_by_username( trans, owner )
- return trans.sa_session.query( trans.model.Repository ) \
- .filter( and_( trans.model.Repository.table.c.name == name,
- trans.model.Repository.table.c.user_id == user.id ) ) \
- .first()
-def get_repository_metadata_by_id( trans, id ):
- """Get repository metadata from the database"""
- return trans.sa_session.query( trans.model.RepositoryMetadata ).get( trans.security.decode_id( id ) )
-def get_repository_metadata_by_repository_id( trans, id ):
- """Get all metadata records for a specified repository."""
- return trans.sa_session.query( trans.model.RepositoryMetadata ) \
- .filter( trans.model.RepositoryMetadata.table.c.repository_id == trans.security.decode_id( id ) )
-def get_repository_metadata_revisions_for_review( repository, reviewed=True ):
- repository_metadata_revisions = []
- metadata_changeset_revision_hashes = []
- if reviewed:
- for metadata_revision in repository.metadata_revisions:
- metadata_changeset_revision_hashes.append( metadata_revision.changeset_revision )
- for review in repository.reviews:
- if review.changeset_revision in metadata_changeset_revision_hashes:
- rmcr_hashes = [ rmr.changeset_revision for rmr in repository_metadata_revisions ]
- if review.changeset_revision not in rmcr_hashes:
- repository_metadata_revisions.append( review.repository_metadata )
- else:
- for review in repository.reviews:
- if review.changeset_revision not in metadata_changeset_revision_hashes:
- metadata_changeset_revision_hashes.append( review.changeset_revision )
- for metadata_revision in repository.metadata_revisions:
- if metadata_revision.changeset_revision not in metadata_changeset_revision_hashes:
- repository_metadata_revisions.append( metadata_revision )
- return repository_metadata_revisions
def get_review( trans, id ):
"""Get a repository_review from the database via id"""
return trans.sa_session.query( trans.model.RepositoryReview ).get( trans.security.decode_id( id ) )
@@ -693,6 +827,8 @@
id=trans.security.encode_id( repository.id ),
message=error_message,
status='error' ) )
+def tool_shed_is_this_tool_shed( toolshed_base_url ):
+ return toolshed_base_url.rstrip( '/' ) == str( url_for( '/', qualified=True ) ).rstrip( '/' )
def update_for_browsing( trans, repository, current_working_dir, commit_message='' ):
# This method id deprecated, but we'll keep it around for a while in case we need it. The problem is that hg purge
# is not supported by the mercurial API.
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -1748,9 +1748,11 @@
add_id_to_name=False,
downloadable=False )
revision_label = get_revision_label( trans, repository, repository.tip( trans.app ) )
+ repository_metadata = None
repository_metadata_id = None
metadata = None
is_malicious = False
+ repository_dependencies = []
if changeset_revision != INITIAL_CHANGELOG_HASH:
repository_metadata = get_repository_metadata_by_changeset_revision( trans, id, changeset_revision )
if repository_metadata:
@@ -1768,6 +1770,15 @@
repository_metadata_id = trans.security.encode_id( repository_metadata.id )
metadata = repository_metadata.metadata
is_malicious = repository_metadata.malicious
+ if repository_metadata:
+ # Get a dictionary of all repositories upon which the contents of the current repository_metadata record depend.
+ repository_dependencies = get_repository_dependencies_for_changeset_revision( trans,
+ repo,
+ repository,
+ repository_metadata,
+ str( url_for( '/', qualified=True ) ).rstrip( '/' ),
+ repository_dependencies=None,
+ all_repository_dependencies=None )
if is_malicious:
if trans.app.security_agent.can_push( trans.app, trans.user, repository ):
message += malicious_error_can_push
@@ -1787,6 +1798,7 @@
review_id = trans.security.encode_id( review.id )
else:
review_id = None
+ containers_dict = build_repository_containers( repository, changeset_revision, repository_dependencies, repository_metadata )
return trans.fill_template( '/webapps/community/repository/manage_repository.mako',
cntrller=cntrller,
repo_name=repo_name,
@@ -1796,6 +1808,7 @@
allow_push_select_field=allow_push_select_field,
repo=repo,
repository=repository,
+ containers_dict=containers_dict,
repository_metadata_id=repository_metadata_id,
changeset_revision=changeset_revision,
reviewed_by_user=reviewed_by_user,
@@ -1865,22 +1878,35 @@
message = util.restore_text( params.get( 'message', '' ) )
status = params.get( 'status', 'done' )
repository = get_repository_in_tool_shed( trans, repository_id )
+ repo_dir = repository.repo_path( trans.app )
+ repo = hg.repository( get_configured_ui(), repo_dir )
changeset_revision = util.restore_text( params.get( 'changeset_revision', repository.tip( trans.app ) ) )
repository_metadata = get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision )
if repository_metadata:
repository_metadata_id = trans.security.encode_id( repository_metadata.id ),
metadata = repository_metadata.metadata
+ # Get a dictionary of all repositories upon which the contents of the current repository_metadata record depend.
+ repository_dependencies = get_repository_dependencies_for_changeset_revision( trans,
+ repo,
+ repository,
+ repository_metadata,
+ str( url_for( '/', qualified=True ) ).rstrip( '/' ),
+ repository_dependencies=None,
+ all_repository_dependencies=None )
else:
repository_metadata_id = None
metadata = None
+ repository_dependencies = 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,
downloadable=False )
+ containers_dict = build_repository_containers( repository, changeset_revision, repository_dependencies, repository_metadata )
return trans.fill_template( '/webapps/community/repository/preview_tools_in_changeset.mako',
repository=repository,
+ containers_dict=containers_dict,
repository_metadata_id=repository_metadata_id,
changeset_revision=changeset_revision,
revision_label=revision_label,
@@ -2408,6 +2434,7 @@
email_alerts = from_json_string( repository.email_alerts )
else:
email_alerts = []
+ repository_dependencies = []
user = trans.user
if user and params.get( 'receive_email_alerts_button', False ):
flush_needed = False
@@ -2434,8 +2461,16 @@
revision_label = get_revision_label( trans, repository, changeset_revision )
repository_metadata = get_repository_metadata_by_changeset_revision( trans, id, changeset_revision )
if repository_metadata:
- repository_metadata_id = trans.security.encode_id( repository_metadata.id ),
+ repository_metadata_id = trans.security.encode_id( repository_metadata.id )
metadata = repository_metadata.metadata
+ # Get a dictionary of all repositories upon which the contents of the current repository_metadata record depend.
+ repository_dependencies = get_repository_dependencies_for_changeset_revision( trans,
+ repo,
+ repository,
+ repository_metadata,
+ str( url_for( '/', qualified=True ) ).rstrip( '/' ),
+ repository_dependencies=None,
+ all_repository_dependencies=None )
else:
repository_metadata_id = None
metadata = None
@@ -2456,12 +2491,14 @@
review_id = trans.security.encode_id( review.id )
else:
review_id = None
+ containers_dict = build_repository_containers( repository, changeset_revision, repository_dependencies, repository_metadata )
return trans.fill_template( '/webapps/community/repository/view_repository.mako',
cntrller=cntrller,
repo=repo,
repository=repository,
repository_metadata_id=repository_metadata_id,
metadata=metadata,
+ containers_dict=containers_dict,
avg_rating=avg_rating,
display_reviews=display_reviews,
num_ratings=num_ratings,
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c lib/galaxy/webapps/community/controllers/repository_review.py
--- a/lib/galaxy/webapps/community/controllers/repository_review.py
+++ b/lib/galaxy/webapps/community/controllers/repository_review.py
@@ -7,6 +7,7 @@
from galaxy.model.orm import *
from sqlalchemy.sql.expression import func
from common import *
+from galaxy.webapps.community.util.container_util import STRSEP
from repository import RepositoryGrid
from galaxy.util.shed_util_common import *
from galaxy.util.odict import odict
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c lib/galaxy/webapps/community/controllers/workflow.py
--- a/lib/galaxy/webapps/community/controllers/workflow.py
+++ b/lib/galaxy/webapps/community/controllers/workflow.py
@@ -151,7 +151,7 @@
changeset_revision=repository_metadata.changeset_revision,
repository_metadata_id=repository_metadata_id,
workflow_name=workflow_name,
- metadata=repository_metadata,
+ metadata=repository_metadata.metadata,
message=message,
status=status )
@web.expose
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c lib/galaxy/webapps/community/util/container_util.py
--- /dev/null
+++ b/lib/galaxy/webapps/community/util/container_util.py
@@ -0,0 +1,314 @@
+import logging
+from galaxy.web import url_for
+
+log = logging.getLogger( __name__ )
+
+# String separator
+STRSEP = '__ESEP__'
+
+class Folder( object ):
+ """Container object."""
+ def __init__( self, id=None, key=None, label=None ):
+ self.id = id
+ self.key = key
+ self.label = label
+ self.datatypes = []
+ self.folders = []
+ self.invalid_tools = []
+ self.valid_tools = []
+ self.tool_dependencies = []
+ self.repository_dependencies = []
+ self.workflows = []
+ def contains_folder( self, folder ):
+ for index, contained_folder in enumerate( self.folders ):
+ if folder == contained_folder:
+ return index, contained_folder
+ return 0, None
+
+class Datatype( object ):
+ """Datatype object"""
+ def __init__( self, id=None, extension=None, type=None, mimetype=None, subclass=None ):
+ self.id = id
+ self.extension = extension
+ self.type = type
+ self.mimetype = mimetype
+ self.subclass = subclass
+
+class InvalidTool( object ):
+ """Invalid tool object"""
+ def __init__( self, id=None, tool_config=None, repository_id=None, changeset_revision=None ):
+ self.id = id
+ self.tool_config = tool_config
+ self.repository_id = repository_id
+ self.changeset_revision = changeset_revision
+
+class RepositoryDependency( object ):
+ """Repository dependency object"""
+ def __init__( self, id=None, toolshed=None, repository_name=None, repository_owner=None, changeset_revision=None ):
+ self.id = id
+ self.toolshed = toolshed
+ self.repository_name = repository_name
+ self.repository_owner = repository_owner
+ self.changeset_revision = changeset_revision
+
+class Tool( object ):
+ """Tool object"""
+ def __init__( self, id=None, tool_config=None, tool_id=None, name=None, description=None, version=None, requirements=None,
+ repository_id=None, changeset_revision=None ):
+ self.id = id
+ self.tool_config = tool_config
+ self.tool_id = tool_id
+ self.name = name
+ self.description = description
+ self.version = version
+ self.requirements = requirements
+ self.repository_id = repository_id
+ self.changeset_revision = changeset_revision
+
+class ToolDependency( object ):
+ """Tool dependency object"""
+ def __init__( self, id=None, name=None, version=None, type=None ):
+ self.id = id
+ self.name = name
+ self.version = version
+ self.type = type
+
+class Workflow( object ):
+ """Workflow object"""
+ def __init__( self, id=None, repository_metadata_id=None, workflow_name=None, steps=None, format_version=None, annotation=None ):
+ self.id = id
+ self.repository_metadata_id = repository_metadata_id
+ self.workflow_name = workflow_name
+ self.steps = steps
+ self.format_version = format_version
+ self.annotation = annotation
+
+def build_datatypes_folder( folder_id, datatypes, label='Datatypes' ):
+ """Return a folder hierarchy containing datatypes."""
+ if datatypes:
+ datatype_id = 0
+ folder_id += 1
+ datatypes_root_folder = Folder( id=folder_id, key='root', label='root' )
+ folder_id += 1
+ folder = Folder( id=folder_id, key='datatypes', label=label )
+ datatypes_root_folder.folders.append( folder )
+ # Insert a header row.
+ datatype_id += 1
+ datatype = Datatype( id=datatype_id,
+ extension='extension',
+ type='type',
+ mimetype='mimetype',
+ subclass='subclass' )
+ folder.datatypes.append( datatype )
+ for datatypes_dict in datatypes:
+ datatype_id += 1
+ datatype = Datatype( id=datatype_id,
+ extension=datatypes_dict.get( 'extension', '' ),
+ type=datatypes_dict.get( 'dtype', '' ),
+ mimetype=datatypes_dict.get( 'mimetype', '' ),
+ subclass=datatypes_dict.get( 'subclass', '' ) )
+ folder.datatypes.append( datatype )
+ else:
+ datatypes_root_folder = None
+ return folder_id, datatypes_root_folder
+def build_invalid_tools_folder( folder_id, invalid_tool_configs, repository, changeset_revision, label='Invalid tools' ):
+ """Return a folder hierarchy containing invalid tools."""
+ if invalid_tool_configs:
+ invalid_tool_id = 0
+ folder_id += 1
+ invalid_tools_root_folder = Folder( id=folder_id, key='root', label='root' )
+ folder_id += 1
+ folder = Folder( id=folder_id, key='invalid_tools', label=label )
+ invalid_tools_root_folder.folders.append( folder )
+ for invalid_tool_config in invalid_tool_configs:
+ invalid_tool_id += 1
+ invalid_tool = InvalidTool( id=invalid_tool_id,
+ tool_config=invalid_tool_config,
+ repository_id=repository.id,
+ changeset_revision=changeset_revision )
+ folder.invalid_tools.append( invalid_tool )
+ else:
+ invalid_tools_root_folder = None
+ return folder_id, invalid_tools_root_folder
+def build_repository_dependencies_folder( repository, changeset_revision, folder_id, repository_dependencies, label='Repository dependencies' ):
+ """Return a folder hierarchy containing repository dependencies."""
+ if repository_dependencies:
+ repository_dependency_id = 0
+ folder_id += 1
+ # Create the root folder.
+ repository_dependencies_root_folder = Folder( id=folder_id, key='root', label='root' )
+ folder_id += 1
+ # Create the Repository dependencies folder and add it to the root folder.
+ key = generate_repository_dependencies_key_for_repository( repository, changeset_revision )
+ repository_dependencies_folder = Folder( id=folder_id, key=key, label=label )
+ repository_dependencies_root_folder.folders.append( repository_dependencies_folder )
+ # Process the repository dependencies.
+ for key, val in repository_dependencies.items():
+ # Only create a new folder object if necessary.
+ folder = get_folder( repository_dependencies_root_folder, key )
+ if not folder:
+ # Create a new folder.
+ folder_id += 1
+ label = generate_repository_dependencies_folder_label_from_key( repository, changeset_revision, key )
+ folder = Folder( id=folder_id, key=key, label=label )
+ for repository_dependency_tup in val:
+ toolshed, name, owner, changeset_revision = repository_dependency_tup
+ if not is_folder( repository_dependencies.keys(), toolshed, name, owner, changeset_revision ):
+ # Create a new repository_dependency.
+ repository_dependency_id += 1
+ repository_dependency = RepositoryDependency( id=repository_dependency_id,
+ toolshed=toolshed,
+ repository_name=name,
+ repository_owner=owner,
+ changeset_revision=changeset_revision )
+ # Insert the repository_dependency into the folder.
+ folder.repository_dependencies.append( repository_dependency )
+ if not get_folder( repository_dependencies_folder, key ):
+ # Insert the folder into the list.
+ repository_dependencies_folder.folders.append( folder )
+ else:
+ repository_dependencies_root_folder = None
+ return folder_id, repository_dependencies_root_folder
+def build_tools_folder( folder_id, tool_dicts, repository, changeset_revision, valid=True, label='Valid tools' ):
+ """Return a folder hierarchy containing valid tools."""
+ if tool_dicts:
+ tool_id = 0
+ folder_id += 1
+ tools_root_folder = Folder( id=folder_id, key='root', label='root' )
+ folder_id += 1
+ folder = Folder( id=folder_id, key='tools', label=label )
+ tools_root_folder.folders.append( folder )
+ # Insert a header row.
+ tool_id += 1
+ tool = Tool( id=tool_id,
+ tool_config='',
+ tool_id='',
+ name='Name',
+ description='Description',
+ version='Version',
+ requirements='',
+ repository_id='',
+ changeset_revision='' )
+ folder.valid_tools.append( tool )
+ for tool_dict in tool_dicts:
+ tool_id += 1
+ if 'requirements' in tool_dict:
+ requirements = tool_dict[ 'requirements' ]
+ requirements_str = ''
+ for requirement_dict in requirements:
+ requirements_str += '%s (%s), ' % ( requirement_dict[ 'name' ], requirement_dict[ 'type' ] )
+ requirements_str = requirements_str.rstrip( ', ' )
+ else:
+ requirements_str = 'none'
+ tool = Tool( id=tool_id,
+ tool_config=tool_dict[ 'tool_config' ],
+ tool_id=tool_dict[ 'id' ],
+ name=tool_dict[ 'name' ],
+ description=tool_dict[ 'description' ],
+ version=tool_dict[ 'version' ],
+ requirements=requirements_str,
+ repository_id=repository.id,
+ changeset_revision=changeset_revision )
+ folder.valid_tools.append( tool )
+ else:
+ tools_root_folder = None
+ return folder_id, tools_root_folder
+def build_tool_dependencies_folder( folder_id, tool_dependencies, label='Tool dependencies' ):
+ """Return a folder hierarchy containing tool dependencies."""
+ if tool_dependencies:
+ tool_dependency_id = 0
+ folder_id += 1
+ tool_dependencies_root_folder = Folder( id=folder_id, key='root', label='root' )
+ folder_id += 1
+ folder = Folder( id=folder_id, key='tool_dependencies', label=label )
+ tool_dependencies_root_folder.folders.append( folder )
+ # Insert a header row.
+ tool_dependency_id += 1
+ tool_dependency = ToolDependency( id=tool_dependency_id,
+ name='Name',
+ version='Version',
+ type='Type' )
+ folder.tool_dependencies.append( tool_dependency )
+ for dependency_key, requirements_dict in tool_dependencies.items():
+ tool_dependency_id += 1
+ if dependency_key == 'set_environment':
+ version = None
+ else:
+ version = requirements_dict[ 'version' ]
+ tool_dependency = ToolDependency( id=tool_dependency_id,
+ name=requirements_dict[ 'name' ],
+ version=version,
+ type=requirements_dict[ 'type' ] )
+ folder.tool_dependencies.append( tool_dependency )
+ else:
+ tool_dependencies_root_folder = None
+ return folder_id, tool_dependencies_root_folder
+def build_workflows_folder( folder_id, workflows, repository_metadata, label='Workflows' ):
+ """Return a folder hierarchy containing invalid tools."""
+ if workflows:
+ workflow_id = 0
+ folder_id += 1
+ workflows_root_folder = Folder( id=folder_id, key='root', label='root' )
+ folder_id += 1
+ folder = Folder( id=folder_id, key='workflows', label=label )
+ workflows_root_folder.folders.append( folder )
+ # Insert a header row.
+ workflow_id += 1
+ workflow = Workflow( id=workflow_id,
+ repository_metadata_id=None,
+ workflow_name='Name',
+ steps='steps',
+ format_version='format-version',
+ annotation='annotation' )
+ folder.workflows.append( workflow )
+ for workflow_tup in workflows:
+ workflow_dict=workflow_tup[ 1 ]
+ steps = workflow_dict.get( 'steps', [] )
+ if steps:
+ steps = str( len( steps ) )
+ else:
+ steps = 'unknown'
+ workflow_id += 1
+ workflow = Workflow( id=workflow_id,
+ repository_metadata_id=repository_metadata.id,
+ workflow_name=workflow_dict[ 'name' ],
+ steps=steps,
+ format_version=workflow_dict[ 'format-version' ],
+ annotation=workflow_dict[ 'annotation' ] )
+ folder.workflows.append( workflow )
+ else:
+ workflows_root_folder = None
+ return folder_id, workflows_root_folder
+def generate_repository_dependencies_folder_label_from_key( repository, changeset_revision, key ):
+ """Return a repository dependency label based on the repository dependency key."""
+ if key_is_current_repositorys_key( repository, changeset_revision, key ):
+ label = 'Repository dependencies'
+ else:
+ toolshed_base_url, name, owner, revision = get_components_from_key( key )
+ label = "Repository <b>%s</b> revision <b>%s</b> owned by <b>%s</b>" % ( name, revision, owner )
+ return label
+def generate_repository_dependencies_key_for_repository( repository, changeset_revision ):
+ # FIXME: assumes tool shed is current tool shed since repository dependencies across tool sheds is not yet supported.
+ toolshed_base_url = str( url_for( '/', qualified=True ) ).rstrip( '/' )
+ return '%s%s%s%s%s%s%s' % ( toolshed_base_url, STRSEP, repository.name, STRSEP, repository.user.username, STRSEP, changeset_revision )
+def get_folder( folder, key ):
+ if folder and folder.key == key:
+ return folder
+ for sub_folder in folder.folders:
+ return get_folder( sub_folder, key )
+ return None
+def get_components_from_key( key ):
+ # FIXME: assumes tool shed is current tool shed since repository dependencies across tool sheds is not yet supported.
+ items = key.split( STRSEP )
+ toolshed_base_url = items[ 0 ]
+ repository_name = items[ 1 ]
+ repository_owner = items[ 2 ]
+ changeset_revision = items[ 3 ]
+ return toolshed_base_url, repository_name, repository_owner, changeset_revision
+def is_folder( folder_keys, toolshed_base_url, repository_name, repository_owner, changeset_revision ):
+ key = '%s%s%s%s%s%s%s' % ( toolshed_base_url, STRSEP, repository_name, STRSEP, repository_owner, STRSEP, changeset_revision )
+ return key in folder_keys
+def key_is_current_repositorys_key( repository, changeset_revision, key ):
+ toolshed_base_url, repository_name, repository_owner, changeset_revision = get_components_from_key( key )
+ return repository_name == repository.name and repository_owner == repository.user.username and repository_changeset_revision == changeset_revision
+
\ No newline at end of file
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c templates/webapps/community/repository/common.mako
--- a/templates/webapps/community/repository/common.mako
+++ b/templates/webapps/community/repository/common.mako
@@ -75,6 +75,93 @@
</script></%def>
+<%def name="dependency_javascripts()">
+ <script type="text/javascript">
+ var init_dependencies = function() {
+ var storage_id = "library-expand-state-${trans.security.encode_id(10000)}";
+ var restore_folder_state = function() {
+ var state = $.jStorage.get(storage_id);
+ if (state) {
+ for (var id in state) {
+ if (state[id] === true) {
+ var row = $("#" + id),
+ index = row.parent().children().index(row);
+ row.addClass("expanded").show();
+ row.siblings().filter("tr[parent='" + index + "']").show();
+ }
+ }
+ }
+ };
+ var save_folder_state = function() {
+ var state = {};
+ $("tr.folderRow").each( function() {
+ var folder = $(this);
+ state[folder.attr("id")] = folder.hasClass("expanded");
+ });
+ $.jStorage.set(storage_id, state);
+ };
+ $(".container-table").each(function() {
+ //var container_id = this.id.split( "-" )[0];
+ //alert( container_id );
+ var child_of_parent_cache = {};
+ // Recursively fill in children and descendants of each row
+ var process_row = function(q, parents) {
+ // Find my index
+ var parent = q.parent(),
+ this_level = child_of_parent_cache[parent] || (child_of_parent_cache[parent] = parent.children());
+ var index = this_level.index(q);
+ // Find my immediate children
+ var children = $(par_child_dict[index]);
+ // Recursively handle them
+ var descendants = children;
+ children.each( function() {
+ child_descendants = process_row( $(this), parents.add(q) );
+ descendants = descendants.add(child_descendants);
+ });
+ // Set up expand / hide link
+ var expand_fn = function() {
+ if ( q.hasClass("expanded") ) {
+ descendants.hide();
+ descendants.removeClass("expanded");
+ q.removeClass("expanded");
+ } else {
+ children.show();
+ q.addClass("expanded");
+ }
+ save_folder_state();
+ };
+ $("." + q.attr("id") + "-click").click(expand_fn);
+ // return descendants for use by parent
+ return descendants;
+ }
+ // Initialize dict[parent_id] = rows_which_have_that_parent_id_as_parent_attr
+ var par_child_dict = {},
+ no_parent = [];
+ $(this).find("tbody tr").each( function() {
+ if ( $(this).attr("parent")) {
+ var parent = $(this).attr("parent");
+ if (par_child_dict[parent] !== undefined) {
+ par_child_dict[parent].push(this);
+ } else {
+ par_child_dict[parent] = [this];
+ }
+ } else {
+ no_parent.push(this);
+ }
+ });
+ $(no_parent).each( function() {
+ descendants = process_row( $(this), $([]) );
+ descendants.hide();
+ });
+ });
+ restore_folder_state();
+ };
+ $(function() {
+ init_dependencies();
+ });
+ </script>
+</%def>
+
<%def name="render_clone_str( repository )"><%
from galaxy.util.shed_util_common import generate_clone_url_for_repository_in_tool_shed
@@ -83,272 +170,337 @@
hg clone <a href="${clone_str}">${clone_str}</a></%def>
-<%def name="render_repository_items( repository_metadata_id, changeset_revision, metadata, can_set_metadata=False )">
- <% from galaxy.tool_shed.encoding_util import tool_shed_encode %>
- %if metadata or can_set_metadata:
+<%def name="render_folder( folder, folder_pad, parent=None, row_counter=None, is_root_folder=False )">
+ <%
+ encoded_id = trans.security.encode_id( folder.id )
+
+ if is_root_folder:
+ pad = folder_pad
+ expander = h.url_for("/static/images/silk/resultset_bottom.png")
+ folder_img = h.url_for("/static/images/silk/folder_page.png")
+ else:
+ pad = folder_pad + 20
+ expander = h.url_for("/static/images/silk/resultset_next.png")
+ folder_img = h.url_for("/static/images/silk/folder.png")
+ my_row = None
+ %>
+ %if not is_root_folder:
+ <%
+ if parent is None:
+ bg_str = 'bgcolor="#D8D8D8"'
+ else:
+ bg_str = ''
+ %>
+ <tr id="folder-${encoded_id}" ${bg_str} class="folderRow libraryOrFolderRow"
+ %if parent is not None:
+ parent="${parent}"
+ style="display: none;"
+ %endif
+ >
+ <%
+ col_span_str = ''
+ if folder.datatypes:
+ label = folder.label
+ col_span_str = 'colspan="4"'
+ elif folder.label == 'Repository dependencies':
+ label = "%s<i> - this repository requires installation of these additional repositories</i>" % folder.label
+ elif folder.repository_dependencies:
+ label = folder.label
+ elif folder.invalid_tools:
+ label = "%s<i> - click the tool config file name to see why the tool is invalid</i>" % folder.label
+ elif folder.tool_dependencies:
+ label = "%s<i> - this repository's tools require installation of these dependencies</i>" % folder.label
+ col_span_str = 'colspan="3"'
+ elif folder.valid_tools:
+ label = "%s<i> - click the name to preview the tool and use the pop-up menu to inspect all metadata</i>" % folder.label
+ col_span_str = 'colspan="3"'
+ elif folder.workflows:
+ label = folder.label
+ col_span_str = 'colspan="4"'
+ %>
+ <td ${col_span_str} style="padding-left: ${folder_pad}px;">
+ <span class="expandLink folder-${encoded_id}-click">
+ <div style="float: left; margin-left: 2px;" class="expandLink folder-${encoded_id}-click">
+ <a class="folder-${encoded_id}-click" href="javascript:void(0);">
+ ${label}
+ </a>
+ </div>
+ </span>
+ <td>
+ </tr>
+ <%
+ my_row = row_counter.count
+ row_counter.increment()
+ %>
+ %endif
+ %for sub_folder in folder.folders:
+ ${render_folder( sub_folder, pad, parent=my_row, row_counter=row_counter, is_root_folder=False )}
+ %endfor
+ %for repository_dependency in folder.repository_dependencies:
+ ${render_repository_dependency( repository_dependency, pad, my_row, row_counter )}
+ %endfor
+ %for index, tool_dependency in enumerate( folder.tool_dependencies ):
+ <% row_is_header = index == 0 %>
+ ${render_tool_dependency( tool_dependency, pad, my_row, row_counter, row_is_header )}
+ %endfor
+ %if folder.valid_tools:
+ %for index, tool in enumerate( folder.valid_tools ):
+ <% row_is_header = index == 0 %>
+ ${render_tool( tool, pad, my_row, row_counter, row_is_header )}
+ %endfor
+ %endif
+ %for invalid_tool in folder.invalid_tools:
+ ${render_invalid_tool( invalid_tool, pad, my_row, row_counter )}
+ %endfor
+ %if folder.workflows:
+ %for index, workflow in enumerate( folder.workflows ):
+ <% row_is_header = index == 0 %>
+ ${render_workflow( workflow, pad, my_row, row_counter, row_is_header )}
+ %endfor
+ %endif
+ %if folder.datatypes:
+ %for index, datatype in enumerate( folder.datatypes ):
+ <% row_is_header = index == 0 %>
+ ${render_datatype( datatype, pad, my_row, row_counter, row_is_header )}
+ %endfor
+ %endif
+</%def>
+
+<%def name="render_datatype( datatype, pad, parent, row_counter, row_is_header=False )">
+ <%
+ encoded_id = trans.security.encode_id( datatype.id )
+ if row_is_header:
+ cell_type = 'th'
+ else:
+ cell_type = 'td'
+ %>
+ <tr class="datasetRow"
+ %if parent is not None:
+ parent="${parent}"
+ %endif
+ id="libraryItem-${encoded_id}">
+ <${cell_type} style="padding-left: ${pad+20}px;">${datatype.extension | h}</${cell_type}>
+ <${cell_type}>${datatype.type | h}</${cell_type}>
+ <${cell_type}>${datatype.mimetype | h}</${cell_type}>
+ <${cell_type}>${datatype.subclass | h}</${cell_type}>
+ </tr>
+ <%
+ my_row = row_counter.count
+ row_counter.increment()
+ %>
+</%def>
+
+<%def name="render_invalid_tool( invalid_tool, pad, parent, row_counter, valid=True )">
+ <% encoded_id = trans.security.encode_id( invalid_tool.id ) %>
+ <tr class="datasetRow"
+ %if parent is not None:
+ parent="${parent}"
+ %endif
+ id="libraryItem-${encoded_id}">
+ <td style="padding-left: ${pad+20}px;">
+ <a class="view-info" href="${h.url_for( controller='repository', action='load_invalid_tool', repository_id=trans.security.encode_id( invalid_tool.repository_id ), tool_config=invalid_tool.tool_config, changeset_revision=invalid_tool.changeset_revision )}">
+ ${invalid_tool.tool_config | h}
+ </a>
+ </td>
+ </tr>
+ <%
+ my_row = row_counter.count
+ row_counter.increment()
+ %>
+</%def>
+
+<%def name="render_repository_dependency( repository_dependency, pad, parent, row_counter )">
+
+ <% encoded_id = trans.security.encode_id( repository_dependency.id ) %>
+ <tr class="datasetRow"
+ %if parent is not None:
+ parent="${parent}"
+ %endif
+ id="libraryItem-${encoded_id}">
+ ##<td style="padding-left: ${pad+20}px;">${repository_dependency.toolshed | h}</td>
+ <td style="padding-left: ${pad+20}px;">Repository <b>${repository_dependency.repository_name | h}</b> revision <b>${repository_dependency.changeset_revision | h}</b> owned by <b>${repository_dependency.repository_owner | h}</b></td>
+ </tr>
+ <%
+ my_row = row_counter.count
+ row_counter.increment()
+ %>
+</%def>
+
+<%def name="render_tool( tool, pad, parent, row_counter, row_is_header )">
+ <%
+ encoded_id = trans.security.encode_id( tool.id )
+ if row_is_header:
+ cell_type = 'th'
+ else:
+ cell_type = 'td'
+ %>
+ <tr class="datasetRow"
+ %if parent is not None:
+ parent="${parent}"
+ %endif
+ id="libraryItem-${encoded_id}">
+ %if row_is_header:
+ <th style="padding-left: ${pad+20}px;">${tool.name | h}</th>
+ %else:
+ <td style="padding-left: ${pad+20}px;">
+ <div style="float:left;" class="menubutton split popup" id="tool-${encoded_id}-popup">
+ <a class="view-info" href="${h.url_for( controller='repository', action='display_tool', repository_id=trans.security.encode_id( tool.repository_id ), tool_config=tool.tool_config, changeset_revision=tool.changeset_revision )}">${tool.name | h}</a>
+ </div>
+ <div popupmenu="tool-${encoded_id}-popup">
+ <a class="action-button" href="${h.url_for( controller='repository', action='view_tool_metadata', repository_id=trans.security.encode_id( tool.repository_id ), changeset_revision=tool.changeset_revision, tool_id=tool.tool_id )}">View tool metadata</a>
+ </div>
+ </td>
+ %endif
+ <${cell_type}>${tool.description | h}</${cell_type}>
+ <${cell_type}>${tool.version | h}</${cell_type}>
+ ##<${cell_type}>${tool.requirements | h}</${cell_type}>
+ </tr>
+ <%
+ my_row = row_counter.count
+ row_counter.increment()
+ %>
+</%def>
+
+<%def name="render_tool_dependency( tool_dependency, pad, parent, row_counter, row_is_header )">
+ <%
+ encoded_id = trans.security.encode_id( tool_dependency.id )
+ if row_is_header:
+ cell_type = 'th'
+ else:
+ cell_type = 'td'
+ %>
+ <tr class="datasetRow"
+ %if parent is not None:
+ parent="${parent}"
+ %endif
+ id="libraryItem-${encoded_id}">
+ <${cell_type} style="padding-left: ${pad+20}px;">${tool_dependency.name | h}</${cell_type}>
+ <${cell_type}>
+ <%
+ if tool_dependency.version:
+ version_str = tool_dependency.version
+ else:
+ version_str = ''
+ %>
+ ${version_str | h}
+ </${cell_type}>
+ <${cell_type}>${tool_dependency.type | h}</${cell_type}>
+ </tr>
+ <%
+ my_row = row_counter.count
+ row_counter.increment()
+ %>
+</%def>
+
+<%def name="render_workflow( workflow, pad, parent, row_counter, row_is_header=False )">
+ <%
+ from galaxy.tool_shed.encoding_util import tool_shed_encode
+ encoded_id = trans.security.encode_id( workflow.id )
+ if row_is_header:
+ cell_type = 'th'
+ else:
+ cell_type = 'td'
+ %>
+ <tr class="datasetRow"
+ %if parent is not None:
+ parent="${parent}"
+ %endif
+ id="libraryItem-${encoded_id}">
+ <${cell_type} style="padding-left: ${pad+20}px;">
+ %if row_is_header:
+ ${workflow.workflow_name | h}
+ %else:
+ <a href="${h.url_for( controller='workflow', action='view_workflow', repository_metadata_id=trans.security.encode_id( workflow.repository_metadata_id ), workflow_name=tool_shed_encode( workflow.workflow_name ) )}">${workflow.workflow_name | h}</a>
+ %endif
+ </${cell_type}>
+ <${cell_type}>${workflow.steps | h}</${cell_type}>
+ <${cell_type}>${workflow.format_version | h}</${cell_type}>
+ <${cell_type}>${workflow.annotation | h}</${cell_type}>
+ </tr>
+ <%
+ my_row = row_counter.count
+ row_counter.increment()
+ %>
+</%def>
+
+<%def name="render_repository_items( repository_metadata_id, changeset_revision, metadata, containers_dict, can_set_metadata=False )">
+ <%
+ from galaxy.tool_shed.encoding_util import tool_shed_encode
+
+ has_datatypes = metadata and 'datatypes' in metadata
+ has_readme = metadata and 'readme' in metadata
+ has_workflows = metadata and 'workflows' in metadata
+
+ datatypes_root_folder = containers_dict[ 'datatypes' ]
+ invalid_tools_root_folder = containers_dict[ 'invalid_tools' ]
+ repository_dependencies_root_folder = containers_dict[ 'repository_dependencies' ]
+ tool_dependencies_root_folder = containers_dict[ 'tool_dependencies' ]
+ valid_tools_root_folder = containers_dict[ 'valid_tools' ]
+ workflows_root_folder = containers_dict[ 'workflows' ]
+
+ has_contents = datatypes_root_folder, invalid_tools_root_folder or valid_tools_root_folder or workflows_root_folder
+
+ class RowCounter( object ):
+ def __init__( self ):
+ self.count = 0
+ def increment( self ):
+ self.count += 1
+ def __str__( self ):
+ return str( self.count )
+ %>
+ %if repository_dependencies_root_folder or tool_dependencies_root_folder:
+ <div class="toolForm">
+ <div class="toolFormTitle">Dependencies of this repository</div>
+ <div class="toolFormBody">
+ %if repository_dependencies_root_folder:
+ <p/>
+ <% row_counter = RowCounter() %>
+ <table cellspacing="0" cellpadding="0" border="0" width="100%" class="tables container-table" id="repository_dependencies">
+ ${self.render_folder( repository_dependencies_root_folder, 0, parent=None, row_counter=row_counter, is_root_folder=True )}
+ </table>
+ %endif
+ %if tool_dependencies_root_folder:
+ <p/>
+ <% row_counter = RowCounter() %>
+ <table cellspacing="0" cellpadding="0" border="0" width="100%" class="tables container-table" id="tool_dependencies">
+ ${self.render_folder( tool_dependencies_root_folder, 0, parent=None, row_counter=row_counter, is_root_folder=True )}
+ </table>
+ %endif
+ </div>
+ </div>
+ %endif
+ %if has_contents:
<p/><div class="toolForm">
- <div class="toolFormTitle">Preview tools and inspect metadata by tool version</div>
+ <div class="toolFormTitle">Contents of this repository</div><div class="toolFormBody">
- %if metadata:
- %if 'repository_dependencies' in metadata:
- <div class="form-row">
- <table class="grid">
- <tr>
- <td><b>tool shed</b></td>
- <td><b>name</b></td>
- <td><b>version</b></td>
- <td><b>type</b></td>
- </tr>
- %for repository_dependency_tup in metadata[ 'repository_dependencies' ]:
- <% toolshed, name, owner, changeset_revision = repository_dependency_tup %>
- <tr>
- <td>${toolshed | h}</td>
- <td>${name | h}</td>
- <td>${owner | h}</td>
- <td>${changeset_revision | h}</td>
- </tr>
- %endfor
- </table>
- </div>
- <div style="clear: both"></div>
- %endif
- %if 'tool_dependencies' in metadata:
- <%
- # See if tool dependencies are packages, environment settings or both.
- tool_dependencies = metadata[ 'tool_dependencies' ]
- contains_packages = False
- for k in tool_dependencies.keys():
- if k != 'set_environment':
- contains_packages = True
- break
- contains_env_settings = 'set_environment' in tool_dependencies.keys()
- %>
- %if contains_packages:
- <div class="form-row">
- <table width="100%">
- <tr bgcolor="#D8D8D8" width="100%">
- <td><b>The following tool dependencies can optionally be automatically installed</i></td>
- </tr>
- </table>
- </div>
- <div style="clear: both"></div>
- <div class="form-row">
- <table class="grid">
- <tr>
- <td><b>name</b></td>
- <td><b>version</b></td>
- <td><b>type</b></td>
- </tr>
- %for dependency_key, requirements_dict in tool_dependencies.items():
- %if dependency_key != 'set_environment':
- <%
- name = requirements_dict[ 'name' ]
- version = requirements_dict[ 'version' ]
- type = requirements_dict[ 'type' ]
- %>
- <tr>
- <td>${name | h}</td>
- <td>${version | h}</td>
- <td>${type | h}</td>
- </tr>
- %endif
- %endfor
- </table>
- </div>
- <div style="clear: both"></div>
- %endif
- %if contains_env_settings:
- <div class="form-row">
- <table width="100%">
- <tr bgcolor="#D8D8D8" width="100%">
- <td><b>The following environment settings can optionally be handled as part of the installation</i></td>
- </tr>
- </table>
- </div>
- <div style="clear: both"></div>
- <div class="form-row">
- <table class="grid">
- <tr>
- <td><b>name</b></td>
- <td><b>type</b></td>
- </tr>
- <% environment_settings = tool_dependencies[ 'set_environment' ] %>
- %for requirements_dict in environment_settings:
- <tr>
- <td>${requirements_dict[ 'name' ] | h}</td>
- <td>${requirements_dict[ 'type' ] | h}</td>
- </tr>
- %endfor
- </table>
- </div>
- <div style="clear: both"></div>
- %endif
- %endif
- %if 'tools' in metadata:
- <div class="form-row">
- <table width="100%">
- <tr bgcolor="#D8D8D8" width="100%">
- <td><b>Valid 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 index, tool_dict in enumerate( tool_dicts ):
- <tr>
- <td>
- <div style="float:left;" class="menubutton split popup" id="tool-${index}-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-${index}-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' ] | h}</td>
- <td>${tool_dict[ 'version' ] | h}</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 | h}
- %else:
- none
- %endif
- </td>
- </tr>
- %endfor
- </table>
- </div>
- <div style="clear: both"></div>
- %endif
- %if 'invalid_tools' in metadata:
- <div class="form-row">
- <table width="100%">
- <tr bgcolor="#D8D8D8" width="100%">
- <td><b>Invalid tools</b><i> - click the tool config file name to see why the tool is invalid</i></td>
- </tr>
- </table>
- </div>
- <div style="clear: both"></div>
- <div class="form-row">
- <% invalid_tool_configs = metadata[ 'invalid_tools' ] %>
- <table class="grid">
- %for invalid_tool_config in invalid_tool_configs:
- <tr>
- <td>
- <a class="view-info" href="${h.url_for( controller='repository', action='load_invalid_tool', repository_id=trans.security.encode_id( repository.id ), tool_config=invalid_tool_config, changeset_revision=changeset_revision )}">
- ${invalid_tool_config | h}
- </a>
- </td>
- </tr>
- %endfor
- </table>
- </div>
- <div style="clear: both"></div>
- %endif
- %if 'workflows' in metadata:
- ## metadata[ 'workflows' ] is a list of tuples where each contained tuple is
- ## [ <relative path to the .ga file in the repository>, <exported workflow dict> ]
- <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_tups = metadata[ 'workflows' ] %>
- <table class="grid">
- <tr>
- <td><b>name</b></td>
- <td><b>steps</b></td>
- <td><b>format-version</b></td>
- <td><b>annotation</b></td>
- </tr>
- %for workflow_tup in workflow_tups:
- <%
- relative_path = workflow_tup[0]
- workflow_dict = workflow_tup[1]
- workflow_name = workflow_dict[ 'name' ]
- ## Initially steps were not stored in the metadata record.
- steps = workflow_dict.get( 'steps', [] )
- format_version = workflow_dict[ 'format-version' ]
- annotation = workflow_dict[ 'annotation' ]
- %>
- <tr>
- <td>
- <a href="${h.url_for( controller='workflow', action='view_workflow', repository_metadata_id=repository_metadata_id, workflow_name=tool_shed_encode( workflow_name ) )}">${workflow_name | h}</a>
- </td>
- <td>
- %if steps:
- ${len( steps )}
- %else:
- unknown
- %endif
- </td>
- <td>${format_version | h}</td>
- <td>${annotation | h}</td>
- </tr>
- %endfor
- </table>
- </div>
- <div style="clear: both"></div>
- %endif
- %if 'datatypes' in metadata:
- <div class="form-row">
- <table width="100%">
- <tr bgcolor="#D8D8D8" width="100%">
- <td><b>Data types</b></td>
- </tr>
- </table>
- </div>
- <div style="clear: both"></div>
- <div class="form-row">
- <% datatypes_dicts = metadata[ 'datatypes' ] %>
- <table class="grid">
- <tr>
- <td><b>extension</b></td>
- <td><b>type</b></td>
- <td><b>mimetype</b></td>
- <td><b>subclass</b></td>
- </tr>
- %for datatypes_dict in datatypes_dicts:
- <%
- extension = datatypes_dict.get( 'extension', ' ' )
- dtype = datatypes_dict.get( 'dtype', ' ' )
- mimetype = datatypes_dict.get( 'mimetype', ' ' )
- subclass = datatypes_dict.get( 'subclass', ' ' )
- %>
- <tr>
- <td>${extension | h}</td>
- <td>${dtype | h}</td>
- <td>${mimetype | h}</td>
- <td>${subclass | h}</td>
- </tr>
- %endfor
- </table>
- </div>
- <div style="clear: both"></div>
- %endif
+ %if valid_tools_root_folder:
+ <p/>
+ <% row_counter = RowCounter() %>
+ <table cellspacing="0" cellpadding="0" border="0" width="100%" class="tables container-table" id="valid_tools">
+ ${self.render_folder( valid_tools_root_folder, 0, parent=None, row_counter=row_counter, is_root_folder=True )}
+ </table>
+ %endif
+ %if invalid_tools_root_folder:
+ <p/>
+ <% row_counter = RowCounter() %>
+ <table cellspacing="0" cellpadding="0" border="0" width="100%" class="tables container-table" id="invalid_tools">
+ ${self.render_folder( invalid_tools_root_folder, 0, parent=None, row_counter=row_counter, is_root_folder=True )}
+ </table>
+ %endif
+ %if workflows_root_folder:
+ <p/>
+ <% row_counter = RowCounter() %>
+ <table cellspacing="0" cellpadding="0" border="0" width="100%" class="tables container-table" id="workflows">
+ ${self.render_folder( workflows_root_folder, 0, parent=None, row_counter=row_counter, is_root_folder=True )}
+ </table>
+ %endif
+ %if datatypes_root_folder:
+ <p/>
+ <% row_counter = RowCounter() %>
+ <table cellspacing="0" cellpadding="0" border="0" width="100%" class="tables container-table" id="datatypes">
+ ${self.render_folder( datatypes_root_folder, 0, parent=None, row_counter=row_counter, is_root_folder=True )}
+ </table>
%endif
</div></div>
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c templates/webapps/community/repository/manage_repository.mako
--- a/templates/webapps/community/repository/manage_repository.mako
+++ b/templates/webapps/community/repository/manage_repository.mako
@@ -16,10 +16,6 @@
can_set_metadata = not is_new and not is_deprecated
can_rate = not is_new and not is_deprecated and trans.user and repository.user != trans.user
can_view_change_log = not is_new
- if can_push:
- browse_label = 'Browse or delete repository tip files'
- else:
- browse_label = 'Browse repository tip files'
can_set_malicious = metadata and can_set_metadata and is_admin and changeset_revision == repository.tip( trans.app )
can_deprecate = not is_new and trans.user and ( is_admin or repository.user == trans.user ) and not is_deprecated
can_undeprecate = trans.user and ( is_admin or repository.user == trans.user ) and is_deprecated
@@ -27,6 +23,11 @@
has_readme = metadata and 'readme' in metadata
can_review_repository = not is_deprecated and trans.app.security_agent.user_can_review_repositories( trans.user )
reviewing_repository = cntrller and cntrller == 'repository_review'
+
+ if can_push:
+ browse_label = 'Browse or delete repository tip files'
+ else:
+ browse_label = 'Browse repository tip files'
if changeset_revision == repository.tip( trans.app ):
tip_str = 'repository tip'
else:
@@ -42,10 +43,15 @@
%><%inherit file="${inherit(context)}"/>
+<%def name="stylesheets()">
+ ${parent.stylesheets()}
+ ${h.css( "library" )}
+</%def>
+
<%def name="javascripts()">
${parent.javascripts()}
- ${h.js( "libs/jquery/jquery.rating" )}
- ${common_javascripts(repository)}
+ ${h.js("libs/jquery/jquery.rating", "libs/jquery/jstorage" )}
+ ${dependency_javascripts()}
</%def><br/><br/>
@@ -204,7 +210,7 @@
</form></div></div>
-${render_repository_items( repository_metadata_id, changeset_revision, metadata, can_set_metadata=True )}
+${render_repository_items( repository_metadata_id, changeset_revision, metadata, containers_dict, can_set_metadata=True )}
<p/><div class="toolForm"><div class="toolFormTitle">Manage categories</div>
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c 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
@@ -28,10 +28,15 @@
%><%inherit file="${inherit(context)}"/>
+<%def name="stylesheets()">
+ ${parent.stylesheets()}
+ ${h.css( "library" )}
+</%def>
+
<%def name="javascripts()">
${parent.javascripts()}
- ${h.js( "libs/jquery/jquery.rating" )}
- ${common_javascripts(repository)}
+ ${h.js("libs/jquery/jquery.rating", "libs/jquery/jstorage" )}
+ ${dependency_javascripts()}
</%def><br/><br/>
@@ -79,4 +84,4 @@
</div></div><p/>
-${render_repository_items( repository_metadata_id, changeset_revision, metadata, can_set_metadata=False )}
+${render_repository_items( repository_metadata_id, changeset_revision, metadata, containers_dict, can_set_metadata=False )}
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c templates/webapps/community/repository/view_repository.mako
--- a/templates/webapps/community/repository/view_repository.mako
+++ b/templates/webapps/community/repository/view_repository.mako
@@ -32,10 +32,15 @@
%><%inherit file="${inherit(context)}"/>
+<%def name="stylesheets()">
+ ${parent.stylesheets()}
+ ${h.css( "library" )}
+</%def>
+
<%def name="javascripts()">
${parent.javascripts()}
- ${h.js( "libs/jquery/jquery.rating" )}
- ${common_javascripts(repository)}
+ ${h.js("libs/jquery/jquery.rating", "libs/jquery/jstorage" )}
+ ${dependency_javascripts()}
</%def><br/><br/>
@@ -181,7 +186,7 @@
%endif
</div></div>
-${render_repository_items( repository_metadata_id, changeset_revision, metadata, can_set_metadata=False )}
+${render_repository_items( repository_metadata_id, changeset_revision, metadata, containers_dict, can_set_metadata=False )}
%if repository.categories:
<p/><div class="toolForm">
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c templates/webapps/community/repository_review/browse_review.mako
--- a/templates/webapps/community/repository_review/browse_review.mako
+++ b/templates/webapps/community/repository_review/browse_review.mako
@@ -4,7 +4,7 @@
<%
from galaxy.web.form_builder import CheckboxField
- from galaxy.webapps.community.controllers.common import STRSEP
+ from galaxy.webapps.community.util.container_util import STRSEP
can_manage_repository = is_admin or repository.user == trans.user
%>
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c templates/webapps/community/repository_review/edit_review.mako
--- a/templates/webapps/community/repository_review/edit_review.mako
+++ b/templates/webapps/community/repository_review/edit_review.mako
@@ -5,7 +5,7 @@
<%
from galaxy.web.form_builder import CheckboxField
from galaxy.webapps.community.controllers.repository_review import build_approved_select_field
- from galaxy.webapps.community.controllers.common import STRSEP
+ from galaxy.webapps.community.util.container_util import STRSEP
can_manage_repository = is_admin or repository.user == trans.user
%>
diff -r eea034b7cc625fa294fdd1e071d99defb40f67d3 -r 519b7df6d72a28689582e02879026c04b2214f2c templates/webapps/community/repository_review/reviews_of_changeset_revision.mako
--- a/templates/webapps/community/repository_review/reviews_of_changeset_revision.mako
+++ b/templates/webapps/community/repository_review/reviews_of_changeset_revision.mako
@@ -5,7 +5,7 @@
<%
from galaxy.webapps.community.controllers.repository_review import build_approved_select_field
- from galaxy.webapps.community.controllers.common import STRSEP
+ from galaxy.webapps.community.util.container_util import STRSEP
is_admin = trans.user_is_admin()
is_new = repository.is_new( trans.app )
can_browse_contents = not is_new
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.
1
0
commit/galaxy-central: greg: Fix the tool migration process that was broken due to the recent changes in the imports to various Galaxy framework files, mostly the Galaxy model.
by Bitbucket 24 Nov '12
by Bitbucket 24 Nov '12
24 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/eea034b7cc62/
changeset: eea034b7cc62
user: greg
date: 2012-11-24 16:21:48
summary: Fix the tool migration process that was broken due to the recent changes in the imports to various Galaxy framework files, mostly the Galaxy model.
affected #: 4 files
diff -r 1d078ed70cb8faf207c6367761a683bf6d9c3e68 -r eea034b7cc625fa294fdd1e071d99defb40f67d3 lib/galaxy/tool_shed/__init__.py
--- a/lib/galaxy/tool_shed/__init__.py
+++ b/lib/galaxy/tool_shed/__init__.py
@@ -2,7 +2,7 @@
Classes encapsulating the management of repositories installed from Galaxy tool sheds.
"""
import os
-import galaxy.util.shed_util
+from galaxy.util.shed_util import *
from galaxy.model.orm import *
from galaxy import eggs
@@ -27,7 +27,7 @@
ElementInclude.include( root )
tool_path = root.get( 'tool_path', None )
if tool_path:
- tool_shed = galaxy.util.shed_util.clean_tool_shed_url( tool_shed_repository.tool_shed )
+ tool_shed = clean_tool_shed_url( tool_shed_repository.tool_shed )
relative_path = os.path.join( tool_path,
tool_shed,
'repos',
@@ -44,13 +44,13 @@
.order_by( self.model.ToolShedRepository.table.c.id ):
relative_install_dir = self.get_repository_install_dir( tool_shed_repository )
if relative_install_dir:
- installed_repository_dict = galaxy.util.shed_util.load_installed_datatypes( self.app, tool_shed_repository, relative_install_dir )
+ installed_repository_dict = load_installed_datatypes( self.app, tool_shed_repository, relative_install_dir )
if installed_repository_dict:
self.installed_repository_dicts.append( installed_repository_dict )
def load_proprietary_converters_and_display_applications( self, deactivate=False ):
for installed_repository_dict in self.installed_repository_dicts:
if installed_repository_dict[ 'converter_path' ]:
- galaxy.util.shed_util.load_installed_datatype_converters( self.app, installed_repository_dict, deactivate=deactivate )
+ load_installed_datatype_converters( self.app, installed_repository_dict, deactivate=deactivate )
if installed_repository_dict[ 'display_path' ]:
- galaxy.util.shed_util.load_installed_display_applications( self.app, installed_repository_dict, deactivate=deactivate )
+ load_installed_display_applications( self.app, installed_repository_dict, deactivate=deactivate )
\ No newline at end of file
diff -r 1d078ed70cb8faf207c6367761a683bf6d9c3e68 -r eea034b7cc625fa294fdd1e071d99defb40f67d3 lib/galaxy/tool_shed/migrate/common.py
--- a/lib/galaxy/tool_shed/migrate/common.py
+++ b/lib/galaxy/tool_shed/migrate/common.py
@@ -2,6 +2,7 @@
import galaxy.config
import galaxy.datatypes.registry
from galaxy import tools
+from galaxy.tools.data import *
import galaxy.model.mapping
import galaxy.tools.search
from galaxy.objectstore import build_object_store_from_config
@@ -42,8 +43,8 @@
# Load the data types in the Galaxy distribution, which are defined in self.config.datatypes_config.
self.datatypes_registry.load_datatypes( self.config.root, self.config.datatypes_config )
# Initialize tool data tables using the config defined by self.config.tool_data_table_config_path.
- self.tool_data_tables = galaxy.tools.data.ToolDataTableManager( tool_data_path=self.config.tool_data_path,
- config_filename=self.config.tool_data_table_config_path )
+ self.tool_data_tables = ToolDataTableManager( tool_data_path=self.config.tool_data_path,
+ config_filename=self.config.tool_data_table_config_path )
# Load additional entries defined by self.config.shed_tool_data_table_config into tool data tables.
self.tool_data_tables.load_from_config_file( config_filename=self.config.shed_tool_data_table_config,
tool_data_path=self.tool_data_tables.tool_data_path,
diff -r 1d078ed70cb8faf207c6367761a683bf6d9c3e68 -r eea034b7cc625fa294fdd1e071d99defb40f67d3 lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -1,7 +1,6 @@
import os, tempfile, shutil, logging, urllib2
from galaxy import util
from galaxy.datatypes.checkers import *
-from galaxy.datatypes.sniff import is_column_based
from galaxy.util.json import *
from galaxy.util.shed_util_common import *
from galaxy.tools.search import ToolBoxSearch
@@ -475,13 +474,6 @@
else:
tool_section = None
return tool_section
-def generate_workflow_metadata( relative_path, exported_workflow_dict, metadata_dict ):
- """Update the received metadata_dict with changes that have been applied to the received exported_workflow_dict."""
- if 'workflows' in metadata_dict:
- metadata_dict[ 'workflows' ].append( ( relative_path, exported_workflow_dict ) )
- else:
- metadata_dict[ 'workflows' ] = [ ( relative_path, exported_workflow_dict ) ]
- return metadata_dict
def get_config( config_file, repo, ctx, dir ):
"""Return the latest version of config_filename from the repository manifest."""
config_file = strip_path( config_file )
@@ -817,6 +809,24 @@
parent_id=tool_version_using_parent_id.id )
sa_session.add( tool_version_association )
sa_session.flush()
+def is_column_based( fname, sep='\t', skip=0, is_multi_byte=False ):
+ """See if the file is column based with respect to a separator."""
+ headers = get_headers( fname, sep, is_multi_byte=is_multi_byte )
+ count = 0
+ if not headers:
+ return False
+ for hdr in headers[ skip: ]:
+ if hdr and hdr[ 0 ] and not hdr[ 0 ].startswith( '#' ):
+ if len( hdr ) > 1:
+ count = len( hdr )
+ break
+ if count < 2:
+ return False
+ for hdr in headers[ skip: ]:
+ if hdr and hdr[ 0 ] and not hdr[ 0 ].startswith( '#' ):
+ if len( hdr ) != count:
+ return False
+ return True
def is_data_index_sample_file( file_path ):
"""
Attempt to determine if a .sample file is appropriate for copying to ~/tool-data when a tool shed repository is being installed
diff -r 1d078ed70cb8faf207c6367761a683bf6d9c3e68 -r eea034b7cc625fa294fdd1e071d99defb40f67d3 lib/galaxy/util/shed_util_common.py
--- a/lib/galaxy/util/shed_util_common.py
+++ b/lib/galaxy/util/shed_util_common.py
@@ -2,6 +2,7 @@
from galaxy import util
from galaxy.tools import parameters
from galaxy.util import inflector
+from galaxy.util.json import *
from galaxy.web import url_for
from galaxy.web.form_builder import SelectField
from galaxy.datatypes.checkers import *
@@ -724,6 +725,13 @@
else:
metadata_dict[ 'tools' ] = [ tool_dict ]
return metadata_dict
+def generate_workflow_metadata( relative_path, exported_workflow_dict, metadata_dict ):
+ """Update the received metadata_dict with changes that have been applied to the received exported_workflow_dict."""
+ if 'workflows' in metadata_dict:
+ metadata_dict[ 'workflows' ].append( ( relative_path, exported_workflow_dict ) )
+ else:
+ metadata_dict[ 'workflows' ] = [ ( relative_path, exported_workflow_dict ) ]
+ return metadata_dict
def get_changectx_for_changeset( repo, changeset_revision, **kwd ):
"""Retrieve a specified changectx from a repository"""
for changeset in repo.changelog:
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.
1
0
commit/galaxy-central: inithello: Added tool shed functional test features for tool metadata.
by Bitbucket 21 Nov '12
by Bitbucket 21 Nov '12
21 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/1d078ed70cb8/
changeset: 1d078ed70cb8
user: inithello
date: 2012-11-21 22:32:17
summary: Added tool shed functional test features for tool metadata.
affected #: 2 files
diff -r 7d278a17747ad9cb35b1af5ec011e46f814c339a -r 1d078ed70cb8faf207c6367761a683bf6d9c3e68 test/tool_shed/base/twilltestcase.py
--- a/test/tool_shed/base/twilltestcase.py
+++ b/test/tool_shed/base/twilltestcase.py
@@ -30,6 +30,11 @@
if strings_not_displayed:
for string in strings_not_displayed:
self.check_string_not_in_page( string )
+ def check_for_tool_metadata(self, repository, changeset_revision, tool_id, strings_displayed=[], strings_not_displayed=[] ):
+ url = '/repository/view_tool_metadata?repository_id=%s&changeset_revision=%s&tool_id=%s' % \
+ ( self.security.encode_id( repository.id ), changeset_revision, tool_id )
+ self.visit_url( url )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
def check_for_valid_tools( self, repository ):
self.manage_repository( repository )
self.check_page_for_string( '<b>Valid tools</b><i> - click the name to preview the tool' )
@@ -118,6 +123,14 @@
tc.fv( "3", "allow_push", '+%s' % username )
tc.submit( 'user_access_button' )
self.check_for_strings( strings_displayed, strings_not_displayed )
+ def load_display_tool_page( self, repository, tool_xml_filename, changeset_revision, strings_displayed=[], strings_not_displayed=[] ):
+ repository_id = self.security.encode_id( repository.id )
+ repo_subdirectory = '%03d' % int( repository.id / 1000 )
+ tool_xml_path = '%2f'.join( [ 'database', 'community_files', repo_subdirectory, 'repo_%d' % repository.id, tool_xml_filename ] )
+ url = '/repository/display_tool?repository_id=%s&tool_config=%s&changeset_revision=%s' % \
+ ( repository_id, tool_xml_path, changeset_revision )
+ self.visit_url( url )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
def manage_repository( self, repository, strings_displayed=[], strings_not_displayed=[] ):
url = '/repository/manage_repository?id=%s' % self.security.encode_id( repository.id )
self.visit_url( url )
diff -r 7d278a17747ad9cb35b1af5ec011e46f814c339a -r 1d078ed70cb8faf207c6367761a683bf6d9c3e68 test/tool_shed/functional/test_0000_create_repository.py
--- a/test/tool_shed/functional/test_0000_create_repository.py
+++ b/test/tool_shed/functional/test_0000_create_repository.py
@@ -69,11 +69,18 @@
strings_displayed=[ "The file '%s' has been successfully uploaded to the repository." % filter_filename ], \
commit_message="Uploaded filtering 1.1.0" )
self.check_for_valid_tools( repository )
- latest_changeset_revision = self.get_latest_repository_metadata_for_repository( repository )
+ latest_repository_metadata = self.get_latest_repository_metadata_for_repository( repository )
+ changeset_revision = latest_repository_metadata.changeset_revision
self.check_repository_changelog( repository, strings_displayed=[ 'Repository metadata is associated with this change set.' ] )
self.set_repository_malicious( repository, strings_displayed=[ 'The repository tip has been defined as malicious.' ] )
self.unset_repository_malicious( repository, strings_displayed=[ 'The repository tip has been defined as <b>not</b> malicious.' ] )
-# self.check_tool_metadata( repository, latest_changeset_revision, strings_displayed=[ 'Filter1' ] )
+ self.load_display_tool_page( repository, tool_xml_filename='filtering.xml', \
+ changeset_revision=changeset_revision, \
+ strings_displayed=[ 'Filter (version 1.1.0)', "c1=='chr1'" ], \
+ strings_not_displayed=[] )
+ tool = latest_repository_metadata.metadata[ 'tools' ][0]
+ metadata_strings_displayed = [ tool[ 'guid' ], tool[ 'version' ], tool[ 'id' ], tool[ 'name' ], tool[ 'description' ], changeset_revision ]
+ self.check_for_tool_metadata( repository, changeset_revision, 'Filter1', strings_displayed=metadata_strings_displayed )
def test_0035_repository_browse_page( self ):
'''Visit the repository browse page'''
repository = get_repository_by_name( repository_name, admin_username )
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.
1
0
commit/galaxy-central: carlfeberhard: history panel: documenting fix to show display and edit attributes buttons for HDA in the error state.
by Bitbucket 21 Nov '12
by Bitbucket 21 Nov '12
21 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/7d278a17747a/
changeset: 7d278a17747a
user: carlfeberhard
date: 2012-11-21 20:02:58
summary: history panel: documenting fix to show display and edit attributes buttons for HDA in the error state.
affected #: 2 files
diff -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 -r 7d278a17747ad9cb35b1af5ec011e46f814c339a static/scripts/mvc/dataset/hda-base.js
--- a/static/scripts/mvc/dataset/hda-base.js
+++ b/static/scripts/mvc/dataset/hda-base.js
@@ -181,7 +181,8 @@
* @returns {jQuery} rendered DOM
*/
_render_displayButton : function(){
- // don't show display if not in ready state, error'd, or not accessible
+ // don't show display if not in ready state or not accessible
+ // DO show if in error (ala previous history panel)
if( ( !this.model.inReadyState() )
//|| ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.ERROR )
|| ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
diff -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 -r 7d278a17747ad9cb35b1af5ec011e46f814c339a static/scripts/mvc/dataset/hda-edit.js
--- a/static/scripts/mvc/dataset/hda-edit.js
+++ b/static/scripts/mvc/dataset/hda-edit.js
@@ -64,8 +64,8 @@
* @returns {jQuery} rendered DOM
*/
_render_editButton : function(){
- // don't show edit while uploading
- //TODO??: error?
+ // don't show edit while uploading, in-accessible
+ // DO show if in error (ala previous history panel)
//TODO??: not viewable/accessible are essentially the same (not viewable set from accessible)
if( ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.UPLOAD )
//|| ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.ERROR )
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.
1
0
21 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/8481560e2c32/
changeset: 8481560e2c32
user: carlfeberhard
date: 2012-11-21 19:28:33
summary: history panel: moved refresh into 'History' header bar. Moved 'Collapse Expanded Datasets', 'Show/Hide Deleted Datasets', and 'Show/Hide Hidden Datasets' into 'History' gear menu. Removed gear menu from current history. Packed scripts.
affected #: 15 files
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 static/scripts/mvc/dataset/hda-base.js
--- a/static/scripts/mvc/dataset/hda-base.js
+++ b/static/scripts/mvc/dataset/hda-base.js
@@ -183,7 +183,7 @@
_render_displayButton : function(){
// don't show display if not in ready state, error'd, or not accessible
if( ( !this.model.inReadyState() )
- || ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.ERROR )
+ //|| ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.ERROR )
|| ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
|| ( !this.model.get( 'accessible' ) ) ){
this.displayButton = null;
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 static/scripts/mvc/dataset/hda-edit.js
--- a/static/scripts/mvc/dataset/hda-edit.js
+++ b/static/scripts/mvc/dataset/hda-edit.js
@@ -68,7 +68,7 @@
//TODO??: error?
//TODO??: not viewable/accessible are essentially the same (not viewable set from accessible)
if( ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.UPLOAD )
- || ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.ERROR )
+ //|| ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.ERROR )
|| ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
|| ( !this.model.get( 'accessible' ) ) ){
this.editButton = null;
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 static/scripts/mvc/dataset/hda-model.js
--- a/static/scripts/mvc/dataset/hda-model.js
+++ b/static/scripts/mvc/dataset/hda-model.js
@@ -125,6 +125,8 @@
*/
inReadyState : function(){
var state = this.get( 'state' );
+ //TODO: to list inclusion test
+ //TODO: class level readyStates list
return (
( state === HistoryDatasetAssociation.STATES.NEW )
|| ( state === HistoryDatasetAssociation.STATES.OK )
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 static/scripts/mvc/history/history-panel.js
--- a/static/scripts/mvc/history/history-panel.js
+++ b/static/scripts/mvc/history/history-panel.js
@@ -127,7 +127,6 @@
/** event map
*/
events : {
- 'click #history-refresh' : function(){ window.location.reload(); },
'click #history-tag' : 'loadAndDisplayTags'
},
@@ -253,7 +252,6 @@
//NOTE: this is done before the items, since item views should handle theirs themselves
newRender.append( HistoryPanel.templates.historyPanel( modelJson ) );
newRender.find( '.tooltip' ).tooltip({ placement: 'bottom' });
- this._setUpActionButton( newRender.find( '#history-action-popup' ) );
// render hda views (if any and any shown (show_deleted/hidden)
//TODO: this seems too elaborate
@@ -305,22 +303,6 @@
return historyView.urls;
},
- /** Set up history actions popup menu
- * @param {jQuery} $button jQuery dom object to turn into the 'button' that activates the menu
- * @see make_popupmenu (galaxy-base.js)
- */
- _setUpActionButton : function( $button ){
- var historyPanel = this,
- show_deletedText = ( this.storage.get( 'show_deleted' ) )?( 'Hide deleted' ):( 'Show deleted' ),
- show_hiddenText = ( this.storage.get( 'show_hidden' ) )?( 'Hide hidden' ):( 'Show hidden' ),
- menuActions = {};
- //menuActions[ _l( 'refresh' ) ] = function(){ window.location.reload(); };
- menuActions[ _l( 'collapse all' ) ] = function(){ historyPanel.hideAllHdaBodies(); };
- menuActions[ _l( show_deletedText ) ] = function(){ historyPanel.toggleShowDeleted(); };
- menuActions[ _l( show_hiddenText ) ] = function(){ historyPanel.toggleShowHidden(); };
- make_popupmenu( $button, menuActions );
- },
-
/** Set up/render a view for each HDA to be shown, init with model and listeners.
* HDA views are cached to the map this.hdaViews (using the model.id as key).
* @param {jQuery} $whereTo what dom element to prepend the HDA views to
@@ -441,7 +423,7 @@
/** Collapse all hda bodies and clear expandedHdas in the storage
*/
- hideAllHdaBodies : function(){
+ collapseAllHdaBodies : function(){
_.each( this.hdaViews, function( item ){
item.toggleBodyVisibility( null, false );
});
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 static/scripts/packed/mvc/dataset/hda-base.js
--- a/static/scripts/packed/mvc/dataset/hda-base.js
+++ b/static/scripts/packed/mvc/dataset/hda-base.js
@@ -1,1 +1,1 @@
-var HDABaseView=BaseView.extend(LoggableMixin).extend({tagName:"div",className:"historyItemContainer",initialize:function(a){this.log(this+".initialize:",a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton];if(!a.urlTemplates){throw ("HDAView needs urlTemplates on initialize")}this.urls=this._renderUrls(a.urlTemplates,this.model.toJSON());this.expanded=a.expanded||false;this.model.bind("change",this.render,this)},_renderUrls:function(d,a){var b=this,c={};_.each(d,function(e,f){if(_.isObject(e)){c[f]=b._renderUrls(e,a)}else{if(f==="meta_download"){c[f]=b._renderMetaDownloadUrls(e,a)}else{c[f]=_.template(e,a)}}});return c},_renderMetaDownloadUrls:function(b,a){return _.map(a.meta_files,function(c){return{url:_.template(b,{id:a.id,file_type:c.file_type}),file_type:c.file_type}})},render:function(){var b=this,e=this.model.get("id"),c=this.model.get("state"),a=$("<div/>").attr("id","historyItem-"+e),d=(this.$el.children().size()===0);this.$el.attr("id","historyItemContainer-"+e);a.addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+c);a.append(this._render_warnings());a.append(this._render_titleBar());this.body=$(this._render_body());a.append(this.body);make_popup_menus(a);a.find(".tooltip").tooltip({placement:"bottom"});this.$el.fadeOut("fast",function(){b.$el.children().remove();b.$el.append(a).fadeIn("fast",function(){b.log(b+" rendered:",b.$el);var f="rendered";if(d){f+=":initial"}else{if(b.model.inReadyState()){f+=":ready"}}b.trigger(f)})});return this},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());return a},_render_displayButton:function(){if((!this.model.inReadyState())||(this.model.get("state")===HistoryDatasetAssociation.STATES.ERROR)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.displayButton=null;return null}var a={icon_class:"display",target:"galaxy_main"};if(this.model.get("purged")){a.enabled=false;a.title=_l("Cannot display datasets removed from disk")}else{a.title=_l("Display data in browser");a.href=this.urls.display}this.displayButton=new IconButtonView({model:new IconButton(a)});return this.displayButton.render().$el},_render_titleLink:function(){return $(jQuery.trim(HDABaseView.templates.titleLink(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});return HDABaseView.templates.hdaSummary(a)},_render_primaryActionButtons:function(c){var a=this,b=$("<div/>").attr("id","primary-actions-"+this.model.get("id"));_.each(c,function(d){b.append(d.call(a))});return b},_render_downloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}var a=HDABaseView.templates.downloadLinks(_.extend(this.model.toJSON(),{urls:this.urls}));return $(a)},_render_showParamsButton:function(){this.showParamsButton=new IconButtonView({model:new IconButton({title:_l("View details"),href:this.urls.show_params,target:"galaxy_main",icon_class:"information"})});return this.showParamsButton.render().$el},_render_displayApps:function(){if(!this.model.hasData()){return null}var a=$("<div/>").addClass("display-apps");if(!_.isEmpty(this.model.get("display_types"))){a.append(HDABaseView.templates.displayApps({displayApps:this.model.get("display_types")}))}if(!_.isEmpty(this.model.get("display_apps"))){a.append(HDABaseView.templates.displayApps({displayApps:this.model.get("display_apps")}))}return a},_render_peek:function(){if(!this.model.get("peek")){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(this.model.get("peek")))},_render_body:function(){var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: block");switch(this.model.get("state")){case HistoryDatasetAssociation.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryDatasetAssociation.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryDatasetAssociation.STATES.PAUSED:this._render_body_paused(a);break;case HistoryDatasetAssociation.STATES.QUEUED:this._render_body_queued(a);break;case HistoryDatasetAssociation.STATES.RUNNING:this._render_body_running(a);break;case HistoryDatasetAssociation.STATES.ERROR:this._render_body_error(a);break;case HistoryDatasetAssociation.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryDatasetAssociation.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryDatasetAssociation.STATES.EMPTY:this._render_body_empty(a);break;case HistoryDatasetAssociation.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryDatasetAssociation.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+state+'".</div>'))}a.append('<div style="clear: both"></div>');if(this.expanded){a.show()}else{a.hide()}return a},_render_body_not_viewable:function(a){a.append($("<div>"+_l("You do not have permission to view dataset")+".</div>"))},_render_body_uploading:function(a){a.append($("<div>"+_l("Dataset is uploading")+"</div>"))},_render_body_queued:function(a){a.append($("<div>"+_l("Job is waiting to run")+".</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_paused:function(a){a.append($("<div>"+_l("Job is paused. Use the history menu to unpause")+".</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_running:function(a){a.append("<div>"+_l("Job is currently running")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append((_l("An error occurred running this job")+": <i>"+$.trim(this.model.get("misc_info"))+"</i>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers.concat([this._render_downloadButton])))},_render_body_discarded:function(a){a.append("<div>"+_l("The job creating this dataset was cancelled before completion")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_setting_metadata:function(a){a.append($("<div>"+_l("Metadata is being auto-detected")+".</div>"))},_render_body_empty:function(a){a.append($("<div>"+_l("No data")+": <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_failed_metadata:function(a){a.append($(HDABaseView.templates.failedMetadata(this.model.toJSON())));this._render_body_ok(a)},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));a.append('<div class="clear"/>');a.append(this._render_displayApps());a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility"},toggleBodyVisibility:function(c,a){var b=this,d=this.$el.find(".historyItemBody");a=(a===undefined)?(!d.is(":visible")):(a);if(a){d.slideDown("fast",function(){b.trigger("body-expanded",b.model.get("id"))})}else{d.slideUp("fast",function(){b.trigger("body-collapsed",b.model.get("id"))})}},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDABaseView("+a+")"}});HDABaseView.templates={warningMsg:Handlebars.templates["template-warningmessagesmall"],messages:Handlebars.templates["template-hda-warning-messages"],titleLink:Handlebars.templates["template-hda-titleLink"],hdaSummary:Handlebars.templates["template-hda-hdaSummary"],downloadLinks:Handlebars.templates["template-hda-downloadLinks"],failedMetadata:Handlebars.templates["template-hda-failedMetadata"],displayApps:Handlebars.templates["template-hda-displayApps"]};
\ No newline at end of file
+var HDABaseView=BaseView.extend(LoggableMixin).extend({tagName:"div",className:"historyItemContainer",initialize:function(a){this.log(this+".initialize:",a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton];if(!a.urlTemplates){throw ("HDAView needs urlTemplates on initialize")}this.urls=this._renderUrls(a.urlTemplates,this.model.toJSON());this.expanded=a.expanded||false;this.model.bind("change",this.render,this)},_renderUrls:function(d,a){var b=this,c={};_.each(d,function(e,f){if(_.isObject(e)){c[f]=b._renderUrls(e,a)}else{if(f==="meta_download"){c[f]=b._renderMetaDownloadUrls(e,a)}else{c[f]=_.template(e,a)}}});return c},_renderMetaDownloadUrls:function(b,a){return _.map(a.meta_files,function(c){return{url:_.template(b,{id:a.id,file_type:c.file_type}),file_type:c.file_type}})},render:function(){var b=this,e=this.model.get("id"),c=this.model.get("state"),a=$("<div/>").attr("id","historyItem-"+e),d=(this.$el.children().size()===0);this.$el.attr("id","historyItemContainer-"+e);a.addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+c);a.append(this._render_warnings());a.append(this._render_titleBar());this.body=$(this._render_body());a.append(this.body);make_popup_menus(a);a.find(".tooltip").tooltip({placement:"bottom"});this.$el.fadeOut("fast",function(){b.$el.children().remove();b.$el.append(a).fadeIn("fast",function(){b.log(b+" rendered:",b.$el);var f="rendered";if(d){f+=":initial"}else{if(b.model.inReadyState()){f+=":ready"}}b.trigger(f)})});return this},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());return a},_render_displayButton:function(){if((!this.model.inReadyState())||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.displayButton=null;return null}var a={icon_class:"display",target:"galaxy_main"};if(this.model.get("purged")){a.enabled=false;a.title=_l("Cannot display datasets removed from disk")}else{a.title=_l("Display data in browser");a.href=this.urls.display}this.displayButton=new IconButtonView({model:new IconButton(a)});return this.displayButton.render().$el},_render_titleLink:function(){return $(jQuery.trim(HDABaseView.templates.titleLink(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});return HDABaseView.templates.hdaSummary(a)},_render_primaryActionButtons:function(c){var a=this,b=$("<div/>").attr("id","primary-actions-"+this.model.get("id"));_.each(c,function(d){b.append(d.call(a))});return b},_render_downloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}var a=HDABaseView.templates.downloadLinks(_.extend(this.model.toJSON(),{urls:this.urls}));return $(a)},_render_showParamsButton:function(){this.showParamsButton=new IconButtonView({model:new IconButton({title:_l("View details"),href:this.urls.show_params,target:"galaxy_main",icon_class:"information"})});return this.showParamsButton.render().$el},_render_displayApps:function(){if(!this.model.hasData()){return null}var a=$("<div/>").addClass("display-apps");if(!_.isEmpty(this.model.get("display_types"))){a.append(HDABaseView.templates.displayApps({displayApps:this.model.get("display_types")}))}if(!_.isEmpty(this.model.get("display_apps"))){a.append(HDABaseView.templates.displayApps({displayApps:this.model.get("display_apps")}))}return a},_render_peek:function(){if(!this.model.get("peek")){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(this.model.get("peek")))},_render_body:function(){var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: block");switch(this.model.get("state")){case HistoryDatasetAssociation.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryDatasetAssociation.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryDatasetAssociation.STATES.PAUSED:this._render_body_paused(a);break;case HistoryDatasetAssociation.STATES.QUEUED:this._render_body_queued(a);break;case HistoryDatasetAssociation.STATES.RUNNING:this._render_body_running(a);break;case HistoryDatasetAssociation.STATES.ERROR:this._render_body_error(a);break;case HistoryDatasetAssociation.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryDatasetAssociation.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryDatasetAssociation.STATES.EMPTY:this._render_body_empty(a);break;case HistoryDatasetAssociation.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryDatasetAssociation.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+state+'".</div>'))}a.append('<div style="clear: both"></div>');if(this.expanded){a.show()}else{a.hide()}return a},_render_body_not_viewable:function(a){a.append($("<div>"+_l("You do not have permission to view dataset")+".</div>"))},_render_body_uploading:function(a){a.append($("<div>"+_l("Dataset is uploading")+"</div>"))},_render_body_queued:function(a){a.append($("<div>"+_l("Job is waiting to run")+".</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_paused:function(a){a.append($("<div>"+_l("Job is paused. Use the history menu to unpause")+".</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_running:function(a){a.append("<div>"+_l("Job is currently running")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append((_l("An error occurred running this job")+": <i>"+$.trim(this.model.get("misc_info"))+"</i>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers.concat([this._render_downloadButton])))},_render_body_discarded:function(a){a.append("<div>"+_l("The job creating this dataset was cancelled before completion")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_setting_metadata:function(a){a.append($("<div>"+_l("Metadata is being auto-detected")+".</div>"))},_render_body_empty:function(a){a.append($("<div>"+_l("No data")+": <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_failed_metadata:function(a){a.append($(HDABaseView.templates.failedMetadata(this.model.toJSON())));this._render_body_ok(a)},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));a.append('<div class="clear"/>');a.append(this._render_displayApps());a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility"},toggleBodyVisibility:function(c,a){var b=this,d=this.$el.find(".historyItemBody");a=(a===undefined)?(!d.is(":visible")):(a);if(a){d.slideDown("fast",function(){b.trigger("body-expanded",b.model.get("id"))})}else{d.slideUp("fast",function(){b.trigger("body-collapsed",b.model.get("id"))})}},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDABaseView("+a+")"}});HDABaseView.templates={warningMsg:Handlebars.templates["template-warningmessagesmall"],messages:Handlebars.templates["template-hda-warning-messages"],titleLink:Handlebars.templates["template-hda-titleLink"],hdaSummary:Handlebars.templates["template-hda-hdaSummary"],downloadLinks:Handlebars.templates["template-hda-downloadLinks"],failedMetadata:Handlebars.templates["template-hda-failedMetadata"],displayApps:Handlebars.templates["template-hda-displayApps"]};
\ No newline at end of file
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 static/scripts/packed/mvc/dataset/hda-edit.js
--- a/static/scripts/packed/mvc/dataset/hda-edit.js
+++ b/static/scripts/packed/mvc/dataset/hda-edit.js
@@ -1,1 +1,1 @@
-var HDAEditView=HDABaseView.extend(LoggableMixin).extend({initialize:function(a){HDABaseView.prototype.initialize.call(this,a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton,this._render_rerunButton]},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());a.append(this._render_editButton());a.append(this._render_deleteButton());return a},_render_editButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.UPLOAD)||(this.model.get("state")===HistoryDatasetAssociation.STATES.ERROR)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.editButton=null;return null}var c=this.model.get("purged"),a=this.model.get("deleted"),b={title:_l("Edit Attributes"),href:this.urls.edit,target:"galaxy_main",icon_class:"edit"};if(a||c){b.enabled=false;if(c){b.title=_l("Cannot edit attributes of datasets removed from disk")}else{if(a){b.title=_l("Undelete dataset to edit attributes")}}}this.editButton=new IconButtonView({model:new IconButton(b)});return this.editButton.render().$el},_render_deleteButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.deleteButton=null;return null}var a={title:_l("Delete"),href:this.urls["delete"],id:"historyItemDeleter-"+this.model.get("id"),icon_class:"delete"};if(this.model.get("deleted")||this.model.get("purged")){a={title:_l("Dataset is already deleted"),icon_class:"delete",enabled:false}}this.deleteButton=new IconButtonView({model:new IconButton(a)});return this.deleteButton.render().$el},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){_.extend(a,{dbkey_unknown_and_editable:true})}return HDABaseView.templates.hdaSummary(a)},_render_errButton:function(){if(this.model.get("state")!==HistoryDatasetAssociation.STATES.ERROR){this.errButton=null;return null}this.errButton=new IconButtonView({model:new IconButton({title:_l("View or report this error"),href:this.urls.report_error,target:"galaxy_main",icon_class:"bug"})});return this.errButton.render().$el},_render_rerunButton:function(){this.rerunButton=new IconButtonView({model:new IconButton({title:_l("Run this job again"),href:this.urls.rerun,target:"galaxy_main",icon_class:"arrow-circle"})});return this.rerunButton.render().$el},_render_visualizationsButton:function(){var c=this.model.get("dbkey"),a=this.model.get("visualizations"),f=this.urls.visualization,d={},g={dataset_id:this.model.get("id"),hda_ldda:"hda"};if(!(this.model.hasData())||!(a&&a.length)||!(f)){this.visualizationsButton=null;return null}this.visualizationsButton=new IconButtonView({model:new IconButton({title:_l("Visualize"),href:f,icon_class:"chart_curve"})});var b=this.visualizationsButton.render().$el;b.addClass("visualize-icon");if(c){g.dbkey=c}function e(h){switch(h){case"trackster":return create_trackster_action_fn(f,g,c);case"scatterplot":return create_scatterplot_action_fn(f,g);default:return function(){window.parent.location=f+"/"+h+"?"+$.param(g)}}}if(a.length===1){b.attr("title",a[0]);b.click(e(a[0]))}else{_.each(a,function(i){var h=i.charAt(0).toUpperCase()+i.slice(1);d[_l(h)]=e(i)});make_popupmenu(b,d)}return b},_render_secondaryActionButtons:function(b){var c=$("<div/>"),a=this;c.attr("style","float: right;").attr("id","secondary-actions-"+this.model.get("id"));_.each(b,function(d){c.append(d.call(a))});return c},_render_tagButton:function(){if(!(this.model.hasData())||(!this.urls.tags.get)){this.tagButton=null;return null}this.tagButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset tags"),target:"galaxy_main",href:this.urls.tags.get,icon_class:"tags"})});return this.tagButton.render().$el},_render_annotateButton:function(){if(!(this.model.hasData())||(!this.urls.annotation.get)){this.annotateButton=null;return null}this.annotateButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset annotation"),target:"galaxy_main",icon_class:"annotate"})});return this.annotateButton.render().$el},_render_tagArea:function(){if(!this.urls.tags.set){return null}return $(HDAEditView.templates.tagArea(_.extend(this.model.toJSON(),{urls:this.urls})))},_render_annotationArea:function(){if(!this.urls.annotation.get){return null}return $(HDAEditView.templates.annotationArea(_.extend(this.model.toJSON(),{urls:this.urls})))},_render_body_error:function(a){HDABaseView.prototype._render_body_error.call(this,a);var b=a.find("#primary-actions-"+this.model.get("id"));b.prepend(this._render_errButton())},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton,this._render_visualizationsButton]));a.append(this._render_secondaryActionButtons([this._render_tagButton,this._render_annotateButton]));a.append('<div class="clear"/>');a.append(this._render_tagArea());a.append(this._render_annotationArea());a.append(this._render_displayApps());a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility","click a.icon-button.tags":"loadAndDisplayTags","click a.icon-button.annotate":"loadAndDisplayAnnotation"},loadAndDisplayTags:function(b){this.log(this+".loadAndDisplayTags",b);var c=this.$el.find(".tag-area"),a=c.find(".tag-elt");if(c.is(":hidden")){if(!jQuery.trim(a.html())){$.ajax({url:this.urls.tags.get,error:function(){alert(_l("Tagging failed"))},success:function(d){a.html(d);a.find(".tooltip").tooltip();c.slideDown("fast")}})}else{c.slideDown("fast")}}else{c.slideUp("fast")}return false},loadAndDisplayAnnotation:function(b){this.log(this+".loadAndDisplayAnnotation",b);var d=this.$el.find(".annotation-area"),c=d.find(".annotation-elt"),a=this.urls.annotation.set;if(d.is(":hidden")){if(!jQuery.trim(c.html())){$.ajax({url:this.urls.annotation.get,error:function(){alert(_l("Annotations failed"))},success:function(e){if(e===""){e="<em>"+_l("Describe or add notes to dataset")+"</em>"}c.html(e);d.find(".tooltip").tooltip();async_save_text(c.attr("id"),c.attr("id"),a,"new_annotation",18,true,4);d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDAView("+a+")"}});HDAEditView.templates={tagArea:Handlebars.templates["template-hda-tagArea"],annotationArea:Handlebars.templates["template-hda-annotationArea"]};function create_scatterplot_action_fn(a,b){action=function(){var d=$(window.parent.document).find("iframe#galaxy_main"),c=a+"/scatterplot?"+$.param(b);d.attr("src",c);$("div.popmenu-wrapper").remove();return false};return action}function create_trackster_action_fn(a,c,b){return function(){var d={};if(b){d.dbkey=b}$.ajax({url:a+"/list_tracks?f-"+$.param(d),dataType:"html",error:function(){alert(_l("Could not add this dataset to browser")+".")},success:function(e){var f=window.parent;f.show_modal(_l("View Data in a New or Saved Visualization"),"",{Cancel:function(){f.hide_modal()},"View in saved visualization":function(){f.show_modal(_l("Add Data to Saved Visualization"),e,{Cancel:function(){f.hide_modal()},"Add to visualization":function(){$(f.document).find("input[name=id]:checked").each(function(){var g=$(this).val();c.id=g;f.location=a+"/trackster?"+$.param(c)})}})},"View in new visualization":function(){f.location=a+"/trackster?"+$.param(c)}})}});return false}};
\ No newline at end of file
+var HDAEditView=HDABaseView.extend(LoggableMixin).extend({initialize:function(a){HDABaseView.prototype.initialize.call(this,a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton,this._render_rerunButton]},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());a.append(this._render_editButton());a.append(this._render_deleteButton());return a},_render_editButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.UPLOAD)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.editButton=null;return null}var c=this.model.get("purged"),a=this.model.get("deleted"),b={title:_l("Edit Attributes"),href:this.urls.edit,target:"galaxy_main",icon_class:"edit"};if(a||c){b.enabled=false;if(c){b.title=_l("Cannot edit attributes of datasets removed from disk")}else{if(a){b.title=_l("Undelete dataset to edit attributes")}}}this.editButton=new IconButtonView({model:new IconButton(b)});return this.editButton.render().$el},_render_deleteButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.deleteButton=null;return null}var a={title:_l("Delete"),href:this.urls["delete"],id:"historyItemDeleter-"+this.model.get("id"),icon_class:"delete"};if(this.model.get("deleted")||this.model.get("purged")){a={title:_l("Dataset is already deleted"),icon_class:"delete",enabled:false}}this.deleteButton=new IconButtonView({model:new IconButton(a)});return this.deleteButton.render().$el},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){_.extend(a,{dbkey_unknown_and_editable:true})}return HDABaseView.templates.hdaSummary(a)},_render_errButton:function(){if(this.model.get("state")!==HistoryDatasetAssociation.STATES.ERROR){this.errButton=null;return null}this.errButton=new IconButtonView({model:new IconButton({title:_l("View or report this error"),href:this.urls.report_error,target:"galaxy_main",icon_class:"bug"})});return this.errButton.render().$el},_render_rerunButton:function(){this.rerunButton=new IconButtonView({model:new IconButton({title:_l("Run this job again"),href:this.urls.rerun,target:"galaxy_main",icon_class:"arrow-circle"})});return this.rerunButton.render().$el},_render_visualizationsButton:function(){var c=this.model.get("dbkey"),a=this.model.get("visualizations"),f=this.urls.visualization,d={},g={dataset_id:this.model.get("id"),hda_ldda:"hda"};if(!(this.model.hasData())||!(a&&a.length)||!(f)){this.visualizationsButton=null;return null}this.visualizationsButton=new IconButtonView({model:new IconButton({title:_l("Visualize"),href:f,icon_class:"chart_curve"})});var b=this.visualizationsButton.render().$el;b.addClass("visualize-icon");if(c){g.dbkey=c}function e(h){switch(h){case"trackster":return create_trackster_action_fn(f,g,c);case"scatterplot":return create_scatterplot_action_fn(f,g);default:return function(){window.parent.location=f+"/"+h+"?"+$.param(g)}}}if(a.length===1){b.attr("title",a[0]);b.click(e(a[0]))}else{_.each(a,function(i){var h=i.charAt(0).toUpperCase()+i.slice(1);d[_l(h)]=e(i)});make_popupmenu(b,d)}return b},_render_secondaryActionButtons:function(b){var c=$("<div/>"),a=this;c.attr("style","float: right;").attr("id","secondary-actions-"+this.model.get("id"));_.each(b,function(d){c.append(d.call(a))});return c},_render_tagButton:function(){if(!(this.model.hasData())||(!this.urls.tags.get)){this.tagButton=null;return null}this.tagButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset tags"),target:"galaxy_main",href:this.urls.tags.get,icon_class:"tags"})});return this.tagButton.render().$el},_render_annotateButton:function(){if(!(this.model.hasData())||(!this.urls.annotation.get)){this.annotateButton=null;return null}this.annotateButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset annotation"),target:"galaxy_main",icon_class:"annotate"})});return this.annotateButton.render().$el},_render_tagArea:function(){if(!this.urls.tags.set){return null}return $(HDAEditView.templates.tagArea(_.extend(this.model.toJSON(),{urls:this.urls})))},_render_annotationArea:function(){if(!this.urls.annotation.get){return null}return $(HDAEditView.templates.annotationArea(_.extend(this.model.toJSON(),{urls:this.urls})))},_render_body_error:function(a){HDABaseView.prototype._render_body_error.call(this,a);var b=a.find("#primary-actions-"+this.model.get("id"));b.prepend(this._render_errButton())},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton,this._render_visualizationsButton]));a.append(this._render_secondaryActionButtons([this._render_tagButton,this._render_annotateButton]));a.append('<div class="clear"/>');a.append(this._render_tagArea());a.append(this._render_annotationArea());a.append(this._render_displayApps());a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility","click a.icon-button.tags":"loadAndDisplayTags","click a.icon-button.annotate":"loadAndDisplayAnnotation"},loadAndDisplayTags:function(b){this.log(this+".loadAndDisplayTags",b);var c=this.$el.find(".tag-area"),a=c.find(".tag-elt");if(c.is(":hidden")){if(!jQuery.trim(a.html())){$.ajax({url:this.urls.tags.get,error:function(){alert(_l("Tagging failed"))},success:function(d){a.html(d);a.find(".tooltip").tooltip();c.slideDown("fast")}})}else{c.slideDown("fast")}}else{c.slideUp("fast")}return false},loadAndDisplayAnnotation:function(b){this.log(this+".loadAndDisplayAnnotation",b);var d=this.$el.find(".annotation-area"),c=d.find(".annotation-elt"),a=this.urls.annotation.set;if(d.is(":hidden")){if(!jQuery.trim(c.html())){$.ajax({url:this.urls.annotation.get,error:function(){alert(_l("Annotations failed"))},success:function(e){if(e===""){e="<em>"+_l("Describe or add notes to dataset")+"</em>"}c.html(e);d.find(".tooltip").tooltip();async_save_text(c.attr("id"),c.attr("id"),a,"new_annotation",18,true,4);d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDAView("+a+")"}});HDAEditView.templates={tagArea:Handlebars.templates["template-hda-tagArea"],annotationArea:Handlebars.templates["template-hda-annotationArea"]};function create_scatterplot_action_fn(a,b){action=function(){var d=$(window.parent.document).find("iframe#galaxy_main"),c=a+"/scatterplot?"+$.param(b);d.attr("src",c);$("div.popmenu-wrapper").remove();return false};return action}function create_trackster_action_fn(a,c,b){return function(){var d={};if(b){d.dbkey=b}$.ajax({url:a+"/list_tracks?f-"+$.param(d),dataType:"html",error:function(){alert(_l("Could not add this dataset to browser")+".")},success:function(e){var f=window.parent;f.show_modal(_l("View Data in a New or Saved Visualization"),"",{Cancel:function(){f.hide_modal()},"View in saved visualization":function(){f.show_modal(_l("Add Data to Saved Visualization"),e,{Cancel:function(){f.hide_modal()},"Add to visualization":function(){$(f.document).find("input[name=id]:checked").each(function(){var g=$(this).val();c.id=g;f.location=a+"/trackster?"+$.param(c)})}})},"View in new visualization":function(){f.location=a+"/trackster?"+$.param(c)}})}});return false}};
\ No newline at end of file
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 static/scripts/packed/mvc/history/history-panel.js
--- a/static/scripts/packed/mvc/history/history-panel.js
+++ b/static/scripts/packed/mvc/history/history-panel.js
@@ -1,1 +1,1 @@
-var HistoryPanel=BaseView.extend(LoggableMixin).extend({el:"body.historyPage",HDAView:HDAEditView,events:{"click #history-refresh":function(){window.location.reload()},"click #history-tag":"loadAndDisplayTags"},initialize:function(a){this.log(this+".initialize:",a);if(!a.urlTemplates){throw (this+" needs urlTemplates on initialize")}if(!a.urlTemplates.history){throw (this+" needs urlTemplates.history on initialize")}if(!a.urlTemplates.hda){throw (this+" needs urlTemplates.hda on initialize")}this.urlTemplates=a.urlTemplates.history;this.hdaUrlTemplates=a.urlTemplates.hda;this._setUpWebStorage(a.initiallyExpanded,a.show_deleted,a.show_hidden);this.model.bind("change:nice_size",this.updateHistoryDiskSize,this);this.model.hdas.bind("add",this.add,this);this.model.hdas.bind("reset",this.addAll,this);this.hdaViews={};this.urls={}},_setUpWebStorage:function(b,a,c){this.storage=new PersistantStorage("HistoryView."+this.model.get("id"),{expandedHdas:{},show_deleted:false,show_hidden:false});this.log("this.storage:",this.storage.get());if(b){this.storage.set("exandedHdas",b)}if((a===true)||(a===false)){this.storage.set("show_deleted",a)}if((c===true)||(c===false)){this.storage.set("show_hidden",c)}this.show_deleted=this.storage.get("show_deleted");this.show_hidden=this.storage.get("show_hidden");this.log("(init'd) this.storage:",this.storage.get())},add:function(a){},addAll:function(){this.render()},render:function(){var b=this,d=b.toString()+".set-up",c=$("<div/>"),a=this.model.toJSON(),e=(this.$el.children().size()===0);a.urls=this._renderUrls(a);c.append(HistoryPanel.templates.historyPanel(a));c.find(".tooltip").tooltip({placement:"bottom"});this._setUpActionButton(c.find("#history-action-popup"));if(!this.model.hdas.length||!this.renderItems(c.find("#"+this.model.get("id")+"-datasets"))){c.find("#emptyHistoryMessage").show()}$(b).queue(d,function(f){b.$el.fadeOut("fast",function(){f()})});$(b).queue(d,function(f){b.$el.html("");b.$el.append(c.children());b.$el.fadeIn("fast",function(){f()})});$(b).queue(d,function(f){this.log(b+" rendered:",b.$el);b._setUpBehaviours();if(e){b.trigger("rendered:initial")}else{b.trigger("rendered")}f()});$(b).dequeue(d);return this},_renderUrls:function(a){var b=this;b.urls={};_.each(this.urlTemplates,function(d,c){b.urls[c]=_.template(d,a)});return b.urls},_setUpActionButton:function(e){var c=this,d=(this.storage.get("show_deleted"))?("Hide deleted"):("Show deleted"),a=(this.storage.get("show_hidden"))?("Hide hidden"):("Show hidden"),b={};b[_l("collapse all")]=function(){c.hideAllHdaBodies()};b[_l(d)]=function(){c.toggleShowDeleted()};b[_l(a)]=function(){c.toggleShowHidden()};make_popupmenu(e,b)},renderItems:function(b){this.hdaViews={};var a=this,c=this.model.hdas.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"));_.each(c,function(f){var e=f.get("id"),d=a.storage.get("expandedHdas").get(e);a.hdaViews[e]=new a.HDAView({model:f,expanded:d,urlTemplates:a.hdaUrlTemplates});a._setUpHdaListeners(a.hdaViews[e]);b.prepend(a.hdaViews[e].render().$el)});return c.length},_setUpHdaListeners:function(b){var a=this;b.bind("body-expanded",function(c){a.storage.get("expandedHdas").set(c,true)});b.bind("body-collapsed",function(c){a.storage.get("expandedHdas").deleteKey(c)})},_setUpBehaviours:function(){if(!(this.model.get("user")&&this.model.get("user").email)){return}var a=this.$("#history-annotation-area");this.$("#history-annotate").click(function(){if(a.is(":hidden")){a.slideDown("fast")}else{a.slideUp("fast")}return false});async_save_text("history-name-container","history-name",this.urls.rename,"new_name",18);async_save_text("history-annotation-container","history-annotation",this.urls.annotate,"new_annotation",18,true,4)},updateHistoryDiskSize:function(){this.$el.find("#history-size").text(this.model.get("nice_size"))},showQuotaMessage:function(){var a=this.$el.find("#quota-message-container");if(a.is(":hidden")){a.slideDown("fast")}},hideQuotaMessage:function(){var a=this.$el.find("#quota-message-container");if(!a.is(":hidden")){a.slideUp("fast")}},toggleShowDeleted:function(){this.storage.set("show_deleted",!this.storage.get("show_deleted"));this.render()},toggleShowHidden:function(){this.storage.set("show_hidden",!this.storage.get("show_hidden"));this.render()},hideAllHdaBodies:function(){_.each(this.hdaViews,function(a){a.toggleBodyVisibility(null,false)});this.storage.set("expandedHdas",{})},loadAndDisplayTags:function(c){this.log(this+".loadAndDisplayTags",c);var d=this.$el.find("#history-tag-area"),b=d.find(".tag-elt");this.log("\t tagArea",d," tagElt",b);if(d.is(":hidden")){if(!jQuery.trim(b.html())){var a=this;$.ajax({url:a.urls.tag,error:function(){alert(_l("Tagging failed"))},success:function(e){b.html(e);b.find(".tooltip").tooltip();d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=this.model.get("name")||"";return"HistoryPanel("+a+")"}});HistoryPanel.templates={historyPanel:Handlebars.templates["template-history-historyPanel"]};
\ No newline at end of file
+var HistoryPanel=BaseView.extend(LoggableMixin).extend({el:"body.historyPage",HDAView:HDAEditView,events:{"click #history-tag":"loadAndDisplayTags"},initialize:function(a){this.log(this+".initialize:",a);if(!a.urlTemplates){throw (this+" needs urlTemplates on initialize")}if(!a.urlTemplates.history){throw (this+" needs urlTemplates.history on initialize")}if(!a.urlTemplates.hda){throw (this+" needs urlTemplates.hda on initialize")}this.urlTemplates=a.urlTemplates.history;this.hdaUrlTemplates=a.urlTemplates.hda;this._setUpWebStorage(a.initiallyExpanded,a.show_deleted,a.show_hidden);this.model.bind("change:nice_size",this.updateHistoryDiskSize,this);this.model.hdas.bind("add",this.add,this);this.model.hdas.bind("reset",this.addAll,this);this.hdaViews={};this.urls={}},_setUpWebStorage:function(b,a,c){this.storage=new PersistantStorage("HistoryView."+this.model.get("id"),{expandedHdas:{},show_deleted:false,show_hidden:false});this.log("this.storage:",this.storage.get());if(b){this.storage.set("exandedHdas",b)}if((a===true)||(a===false)){this.storage.set("show_deleted",a)}if((c===true)||(c===false)){this.storage.set("show_hidden",c)}this.show_deleted=this.storage.get("show_deleted");this.show_hidden=this.storage.get("show_hidden");this.log("(init'd) this.storage:",this.storage.get())},add:function(a){},addAll:function(){this.render()},render:function(){var b=this,d=b.toString()+".set-up",c=$("<div/>"),a=this.model.toJSON(),e=(this.$el.children().size()===0);a.urls=this._renderUrls(a);c.append(HistoryPanel.templates.historyPanel(a));c.find(".tooltip").tooltip({placement:"bottom"});if(!this.model.hdas.length||!this.renderItems(c.find("#"+this.model.get("id")+"-datasets"))){c.find("#emptyHistoryMessage").show()}$(b).queue(d,function(f){b.$el.fadeOut("fast",function(){f()})});$(b).queue(d,function(f){b.$el.html("");b.$el.append(c.children());b.$el.fadeIn("fast",function(){f()})});$(b).queue(d,function(f){this.log(b+" rendered:",b.$el);b._setUpBehaviours();if(e){b.trigger("rendered:initial")}else{b.trigger("rendered")}f()});$(b).dequeue(d);return this},_renderUrls:function(a){var b=this;b.urls={};_.each(this.urlTemplates,function(d,c){b.urls[c]=_.template(d,a)});return b.urls},renderItems:function(b){this.hdaViews={};var a=this,c=this.model.hdas.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"));_.each(c,function(f){var e=f.get("id"),d=a.storage.get("expandedHdas").get(e);a.hdaViews[e]=new a.HDAView({model:f,expanded:d,urlTemplates:a.hdaUrlTemplates});a._setUpHdaListeners(a.hdaViews[e]);b.prepend(a.hdaViews[e].render().$el)});return c.length},_setUpHdaListeners:function(b){var a=this;b.bind("body-expanded",function(c){a.storage.get("expandedHdas").set(c,true)});b.bind("body-collapsed",function(c){a.storage.get("expandedHdas").deleteKey(c)})},_setUpBehaviours:function(){if(!(this.model.get("user")&&this.model.get("user").email)){return}var a=this.$("#history-annotation-area");this.$("#history-annotate").click(function(){if(a.is(":hidden")){a.slideDown("fast")}else{a.slideUp("fast")}return false});async_save_text("history-name-container","history-name",this.urls.rename,"new_name",18);async_save_text("history-annotation-container","history-annotation",this.urls.annotate,"new_annotation",18,true,4)},updateHistoryDiskSize:function(){this.$el.find("#history-size").text(this.model.get("nice_size"))},showQuotaMessage:function(){var a=this.$el.find("#quota-message-container");if(a.is(":hidden")){a.slideDown("fast")}},hideQuotaMessage:function(){var a=this.$el.find("#quota-message-container");if(!a.is(":hidden")){a.slideUp("fast")}},toggleShowDeleted:function(){this.storage.set("show_deleted",!this.storage.get("show_deleted"));this.render()},toggleShowHidden:function(){this.storage.set("show_hidden",!this.storage.get("show_hidden"));this.render()},collapseAllHdaBodies:function(){_.each(this.hdaViews,function(a){a.toggleBodyVisibility(null,false)});this.storage.set("expandedHdas",{})},loadAndDisplayTags:function(c){this.log(this+".loadAndDisplayTags",c);var d=this.$el.find("#history-tag-area"),b=d.find(".tag-elt");this.log("\t tagArea",d," tagElt",b);if(d.is(":hidden")){if(!jQuery.trim(b.html())){var a=this;$.ajax({url:a.urls.tag,error:function(){alert(_l("Tagging failed"))},success:function(e){b.html(e);b.find(".tooltip").tooltip();d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=this.model.get("name")||"";return"HistoryPanel("+a+")"}});HistoryPanel.templates={historyPanel:Handlebars.templates["template-history-historyPanel"]};
\ No newline at end of file
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 static/scripts/packed/templates/compiled/template-history-historyPanel.js
--- a/static/scripts/packed/templates/compiled/template-history-historyPanel.js
+++ b/static/scripts/packed/templates/compiled/template-history-historyPanel.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(j,C,A,r,J){A=A||j.helpers;var B="",n,m,x=this,f="function",c=A.blockHelperMissing,e=this.escapeExpression;function u(O,N){var L="",M,K;L+='\n <div id="history-name" class="tooltip editable-text"\n title="';K=A.local;if(K){M=K.call(O,{hash:{},inverse:x.noop,fn:x.program(2,t,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:x.noop,fn:x.program(2,t,N)})}if(M||M===0){L+=M}L+='">';K=A.name;if(K){M=K.call(O,{hash:{}})}else{M=O.name;M=typeof M===f?M():M}L+=e(M)+"</div>\n ";return L}function t(L,K){return"Click to rename history"}function s(O,N){var L="",M,K;L+='\n <div id="history-name" class="tooltip"\n title="';K=A.local;if(K){M=K.call(O,{hash:{},inverse:x.noop,fn:x.program(5,q,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:x.noop,fn:x.program(5,q,N)})}if(M||M===0){L+=M}L+='">';K=A.name;if(K){M=K.call(O,{hash:{}})}else{M=O.name;M=typeof M===f?M():M}L+=e(M)+"</div>\n ";return L}function q(L,K){return"You must be logged in to edit your history name"}function p(O,N){var L="",M,K;L+='\n <a id="history-tag" title="';K=A.local;if(K){M=K.call(O,{hash:{},inverse:x.noop,fn:x.program(8,l,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:x.noop,fn:x.program(8,l,N)})}if(M||M===0){L+=M}L+='"\n class="icon-button tags tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n <a id="history-annotate" title="';K=A.local;if(K){M=K.call(O,{hash:{},inverse:x.noop,fn:x.program(10,I,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:x.noop,fn:x.program(10,I,N)})}if(M||M===0){L+=M}L+='"\n class="icon-button annotate tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n ';return L}function l(L,K){return"Edit history tags"}function I(L,K){return"Edit history annotation"}function H(L,K){return"Refresh this display"}function G(L,K){return"Click to see more actions for this history"}function F(O,N){var L="",M,K;L+="\n ";K=A.warningmessagesmall;if(K){M=K.call(O,{hash:{},inverse:x.noop,fn:x.program(17,E,N)})}else{M=O.warningmessagesmall;M=typeof M===f?M():M}if(!A.warningmessagesmall){M=c.call(O,M,{hash:{},inverse:x.noop,fn:x.program(17,E,N)})}if(M||M===0){L+=M}L+="\n ";return L}function E(N,M){var L,K;K=A.local;if(K){L=K.call(N,{hash:{},inverse:x.noop,fn:x.program(18,D,M)})}else{L=N.local;L=typeof L===f?L():L}if(!A.local){L=c.call(N,L,{hash:{},inverse:x.noop,fn:x.program(18,D,M)})}if(L||L===0){return L}else{return""}}function D(L,K){return"You are currently viewing a deleted history!"}function o(O,N){var L="",M,K;L+='\n <div id="history-tag-annotation">\n\n <div id="history-tag-area" style="display: none">\n <strong>';K=A.local;if(K){M=K.call(O,{hash:{},inverse:x.noop,fn:x.program(21,k,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:x.noop,fn:x.program(21,k,N)})}if(M||M===0){L+=M}L+=':</strong>\n <div class="tag-elt"></div>\n </div>\n\n <div id="history-annotation-area" style="display: none">\n <strong>';K=A.local;if(K){M=K.call(O,{hash:{},inverse:x.noop,fn:x.program(23,i,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:x.noop,fn:x.program(23,i,N)})}if(M||M===0){L+=M}L+=':</strong>\n <div id="history-annotation-container">\n <div id="history-annotation" class="tooltip editable-text"\n title="';K=A.local;if(K){M=K.call(O,{hash:{},inverse:x.noop,fn:x.program(25,h,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:x.noop,fn:x.program(25,h,N)})}if(M||M===0){L+=M}L+='">\n ';M=O.annotation;M=A["if"].call(O,M,{hash:{},inverse:x.program(29,d,N),fn:x.program(27,g,N)});if(M||M===0){L+=M}L+="\n </div>\n </div>\n </div>\n </div>\n ";return L}function k(L,K){return"Tags"}function i(L,K){return"Annotation"}function h(L,K){return"Click to edit annotation"}function g(O,N){var L="",M,K;L+="\n ";K=A.annotation;if(K){M=K.call(O,{hash:{}})}else{M=O.annotation;M=typeof M===f?M():M}L+=e(M)+"\n ";return L}function d(O,N){var L="",M,K;L+="\n <em>";K=A.local;if(K){M=K.call(O,{hash:{},inverse:x.noop,fn:x.program(30,z,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:x.noop,fn:x.program(30,z,N)})}if(M||M===0){L+=M}L+="</em>\n ";return L}function z(L,K){return"Describe or add notes to history"}function y(O,N){var L="",M,K;L+='\n <div id="message-container">\n <div class="';K=A.status;if(K){M=K.call(O,{hash:{}})}else{M=O.status;M=typeof M===f?M():M}L+=e(M)+'message">\n ';K=A.message;if(K){M=K.call(O,{hash:{}})}else{M=O.message;M=typeof M===f?M():M}L+=e(M)+"\n </div><br />\n </div>\n ";return L}function w(L,K){return"You are over your disk quota.\n Tool execution is on hold until your disk usage drops below your allocated quota."}function v(L,K){return"Your history is empty. Click 'Get Data' on the left pane to start"}B+='<div id="history-controls">\n <div id="history-title-area" class="historyLinks">\n\n ';B+='\n <div id="history-name-container">\n ';B+="\n ";n=C.user;n=n==null||n===false?n:n.email;n=A["if"].call(C,n,{hash:{},inverse:x.program(4,s,J),fn:x.program(1,u,J)});if(n||n===0){B+=n}B+='\n </div>\n </div>\n\n <div id="history-subtitle-area">\n <div id="history-size" style="float:left;">';m=A.nice_size;if(m){n=m.call(C,{hash:{}})}else{n=C.nice_size;n=typeof n===f?n():n}B+=e(n)+'</div>\n\n <div id="history-secondary-links" style="float: right;">\n ';n=C.user;n=n==null||n===false?n:n.email;n=A["if"].call(C,n,{hash:{},inverse:x.noop,fn:x.program(7,p,J)});if(n||n===0){B+=n}B+='\n <a id="history-refresh" class="tooltip" title="';m=A.local;if(m){n=m.call(C,{hash:{},inverse:x.noop,fn:x.program(12,H,J)})}else{n=C.local;n=typeof n===f?n():n}if(!A.local){n=c.call(C,n,{hash:{},inverse:x.noop,fn:x.program(12,H,J)})}if(n||n===0){B+=n}B+='"\n href="javascript:void(0);">\n <span class="ficon refresh large"></span>\n </a>\n <a id="history-action-popup" class="tooltip" title="';m=A.local;if(m){n=m.call(C,{hash:{},inverse:x.noop,fn:x.program(14,G,J)})}else{n=C.local;n=typeof n===f?n():n}if(!A.local){n=c.call(C,n,{hash:{},inverse:x.noop,fn:x.program(14,G,J)})}if(n||n===0){B+=n}B+='"\n href="javascript:void(0);">\n <span class="ficon cogs large"></span>\n </a>\n </div>\n <div style="clear: both;"></div>\n </div>\n\n ';n=C.deleted;n=A["if"].call(C,n,{hash:{},inverse:x.noop,fn:x.program(16,F,J)});if(n||n===0){B+=n}B+="\n\n ";B+="\n ";B+="\n ";n=C.user;n=n==null||n===false?n:n.email;n=A["if"].call(C,n,{hash:{},inverse:x.noop,fn:x.program(20,o,J)});if(n||n===0){B+=n}B+="\n\n ";n=C.message;n=A["if"].call(C,n,{hash:{},inverse:x.noop,fn:x.program(32,y,J)});if(n||n===0){B+=n}B+='\n\n <div id="quota-message-container" style="display: none">\n <div id="quota-message" class="errormessage">\n ';m=A.local;if(m){n=m.call(C,{hash:{},inverse:x.noop,fn:x.program(34,w,J)})}else{n=C.local;n=typeof n===f?n():n}if(!A.local){n=c.call(C,n,{hash:{},inverse:x.noop,fn:x.program(34,w,J)})}if(n||n===0){B+=n}B+='\n </div>\n </div>\n</div>\n\n<div id="';m=A.id;if(m){n=m.call(C,{hash:{}})}else{n=C.id;n=typeof n===f?n():n}B+=e(n)+'-datasets" class="history-datasets-list"></div>\n\n<div class="infomessagesmall" id="emptyHistoryMessage" style="display: none;">\n ';m=A.local;if(m){n=m.call(C,{hash:{},inverse:x.noop,fn:x.program(36,v,J)})}else{n=C.local;n=typeof n===f?n():n}if(!A.local){n=c.call(C,n,{hash:{},inverse:x.noop,fn:x.program(36,v,J)})}if(n||n===0){B+=n}B+="\n</div>";return B})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(j,z,x,q,H){x=x||j.helpers;var y="",n,m,u=this,e="function",c=x.blockHelperMissing,d=this.escapeExpression;function t(M,L){var J="",K,I;J+='\n <div id="history-name" class="tooltip editable-text"\n title="';I=x.local;if(I){K=I.call(M,{hash:{},inverse:u.noop,fn:u.program(2,s,L)})}else{K=M.local;K=typeof K===e?K():K}if(!x.local){K=c.call(M,K,{hash:{},inverse:u.noop,fn:u.program(2,s,L)})}if(K||K===0){J+=K}J+='">';I=x.name;if(I){K=I.call(M,{hash:{}})}else{K=M.name;K=typeof K===e?K():K}J+=d(K)+"</div>\n ";return J}function s(J,I){return"Click to rename history"}function r(M,L){var J="",K,I;J+='\n <div id="history-name" class="tooltip"\n title="';I=x.local;if(I){K=I.call(M,{hash:{},inverse:u.noop,fn:u.program(5,p,L)})}else{K=M.local;K=typeof K===e?K():K}if(!x.local){K=c.call(M,K,{hash:{},inverse:u.noop,fn:u.program(5,p,L)})}if(K||K===0){J+=K}J+='">';I=x.name;if(I){K=I.call(M,{hash:{}})}else{K=M.name;K=typeof K===e?K():K}J+=d(K)+"</div>\n ";return J}function p(J,I){return"You must be logged in to edit your history name"}function o(M,L){var J="",K,I;J+='\n <a id="history-tag" title="';I=x.local;if(I){K=I.call(M,{hash:{},inverse:u.noop,fn:u.program(8,l,L)})}else{K=M.local;K=typeof K===e?K():K}if(!x.local){K=c.call(M,K,{hash:{},inverse:u.noop,fn:u.program(8,l,L)})}if(K||K===0){J+=K}J+='"\n class="icon-button tags tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n <a id="history-annotate" title="';I=x.local;if(I){K=I.call(M,{hash:{},inverse:u.noop,fn:u.program(10,G,L)})}else{K=M.local;K=typeof K===e?K():K}if(!x.local){K=c.call(M,K,{hash:{},inverse:u.noop,fn:u.program(10,G,L)})}if(K||K===0){J+=K}J+='"\n class="icon-button annotate tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n ';return J}function l(J,I){return"Edit history tags"}function G(J,I){return"Edit history annotation"}function F(M,L){var J="",K,I;J+="\n ";I=x.warningmessagesmall;if(I){K=I.call(M,{hash:{},inverse:u.noop,fn:u.program(13,E,L)})}else{K=M.warningmessagesmall;K=typeof K===e?K():K}if(!x.warningmessagesmall){K=c.call(M,K,{hash:{},inverse:u.noop,fn:u.program(13,E,L)})}if(K||K===0){J+=K}J+="\n ";return J}function E(L,K){var J,I;I=x.local;if(I){J=I.call(L,{hash:{},inverse:u.noop,fn:u.program(14,D,K)})}else{J=L.local;J=typeof J===e?J():J}if(!x.local){J=c.call(L,J,{hash:{},inverse:u.noop,fn:u.program(14,D,K)})}if(J||J===0){return J}else{return""}}function D(J,I){return"You are currently viewing a deleted history!"}function C(M,L){var J="",K,I;J+='\n <div id="history-tag-annotation">\n\n <div id="history-tag-area" style="display: none">\n <strong>';I=x.local;if(I){K=I.call(M,{hash:{},inverse:u.noop,fn:u.program(17,B,L)})}else{K=M.local;K=typeof K===e?K():K}if(!x.local){K=c.call(M,K,{hash:{},inverse:u.noop,fn:u.program(17,B,L)})}if(K||K===0){J+=K}J+=':</strong>\n <div class="tag-elt"></div>\n </div>\n\n <div id="history-annotation-area" style="display: none">\n <strong>';I=x.local;if(I){K=I.call(M,{hash:{},inverse:u.noop,fn:u.program(19,A,L)})}else{K=M.local;K=typeof K===e?K():K}if(!x.local){K=c.call(M,K,{hash:{},inverse:u.noop,fn:u.program(19,A,L)})}if(K||K===0){J+=K}J+=':</strong>\n <div id="history-annotation-container">\n <div id="history-annotation" class="tooltip editable-text"\n title="';I=x.local;if(I){K=I.call(M,{hash:{},inverse:u.noop,fn:u.program(21,k,L)})}else{K=M.local;K=typeof K===e?K():K}if(!x.local){K=c.call(M,K,{hash:{},inverse:u.noop,fn:u.program(21,k,L)})}if(K||K===0){J+=K}J+='">\n ';K=M.annotation;K=x["if"].call(M,K,{hash:{},inverse:u.program(25,h,L),fn:u.program(23,i,L)});if(K||K===0){J+=K}J+="\n </div>\n </div>\n </div>\n </div>\n ";return J}function B(J,I){return"Tags"}function A(J,I){return"Annotation"}function k(J,I){return"Click to edit annotation"}function i(M,L){var J="",K,I;J+="\n ";I=x.annotation;if(I){K=I.call(M,{hash:{}})}else{K=M.annotation;K=typeof K===e?K():K}J+=d(K)+"\n ";return J}function h(M,L){var J="",K,I;J+="\n <em>";I=x.local;if(I){K=I.call(M,{hash:{},inverse:u.noop,fn:u.program(26,g,L)})}else{K=M.local;K=typeof K===e?K():K}if(!x.local){K=c.call(M,K,{hash:{},inverse:u.noop,fn:u.program(26,g,L)})}if(K||K===0){J+=K}J+="</em>\n ";return J}function g(J,I){return"Describe or add notes to history"}function f(M,L){var J="",K,I;J+='\n <div id="message-container">\n <div class="';I=x.status;if(I){K=I.call(M,{hash:{}})}else{K=M.status;K=typeof K===e?K():K}J+=d(K)+'message">\n ';I=x.message;if(I){K=I.call(M,{hash:{}})}else{K=M.message;K=typeof K===e?K():K}J+=d(K)+"\n </div><br />\n </div>\n ";return J}function w(J,I){return"You are over your disk quota.\n Tool execution is on hold until your disk usage drops below your allocated quota."}function v(J,I){return"Your history is empty. Click 'Get Data' on the left pane to start"}y+='<div id="history-controls">\n <div id="history-title-area" class="historyLinks">\n\n ';y+='\n <div id="history-name-container">\n ';y+="\n ";n=z.user;n=n==null||n===false?n:n.email;n=x["if"].call(z,n,{hash:{},inverse:u.program(4,r,H),fn:u.program(1,t,H)});if(n||n===0){y+=n}y+='\n </div>\n </div>\n\n <div id="history-subtitle-area">\n <div id="history-size" style="float:left;">';m=x.nice_size;if(m){n=m.call(z,{hash:{}})}else{n=z.nice_size;n=typeof n===e?n():n}y+=d(n)+'</div>\n\n <div id="history-secondary-links" style="float: right;">\n ';n=z.user;n=n==null||n===false?n:n.email;n=x["if"].call(z,n,{hash:{},inverse:u.noop,fn:u.program(7,o,H)});if(n||n===0){y+=n}y+='\n </div>\n <div style="clear: both;"></div>\n </div>\n\n ';n=z.deleted;n=x["if"].call(z,n,{hash:{},inverse:u.noop,fn:u.program(12,F,H)});if(n||n===0){y+=n}y+="\n\n ";y+="\n ";y+="\n ";n=z.user;n=n==null||n===false?n:n.email;n=x["if"].call(z,n,{hash:{},inverse:u.noop,fn:u.program(16,C,H)});if(n||n===0){y+=n}y+="\n\n ";n=z.message;n=x["if"].call(z,n,{hash:{},inverse:u.noop,fn:u.program(28,f,H)});if(n||n===0){y+=n}y+='\n\n <div id="quota-message-container" style="display: none">\n <div id="quota-message" class="errormessage">\n ';m=x.local;if(m){n=m.call(z,{hash:{},inverse:u.noop,fn:u.program(30,w,H)})}else{n=z.local;n=typeof n===e?n():n}if(!x.local){n=c.call(z,n,{hash:{},inverse:u.noop,fn:u.program(30,w,H)})}if(n||n===0){y+=n}y+='\n </div>\n </div>\n</div>\n\n<div id="';m=x.id;if(m){n=m.call(z,{hash:{}})}else{n=z.id;n=typeof n===e?n():n}y+=d(n)+'-datasets" class="history-datasets-list"></div>\n\n<div class="infomessagesmall" id="emptyHistoryMessage" style="display: none;">\n ';m=x.local;if(m){n=m.call(z,{hash:{},inverse:u.noop,fn:u.program(32,v,H)})}else{n=z.local;n=typeof n===e?n():n}if(!x.local){n=c.call(z,n,{hash:{},inverse:u.noop,fn:u.program(32,v,H)})}if(n||n===0){y+=n}y+="\n</div>";return y})})();
\ No newline at end of file
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 static/scripts/packed/templates/compiled/template-visualization-scatterplotControlForm.js
--- a/static/scripts/packed/templates/compiled/template-visualization-scatterplotControlForm.js
+++ b/static/scripts/packed/templates/compiled/template-visualization-scatterplotControlForm.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-scatterplotControlForm"]=b(function(g,n,f,m,l){f=f||g.helpers;var j="",d,i,h="function",k=this.escapeExpression,p=this;function e(u,t){var r="",s,q;r+='\n <option value="';q=f.index;if(q){s=q.call(u,{hash:{}})}else{s=u.index;s=typeof s===h?s():s}r+=k(s)+'">';q=f.name;if(q){s=q.call(u,{hash:{}})}else{s=u.name;s=typeof s===h?s():s}r+=k(s)+"</option>\n ";return r}function c(u,t){var r="",s,q;r+='\n <option value="';q=f.index;if(q){s=q.call(u,{hash:{}})}else{s=u.index;s=typeof s===h?s():s}r+=k(s)+'">';q=f.name;if(q){s=q.call(u,{hash:{}})}else{s=u.name;s=typeof s===h?s():s}r+=k(s)+"</option>\n ";return r}function o(u,t){var r="",s,q;r+='\n <option value="';q=f.index;if(q){s=q.call(u,{hash:{}})}else{s=u.index;s=typeof s===h?s():s}r+=k(s)+'">';q=f.name;if(q){s=q.call(u,{hash:{}})}else{s=u.name;s=typeof s===h?s():s}r+=k(s)+"</option>\n ";return r}j+='\n\n<ul class="nav nav-tabs">\n <li class="active">\n <a data-toggle="tab" href="#data-settings">Data Controls</a>\n </li>\n <li><a data-toggle="tab" href="#chart-settings">Plot Controls</a></li>\n <li><a data-toggle="tab" href="#chart-stats">Statistics</a></li>\n</ul>\n\n';j+='\n<div class="tab-content">\n<div id="data-settings" class="tab-pane active">\n\n <p class="help-text">\n Use the following controls to change the data used by the chart.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n </p>\n \n ';j+='\n <div class="column-select">\n <label for="X-select">Data column for X: </label>\n <select name="X" id="X-select">\n ';d=n.numericColumns;d=f.each.call(n,d,{hash:{},inverse:p.noop,fn:p.program(1,e,l)});if(d||d===0){j+=d}j+='\n </select>\n </div>\n <div class="column-select">\n <label for="Y-select">Data column for Y: </label>\n <select name="Y" id="Y-select">\n ';d=n.numericColumns;d=f.each.call(n,d,{hash:{},inverse:p.noop,fn:p.program(3,c,l)});if(d||d===0){j+=d}j+="\n </select>\n </div>\n \n ";j+='\n <div id="include-id">\n <label for="include-id-checkbox">Include a third column as data point IDs?</label>\n <input type="checkbox" name="include-id" id="include-id-checkbox" />\n <p class="help-text-small">\n These will be displayed (along with the x and y values) when you hover over\n a data point.\n </p>\n </div>\n <div class="column-select" style="display: none">\n <label for="ID-select">Data column for IDs: </label>\n <select name="ID" id="ID-select">\n ';d=n.allColumns;d=f.each.call(n,d,{hash:{},inverse:p.noop,fn:p.program(5,o,l)});if(d||d===0){j+=d}j+='\n </select>\n </div>\n \n <input id="render-button" type="button" value="Draw" />\n <input id="save-button" type="button" value="Download Plot as SVG" style="display: none;" />\n <div class="clear"></div>\n</div>\n\n<div id="chart-settings" class="tab-pane">\n</div>\n\n<div id="chart-stats" class="tab-pane">\n</div>\n</div>';j+="\n\n";j+='\n<div id="loading-indicator" style="display: none;">\n <img class="loading-img" src="';i=f.loadingIndicatorImagePath;if(i){d=i.call(n,{hash:{}})}else{d=n.loadingIndicatorImagePath;d=typeof d===h?d():d}j+=k(d)+'" />\n <span class="loading-message">';i=f.message;if(i){d=i.call(n,{hash:{}})}else{d=n.message;d=typeof d===h?d():d}j+=k(d)+"</span>\n</div>";return j})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-scatterplotControlForm"]=b(function(g,n,f,m,l){f=f||g.helpers;var j="",d,i,h="function",k=this.escapeExpression,p=this;function e(u,t){var r="",s,q;r+='\n <option value="';q=f.index;if(q){s=q.call(u,{hash:{}})}else{s=u.index;s=typeof s===h?s():s}r+=k(s)+'">';q=f.name;if(q){s=q.call(u,{hash:{}})}else{s=u.name;s=typeof s===h?s():s}r+=k(s)+"</option>\n ";return r}function c(u,t){var r="",s,q;r+='\n <option value="';q=f.index;if(q){s=q.call(u,{hash:{}})}else{s=u.index;s=typeof s===h?s():s}r+=k(s)+'">';q=f.name;if(q){s=q.call(u,{hash:{}})}else{s=u.name;s=typeof s===h?s():s}r+=k(s)+"</option>\n ";return r}function o(u,t){var r="",s,q;r+='\n <option value="';q=f.index;if(q){s=q.call(u,{hash:{}})}else{s=u.index;s=typeof s===h?s():s}r+=k(s)+'">';q=f.name;if(q){s=q.call(u,{hash:{}})}else{s=u.name;s=typeof s===h?s():s}r+=k(s)+"</option>\n ";return r}j+='\n\n<ul class="nav nav-tabs">\n <li class="active"><a data-toggle="tab" href="#data-settings">Data Controls</a></li>\n <li><a data-toggle="tab" href="#chart-settings">Plot Controls</a></li>\n <li><a data-toggle="tab" href="#chart-stats">Statistics</a></li>\n <li><a data-toggle="tab" href="#chart">Chart</a></li>\n</ul>\n\n';j+='\n<div class="tab-content">\n<div id="data-settings" class="tab-pane active">\n\n <p class="help-text">\n Use the following controls to change the data used by the chart.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n </p>\n \n ';j+='\n <div class="column-select">\n <label for="X-select">Data column for X: </label>\n <select name="X" id="X-select">\n ';d=n.numericColumns;d=f.each.call(n,d,{hash:{},inverse:p.noop,fn:p.program(1,e,l)});if(d||d===0){j+=d}j+='\n </select>\n </div>\n <div class="column-select">\n <label for="Y-select">Data column for Y: </label>\n <select name="Y" id="Y-select">\n ';d=n.numericColumns;d=f.each.call(n,d,{hash:{},inverse:p.noop,fn:p.program(3,c,l)});if(d||d===0){j+=d}j+="\n </select>\n </div>\n \n ";j+='\n <div id="include-id">\n <label for="include-id-checkbox">Include a third column as data point IDs?</label>\n <input type="checkbox" name="include-id" id="include-id-checkbox" />\n <p class="help-text-small">\n These will be displayed (along with the x and y values) when you hover over\n a data point.\n </p>\n </div>\n <div class="column-select" style="display: none">\n <label for="ID-select">Data column for IDs: </label>\n <select name="ID" id="ID-select">\n ';d=n.allColumns;d=f.each.call(n,d,{hash:{},inverse:p.noop,fn:p.program(5,o,l)});if(d||d===0){j+=d}j+='\n </select>\n </div>\n \n <input id="render-button" type="button" value="Draw" />\n <input id="save-button" type="button" value="Download Plot as SVG" style="display: none;" />\n <div class="clear"></div>\n</div>\n\n<div id="chart-settings" class="tab-pane">\n</div>\n\n<div id="chart-stats" class="tab-pane">\n</div>\n</div>';j+="\n\n";j+='\n<div id="loading-indicator" style="display: none;">\n <img class="loading-img" src="';i=f.loadingIndicatorImagePath;if(i){d=i.call(n,{hash:{}})}else{d=n.loadingIndicatorImagePath;d=typeof d===h?d():d}j+=k(d)+'" />\n <span class="loading-message">';i=f.message;if(i){d=i.call(n,{hash:{}})}else{d=n.message;d=typeof d===h?d():d}j+=k(d)+"</span>\n</div>";return j})})();
\ No newline at end of file
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 static/scripts/packed/viz/scatterplot.js
--- a/static/scripts/packed/viz/scatterplot.js
+++ b/static/scripts/packed/viz/scatterplot.js
@@ -1,1 +1,1 @@
-define(["../libs/underscore","../mvc/base-mvc","../utils/LazyDataLoader","../templates/compiled/template-visualization-scatterplotControlForm","../templates/compiled/template-visualization-statsTable","../templates/compiled/template-visualization-chartSettings","../libs/d3","../libs/bootstrap","../libs/jquery/jquery-ui"],function(){function a(f){var d=10,h=7,g=10,e=8,c=5;this.log=function(){if(this.debugging&&console&&console.debug){var i=Array.prototype.slice.call(arguments);i.unshift(this.toString());console.debug.apply(console,i)}};this.log("new TwoVarScatterplot:",f);this.defaults={id:"TwoVarScatterplot",containerSelector:"body",maxDataPoints:30000,datapointSize:4,animDuration:500,xNumTicks:10,yNumTicks:10,xAxisLabelBumpY:40,yAxisLabelBumpX:-35,width:500,height:500,marginTop:50,marginRight:50,marginBottom:50,marginLeft:50,xMin:null,xMax:null,yMin:null,yMax:null,xLabel:"X",yLabel:"Y"};this.config=_.extend({},this.defaults,f);this.updateConfig=function(i,j){_.extend(this.config,i)};this.toString=function(){return this.config.id};this.translateStr=function(i,j){return"translate("+i+","+j+")"};this.rotateStr=function(j,i,k){return"rotate("+j+","+i+","+k+")"};this.svg=d3.select(this.config.containerSelector).append("svg:svg").attr("class","chart");this.content=this.svg.append("svg:g").attr("class","content").attr("id",this.config.id);this.xAxis=this.content.append("g").attr("class","axis").attr("id","x-axis");this.xAxisLabel=this.xAxis.append("text").attr("class","axis-label").attr("id","x-axis-label");this.yAxis=this.content.append("g").attr("class","axis").attr("id","y-axis");this.yAxisLabel=this.yAxis.append("text").attr("class","axis-label").attr("id","y-axis-label");this.adjustChartDimensions=function(l,j,i,k){l=l||0;j=j||0;i=i||0;k=k||0;this.svg.attr("width",this.config.width+(this.config.marginRight+j)+(this.config.marginLeft+k)).attr("height",this.config.height+(this.config.marginTop+l)+(this.config.marginBottom+i)).style("display","block");this.content=this.svg.select("g.content").attr("transform",this.translateStr(this.config.marginLeft+k,this.config.marginTop+l))};this.preprocessData=function(k,j,i){return(k.length>this.config.maxDataPoints)?(k.slice(0,this.config.maxDataPoints)):(k)};this.setUpDomains=function(i,k,j){this.xMin=this.config.xMin||(j)?(j[0].min):(d3.min(i));this.xMax=this.config.xMax||(j)?(j[0].max):(d3.max(i));this.yMin=this.config.yMin||(j)?(j[1].min):(d3.min(k));this.yMax=this.config.yMax||(j)?(j[1].max):(d3.max(k))};this.setUpScales=function(){this.xScale=d3.scale.linear().domain([this.xMin,this.xMax]).range([0,this.config.width]),this.yScale=d3.scale.linear().domain([this.yMin,this.yMax]).range([this.config.height,0])};this.setUpXAxis=function(){this.xAxisFn=d3.svg.axis().scale(this.xScale).ticks(this.config.xNumTicks).orient("bottom");this.xAxis.attr("transform",this.translateStr(0,this.config.height)).call(this.xAxisFn);this.xLongestLabel=d3.max(_.map([this.xMin,this.xMax],function(i){return(String(i)).length}));if(this.xLongestLabel>=c){this.xAxis.selectAll("g").filter(":nth-child(odd)").style("display","none")}this.xAxisLabel.attr("x",this.config.width/2).attr("y",this.config.xAxisLabelBumpY).attr("text-anchor","middle").text(this.config.xLabel)};this.setUpYAxis=function(){this.yAxisFn=d3.svg.axis().scale(this.yScale).ticks(this.config.yNumTicks).orient("left");this.yAxis.call(this.yAxisFn);var i=this.yAxis.selectAll("text").filter(function(m,l){return l!==0});this.yLongestLabel=d3.max(i[0].map(function(m,l){return(d3.select(m).text()).length}))||0;var j=d+(this.yLongestLabel*h)+e+g;this.config.yAxisLabelBumpX=-(j-g);if(this.config.marginLeft<j){var k=(j)-this.config.marginLeft;k=(k<0)?(0):(k);this.adjustChartDimensions(0,0,0,k)}this.yAxisLabel.attr("x",this.config.yAxisLabelBumpX).attr("y",this.config.height/2).attr("text-anchor","middle").attr("transform",this.rotateStr(-90,this.config.yAxisLabelBumpX,this.config.height/2)).text(this.config.yLabel)};this.renderGrid=function(){this.vGridLines=this.content.selectAll("line.v-grid-line").data(this.xScale.ticks(this.xAxisFn.ticks()[0]));this.vGridLines.enter().append("svg:line").classed("grid-line v-grid-line",true);this.vGridLines.attr("x1",this.xScale).attr("y1",0).attr("x2",this.xScale).attr("y2",this.config.height);this.vGridLines.exit().remove();this.hGridLines=this.content.selectAll("line.h-grid-line").data(this.yScale.ticks(this.yAxisFn.ticks()[0]));this.hGridLines.enter().append("svg:line").classed("grid-line h-grid-line",true);this.hGridLines.attr("x1",0).attr("y1",this.yScale).attr("x2",this.config.width).attr("y2",this.yScale);this.hGridLines.exit().remove()};this.glyphEnterState=function(i){};this.glyphFinalState=function(i){};this.glyphExitState=function(i){};this.renderDatapoints=function(i,l,j){this.log(this+".renderDatapoints",arguments);var k=0;this.datapoints=this.addDatapoints(i,l,j,".glyph");this.datapoints.exit().each(function(){k+=1}).transition().duration(this.config.animDuration).attr("cy",this.config.height).attr("r",0).remove();this.log(k," glyphs removed")};this.addDatapoints=function(m,k,i,l){this.log(this+".addDatapoints",arguments);var p=this,o=0,q=function(s,r){return p.xScale(m[r])},j=function(s,r){return p.yScale(k[r])};var n=this.content.selectAll(l);this.log("existing datapoints:",n);n=n.data(m);o=0;n.enter().append("svg:circle").each(function(){o+=1}).classed("glyph",true).attr("cx",q).attr("cy",j).attr("r",0);this.log(o," new glyphs created");o=0;n.transition().duration(this.config.animDuration).each(function(){o+=1}).attr("cx",q).attr("cy",j).attr("r",p.config.datapointSize);this.log(o," existing glyphs transitioned");if(i){n.attr("data",function(s,r){return(i[r])})}n.attr("title",function(s,r){return((i)?(i[r]+": "):(""))+m[r]+", "+k[r]});n.on("mouseover",function(t,r){var s=d3.select(this);s.style("fill","red").style("fill-opacity",1);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",s.attr("cx")).attr("y1",s.attr("cy")).attr("x2",0).attr("y2",s.attr("cy")).classed("hoverline",true);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",s.attr("cx")).attr("y1",s.attr("cy")).attr("x2",s.attr("cx")).attr("y2",p.config.height).classed("hoverline",true)}).on("mouseout",function(){d3.select(this).style("fill","black").style("fill-opacity",0.2);d3.selectAll(".hoverline").remove()});return n};this.render=function(k,l){this.log(this+".render",arguments);var i=k[0],m=k[1],j=(k.length>2)?(k[2]):(undefined);i=this.preprocessData(i);m=this.preprocessData(m);this.log("xCol len",i.length,"yCol len",m.length);this.setUpDomains(i,m,l);this.setUpScales();this.adjustChartDimensions();this.setUpXAxis();this.setUpYAxis();this.renderGrid();this.renderDatapoints(i,m,j)}}var b=BaseView.extend(LoggableMixin).extend({className:"scatterplot-settings-form",dataLoadDelay:500,dataLoadSize:3001,loadingIndicatorImage:"loading_large_white_bg.gif",initialize:function(c){this.log(this+".initialize, attributes:",c);this.dataset=null;this.chartConfig=null;this.plot=null;this.loader=null;this.$statsPanel=null;this.$chartSettingsPanel=null;this.$dataSettingsPanel=null;this.dataFetch=null;this.initializeFromAttributes(c);this.initializeChart(c);this.initializeDataLoader(c)},initializeFromAttributes:function(c){if(!c||!c.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=c.dataset}if(jQuery.type(this.dataset.metadata_column_types)==="string"){this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ")}this.log("dataset:",this.dataset);if(!c.apiDatasetsURL){throw ("ScatterplotView requires a apiDatasetsURL")}else{this.dataURL=c.apiDatasetsURL+"/"+this.dataset.id+"?"}this.log("this.dataURL:",this.dataURL)},initializeChart:function(c){this.chartConfig=c.chartConfig||{};if(this.logger){this.chartConfig.debugging=true}this.log("initial chartConfig:",this.chartConfig);this.plot=new a(this.chartConfig);this.chartConfig=this.plot.config},initializeDataLoader:function(d){var c=this;this.loader=new LazyDataLoader({logger:(this.logger)?(this.logger):(null),url:null,start:d.start||0,total:d.total||this.dataset.metadata_data_lines,delay:this.dataLoadDelay,size:this.dataLoadSize,buildUrl:function(f,e){return this.url+"&"+jQuery.param({start_val:f,max_vals:e})}});$(this.loader).bind("error",function(g,e,f){c.log("ERROR:",e,f);alert("ERROR fetching data:\n"+e+"\n"+f);c.hideLoadingIndicator()})},render:function(){var c=this,d={config:this.chartConfig,allColumns:[],numericColumns:[],loadingIndicatorImagePath:galaxy_paths.get("image_path")+"/"+this.loadingIndicatorImage};_.each(this.dataset.metadata_column_types,function(g,f){var e="column "+(f+1);if(c.dataset.metadata_column_names){e=c.dataset.metadata_column_names[f]}if(g==="int"||g==="float"){d.numericColumns.push({index:(f+1),name:e})}d.allColumns.push({index:(f+1),name:e})});this.$el.append(b.templates.form(d));this.$dataSettingsPanel=this.$el.find(".tab-pane#data-settings");this.$chartSettingsPanel=this._render_chartSettings();this.$statsPanel=this.$el.find(".tab-pane#chart-stats");this.$dataSettingsPanel.find("#X-select").val(this.chartConfig.xColumn);this.$dataSettingsPanel.find("#Y-select").val(this.chartConfig.yColumn);if(this.chartConfig.idColumn!==undefined){this.$dataSettingsPanel.find("#include-id-checkbox").attr("checked",true).trigger("change");this.$dataSettingsPanel.find("#ID-select").val(this.chartConfig.idColumn)}if(this.chartConfig.xColumn&&this.chartConfig.yColumn){this.renderPlot()}return this},isColumnNumeric:function(c){if((c>=0)&&(c<this.dataset.metadata_column_types.length)){var d=this.dataset.metadata_column_types[c];return(d==="int"||d==="float")}return false},_render_chartSettings:function(){var c=this,d=this.$el.find(".tab-pane#chart-settings"),e={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};d.append(b.templates.chartSettings(this.chartConfig));d.find(".numeric-slider-input").each(function(){var h=$(this),g=h.find(".slider-output"),i=h.find(".slider"),j=h.attr("id");function f(){var l=$(this),k=l.slider("value");g.text(k)}i.slider(_.extend(e[j],{value:c.chartConfig[j],change:f,slide:f}))});return d},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","click #data-settings #render-button":"renderPlot","click #chart-settings #render-button":"changeChartSettings"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},showLoadingIndicator:function(d,e){d=d||"";var c=this.$el.find("div#loading-indicator");messageBox=c.find(".loading-message");if(c.is(":visible")){if(d){messageBox.fadeOut("fast",function(){messageBox.text(d);messageBox.fadeIn("fast",e)})}else{e()}}else{if(d){messageBox.text(d)}c.fadeIn("fast",e)}},hideLoadingIndicator:function(c){this.$el.find("div#loading-indicator").fadeOut("fast",c)},renderPlot:function(){var c=this;c.data=null;c.meta=null;_.extend(this.chartConfig,this.getGraphSettings());this.log("this.chartConfig:",this.chartConfig);this.plot.updateConfig(this.chartConfig,false);this.loader.url=this.dataURL+"&"+jQuery.param(this.getDataSettings());this.log("this.loader, url:",this.loader.url,"total:",this.loader.total);$(this.loader).bind("loaded.new",function(e,d){c.log(c+" loaded.new",d);c.postProcessDataFetchResponse(d);c.log("postprocessed data:",c.data,"meta:",c.meta);c.showLoadingIndicator("Rendering...",function(){c.$el.find("ul.nav").find('a[href="#chart-stats"]').tab("show");c.plot.render(c.data,c.meta);c.renderStats(c.data,c.meta);c.hideLoadingIndicator()})});$(this.loader).bind("complete",function(d,e){c.log("complete",e);$(c.loader).unbind()});c.showLoadingIndicator("Fetching data...",function(){c.loader.load()})},renderStats:function(){this.$statsPanel.html(b.templates.statsTable({stats:[{name:"Count",xval:this.meta[0].count,yval:this.meta[1].count},{name:"Min",xval:this.meta[0].min,yval:this.meta[1].min},{name:"Max",xval:this.meta[0].max,yval:this.meta[1].max},{name:"Sum",xval:this.meta[0].sum,yval:this.meta[1].sum},{name:"Mean",xval:this.meta[0].mean,yval:this.meta[1].mean},{name:"Median",xval:this.meta[0].median,yval:this.meta[1].median}]}))},changeChartSettings:function(){var c=this;newGraphSettings=this.getGraphSettings();this.log("newGraphSettings:",newGraphSettings);_.extend(this.chartConfig,newGraphSettings);this.log("this.chartConfig:",this.chartConfig);this.plot.updateConfig(this.chartConfig,false);if(c.data&&c.meta){c.showLoadingIndicator("Rendering...",function(){c.plot.render(c.data,c.meta);c.hideLoadingIndicator()})}else{this.renderPlot()}},postProcessDataFetchResponse:function(c){this.postProcessData(c.data);this.postProcessMeta(c.meta)},postProcessData:function(d){var c=this;if(c.data){_.each(d,function(f,e){c.data[e]=c.data[e].concat(f)})}else{c.data=d}},postProcessMeta:function(e){var c=this,d=this.dataset.metadata_column_types;if(c.meta){_.each(e,function(g,f){var k=c.meta[f],i=d[f];c.log(f+" postprocessing meta:",g);k.count+=(g.count)?(g.count):(0);c.log(f,"count:",k.count);if((i==="int")||(i==="float")){k.min=Math.min(g.min,k.min);k.max=Math.max(g.max,k.max);k.sum=g.sum+k.sum;k.mean=(k.count)?(k.sum/k.count):(null);var h=c.data[f].slice().sort(),j=Math.floor(h.length/2);if(h.length%2===0){k.median=((h[j]+h[(j+1)])/2)}else{k.median=h[j]}}})}else{c.meta=e;c.log("initial meta:",c.meta)}},getDataSettings:function(){var d=this.getColumnSelections(),c=[];this.log("columnSelections:",d);c=[d.X.colIndex,d.Y.colIndex];if(this.$dataSettingsPanel.find("#include-id-checkbox").attr("checked")){c.push(d.ID.colIndex)}var e={data_type:"raw_data",columns:"["+c+"]"};this.log("params:",e);return e},getColumnSelections:function(){var c={};this.$dataSettingsPanel.find("div.column-select select").each(function(){var d=$(this),e=d.val();c[d.attr("name")]={colIndex:e,colName:d.children('[value="'+e+'"]').text()}});return c},getGraphSettings:function(){var e={},f=this.getColumnSelections();e.datapointSize=this.$chartSettingsPanel.find("#datapointSize.numeric-slider-input").find(".slider").slider("value");e.width=this.$chartSettingsPanel.find("#width.numeric-slider-input").find(".slider").slider("value");e.height=this.$chartSettingsPanel.find("#height.numeric-slider-input").find(".slider").slider("value");var d=this.$chartSettingsPanel.find("input#X-axis-label").val(),c=this.$chartSettingsPanel.find("input#Y-axis-label").val();e.xLabel=(d==="X")?(f.X.colName):(d);e.yLabel=(c==="Y")?(f.Y.colName):(c);e.animDuration=10;if(this.$chartSettingsPanel.find("#animDuration.checkbox-input").is(":checked")){e.animDuration=500}this.log("graphSettings:",e);return e},toString:function(){return"ScatterplotControlForm("+((this.dataset)?(this.dataset.id):(""))+")"}});b.templates={form:Handlebars.templates["template-visualization-scatterplotControlForm"],statsTable:Handlebars.templates["template-visualization-statsTable"],chartSettings:Handlebars.templates["template-visualization-chartSettings"]};return{LazyDataLoader:LazyDataLoader,TwoVarScatterplot:a,ScatterplotControlForm:b}});
\ No newline at end of file
+define(["../libs/underscore","../mvc/base-mvc","../utils/LazyDataLoader","../templates/compiled/template-visualization-scatterplotControlForm","../templates/compiled/template-visualization-statsTable","../templates/compiled/template-visualization-chartSettings","../libs/d3","../libs/bootstrap","../libs/jquery/jquery-ui"],function(){function a(f){var d=10,h=7,g=10,e=8,c=5;this.log=function(){if(this.debugging&&console&&console.debug){var i=Array.prototype.slice.call(arguments);i.unshift(this.toString());console.debug.apply(console,i)}};this.log("new TwoVarScatterplot:",f);this.defaults={id:"TwoVarScatterplot",containerSelector:"body",maxDataPoints:30000,datapointSize:4,animDuration:500,xNumTicks:10,yNumTicks:10,xAxisLabelBumpY:40,yAxisLabelBumpX:-35,width:500,height:500,marginTop:50,marginRight:50,marginBottom:50,marginLeft:50,xMin:null,xMax:null,yMin:null,yMax:null,xLabel:"X",yLabel:"Y"};this.config=_.extend({},this.defaults,f);this.updateConfig=function(i,j){_.extend(this.config,i)};this.toString=function(){return this.config.id};this.translateStr=function(i,j){return"translate("+i+","+j+")"};this.rotateStr=function(j,i,k){return"rotate("+j+","+i+","+k+")"};this.svg=d3.select(this.config.containerSelector).append("svg:svg").attr("class","chart");this.content=this.svg.append("svg:g").attr("class","content").attr("id",this.config.id);this.xAxis=this.content.append("g").attr("class","axis").attr("id","x-axis");this.xAxisLabel=this.xAxis.append("text").attr("class","axis-label").attr("id","x-axis-label");this.yAxis=this.content.append("g").attr("class","axis").attr("id","y-axis");this.yAxisLabel=this.yAxis.append("text").attr("class","axis-label").attr("id","y-axis-label");this.adjustChartDimensions=function(l,j,i,k){l=l||0;j=j||0;i=i||0;k=k||0;this.svg.attr("width",this.config.width+(this.config.marginRight+j)+(this.config.marginLeft+k)).attr("height",this.config.height+(this.config.marginTop+l)+(this.config.marginBottom+i)).style("display","block");this.content=this.svg.select("g.content").attr("transform",this.translateStr(this.config.marginLeft+k,this.config.marginTop+l))};this.preprocessData=function(k,j,i){return(k.length>this.config.maxDataPoints)?(k.slice(0,this.config.maxDataPoints)):(k)};this.setUpDomains=function(i,k,j){this.xMin=this.config.xMin||(j)?(j[0].min):(d3.min(i));this.xMax=this.config.xMax||(j)?(j[0].max):(d3.max(i));this.yMin=this.config.yMin||(j)?(j[1].min):(d3.min(k));this.yMax=this.config.yMax||(j)?(j[1].max):(d3.max(k))};this.setUpScales=function(){this.xScale=d3.scale.linear().domain([this.xMin,this.xMax]).range([0,this.config.width]),this.yScale=d3.scale.linear().domain([this.yMin,this.yMax]).range([this.config.height,0])};this.setUpXAxis=function(){this.xAxisFn=d3.svg.axis().scale(this.xScale).ticks(this.config.xNumTicks).orient("bottom");this.xAxis.attr("transform",this.translateStr(0,this.config.height)).call(this.xAxisFn);this.xLongestLabel=d3.max(_.map([this.xMin,this.xMax],function(i){return(String(i)).length}));if(this.xLongestLabel>=c){this.xAxis.selectAll("g").filter(":nth-child(odd)").style("display","none")}this.xAxisLabel.attr("x",this.config.width/2).attr("y",this.config.xAxisLabelBumpY).attr("text-anchor","middle").text(this.config.xLabel)};this.setUpYAxis=function(){this.yAxisFn=d3.svg.axis().scale(this.yScale).ticks(this.config.yNumTicks).orient("left");this.yAxis.call(this.yAxisFn);var i=this.yAxis.selectAll("text").filter(function(m,l){return l!==0});this.yLongestLabel=d3.max(i[0].map(function(m,l){return(d3.select(m).text()).length}))||0;var j=d+(this.yLongestLabel*h)+e+g;this.config.yAxisLabelBumpX=-(j-g);if(this.config.marginLeft<j){var k=(j)-this.config.marginLeft;k=(k<0)?(0):(k);this.adjustChartDimensions(0,0,0,k)}this.yAxisLabel.attr("x",this.config.yAxisLabelBumpX).attr("y",this.config.height/2).attr("text-anchor","middle").attr("transform",this.rotateStr(-90,this.config.yAxisLabelBumpX,this.config.height/2)).text(this.config.yLabel)};this.renderGrid=function(){this.vGridLines=this.content.selectAll("line.v-grid-line").data(this.xScale.ticks(this.xAxisFn.ticks()[0]));this.vGridLines.enter().append("svg:line").classed("grid-line v-grid-line",true);this.vGridLines.attr("x1",this.xScale).attr("y1",0).attr("x2",this.xScale).attr("y2",this.config.height);this.vGridLines.exit().remove();this.hGridLines=this.content.selectAll("line.h-grid-line").data(this.yScale.ticks(this.yAxisFn.ticks()[0]));this.hGridLines.enter().append("svg:line").classed("grid-line h-grid-line",true);this.hGridLines.attr("x1",0).attr("y1",this.yScale).attr("x2",this.config.width).attr("y2",this.yScale);this.hGridLines.exit().remove()};this.glyphEnterState=function(i){};this.glyphFinalState=function(i){};this.glyphExitState=function(i){};this.renderDatapoints=function(i,l,j){this.log(this+".renderDatapoints",arguments);var k=0;this.datapoints=this.addDatapoints(i,l,j,".glyph");this.datapoints.exit().each(function(){k+=1}).transition().duration(this.config.animDuration).attr("cy",this.config.height).attr("r",0).remove();this.log(k," glyphs removed")};this.addDatapoints=function(m,k,i,l){this.log(this+".addDatapoints",arguments);var p=this,o=0,q=function(s,r){return p.xScale(m[r])},j=function(s,r){return p.yScale(k[r])};var n=this.content.selectAll(l);this.log("existing datapoints:",n);n=n.data(m);o=0;n.enter().append("svg:circle").each(function(){o+=1}).classed("glyph",true).attr("cx",q).attr("cy",j).attr("r",0);this.log(o," new glyphs created");o=0;n.transition().duration(this.config.animDuration).each(function(){o+=1}).attr("cx",q).attr("cy",j).attr("r",p.config.datapointSize);this.log(o," existing glyphs transitioned");if(i){n.attr("data",function(s,r){return(i[r])})}n.attr("title",function(s,r){return((i)?(i[r]+": "):(""))+m[r]+", "+k[r]});n.on("mouseover",function(t,r){var s=d3.select(this);s.style("fill","red").style("fill-opacity",1);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",s.attr("cx")).attr("y1",s.attr("cy")).attr("x2",0).attr("y2",s.attr("cy")).classed("hoverline",true);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",s.attr("cx")).attr("y1",s.attr("cy")).attr("x2",s.attr("cx")).attr("y2",p.config.height).classed("hoverline",true)}).on("mouseout",function(){d3.select(this).style("fill","black").style("fill-opacity",0.2);d3.selectAll(".hoverline").remove()});return n};this.render=function(k,l){this.log(this+".render",arguments);var i=k[0],m=k[1],j=(k.length>2)?(k[2]):(undefined);i=this.preprocessData(i);m=this.preprocessData(m);this.log("xCol len",i.length,"yCol len",m.length);this.setUpDomains(i,m,l);this.setUpScales();this.adjustChartDimensions();this.setUpXAxis();this.setUpYAxis();this.renderGrid();this.renderDatapoints(i,m,j)}}var b=BaseView.extend(LoggableMixin).extend({className:"scatterplot-settings-form",dataLoadDelay:500,dataLoadSize:3001,loadingIndicatorImage:"loading_large_white_bg.gif",initialize:function(c){this.log(this+".initialize, attributes:",c);this.dataset=null;this.chartConfig=null;this.plot=null;this.loader=null;this.$statsPanel=null;this.$chartSettingsPanel=null;this.$dataSettingsPanel=null;this.dataFetch=null;this.initializeFromAttributes(c);this.initializeChart(c);this.initializeDataLoader(c)},initializeFromAttributes:function(c){if(!c||!c.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=c.dataset}if(jQuery.type(this.dataset.metadata_column_types)==="string"){this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ")}this.log("dataset:",this.dataset);if(!c.apiDatasetsURL){throw ("ScatterplotView requires a apiDatasetsURL")}else{this.dataURL=c.apiDatasetsURL+"/"+this.dataset.id+"?"}this.log("this.dataURL:",this.dataURL)},initializeChart:function(c){this.chartConfig=c.chartConfig||{};if(this.logger){this.chartConfig.debugging=true}this.log("initial chartConfig:",this.chartConfig);this.plot=new a(this.chartConfig);this.chartConfig=this.plot.config},initializeDataLoader:function(d){var c=this;this.loader=new LazyDataLoader({logger:(this.logger)?(this.logger):(null),url:null,start:d.start||0,total:d.total||this.dataset.metadata_data_lines,delay:this.dataLoadDelay,size:this.dataLoadSize,buildUrl:function(f,e){return this.url+"&"+jQuery.param({start_val:f,max_vals:e})}});$(this.loader).bind("error",function(g,e,f){c.log("ERROR:",e,f);alert("ERROR fetching data:\n"+e+"\n"+f);c.hideLoadingIndicator()})},render:function(){var c=this,d={config:this.chartConfig,allColumns:[],numericColumns:[],loadingIndicatorImagePath:galaxy_paths.get("image_path")+"/"+this.loadingIndicatorImage};_.each(this.dataset.metadata_column_types,function(g,f){var e="column "+(f+1);if(c.dataset.metadata_column_names){e=c.dataset.metadata_column_names[f]}if(g==="int"||g==="float"){d.numericColumns.push({index:(f+1),name:e})}d.allColumns.push({index:(f+1),name:e})});this.$el.append(b.templates.form(d));this.$dataSettingsPanel=this.$el.find(".tab-pane#data-settings");this.$chartSettingsPanel=this._render_chartSettings();this.$statsPanel=this.$el.find(".tab-pane#chart-stats");this.$dataSettingsPanel.find("#X-select").val(this.chartConfig.xColumn);this.$dataSettingsPanel.find("#Y-select").val(this.chartConfig.yColumn);if(this.chartConfig.idColumn!==undefined){this.$dataSettingsPanel.find("#include-id-checkbox").attr("checked",true).trigger("change");this.$dataSettingsPanel.find("#ID-select").val(this.chartConfig.idColumn)}if(this.chartConfig.xColumn&&this.chartConfig.yColumn){this.renderPlot()}return this},isColumnNumeric:function(c){if((c>=0)&&(c<this.dataset.metadata_column_types.length)){var d=this.dataset.metadata_column_types[c];return(d==="int"||d==="float")}return false},_render_chartSettings:function(){var c=this,d=this.$el.find(".tab-pane#chart-settings"),e={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};d.append(b.templates.chartSettings(this.chartConfig));d.find(".numeric-slider-input").each(function(){var h=$(this),g=h.find(".slider-output"),i=h.find(".slider"),j=h.attr("id");function f(){var l=$(this),k=l.slider("value");g.text(k)}i.slider(_.extend(e[j],{value:c.chartConfig[j],change:f,slide:f}))});return d},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","click #data-settings #render-button":"renderPlot","click #chart-settings #render-button":"changeChartSettings"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},showLoadingIndicator:function(d,e){d=d||"";var c=this.$el.find("div#loading-indicator");messageBox=c.find(".loading-message");if(c.is(":visible")){if(d){messageBox.fadeOut("fast",function(){messageBox.text(d);messageBox.fadeIn("fast",e)})}else{e()}}else{if(d){messageBox.text(d)}c.fadeIn("fast",e)}},hideLoadingIndicator:function(c){this.$el.find("div#loading-indicator").fadeOut("fast",c)},renderPlot:function(){var c=this;c.data=null;c.meta=null;_.extend(this.chartConfig,this.getGraphSettings());this.log("this.chartConfig:",this.chartConfig);this.plot.updateConfig(this.chartConfig,false);this.loader.url=this.dataURL+"&"+jQuery.param(this.getDataSettings());this.log("this.loader, url:",this.loader.url,"total:",this.loader.total);$(this.loader).bind("loaded.new",function(e,d){c.log(c+" loaded.new",d);c.postProcessDataFetchResponse(d);c.log("postprocessed data:",c.data,"meta:",c.meta);c.showLoadingIndicator("Rendering...",function(){c.$el.find("ul.nav").find('a[href="#chart-stats"]').tab("show");c.plot.render(c.data,c.meta);c.renderStats(c.data,c.meta);c.hideLoadingIndicator()})});$(this.loader).bind("complete",function(d,e){c.log("complete",e);$(c.loader).unbind()});c.showLoadingIndicator("Fetching data...",function(){c.loader.load()})},renderStats:function(){this.$statsPanel.html(b.templates.statsTable({stats:[{name:"Count",xval:this.meta[0].count,yval:this.meta[1].count},{name:"Min",xval:this.meta[0].min,yval:this.meta[1].min},{name:"Max",xval:this.meta[0].max,yval:this.meta[1].max},{name:"Sum",xval:this.meta[0].sum,yval:this.meta[1].sum},{name:"Mean",xval:this.meta[0].mean,yval:this.meta[1].mean},{name:"Median",xval:this.meta[0].median,yval:this.meta[1].median}]}))},changeChartSettings:function(){var c=this;newGraphSettings=this.getGraphSettings();this.log("newGraphSettings:",newGraphSettings);_.extend(this.chartConfig,newGraphSettings);this.log("this.chartConfig:",this.chartConfig);this.plot.updateConfig(this.chartConfig,false);if(c.data&&c.meta){c.showLoadingIndicator("Rendering...",function(){c.plot.render(c.data,c.meta);c.hideLoadingIndicator()})}else{this.renderPlot()}},postProcessDataFetchResponse:function(c){this.postProcessData(c.data);this.postProcessMeta(c.meta)},postProcessData:function(d){var c=this;if(c.data){_.each(d,function(f,e){c.data[e]=c.data[e].concat(f)})}else{c.data=d}},postProcessMeta:function(e){var c=this,d=this.dataset.metadata_column_types;if(c.meta){_.each(e,function(g,f){var k=c.meta[f],i=d[f];c.log(f+" postprocessing meta:",g);k.count+=(g.count)?(g.count):(0);c.log(f,"count:",k.count);if((i==="int")||(i==="float")){k.min=Math.min(g.min,k.min);k.max=Math.max(g.max,k.max);k.sum=g.sum+k.sum;k.mean=(k.count)?(k.sum/k.count):(null);var h=c.data[f].slice().sort(),j=Math.floor(h.length/2);if(h.length%2===0){k.median=((h[j]+h[(j+1)])/2)}else{k.median=h[j]}}})}else{c.meta=e;c.log("initial meta:",c.meta)}},getDataSettings:function(){var d=this.getColumnSelections(),c=[];this.log("columnSelections:",d);c=[d.X.colIndex,d.Y.colIndex];if(this.$dataSettingsPanel.find("#include-id-checkbox").attr("checked")){c.push(d.ID.colIndex)}var e={data_type:"raw_data",columns:"["+c+"]"};this.log("params:",e);return e},getColumnSelections:function(){var c={};this.$dataSettingsPanel.find("div.column-select select").each(function(){var d=$(this),e=parseInt(d.val(),10)-1;c[d.attr("name")]={colIndex:e,colName:d.children('[value="'+e+'"]').text()}});return c},getGraphSettings:function(){var e={},f=this.getColumnSelections();e.datapointSize=this.$chartSettingsPanel.find("#datapointSize.numeric-slider-input").find(".slider").slider("value");e.width=this.$chartSettingsPanel.find("#width.numeric-slider-input").find(".slider").slider("value");e.height=this.$chartSettingsPanel.find("#height.numeric-slider-input").find(".slider").slider("value");var d=this.$chartSettingsPanel.find("input#X-axis-label").val(),c=this.$chartSettingsPanel.find("input#Y-axis-label").val();e.xLabel=(d==="X")?(f.X.colName):(d);e.yLabel=(c==="Y")?(f.Y.colName):(c);e.animDuration=10;if(this.$chartSettingsPanel.find("#animDuration.checkbox-input").is(":checked")){e.animDuration=500}this.log("graphSettings:",e);return e},toString:function(){return"ScatterplotControlForm("+((this.dataset)?(this.dataset.id):(""))+")"}});b.templates={form:Handlebars.templates["template-visualization-scatterplotControlForm"],statsTable:Handlebars.templates["template-visualization-statsTable"],chartSettings:Handlebars.templates["template-visualization-chartSettings"]};return{LazyDataLoader:LazyDataLoader,TwoVarScatterplot:a,ScatterplotControlForm:b}});
\ No newline at end of file
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 static/scripts/templates/compiled/template-history-historyPanel.js
--- a/static/scripts/templates/compiled/template-history-historyPanel.js
+++ b/static/scripts/templates/compiled/template-history-historyPanel.js
@@ -73,82 +73,72 @@
function program12(depth0,data) {
+ var buffer = "", stack1, foundHelper;
+ buffer += "\n ";
+ foundHelper = helpers.warningmessagesmall;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(13, program13, data)}); }
+ else { stack1 = depth0.warningmessagesmall; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ if (!helpers.warningmessagesmall) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(13, program13, data)}); }
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n ";
+ return buffer;}
+function program13(depth0,data) {
- return "Refresh this display";}
-
+ var stack1, foundHelper;
+ foundHelper = helpers.local;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(14, program14, data)}); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(14, program14, data)}); }
+ if(stack1 || stack1 === 0) { return stack1; }
+ else { return ''; }}
function program14(depth0,data) {
- return "Click to see more actions for this history";}
+ return "You are currently viewing a deleted history!";}
function program16(depth0,data) {
var buffer = "", stack1, foundHelper;
- buffer += "\n ";
- foundHelper = helpers.warningmessagesmall;
+ buffer += "\n <div id=\"history-tag-annotation\">\n\n <div id=\"history-tag-area\" style=\"display: none\">\n <strong>";
+ foundHelper = helpers.local;
if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(17, program17, data)}); }
- else { stack1 = depth0.warningmessagesmall; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
- if (!helpers.warningmessagesmall) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(17, program17, data)}); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(17, program17, data)}); }
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\n ";
- return buffer;}
-function program17(depth0,data) {
-
- var stack1, foundHelper;
+ buffer += ":</strong>\n <div class=\"tag-elt\"></div>\n </div>\n\n <div id=\"history-annotation-area\" style=\"display: none\">\n <strong>";
foundHelper = helpers.local;
- if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(18, program18, data)}); }
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(19, program19, data)}); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
- if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(18, program18, data)}); }
- if(stack1 || stack1 === 0) { return stack1; }
- else { return ''; }}
-function program18(depth0,data) {
-
-
- return "You are currently viewing a deleted history!";}
-
-function program20(depth0,data) {
-
- var buffer = "", stack1, foundHelper;
- buffer += "\n <div id=\"history-tag-annotation\">\n\n <div id=\"history-tag-area\" style=\"display: none\">\n <strong>";
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(19, program19, data)}); }
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += ":</strong>\n <div id=\"history-annotation-container\">\n <div id=\"history-annotation\" class=\"tooltip editable-text\"\n title=\"";
foundHelper = helpers.local;
if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(21, program21, data)}); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(21, program21, data)}); }
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += ":</strong>\n <div class=\"tag-elt\"></div>\n </div>\n\n <div id=\"history-annotation-area\" style=\"display: none\">\n <strong>";
- foundHelper = helpers.local;
- if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(23, program23, data)}); }
- else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
- if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(23, program23, data)}); }
- if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += ":</strong>\n <div id=\"history-annotation-container\">\n <div id=\"history-annotation\" class=\"tooltip editable-text\"\n title=\"";
- foundHelper = helpers.local;
- if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(25, program25, data)}); }
- else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
- if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(25, program25, data)}); }
- if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\">\n ";
stack1 = depth0.annotation;
- stack1 = helpers['if'].call(depth0, stack1, {hash:{},inverse:self.program(29, program29, data),fn:self.program(27, program27, data)});
+ stack1 = helpers['if'].call(depth0, stack1, {hash:{},inverse:self.program(25, program25, data),fn:self.program(23, program23, data)});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n </div>\n </div>\n </div>\n </div>\n ";
return buffer;}
-function program21(depth0,data) {
+function program17(depth0,data) {
return "Tags";}
-function program23(depth0,data) {
+function program19(depth0,data) {
return "Annotation";}
-function program25(depth0,data) {
+function program21(depth0,data) {
return "Click to edit annotation";}
-function program27(depth0,data) {
+function program23(depth0,data) {
var buffer = "", stack1, foundHelper;
buffer += "\n ";
@@ -158,23 +148,23 @@
buffer += escapeExpression(stack1) + "\n ";
return buffer;}
-function program29(depth0,data) {
+function program25(depth0,data) {
var buffer = "", stack1, foundHelper;
buffer += "\n <em>";
foundHelper = helpers.local;
- if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(30, program30, data)}); }
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(26, program26, data)}); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
- if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(30, program30, data)}); }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(26, program26, data)}); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "</em>\n ";
return buffer;}
-function program30(depth0,data) {
+function program26(depth0,data) {
return "Describe or add notes to history";}
-function program32(depth0,data) {
+function program28(depth0,data) {
var buffer = "", stack1, foundHelper;
buffer += "\n <div id=\"message-container\">\n <div class=\"";
@@ -188,12 +178,12 @@
buffer += escapeExpression(stack1) + "\n </div><br />\n </div>\n ";
return buffer;}
-function program34(depth0,data) {
+function program30(depth0,data) {
return "You are over your disk quota.\n Tool execution is on hold until your disk usage drops below your allocated quota.";}
-function program36(depth0,data) {
+function program32(depth0,data) {
return "Your history is empty. Click 'Get Data' on the left pane to start";}
@@ -214,38 +204,26 @@
stack1 = stack1 == null || stack1 === false ? stack1 : stack1.email;
stack1 = helpers['if'].call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(7, program7, data)});
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\n <a id=\"history-refresh\" class=\"tooltip\" title=\"";
- foundHelper = helpers.local;
- if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(12, program12, data)}); }
- else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
- if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(12, program12, data)}); }
+ buffer += "\n </div>\n <div style=\"clear: both;\"></div>\n </div>\n\n ";
+ stack1 = depth0.deleted;
+ stack1 = helpers['if'].call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(12, program12, data)});
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\"\n href=\"javascript:void(0);\">\n <span class=\"ficon refresh large\"></span>\n </a>\n <a id=\"history-action-popup\" class=\"tooltip\" title=\"";
- foundHelper = helpers.local;
- if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(14, program14, data)}); }
- else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
- if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(14, program14, data)}); }
- if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\"\n href=\"javascript:void(0);\">\n <span class=\"ficon cogs large\"></span>\n </a>\n </div>\n <div style=\"clear: both;\"></div>\n </div>\n\n ";
- stack1 = depth0.deleted;
+ buffer += "\n\n ";
+ buffer += "\n ";
+ buffer += "\n ";
+ stack1 = depth0.user;
+ stack1 = stack1 == null || stack1 === false ? stack1 : stack1.email;
stack1 = helpers['if'].call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(16, program16, data)});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n ";
- buffer += "\n ";
- buffer += "\n ";
- stack1 = depth0.user;
- stack1 = stack1 == null || stack1 === false ? stack1 : stack1.email;
- stack1 = helpers['if'].call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(20, program20, data)});
- if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\n\n ";
stack1 = depth0.message;
- stack1 = helpers['if'].call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(32, program32, data)});
+ stack1 = helpers['if'].call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(28, program28, data)});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n <div id=\"quota-message-container\" style=\"display: none\">\n <div id=\"quota-message\" class=\"errormessage\">\n ";
foundHelper = helpers.local;
- if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(34, program34, data)}); }
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(30, program30, data)}); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
- if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(34, program34, data)}); }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(30, program30, data)}); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n </div>\n </div>\n</div>\n\n<div id=\"";
foundHelper = helpers.id;
@@ -253,9 +231,9 @@
else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
buffer += escapeExpression(stack1) + "-datasets\" class=\"history-datasets-list\"></div>\n\n<div class=\"infomessagesmall\" id=\"emptyHistoryMessage\" style=\"display: none;\">\n ";
foundHelper = helpers.local;
- if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(36, program36, data)}); }
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(32, program32, data)}); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
- if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(36, program36, data)}); }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(32, program32, data)}); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n</div>";
return buffer;});
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 static/scripts/templates/compiled/template-visualization-scatterplotControlForm.js
--- a/static/scripts/templates/compiled/template-visualization-scatterplotControlForm.js
+++ b/static/scripts/templates/compiled/template-visualization-scatterplotControlForm.js
@@ -46,7 +46,7 @@
buffer += escapeExpression(stack1) + "</option>\n ";
return buffer;}
- buffer += "\n\n<ul class=\"nav nav-tabs\">\n <li class=\"active\">\n <a data-toggle=\"tab\" href=\"#data-settings\">Data Controls</a>\n </li>\n <li><a data-toggle=\"tab\" href=\"#chart-settings\">Plot Controls</a></li>\n <li><a data-toggle=\"tab\" href=\"#chart-stats\">Statistics</a></li>\n</ul>\n\n";
+ buffer += "\n\n<ul class=\"nav nav-tabs\">\n <li class=\"active\"><a data-toggle=\"tab\" href=\"#data-settings\">Data Controls</a></li>\n <li><a data-toggle=\"tab\" href=\"#chart-settings\">Plot Controls</a></li>\n <li><a data-toggle=\"tab\" href=\"#chart-stats\">Statistics</a></li>\n <li><a data-toggle=\"tab\" href=\"#chart\">Chart</a></li>\n</ul>\n\n";
buffer += "\n<div class=\"tab-content\">\n<div id=\"data-settings\" class=\"tab-pane active\">\n\n <p class=\"help-text\">\n Use the following controls to change the data used by the chart.\n Use the 'Draw' button to render (or re-render) the chart with the current settings.\n </p>\n \n ";
buffer += "\n <div class=\"column-select\">\n <label for=\"X-select\">Data column for X: </label>\n <select name=\"X\" id=\"X-select\">\n ";
stack1 = depth0.numericColumns;
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 static/scripts/templates/history-templates.html
--- a/static/scripts/templates/history-templates.html
+++ b/static/scripts/templates/history-templates.html
@@ -28,14 +28,6 @@
<a id="history-annotate" title="{{#local}}Edit history annotation{{/local}}"
class="icon-button annotate tooltip" target="galaxy_main" href="javascript:void(0)"></a>
{{/if}}
- <a id="history-refresh" class="tooltip" title="{{#local}}Refresh this display{{/local}}"
- href="javascript:void(0);">
- <span class="ficon refresh large"></span>
- </a>
- <a id="history-action-popup" class="tooltip" title="{{#local}}Click to see more actions for this history{{/local}}"
- href="javascript:void(0);">
- <span class="ficon cogs large"></span>
- </a></div><div style="clear: both;"></div></div>
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 templates/root/alternate_history.mako
--- a/templates/root/alternate_history.mako
+++ b/templates/root/alternate_history.mako
@@ -378,8 +378,9 @@
quotaMeter.update()
}, quotaMeter );
-
- if( !Galaxy.currHistoryPanel ){ Galaxy.currHistoryPanel = historyPanel; }
+ // set it up to be accessible across iframes
+ //TODO:?? mem leak
+ top.Galaxy.currHistoryPanel = historyPanel;
return;
});
@@ -413,7 +414,7 @@
#history-name {
word-wrap: break-word;
font-weight: bold;
- color: black;
+ /*color: gray;*/
}
.editable-text {
border: solid transparent 1px;
@@ -422,7 +423,7 @@
width: 90%;
margin: -2px 0px -3px -4px;
font-weight: bold;
- color: black;
+ /*color: gray;*/
}
#quota-message-container {
diff -r 43e41e09206d2ddc52f4a46114303ef9fd067251 -r 8481560e2c3287a75f85e3a05e59b50b18bcd634 templates/root/index.mako
--- a/templates/root/index.mako
+++ b/templates/root/index.mako
@@ -40,11 +40,17 @@
"${_("Resume Paused Jobs")}": function() {
galaxy_history.location = "${h.url_for( controller='history', action='resume_paused_jobs', current=True)}";
},
- "${_("Show Deleted Datasets")}": function() {
- galaxy_history.location = "${h.url_for( controller='root', action='history', show_deleted=True)}";
+ "${_("Collapse Expanded Datasets")}": function() {
+ Galaxy.currHistoryPanel.collapseAllHdaBodies();
+ //galaxy_history.location = "${h.url_for( controller='root', action='history', show_deleted=True)}";
},
- "${_("Show Hidden Datasets")}": function() {
- galaxy_history.location = "${h.url_for( controller='root', action='history', show_hidden=True)}";
+ "${_("Show/Hide Deleted Datasets")}": function() {
+ Galaxy.currHistoryPanel.toggleShowDeleted();
+ //galaxy_history.location = "${h.url_for( controller='root', action='history', show_deleted=True)}";
+ },
+ "${_("Show/Hide Hidden Datasets")}": function() {
+ Galaxy.currHistoryPanel.toggleShowHidden();
+ //galaxy_history.location = "${h.url_for( controller='root', action='history', show_hidden=True)}";
},
"${_("Unhide Hidden Datasets")}": function() {
if ( confirm( "Really unhide all hidden datasets?" ) ) {
@@ -136,7 +142,14 @@
<div class="unified-panel-header" unselectable="on"><div class="unified-panel-header-inner"><div style="float: right">
- <a id="history-options-button" class='panel-header-button' href="${h.url_for( controller='root', action='history_options' )}" target="galaxy_main"><span class="ficon large cog"></span></a>
+ <a id="history-refresh-button" class='panel-header-button'
+ href="${h.url_for( controller='root', action='history' )}" target="galaxy_history">
+ <span class="ficon large refresh"></span>
+ </a>
+ <a id="history-options-button" class='panel-header-button'
+ href="${h.url_for( controller='root', action='history_options' )}" target="galaxy_main">
+ <span class="ficon large cog"></span>
+ </a></div><div class="panel-header-text">${_('History')}</div></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.
1
0
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/43e41e09206d/
changeset: 43e41e09206d
user: greg
date: 2012-11-21 16:50:52
summary: More shed_util refactoring.
affected #: 2 files
diff -r 5376431b78bf67afc967eb7dbebde50a02e69518 -r 43e41e09206d2ddc52f4a46114303ef9fd067251 lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -168,16 +168,6 @@
os.close( fd )
shutil.move( filename, os.path.abspath( config_filename ) )
os.chmod( config_filename, 0644 )
-def copy_disk_sample_files_to_dir( trans, repo_files_dir, dest_path ):
- sample_files = []
- for root, dirs, files in os.walk( repo_files_dir ):
- if root.find( '.hg' ) < 0:
- for name in files:
- if name.endswith( '.sample' ):
- relative_path = os.path.join( root, name )
- copy_sample_file( trans.app, relative_path, dest_path=dest_path )
- sample_files.append( name )
- return sample_files
def clean_tool_shed_url( tool_shed_url ):
if tool_shed_url.find( ':' ) > 0:
# Eliminate the port, if any, since it will result in an invalid directory name.
@@ -544,17 +534,6 @@
if converter_path and display_path:
break
return converter_path, display_path
-def get_ctx_file_path_from_manifest( filename, repo, changeset_revision ):
- """Get the ctx file path for the latest revision of filename from the repository manifest up to the value of changeset_revision."""
- stripped_filename = strip_path( filename )
- for changeset in reversed_upper_bounded_changelog( repo, changeset_revision ):
- manifest_changeset_revision = str( repo.changectx( changeset ) )
- manifest_ctx = repo.changectx( changeset )
- for ctx_file in manifest_ctx.files():
- ctx_file_name = strip_path( ctx_file )
- if ctx_file_name == stripped_filename:
- return manifest_ctx, ctx_file
- return None, None
def get_ctx_rev( tool_shed_url, name, owner, changeset_revision ):
url = url_join( tool_shed_url, 'repository/get_ctx_rev?name=%s&owner=%s&changeset_revision=%s' % ( name, owner, changeset_revision ) )
response = urllib2.urlopen( url )
@@ -564,38 +543,6 @@
def get_installed_tool_shed_repository( trans, id ):
"""Get a repository on the Galaxy side from the database via id"""
return trans.sa_session.query( trans.model.ToolShedRepository ).get( trans.security.decode_id( id ) )
-def get_list_of_copied_sample_files( repo, ctx, dir ):
- """
- Find all sample files (files in the repository with the special .sample extension) in the reversed repository manifest up to ctx. Copy
- each discovered file to dir and return the list of filenames. If a .sample file was added in a changeset and then deleted in a later
- changeset, it will be returned in the deleted_sample_files list. The caller will set the value of app.config.tool_data_path to dir in
- order to load the tools and generate metadata for them.
- """
- deleted_sample_files = []
- sample_files = []
- for changeset in reversed_upper_bounded_changelog( repo, ctx ):
- changeset_ctx = repo.changectx( changeset )
- for ctx_file in changeset_ctx.files():
- ctx_file_name = strip_path( ctx_file )
- # If we decide in the future that files deleted later in the changelog should not be used, we can use the following if statement.
- # if ctx_file_name.endswith( '.sample' ) and ctx_file_name not in sample_files and ctx_file_name not in deleted_sample_files:
- if ctx_file_name.endswith( '.sample' ) and ctx_file_name not in sample_files:
- fctx = get_file_context_from_ctx( changeset_ctx, ctx_file )
- if fctx in [ 'DELETED' ]:
- # Since the possibly future used if statement above is commented out, the same file that was initially added will be
- # discovered in an earlier changeset in the change log and fall through to the else block below. In other words, if
- # a file named blast2go.loc.sample was added in change set 0 and then deleted in changeset 3, the deleted file in changeset
- # 3 will be handled here, but the later discovered file in changeset 0 will be handled in the else block below. In this
- # way, the file contents will always be found for future tools even though the file was deleted.
- if ctx_file_name not in deleted_sample_files:
- deleted_sample_files.append( ctx_file_name )
- else:
- sample_files.append( ctx_file_name )
- tmp_ctx_file_name = os.path.join( dir, ctx_file_name.replace( '.sample', '' ) )
- fh = open( tmp_ctx_file_name, 'wb' )
- fh.write( fctx.data() )
- fh.close()
- return sample_files, deleted_sample_files
def get_repository_owner( cleaned_repository_url ):
items = cleaned_repository_url.split( 'repos' )
repo_path = items[ 1 ]
@@ -916,31 +863,6 @@
def load_installed_display_applications( app, installed_repository_dict, deactivate=False ):
# Load or deactivate proprietary datatype display applications
app.datatypes_registry.load_display_applications( installed_repository_dict=installed_repository_dict, deactivate=deactivate )
-def load_tool_from_tmp_config( trans, repo, ctx, ctx_file, work_dir ):
- tool = None
- message = ''
- tmp_tool_config = get_named_tmpfile_from_ctx( ctx, ctx_file, work_dir )
- if tmp_tool_config:
- element_tree = util.parse_xml( tmp_tool_config )
- element_tree_root = element_tree.getroot()
- # Look for code files required by the tool config.
- tmp_code_files = []
- for code_elem in element_tree_root.findall( 'code' ):
- code_file_name = code_elem.get( 'file' )
- tmp_code_file_name = copy_file_from_manifest( repo, ctx, code_file_name, work_dir )
- if tmp_code_file_name:
- tmp_code_files.append( tmp_code_file_name )
- tool, valid, message = load_tool_from_config( trans.app, tmp_tool_config )
- for tmp_code_file in tmp_code_files:
- try:
- os.unlink( tmp_code_file )
- except:
- pass
- try:
- os.unlink( tmp_tool_config )
- except:
- pass
- return tool, message
def panel_entry_per_tool( tool_section_dict ):
# Return True if tool_section_dict looks like this.
# {<Tool guid> : [{ tool_config : <tool_config_file>, id: <ToolSection id>, version : <ToolSection version>, name : <TooSection name>}]}
diff -r 5376431b78bf67afc967eb7dbebde50a02e69518 -r 43e41e09206d2ddc52f4a46114303ef9fd067251 lib/galaxy/util/shed_util_common.py
--- a/lib/galaxy/util/shed_util_common.py
+++ b/lib/galaxy/util/shed_util_common.py
@@ -284,6 +284,28 @@
else:
message = ''
return message
+def copy_disk_sample_files_to_dir( trans, repo_files_dir, dest_path ):
+ sample_files = []
+ for root, dirs, files in os.walk( repo_files_dir ):
+ if root.find( '.hg' ) < 0:
+ for name in files:
+ if name.endswith( '.sample' ):
+ relative_path = os.path.join( root, name )
+ copy_sample_file( trans.app, relative_path, dest_path=dest_path )
+ sample_files.append( name )
+ return sample_files
+def copy_file_from_manifest( repo, ctx, filename, dir ):
+ """Copy the latest version of the file named filename from the repository manifest to the directory to which dir refers."""
+ for changeset in reversed_upper_bounded_changelog( repo, ctx ):
+ changeset_ctx = repo.changectx( changeset )
+ fctx = get_file_context_from_ctx( changeset_ctx, filename )
+ if fctx and fctx not in [ 'DELETED' ]:
+ file_path = os.path.join( dir, filename )
+ fh = open( file_path, 'wb' )
+ fh.write( fctx.data() )
+ fh.close()
+ return file_path
+ return None
def copy_sample_file( app, filename, dest_path=None ):
"""Copy xxx.sample to dest_path/xxx.sample and dest_path/xxx. The default value for dest_path is ~/tool-data."""
if dest_path is None:
@@ -603,10 +625,12 @@
is_valid = False
if is_valid:
for repository_elem in root.findall( 'repository' ):
- repository_dependencies_tups.append( ( repository_elem.attrib[ 'toolshed' ],
- repository_elem.attrib[ 'name' ],
- repository_elem.attrib[ 'owner'],
- repository_elem.attrib[ 'changeset_revision' ] ) )
+ repository_dependencies_tup = ( repository_elem.attrib[ 'toolshed' ],
+ repository_elem.attrib[ 'name' ],
+ repository_elem.attrib[ 'owner'],
+ repository_elem.attrib[ 'changeset_revision' ] )
+ if repository_dependencies_tup not in repository_dependencies_tups:
+ repository_dependencies_tups.append( repository_dependencies_tup )
if repository_dependencies_tups:
metadata_dict[ 'repository_dependencies' ] = repository_dependencies_tups
return metadata_dict
@@ -723,6 +747,17 @@
# quiet = True
_ui.setconfig( 'ui', 'quiet', True )
return _ui
+def get_ctx_file_path_from_manifest( filename, repo, changeset_revision ):
+ """Get the ctx file path for the latest revision of filename from the repository manifest up to the value of changeset_revision."""
+ stripped_filename = strip_path( filename )
+ for changeset in reversed_upper_bounded_changelog( repo, changeset_revision ):
+ manifest_changeset_revision = str( repo.changectx( changeset ) )
+ manifest_ctx = repo.changectx( changeset )
+ for ctx_file in manifest_ctx.files():
+ ctx_file_name = strip_path( ctx_file )
+ if ctx_file_name == stripped_filename:
+ return manifest_ctx, ctx_file
+ return None, None
def get_file_context_from_ctx( ctx, filename ):
# We have to be careful in determining if we found the correct file because multiple files with the same name may be in different directories
# within ctx if the files were moved within the change set. For example, in the following ctx.files() list, the former may have been moved to
@@ -743,6 +778,77 @@
if deleted:
return 'DELETED'
return None
+def get_list_of_copied_sample_files( repo, ctx, dir ):
+ """
+ Find all sample files (files in the repository with the special .sample extension) in the reversed repository manifest up to ctx. Copy
+ each discovered file to dir and return the list of filenames. If a .sample file was added in a changeset and then deleted in a later
+ changeset, it will be returned in the deleted_sample_files list. The caller will set the value of app.config.tool_data_path to dir in
+ order to load the tools and generate metadata for them.
+ """
+ deleted_sample_files = []
+ sample_files = []
+ for changeset in reversed_upper_bounded_changelog( repo, ctx ):
+ changeset_ctx = repo.changectx( changeset )
+ for ctx_file in changeset_ctx.files():
+ ctx_file_name = strip_path( ctx_file )
+ # If we decide in the future that files deleted later in the changelog should not be used, we can use the following if statement.
+ # if ctx_file_name.endswith( '.sample' ) and ctx_file_name not in sample_files and ctx_file_name not in deleted_sample_files:
+ if ctx_file_name.endswith( '.sample' ) and ctx_file_name not in sample_files:
+ fctx = get_file_context_from_ctx( changeset_ctx, ctx_file )
+ if fctx in [ 'DELETED' ]:
+ # Since the possibly future used if statement above is commented out, the same file that was initially added will be
+ # discovered in an earlier changeset in the change log and fall through to the else block below. In other words, if
+ # a file named blast2go.loc.sample was added in change set 0 and then deleted in changeset 3, the deleted file in changeset
+ # 3 will be handled here, but the later discovered file in changeset 0 will be handled in the else block below. In this
+ # way, the file contents will always be found for future tools even though the file was deleted.
+ if ctx_file_name not in deleted_sample_files:
+ deleted_sample_files.append( ctx_file_name )
+ else:
+ sample_files.append( ctx_file_name )
+ tmp_ctx_file_name = os.path.join( dir, ctx_file_name.replace( '.sample', '' ) )
+ fh = open( tmp_ctx_file_name, 'wb' )
+ fh.write( fctx.data() )
+ fh.close()
+ return sample_files, deleted_sample_files
+def get_named_tmpfile_from_ctx( ctx, filename, dir ):
+ filename = strip_path( filename )
+ for ctx_file in ctx.files():
+ ctx_file_name = strip_path( ctx_file )
+ if filename == ctx_file_name:
+ try:
+ # If the file was moved, its destination file contents will be returned here.
+ fctx = ctx[ ctx_file ]
+ except LookupError, e:
+ # Continue looking in case the file was moved.
+ fctx = None
+ continue
+ if fctx:
+ fh = tempfile.NamedTemporaryFile( 'wb', dir=dir )
+ tmp_filename = fh.name
+ fh.close()
+ fh = open( tmp_filename, 'wb' )
+ fh.write( fctx.data() )
+ fh.close()
+ return tmp_filename
+ return None
+def get_parent_id( trans, id, old_id, version, guid, changeset_revisions ):
+ parent_id = None
+ # Compare from most recent to oldest.
+ changeset_revisions.reverse()
+ for changeset_revision in changeset_revisions:
+ repository_metadata = get_repository_metadata_by_changeset_revision( trans, id, changeset_revision )
+ metadata = repository_metadata.metadata
+ tools_dicts = metadata.get( 'tools', [] )
+ for tool_dict in tools_dicts:
+ if tool_dict[ 'guid' ] == guid:
+ # The tool has not changed between the compared changeset revisions.
+ continue
+ if tool_dict[ 'id' ] == old_id and tool_dict[ 'version' ] != version:
+ # The tool version is different, so we've found the parent.
+ return tool_dict[ 'guid' ]
+ if parent_id is None:
+ # The tool did not change through all of the changeset revisions.
+ return old_id
def get_readme_file_names( repository_name ):
readme_files = [ 'readme', 'read_me', 'install' ]
valid_filenames = [ r for r in readme_files ]
@@ -803,27 +909,20 @@
elif all_metadata_records:
return all_metadata_records[ 0 ]
return None
-def get_named_tmpfile_from_ctx( ctx, filename, dir ):
- filename = strip_path( filename )
- for ctx_file in ctx.files():
- ctx_file_name = strip_path( ctx_file )
- if filename == ctx_file_name:
- try:
- # If the file was moved, its destination file contents will be returned here.
- fctx = ctx[ ctx_file ]
- except LookupError, e:
- # Continue looking in case the file was moved.
- fctx = None
- continue
- if fctx:
- fh = tempfile.NamedTemporaryFile( 'wb', dir=dir )
- tmp_filename = fh.name
- fh.close()
- fh = open( tmp_filename, 'wb' )
- fh.write( fctx.data() )
- fh.close()
- return tmp_filename
- return None
+def get_relative_path_to_repository_file( root, name, relative_install_dir, work_dir, shed_config_dict, resetting_all_metadata_on_repository ):
+ if resetting_all_metadata_on_repository:
+ full_path_to_file = os.path.join( root, name )
+ stripped_path_to_file = full_path_to_file.replace( work_dir, '' )
+ if stripped_path_to_file.startswith( '/' ):
+ stripped_path_to_file = stripped_path_to_file[ 1: ]
+ relative_path_to_file = os.path.join( relative_install_dir, stripped_path_to_file )
+ else:
+ relative_path_to_file = os.path.join( root, name )
+ if relative_install_dir and \
+ shed_config_dict.get( 'tool_path' ) and \
+ relative_path_to_file.startswith( os.path.join( shed_config_dict.get( 'tool_path' ), relative_install_dir ) ):
+ relative_path_to_file = relative_path_to_file[ len( shed_config_dict.get( 'tool_path' ) ) + 1: ]
+ return relative_path_to_file
def get_sample_files_from_disk( repository_files_dir, tool_path = None, relative_install_dir=None, resetting_all_metadata_on_repository=False ):
if resetting_all_metadata_on_repository:
# Keep track of the location where the repository is temporarily cloned so that we can strip it when setting metadata.
@@ -852,38 +951,6 @@
relative_path_to_sample_file = relative_path_to_sample_file[ len( tool_path ) + 1 :]
sample_file_metadata_paths.append( relative_path_to_sample_file )
return sample_file_metadata_paths, sample_file_copy_paths
-def get_parent_id( trans, id, old_id, version, guid, changeset_revisions ):
- parent_id = None
- # Compare from most recent to oldest.
- changeset_revisions.reverse()
- for changeset_revision in changeset_revisions:
- repository_metadata = get_repository_metadata_by_changeset_revision( trans, id, changeset_revision )
- metadata = repository_metadata.metadata
- tools_dicts = metadata.get( 'tools', [] )
- for tool_dict in tools_dicts:
- if tool_dict[ 'guid' ] == guid:
- # The tool has not changed between the compared changeset revisions.
- continue
- if tool_dict[ 'id' ] == old_id and tool_dict[ 'version' ] != version:
- # The tool version is different, so we've found the parent.
- return tool_dict[ 'guid' ]
- if parent_id is None:
- # The tool did not change through all of the changeset revisions.
- return old_id
-def get_relative_path_to_repository_file( root, name, relative_install_dir, work_dir, shed_config_dict, resetting_all_metadata_on_repository ):
- if resetting_all_metadata_on_repository:
- full_path_to_file = os.path.join( root, name )
- stripped_path_to_file = full_path_to_file.replace( work_dir, '' )
- if stripped_path_to_file.startswith( '/' ):
- stripped_path_to_file = stripped_path_to_file[ 1: ]
- relative_path_to_file = os.path.join( relative_install_dir, stripped_path_to_file )
- else:
- relative_path_to_file = os.path.join( root, name )
- if relative_install_dir and \
- shed_config_dict.get( 'tool_path' ) and \
- relative_path_to_file.startswith( os.path.join( shed_config_dict.get( 'tool_path' ), relative_install_dir ) ):
- relative_path_to_file = relative_path_to_file[ len( shed_config_dict.get( 'tool_path' ) ) + 1: ]
- return relative_path_to_file
def handle_existing_tool_dependencies_that_changed_in_update( app, repository, original_dependency_dict, new_dependency_dict ):
"""
This method is called when a Galaxy admin is getting updates for an installed tool shed repository in order to cover the case where an
@@ -969,6 +1036,31 @@
valid = False
error_message = str( e )
return tool, valid, error_message
+def load_tool_from_tmp_config( trans, repo, ctx, ctx_file, work_dir ):
+ tool = None
+ message = ''
+ tmp_tool_config = get_named_tmpfile_from_ctx( ctx, ctx_file, work_dir )
+ if tmp_tool_config:
+ element_tree = util.parse_xml( tmp_tool_config )
+ element_tree_root = element_tree.getroot()
+ # Look for code files required by the tool config.
+ tmp_code_files = []
+ for code_elem in element_tree_root.findall( 'code' ):
+ code_file_name = code_elem.get( 'file' )
+ tmp_code_file_name = copy_file_from_manifest( repo, ctx, code_file_name, work_dir )
+ if tmp_code_file_name:
+ tmp_code_files.append( tmp_code_file_name )
+ tool, valid, message = load_tool_from_config( trans.app, tmp_tool_config )
+ for tmp_code_file in tmp_code_files:
+ try:
+ os.unlink( tmp_code_file )
+ except:
+ pass
+ try:
+ os.unlink( tmp_tool_config )
+ except:
+ pass
+ return tool, message
def open_repository_files_folder( trans, folder_path ):
try:
files_list = get_repository_files( trans, folder_path )
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.
1
0
commit/galaxy-central: jgoecks: eXpress in tool menus: (a) move to position after Cuff* tools and (b) add to main's tool conf.
by Bitbucket 21 Nov '12
by Bitbucket 21 Nov '12
21 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/5376431b78bf/
changeset: 5376431b78bf
user: jgoecks
date: 2012-11-21 15:56:01
summary: eXpress in tool menus: (a) move to position after Cuff* tools and (b) add to main's tool conf.
affected #: 2 files
diff -r 46339150e5e134fb2eb57e4945617841e03a5a3f -r 5376431b78bf67afc967eb7dbebde50a02e69518 tool_conf.xml.main
--- a/tool_conf.xml.main
+++ b/tool_conf.xml.main
@@ -330,8 +330,9 @@
<tool file="ngs_rna/tophat_wrapper.xml" /><tool file="ngs_rna/cufflinks_wrapper.xml" /><tool file="ngs_rna/cuffcompare_wrapper.xml" />
- <tool file="ngs_rna/cuffmerge_wrapper.xml" />
+ <tool file="ngs_rna/cuffmerge_wrapper.xml" /><tool file="ngs_rna/cuffdiff_wrapper.xml" />
+ <tool file="ngs_rna/express_wrapper.xml" /><label text="Filtering" id="filtering" /><tool file="ngs_rna/filter_transcripts_via_tracking.xml" /></section>
diff -r 46339150e5e134fb2eb57e4945617841e03a5a3f -r 5376431b78bf67afc967eb7dbebde50a02e69518 tool_conf.xml.sample
--- a/tool_conf.xml.sample
+++ b/tool_conf.xml.sample
@@ -331,9 +331,9 @@
<tool file="ngs_rna/tophat_color_wrapper.xml" /><tool file="ngs_rna/cufflinks_wrapper.xml" /><tool file="ngs_rna/cuffcompare_wrapper.xml" />
+ <tool file="ngs_rna/cuffmerge_wrapper.xml" />
+ <tool file="ngs_rna/cuffdiff_wrapper.xml" /><tool file="ngs_rna/express_wrapper.xml" />
- <tool file="ngs_rna/cuffmerge_wrapper.xml" />
- <tool file="ngs_rna/cuffdiff_wrapper.xml" /><!-- Trinity is very memory-intensive and should only be enabled/run
on instances with sufficient resources.
<label text="De novo Assembly" id="de_novo_assembly "/>
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.
1
0
commit/galaxy-central: carlfeberhard: scatterplot: fix column selection broken in 7002f41
by Bitbucket 20 Nov '12
by Bitbucket 20 Nov '12
20 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/46339150e5e1/
changeset: 46339150e5e1
user: carlfeberhard
date: 2012-11-20 21:42:01
summary: scatterplot: fix column selection broken in 7002f41
affected #: 1 file
diff -r 7002f41bcaa3b1a5f5023e3c2d523488812873df -r 46339150e5e134fb2eb57e4945617841e03a5a3f static/scripts/viz/scatterplot.js
--- a/static/scripts/viz/scatterplot.js
+++ b/static/scripts/viz/scatterplot.js
@@ -939,7 +939,7 @@
var selections = {};
this.$dataSettingsPanel.find( 'div.column-select select' ).each( function(){
var $this = $( this ),
- val = $this.val();
+ val = parseInt( $this.val(), 10 ) - 1;
selections[ $this.attr( 'name' ) ] = {
colIndex : val,
colName : $this.children( '[value="' + val + '"]' ).text()
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.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/0941c74d1d05/
changeset: 0941c74d1d05
user: carlfeberhard
date: 2012-11-20 21:30:22
summary: scatterplot: add ability to auto-render based on query string
affected #: 4 files
diff -r 67b9614dcab440027292c5dc387ef2eb1a763c19 -r 0941c74d1d058ad6183347417e45fd5fd1528501 lib/galaxy/webapps/galaxy/controllers/visualization.py
--- a/lib/galaxy/webapps/galaxy/controllers/visualization.py
+++ b/lib/galaxy/webapps/galaxy/controllers/visualization.py
@@ -786,6 +786,9 @@
@web.expose
def scatterplot( self, trans, dataset_id, **kwargs ):
+ """
+ Returns a page that controls and renders a scatteplot graph.
+ """
# Get HDA.
hda = self.get_dataset( trans, dataset_id, check_ownership=False, check_accessible=True )
hda_dict = hda.get_api_value()
@@ -793,6 +796,7 @@
if( hda_dict[ 'metadata_column_names' ] == None
and hasattr( hda.datatype, 'column_names' ) ):
hda_dict[ 'metadata_column_names' ] = hda.datatype.column_names
+
history_id = trans.security.encode_id( hda.history.id )
#TODO: add column data
@@ -845,4 +849,3 @@
name = fields[4]
rows.append( [location, name] )
return { 'data': rows }
-
diff -r 67b9614dcab440027292c5dc387ef2eb1a763c19 -r 0941c74d1d058ad6183347417e45fd5fd1528501 static/scripts/templates/visualization-templates.html
--- a/static/scripts/templates/visualization-templates.html
+++ b/static/scripts/templates/visualization-templates.html
@@ -2,11 +2,10 @@
{{! main controls }}
<ul class="nav nav-tabs">
- <li class="active">
- <a data-toggle="tab" href="#data-settings">Data Controls</a>
- </li>
+ <li class="active"><a data-toggle="tab" href="#data-settings">Data Controls</a></li><li><a data-toggle="tab" href="#chart-settings">Plot Controls</a></li><li><a data-toggle="tab" href="#chart-stats">Statistics</a></li>
+ <li><a data-toggle="tab" href="#chart">Chart</a></li></ul>
{{! data settings }}
diff -r 67b9614dcab440027292c5dc387ef2eb1a763c19 -r 0941c74d1d058ad6183347417e45fd5fd1528501 static/scripts/viz/scatterplot.js
--- a/static/scripts/viz/scatterplot.js
+++ b/static/scripts/viz/scatterplot.js
@@ -412,14 +412,14 @@
}
// titles
- newDatapoints.attr( 'title', function( d, i ){
- return (( ids )?( ids[ i ] + ': ' ):( '' )) + newXCol[ i ] + ', ' + newYCol[ i ];
- });
+ //newDatapoints.attr( 'title', function( d, i ){
+ // return (( ids )?( ids[ i ] + ': ' ):( '' )) + newXCol[ i ] + ', ' + newYCol[ i ];
+ //});
// events
newDatapoints
//TODO: remove magic numbers
- .on( 'mouseover', function(){
+ .on( 'mouseover', function( d, i ){
var datapoint = d3.select( this );
datapoint
.style( 'fill', 'red' )
@@ -438,12 +438,24 @@
.attr( 'x1', datapoint.attr( 'cx' ) ).attr( 'y1', datapoint.attr( 'cy' ) )
.attr( 'x2', datapoint.attr( 'cx' ) ).attr( 'y2', plot.config.height )
.classed( 'hoverline', true );
+
+ //var datapointWindowPos = $( this ).position();
+ var datapointWindowPos = $( this ).offset();
+ window.dot = this;
+ console.debug( 'datapointWindowPos:', datapointWindowPos );
+ console.debug( 'datapoint r:', datapoint.attr( 'r' ) );
+ //this.popup = make_abs_box( datapointWindowPos.top, datapointWindowPos.left + datapoint.attr( 'r' ),
+ this.popup = make_abs_box( datapointWindowPos.top, datapointWindowPos.left,
+ newXCol[ i ], newYCol[ i ], ( ids )?( ids[ i ] ):( undefined ) );
+ $( 'body' ).append( this.popup );
})
.on( 'mouseout', function(){
d3.select( this )
.style( 'fill', 'black' )
.style( 'fill-opacity', 0.2 );
-
+ if( this.popup ){
+ this.popup.remove();
+ }
d3.selectAll( '.hoverline' ).remove();
});
@@ -499,7 +511,7 @@
loadingIndicatorImage : 'loading_large_white_bg.gif',
initialize : function( attributes ){
- if( this.logger ){ window.form = this; }
+ console.debug( this + '.initialize, attributes:', attributes );
this.dataset = null;
this.chartConfig = null;
@@ -517,7 +529,7 @@
},
initializeFromAttributes : function( attributes ){
- // ensure certain vars we need are passed in attributes
+ // required settings: ensure certain vars we need are passed in attributes
if( !attributes || !attributes.dataset ){
throw( "ScatterplotView requires a dataset" );
} else {
@@ -586,9 +598,9 @@
loadingIndicatorImagePath : galaxy_paths.get( 'image_path' ) + '/' + this.loadingIndicatorImage
};
+ //TODO: isNumericColumn
// gather column indeces (from metadata_column_types) and names (from metadata_columnnames)
_.each( this.dataset.metadata_column_types, function( type, index ){
- //TODO: using 0-based indeces
// label with the name if available (fall back on 'column <index>')
var name = 'column ' + ( index + 1 );
if( view.dataset.metadata_column_names ){
@@ -597,23 +609,46 @@
// filter numeric columns to their own list
if( type === 'int' || type === 'float' ){
- formData.numericColumns.push({ index: index, name: name });
+ formData.numericColumns.push({ index: ( index + 1 ), name: name });
}
- formData.allColumns.push({ index: index, name: name });
+ formData.allColumns.push({ index: ( index + 1 ), name: name });
});
-
//TODO: other vals: max_vals, start_val, pagination (plot-settings)
// render template and set up panels, store refs
this.$el.append( ScatterplotControlForm.templates.form( formData ) );
+
this.$dataSettingsPanel = this.$el.find( '.tab-pane#data-settings' );
this.$chartSettingsPanel = this._render_chartSettings();
this.$statsPanel = this.$el.find( '.tab-pane#chart-stats' );
-
+
+ // preset to column selectors if they were passed in the config
+ this.$dataSettingsPanel.find( '#X-select' ).val( this.chartConfig.xColumn );
+ this.$dataSettingsPanel.find( '#Y-select' ).val( this.chartConfig.yColumn );
+ if( this.chartConfig.idColumn !== undefined ){
+ this.$dataSettingsPanel.find( '#include-id-checkbox' )
+ .attr( 'checked', true ).trigger( 'change' );
+ this.$dataSettingsPanel.find( '#ID-select' ).val( this.chartConfig.idColumn );
+ }
+
//this.$el.find( 'ul.nav' ).find( 'a[href="#chart-settings"]' ).tab( 'show' );
+
+ //TODO:?? add autoRender=1 to query maybe?
+ if( this.chartConfig.xColumn && this.chartConfig.yColumn ){
+ this.renderPlot();
+ }
return this;
},
-
+
+ //TODO: seems like a function of dataset or metadata
+ isColumnNumeric : function( index ){
+ if( ( index >= 0 ) && ( index < this.dataset.metadata_column_types.length ) ){
+ var columnType = this.dataset.metadata_column_types[ index ];
+ return ( columnType === 'int' || columnType === 'float' );
+ }
+ return false;
+ },
+
_render_chartSettings : function(){
// chart settings panel
var chartControl = this,
@@ -658,7 +693,7 @@
// ------------------------------------------------------------------------- EVENTS
events : {
- 'click #include-id-checkbox' : 'toggleThirdColumnSelector',
+ 'change #include-id-checkbox' : 'toggleThirdColumnSelector',
'click #data-settings #render-button' : 'renderPlot',
'click #chart-settings #render-button' : 'changeChartSettings'
},
@@ -948,7 +983,7 @@
},
toString : function(){
- return 'ScatterplotControlForm(' + this.dataset.id + ')';
+ return 'ScatterplotControlForm(' + (( this.dataset )?( this.dataset.id ):( '' )) + ')';
}
});
diff -r 67b9614dcab440027292c5dc387ef2eb1a763c19 -r 0941c74d1d058ad6183347417e45fd5fd1528501 templates/visualization/scatterplot.mako
--- a/templates/visualization/scatterplot.mako
+++ b/templates/visualization/scatterplot.mako
@@ -193,6 +193,15 @@
fill-opacity: 0.2;
}
+/* -------------------------------------------- info box */
+.zero-dimensions {
+ width: 0;
+ height: 0;
+ border-top: 8px solid transparent;
+ border-bottom: 8px solid transparent;
+ border-right: 8px solid grey;
+}
+
</style></%def>
@@ -207,21 +216,88 @@
require([ "viz/scatterplot" ], function( scatterplot ){
var hda = ${h.to_json_string( hda )},
- historyID = '${historyID}';
-
- settingsForm = new scatterplot.ScatterplotControlForm({
- dataset : hda,
- el : $( '#chart-settings-form' ),
- apiDatasetsURL : "${h.url_for( controller='/api/datasets' )}",
+ historyID = '${historyID}',
+ querySettings = ${h.to_json_string( kwargs )},
+ chartConfig = _.extend( querySettings, {
+ containerSelector : '#chart-holder',
+ //TODO: move to ScatterplotControlForm.initialize
+ marginTop : ( querySettings.marginTop > 20 )?( querySettings.marginTop ):( 20 ),
- chartConfig : {
- containerSelector : '#chart-holder',
- marginTop : 20,
- }
+ xColumn : querySettings.xColumn,
+ yColumn : querySettings.yColumn,
+ idColumn : querySettings.idColumn
+ });
+ console.debug( querySettings );
+
+ var settingsForm = new scatterplot.ScatterplotControlForm({
+ dataset : hda,
+ apiDatasetsURL : "${h.url_for( controller='/api/datasets' )}",
+ el : $( '#chart-settings-form' ),
+ chartConfig : chartConfig
}).render();
});
+
+function make_abs_box( top, left, x, y, id ){
+ console.debug( top, left, x, y, id );
+ var ARROW_SIZE = 8,
+ ARROW_COLOR = 'grey',
+ DIST_TO_POINT = 4,
+ halfArrowSize = ARROW_SIZE / 2;
+
+ var boxContainer = $( '<div />' )
+ .attr( 'id', 'abs-box-container' )
+ // top left arrow
+ .css({
+ 'position' : 'absolute',
+ 'top' : top - halfArrowSize,
+ 'left' : left + ARROW_SIZE + DIST_TO_POINT,
+ 'background-color': 'transparent',
+ });
+ window.boxContainer = boxContainer;
+
+ var arrowLeft = $( '<div />' )
+ .attr( 'id', 'abs-box-arrow' )
+ .addClass( 'zero-dimensions' )
+ .css({
+ 'border-top' : ARROW_SIZE + 'px solid transparent',
+ 'border-bottom' : ARROW_SIZE + 'px solid transparent',
+ 'border-right' : ARROW_SIZE + 'px solid ' + ARROW_COLOR,
+ });
+ boxContainer.append( arrowLeft );
+ window.arrow = arrowLeft;
+
+ console.debug( 'arrow height:', arrowLeft.height() );
+ var boxInfo = $( '<div />' )
+ .attr( 'id', 'abs-box' )
+ .css({
+ 'position' : 'relative',
+ //TODO: 4 here is the border-radius
+ 'top' : -( 2 * ARROW_SIZE + 6 ),
+ 'left' : ARROW_SIZE,
+ 'border' : '2px solid grey',
+ 'border-radius' : '4px',
+ 'padding' : '4px',
+ 'background-color': 'white',
+ 'box-shadow' : '4px 4px 4px black'
+ });
+
+ // remove
+ if( id ){
+ $( '<div />' ).addClass( 'abs-box-id' ).css( 'font-weight', 'bold' ).text( id ).appendTo( boxInfo );
+ }
+ $( '<div />' ).addClass( 'abs-box-x' ).text( x ).appendTo( boxInfo );
+ $( '<div />' ).addClass( 'abs-box-y' ).text( y ).appendTo( boxInfo );
+ boxContainer.append( boxInfo );
+ boxContainer.append( '<div style="clear:both"></div>' );
+ window.boxInfo = boxContainer;
+
+ //console.debug( boxContainer );
+ return boxContainer;
+}
+
+
</script></%def>
https://bitbucket.org/galaxy/galaxy-central/changeset/f25f13784d20/
changeset: f25f13784d20
user: carlfeberhard
date: 2012-11-20 21:32:14
summary: scatterplot: clean up
affected #: 2 files
diff -r 0941c74d1d058ad6183347417e45fd5fd1528501 -r f25f13784d20b7f8697ff499b73339ac7d2b4acc static/scripts/viz/scatterplot.js
--- a/static/scripts/viz/scatterplot.js
+++ b/static/scripts/viz/scatterplot.js
@@ -412,9 +412,9 @@
}
// titles
- //newDatapoints.attr( 'title', function( d, i ){
- // return (( ids )?( ids[ i ] + ': ' ):( '' )) + newXCol[ i ] + ', ' + newYCol[ i ];
- //});
+ newDatapoints.attr( 'title', function( d, i ){
+ return (( ids )?( ids[ i ] + ': ' ):( '' )) + newXCol[ i ] + ', ' + newYCol[ i ];
+ });
// events
newDatapoints
@@ -440,23 +440,21 @@
.classed( 'hoverline', true );
//var datapointWindowPos = $( this ).position();
- var datapointWindowPos = $( this ).offset();
- window.dot = this;
- console.debug( 'datapointWindowPos:', datapointWindowPos );
- console.debug( 'datapoint r:', datapoint.attr( 'r' ) );
- //this.popup = make_abs_box( datapointWindowPos.top, datapointWindowPos.left + datapoint.attr( 'r' ),
- this.popup = make_abs_box( datapointWindowPos.top, datapointWindowPos.left,
- newXCol[ i ], newYCol[ i ], ( ids )?( ids[ i ] ):( undefined ) );
- $( 'body' ).append( this.popup );
+ //var datapointWindowPos = $( this ).offset();
+ //window.dot = this;
+ ////this.popup = make_abs_box( datapointWindowPos.top, datapointWindowPos.left + datapoint.attr( 'r' ),
+ //this.popup = make_abs_box( datapointWindowPos.top, datapointWindowPos.left,
+ // newXCol[ i ], newYCol[ i ], ( ids )?( ids[ i ] ):( undefined ) );
+ //$( 'body' ).append( this.popup );
})
.on( 'mouseout', function(){
d3.select( this )
.style( 'fill', 'black' )
.style( 'fill-opacity', 0.2 );
- if( this.popup ){
- this.popup.remove();
- }
d3.selectAll( '.hoverline' ).remove();
+ //if( this.popup ){
+ // this.popup.remove();
+ //}
});
return newDatapoints;
@@ -511,7 +509,7 @@
loadingIndicatorImage : 'loading_large_white_bg.gif',
initialize : function( attributes ){
- console.debug( this + '.initialize, attributes:', attributes );
+ this.log( this + '.initialize, attributes:', attributes );
this.dataset = null;
this.chartConfig = null;
diff -r 0941c74d1d058ad6183347417e45fd5fd1528501 -r f25f13784d20b7f8697ff499b73339ac7d2b4acc templates/visualization/scatterplot.mako
--- a/templates/visualization/scatterplot.mako
+++ b/templates/visualization/scatterplot.mako
@@ -227,7 +227,7 @@
yColumn : querySettings.yColumn,
idColumn : querySettings.idColumn
});
- console.debug( querySettings );
+ //console.debug( querySettings );
var settingsForm = new scatterplot.ScatterplotControlForm({
dataset : hda,
https://bitbucket.org/galaxy/galaxy-central/changeset/7002f41bcaa3/
changeset: 7002f41bcaa3
user: carlfeberhard
date: 2012-11-20 21:32:40
summary: pack scripts
affected #: 1 file
diff -r f25f13784d20b7f8697ff499b73339ac7d2b4acc -r 7002f41bcaa3b1a5f5023e3c2d523488812873df static/scripts/packed/viz/scatterplot.js
--- a/static/scripts/packed/viz/scatterplot.js
+++ b/static/scripts/packed/viz/scatterplot.js
@@ -1,1 +1,1 @@
-define(["../libs/underscore","../mvc/base-mvc","../utils/LazyDataLoader","../templates/compiled/template-visualization-scatterplotControlForm","../templates/compiled/template-visualization-statsTable","../templates/compiled/template-visualization-chartSettings","../libs/d3","../libs/bootstrap","../libs/jquery/jquery-ui"],function(){function a(f){var d=10,h=7,g=10,e=8,c=5;this.log=function(){if(this.debugging&&console&&console.debug){var i=Array.prototype.slice.call(arguments);i.unshift(this.toString());console.debug.apply(console,i)}};this.log("new TwoVarScatterplot:",f);this.defaults={id:"TwoVarScatterplot",containerSelector:"body",maxDataPoints:30000,datapointSize:4,animDuration:500,xNumTicks:10,yNumTicks:10,xAxisLabelBumpY:40,yAxisLabelBumpX:-35,width:500,height:500,marginTop:50,marginRight:50,marginBottom:50,marginLeft:50,xMin:null,xMax:null,yMin:null,yMax:null,xLabel:"X",yLabel:"Y"};this.config=_.extend({},this.defaults,f);this.updateConfig=function(i,j){_.extend(this.config,i)};this.toString=function(){return this.config.id};this.translateStr=function(i,j){return"translate("+i+","+j+")"};this.rotateStr=function(j,i,k){return"rotate("+j+","+i+","+k+")"};this.svg=d3.select(this.config.containerSelector).append("svg:svg").attr("class","chart");this.content=this.svg.append("svg:g").attr("class","content").attr("id",this.config.id);this.xAxis=this.content.append("g").attr("class","axis").attr("id","x-axis");this.xAxisLabel=this.xAxis.append("text").attr("class","axis-label").attr("id","x-axis-label");this.yAxis=this.content.append("g").attr("class","axis").attr("id","y-axis");this.yAxisLabel=this.yAxis.append("text").attr("class","axis-label").attr("id","y-axis-label");this.adjustChartDimensions=function(l,j,i,k){l=l||0;j=j||0;i=i||0;k=k||0;this.svg.attr("width",this.config.width+(this.config.marginRight+j)+(this.config.marginLeft+k)).attr("height",this.config.height+(this.config.marginTop+l)+(this.config.marginBottom+i)).style("display","block");this.content=this.svg.select("g.content").attr("transform",this.translateStr(this.config.marginLeft+k,this.config.marginTop+l))};this.preprocessData=function(k,j,i){return(k.length>this.config.maxDataPoints)?(k.slice(0,this.config.maxDataPoints)):(k)};this.setUpDomains=function(i,k,j){this.xMin=this.config.xMin||(j)?(j[0].min):(d3.min(i));this.xMax=this.config.xMax||(j)?(j[0].max):(d3.max(i));this.yMin=this.config.yMin||(j)?(j[1].min):(d3.min(k));this.yMax=this.config.yMax||(j)?(j[1].max):(d3.max(k))};this.setUpScales=function(){this.xScale=d3.scale.linear().domain([this.xMin,this.xMax]).range([0,this.config.width]),this.yScale=d3.scale.linear().domain([this.yMin,this.yMax]).range([this.config.height,0])};this.setUpXAxis=function(){this.xAxisFn=d3.svg.axis().scale(this.xScale).ticks(this.config.xNumTicks).orient("bottom");this.xAxis.attr("transform",this.translateStr(0,this.config.height)).call(this.xAxisFn);this.xLongestLabel=d3.max(_.map([this.xMin,this.xMax],function(i){return(String(i)).length}));if(this.xLongestLabel>=c){this.xAxis.selectAll("g").filter(":nth-child(odd)").style("display","none")}this.xAxisLabel.attr("x",this.config.width/2).attr("y",this.config.xAxisLabelBumpY).attr("text-anchor","middle").text(this.config.xLabel)};this.setUpYAxis=function(){this.yAxisFn=d3.svg.axis().scale(this.yScale).ticks(this.config.yNumTicks).orient("left");this.yAxis.call(this.yAxisFn);var i=this.yAxis.selectAll("text").filter(function(m,l){return l!==0});this.yLongestLabel=d3.max(i[0].map(function(m,l){return(d3.select(m).text()).length}))||0;var j=d+(this.yLongestLabel*h)+e+g;this.config.yAxisLabelBumpX=-(j-g);if(this.config.marginLeft<j){var k=(j)-this.config.marginLeft;k=(k<0)?(0):(k);this.adjustChartDimensions(0,0,0,k)}this.yAxisLabel.attr("x",this.config.yAxisLabelBumpX).attr("y",this.config.height/2).attr("text-anchor","middle").attr("transform",this.rotateStr(-90,this.config.yAxisLabelBumpX,this.config.height/2)).text(this.config.yLabel)};this.renderGrid=function(){this.vGridLines=this.content.selectAll("line.v-grid-line").data(this.xScale.ticks(this.xAxisFn.ticks()[0]));this.vGridLines.enter().append("svg:line").classed("grid-line v-grid-line",true);this.vGridLines.attr("x1",this.xScale).attr("y1",0).attr("x2",this.xScale).attr("y2",this.config.height);this.vGridLines.exit().remove();this.hGridLines=this.content.selectAll("line.h-grid-line").data(this.yScale.ticks(this.yAxisFn.ticks()[0]));this.hGridLines.enter().append("svg:line").classed("grid-line h-grid-line",true);this.hGridLines.attr("x1",0).attr("y1",this.yScale).attr("x2",this.config.width).attr("y2",this.yScale);this.hGridLines.exit().remove()};this.glyphEnterState=function(i){};this.glyphFinalState=function(i){};this.glyphExitState=function(i){};this.renderDatapoints=function(i,l,j){this.log(this+".renderDatapoints",arguments);var k=0;this.datapoints=this.addDatapoints(i,l,j,".glyph");this.datapoints.exit().each(function(){k+=1}).transition().duration(this.config.animDuration).attr("cy",this.config.height).attr("r",0).remove();this.log(k," glyphs removed")};this.addDatapoints=function(m,k,i,l){this.log(this+".addDatapoints",arguments);var p=this,o=0,q=function(s,r){return p.xScale(m[r])},j=function(s,r){return p.yScale(k[r])};var n=this.content.selectAll(l);this.log("existing datapoints:",n);n=n.data(m);o=0;n.enter().append("svg:circle").each(function(){o+=1}).classed("glyph",true).attr("cx",q).attr("cy",j).attr("r",0);this.log(o," new glyphs created");o=0;n.transition().duration(this.config.animDuration).each(function(){o+=1}).attr("cx",q).attr("cy",j).attr("r",p.config.datapointSize);this.log(o," existing glyphs transitioned");if(i){n.attr("data",function(s,r){return(i[r])})}n.attr("title",function(s,r){return((i)?(i[r]+": "):(""))+m[r]+", "+k[r]});n.on("mouseover",function(){var r=d3.select(this);r.style("fill","red").style("fill-opacity",1);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",r.attr("cx")).attr("y1",r.attr("cy")).attr("x2",0).attr("y2",r.attr("cy")).classed("hoverline",true);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",r.attr("cx")).attr("y1",r.attr("cy")).attr("x2",r.attr("cx")).attr("y2",p.config.height).classed("hoverline",true)}).on("mouseout",function(){d3.select(this).style("fill","black").style("fill-opacity",0.2);d3.selectAll(".hoverline").remove()});return n};this.render=function(k,l){this.log(this+".render",arguments);var i=k[0],m=k[1],j=(k.length>2)?(k[2]):(undefined);i=this.preprocessData(i);m=this.preprocessData(m);this.log("xCol len",i.length,"yCol len",m.length);this.setUpDomains(i,m,l);this.setUpScales();this.adjustChartDimensions();this.setUpXAxis();this.setUpYAxis();this.renderGrid();this.renderDatapoints(i,m,j)}}var b=BaseView.extend(LoggableMixin).extend({className:"scatterplot-settings-form",dataLoadDelay:500,dataLoadSize:3001,loadingIndicatorImage:"loading_large_white_bg.gif",initialize:function(c){if(this.logger){window.form=this}this.dataset=null;this.chartConfig=null;this.plot=null;this.loader=null;this.$statsPanel=null;this.$chartSettingsPanel=null;this.$dataSettingsPanel=null;this.dataFetch=null;this.initializeFromAttributes(c);this.initializeChart(c);this.initializeDataLoader(c)},initializeFromAttributes:function(c){if(!c||!c.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=c.dataset}if(jQuery.type(this.dataset.metadata_column_types)==="string"){this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ")}this.log("dataset:",this.dataset);if(!c.apiDatasetsURL){throw ("ScatterplotView requires a apiDatasetsURL")}else{this.dataURL=c.apiDatasetsURL+"/"+this.dataset.id+"?"}this.log("this.dataURL:",this.dataURL)},initializeChart:function(c){this.chartConfig=c.chartConfig||{};if(this.logger){this.chartConfig.debugging=true}this.log("initial chartConfig:",this.chartConfig);this.plot=new a(this.chartConfig);this.chartConfig=this.plot.config},initializeDataLoader:function(d){var c=this;this.loader=new LazyDataLoader({logger:(this.logger)?(this.logger):(null),url:null,start:d.start||0,total:d.total||this.dataset.metadata_data_lines,delay:this.dataLoadDelay,size:this.dataLoadSize,buildUrl:function(f,e){return this.url+"&"+jQuery.param({start_val:f,max_vals:e})}});$(this.loader).bind("error",function(g,e,f){c.log("ERROR:",e,f);alert("ERROR fetching data:\n"+e+"\n"+f);c.hideLoadingIndicator()})},render:function(){var c=this,d={config:this.chartConfig,allColumns:[],numericColumns:[],loadingIndicatorImagePath:galaxy_paths.get("image_path")+"/"+this.loadingIndicatorImage};_.each(this.dataset.metadata_column_types,function(g,f){var e="column "+(f+1);if(c.dataset.metadata_column_names){e=c.dataset.metadata_column_names[f]}if(g==="int"||g==="float"){d.numericColumns.push({index:f,name:e})}d.allColumns.push({index:f,name:e})});this.$el.append(b.templates.form(d));this.$dataSettingsPanel=this.$el.find(".tab-pane#data-settings");this.$chartSettingsPanel=this._render_chartSettings();this.$statsPanel=this.$el.find(".tab-pane#chart-stats");return this},_render_chartSettings:function(){var c=this,d=this.$el.find(".tab-pane#chart-settings"),e={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};d.append(b.templates.chartSettings(this.chartConfig));d.find(".numeric-slider-input").each(function(){var h=$(this),g=h.find(".slider-output"),i=h.find(".slider"),j=h.attr("id");function f(){var l=$(this),k=l.slider("value");g.text(k)}i.slider(_.extend(e[j],{value:c.chartConfig[j],change:f,slide:f}))});return d},events:{"click #include-id-checkbox":"toggleThirdColumnSelector","click #data-settings #render-button":"renderPlot","click #chart-settings #render-button":"changeChartSettings"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},showLoadingIndicator:function(d,e){d=d||"";var c=this.$el.find("div#loading-indicator");messageBox=c.find(".loading-message");if(c.is(":visible")){if(d){messageBox.fadeOut("fast",function(){messageBox.text(d);messageBox.fadeIn("fast",e)})}else{e()}}else{if(d){messageBox.text(d)}c.fadeIn("fast",e)}},hideLoadingIndicator:function(c){this.$el.find("div#loading-indicator").fadeOut("fast",c)},renderPlot:function(){var c=this;c.data=null;c.meta=null;_.extend(this.chartConfig,this.getGraphSettings());this.log("this.chartConfig:",this.chartConfig);this.plot.updateConfig(this.chartConfig,false);this.loader.url=this.dataURL+"&"+jQuery.param(this.getDataSettings());this.log("this.loader, url:",this.loader.url,"total:",this.loader.total);$(this.loader).bind("loaded.new",function(e,d){c.log(c+" loaded.new",d);c.postProcessDataFetchResponse(d);c.log("postprocessed data:",c.data,"meta:",c.meta);c.showLoadingIndicator("Rendering...",function(){c.$el.find("ul.nav").find('a[href="#chart-stats"]').tab("show");c.plot.render(c.data,c.meta);c.renderStats(c.data,c.meta);c.hideLoadingIndicator()})});$(this.loader).bind("complete",function(d,e){c.log("complete",e);$(c.loader).unbind()});c.showLoadingIndicator("Fetching data...",function(){c.loader.load()})},renderStats:function(){this.$statsPanel.html(b.templates.statsTable({stats:[{name:"Count",xval:this.meta[0].count,yval:this.meta[1].count},{name:"Min",xval:this.meta[0].min,yval:this.meta[1].min},{name:"Max",xval:this.meta[0].max,yval:this.meta[1].max},{name:"Sum",xval:this.meta[0].sum,yval:this.meta[1].sum},{name:"Mean",xval:this.meta[0].mean,yval:this.meta[1].mean},{name:"Median",xval:this.meta[0].median,yval:this.meta[1].median}]}))},changeChartSettings:function(){var c=this;newGraphSettings=this.getGraphSettings();this.log("newGraphSettings:",newGraphSettings);_.extend(this.chartConfig,newGraphSettings);this.log("this.chartConfig:",this.chartConfig);this.plot.updateConfig(this.chartConfig,false);if(c.data&&c.meta){c.showLoadingIndicator("Rendering...",function(){c.plot.render(c.data,c.meta);c.hideLoadingIndicator()})}else{this.renderPlot()}},postProcessDataFetchResponse:function(c){this.postProcessData(c.data);this.postProcessMeta(c.meta)},postProcessData:function(d){var c=this;if(c.data){_.each(d,function(f,e){c.data[e]=c.data[e].concat(f)})}else{c.data=d}},postProcessMeta:function(e){var c=this,d=this.dataset.metadata_column_types;if(c.meta){_.each(e,function(g,f){var k=c.meta[f],i=d[f];c.log(f+" postprocessing meta:",g);k.count+=(g.count)?(g.count):(0);c.log(f,"count:",k.count);if((i==="int")||(i==="float")){k.min=Math.min(g.min,k.min);k.max=Math.max(g.max,k.max);k.sum=g.sum+k.sum;k.mean=(k.count)?(k.sum/k.count):(null);var h=c.data[f].slice().sort(),j=Math.floor(h.length/2);if(h.length%2===0){k.median=((h[j]+h[(j+1)])/2)}else{k.median=h[j]}}})}else{c.meta=e;c.log("initial meta:",c.meta)}},getDataSettings:function(){var d=this.getColumnSelections(),c=[];this.log("columnSelections:",d);c=[d.X.colIndex,d.Y.colIndex];if(this.$dataSettingsPanel.find("#include-id-checkbox").attr("checked")){c.push(d.ID.colIndex)}var e={data_type:"raw_data",columns:"["+c+"]"};this.log("params:",e);return e},getColumnSelections:function(){var c={};this.$dataSettingsPanel.find("div.column-select select").each(function(){var d=$(this),e=d.val();c[d.attr("name")]={colIndex:e,colName:d.children('[value="'+e+'"]').text()}});return c},getGraphSettings:function(){var e={},f=this.getColumnSelections();e.datapointSize=this.$chartSettingsPanel.find("#datapointSize.numeric-slider-input").find(".slider").slider("value");e.width=this.$chartSettingsPanel.find("#width.numeric-slider-input").find(".slider").slider("value");e.height=this.$chartSettingsPanel.find("#height.numeric-slider-input").find(".slider").slider("value");var d=this.$chartSettingsPanel.find("input#X-axis-label").val(),c=this.$chartSettingsPanel.find("input#Y-axis-label").val();e.xLabel=(d==="X")?(f.X.colName):(d);e.yLabel=(c==="Y")?(f.Y.colName):(c);e.animDuration=10;if(this.$chartSettingsPanel.find("#animDuration.checkbox-input").is(":checked")){e.animDuration=500}this.log("graphSettings:",e);return e},toString:function(){return"ScatterplotControlForm("+this.dataset.id+")"}});b.templates={form:Handlebars.templates["template-visualization-scatterplotControlForm"],statsTable:Handlebars.templates["template-visualization-statsTable"],chartSettings:Handlebars.templates["template-visualization-chartSettings"]};return{LazyDataLoader:LazyDataLoader,TwoVarScatterplot:a,ScatterplotControlForm:b}});
\ No newline at end of file
+define(["../libs/underscore","../mvc/base-mvc","../utils/LazyDataLoader","../templates/compiled/template-visualization-scatterplotControlForm","../templates/compiled/template-visualization-statsTable","../templates/compiled/template-visualization-chartSettings","../libs/d3","../libs/bootstrap","../libs/jquery/jquery-ui"],function(){function a(f){var d=10,h=7,g=10,e=8,c=5;this.log=function(){if(this.debugging&&console&&console.debug){var i=Array.prototype.slice.call(arguments);i.unshift(this.toString());console.debug.apply(console,i)}};this.log("new TwoVarScatterplot:",f);this.defaults={id:"TwoVarScatterplot",containerSelector:"body",maxDataPoints:30000,datapointSize:4,animDuration:500,xNumTicks:10,yNumTicks:10,xAxisLabelBumpY:40,yAxisLabelBumpX:-35,width:500,height:500,marginTop:50,marginRight:50,marginBottom:50,marginLeft:50,xMin:null,xMax:null,yMin:null,yMax:null,xLabel:"X",yLabel:"Y"};this.config=_.extend({},this.defaults,f);this.updateConfig=function(i,j){_.extend(this.config,i)};this.toString=function(){return this.config.id};this.translateStr=function(i,j){return"translate("+i+","+j+")"};this.rotateStr=function(j,i,k){return"rotate("+j+","+i+","+k+")"};this.svg=d3.select(this.config.containerSelector).append("svg:svg").attr("class","chart");this.content=this.svg.append("svg:g").attr("class","content").attr("id",this.config.id);this.xAxis=this.content.append("g").attr("class","axis").attr("id","x-axis");this.xAxisLabel=this.xAxis.append("text").attr("class","axis-label").attr("id","x-axis-label");this.yAxis=this.content.append("g").attr("class","axis").attr("id","y-axis");this.yAxisLabel=this.yAxis.append("text").attr("class","axis-label").attr("id","y-axis-label");this.adjustChartDimensions=function(l,j,i,k){l=l||0;j=j||0;i=i||0;k=k||0;this.svg.attr("width",this.config.width+(this.config.marginRight+j)+(this.config.marginLeft+k)).attr("height",this.config.height+(this.config.marginTop+l)+(this.config.marginBottom+i)).style("display","block");this.content=this.svg.select("g.content").attr("transform",this.translateStr(this.config.marginLeft+k,this.config.marginTop+l))};this.preprocessData=function(k,j,i){return(k.length>this.config.maxDataPoints)?(k.slice(0,this.config.maxDataPoints)):(k)};this.setUpDomains=function(i,k,j){this.xMin=this.config.xMin||(j)?(j[0].min):(d3.min(i));this.xMax=this.config.xMax||(j)?(j[0].max):(d3.max(i));this.yMin=this.config.yMin||(j)?(j[1].min):(d3.min(k));this.yMax=this.config.yMax||(j)?(j[1].max):(d3.max(k))};this.setUpScales=function(){this.xScale=d3.scale.linear().domain([this.xMin,this.xMax]).range([0,this.config.width]),this.yScale=d3.scale.linear().domain([this.yMin,this.yMax]).range([this.config.height,0])};this.setUpXAxis=function(){this.xAxisFn=d3.svg.axis().scale(this.xScale).ticks(this.config.xNumTicks).orient("bottom");this.xAxis.attr("transform",this.translateStr(0,this.config.height)).call(this.xAxisFn);this.xLongestLabel=d3.max(_.map([this.xMin,this.xMax],function(i){return(String(i)).length}));if(this.xLongestLabel>=c){this.xAxis.selectAll("g").filter(":nth-child(odd)").style("display","none")}this.xAxisLabel.attr("x",this.config.width/2).attr("y",this.config.xAxisLabelBumpY).attr("text-anchor","middle").text(this.config.xLabel)};this.setUpYAxis=function(){this.yAxisFn=d3.svg.axis().scale(this.yScale).ticks(this.config.yNumTicks).orient("left");this.yAxis.call(this.yAxisFn);var i=this.yAxis.selectAll("text").filter(function(m,l){return l!==0});this.yLongestLabel=d3.max(i[0].map(function(m,l){return(d3.select(m).text()).length}))||0;var j=d+(this.yLongestLabel*h)+e+g;this.config.yAxisLabelBumpX=-(j-g);if(this.config.marginLeft<j){var k=(j)-this.config.marginLeft;k=(k<0)?(0):(k);this.adjustChartDimensions(0,0,0,k)}this.yAxisLabel.attr("x",this.config.yAxisLabelBumpX).attr("y",this.config.height/2).attr("text-anchor","middle").attr("transform",this.rotateStr(-90,this.config.yAxisLabelBumpX,this.config.height/2)).text(this.config.yLabel)};this.renderGrid=function(){this.vGridLines=this.content.selectAll("line.v-grid-line").data(this.xScale.ticks(this.xAxisFn.ticks()[0]));this.vGridLines.enter().append("svg:line").classed("grid-line v-grid-line",true);this.vGridLines.attr("x1",this.xScale).attr("y1",0).attr("x2",this.xScale).attr("y2",this.config.height);this.vGridLines.exit().remove();this.hGridLines=this.content.selectAll("line.h-grid-line").data(this.yScale.ticks(this.yAxisFn.ticks()[0]));this.hGridLines.enter().append("svg:line").classed("grid-line h-grid-line",true);this.hGridLines.attr("x1",0).attr("y1",this.yScale).attr("x2",this.config.width).attr("y2",this.yScale);this.hGridLines.exit().remove()};this.glyphEnterState=function(i){};this.glyphFinalState=function(i){};this.glyphExitState=function(i){};this.renderDatapoints=function(i,l,j){this.log(this+".renderDatapoints",arguments);var k=0;this.datapoints=this.addDatapoints(i,l,j,".glyph");this.datapoints.exit().each(function(){k+=1}).transition().duration(this.config.animDuration).attr("cy",this.config.height).attr("r",0).remove();this.log(k," glyphs removed")};this.addDatapoints=function(m,k,i,l){this.log(this+".addDatapoints",arguments);var p=this,o=0,q=function(s,r){return p.xScale(m[r])},j=function(s,r){return p.yScale(k[r])};var n=this.content.selectAll(l);this.log("existing datapoints:",n);n=n.data(m);o=0;n.enter().append("svg:circle").each(function(){o+=1}).classed("glyph",true).attr("cx",q).attr("cy",j).attr("r",0);this.log(o," new glyphs created");o=0;n.transition().duration(this.config.animDuration).each(function(){o+=1}).attr("cx",q).attr("cy",j).attr("r",p.config.datapointSize);this.log(o," existing glyphs transitioned");if(i){n.attr("data",function(s,r){return(i[r])})}n.attr("title",function(s,r){return((i)?(i[r]+": "):(""))+m[r]+", "+k[r]});n.on("mouseover",function(t,r){var s=d3.select(this);s.style("fill","red").style("fill-opacity",1);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",s.attr("cx")).attr("y1",s.attr("cy")).attr("x2",0).attr("y2",s.attr("cy")).classed("hoverline",true);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",s.attr("cx")).attr("y1",s.attr("cy")).attr("x2",s.attr("cx")).attr("y2",p.config.height).classed("hoverline",true)}).on("mouseout",function(){d3.select(this).style("fill","black").style("fill-opacity",0.2);d3.selectAll(".hoverline").remove()});return n};this.render=function(k,l){this.log(this+".render",arguments);var i=k[0],m=k[1],j=(k.length>2)?(k[2]):(undefined);i=this.preprocessData(i);m=this.preprocessData(m);this.log("xCol len",i.length,"yCol len",m.length);this.setUpDomains(i,m,l);this.setUpScales();this.adjustChartDimensions();this.setUpXAxis();this.setUpYAxis();this.renderGrid();this.renderDatapoints(i,m,j)}}var b=BaseView.extend(LoggableMixin).extend({className:"scatterplot-settings-form",dataLoadDelay:500,dataLoadSize:3001,loadingIndicatorImage:"loading_large_white_bg.gif",initialize:function(c){this.log(this+".initialize, attributes:",c);this.dataset=null;this.chartConfig=null;this.plot=null;this.loader=null;this.$statsPanel=null;this.$chartSettingsPanel=null;this.$dataSettingsPanel=null;this.dataFetch=null;this.initializeFromAttributes(c);this.initializeChart(c);this.initializeDataLoader(c)},initializeFromAttributes:function(c){if(!c||!c.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=c.dataset}if(jQuery.type(this.dataset.metadata_column_types)==="string"){this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ")}this.log("dataset:",this.dataset);if(!c.apiDatasetsURL){throw ("ScatterplotView requires a apiDatasetsURL")}else{this.dataURL=c.apiDatasetsURL+"/"+this.dataset.id+"?"}this.log("this.dataURL:",this.dataURL)},initializeChart:function(c){this.chartConfig=c.chartConfig||{};if(this.logger){this.chartConfig.debugging=true}this.log("initial chartConfig:",this.chartConfig);this.plot=new a(this.chartConfig);this.chartConfig=this.plot.config},initializeDataLoader:function(d){var c=this;this.loader=new LazyDataLoader({logger:(this.logger)?(this.logger):(null),url:null,start:d.start||0,total:d.total||this.dataset.metadata_data_lines,delay:this.dataLoadDelay,size:this.dataLoadSize,buildUrl:function(f,e){return this.url+"&"+jQuery.param({start_val:f,max_vals:e})}});$(this.loader).bind("error",function(g,e,f){c.log("ERROR:",e,f);alert("ERROR fetching data:\n"+e+"\n"+f);c.hideLoadingIndicator()})},render:function(){var c=this,d={config:this.chartConfig,allColumns:[],numericColumns:[],loadingIndicatorImagePath:galaxy_paths.get("image_path")+"/"+this.loadingIndicatorImage};_.each(this.dataset.metadata_column_types,function(g,f){var e="column "+(f+1);if(c.dataset.metadata_column_names){e=c.dataset.metadata_column_names[f]}if(g==="int"||g==="float"){d.numericColumns.push({index:(f+1),name:e})}d.allColumns.push({index:(f+1),name:e})});this.$el.append(b.templates.form(d));this.$dataSettingsPanel=this.$el.find(".tab-pane#data-settings");this.$chartSettingsPanel=this._render_chartSettings();this.$statsPanel=this.$el.find(".tab-pane#chart-stats");this.$dataSettingsPanel.find("#X-select").val(this.chartConfig.xColumn);this.$dataSettingsPanel.find("#Y-select").val(this.chartConfig.yColumn);if(this.chartConfig.idColumn!==undefined){this.$dataSettingsPanel.find("#include-id-checkbox").attr("checked",true).trigger("change");this.$dataSettingsPanel.find("#ID-select").val(this.chartConfig.idColumn)}if(this.chartConfig.xColumn&&this.chartConfig.yColumn){this.renderPlot()}return this},isColumnNumeric:function(c){if((c>=0)&&(c<this.dataset.metadata_column_types.length)){var d=this.dataset.metadata_column_types[c];return(d==="int"||d==="float")}return false},_render_chartSettings:function(){var c=this,d=this.$el.find(".tab-pane#chart-settings"),e={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};d.append(b.templates.chartSettings(this.chartConfig));d.find(".numeric-slider-input").each(function(){var h=$(this),g=h.find(".slider-output"),i=h.find(".slider"),j=h.attr("id");function f(){var l=$(this),k=l.slider("value");g.text(k)}i.slider(_.extend(e[j],{value:c.chartConfig[j],change:f,slide:f}))});return d},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","click #data-settings #render-button":"renderPlot","click #chart-settings #render-button":"changeChartSettings"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},showLoadingIndicator:function(d,e){d=d||"";var c=this.$el.find("div#loading-indicator");messageBox=c.find(".loading-message");if(c.is(":visible")){if(d){messageBox.fadeOut("fast",function(){messageBox.text(d);messageBox.fadeIn("fast",e)})}else{e()}}else{if(d){messageBox.text(d)}c.fadeIn("fast",e)}},hideLoadingIndicator:function(c){this.$el.find("div#loading-indicator").fadeOut("fast",c)},renderPlot:function(){var c=this;c.data=null;c.meta=null;_.extend(this.chartConfig,this.getGraphSettings());this.log("this.chartConfig:",this.chartConfig);this.plot.updateConfig(this.chartConfig,false);this.loader.url=this.dataURL+"&"+jQuery.param(this.getDataSettings());this.log("this.loader, url:",this.loader.url,"total:",this.loader.total);$(this.loader).bind("loaded.new",function(e,d){c.log(c+" loaded.new",d);c.postProcessDataFetchResponse(d);c.log("postprocessed data:",c.data,"meta:",c.meta);c.showLoadingIndicator("Rendering...",function(){c.$el.find("ul.nav").find('a[href="#chart-stats"]').tab("show");c.plot.render(c.data,c.meta);c.renderStats(c.data,c.meta);c.hideLoadingIndicator()})});$(this.loader).bind("complete",function(d,e){c.log("complete",e);$(c.loader).unbind()});c.showLoadingIndicator("Fetching data...",function(){c.loader.load()})},renderStats:function(){this.$statsPanel.html(b.templates.statsTable({stats:[{name:"Count",xval:this.meta[0].count,yval:this.meta[1].count},{name:"Min",xval:this.meta[0].min,yval:this.meta[1].min},{name:"Max",xval:this.meta[0].max,yval:this.meta[1].max},{name:"Sum",xval:this.meta[0].sum,yval:this.meta[1].sum},{name:"Mean",xval:this.meta[0].mean,yval:this.meta[1].mean},{name:"Median",xval:this.meta[0].median,yval:this.meta[1].median}]}))},changeChartSettings:function(){var c=this;newGraphSettings=this.getGraphSettings();this.log("newGraphSettings:",newGraphSettings);_.extend(this.chartConfig,newGraphSettings);this.log("this.chartConfig:",this.chartConfig);this.plot.updateConfig(this.chartConfig,false);if(c.data&&c.meta){c.showLoadingIndicator("Rendering...",function(){c.plot.render(c.data,c.meta);c.hideLoadingIndicator()})}else{this.renderPlot()}},postProcessDataFetchResponse:function(c){this.postProcessData(c.data);this.postProcessMeta(c.meta)},postProcessData:function(d){var c=this;if(c.data){_.each(d,function(f,e){c.data[e]=c.data[e].concat(f)})}else{c.data=d}},postProcessMeta:function(e){var c=this,d=this.dataset.metadata_column_types;if(c.meta){_.each(e,function(g,f){var k=c.meta[f],i=d[f];c.log(f+" postprocessing meta:",g);k.count+=(g.count)?(g.count):(0);c.log(f,"count:",k.count);if((i==="int")||(i==="float")){k.min=Math.min(g.min,k.min);k.max=Math.max(g.max,k.max);k.sum=g.sum+k.sum;k.mean=(k.count)?(k.sum/k.count):(null);var h=c.data[f].slice().sort(),j=Math.floor(h.length/2);if(h.length%2===0){k.median=((h[j]+h[(j+1)])/2)}else{k.median=h[j]}}})}else{c.meta=e;c.log("initial meta:",c.meta)}},getDataSettings:function(){var d=this.getColumnSelections(),c=[];this.log("columnSelections:",d);c=[d.X.colIndex,d.Y.colIndex];if(this.$dataSettingsPanel.find("#include-id-checkbox").attr("checked")){c.push(d.ID.colIndex)}var e={data_type:"raw_data",columns:"["+c+"]"};this.log("params:",e);return e},getColumnSelections:function(){var c={};this.$dataSettingsPanel.find("div.column-select select").each(function(){var d=$(this),e=d.val();c[d.attr("name")]={colIndex:e,colName:d.children('[value="'+e+'"]').text()}});return c},getGraphSettings:function(){var e={},f=this.getColumnSelections();e.datapointSize=this.$chartSettingsPanel.find("#datapointSize.numeric-slider-input").find(".slider").slider("value");e.width=this.$chartSettingsPanel.find("#width.numeric-slider-input").find(".slider").slider("value");e.height=this.$chartSettingsPanel.find("#height.numeric-slider-input").find(".slider").slider("value");var d=this.$chartSettingsPanel.find("input#X-axis-label").val(),c=this.$chartSettingsPanel.find("input#Y-axis-label").val();e.xLabel=(d==="X")?(f.X.colName):(d);e.yLabel=(c==="Y")?(f.Y.colName):(c);e.animDuration=10;if(this.$chartSettingsPanel.find("#animDuration.checkbox-input").is(":checked")){e.animDuration=500}this.log("graphSettings:",e);return e},toString:function(){return"ScatterplotControlForm("+((this.dataset)?(this.dataset.id):(""))+")"}});b.templates={form:Handlebars.templates["template-visualization-scatterplotControlForm"],statsTable:Handlebars.templates["template-visualization-statsTable"],chartSettings:Handlebars.templates["template-visualization-chartSettings"]};return{LazyDataLoader:LazyDataLoader,TwoVarScatterplot:a,ScatterplotControlForm:b}});
\ No newline at end of file
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.
1
0
commit/galaxy-central: dannon: Adjust sqlalchemy import ordering, fixes functional test running.
by Bitbucket 20 Nov '12
by Bitbucket 20 Nov '12
20 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/67b9614dcab4/
changeset: 67b9614dcab4
user: dannon
date: 2012-11-20 19:05:32
summary: Adjust sqlalchemy import ordering, fixes functional test running.
affected #: 1 file
diff -r e856e0b90cd21338e27c385e9615612715bc7632 -r 67b9614dcab440027292c5dc387ef2eb1a763c19 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -9,8 +9,6 @@
pkg_resources.require("simplejson")
pkg_resources.require("pexpect")
import simplejson, os, errno, codecs, operator, socket, pexpect, logging, time
-from sqlalchemy.orm import object_session
-from sqlalchemy.sql.expression import func
import galaxy.datatypes
import galaxy.datatypes.registry
from galaxy.datatypes.metadata import MetadataCollection
@@ -21,6 +19,8 @@
from galaxy.web.form_builder import (AddressField, CheckboxField, PasswordField, SelectField, TextArea, TextField,
WorkflowField, WorkflowMappingField, HistoryField)
from galaxy.model.item_attrs import UsesAnnotations, APIItem
+from sqlalchemy.orm import object_session
+from sqlalchemy.sql.expression import func
log = logging.getLogger( __name__ )
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.
1
0
commit/galaxy-central: richard_burhans: updates to Phenotype Association tools from Belinda
by Bitbucket 20 Nov '12
by Bitbucket 20 Nov '12
20 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/e856e0b90cd2/
changeset: e856e0b90cd2
user: richard_burhans
date: 2012-11-20 17:42:13
summary: updates to Phenotype Association tools from Belinda
affected #: 16 files
Diff too large to display.
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.
1
0
commit/galaxy-central: inithello: Extend the tool shed functional test framework.
by Bitbucket 20 Nov '12
by Bitbucket 20 Nov '12
20 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/d69b780edd18/
changeset: d69b780edd18
user: inithello
date: 2012-11-20 15:17:41
summary: Extend the tool shed functional test framework.
affected #: 3 files
diff -r 0741ac889c4b85286a9baadcf6110f3e052a79f0 -r d69b780edd1816171c2751e2ce4d987f7254019e test/tool_shed/base/test_db_util.py
--- a/test/tool_shed/base/test_db_util.py
+++ b/test/tool_shed/base/test_db_util.py
@@ -2,6 +2,7 @@
from galaxy.model.orm import *
from galaxy.webapps.community.model.mapping import context as sa_session
from base.twilltestcase import *
+from sqlalchemy import desc
import sys
def delete_obj( obj ):
@@ -31,9 +32,20 @@
return sa_session.query( model.User ) \
.filter( model.User.table.c.email==email ) \
.first()
+def get_user_by_name( username ):
+ return sa_session.query( model.User ) \
+ .filter( model.User.table.c.username==username ) \
+ .first()
def mark_obj_deleted( obj ):
obj.deleted = True
sa_session.add( obj )
sa_session.flush()
def refresh( obj ):
sa_session.refresh( obj )
+def get_repository_by_name( name, owner_username ):
+ owner = get_user_by_name( owner_username )
+ repository = sa_session.query( model.Repository ) \
+ .filter( model.Repository.table.c.name==name ) \
+ .filter( model.Repository.table.c.user_id==owner.id ) \
+ .first()
+ return repository
diff -r 0741ac889c4b85286a9baadcf6110f3e052a79f0 -r d69b780edd1816171c2751e2ce4d987f7254019e test/tool_shed/base/twilltestcase.py
--- a/test/tool_shed/base/twilltestcase.py
+++ b/test/tool_shed/base/twilltestcase.py
@@ -1,4 +1,5 @@
from base.twilltestcase import *
+from tool_shed.base.test_db_util import *
class ShedTwillTestCase( TwillTestCase ):
def setUp( self ):
@@ -18,3 +19,123 @@
except:
pass
self.home()
+ def browse_repository( self, repository, strings_displayed=[], strings_not_displayed=[] ):
+ url = '/repository/browse_repository?id=%s' % self.security.encode_id( repository.id )
+ self.visit_url( url )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
+ def check_for_strings( self, strings_displayed=[], strings_not_displayed=[] ):
+ if strings_displayed:
+ for string in strings_displayed:
+ self.check_page_for_string( string )
+ if strings_not_displayed:
+ for string in strings_not_displayed:
+ self.check_string_not_in_page( string )
+ def check_for_valid_tools( self, repository ):
+ self.manage_repository( repository )
+ self.check_page_for_string( '<b>Valid tools</b><i> - click the name to preview the tool' )
+ def check_repository_changelog( self, repository, strings_displayed=[], strings_not_displayed=[] ):
+ url = '/repository/view_changelog?id=%s' % self.security.encode_id( repository.id )
+ self.visit_url( url )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
+ def create_category( self, category_name, category_description ):
+ self.visit_url( '/admin/manage_categories?operation=create' )
+ tc.fv( "1", "name", category_name )
+ tc.fv( "1", "description", category_description )
+ tc.submit( "create_category_button" )
+ def create_repository( self, repository_name, repository_description, repository_long_description=None, categories=[], strings_displayed=[], strings_not_displayed=[] ):
+ self.visit_url( '/repository/create_repository' )
+ tc.fv( "1", "name", repository_name )
+ tc.fv( "1", "description", repository_description )
+ if repository_long_description is not None:
+ tc.fv( "1", "long_description", repository_long_description )
+ for category in categories:
+ tc.fv( "1", "category_id", "+%s" % category )
+ tc.submit( "create_repository_button" )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
+ def display_repository_clone_page( self, owner_name, repository_name, strings_displayed=[], strings_not_displayed=[] ):
+ url = '/repos/%s/%s' % ( owner_name, repository_name )
+ self.visit_url( url )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
+ def edit_repository_categories( self, repository, categories_to_add=[], categories_to_remove=[], restore_original=True ):
+ url = '/repository/manage_repository?id=%s' % self.security.encode_id( repository.id )
+ self.visit_url( url )
+ strings_displayed = []
+ strings_not_displayed = []
+ for category in categories_to_add:
+ tc.fv( "2", "category_id", '+%s' % category)
+ strings_displayed.append( "selected>%s</option>" % category )
+ for category in categories_to_remove:
+ tc.fv( "2", "category_id", '-%s' % category)
+ strings_not_displayed.append( "selected>%s</option>" % category )
+ tc.submit( "manage_categories_button" )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
+ if restore_original:
+ strings_displayed = []
+ strings_not_displayed = []
+ for category in categories_to_remove:
+ tc.fv( "2", "category_id", '+%s' % category)
+ strings_displayed.append( "selected>%s</option>" % category )
+ for category in categories_to_add:
+ tc.fv( "2", "category_id", '-%s' % category)
+ strings_not_displayed.append( "selected>%s</option>" % category )
+ tc.submit( "manage_categories_button" )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
+ def edit_repository_information( self, repository, **kwargs ):
+ url = '/repository/manage_repository?id=%s' % self.security.encode_id( repository.id )
+ self.visit_url( url )
+ original_information = dict( repo_name=repository.name, description=repository.description, long_description=repository.long_description )
+ strings_displayed = []
+ strings_not_displayed = []
+ for input_elem_name in [ 'repo_name', 'description', 'long_description' ]:
+ if input_elem_name in kwargs:
+ tc.fv( "1", input_elem_name, kwargs[ input_elem_name ] )
+ strings_displayed.append( self.escape_html( kwargs[ input_elem_name ] ) )
+ tc.submit( "edit_repository_button" )
+ self.check_for_strings( strings_displayed )
+ strings_displayed = []
+ for input_elem_name in [ 'repo_name', 'description', 'long_description' ]:
+ tc.fv( "1", input_elem_name, original_information[ input_elem_name ] )
+ strings_displayed.append( self.escape_html( original_information[ input_elem_name ] ) )
+ tc.submit( "edit_repository_button" )
+ self.check_for_strings( strings_displayed )
+ def escape_html( self, string ):
+ html_entities = [ ('&', 'X' ), ( "'", ''' ), ( '"', '"' ) ]
+ for character, replacement in html_entities:
+ string = string.replace( character, replacement )
+ return string
+ def get_latest_repository_metadata_for_repository( self, repository ):
+ return repository.metadata_revisions[ 0 ]
+ def get_readme( self, repository, strings_displayed=[], strings_not_displayed=[] ):
+ repository_metadata = self.get_latest_repository_metadata_for_repository( repository )
+ changeset_revision = repository_metadata.changeset_revision
+ repository_id = self.security.encode_id( repository.id )
+ self.visit_url( '/repository/view_readme?changeset_revision=%s&id=%s' % ( changeset_revision, repository_id ) )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
+ def grant_write_access( self, repository, usernames=[], strings_displayed=[], strings_not_displayed=[] ):
+ self.manage_repository( repository )
+ tc.fv( "3", "allow_push", '-Select one' )
+ for username in usernames:
+ tc.fv( "3", "allow_push", '+%s' % username )
+ tc.submit( 'user_access_button' )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
+ def manage_repository( self, repository, strings_displayed=[], strings_not_displayed=[] ):
+ url = '/repository/manage_repository?id=%s' % self.security.encode_id( repository.id )
+ self.visit_url( url )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
+ def set_repository_malicious( self, repository, strings_displayed=[], strings_not_displayed=[] ):
+ self.manage_repository( repository )
+ tc.fv( "malicious", "malicious", True )
+ tc.submit( "malicious_button" )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
+ def unset_repository_malicious( self, repository, strings_displayed=[], strings_not_displayed=[] ):
+ self.manage_repository( repository )
+ tc.fv( "malicious", "malicious", False )
+ tc.submit( "malicious_button" )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
+ def upload( self, repository, filename, strings_displayed=[], strings_not_displayed=[], **kwargs ):
+ self.visit_url( '/upload/upload?repository_id=%s' % self.security.encode_id( repository.id ) )
+ for key in kwargs:
+ tc.fv( "1", key, kwargs[ key ] )
+ tc.formfile( "1", "file_data", filename )
+ tc.submit( "upload_button" )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
diff -r 0741ac889c4b85286a9baadcf6110f3e052a79f0 -r d69b780edd1816171c2751e2ce4d987f7254019e test/tool_shed/functional/test_0000_create_repository.py
--- a/test/tool_shed/functional/test_0000_create_repository.py
+++ b/test/tool_shed/functional/test_0000_create_repository.py
@@ -11,34 +11,77 @@
admin_email = 'test(a)bx.psu.edu'
admin_username = 'admin-user'
+regular_user = None
+regular_user_private_role = None
+regular_email = 'test-1(a)bx.psu.edu'
+regular_username = 'user1'
+
+repository_name = 'filter'
+repository_description = "Galaxy's filter tool"
+repository_long_description = "Long description of Galaxy's filter tool"
+files_path = os.path.abspath( os.path.join( "test", "tool_shed", "test_data" ) )
+filter_filename = os.path.join( files_path, "filtering_1.1.0.tar" )
+
class TestCreateRepository( ShedTwillTestCase ):
def test_0000_initiate_users( self ):
"""Create necessary users and login as an admin user."""
+ self.login( email=regular_email, username=regular_username )
+ regular_user = get_user( regular_email )
+ assert regular_user is not None, 'Problem retrieving user with email %s from the database' % regular_email
+ regular_user_private_role = get_private_role( regular_user )
self.logout()
self.login( email=admin_email, username=admin_username )
admin_user = get_user( admin_email )
assert admin_user is not None, 'Problem retrieving user with email %s from the database' % admin_email
admin_user_private_role = get_private_role( admin_user )
- def test_0005_create_category( self ):
+ def test_0005_create_categories( self ):
"""Create a category"""
- self.visit_url( '/admin/manage_categories?operation=create' )
- try:
- tc.fv( "1", "name", "Text Manipulation" )
- tc.fv( "1", "description", "Tools for manipulating text" )
- tc.submit( "create_category_button" )
- except Exception, e:
- errmsg = "Problem creating a category: %s" % str( e )
- raise AssertionError( e )
- def test_0010_create_filter_repository( self ):
+ self.create_category( 'Text Manipulation', 'Tools for manipulating text' )
+ self.create_category( 'Text Analysis', 'Tools for analyzing text' )
+ def test_0010_create_repository( self ):
"""Create a repository"""
- self.visit_url( '/repository/create_repository' )
- try:
- tc.fv( "1", "name", "filter" )
- tc.fv( "1", "description", "Galaxy's filter tool" )
- tc.fv( "1", "long_description", "Long description of Galaxy's filter tool" )
- tc.fv( "1", "category_id", "Text Manipulation" )
- tc.submit( "create_repository_button" )
- except Exception, e:
- errmsg = "Problem creating a repository: %s" % str( e )
- raise AssertionError( e )
+ strings_displayed = [ '<div class="toolFormTitle">Repository %s</div>' % "'%s'" % repository_name, \
+ 'Repository %s has been created' % "'%s'" % repository_name ]
+ self.create_repository( repository_name, repository_description, \
+ repository_long_description=repository_long_description, \
+ categories=[ 'Text Manipulation' ], \
+ strings_displayed=strings_displayed )
+ def test_0015_edit_repository( self ):
+ """Edit the repository name, description, and long description"""
+ repository = get_repository_by_name( repository_name, admin_username )
+ new_name = "renamed_filter"
+ new_description = "Edited filter tool"
+ new_long_description = "Edited long description"
+ self.edit_repository_information( repository, repo_name=new_name, description=new_description, long_description=new_long_description )
+ def test_0020_change_repository_category( self ):
+ """Change the category of a repository"""
+ repository = get_repository_by_name( repository_name, admin_username )
+ self.edit_repository_categories( repository, categories_to_add=[ "Text Analysis" ], categories_to_remove=[ "Text Manipulation" ] )
+# def test_0025_grant_write_access( self ):
+# '''Grant write access to another user'''
+# repository = get_repository_by_name( repository_name, admin_username )
+# self.grant_write_access( repository, usernames=[ regular_username ] )
+ def test_0030_upload_tarball( self ):
+ """Upload filtering_1.1.0.tar to the repository"""
+ repository = get_repository_by_name( repository_name, admin_username )
+ self.upload( repository, filter_filename, \
+ strings_displayed=[ "The file '%s' has been successfully uploaded to the repository." % filter_filename ], \
+ commit_message="Uploaded filtering 1.1.0" )
+ self.check_for_valid_tools( repository )
+ latest_changeset_revision = self.get_latest_repository_metadata_for_repository( repository )
+ self.check_repository_changelog( repository, strings_displayed=[ 'Repository metadata is associated with this change set.' ] )
+ self.set_repository_malicious( repository, strings_displayed=[ 'The repository tip has been defined as malicious.' ] )
+ self.unset_repository_malicious( repository, strings_displayed=[ 'The repository tip has been defined as <b>not</b> malicious.' ] )
+# self.check_tool_metadata( repository, latest_changeset_revision, strings_displayed=[ 'Filter1' ] )
+ def test_0035_repository_browse_page( self ):
+ '''Visit the repository browse page'''
+ repository = get_repository_by_name( repository_name, admin_username )
+ self.browse_repository( repository, strings_displayed=[ 'Browse %s revision' % repository.name, '(repository tip)' ] )
+ def test_0040_visit_clone_url_via_hgweb( self ):
+ '''Visit the repository clone URL via hgweb'''
+ repository = get_repository_by_name( repository_name, admin_username )
+ latest_changeset_revision = self.get_latest_repository_metadata_for_repository( repository )
+ self.display_repository_clone_page( admin_username, \
+ repository_name, \
+ strings_displayed=[ 'Uploaded filtering 1.1.0', latest_changeset_revision.changeset_revision ] )
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.
1
0
commit/galaxy-central: dannon: Update README to display a compatible python version as a result of python -V.
by Bitbucket 19 Nov '12
by Bitbucket 19 Nov '12
19 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/0741ac889c4b/
changeset: 0741ac889c4b
user: dannon
date: 2012-11-19 23:05:34
summary: Update README to display a compatible python version as a result of python -V.
affected #: 1 file
diff -r 8155a8ff8dd4f8aaabe4cee31ca0415c39302ed3 -r 0741ac889c4b85286a9baadcf6110f3e052a79f0 README.txt
--- a/README.txt
+++ b/README.txt
@@ -10,7 +10,7 @@
Galaxy requires Python 2.5, 2.6 or 2.7. To check your python version, run:
% python -V
-Python 2.4.4
+Python 2.7.3
Start Galaxy:
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.
1
0
commit/galaxy-central: dannon: Require pexpect -- previously not explicitly required
by Bitbucket 19 Nov '12
by Bitbucket 19 Nov '12
19 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/8155a8ff8dd4/
changeset: 8155a8ff8dd4
user: dannon
date: 2012-11-19 19:02:12
summary: Require pexpect -- previously not explicitly required
affected #: 1 file
diff -r 886d8ada4a2215aa4b69244908cb4859352a2f03 -r 8155a8ff8dd4f8aaabe4cee31ca0415c39302ed3 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -5,9 +5,10 @@
the relationship cardinalities are obvious (e.g. prefer Dataset to Data)
"""
-import pkg_resources, os, errno, codecs, operator, socket, pexpect, logging, time
-pkg_resources.require( "simplejson" )
-import simplejson
+import pkg_resources
+pkg_resources.require("simplejson")
+pkg_resources.require("pexpect")
+import simplejson, os, errno, codecs, operator, socket, pexpect, logging, time
from sqlalchemy.orm import object_session
from sqlalchemy.sql.expression import func
import galaxy.datatypes
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.
1
0
commit/galaxy-central: dannon: Refactor imports to remove 'import *s', remove unused variables/dead code, strip whitespace.
by Bitbucket 19 Nov '12
by Bitbucket 19 Nov '12
19 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/886d8ada4a22/
changeset: 886d8ada4a22
user: dannon
date: 2012-11-19 18:54:46
summary: Refactor imports to remove 'import *s', remove unused variables/dead code, strip whitespace.
affected #: 1 file
diff -r 950544a9b858d86bd1f3ff51c7433a90d2e89bfb -r 886d8ada4a2215aa4b69244908cb4859352a2f03 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -4,24 +4,22 @@
Naming: try to use class names that have a distinct plural form so that
the relationship cardinalities are obvious (e.g. prefer Dataset to Data)
"""
-import pkg_resources
+
+import pkg_resources, os, errno, codecs, operator, socket, pexpect, logging, time
pkg_resources.require( "simplejson" )
import simplejson
+from sqlalchemy.orm import object_session
+from sqlalchemy.sql.expression import func
import galaxy.datatypes
-from galaxy.util.bunch import Bunch
-from galaxy import util
import galaxy.datatypes.registry
from galaxy.datatypes.metadata import MetadataCollection
-from galaxy.security import RBACAgent, get_permitted_actions
-from galaxy.util.hash_util import *
-from galaxy.web.form_builder import *
+from galaxy.security import get_permitted_actions
+from galaxy import util
+from galaxy.util.bunch import Bunch
+from galaxy.util.hash_util import new_secure_hash
+from galaxy.web.form_builder import (AddressField, CheckboxField, PasswordField, SelectField, TextArea, TextField,
+ WorkflowField, WorkflowMappingField, HistoryField)
from galaxy.model.item_attrs import UsesAnnotations, APIItem
-from sqlalchemy.orm import object_session
-from sqlalchemy.sql.expression import func
-import os.path, os, errno, codecs, operator, socket, pexpect, logging, time, shutil
-
-if sys.version_info[:2] < ( 2, 5 ):
- from sets import Set as set
log = logging.getLogger( __name__ )
@@ -138,13 +136,13 @@
self.exit_code = None
# TODO: Add accessors for members defined in SQL Alchemy for the Job table and
- # for the mapper defined to the Job table.
+ # for the mapper defined to the Job table.
def get_external_output_metadata( self ):
"""
- The external_output_metadata is currently a reference from Job to
+ The external_output_metadata is currently a reference from Job to
JobExternalOutputMetadata. It exists for a job but not a task.
"""
- return self.external_output_metadata
+ return self.external_output_metadata
def get_session_id( self ):
return self.session_id
def get_user_id( self ):
@@ -177,7 +175,7 @@
# runner_name is not the same thing.
return self.job_runner_name
def get_job_runner_external_id( self ):
- # This is different from the Task just in the member accessed:
+ # This is different from the Task just in the member accessed:
return self.job_runner_external_id
def get_post_job_actions( self ):
return self.post_job_actions
@@ -197,10 +195,10 @@
# The tasks member is pert of a reference in the SQL Alchemy schema:
return self.tasks
def get_id_tag( self ):
- """
- Return a tag that can be useful in identifying a Job.
+ """
+ Return a tag that can be useful in identifying a Job.
This returns the Job's get_id
- """
+ """
return "%s" % self.id;
def set_session_id( self, session_id ):
@@ -324,8 +322,8 @@
self.task_runner_name = None
self.task_runner_external_id = None
self.job = job
- self.stdout = ""
- self.stderr = ""
+ self.stdout = ""
+ self.stderr = ""
self.exit_code = None
self.prepare_input_files_cmd = prepare_files_cmd
@@ -340,8 +338,8 @@
return param_dict
def get_id( self ):
- # This is defined in the SQL Alchemy schema:
- return self.id
+ # This is defined in the SQL Alchemy schema:
+ return self.id
def get_id_tag( self ):
"""
Return an id tag suitable for identifying the task.
@@ -378,7 +376,7 @@
# metdata). These can be filled in as needed.
def get_external_output_metadata( self ):
"""
- The external_output_metadata is currently a backref to
+ The external_output_metadata is currently a backref to
JobExternalOutputMetadata. It exists for a job but not a task,
and when a task is cancelled its corresponding parent Job will
be cancelled. So None is returned now, but that could be changed
@@ -395,13 +393,13 @@
"""
Runners will use the same methods to get information about the Task
class as they will about the Job class, so this method just returns
- the task's external id.
+ the task's external id.
"""
# TODO: Merge into get_runner_external_id.
return self.task_runner_external_id
def get_session_id( self ):
# The Job's galaxy session is equal to the Job's session, so the
- # Job's session is the same as the Task's session.
+ # Job's session is the same as the Task's session.
return self.get_job().get_session_id()
def set_id( self, id ):
@@ -424,7 +422,7 @@
# This method is available for runners that do not want/need to
# differentiate between the kinds of Runnable things (Jobs and Tasks)
# that they're using.
- log.debug( "Task %d: Set external id to %s"
+ log.debug( "Task %d: Set external id to %s"
% ( self.id, task_runner_external_id ) )
self.task_runner_external_id = task_runner_external_id
def set_task_runner_external_id( self, task_runner_external_id ):
@@ -954,7 +952,7 @@
return False
try:
return util.is_multi_byte( codecs.open( self.file_name, 'r', 'utf-8' ).read( 100 ) )
- except UnicodeDecodeError, e:
+ except UnicodeDecodeError:
return False
# FIXME: sqlalchemy will replace this
def _delete(self):
@@ -1136,7 +1134,6 @@
"""
Returns dict of { "dependency" => HDA }
"""
- converted_dataset = self.get_converted_files_by_type( target_ext )
# List of string of dependencies
try:
depends_list = trans.app.datatypes_registry.converter_deps[self.extension][target_ext]
@@ -1307,7 +1304,7 @@
"""
Returns datasources for dataset; if datasources are not available
due to indexing, indexing is started. Return value is a dictionary
- with entries of type
+ with entries of type
(<datasource_type> : {<datasource_name>, <indexing_message>}).
"""
track_type, data_sources = self.datatype.get_track_type()
@@ -1320,17 +1317,17 @@
else:
# Convert.
msg = self.convert_dataset( trans, data_source )
-
+
# Store msg.
data_sources_dict[ source_type ] = { "name" : data_source, "message": msg }
-
+
return data_sources_dict
def convert_dataset( self, trans, target_type ):
"""
- Converts a dataset to the target_type and returns a message indicating
+ Converts a dataset to the target_type and returns a message indicating
status of the conversion. None is returned to indicate that dataset
- was converted successfully.
+ was converted successfully.
"""
# FIXME: copied from controller.py
@@ -1402,7 +1399,7 @@
hda.metadata = self.metadata
if copy_children:
for child in self.children:
- child_copy = child.copy( copy_children = copy_children, parent_id = hda.id )
+ child.copy( copy_children = copy_children, parent_id = hda.id )
if not self.datatype.copy_safe_peek:
# In some instances peek relies on dataset_id, i.e. gmaj.zip for viewing MAFs
hda.set_peek()
@@ -1454,11 +1451,11 @@
object_session( self ).add( library_dataset )
object_session( self ).flush()
for child in self.children:
- child_copy = child.to_library_dataset_dataset_association( trans,
- target_folder=target_folder,
- replace_dataset=replace_dataset,
- parent_id=ldda.id,
- user=ldda.user )
+ child.to_library_dataset_dataset_association( trans,
+ target_folder=target_folder,
+ replace_dataset=replace_dataset,
+ parent_id=ldda.id,
+ user=ldda.user )
if not self.datatype.copy_safe_peek:
# In some instances peek relies on dataset_id, i.e. gmaj.zip for viewing MAFs
ldda.set_peek()
@@ -1808,7 +1805,7 @@
if add_to_history and target_history:
target_history.add_dataset( hda )
for child in self.children:
- child_copy = child.to_history_dataset_association( target_history = target_history, parent_id = hda.id, add_to_history = False )
+ child.to_history_dataset_association( target_history = target_history, parent_id = hda.id, add_to_history = False )
if not self.datatype.copy_safe_peek:
hda.set_peek() #in some instances peek relies on dataset_id, i.e. gmaj.zip for viewing MAFs
object_session( self ).flush()
@@ -1833,7 +1830,7 @@
ldda.metadata = self.metadata
if copy_children:
for child in self.children:
- child_copy = child.copy( copy_children = copy_children, parent_id = ldda.id )
+ child.copy( copy_children = copy_children, parent_id = ldda.id )
if not self.datatype.copy_safe_peek:
# In some instances peek relies on dataset_id, i.e. gmaj.zip for viewing MAFs
ldda.set_peek()
@@ -2640,7 +2637,7 @@
events={ '.ssword:*': scp_configs['password']+'\r\n',
pexpect.TIMEOUT:print_ticks},
timeout=10 )
- except Exception, e:
+ except Exception:
return error_msg
# cleanup the output to get just the file size
return output.replace( filepath, '' )\
@@ -3280,7 +3277,6 @@
.first()
return None
def get_versions( self, app ):
- sa_session = app.model.context.current
tool_versions = []
# Prepend ancestors.
def __ancestors( app, tool_version ):
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.
1
0
commit/galaxy-central: carlfeberhard: history panel: noop on ajax error fetching history updates when interrupted by iframe refresh.
by Bitbucket 19 Nov '12
by Bitbucket 19 Nov '12
19 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/950544a9b858/
changeset: 950544a9b858
user: carlfeberhard
date: 2012-11-19 18:18:10
summary: history panel: noop on ajax error fetching history updates when interrupted by iframe refresh.
affected #: 2 files
diff -r 9b27168c94423a91e0dc0249bb9453adc9532610 -r 950544a9b858d86bd1f3ff51c7433a90d2e89bfb static/scripts/mvc/history/history-model.js
--- a/static/scripts/mvc/history/history-model.js
+++ b/static/scripts/mvc/history/history-model.js
@@ -184,10 +184,14 @@
}
}).error( function( xhr, status, error ){
- if( console && console.warn ){
- console.warn( 'Error getting history updates from the server:', xhr, status, error );
+ // if not interruption by iframe reload
+ //TODO: remove when iframes are removed
+ if( !( ( xhr.readyState === 0 ) && ( xhr.status === 0 ) ) ){
+ if( console && console.warn ){
+ console.warn( 'Error getting history updates from the server:', xhr, status, error );
+ }
+ alert( _l( 'Error getting history updates from the server.' ) + '\n' + error );
}
- alert( _l( 'Error getting history updates from the server.' ) + '\n' + error );
});
},
diff -r 9b27168c94423a91e0dc0249bb9453adc9532610 -r 950544a9b858d86bd1f3ff51c7433a90d2e89bfb static/scripts/packed/mvc/history/history-model.js
--- a/static/scripts/packed/mvc/history/history-model.js
+++ b/static/scripts/packed/mvc/history/history-model.js
@@ -1,1 +1,1 @@
-var History=BaseModel.extend(LoggableMixin).extend({defaults:{id:"",name:"",state:"",diskSize:0,deleted:false,annotation:null,message:null},urlRoot:"api/histories/",url:function(){return"api/histories/"+this.get("id")},initialize:function(a,b){this.log(this+".initialize:",a,b);this.hdas=new HDACollection();if(b&&b.length){this.hdas.reset(b);this.checkForUpdates()}},loadFromApi:function(a,c){var b=this;b.attributes.id=a;jQuery.when(jQuery.ajax("api/users/current"),b.fetch()).then(function(e,d){b.attributes.user=e[0];b.trigger("loaded:user",e[0]);b.trigger("loaded",d[0])}).then(function(){jQuery.ajax(b.url()+"/contents?"+jQuery.param({ids:b.hdaIdsFromStateIds().join(",")})).success(function(d){b.hdas.reset(d);b.checkForUpdates();b.trigger("loaded:hdas",d);if(c){callback(b)}})})},hdaIdsFromStateIds:function(){return _.reduce(_.values(this.get("state_ids")),function(b,a){return b.concat(a)})},checkForUpdates:function(a){if(this.hdas.running().length){this.stateUpdater()}else{this.trigger("ready")}return this},stateUpdater:function(){var c=this,a=this.get("state"),b=this.get("state_ids");jQuery.ajax("api/histories/"+this.get("id")).success(function(d){c.set(d);c.log("current history state:",c.get("state"),"(was)",a,"new size:",c.get("nice_size"));var e=[];_.each(_.keys(d.state_ids),function(g){var f=_.difference(d.state_ids[g],b[g]);e=e.concat(f)});if(e.length){c.hdas.update(e)}if((c.get("state")===HistoryDatasetAssociation.STATES.RUNNING)||(c.get("state")===HistoryDatasetAssociation.STATES.QUEUED)){setTimeout(function(){c.stateUpdater()},4000)}else{c.trigger("ready")}}).error(function(f,d,e){if(console&&console.warn){console.warn("Error getting history updates from the server:",f,d,e)}alert(_l("Error getting history updates from the server.")+"\n"+e)})},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});var HistoryCollection=Backbone.Collection.extend(LoggableMixin).extend({model:History,urlRoot:"api/histories"});
\ No newline at end of file
+var History=BaseModel.extend(LoggableMixin).extend({defaults:{id:"",name:"",state:"",diskSize:0,deleted:false,annotation:null,message:null},urlRoot:"api/histories/",url:function(){return"api/histories/"+this.get("id")},initialize:function(a,b){this.log(this+".initialize:",a,b);this.hdas=new HDACollection();if(b&&b.length){this.hdas.reset(b);this.checkForUpdates()}},loadFromApi:function(a,c){var b=this;b.attributes.id=a;jQuery.when(jQuery.ajax("api/users/current"),b.fetch()).then(function(e,d){b.attributes.user=e[0];b.trigger("loaded:user",e[0]);b.trigger("loaded",d[0])}).then(function(){jQuery.ajax(b.url()+"/contents?"+jQuery.param({ids:b.hdaIdsFromStateIds().join(",")})).success(function(d){b.hdas.reset(d);b.checkForUpdates();b.trigger("loaded:hdas",d);if(c){callback(b)}})})},hdaIdsFromStateIds:function(){return _.reduce(_.values(this.get("state_ids")),function(b,a){return b.concat(a)})},checkForUpdates:function(a){if(this.hdas.running().length){this.stateUpdater()}else{this.trigger("ready")}return this},stateUpdater:function(){var c=this,a=this.get("state"),b=this.get("state_ids");jQuery.ajax("api/histories/"+this.get("id")).success(function(d){c.set(d);c.log("current history state:",c.get("state"),"(was)",a,"new size:",c.get("nice_size"));var e=[];_.each(_.keys(d.state_ids),function(g){var f=_.difference(d.state_ids[g],b[g]);e=e.concat(f)});if(e.length){c.hdas.update(e)}if((c.get("state")===HistoryDatasetAssociation.STATES.RUNNING)||(c.get("state")===HistoryDatasetAssociation.STATES.QUEUED)){setTimeout(function(){c.stateUpdater()},4000)}else{c.trigger("ready")}}).error(function(f,d,e){if(!((f.readyState===0)&&(f.status===0))){if(console&&console.warn){console.warn("Error getting history updates from the server:",f,d,e)}alert(_l("Error getting history updates from the server.")+"\n"+e)}})},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});var HistoryCollection=Backbone.Collection.extend(LoggableMixin).extend({model:History,urlRoot:"api/histories"});
\ No newline at end of file
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.
1
0
commit/galaxy-central: carlfeberhard: sphinx-autodoc: better formatting for metadata_spec
by Bitbucket 19 Nov '12
by Bitbucket 19 Nov '12
19 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/9b27168c9442/
changeset: 9b27168c9442
user: carlfeberhard
date: 2012-11-19 17:30:35
summary: sphinx-autodoc: better formatting for metadata_spec
affected #: 3 files
diff -r 19cbbaf566216cb46ecc6a6d17e0f1e0ab52978e -r 9b27168c94423a91e0dc0249bb9453adc9532610 lib/galaxy/datatypes/assembly.py
--- a/lib/galaxy/datatypes/assembly.py
+++ b/lib/galaxy/datatypes/assembly.py
@@ -225,4 +225,3 @@
if __name__ == '__main__':
import doctest, sys
doctest.testmod(sys.modules[__name__])
-
diff -r 19cbbaf566216cb46ecc6a6d17e0f1e0ab52978e -r 9b27168c94423a91e0dc0249bb9453adc9532610 lib/galaxy/datatypes/data.py
--- a/lib/galaxy/datatypes/data.py
+++ b/lib/galaxy/datatypes/data.py
@@ -69,6 +69,9 @@
<class 'galaxy.datatypes.metadata.MetadataParameter'>
"""
+ #: dictionary of metadata fields for this datatype::
+ metadata_spec = None
+
__metaclass__ = DataMeta
# Add metadata elements
MetadataElement( name="dbkey", desc="Database/Build", default="?", param=metadata.DBKeyParameter, multiple=False, no_value="?" )
@@ -849,4 +852,3 @@
except UnicodeDecodeError:
text = "binary/unknown file"
return text
-
diff -r 19cbbaf566216cb46ecc6a6d17e0f1e0ab52978e -r 9b27168c94423a91e0dc0249bb9453adc9532610 lib/galaxy/datatypes/metadata.py
--- a/lib/galaxy/datatypes/metadata.py
+++ b/lib/galaxy/datatypes/metadata.py
@@ -123,6 +123,7 @@
def __getstate__( self ):
return None #cannot pickle a weakref item (self._parent), when data._metadata_collection is None, it will be recreated on demand
+
class MetadataSpecCollection( odict ):
"""
A simple extension of dict which allows cleaner access to items
@@ -132,13 +133,21 @@
"""
def __init__( self, dict = None ):
odict.__init__( self, dict = None )
+
def append( self, item ):
self[item.name] = item
+
def iter( self ):
return self.itervalues()
+
def __getattr__( self, name ):
return self.get( name )
+ def __repr__( self ):
+ # force elements to draw with __str__ for sphinx-apidoc
+ return ', '.join([ item.__str__() for item in self.iter() ])
+
+
class MetadataParameter( object ):
def __init__( self, spec ):
self.spec = spec
@@ -185,7 +194,6 @@
"""
pass
-
def unwrap( self, form_value ):
"""
Turns a value into its storable form.
@@ -205,19 +213,22 @@
Turns a value read from an external dict into its value to be pushed directly into the metadata dict.
"""
return value
+
def to_external_value( self, value ):
"""
Turns a value read from a metadata into its value to be pushed directly into the external dict.
"""
return value
+
class MetadataElementSpec( object ):
"""
Defines a metadata element and adds it to the metadata_spec (which
is a MetadataSpecCollection) of datatype.
"""
-
- def __init__( self, datatype, name=None, desc=None, param=MetadataParameter, default=None, no_value = None, visible=True, set_in_upload = False, **kwargs ):
+ def __init__( self, datatype,
+ name=None, desc=None, param=MetadataParameter, default=None, no_value = None,
+ visible=True, set_in_upload = False, **kwargs ):
self.name = name
self.desc = desc or name
self.default = default
@@ -226,24 +237,37 @@
self.set_in_upload = set_in_upload
# Catch-all, allows for extra attributes to be set
self.__dict__.update(kwargs)
- #set up param last, as it uses values set above
+ # set up param last, as it uses values set above
self.param = param( self )
- datatype.metadata_spec.append( self ) #add spec element to the spec
+ # add spec element to the spec
+ datatype.metadata_spec.append( self )
+
def get( self, name, default=None ):
return self.__dict__.get(name, default)
+
def wrap( self, value ):
"""
Turns a stored value into its usable form.
"""
return self.param.wrap( value )
+
def unwrap( self, value ):
"""
Turns an incoming value into its storable form.
"""
return self.param.unwrap( value )
+ def __str__( self ):
+ #TODO??: assuming param is the class of this MetadataElementSpec - add the plain class name for that
+ spec_dict = dict( param_class=self.param.__class__.__name__ )
+ spec_dict.update( self.__dict__ )
+ return ( "{name} ({param_class}): {desc}, defaults to '{default}'".format( **spec_dict ) )
+
+# create a statement class that, when called,
+# will add a new MetadataElementSpec to a class's metadata_spec
MetadataElement = Statement( MetadataElementSpec )
+
"""
MetadataParameter sub-classes.
"""
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.
1
0
commit/galaxy-central: dannon: Jobs need to be set back to NEW to immediately resume running, instead of QUEUED.
by Bitbucket 16 Nov '12
by Bitbucket 16 Nov '12
16 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/19cbbaf56621/
changeset: 19cbbaf56621
user: dannon
date: 2012-11-16 21:49:10
summary: Jobs need to be set back to NEW to immediately resume running, instead of QUEUED.
affected #: 1 file
diff -r 243ff2bfbf28fb92f94eca408d063fb5257a6481 -r 19cbbaf566216cb46ecc6a6d17e0f1e0ab52978e lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -702,7 +702,7 @@
for dataset in self.datasets:
job = dataset.creating_job
if job is not None and job.state == Job.states.PAUSED:
- job.set_state(Job.states.QUEUED)
+ job.set_state(Job.states.NEW)
def get_disk_size( self, nice_size=False ):
# unique datasets only
db_session = object_session( self )
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.
1
0
commit/galaxy-central: inithello: Fix for TwillTestCase.wait() with the new client-side histories.
by Bitbucket 16 Nov '12
by Bitbucket 16 Nov '12
16 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/243ff2bfbf28/
changeset: 243ff2bfbf28
user: inithello
date: 2012-11-16 21:39:50
summary: Fix for TwillTestCase.wait() with the new client-side histories.
affected #: 1 file
diff -r 8bd9f729fb6a92077b9652690b11877f203902ec -r 243ff2bfbf28fb92f94eca408d063fb5257a6481 test/base/twilltestcase.py
--- a/test/base/twilltestcase.py
+++ b/test/base/twilltestcase.py
@@ -1199,15 +1199,25 @@
tc.fv( 2, "hgta_doGalaxyQuery", "Send query to Galaxy" )
self.submit_form( button="Send query to Galaxy" )#, **output_params ) #AssertionError: Attempting to set field 'fbQual' to value '['whole']' in form 'None' threw exception: no matching forms! control: <RadioControl(fbQual=[whole, upstreamAll, endAll])>
+ def get_running_datasets( self ):
+ self.visit_url( '/api/histories' )
+ history_id = from_json_string( self.last_page() )[0][ 'id' ]
+ self.visit_url( '/api/histories/%s/contents' % history_id )
+ jsondata = from_json_string( self.last_page() )
+ for history_item in jsondata:
+ self.visit_url( history_item[ 'url' ] )
+ item_json = from_json_string( self.last_page() )
+ if item_json[ 'state' ] in [ 'queued', 'running', 'paused' ]:
+ return True
+ return False
+
def wait( self, maxseconds=120 ):
"""Waits for the tools to finish"""
sleep_amount = 0.1
slept = 0
self.home()
while slept <= maxseconds:
- self.visit_page( "history" )
- page = tc.browser.get_html()
- if page.find( '<!-- running: do not change this comment, used by TwillTestCase.wait -->' ) > -1:
+ if self.get_running_datasets():
time.sleep( sleep_amount )
slept += sleep_amount
sleep_amount *= 2
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.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/430ea49ff3c2/
changeset: 430ea49ff3c2
user: natefoo
date: 2012-11-16 21:36:31
summary: Jobs now have their runner name set prior to actually being submitted to the runner, meaning that runners' recover() methods must handle the case where the job was never actually submitted.
affected #: 4 files
diff -r 7f7171c52b1d922fb6471c8ce373fa3e50901206 -r 430ea49ff3c2ab00af9e5d602216ac37c489156e lib/galaxy/jobs/runners/cli.py
--- a/lib/galaxy/jobs/runners/cli.py
+++ b/lib/galaxy/jobs/runners/cli.py
@@ -359,12 +359,16 @@
def recover( self, job, job_wrapper ):
"""Recovers jobs stuck in the queued/running state when Galaxy started"""
+ job_id = job.get_job_runner_external_id()
+ if job_id is None:
+ self.put( job_wrapper )
+ return
runner_job_state = RunnerJobState()
runner_job_state.ofile = "%s.gjout" % os.path.join(job_wrapper.working_directory, job_wrapper.get_id_tag())
runner_job_state.efile = "%s.gjerr" % os.path.join(job_wrapper.working_directory, job_wrapper.get_id_tag())
runner_job_state.ecfile = "%s.gjec" % os.path.join(job_wrapper.working_directory, job_wrapper.get_id_tag())
runner_job_state.job_file = "%s/galaxy_%s.sh" % (self.app.config.cluster_files_directory, job_wrapper.get_id_tag())
- runner_job_state.external_job_id = str( job.job_runner_external_id )
+ runner_job_state.external_job_id = str( job_id )
job_wrapper.command_line = job.command_line
runner_job_state.job_wrapper = job_wrapper
runner_job_state.runner_url = job.job_runner_name
diff -r 7f7171c52b1d922fb6471c8ce373fa3e50901206 -r 430ea49ff3c2ab00af9e5d602216ac37c489156e lib/galaxy/jobs/runners/condor.py
--- a/lib/galaxy/jobs/runners/condor.py
+++ b/lib/galaxy/jobs/runners/condor.py
@@ -368,11 +368,15 @@
def recover( self, job, job_wrapper ):
"""Recovers jobs stuck in the queued/running state when Galaxy started"""
# TODO Check if we need any changes here
+ job_id = job.get_job_runner_external_id()
+ if job_id is None:
+ self.put( job_wrapper )
+ return
drm_job_state = CondorJobState()
drm_job_state.ofile = "%s/database/pbs/%s.o" % (os.getcwd(), job.id)
drm_job_state.efile = "%s/database/pbs/%s.e" % (os.getcwd(), job.id)
drm_job_state.job_file = "%s/database/pbs/galaxy_%s.sh" % (os.getcwd(), job.id)
- drm_job_state.job_id = str( job.job_runner_external_id )
+ drm_job_state.job_id = str( job_id )
drm_job_state.runner_url = job_wrapper.get_job_runner()
job_wrapper.command_line = job.command_line
drm_job_state.job_wrapper = job_wrapper
diff -r 7f7171c52b1d922fb6471c8ce373fa3e50901206 -r 430ea49ff3c2ab00af9e5d602216ac37c489156e lib/galaxy/jobs/runners/drmaa.py
--- a/lib/galaxy/jobs/runners/drmaa.py
+++ b/lib/galaxy/jobs/runners/drmaa.py
@@ -411,12 +411,16 @@
def recover( self, job, job_wrapper ):
"""Recovers jobs stuck in the queued/running state when Galaxy started"""
+ job_id = job.get_job_runner_external_id()
+ if job_id is None:
+ self.put( job_wrapper )
+ return
drm_job_state = DRMAAJobState()
drm_job_state.ofile = "%s.drmout" % os.path.join(os.getcwd(), job_wrapper.working_directory, job_wrapper.get_id_tag())
drm_job_state.efile = "%s.drmerr" % os.path.join(os.getcwd(), job_wrapper.working_directory, job_wrapper.get_id_tag())
drm_job_state.ecfile = "%s.drmec" % os.path.join(os.getcwd(), job_wrapper.working_directory, job_wrapper.get_id_tag())
drm_job_state.job_file = "%s/galaxy_%s.sh" % (self.app.config.cluster_files_directory, job.get_id())
- drm_job_state.job_id = str( job.get_job_runner_external_id() )
+ drm_job_state.job_id = str( job_id )
drm_job_state.runner_url = job_wrapper.get_job_runner_url()
job_wrapper.command_line = job.get_command_line()
drm_job_state.job_wrapper = job_wrapper
diff -r 7f7171c52b1d922fb6471c8ce373fa3e50901206 -r 430ea49ff3c2ab00af9e5d602216ac37c489156e lib/galaxy/jobs/runners/pbs.py
--- a/lib/galaxy/jobs/runners/pbs.py
+++ b/lib/galaxy/jobs/runners/pbs.py
@@ -640,12 +640,16 @@
def recover( self, job, job_wrapper ):
"""Recovers jobs stuck in the queued/running state when Galaxy started"""
+ job_id = job.get_job_runner_external_id()
+ if job_id is None:
+ self.put( job_wrapper )
+ return
pbs_job_state = PBSJobState()
pbs_job_state.ofile = "%s/%s.o" % (self.app.config.cluster_files_directory, job.id)
pbs_job_state.efile = "%s/%s.e" % (self.app.config.cluster_files_directory, job.id)
pbs_job_state.ecfile = "%s/%s.ec" % (self.app.config.cluster_files_directory, job.id)
pbs_job_state.job_file = "%s/%s.sh" % (self.app.config.cluster_files_directory, job.id)
- pbs_job_state.job_id = str( job.get_job_runner_external_id() )
+ pbs_job_state.job_id = str( job_id )
pbs_job_state.runner_url = job_wrapper.get_job_runner_url()
job_wrapper.command_line = job.command_line
pbs_job_state.job_wrapper = job_wrapper
https://bitbucket.org/galaxy/galaxy-central/changeset/8bd9f729fb6a/
changeset: 8bd9f729fb6a
user: natefoo
date: 2012-11-16 21:36:56
summary: Remove the long-deprecated SGE runner. Use the DRMAA runner.
affected #: 1 file
diff -r 430ea49ff3c2ab00af9e5d602216ac37c489156e -r 8bd9f729fb6a92077b9652690b11877f203902ec lib/galaxy/jobs/runners/sge.py
--- a/lib/galaxy/jobs/runners/sge.py
+++ /dev/null
@@ -1,392 +0,0 @@
-import os, logging, threading, time
-from Queue import Queue, Empty
-
-from galaxy import model
-from galaxy.jobs.runners import BaseJobRunner
-
-from paste.deploy.converters import asbool
-
-import pkg_resources
-
-egg_message = """
-
-The 'sge' runner depends on 'DRMAA_python' which is not installed. Galaxy's
-"scramble" system should make this installation simple, please follow the
-instructions found at:
-
- http://wiki.g2.bx.psu.edu/Admin/Config/Performance/Cluster
-
-Additional errors may follow:
-%s
-"""
-
-
-try:
- pkg_resources.require( "DRMAA_python" )
- import DRMAA
-except Exception, e:
- raise Exception( egg_message % str( e ) )
-
-
-log = logging.getLogger( __name__ )
-
-__all__ = [ 'SGEJobRunner' ]
-
-DRMAA_state = {
- DRMAA.Session.UNDETERMINED: 'process status cannot be determined',
- DRMAA.Session.QUEUED_ACTIVE: 'job is queued and waiting to be scheduled',
- DRMAA.Session.SYSTEM_ON_HOLD: 'job is queued and in system hold',
- DRMAA.Session.USER_ON_HOLD: 'job is queued and in user hold',
- DRMAA.Session.USER_SYSTEM_ON_HOLD: 'job is queued and in user and system hold',
- DRMAA.Session.RUNNING: 'job is running',
- DRMAA.Session.SYSTEM_SUSPENDED: 'job is system suspended',
- DRMAA.Session.USER_SUSPENDED: 'job is user suspended',
- DRMAA.Session.DONE: 'job finished normally',
- DRMAA.Session.FAILED: 'job finished, but failed',
-}
-
-sge_template = """#!/bin/sh
-#$ -S /bin/sh
-GALAXY_LIB="%s"
-if [ "$GALAXY_LIB" != "None" ]; then
- if [ -n "$PYTHONPATH" ]; then
- PYTHONPATH="$GALAXY_LIB:$PYTHONPATH"
- else
- PYTHONPATH="$GALAXY_LIB"
- fi
- export PYTHONPATH
-fi
-cd %s
-%s
-"""
-
-class SGEJobState( object ):
- def __init__( self ):
- """
- Encapsulates state related to a job that is being run via SGE and
- that we need to monitor.
- """
- self.job_wrapper = None
- self.job_id = None
- self.old_state = None
- self.running = False
- self.job_file = None
- self.ofile = None
- self.efile = None
- self.runner_url = None
-
-class SGEJobRunner( BaseJobRunner ):
- """
- Job runner backed by a finite pool of worker threads. FIFO scheduling
- """
- STOP_SIGNAL = object()
- def __init__( self, app ):
- """Initialize this job runner and start the monitor thread"""
- self.app = app
- self.sa_session = app.model.context
- # 'watched' and 'queue' are both used to keep track of jobs to watch.
- # 'queue' is used to add new watched jobs, and can be called from
- # any thread (usually by the 'queue_job' method). 'watched' must only
- # be modified by the monitor thread, which will move items from 'queue'
- # to 'watched' and then manage the watched jobs.
- self.watched = []
- self.monitor_queue = Queue()
- self.default_cell = self.determine_sge_cell( self.app.config.default_cluster_job_runner )
- self.ds = DRMAA.Session()
- self.ds.init( self.default_cell )
- self.monitor_thread = threading.Thread( target=self.monitor )
- self.monitor_thread.start()
- self.work_queue = Queue()
- self.work_threads = []
- nworkers = app.config.cluster_job_queue_workers
- for i in range( nworkers ):
- worker = threading.Thread( target=self.run_next )
- worker.start()
- self.work_threads.append( worker )
- log.debug( "%d workers ready" % nworkers )
-
- def determine_sge_cell( self, url ):
- """Determine what SGE cell we are using"""
- url_split = url.split("/")
- if url_split[0] == 'sge:':
- return url_split[2]
- # this could happen if sge is started, but is not the default runner
- else:
- return ''
-
- def determine_sge_queue( self, url ):
- """Determine what SGE queue we are submitting to"""
- try:
- return url.split('/')[3] or None
- except:
- return None
-
- def determine_sge_project( self, url ):
- """Determine what SGE project we are submitting to"""
- try:
- return url.split('/')[4] or None
- except:
- return None
-
- def determine_sge_tool_parameters( self, url ):
- """Determine what are the tool's specific paramters"""
- try:
- return url.split('/')[5] or None
- except:
- return None
-
- def run_next( self ):
- """
- Run the next item in the queue (a job waiting to run or finish )
- """
- while 1:
- ( op, obj ) = self.work_queue.get()
- if op is self.STOP_SIGNAL:
- return
- try:
- if op == 'queue':
- self.queue_job( obj )
- elif op == 'finish':
- self.finish_job( obj )
- elif op == 'fail':
- self.fail_job( obj )
- except:
- log.exception( "Uncaught exception %sing job" % op )
-
- def queue_job( self, job_wrapper ):
- """Create SGE script for a job and submit it to the SGE queue"""
-
- try:
- job_wrapper.prepare()
- command_line = self.build_command_line( job_wrapper, include_metadata = True )
- except:
- job_wrapper.fail( "failure preparing job", exception=True )
- log.exception("failure running job %d" % job_wrapper.job_id)
- return
-
- runner_url = job_wrapper.get_job_runner_url()
-
- # This is silly, why would we queue a job with no command line?
- if not command_line:
- job_wrapper.finish( '', '' )
- return
-
- # Check for deletion before we change state
- if job_wrapper.get_state() == model.Job.states.DELETED:
- log.debug( "Job %s deleted by user before it entered the SGE queue" % job_wrapper.job_id )
- job_wrapper.cleanup()
- return
-
- # Change to queued state immediately
- job_wrapper.change_state( model.Job.states.QUEUED )
-
- if self.determine_sge_cell( runner_url ) != self.default_cell:
- # TODO: support multiple cells
- log.warning( "(%s) Using multiple SGE cells is not supported. This job will be submitted to the default cell." % job_wrapper.job_id )
- sge_queue_name = self.determine_sge_queue( runner_url )
- sge_project_name = self.determine_sge_project( runner_url )
- sge_extra_params = self.determine_sge_tool_parameters ( runner_url )
-
- # define job attributes
- ofile = "%s/%s.o" % (self.app.config.cluster_files_directory, job_wrapper.job_id)
- efile = "%s/%s.e" % (self.app.config.cluster_files_directory, job_wrapper.job_id)
- jt = self.ds.createJobTemplate()
- jt.remoteCommand = "%s/database/pbs/galaxy_%s.sh" % (os.getcwd(), job_wrapper.job_id)
- jt.outputPath = ":%s" % ofile
- jt.errorPath = ":%s" % efile
- nativeSpec = []
- if sge_queue_name is not None:
- nativeSpec.append( "-q '%s'" % sge_queue_name )
- if sge_project_name is not None:
- nativeSpec.append( "-P '%s'" % sge_project_name)
- if sge_extra_params is not None:
- nativeSpec.append( sge_extra_params )
- if len(nativeSpec)>0:
- jt.nativeSpecification = ' '.join(nativeSpec)
-
- script = sge_template % (job_wrapper.galaxy_lib_dir, os.path.abspath( job_wrapper.working_directory ), command_line)
-
- fh = file( jt.remoteCommand, "w" )
- fh.write( script )
- fh.close()
- os.chmod( jt.remoteCommand, 0750 )
-
- # job was deleted while we were preparing it
- if job_wrapper.get_state() == model.Job.states.DELETED:
- log.debug( "Job %s deleted by user before it entered the SGE queue" % job_wrapper.job_id )
- self.cleanup( ( ofile, efile, jt.remoteCommand ) )
- job_wrapper.cleanup()
- return
-
- galaxy_job_id = job_wrapper.job_id
- log.debug("(%s) submitting file %s" % ( galaxy_job_id, jt.remoteCommand ) )
- log.debug("(%s) command is: %s" % ( galaxy_job_id, command_line ) )
- # runJob will raise if there's a submit problem
- job_id = self.ds.runJob(jt)
- if sge_queue_name is None:
- log.debug("(%s) queued in default queue as %s" % (galaxy_job_id, job_id) )
- else:
- log.debug("(%s) queued in %s queue as %s" % (galaxy_job_id, sge_queue_name, job_id) )
-
- # store runner information for tracking if Galaxy restarts
- job_wrapper.set_runner( runner_url, job_id )
-
- # Store SGE related state information for job
- sge_job_state = SGEJobState()
- sge_job_state.job_wrapper = job_wrapper
- sge_job_state.job_id = job_id
- sge_job_state.ofile = ofile
- sge_job_state.efile = efile
- sge_job_state.job_file = jt.remoteCommand
- sge_job_state.old_state = 'new'
- sge_job_state.running = False
- sge_job_state.runner_url = runner_url
-
- # delete the job template
- self.ds.deleteJobTemplate( jt )
-
- # Add to our 'queue' of jobs to monitor
- self.monitor_queue.put( sge_job_state )
-
- def monitor( self ):
- """
- Watches jobs currently in the PBS queue and deals with state changes
- (queued to running) and job completion
- """
- while 1:
- # Take any new watched jobs and put them on the monitor list
- try:
- while 1:
- sge_job_state = self.monitor_queue.get_nowait()
- if sge_job_state is self.STOP_SIGNAL:
- # TODO: This is where any cleanup would occur
- self.ds.exit()
- return
- self.watched.append( sge_job_state )
- except Empty:
- pass
- # Iterate over the list of watched jobs and check state
- self.check_watched_items()
- # Sleep a bit before the next state check
- time.sleep( 1 )
-
- def check_watched_items( self ):
- """
- Called by the monitor thread to look at each watched job and deal
- with state changes.
- """
- new_watched = []
- for sge_job_state in self.watched:
- job_id = sge_job_state.job_id
- galaxy_job_id = sge_job_state.job_wrapper.job_id
- old_state = sge_job_state.old_state
- try:
- state = self.ds.getJobProgramStatus( job_id )
- except DRMAA.InvalidJobError:
- # we should only get here if an orphaned job was put into the queue at app startup
- log.debug("(%s/%s) job left SGE queue" % ( galaxy_job_id, job_id ) )
- self.work_queue.put( ( 'finish', sge_job_state ) )
- continue
- except Exception, e:
- # so we don't kill the monitor thread
- log.exception("(%s/%s) Unable to check job status" % ( galaxy_job_id, job_id ) )
- log.warning("(%s/%s) job will now be errored" % ( galaxy_job_id, job_id ) )
- sge_job_state.fail_message = "Cluster could not complete job"
- self.work_queue.put( ( 'fail', sge_job_state ) )
- continue
- if state != old_state:
- log.debug("(%s/%s) state change: %s" % ( galaxy_job_id, job_id, DRMAA_state[state] ) )
- if state == DRMAA.Session.RUNNING and not sge_job_state.running:
- sge_job_state.running = True
- sge_job_state.job_wrapper.change_state( model.Job.states.RUNNING )
- if state in ( DRMAA.Session.DONE, DRMAA.Session.FAILED ):
- self.work_queue.put( ( 'finish', sge_job_state ) )
- continue
- sge_job_state.old_state = state
- new_watched.append( sge_job_state )
- # Replace the watch list with the updated version
- self.watched = new_watched
-
- def finish_job( self, sge_job_state ):
- """
- Get the output/error for a finished job, pass to `job_wrapper.finish`
- and cleanup all the SGE temporary files.
- """
- ofile = sge_job_state.ofile
- efile = sge_job_state.efile
- job_file = sge_job_state.job_file
- # collect the output
- try:
- ofh = file(ofile, "r")
- efh = file(efile, "r")
- stdout = ofh.read( 32768 )
- stderr = efh.read( 32768 )
- except:
- stdout = ''
- stderr = 'Job output not returned from cluster'
- log.debug(stderr)
-
- try:
- sge_job_state.job_wrapper.finish( stdout, stderr )
- except:
- log.exception("Job wrapper finish method failed")
-
- # clean up the sge files
- self.cleanup( ( ofile, efile, job_file ) )
-
- def fail_job( self, sge_job_state ):
- """
- Seperated out so we can use the worker threads for it.
- """
- self.stop_job( self.sa_session.query( self.app.model.Job ).get( sge_job_state.job_wrapper.job_id ) )
- sge_job_state.job_wrapper.fail( sge_job_state.fail_message )
- self.cleanup( ( sge_job_state.ofile, sge_job_state.efile, sge_job_state.job_file ) )
-
- def cleanup( self, files ):
- if not asbool( self.app.config.get( 'debug', False ) ):
- for file in files:
- if os.access( file, os.R_OK ):
- os.unlink( file )
-
- def put( self, job_wrapper ):
- """Add a job to the queue (by job identifier)"""
- # Change to queued state before handing to worker thread so the runner won't pick it up again
- job_wrapper.change_state( model.Job.states.QUEUED )
- self.work_queue.put( ( 'queue', job_wrapper ) )
-
- def shutdown( self ):
- """Attempts to gracefully shut down the monitor thread"""
- log.info( "sending stop signal to worker threads" )
- self.monitor_queue.put( self.STOP_SIGNAL )
- for i in range( len( self.work_threads ) ):
- self.work_queue.put( ( self.STOP_SIGNAL, None ) )
- log.info( "sge job runner stopped" )
-
- def stop_job( self, job ):
- """Attempts to delete a job from the SGE queue"""
- try:
- self.ds.control( job.get_job_runner_external_id(), DRMAA.Session.TERMINATE )
- log.debug( "(%s/%s) Removed from SGE queue at user's request" % ( job.get_id(), job.get_job_runner_external_id() ) )
- except DRMAA.InvalidJobError:
- log.debug( "(%s/%s) User killed running job, but it was already dead" % ( job.get_id(), job.get_job_runner_external_id() ) )
-
- def recover( self, job, job_wrapper ):
- """Recovers jobs stuck in the queued/running state when Galaxy started"""
- sge_job_state = SGEJobState()
- sge_job_state.ofile = "%s/database/pbs/%s.o" % (os.getcwd(), job.get_id())
- sge_job_state.efile = "%s/database/pbs/%s.e" % (os.getcwd(), job.get_id())
- sge_job_state.job_file = "%s/database/pbs/galaxy_%s.sh" % (os.getcwd(), job.get_id())
- sge_job_state.job_id = str( job.get_job_runner_external_id() )
- sge_job_state.runner_url = job_wrapper.get_job_runner_url()
- job_wrapper.command_line = job.get_command_line()
- sge_job_state.job_wrapper = job_wrapper
- if job.get_state() == model.Job.states.RUNNING:
- log.debug( "(%s/%s) is still in running state, adding to the SGE queue" % ( job.get_id(), job.get_job_runner_external_id() ) )
- sge_job_state.old_state = DRMAA.Session.RUNNING
- sge_job_state.running = True
- self.monitor_queue.put( sge_job_state )
- elif job.get_state() == model.Job.states.QUEUED:
- log.debug( "(%s/%s) is still in SGE queued state, adding to the SGE queue" % ( job.get_id(), job.get_job_runner_external_id() ) )
- sge_job_state.old_state = DRMAA.Session.QUEUED_ACTIVE
- sge_job_state.running = False
- self.monitor_queue.put( sge_job_state )
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.
1
0
commit/galaxy-central: natefoo: Fix unpause when you have datasets imported from a library.
by Bitbucket 16 Nov '12
by Bitbucket 16 Nov '12
16 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/7f7171c52b1d/
changeset: 7f7171c52b1d
user: natefoo
date: 2012-11-16 21:14:11
summary: Fix unpause when you have datasets imported from a library.
affected #: 1 file
diff -r c7bc628577af7f57b5511b2cc8e1423d5faf31df -r 7f7171c52b1d922fb6471c8ce373fa3e50901206 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -701,7 +701,7 @@
def resume_paused_jobs( self ):
for dataset in self.datasets:
job = dataset.creating_job
- if job.state == Job.states.PAUSED:
+ if job is not None and job.state == Job.states.PAUSED:
job.set_state(Job.states.QUEUED)
def get_disk_size( self, nice_size=False ):
# unique datasets only
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.
1
0
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/c7bc628577af/
changeset: c7bc628577af
user: greg
date: 2012-11-16 19:36:36
summary: Yet more shed_util refactoring.
affected #: 2 files
diff -r 9e1d821b5c12f56bbfe1923ea1092608054c9d08 -r c7bc628577af7f57b5511b2cc8e1423d5faf31df lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -784,24 +784,6 @@
# Reset the tool_data_tables by loading the empty tool_data_table_conf.xml file.
reset_tool_data_tables( app )
return repository_tools_tups
-def handle_existing_tool_dependencies_that_changed_in_update( app, repository, original_dependency_dict, new_dependency_dict ):
- """
- This method is called when a Galaxy admin is getting updates for an installed tool shed repository in order to cover the case where an
- existing tool dependency was changed (e.g., the version of the dependency was changed) but the tool version for which it is a dependency
- was not changed. In this case, we only want to determine if any of the dependency information defined in original_dependency_dict was
- changed in new_dependency_dict. We don't care if new dependencies were added in new_dependency_dict since they will just be treated as
- missing dependencies for the tool.
- """
- updated_tool_dependency_names = []
- deleted_tool_dependency_names = []
- for original_dependency_key, original_dependency_val_dict in original_dependency_dict.items():
- if original_dependency_key not in new_dependency_dict:
- updated_tool_dependency = update_existing_tool_dependency( app, repository, original_dependency_val_dict, new_dependency_dict )
- if updated_tool_dependency:
- updated_tool_dependency_names.append( updated_tool_dependency.name )
- else:
- deleted_tool_dependency_names.append( original_dependency_val_dict[ 'name' ] )
- return updated_tool_dependency_names, deleted_tool_dependency_names
def handle_missing_index_file( app, tool_path, sample_files, repository_tools_tups, sample_files_copied ):
"""
Inspect each tool to see if it has any input parameters that are dynamically generated select lists that depend on a .loc file.
@@ -1136,21 +1118,6 @@
trans.sa_session.add( tool_dependency )
trans.sa_session.flush()
return removed, error_message
-def remove_tool_dependency_installation_directory( dependency_install_dir ):
- if os.path.exists( dependency_install_dir ):
- try:
- shutil.rmtree( dependency_install_dir )
- removed = True
- error_message = ''
- log.debug( "Removed tool dependency installation directory: %s" % str( dependency_install_dir ) )
- except Exception, e:
- removed = False
- error_message = "Error removing tool dependency installation directory %s: %s" % ( str( dependency_install_dir ), str( e ) )
- log.debug( error_message )
- else:
- removed = True
- error_message = ''
- return removed, error_message
def to_html_str( text ):
"""Translates the characters in text to an html string"""
translated = []
@@ -1183,65 +1150,6 @@
else:
translated_string = ''
return translated_string
-def update_existing_tool_dependency( app, repository, original_dependency_dict, new_dependencies_dict ):
- """
- Update an exsiting tool dependency whose definition was updated in a change set pulled by a Galaxy administrator when getting updates
- to an installed tool shed repository. The original_dependency_dict is a single tool dependency definition, an example of which is::
-
- {"name": "bwa",
- "readme": "\\nCompiling BWA requires zlib and libpthread to be present on your system.\\n ",
- "type": "package",
- "version": "0.6.2"}
-
- The new_dependencies_dict is the dictionary generated by the generate_tool_dependency_metadata method.
- """
- new_tool_dependency = None
- original_name = original_dependency_dict[ 'name' ]
- original_type = original_dependency_dict[ 'type' ]
- original_version = original_dependency_dict[ 'version' ]
- # Locate the appropriate tool_dependency associated with the repository.
- tool_dependency = None
- for tool_dependency in repository.tool_dependencies:
- if tool_dependency.name == original_name and tool_dependency.type == original_type and tool_dependency.version == original_version:
- break
- if tool_dependency and tool_dependency.can_update:
- dependency_install_dir = tool_dependency.installation_directory( app )
- removed_from_disk, error_message = remove_tool_dependency_installation_directory( dependency_install_dir )
- if removed_from_disk:
- sa_session = app.model.context.current
- new_dependency_name = None
- new_dependency_type = None
- new_dependency_version = None
- for new_dependency_key, new_dependency_val_dict in new_dependencies_dict.items():
- # Match on name only, hopefully this will be enough!
- if original_name == new_dependency_val_dict[ 'name' ]:
- new_dependency_name = new_dependency_val_dict[ 'name' ]
- new_dependency_type = new_dependency_val_dict[ 'type' ]
- new_dependency_version = new_dependency_val_dict[ 'version' ]
- break
- if new_dependency_name and new_dependency_type and new_dependency_version:
- # Update all attributes of the tool_dependency record in the database.
- log.debug( "Updating tool dependency '%s' with type '%s' and version '%s' to have new type '%s' and version '%s'." % \
- ( str( tool_dependency.name ),
- str( tool_dependency.type ),
- str( tool_dependency.version ),
- str( new_dependency_type ),
- str( new_dependency_version ) ) )
- tool_dependency.type = new_dependency_type
- tool_dependency.version = new_dependency_version
- tool_dependency.status = app.model.ToolDependency.installation_status.UNINSTALLED
- tool_dependency.error_message = None
- sa_session.add( tool_dependency )
- sa_session.flush()
- new_tool_dependency = tool_dependency
- else:
- # We have no new tool dependency definition based on a matching dependency name, so remove the existing tool dependency record
- # from the database.
- log.debug( "Deleting tool dependency with name '%s', type '%s' and version '%s' from the database since it is no longer defined." % \
- ( str( tool_dependency.name ), str( tool_dependency.type ), str( tool_dependency.version ) ) )
- sa_session.delete( tool_dependency )
- sa_session.flush()
- return new_tool_dependency
def update_in_shed_tool_config( app, repository ):
# A tool shed repository is being updated so change the shed_tool_conf file. Parse the config file to generate the entire list
# of config_elems instead of using the in-memory list.
diff -r 9e1d821b5c12f56bbfe1923ea1092608054c9d08 -r c7bc628577af7f57b5511b2cc8e1423d5faf31df lib/galaxy/util/shed_util_common.py
--- a/lib/galaxy/util/shed_util_common.py
+++ b/lib/galaxy/util/shed_util_common.py
@@ -884,6 +884,24 @@
relative_path_to_file.startswith( os.path.join( shed_config_dict.get( 'tool_path' ), relative_install_dir ) ):
relative_path_to_file = relative_path_to_file[ len( shed_config_dict.get( 'tool_path' ) ) + 1: ]
return relative_path_to_file
+def handle_existing_tool_dependencies_that_changed_in_update( app, repository, original_dependency_dict, new_dependency_dict ):
+ """
+ This method is called when a Galaxy admin is getting updates for an installed tool shed repository in order to cover the case where an
+ existing tool dependency was changed (e.g., the version of the dependency was changed) but the tool version for which it is a dependency
+ was not changed. In this case, we only want to determine if any of the dependency information defined in original_dependency_dict was
+ changed in new_dependency_dict. We don't care if new dependencies were added in new_dependency_dict since they will just be treated as
+ missing dependencies for the tool.
+ """
+ updated_tool_dependency_names = []
+ deleted_tool_dependency_names = []
+ for original_dependency_key, original_dependency_val_dict in original_dependency_dict.items():
+ if original_dependency_key not in new_dependency_dict:
+ updated_tool_dependency = update_existing_tool_dependency( app, repository, original_dependency_val_dict, new_dependency_dict )
+ if updated_tool_dependency:
+ updated_tool_dependency_names.append( updated_tool_dependency.name )
+ else:
+ deleted_tool_dependency_names.append( original_dependency_val_dict[ 'name' ] )
+ return updated_tool_dependency_names, deleted_tool_dependency_names
def handle_sample_files_and_load_tool_from_disk( trans, repo_files_dir, tool_config_filepath, work_dir ):
# Copy all sample files from disk to a temporary directory since the sample files may be in multiple directories.
message = ''
@@ -978,6 +996,21 @@
shutil.rmtree( dir )
except:
pass
+def remove_tool_dependency_installation_directory( dependency_install_dir ):
+ if os.path.exists( dependency_install_dir ):
+ try:
+ shutil.rmtree( dependency_install_dir )
+ removed = True
+ error_message = ''
+ log.debug( "Removed tool dependency installation directory: %s" % str( dependency_install_dir ) )
+ except Exception, e:
+ removed = False
+ error_message = "Error removing tool dependency installation directory %s: %s" % ( str( dependency_install_dir ), str( e ) )
+ log.debug( error_message )
+ else:
+ removed = True
+ error_message = ''
+ return removed, error_message
def reset_all_metadata_on_installed_repository( trans, id ):
"""Reset all metadata on a single tool shed repository installed into a Galaxy instance."""
repository = get_installed_tool_shed_repository( trans, id )
@@ -1198,6 +1231,65 @@
except:
file_name = fpath
return file_name
+def update_existing_tool_dependency( app, repository, original_dependency_dict, new_dependencies_dict ):
+ """
+ Update an exsiting tool dependency whose definition was updated in a change set pulled by a Galaxy administrator when getting updates
+ to an installed tool shed repository. The original_dependency_dict is a single tool dependency definition, an example of which is::
+
+ {"name": "bwa",
+ "readme": "\\nCompiling BWA requires zlib and libpthread to be present on your system.\\n ",
+ "type": "package",
+ "version": "0.6.2"}
+
+ The new_dependencies_dict is the dictionary generated by the generate_tool_dependency_metadata method.
+ """
+ new_tool_dependency = None
+ original_name = original_dependency_dict[ 'name' ]
+ original_type = original_dependency_dict[ 'type' ]
+ original_version = original_dependency_dict[ 'version' ]
+ # Locate the appropriate tool_dependency associated with the repository.
+ tool_dependency = None
+ for tool_dependency in repository.tool_dependencies:
+ if tool_dependency.name == original_name and tool_dependency.type == original_type and tool_dependency.version == original_version:
+ break
+ if tool_dependency and tool_dependency.can_update:
+ dependency_install_dir = tool_dependency.installation_directory( app )
+ removed_from_disk, error_message = remove_tool_dependency_installation_directory( dependency_install_dir )
+ if removed_from_disk:
+ sa_session = app.model.context.current
+ new_dependency_name = None
+ new_dependency_type = None
+ new_dependency_version = None
+ for new_dependency_key, new_dependency_val_dict in new_dependencies_dict.items():
+ # Match on name only, hopefully this will be enough!
+ if original_name == new_dependency_val_dict[ 'name' ]:
+ new_dependency_name = new_dependency_val_dict[ 'name' ]
+ new_dependency_type = new_dependency_val_dict[ 'type' ]
+ new_dependency_version = new_dependency_val_dict[ 'version' ]
+ break
+ if new_dependency_name and new_dependency_type and new_dependency_version:
+ # Update all attributes of the tool_dependency record in the database.
+ log.debug( "Updating tool dependency '%s' with type '%s' and version '%s' to have new type '%s' and version '%s'." % \
+ ( str( tool_dependency.name ),
+ str( tool_dependency.type ),
+ str( tool_dependency.version ),
+ str( new_dependency_type ),
+ str( new_dependency_version ) ) )
+ tool_dependency.type = new_dependency_type
+ tool_dependency.version = new_dependency_version
+ tool_dependency.status = app.model.ToolDependency.installation_status.UNINSTALLED
+ tool_dependency.error_message = None
+ sa_session.add( tool_dependency )
+ sa_session.flush()
+ new_tool_dependency = tool_dependency
+ else:
+ # We have no new tool dependency definition based on a matching dependency name, so remove the existing tool dependency record
+ # from the database.
+ log.debug( "Deleting tool dependency with name '%s', type '%s' and version '%s' from the database since it is no longer defined." % \
+ ( str( tool_dependency.name ), str( tool_dependency.type ), str( tool_dependency.version ) ) )
+ sa_session.delete( tool_dependency )
+ sa_session.flush()
+ return new_tool_dependency
def update_repository( repo, ctx_rev=None ):
"""
Update the cloned repository to changeset_revision. It is critical that the installed repository is updated to the desired
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.
1
0
commit/galaxy-central: dannon: Add pause icon from fontawesome to paused dataset display.
by Bitbucket 16 Nov '12
by Bitbucket 16 Nov '12
16 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/9e1d821b5c12/
changeset: 9e1d821b5c12
user: dannon
date: 2012-11-16 17:35:07
summary: Add pause icon from fontawesome to paused dataset display.
affected #: 2 files
diff -r 951ae6588d1630858ed55afcff4d426761a25268 -r 9e1d821b5c12f56bbfe1923ea1092608054c9d08 static/june_2007_style/base.less
--- a/static/june_2007_style/base.less
+++ b/static/june_2007_style/base.less
@@ -1640,6 +1640,12 @@
div.historyItem-paused {
// border-color: @history_paused_border;
background: @history_paused_bg;
+ .state-icon {
+ .ficon();
+ &:before {
+ content: "\f04c";
+ }
+ }
}
// Special case for showing the spinner but not changing the background
diff -r 951ae6588d1630858ed55afcff4d426761a25268 -r 9e1d821b5c12f56bbfe1923ea1092608054c9d08 static/june_2007_style/blue/base.css
--- a/static/june_2007_style/blue/base.css
+++ b/static/june_2007_style/blue/base.css
@@ -851,7 +851,7 @@
div.historyItem-upload{background:#ccccff;}div.historyItem-upload .state-icon{background-image:url(data_upload.gif);}
div.historyItem-queued{background:#eeeeee;}
div.historyItem-noPermission{filter:alpha(opacity=60);-moz-opacity:.60;opacity:.60;}
-div.historyItem-paused{background:#d9edf7;}
+div.historyItem-paused{background:#d9edf7;}div.historyItem-paused .state-icon{font-family:FontAwesome;font-weight:normal;font-style:normal;display:inline-block;}div.historyItem-paused .state-icon:before{content:"\f04c";}
div.historyItemTitleBar.spinner .state-icon{background:url(data_running.gif) 0 1px no-repeat !important;}
div.historyItemButtons{float:right;}
div.historyItemBody div{padding-top:2px;}
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.
1
0
commit/galaxy-central: dannon: Add paused dataset state for new history panel. Still needs icon and complete info text.
by Bitbucket 16 Nov '12
by Bitbucket 16 Nov '12
16 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/c3ac1fae1a29/
changeset: c3ac1fae1a29
user: dannon
date: 2012-11-16 15:40:20
summary: Add paused dataset state for new history panel. Still needs icon and complete info text.
affected #: 2 files
diff -r 4212a41ba5ee1f2a45f4d5f84c110808b167c87a -r c3ac1fae1a290c4012f2e7f3d7a87126622b0fc3 static/scripts/mvc/dataset/hda-base.js
--- a/static/scripts/mvc/dataset/hda-base.js
+++ b/static/scripts/mvc/dataset/hda-base.js
@@ -328,34 +328,37 @@
switch( this.model.get( 'state' ) ){
case HistoryDatasetAssociation.STATES.NOT_VIEWABLE :
this._render_body_not_viewable( body );
- break;
+ break;
case HistoryDatasetAssociation.STATES.UPLOAD :
- this._render_body_uploading( body );
- break;
+ this._render_body_uploading( body );
+ break;
+ case HistoryDatasetAssociation.STATES.PAUSED:
+ this._render_body_paused( body );
+ break;
case HistoryDatasetAssociation.STATES.QUEUED :
- this._render_body_queued( body );
- break;
+ this._render_body_queued( body );
+ break;
case HistoryDatasetAssociation.STATES.RUNNING :
- this._render_body_running( body );
- break;
+ this._render_body_running( body );
+ break;
case HistoryDatasetAssociation.STATES.ERROR :
- this._render_body_error( body );
- break;
+ this._render_body_error( body );
+ break;
case HistoryDatasetAssociation.STATES.DISCARDED :
- this._render_body_discarded( body );
- break;
+ this._render_body_discarded( body );
+ break;
case HistoryDatasetAssociation.STATES.SETTING_METADATA :
- this._render_body_setting_metadata( body );
- break;
+ this._render_body_setting_metadata( body );
+ break;
case HistoryDatasetAssociation.STATES.EMPTY :
- this._render_body_empty( body );
- break;
+ this._render_body_empty( body );
+ break;
case HistoryDatasetAssociation.STATES.FAILED_METADATA :
- this._render_body_failed_metadata( body );
- break;
+ this._render_body_failed_metadata( body );
+ break;
case HistoryDatasetAssociation.STATES.OK :
- this._render_body_ok( body );
- break;
+ this._render_body_ok( body );
+ break;
default:
//??: no body?
body.append( $( '<div>Error: unknown dataset state "' + state + '".</div>' ) );
@@ -392,6 +395,14 @@
parent.append( $( '<div>' + _l( 'Job is waiting to run' ) + '.</div>' ) );
parent.append( this._render_primaryActionButtons( this.defaultPrimaryActionButtonRenderers ));
},
+
+ /** Render an HDA whose job is paused.
+ * @param {jQuery} parent DOM to which to append this body
+ */
+ _render_body_paused: function( parent ){
+ parent.append( $( '<div>' + _l( 'Job is paused. Use the history menu to unpause' ) + '.</div>' ) );
+ parent.append( this._render_primaryActionButtons( this.defaultPrimaryActionButtonRenderers ));
+ },
/** Render an HDA whose job is running.
* @param {jQuery} parent DOM to which to append this body
diff -r 4212a41ba5ee1f2a45f4d5f84c110808b167c87a -r c3ac1fae1a290c4012f2e7f3d7a87126622b0fc3 static/scripts/mvc/dataset/hda-model.js
--- a/static/scripts/mvc/dataset/hda-model.js
+++ b/static/scripts/mvc/dataset/hda-model.js
@@ -164,6 +164,8 @@
UPLOAD : 'upload',
/** the job that will produce the dataset queued in the runner */
QUEUED : 'queued',
+ /** the job that will produce the dataset paused */
+ PAUSED : 'paused',
/** the job that will produce the dataset is running */
RUNNING : 'running',
/** metadata for the dataset is being discovered/set */
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.
1
0