galaxy-commits
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 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: Dave Bouvier: Upgrade Fabric egg to 1.7.0.
by commits-noreply@bitbucket.org 23 Sep '13
by commits-noreply@bitbucket.org 23 Sep '13
23 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/45abde58ef55/
Changeset: 45abde58ef55
User: Dave Bouvier
Date: 2013-09-23 17:04:52
Summary: Upgrade Fabric egg to 1.7.0.
Affected #: 1 file
diff -r 216c01ce66250f453425175d97094525b90f9108 -r 45abde58ef552a6838d9cbfbe2b00351bb7dd825 eggs.ini
--- a/eggs.ini
+++ b/eggs.ini
@@ -40,7 +40,7 @@
docutils = 0.7
drmaa = 0.4b3
elementtree = 1.2.6_20050316
-Fabric = 1.4.2
+Fabric = 1.7.0
GeneTrack = 2.0.0_beta_1
lrucache = 0.2
Mako = 0.4.1
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: Redirect to "manage" rather than "view" when creating a new repository in the too shed.
by commits-noreply@bitbucket.org 23 Sep '13
by commits-noreply@bitbucket.org 23 Sep '13
23 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/216c01ce6625/
Changeset: 216c01ce6625
User: greg
Date: 2013-09-23 16:10:05
Summary: Redirect to "manage" rather than "view" when creating a new repository in the too shed.
Affected #: 2 files
diff -r 66d484a18d198725ab5f388d4e538ac86d9f081b -r 216c01ce66250f453425175d97094525b90f9108 lib/galaxy/webapps/tool_shed/controllers/repository.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py
@@ -973,9 +973,9 @@
flush_needed = True
if flush_needed:
trans.sa_session.flush()
- message = "Repository '%s' has been created." % repository.name
+ message = "Repository <b>%s</b> has been created." % str( repository.name )
trans.response.send_redirect( web.url_for( controller='repository',
- action='view_repository',
+ action='manage_repository',
message=message,
id=trans.security.encode_id( repository.id ) ) )
repository_type_select_field = rt_util.build_repository_type_select_field( trans )
diff -r 66d484a18d198725ab5f388d4e538ac86d9f081b -r 216c01ce66250f453425175d97094525b90f9108 test/tool_shed/functional/test_0440_deleting_dependency_definitions.py
--- a/test/tool_shed/functional/test_0440_deleting_dependency_definitions.py
+++ b/test/tool_shed/functional/test_0440_deleting_dependency_definitions.py
@@ -74,7 +74,7 @@
description='Description of Deleted Dependency Definitions category for test 0440' )
self.logout()
self.login( email=common.test_user_1_email, username=common.test_user_1_name )
- strings_displayed = [ "Repository 'column_maker_0440' has been created" ]
+ strings_displayed = [ "Repository <b>column_maker_0440</b> has been created" ]
repository = self.get_or_create_repository( name=column_repository_name,
description=column_repository_description,
long_description=column_repository_long_description,
@@ -99,7 +99,7 @@
category = test_db_util.get_category_by_name( 'Test 0440 Deleted Dependency Definitions' )
self.logout()
self.login( email=common.test_user_1_email, username=common.test_user_1_name )
- strings_displayed = [ "Repository 'convert_chars_0440' has been created" ]
+ strings_displayed = [ "Repository <b>convert_chars_0440</b> has been created" ]
repository = self.get_or_create_repository( name=convert_repository_name,
description=convert_repository_description,
long_description=convert_repository_long_description,
@@ -182,7 +182,7 @@
category = test_db_util.get_category_by_name( 'Test 0440 Deleted Dependency Definitions' )
self.logout()
self.login( email=common.test_user_1_email, username=common.test_user_1_name )
- strings_displayed = [ "Repository 'bwa_package_0440' has been created" ]
+ strings_displayed = [ "Repository <b>bwa_package_0440</b> has been created" ]
repository = self.get_or_create_repository( name=bwa_package_repository_name,
description=bwa_package_repository_description,
long_description=bwa_package_repository_long_description,
@@ -208,7 +208,7 @@
category = test_db_util.get_category_by_name( 'Test 0440 Deleted Dependency Definitions' )
self.logout()
self.login( email=common.test_user_1_email, username=common.test_user_1_name )
- strings_displayed = [ "Repository 'bwa_base_0440' has been created" ]
+ strings_displayed = [ "Repository <b>bwa_base_0440</b> has been created" ]
repository = self.get_or_create_repository( name=bwa_base_repository_name,
description=bwa_base_repository_description,
long_description=bwa_base_repository_long_description,
@@ -291,7 +291,7 @@
category = test_db_util.get_category_by_name( 'Test 0440 Deleted Dependency Definitions' )
self.logout()
self.login( email=common.test_user_1_email, username=common.test_user_1_name )
- strings_displayed = [ "Repository 'bwa_tool_dependency_0440' has been created" ]
+ strings_displayed = [ "Repository <b>bwa_tool_dependency_0440</b> has been created" ]
repository = self.get_or_create_repository( name=bwa_tool_dependency_repository_name,
description=bwa_tool_dependency_repository_description,
long_description=bwa_tool_dependency_repository_long_description,
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/commits/b8b8a4e16d49/
Changeset: b8b8a4e16d49
User: jgoecks
Date: 2013-09-20 19:37:57
Summary: Modal dialog fixes: (a) scroll when necessary and (b) set maximum height so modal does not overflow viewing window.
Affected #: 6 files
diff -r cb95dad5175ec10cf191bddcaf2e1d115546dd7c -r b8b8a4e16d4923f2cad4e10f39acf8d9131c9471 static/scripts/galaxy.panels.js
--- a/static/scripts/galaxy.panels.js
+++ b/static/scripts/galaxy.panels.js
@@ -168,16 +168,17 @@
this.$overlay.show();
this.$dialog.show();
this.$overlay.addClass("in");
- // Fix min-width so that modal cannot shrink considerably if
- // new content is loaded.
+ // Fix min-width so that modal cannot shrink considerably if new content is loaded.
this.$body.css( "min-width", this.$body.width() );
- // Set max-height so that modal does not exceed window size.
- // FIXME: this could perhaps be handled better using a container for the modal
- // header-body-footer and setting max-height for the container.
+ // Set max-height so that modal does not exceed window size and is in middle of page.
+ // TODO: this could perhaps be handled better using CSS.
this.$body.css( "max-height",
- // 2* to provide buffer between bottom of modal and bottom of page.
- $(window).height() - 2 * this.$dialog.offset().top -
- this.$footer.outerHeight() - this.$header.outerHeight());
+ $(window).height() -
+ this.$footer.outerHeight() -
+ this.$header.outerHeight() -
+ parseInt( this.$dialog.css( "padding-top" ), 10 ) -
+ parseInt( this.$dialog.css( "padding-bottom" ), 10 )
+ );
}
// Callback on init
if ( callback ) {
diff -r cb95dad5175ec10cf191bddcaf2e1d115546dd7c -r b8b8a4e16d4923f2cad4e10f39acf8d9131c9471 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -756,6 +756,7 @@
.btn.active,.btn:active{color:inherit}
.dropdown-menu{max-width:auto}
input[type="checkbox"],input[type="radio"]{margin-left:0.5ex;margin-right:0.5ex}
+.modal-body{overflow:auto}
.nav-tabs{margin-bottom:15px}
a{text-decoration:underline}
label{font-weight:normal}
diff -r cb95dad5175ec10cf191bddcaf2e1d115546dd7c -r b8b8a4e16d4923f2cad4e10f39acf8d9131c9471 static/style/blue/sprite-fugue.png
Binary file static/style/blue/sprite-fugue.png has changed
diff -r cb95dad5175ec10cf191bddcaf2e1d115546dd7c -r b8b8a4e16d4923f2cad4e10f39acf8d9131c9471 static/style/blue/sprite-history-buttons.png
Binary file static/style/blue/sprite-history-buttons.png has changed
diff -r cb95dad5175ec10cf191bddcaf2e1d115546dd7c -r b8b8a4e16d4923f2cad4e10f39acf8d9131c9471 static/style/blue/sprite-history-states.png
Binary file static/style/blue/sprite-history-states.png has changed
diff -r cb95dad5175ec10cf191bddcaf2e1d115546dd7c -r b8b8a4e16d4923f2cad4e10f39acf8d9131c9471 static/style/src/less/galaxy_bootstrap/overrides.less
--- a/static/style/src/less/galaxy_bootstrap/overrides.less
+++ b/static/style/src/less/galaxy_bootstrap/overrides.less
@@ -32,6 +32,9 @@
// Modal -- wider by default, scroll like Trello
/*
+
+NOTE: these styles do not currently work.
+
.modal {
position: absolute;
top: 50px;
@@ -54,6 +57,11 @@
}
*/
+// Scroll modal body.
+.modal-body {
+ overflow: auto;
+}
+
// Tabs -- border color is hardcoded in navs.less, change to @btnBorder here
.nav-tabs {
https://bitbucket.org/galaxy/galaxy-central/commits/23abd7b603c8/
Changeset: 23abd7b603c8
User: jgoecks
Date: 2013-09-20 20:01:49
Summary: Popup menu implementation: (a) use trigger rather than reimplementing anchor functionality and (b) set URLs for menu options for clarity and utility.
Affected #: 1 file
diff -r b8b8a4e16d4923f2cad4e10f39acf8d9131c9471 -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 static/scripts/galaxy.base.js
--- a/static/scripts/galaxy.base.js
+++ b/static/scripts/galaxy.base.js
@@ -66,7 +66,10 @@
};
/**
- * Sets up popupmenu rendering and binds options functions to the appropriate links
+ * Sets up popupmenu rendering and binds options functions to the appropriate links.
+ * initial_options is a dict with text describing the option pointing to either (a) a
+ * function to perform; or (b) another dict with two required keys, 'url' and 'action' (the
+ * function to perform. (b) is useful for exposing the underlying URL of the option.
*/
function make_popupmenu(button_element, initial_options) {
/* Use the $.data feature to store options with the link element.
@@ -92,7 +95,9 @@
}
$.each( options, function( k, v ) {
if (v) {
- menu_element.append( $("<li></li>").append( $("<a href='#'></a>").html(k).click(v) ) );
+ // Action can be either an anonymous function and a mapped dict.
+ var action = v.action || v;
+ menu_element.append( $("<li></li>").append( $("<a>").attr("href", v.url).html(k).click(action) ) );
} else {
menu_element.append( $("<li></li>").addClass( "head" ).append( $("<a href='#'></a>").html(k) ) );
}
@@ -164,43 +169,24 @@
options[ link.text() ] = null;
} else {
- options[ link.text() ] = function() {
+ options[ link.text() ] = {
+ url: href,
+ action: function() {
- // if theres confirm text, send the dialog
- if ( !confirmtext || confirm( confirmtext ) ) {
- var f;
- // relocate the center panel
- if ( target === "_parent" ) {
- window.parent.location = href;
-
- // relocate the entire window
- } else if ( target === "_top" ) {
- window.top.location = href;
-
- // Http request target is a window named demolocal on the local box
- } else if ( target === "demo" ) {
- if ( f === undefined || f.closed ) {
- f = window.open( href,target );
- f.creator = self;
+ // if theres confirm text, send the dialog
+ if ( !confirmtext || confirm( confirmtext ) ) {
+ var f;
+ // Http request target is a window named demolocal on the local box
+ if ( target === "demo" ) {
+ if ( f === undefined || f.closed ) {
+ f = window.open( href,target );
+ f.creator = self;
+ }
+
}
-
- // this panel or other, valid panels
- } else {
- // it may be that the button and menu href are not in the same frame:
- // allow certain frame names to be used as a target
- var other_valid_targets = [
- 'galaxy_main'
- // following are blocked until needed
- //'galaxy_tools',
- //'galaxy_history'
- ];
- if( ( target && ( target in window )
- && ( other_valid_targets.indexOf( target ) !== -1 ) ) ){
- window[ target ].location = href;
-
- // relocate this panel
- } else {
- window.location = href;
+ // For all other links, do the default action.
+ else {
+ link.trigger('click');
}
}
}
https://bitbucket.org/galaxy/galaxy-central/commits/66d484a18d19/
Changeset: 66d484a18d19
User: jgoecks
Date: 2013-09-21 04:50:51
Summary: Automated merge.
Affected #: 34 files
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -209,6 +209,7 @@
if self.nginx_upload_store:
self.nginx_upload_store = os.path.abspath( self.nginx_upload_store )
self.object_store = kwargs.get( 'object_store', 'disk' )
+ self.object_store_check_old_style = string_as_bool( kwargs.get( 'object_store_check_old_style', False ) )
self.object_store_cache_path = resolve_path( kwargs.get( "object_store_cache_path", "database/object_store_cache" ), self.root )
# Handle AWS-specific config options for backward compatibility
if kwargs.get( 'aws_access_key', None) is not None:
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -25,7 +25,7 @@
from galaxy.datatypes.metadata import MetadataCollection
from galaxy.model.item_attrs import Dictifiable, UsesAnnotations
from galaxy.security import get_permitted_actions
-from galaxy.util import is_multi_byte, nice_size, Params, restore_text, send_mail
+from galaxy.util import asbool, is_multi_byte, nice_size, Params, restore_text, send_mail
from galaxy.util.bunch import Bunch
from galaxy.util.hash_util import new_secure_hash
from galaxy.web.framework.helpers import to_unicode
@@ -34,6 +34,7 @@
WorkflowMappingField)
from sqlalchemy.orm import object_session
from sqlalchemy.sql.expression import func
+from tool_shed.util import common_util
log = logging.getLogger( __name__ )
@@ -3463,7 +3464,28 @@
@property
def has_repository_dependencies( self ):
if self.metadata:
- return 'repository_dependencies' in self.metadata
+ repository_dependencies_dict = self.metadata.get( 'repository_dependencies', {} )
+ repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ # [["http://localhost:9009", "package_libgtextutils_0_6", "test", "e2003cbf18cd", "True", "True"]]
+ for rd_tup in repository_dependencies:
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
+ if not asbool( only_if_compiling_contained_td ):
+ return True
+ return False
+
+ @property
+ def has_repository_dependencies_only_if_compiling_contained_td( self ):
+ if self.metadata:
+ repository_dependencies_dict = self.metadata.get( 'repository_dependencies', {} )
+ repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ # [["http://localhost:9009", "package_libgtextutils_0_6", "test", "e2003cbf18cd", "True", "True"]]
+ for rd_tup in repository_dependencies:
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
+ if not asbool( only_if_compiling_contained_td ):
+ return False
+ return True
return False
@property
@@ -3695,10 +3717,14 @@
@property
def tuples_of_repository_dependencies_needed_for_compiling_td( self ):
- """Return this repository's repository dependencies that are necessary only for compiling this repository's tool dependencies."""
+ """
+ Return tuples defining this repository's repository dependencies that are necessary only for compiling this repository's tool
+ dependencies.
+ """
rd_tups_of_repositories_needed_for_compiling_td = []
- if self.has_repository_dependencies:
- rd_tups = self.metadata[ 'repository_dependencies' ][ 'repository_dependencies' ]
+ if self.metadata:
+ repository_dependencies = self.metadata.get( 'repository_dependencies', None )
+ rd_tups = repository_dependencies[ 'repository_dependencies' ]
for rd_tup in rd_tups:
if len( rd_tup ) == 6:
tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = rd_tup
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -198,6 +198,7 @@
super(DiskObjectStore, self).__init__(config, file_path=file_path, extra_dirs=extra_dirs)
self.file_path = file_path or config.file_path
self.config = config
+ self.check_old_style = config.object_store_check_old_style
self.extra_dirs['job_work'] = config.job_working_directory
self.extra_dirs['temp'] = config.new_file_path
if extra_dirs is not None:
@@ -264,14 +265,13 @@
return os.path.abspath(path)
def exists(self, obj, **kwargs):
- path = self._construct_path(obj, old_style=True, **kwargs)
- # For backward compatibility, check root path first; otherwise, construct
- # and check hashed path
- if os.path.exists(path):
- return True
- else:
- path = self._construct_path(obj, **kwargs)
- return os.path.exists(path)
+ if self.check_old_style:
+ path = self._construct_path(obj, old_style=True, **kwargs)
+ # For backward compatibility, check root path first; otherwise, construct
+ # and check hashed path
+ if os.path.exists(path):
+ return True
+ return os.path.exists(self._construct_path(obj, **kwargs))
def create(self, obj, **kwargs):
if not self.exists(obj, **kwargs):
@@ -320,13 +320,13 @@
return content
def get_filename(self, obj, **kwargs):
- path = self._construct_path(obj, old_style=True, **kwargs)
- # For backward compatibility, check root path first; otherwise, construct
- # and return hashed path
- if os.path.exists(path):
- return path
- else:
- return self._construct_path(obj, **kwargs)
+ if self.check_old_style:
+ path = self._construct_path(obj, old_style=True, **kwargs)
+ # For backward compatibility, check root path first; otherwise, construct
+ # and return hashed path
+ if os.path.exists(path):
+ return path
+ return self._construct_path(obj, **kwargs)
def update_from_file(self, obj, file_name=None, create=False, **kwargs):
""" `create` parameter is not used in this implementation """
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -587,8 +587,10 @@
hda_dict[ 'api_type' ] = "file"
# Add additional attributes that depend on trans can hence must be added here rather than at the model level.
-
- #NOTE: access is an expensive operation - removing it and adding the precondition of access is already checked
+ can_access_hda = trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), hda.dataset )
+ can_access_hda = ( trans.user_is_admin() or can_access_hda )
+ if not can_access_hda:
+ return self.get_inaccessible_hda_dict( trans, hda )
hda_dict[ 'accessible' ] = True
# ---- return here if deleted AND purged OR can't access
@@ -634,6 +636,18 @@
return trans.security.encode_dict_ids( hda_dict )
+ def get_inaccessible_hda_dict( self, trans, hda ):
+ return trans.security.encode_dict_ids({
+ 'id' : hda.id,
+ 'history_id': hda.history.id,
+ 'hid' : hda.hid,
+ 'name' : hda.name,
+ 'state' : hda.state,
+ 'deleted' : hda.deleted,
+ 'visible' : hda.visible,
+ 'accessible': False
+ })
+
def get_hda_dict_with_error( self, trans, hda, error_msg='' ):
return trans.security.encode_dict_ids({
'id' : hda.id,
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/galaxy/web/framework/helpers/grids.py
--- a/lib/galaxy/web/framework/helpers/grids.py
+++ b/lib/galaxy/web/framework/helpers/grids.py
@@ -198,7 +198,10 @@
if page_num == 0:
# Show all rows in page.
total_num_rows = query.count()
+ # persistant page='all'
page_num = 1
+ #page_num = 'all'
+ #extra_url_args['page'] = page_num
num_pages = 1
else:
# Show a limited number of rows. Before modifying query, get the total number of rows that query
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/galaxy/webapps/galaxy/api/history_contents.py
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -235,8 +235,15 @@
# get file destination
file_destination = dataset.get_file_name()
+ # check if the directory exists
+ dn = os.path.dirname(file_destination)
+ if not os.path.exists(dn):
+ os.makedirs(dn)
+
+ # get file and directory names
+ fn = os.path.basename(content.filename)
+
# save file locally
- fn = os.path.basename(content.filename)
open(file_destination, 'wb').write(content.file.read())
# log
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -812,7 +812,7 @@
status = kwd.get( 'status', 'done' )
shed_tool_conf = kwd.get( 'shed_tool_conf', None )
tool_shed_url = kwd[ 'tool_shed_url' ]
- # Handle repository dependencies.
+ # Handle repository dependencies, which do not include those that are required only for compiling a dependent repository's tool dependencies.
has_repository_dependencies = util.string_as_bool( kwd.get( 'has_repository_dependencies', False ) )
install_repository_dependencies = kwd.get( 'install_repository_dependencies', '' )
# Every repository will be installed into the same tool panel section or all will be installed outside of any sections.
@@ -1061,7 +1061,7 @@
repository_clone_url,
metadata,
trans.model.ToolShedRepository.installation_status.NEW,
- tool_shed_repository.installed_changeset_revision,
+ tool_shed_repository.changeset_revision,
tool_shed_repository.owner,
tool_shed_repository.dist_to_shed )
ctx_rev = suc.get_ctx_rev( trans.app,
@@ -1320,7 +1320,6 @@
missing_tool_dependencies = dependencies_for_repository_dict.get( 'missing_tool_dependencies', None )
repository_name = dependencies_for_repository_dict.get( 'name', None )
repository_owner = dependencies_for_repository_dict.get( 'repository_owner', None )
-
if installed_repository_dependencies or missing_repository_dependencies:
has_repository_dependencies = True
else:
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/galaxy/webapps/galaxy/controllers/history.py
--- a/lib/galaxy/webapps/galaxy/controllers/history.py
+++ b/lib/galaxy/webapps/galaxy/controllers/history.py
@@ -309,7 +309,6 @@
# If deleting the current history, make a new current.
if history == trans.get_history():
deleted_current = True
- trans.get_or_create_default_history()
trans.log_event( "History (%s) marked as deleted" % history.name )
n_deleted += 1
if purge and trans.app.config.allow_user_dataset_purge:
@@ -339,6 +338,8 @@
part += " but the datasets were not removed from disk because that feature is not enabled in this Galaxy instance"
message_parts.append( "%s. " % part )
if deleted_current:
+ #note: this needs to come after commits above or will use an empty history that was deleted above
+ trans.get_or_create_default_history()
message_parts.append( "Your active history was deleted, a new empty history is now active. " )
status = INFO
return ( status, " ".join( message_parts ) )
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/galaxy/webapps/tool_shed/api/repositories.py
--- a/lib/galaxy/webapps/tool_shed/api/repositories.py
+++ b/lib/galaxy/webapps/tool_shed/api/repositories.py
@@ -73,6 +73,7 @@
"changeset_revision": "3a08cc21466f",
"downloadable": true,
"has_repository_dependencies": false,
+ "has_repository_dependencies_only_if_compiling_contained_td": false,
"id": "f9cad7b01a472135",
"includes_datatypes": false,
"includes_tool_dependencies": false,
@@ -125,7 +126,8 @@
action='show',
id=encoded_repository_metadata_id )
# Get the repo_info_dict for installing the repository.
- repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, has_repository_dependencies = \
+ repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, \
+ has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \
repository_util.get_repo_info_dict( trans, encoded_repository_id, changeset_revision )
return repository_dict, repository_metadata_dict, repo_info_dict
else:
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/galaxy/webapps/tool_shed/controllers/repository.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py
@@ -1343,32 +1343,36 @@
def get_changeset_revision_and_ctx_rev( self, trans, **kwd ):
"""Handle a request from a local Galaxy instance to retrieve the changeset revision hash to which an installed repository can be updated."""
def has_galaxy_utilities( repository_metadata ):
- includes_data_managers = False
- includes_datatypes = False
- includes_tools = False
- includes_tools_for_display_in_tool_panel = False
- has_repository_dependencies = False
- includes_tool_dependencies = False
- includes_workflows = False
+ has_galaxy_utilities_dict = dict( includes_data_managers=False,
+ includes_datatypes=False,
+ includes_tools=False,
+ includes_tools_for_display_in_tool_panel=False,
+ has_repository_dependencies=False,
+ has_repository_dependencies_only_if_compiling_contained_td=False,
+ includes_tool_dependencies=False,
+ includes_workflows=False )
if repository_metadata:
includes_tools_for_display_in_tool_panel = repository_metadata.includes_tools_for_display_in_tool_panel
metadata = repository_metadata.metadata
if metadata:
if 'data_manager' in metadata:
- includes_data_managers = True
+ has_galaxy_utilities_dict[ 'includes_data_managers' ] = True
if 'datatypes' in metadata:
- includes_datatypes = True
+ has_galaxy_utilities_dict[ 'includes_datatypes' ] = True
if 'tools' in metadata:
- includes_tools = True
+ has_galaxy_utilities_dict[ 'includes_tools' ] = True
if 'tool_dependencies' in metadata:
- includes_tool_dependencies = True
- if 'repository_dependencies' in metadata:
- has_repository_dependencies = True
+ has_galaxy_utilities_dict[ 'includes_tool_dependencies' ] = True
+ repository_dependencies_dict = metadata.get( 'repository_dependencies', {} )
+ repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \
+ suc.get_repository_dependency_types( repository_dependencies )
+ has_galaxy_utilities_dict[ 'has_repository_dependencies' ] = has_repository_dependencies
+ has_galaxy_utilities_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = \
+ has_repository_dependencies_only_if_compiling_contained_td
if 'workflows' in metadata:
- includes_workflows = True
- return includes_data_managers, includes_datatypes, includes_tools, includes_tools_for_display_in_tool_panel, includes_tool_dependencies, has_repository_dependencies, includes_workflows
- message = kwd.get( 'message', '' )
- status = kwd.get( 'status', 'done' )
+ has_galaxy_utilities_dict[ 'includes_workflows' ] = True
+ return has_galaxy_utilities_dict
name = kwd.get( 'name', None )
owner = kwd.get( 'owner', None )
changeset_revision = kwd.get( 'changeset_revision', None )
@@ -1376,8 +1380,15 @@
repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans,
trans.security.encode_id( repository.id ),
changeset_revision )
- includes_data_managers, includes_datatypes, includes_tools, includes_tools_for_display_in_tool_panel, includes_tool_dependencies, has_repository_dependencies, includes_workflows = \
- has_galaxy_utilities( repository_metadata )
+ has_galaxy_utilities_dict = has_galaxy_utilities( repository_metadata )
+ includes_data_managers = has_galaxy_utilities_dict[ 'includes_data_managers' ]
+ includes_datatypes = has_galaxy_utilities_dict[ 'includes_datatypes' ]
+ includes_tools = has_galaxy_utilities_dict[ 'includes_tools' ]
+ includes_tools_for_display_in_tool_panel = has_galaxy_utilities_dict[ 'includes_tools_for_display_in_tool_panel' ]
+ includes_tool_dependencies = has_galaxy_utilities_dict[ 'includes_tool_dependencies' ]
+ has_repository_dependencies = has_galaxy_utilities_dict[ 'has_repository_dependencies' ]
+ has_repository_dependencies_only_if_compiling_contained_td = has_galaxy_utilities_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ]
+ includes_workflows = has_galaxy_utilities_dict[ 'includes_workflows' ]
repo_dir = repository.repo_path( trans.app )
repo = hg.repository( suc.get_configured_ui(), repo_dir )
# Default to the received changeset revision and ctx_rev.
@@ -1392,6 +1403,7 @@
includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
includes_tool_dependencies=includes_tool_dependencies,
has_repository_dependencies=has_repository_dependencies,
+ has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td,
includes_workflows=includes_workflows )
if changeset_revision == repository.tip( trans.app ):
# If changeset_revision is the repository tip, there are no additional updates.
@@ -1407,6 +1419,7 @@
for changeset in repo.changelog:
includes_tools = False
has_repository_dependencies = False
+ has_repository_dependencies_only_if_compiling_contained_td = False
changeset_hash = str( repo.changectx( changeset ) )
ctx = suc.get_changectx_for_changeset( repo, changeset_hash )
if update_to_changeset_hash:
@@ -1414,8 +1427,15 @@
trans.security.encode_id( repository.id ),
changeset_hash )
if update_to_repository_metadata:
- includes_data_managers, includes_datatypes, includes_tools, includes_tools_for_display_in_tool_panel, includes_tool_dependencies, has_repository_dependencies, includes_workflows = \
- has_galaxy_utilities( update_to_repository_metadata )
+ has_galaxy_utilities_dict = has_galaxy_utilities( repository_metadata )
+ includes_data_managers = has_galaxy_utilities_dict[ 'includes_data_managers' ]
+ includes_datatypes = has_galaxy_utilities_dict[ 'includes_datatypes' ]
+ includes_tools = has_galaxy_utilities_dict[ 'includes_tools' ]
+ includes_tools_for_display_in_tool_panel = has_galaxy_utilities_dict[ 'includes_tools_for_display_in_tool_panel' ]
+ includes_tool_dependencies = has_galaxy_utilities_dict[ 'includes_tool_dependencies' ]
+ has_repository_dependencies = has_galaxy_utilities_dict[ 'has_repository_dependencies' ]
+ has_repository_dependencies_only_if_compiling_contained_td = has_galaxy_utilities_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ]
+ includes_workflows = has_galaxy_utilities_dict[ 'includes_workflows' ]
# We found a RepositoryMetadata record.
if changeset_hash == repository.tip( trans.app ):
# The current ctx is the repository tip, so use it.
@@ -1435,6 +1455,7 @@
update_dict[ 'includes_tool_dependencies' ] = includes_tool_dependencies
update_dict[ 'includes_workflows' ] = includes_workflows
update_dict[ 'has_repository_dependencies' ] = has_repository_dependencies
+ update_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = has_repository_dependencies_only_if_compiling_contained_td
update_dict[ 'changeset_revision' ] = str( latest_changeset_revision )
update_dict[ 'ctx_rev' ] = str( update_to_ctx.rev() )
return encoding_util.tool_shed_encode( update_dict )
@@ -1611,14 +1632,18 @@
includes_tools = False
includes_tools_for_display_in_tool_panel = False
has_repository_dependencies = False
+ has_repository_dependencies_only_if_compiling_contained_td = False
includes_tool_dependencies = False
repo_info_dicts = []
for tup in zip( util.listify( repository_ids ), util.listify( changeset_revisions ) ):
repository_id, changeset_revision = tup
- repo_info_dict, cur_includes_tools, cur_includes_tool_dependencies, cur_includes_tools_for_display_in_tool_panel, cur_has_repository_dependencies = \
+ repo_info_dict, cur_includes_tools, cur_includes_tool_dependencies, cur_includes_tools_for_display_in_tool_panel, \
+ cur_has_repository_dependencies, cur_has_repository_dependencies_only_if_compiling_contained_td = \
repository_util.get_repo_info_dict( trans, repository_id, changeset_revision )
if cur_has_repository_dependencies and not has_repository_dependencies:
has_repository_dependencies = True
+ if cur_has_repository_dependencies_only_if_compiling_contained_td and not has_repository_dependencies_only_if_compiling_contained_td:
+ has_repository_dependencies_only_if_compiling_contained_td = True
if cur_includes_tools and not includes_tools:
includes_tools = True
if cur_includes_tool_dependencies and not includes_tool_dependencies:
@@ -1629,6 +1654,7 @@
return dict( includes_tools=includes_tools,
includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
has_repository_dependencies=has_repository_dependencies,
+ has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td,
includes_tool_dependencies=includes_tool_dependencies,
repo_info_dicts=repo_info_dicts )
@@ -1708,7 +1734,9 @@
tool_version_dicts = []
for changeset in repo.changelog:
current_changeset_revision = str( repo.changectx( changeset ) )
- repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, trans.security.encode_id( repository.id ), current_changeset_revision )
+ repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans,
+ trans.security.encode_id( repository.id ),
+ current_changeset_revision )
if repository_metadata and repository_metadata.tool_versions:
tool_version_dicts.append( repository_metadata.tool_versions )
if current_changeset_revision == changeset_revision:
@@ -1766,22 +1794,30 @@
includes_workflows = True
readme_files_dict = readme_util.build_readme_files_dict( metadata )
# See if the repo_info_dict was populated with repository_dependencies or tool_dependencies.
+ has_repository_dependencies = False
+ has_repository_dependencies_only_if_compiling_contained_td = False
+ includes_tool_dependencies = False
for name, repo_info_tuple in repo_info_dict.items():
- description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
- suc.get_repo_info_tuple_contents( repo_info_tuple )
- if repository_dependencies:
- has_repository_dependencies = True
- else:
- has_repository_dependencies = False
- if tool_dependencies:
- includes_tool_dependencies = True
- else:
- includes_tool_dependencies = False
+ if not has_repository_dependencies or not has_repository_dependencies_only_if_compiling_contained_td or not includes_tool_dependencies:
+ description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
+ suc.get_repo_info_tuple_contents( repo_info_tuple )
+ for rd_key, rd_tups in repository_dependencies.items():
+ if rd_key in [ 'root_key', 'description' ]:
+ continue
+ curr_has_repository_dependencies, curr_has_repository_dependencies_only_if_compiling_contained_td = \
+ suc.get_repository_dependency_types( rd_tups )
+ if curr_has_repository_dependencies and not has_repository_dependencies:
+ has_repository_dependencies = True
+ if curr_has_repository_dependencies_only_if_compiling_contained_td and not has_repository_dependencies_only_if_compiling_contained_td:
+ has_repository_dependencies_only_if_compiling_contained_td = True
+ if tool_dependencies and not includes_tool_dependencies:
+ includes_tool_dependencies = True
return dict( includes_data_managers=includes_data_managers,
includes_datatypes=includes_datatypes,
includes_tools=includes_tools,
includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
has_repository_dependencies=has_repository_dependencies,
+ has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td,
includes_tool_dependencies=includes_tool_dependencies,
includes_workflows=includes_workflows,
readme_files_dict=readme_files_dict,
@@ -2434,7 +2470,9 @@
try:
commands.remove( repo.ui, repo, selected_file, force=True )
except Exception, e:
- log.debug( "Error removing files using the mercurial API, so trying a different approach, the error was: %s" % str( e ))
+ log.debug( "Error removing the following file using the mercurial API:\n %s" % str( selected_file ) )
+ log.debug( "The error was: %s" % str( e ))
+ log.debug( "Attempting to remove the file using a different approach." )
relative_selected_file = selected_file.split( 'repo_%d' % repository.id )[1].lstrip( '/' )
repo.dirstate.remove( relative_selected_file )
repo.dirstate.write()
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/galaxy/webapps/tool_shed/model/__init__.py
--- a/lib/galaxy/webapps/tool_shed/model/__init__.py
+++ b/lib/galaxy/webapps/tool_shed/model/__init__.py
@@ -253,6 +253,7 @@
self.time_last_tested = time_last_tested
self.tool_test_results = tool_test_results
self.has_repository_dependencies = has_repository_dependencies
+ # We don't consider the special case has_repository_dependencies_only_if_compiling_contained_td here.
self.includes_datatypes = includes_datatypes
self.includes_tools = includes_tools
self.includes_tool_dependencies = includes_tool_dependencies
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/tool_shed/galaxy_install/repository_util.py
--- a/lib/tool_shed/galaxy_install/repository_util.py
+++ b/lib/tool_shed/galaxy_install/repository_util.py
@@ -234,10 +234,10 @@
else:
includes_tools = False
includes_tools_for_display_in_tool_panel = repository_metadata.includes_tools_for_display_in_tool_panel
- if 'repository_dependencies' in metadata:
- has_repository_dependencies = True
- else:
- has_repository_dependencies = False
+ repository_dependencies_dict = metadata.get( 'repository_dependencies', {} )
+ repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \
+ suc.get_repository_dependency_types( repository_dependencies )
if 'tool_dependencies' in metadata:
includes_tool_dependencies = True
else:
@@ -246,6 +246,7 @@
# Here's where we may have to handle enhancements to the callers. See above comment.
includes_tools = False
has_repository_dependencies = False
+ has_repository_dependencies_only_if_compiling_contained_td = False
includes_tool_dependencies = False
includes_tools_for_display_in_tool_panel = False
ctx = suc.get_changectx_for_changeset( repo, changeset_revision )
@@ -259,7 +260,8 @@
repository_metadata=repository_metadata,
tool_dependencies=None,
repository_dependencies=None )
- return repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, has_repository_dependencies
+ return repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, \
+ has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td
def get_repository_components_for_installation( encoded_tsr_id, encoded_tsr_ids, repo_info_dicts, tool_panel_section_keys ):
"""
@@ -311,6 +313,7 @@
includes_tool_dependencies = update_dict.get( 'includes_tool_dependencies', False )
includes_workflows = update_dict.get( 'includes_workflows', False )
has_repository_dependencies = update_dict.get( 'has_repository_dependencies', False )
+ has_repository_dependencies_only_if_compiling_contained_td = update_dict.get( 'has_repository_dependencies_only_if_compiling_contained_td', False )
changeset_revision = update_dict.get( 'changeset_revision', None )
ctx_rev = update_dict.get( 'ctx_rev', None )
changeset_revision_dict[ 'includes_data_managers' ] = includes_data_managers
@@ -320,6 +323,7 @@
changeset_revision_dict[ 'includes_tool_dependencies' ] = includes_tool_dependencies
changeset_revision_dict[ 'includes_workflows' ] = includes_workflows
changeset_revision_dict[ 'has_repository_dependencies' ] = has_repository_dependencies
+ changeset_revision_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = has_repository_dependencies_only_if_compiling_contained_td
changeset_revision_dict[ 'changeset_revision' ] = changeset_revision
changeset_revision_dict[ 'ctx_rev' ] = ctx_rev
except Exception, e:
@@ -331,6 +335,7 @@
changeset_revision_dict[ 'includes_tool_dependencies' ] = False
changeset_revision_dict[ 'includes_workflows' ] = False
changeset_revision_dict[ 'has_repository_dependencies' ] = False
+ changeset_revision_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = False
changeset_revision_dict[ 'changeset_revision' ] = None
changeset_revision_dict[ 'ctx_rev' ] = None
return changeset_revision_dict
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
@@ -394,7 +394,7 @@
if not binary_installed:
print 'Binary installation did not occur, so proceeding with install and compile recipe.'
# Make sure to reset for installation if attempt at binary installation resulted in an error.
- if tool_dependency.status != app.model.ToolDependency.installation_status.NEW:
+ if tool_dependency.status != app.model.ToolDependency.installation_status.NEVER_INSTALLED:
removed, error_message = tool_dependency_util.remove_tool_dependency( app, tool_dependency )
install_via_fabric( app,
tool_dependency,
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/tool_shed/util/common_install_util.py
--- a/lib/tool_shed/util/common_install_util.py
+++ b/lib/tool_shed/util/common_install_util.py
@@ -12,6 +12,7 @@
from tool_shed.util import encoding_util
from tool_shed.util import data_manager_util
from tool_shed.util import datatype_util
+from tool_shed.util import tool_dependency_util
from tool_shed.util import tool_util
from tool_shed.util import xml_util
from tool_shed.galaxy_install.tool_dependencies.install_util import install_package
@@ -69,16 +70,28 @@
Return dictionaries containing the sets of installed and missing tool dependencies and repository dependencies associated with the repository defined
by the received repo_info_dict.
"""
+ repository = None
+ installed_rd = {}
+ installed_td = {}
+ missing_rd = {}
+ missing_td = {}
name = repo_info_dict.keys()[ 0 ]
repo_info_tuple = repo_info_dict[ name ]
- description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td = \
+ description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
suc.get_repo_info_tuple_contents( repo_info_tuple )
+ if tool_dependencies:
+ if not includes_tool_dependencies:
+ includes_tool_dependencies = True
+ # Inspect the tool_dependencies dictionary to separate the installed and missing tool dependencies. We don't add to installed_td
+ # and missing_td here because at this point they are empty.
+ installed_td, missing_td = get_installed_and_missing_tool_dependencies( trans, tool_shed_url, tool_dependencies )
+ # In cases where a repository dependency is required only for compiling a dependent repository's tool dependency, the value of
+ # repository_dependencies will be an empty dictionary here.
if repository_dependencies:
# We have a repository with one or more defined repository dependencies.
missing_td = {}
- # Handle the scenario where a repository was installed, then uninstalled and an error occurred during the re-installation process.
- # In this case, a record for the repository will exist in the database with the status of 'New'.
- repository = suc.get_repository_for_dependency_relationship( trans.app, tool_shed_url, name, repository_owner, changeset_revision )
+ if not repository:
+ repository = suc.get_repository_for_dependency_relationship( trans.app, tool_shed_url, name, repository_owner, changeset_revision )
if repository and repository.metadata:
installed_rd, missing_rd = get_installed_and_missing_repository_dependencies( trans, repository )
else:
@@ -86,73 +99,70 @@
# Discover all repository dependencies and retrieve information for installing them.
all_repo_info_dict = get_required_repo_info_dicts( trans, tool_shed_url, util.listify( repo_info_dict ) )
has_repository_dependencies = all_repo_info_dict.get( 'has_repository_dependencies', False )
+ has_repository_dependencies_only_if_compiling_contained_td = all_repo_info_dict.get( 'has_repository_dependencies_only_if_compiling_contained_td', False )
includes_tools_for_display_in_tool_panel = all_repo_info_dict.get( 'includes_tools_for_display_in_tool_panel', False )
includes_tool_dependencies = all_repo_info_dict.get( 'includes_tool_dependencies', False )
includes_tools = all_repo_info_dict.get( 'includes_tools', False )
required_repo_info_dicts = all_repo_info_dict.get( 'all_repo_info_dicts', [] )
# Display tool dependencies defined for each of the repository dependencies.
if required_repo_info_dicts:
- all_tool_dependencies = {}
+ required_tool_dependencies = {}
for rid in required_repo_info_dicts:
for name, repo_info_tuple in rid.items():
- description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, rid_installed_td = \
+ description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, rid_repository_dependencies, rid_tool_dependencies = \
suc.get_repo_info_tuple_contents( repo_info_tuple )
- if rid_installed_td:
- for td_key, td_dict in rid_installed_td.items():
- if td_key not in all_tool_dependencies:
- all_tool_dependencies[ td_key ] = td_dict
- if all_tool_dependencies:
- if installed_td is None:
- installed_td = {}
- else:
- # Move all tool dependencies to the missing_tool_dependencies container.
- for td_key, td_dict in installed_td.items():
- if td_key not in missing_td:
- missing_td[ td_key ] = td_dict
- installed_td = {}
+ if rid_tool_dependencies:
+ for td_key, td_dict in rid_tool_dependencies.items():
+ if td_key not in required_tool_dependencies:
+ required_tool_dependencies[ td_key ] = td_dict
+ if required_tool_dependencies:
# Discover and categorize all tool dependencies defined for this repository's repository dependencies.
- required_tool_dependencies, required_missing_tool_dependencies = \
- get_installed_and_missing_tool_dependencies_for_new_install( trans, all_tool_dependencies )
- if required_tool_dependencies:
+ required_installed_td, required_missing_td = get_installed_and_missing_tool_dependencies( trans,
+ tool_shed_url,
+ required_tool_dependencies )
+ if required_installed_td:
if not includes_tool_dependencies:
includes_tool_dependencies = True
- for td_key, td_dict in required_tool_dependencies.items():
+ for td_key, td_dict in required_installed_td.items():
if td_key not in installed_td:
installed_td[ td_key ] = td_dict
- if required_missing_tool_dependencies:
+ if required_missing_td:
if not includes_tool_dependencies:
includes_tool_dependencies = True
- for td_key, td_dict in required_missing_tool_dependencies.items():
+ for td_key, td_dict in required_missing_td.items():
if td_key not in missing_td:
missing_td[ td_key ] = td_dict
else:
- # We have a single repository with no defined repository dependencies.
+ # We have a single repository with (possibly) no defined repository dependencies.
all_repo_info_dict = get_required_repo_info_dicts( trans, tool_shed_url, util.listify( repo_info_dict ) )
has_repository_dependencies = all_repo_info_dict.get( 'has_repository_dependencies', False )
+ has_repository_dependencies_only_if_compiling_contained_td = all_repo_info_dict.get( 'has_repository_dependencies_only_if_compiling_contained_td', False )
includes_tools_for_display_in_tool_panel = all_repo_info_dict.get( 'includes_tools_for_display_in_tool_panel', False )
includes_tool_dependencies = all_repo_info_dict.get( 'includes_tool_dependencies', False )
includes_tools = all_repo_info_dict.get( 'includes_tools', False )
required_repo_info_dicts = all_repo_info_dict.get( 'all_repo_info_dicts', [] )
- installed_rd = None
- missing_rd = None
- missing_td = None
- dependencies_for_repository_dict = dict( changeset_revision=changeset_revision,
- has_repository_dependencies=has_repository_dependencies,
- includes_tool_dependencies=includes_tool_dependencies,
- includes_tools=includes_tools,
- includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
- installed_repository_dependencies=installed_rd,
- installed_tool_dependencies=installed_td,
- missing_repository_dependencies=missing_rd,
- missing_tool_dependencies=missing_td,
- name=name,
- repository_owner=repository_owner )
+ dependencies_for_repository_dict = \
+ dict( changeset_revision=changeset_revision,
+ has_repository_dependencies=has_repository_dependencies,
+ has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td,
+ includes_tool_dependencies=includes_tool_dependencies,
+ includes_tools=includes_tools,
+ includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
+ installed_repository_dependencies=installed_rd,
+ installed_tool_dependencies=installed_td,
+ missing_repository_dependencies=missing_rd,
+ missing_tool_dependencies=missing_td,
+ name=name,
+ repository_owner=repository_owner )
return dependencies_for_repository_dict
def get_installed_and_missing_repository_dependencies( trans, repository ):
"""
Return the installed and missing repository dependencies for a tool shed repository that has a record in the Galaxy database, but
- may or may not be installed. In this case, the repository dependencies are associated with the repository in the database.
+ may or may not be installed. In this case, the repository dependencies are associated with the repository in the database. Do not
+ include a repository dependency if it is required only to compile a tool dependency defined for the dependent repository since these
+ special kinds of repository dependencies are really a dependency of the dependent repository's contained tool dependency, and only if
+ that tool dependency requires compilation.
"""
missing_repository_dependencies = {}
installed_repository_dependencies = {}
@@ -166,7 +176,14 @@
for tsr in repository.repository_dependencies:
prior_installation_required = suc.set_prior_installation_required( repository, tsr )
only_if_compiling_contained_td = suc.set_only_if_compiling_contained_td( repository, tsr )
- rd_tup = [ tsr.tool_shed, tsr.name, tsr.owner, tsr.changeset_revision, prior_installation_required, only_if_compiling_contained_td, tsr.id, tsr.status ]
+ rd_tup = [ tsr.tool_shed,
+ tsr.name,
+ tsr.owner,
+ tsr.changeset_revision,
+ prior_installation_required,
+ only_if_compiling_contained_td,
+ tsr.id,
+ tsr.status ]
if tsr.status == trans.model.ToolShedRepository.installation_status.INSTALLED:
installed_rd_tups.append( rd_tup )
else:
@@ -184,7 +201,7 @@
repository_dependencies = metadata.get( 'repository_dependencies', {} )
description = repository_dependencies.get( 'description', None )
# We need to add a root_key entry to one or both of installed_repository_dependencies dictionary and the missing_repository_dependencies
- # dictionary for proper display parsing.
+ # dictionaries for proper display parsing.
root_key = container_util.generate_repository_dependencies_key_for_repository( repository.tool_shed,
repository.name,
repository.owner,
@@ -210,7 +227,7 @@
installed_repository_dependencies = {}
missing_rd_tups = []
installed_rd_tups = []
- description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td = \
+ description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
suc.get_repo_info_tuple_contents( repo_info_tuple )
if repository_dependencies:
description = repository_dependencies[ 'description' ]
@@ -228,7 +245,7 @@
# tuple looks like: ( description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td )
tmp_clone_url = suc.generate_clone_url_from_repo_info_tup( rd_tup )
tmp_repo_info_tuple = ( None, tmp_clone_url, changeset_revision, None, owner, None, None )
- repository, current_changeset_revision = suc.repository_was_previously_installed( trans, tool_shed, name, tmp_repo_info_tuple )
+ repository, installed_changeset_revision = suc.repository_was_previously_installed( trans, tool_shed, name, tmp_repo_info_tuple )
if repository:
new_rd_tup = [ tool_shed,
name,
@@ -273,29 +290,46 @@
missing_repository_dependencies[ 'description' ] = description
return installed_repository_dependencies, missing_repository_dependencies
-def get_installed_and_missing_tool_dependencies_for_new_install( trans, all_tool_dependencies ):
+def get_installed_and_missing_tool_dependencies( trans, tool_shed_url, tool_dependencies_dict ):
"""Return the lists of installed tool dependencies and missing tool dependencies for a set of repositories being installed into Galaxy."""
- # FIXME: confirm that this method currently populates and returns only missing tool dependencies. If so, this method should be enhanced to search for
- # installed tool dependencies defined as complex repository dependency relationships.
- if all_tool_dependencies:
- tool_dependencies = {}
- missing_tool_dependencies = {}
- for td_key, val in all_tool_dependencies.items():
- # Set environment tool dependencies are a list, set each member to never installed.
+ installed_tool_dependencies = {}
+ missing_tool_dependencies = {}
+ if tool_dependencies_dict:
+ for td_key, val in tool_dependencies_dict.items():
+ # Default the status to NEVER_INSTALLED.
+ tool_dependency_status = trans.model.ToolDependency.installation_status.NEVER_INSTALLED
+ # Set environment tool dependencies are a list.
if td_key == 'set_environment':
new_val = []
for requirement_dict in val:
- requirement_dict[ 'status' ] = trans.model.ToolDependency.installation_status.NEVER_INSTALLED
+ # {'repository_name': 'xx', 'name': 'bwa', 'version': '0.5.9', 'repository_owner': 'yy', 'changeset_revision': 'zz', 'type': 'package'}
+ tool_dependency = tool_dependency_util.get_tool_dependency_by_name_version_type( trans.app,
+ requirement_dict.get( 'name', None ),
+ requirement_dict.get( 'version', None ),
+ requirement_dict.get( 'type', 'package' ) )
+ if tool_dependency:
+ tool_dependency_status = tool_dependency.status
+ requirement_dict[ 'status' ] = tool_dependency_status
new_val.append( requirement_dict )
- missing_tool_dependencies[ td_key ] = new_val
+ if tool_dependency_status in [ trans.model.ToolDependency.installation_status.INSTALLED ]:
+ installed_tool_dependencies[ td_key ] = new_val
+ else:
+ missing_tool_dependencies[ td_key ] = new_val
else:
- # Since we have a new install, missing tool dependencies have never been installed.
- val[ 'status' ] = trans.model.ToolDependency.installation_status.NEVER_INSTALLED
+ # The val dictionary looks something like this:
+ # {'repository_name': 'xx', 'name': 'bwa', 'version': '0.5.9', 'repository_owner': 'yy', 'changeset_revision': 'zz', 'type': 'package'}
+ tool_dependency = tool_dependency_util.get_tool_dependency_by_name_version_type( trans.app,
+ val.get( 'name', None ),
+ val.get( 'version', None ),
+ val.get( 'type', 'package' ) )
+ if tool_dependency:
+ tool_dependency_status = tool_dependency.status
+ val[ 'status' ] = tool_dependency_status
+ if tool_dependency_status in [ trans.model.ToolDependency.installation_status.INSTALLED ]:
+ installed_tool_dependencies[ td_key ] = val
+ else:
missing_tool_dependencies[ td_key ] = val
- else:
- tool_dependencies = None
- missing_tool_dependencies = None
- return tool_dependencies, missing_tool_dependencies
+ return installed_tool_dependencies, missing_tool_dependencies
def get_required_repo_info_dicts( trans, tool_shed_url, repo_info_dicts ):
"""
@@ -328,7 +362,9 @@
toolshed, name, owner, changeset_revision = container_util.get_components_from_key( key )
components_list = [ toolshed, name, owner, changeset_revision ]
only_if_compiling_contained_td = 'False'
- # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository.
+ # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository since
+ # in this case, the repository dependency is really a dependency of the dependent repository's contained tool dependency, and only if
+ # that tool dependency requires compilation.
if not util.asbool( only_if_compiling_contained_td ):
if components_list not in required_repository_tups:
required_repository_tups.append( components_list )
@@ -337,8 +373,8 @@
only_if_compiling_contained_td = components_list[ 5 ]
except:
only_if_compiling_contained_td = 'False'
- # TODO: Fix this to display the tool dependency if only_if_compiling_contained_td is True, but clarify that installation may not
- # happen.
+ # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository
+ # (see above comment).
if not util.asbool( only_if_compiling_contained_td ):
if components_list not in required_repository_tups:
required_repository_tups.append( components_list )
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/tool_shed/util/common_util.py
--- a/lib/tool_shed/util/common_util.py
+++ b/lib/tool_shed/util/common_util.py
@@ -1,3 +1,4 @@
+import logging
import os
import urllib2
from galaxy.util import json
@@ -5,6 +6,8 @@
from tool_shed.util import encoding_util
from tool_shed.util import xml_util
+log = logging.getLogger( __name__ )
+
REPOSITORY_OWNER = 'devteam'
def accumulate_tool_dependencies( tool_shed_accessible, tool_dependencies, all_tool_dependencies ):
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/tool_shed/util/metadata_util.py
--- a/lib/tool_shed/util/metadata_util.py
+++ b/lib/tool_shed/util/metadata_util.py
@@ -280,13 +280,16 @@
def create_or_update_repository_metadata( trans, id, repository, changeset_revision, metadata_dict ):
"""Create or update a repository_metadatqa record in the tool shed."""
has_repository_dependencies = False
+ has_repository_dependencies_only_if_compiling_contained_td = False
includes_datatypes = False
includes_tools = False
includes_tool_dependencies = False
includes_workflows = False
if metadata_dict:
- if 'repository_dependencies' in metadata_dict:
- has_repository_dependencies = True
+ repository_dependencies_dict = metadata_dict.get( 'repository_dependencies', {} )
+ repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \
+ suc.get_repository_dependency_types( repository_dependencies )
if 'datatypes' in metadata_dict:
includes_datatypes = True
if 'tools' in metadata_dict:
@@ -295,7 +298,11 @@
includes_tool_dependencies = True
if 'workflows' in metadata_dict:
includes_workflows = True
- downloadable = has_repository_dependencies or includes_datatypes or includes_tools or includes_tool_dependencies or includes_workflows
+ if has_repository_dependencies or has_repository_dependencies_only_if_compiling_contained_td or includes_datatypes or \
+ includes_tools or includes_tool_dependencies or includes_workflows:
+ downloadable = True
+ else:
+ downloadable = False
repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, id, changeset_revision )
if repository_metadata:
# A repository metadata record already exists with the received changeset_revision, so we don't need to check the skip_tool_test table.
@@ -1851,10 +1858,13 @@
repository_metadata.includes_datatypes = True
else:
repository_metadata.includes_datatypes = False
- if 'repository_dependencies' in metadata_dict:
- repository_metadata.has_repository_dependencies = True
- else:
- repository_metadata.has_repository_dependencies = False
+ # We don't store information about the special type of repository dependency that is needed only for compiling a tool dependency
+ # defined for the dependent repository.
+ repository_dependencies_dict = metadata_dict.get( 'repository_dependencies', {} )
+ repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \
+ suc.get_repository_dependency_types( repository_dependencies )
+ repository_metadata.has_repository_dependencies = has_repository_dependencies
if 'tool_dependencies' in metadata_dict:
repository_metadata.includes_tool_dependencies = True
else:
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/tool_shed/util/repository_dependency_util.py
--- a/lib/tool_shed/util/repository_dependency_util.py
+++ b/lib/tool_shed/util/repository_dependency_util.py
@@ -139,6 +139,7 @@
# repository dependencies are not to be installed, only those items contained in the received repo_info_dicts list will be processed.
if is_in_repo_info_dicts( repo_info_dict, repo_info_dicts ) or install_repository_dependencies:
if installed_tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.ERROR,
+ trans.model.ToolShedRepository.installation_status.NEW,
trans.model.ToolShedRepository.installation_status.UNINSTALLED ]:
# The current tool shed repository is not currently installed, so we can update it's record in the database.
can_update = True
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/tool_shed/util/shed_util_common.py
--- a/lib/tool_shed/util/shed_util_common.py
+++ b/lib/tool_shed/util/shed_util_common.py
@@ -868,6 +868,31 @@
.first()
return None
+def get_repository_dependency_types( repository_dependencies ):
+ """
+ Inspect the received list of repository_dependencies tuples and return boolean values for has_repository_dependencies and
+ has_repository_dependencies_only_if_compiling_contained_td.
+ """
+ # Set has_repository_dependencies, which will be True only if at least one repository_dependency is defined with the value of
+ # only_if_compiling_contained_td as False.
+ has_repository_dependencies = False
+ for rd_tup in repository_dependencies:
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
+ if not asbool( only_if_compiling_contained_td ):
+ has_repository_dependencies = True
+ break
+ # Set has_repository_dependencies_only_if_compiling_contained_td, which will be True only if at least one repository_dependency is
+ # defined with the value of only_if_compiling_contained_td as True.
+ has_repository_dependencies_only_if_compiling_contained_td = False
+ for rd_tup in repository_dependencies:
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
+ if asbool( only_if_compiling_contained_td ):
+ has_repository_dependencies_only_if_compiling_contained_td = True
+ break
+ return has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td
+
def get_repository_for_dependency_relationship( app, tool_shed, name, owner, changeset_revision ):
"""Return an installed tool_shed_repository database record that is defined by either the current changeset revision or the installed_changeset_revision."""
# This method is used only in Galaxy, not the tool shed.
@@ -1389,14 +1414,23 @@
def repository_was_previously_installed( trans, tool_shed_url, repository_name, repo_info_tuple ):
"""
- Handle the case where the repository was previously installed using an older changeset_revsion, but later the repository was updated
- in the tool shed and now we're trying to install the latest changeset revision of the same repository instead of updating the one
- that was previously installed. We'll look in the database instead of on disk since the repository may be uninstalled.
+ Find out if a repository is already installed into Galaxy - there are several scenarios where this is necessary. For example, this method
+ will handle the case where the repository was previously installed using an older changeset_revsion, but later the repository was updated
+ in the tool shed and now we're trying to install the latest changeset revision of the same repository instead of updating the one that was
+ previously installed. We'll look in the database instead of on disk since the repository may be currently uninstalled.
"""
description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
get_repo_info_tuple_contents( repo_info_tuple )
tool_shed = get_tool_shed_from_clone_url( repository_clone_url )
- # Get all previous change set revisions from the tool shed for the repository back to, but excluding, the previous valid changeset
+ # See if we can locate the repository using the value of changeset_revision.
+ tool_shed_repository = get_tool_shed_repository_by_shed_name_owner_installed_changeset_revision( trans.app,
+ tool_shed,
+ repository_name,
+ repository_owner,
+ changeset_revision )
+ if tool_shed_repository:
+ return tool_shed_repository, changeset_revision
+ # Get all previous changeset revisions from the tool shed for the repository back to, but excluding, the previous valid changeset
# revision to see if it was previously installed using one of them.
url = url_join( tool_shed_url,
'repository/previous_changeset_revisions?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s' % \
@@ -1410,14 +1444,14 @@
repository_name,
repository_owner,
previous_changeset_revision )
- if tool_shed_repository and tool_shed_repository.status not in [ trans.model.ToolShedRepository.installation_status.NEW ]:
+ if tool_shed_repository:
return tool_shed_repository, previous_changeset_revision
return None, None
def reset_previously_installed_repository( trans, repository ):
"""
Reset the atrributes of a tool_shed_repository that was previsouly installed. The repository will be in some state other than with a
- status of INSTALLED, so all atributes will be set to the default (NEW( state. This will enable the repository to be freshly installed.
+ status of INSTALLED, so all atributes will be set to the default NEW state. This will enable the repository to be freshly installed.
"""
repository.deleted = False
repository.tool_shed_status = None
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/tool_shed/util/tool_dependency_util.py
--- a/lib/tool_shed/util/tool_dependency_util.py
+++ b/lib/tool_shed/util/tool_dependency_util.py
@@ -258,6 +258,14 @@
app.model.ToolDependency.table.c.type == type ) ) \
.first()
+def get_tool_dependency_by_name_version_type( app, name, version, type ):
+ sa_session = app.model.context.current
+ return sa_session.query( app.model.ToolDependency ) \
+ .filter( and_( app.model.ToolDependency.table.c.name == name,
+ app.model.ToolDependency.table.c.version == version,
+ app.model.ToolDependency.table.c.type == type ) ) \
+ .first()
+
def get_tool_dependency_by_name_version_type_repository( app, repository, name, version, type ):
sa_session = app.model.context.current
return sa_session.query( app.model.ToolDependency ) \
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b lib/tool_shed/util/tool_util.py
--- a/lib/tool_shed/util/tool_util.py
+++ b/lib/tool_shed/util/tool_util.py
@@ -962,7 +962,7 @@
suc.config_elems_to_xml_file( trans.app, config_elems, shed_tool_conf, tool_path )
def remove_from_tool_panel( trans, repository, shed_tool_conf, uninstall ):
- """A tool shed repository is being deactivated or uninstalled so handle tool panel alterations accordingly."""
+ """A tool shed repository is being deactivated or uninstalled, so handle tool panel alterations accordingly."""
# Determine where the tools are currently defined in the tool panel and store this information so the tools can be displayed
# in the same way when the repository is activated or reinstalled.
tool_panel_dict = suc.generate_tool_panel_dict_from_shed_tool_conf_entries( trans.app, repository )
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b static/scripts/galaxy.grids.js
--- a/static/scripts/galaxy.grids.js
+++ b/static/scripts/galaxy.grids.js
@@ -472,7 +472,7 @@
go_to_URL();
return;
}
-
+
// If there's an operation, do POST; otherwise, do GET.
var method = (grid.get('operation') ? "POST" : "GET" );
$('.loading-elt-overlay').show(); // Show overlay to indicate loading and prevent user actions.
@@ -565,4 +565,4 @@
// return
return true;
-}
\ No newline at end of file
+}
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b static/scripts/galaxy.modal.js
--- a/static/scripts/galaxy.modal.js
+++ b/static/scripts/galaxy.modal.js
@@ -77,13 +77,25 @@
// link functions
$.each(options.buttons, function(name, value)
{
- footer.append($('<button></button>').text(name).click(value)).append(" ");
+ footer.append($('<button id="' + String(name).toLowerCase() + '"></button>').text(name).click(value)).append(" ");
});
} else
// default close button
footer.append($('<button></button>').text('Close').click(function() { self.hide() })).append(" ");
},
+ // enable buttons
+ enable: function(name)
+ {
+ $(this.el).find('#' + String(name).toLowerCase()).prop('disabled', false);
+ },
+
+ // disable buttons
+ disable: function(name)
+ {
+ $(this.el).find('#' + String(name).toLowerCase()).prop('disabled', true);
+ },
+
/*
HTML TEMPLATES
*/
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b static/scripts/galaxy.upload.js
--- a/static/scripts/galaxy.upload.js
+++ b/static/scripts/galaxy.upload.js
@@ -1,5 +1,5 @@
/*
- galaxy upload v1.0
+ galaxy upload
*/
// dependencies
@@ -14,12 +14,20 @@
// button
button_show : null,
- // file counter
- file_counter: 0,
+ // upload mod
+ uploadbox: null,
// initialize
initialize : function()
{
+ // wait for galaxy history panel (workaround due to the use of iframes)
+ if (!Galaxy.currHistoryPanel)
+ {
+ var self = this;
+ window.setTimeout(function() { self.initialize() }, 500)
+ return;
+ }
+
// add activate icon
var self = this;
this.button_show = new mod_master.GalaxyMasterIcon (
@@ -37,87 +45,252 @@
// events
events :
{
- 'mouseover' : 'event_mouseover',
- 'mouseleave' : 'event_mouseleave'
+ 'mouseover' : 'event_mouseover',
+ 'mouseleave' : 'event_mouseleave'
},
// mouse over
event_mouseover : function (e)
{
- $('#galaxy-upload-box').addClass('highlight');
},
// mouse left
event_mouseleave : function (e)
{
- $('#galaxy-upload-box').removeClass('highlight');
},
// start
- event_start : function(index, file, message)
+ event_announce : function(index, file, message)
{
+ // hide info
+ this.uploadbox.info().hide();
+
// make id
- var id = '#galaxy-upload-file-' + index;
+ var id = '#upload-' + index;
- // add tag
- $('#galaxy-upload-box').append(this.template_file(id));
+ // add upload item
+ $(this.el).append(this.template_file(id));
+
+ // scroll to bottom
+ $(this.el).scrollTop($(this.el).prop('scrollHeight'));
+
+ // access upload item
+ var it = this.get_upload_item(index);
+
+ // fade in
+ it.fadeIn();
// update title
- $('#galaxy-upload-file-' + index).find('.title').html(file.name);
+ it.find('.title').html(file.name);
+ // configure select field
+ it.find('#extension').select2(
+ {
+ placeholder: 'Auto-detect',
+ width: 'copy',
+ ajax: {
+ url: "http://www.weighttraining.com/sm/search",
+ dataType: 'jsonp',
+ quietMillis: 100,
+ data: function(term, page)
+ {
+ return {
+ types: ["exercise"],
+ limit: -1,
+ term: term
+ };
+ },
+ results: function(data, page)
+ {
+ return { results: data.results.exercise }
+ }
+ },
+ formatResult: function(exercise)
+ {
+ return "<div class='select2-user-result'>" + exercise.term + "</div>";
+ },
+ formatSelection: function(exercise)
+ {
+ return exercise.term;
+ },
+ initSelection : function (element, callback)
+ {
+ var elementText = $(element).attr('data-init-text');
+ callback({"term":elementText});
+ }
+ });
+
+ // add functionality to remove button
+ var self = this;
+ it.find('.remove').on('click', function() { self.event_remove (index) });
+
// initialize progress
this.event_progress(index, file, 0);
- // update counter
- this.file_counter++;
- this.refresh();
+ // update button status
+ this.modal.enable('Upload');
+ this.modal.enable('Reset');
+ },
+
+ // start
+ event_initialize : function(index, file, message)
+ {
+ // update on screen counter
+ this.button_show.number(message);
+
+ // get element
+ var it = this.get_upload_item(index);
+
+ // read in configuration
+ var data = {
+ source : "upload",
+ space_to_tabs : it.find('#space_to_tabs').is(':checked'),
+ extension : it.find('#extension').val()
+ }
+
+ // return additional data to be send with file
+ return data;
},
// progress
event_progress : function(index, file, message)
{
- // get progress bar
- var el = $('#galaxy-upload-file-' + index);
+ // get element
+ var it = this.get_upload_item(index);
// get value
var percentage = parseInt(message);
// update progress
- el.find('.progress').css({ width : percentage + '%' });
+ it.find('.progress-bar').css({ width : percentage + '%' });
// update info
- el.find('.info').html(percentage + '% of ' + this.size_to_string (file.size));
+ it.find('.info').html(percentage + '% of ' + this.size_to_string (file.size));
},
// end
event_success : function(index, file, message)
- {
+ {
+ // get element
+ var it = this.get_upload_item(index);
+
+ // update progress frame
+ it.addClass('panel-success');
+ it.removeClass('panel-default');
+
// update galaxy history
Galaxy.currHistoryPanel.refresh();
- // update counter
- this.file_counter--;
- this.refresh();
+ // make sure progress is shown correctly
+ this.event_progress(index, file, 100);
+
+ // update on screen counter
+ this.button_show.number('');
},
// end
event_error : function(index, file, message)
{
- // get file box
- var el = $('#galaxy-upload-file-' + index);
+ // get element
+ var it = this.get_upload_item(index);
// update progress frame
- el.find('.progress-frame').addClass('failed');
+ it.addClass('panel-danger');
+ it.removeClass('panel-default');
- // update error message
- el.find('.error').html("<strong>Failed:</strong> " + message);
-
- // update progress
+ // remove progress bar
+ it.find('.progress').remove();
+
+ // write error message
+ it.find('.error').html('<strong>Failed:</strong> ' + message);
+
+ // make sure progress is shown correctly
this.event_progress(index, file, 0);
- // update counter
- this.file_counter--;
- this.refresh();
+ // update on screen counter
+ this.button_show.number('');
+ },
+
+ // start upload process
+ event_upload : function()
+ {
+ // hide configuration
+ $(this.el).find('.panel-body').hide();
+
+ // switch icon
+ $(this.el).find('.remove').each(function()
+ {
+ $(this).removeClass('fa-icon-trash');
+ $(this).addClass('fa-icon-caret-down');
+ });
+
+ // update button status
+ this.modal.disable('Upload');
+
+ // configure url
+ var current_history = Galaxy.currHistoryPanel.model.get('id');
+ this.uploadbox.configure({url : galaxy_config.root + "api/histories/" + current_history + "/contents"});
+
+ // initiate upload procedure in plugin
+ this.uploadbox.upload();
+ },
+
+ // remove all
+ event_reset : function()
+ {
+ // remove from screen
+ var panels = $(this.el).find('.panel');
+ var self = this;
+ panels.fadeOut({complete: function()
+ {
+ // remove panels
+ panels.remove();
+
+ // show on screen info
+ self.uploadbox.info().fadeIn();
+ }});
+
+ // update button status
+ this.modal.disable('Upload');
+ this.modal.disable('Reset');
+
+ // remove from queue
+ this.uploadbox.reset();
+ },
+
+ // remove item from upload list
+ event_remove : function(index)
+ {
+ // remove
+ var self = this;
+ var it = this.get_upload_item(index);
+
+ // fade out and update button status
+ it.fadeOut({complete: function()
+ {
+ // remove from screen
+ it.remove();
+
+ // remove from queue
+ self.uploadbox.remove(index);
+
+ // update reset button
+ if ($(self.el).find('.panel').length > 0)
+ self.modal.enable('Reset');
+ else {
+ // disable reset button
+ self.modal.disable('Reset');
+
+ // show on screen info
+ self.uploadbox.info().fadeIn();
+ }
+
+ // update upload button
+ if (self.uploadbox.length() > 0)
+ self.modal.enable('Upload');
+ else
+ self.modal.disable('Upload');
+ }});
},
// show/hide upload frame
@@ -126,14 +299,6 @@
// prevent default
e.preventDefault();
- // wait for galaxy history panel (workaround due to the use of iframes)
- if (!Galaxy.currHistoryPanel)
- {
- var self = this;
- window.setTimeout(function() { self.event_show(e) }, 200)
- return;
- }
-
// create modal
if (!this.modal)
{
@@ -142,44 +307,45 @@
this.modal = new mod_modal.GalaxyModal(
{
title : 'Upload files from your local drive',
- body : this.template(),
+ body : this.template('upload-box'),
buttons : {
- 'Close' : function() {self.modal.hide()}
+ 'Select' : function() {self.uploadbox.select()},
+ 'Upload' : function() {self.event_upload()},
+ 'Reset' : function() {self.event_reset()},
+ 'Close' : function() {self.modal.hide()}
}
});
- // get current history
- var current_history = Galaxy.currHistoryPanel.model.get('id');
-
+ // set element
+ this.setElement('#upload-box');
+
// file upload
var self = this;
- $('#galaxy-upload-box').uploadbox(
+ this.uploadbox = this.$el.uploadbox(
{
- url : galaxy_config.root + "api/histories/" + current_history + "/contents",
dragover : self.event_mouseover,
dragleave : self.event_mouseleave,
- start : function(index, file, message) { self.event_start(index, file, message) },
+ announce : function(index, file, message) { self.event_announce(index, file, message) },
+ initialize : function(index, file, message) { return self.event_initialize(index, file, message) },
success : function(index, file, message) { self.event_success(index, file, message) },
progress : function(index, file, message) { self.event_progress(index, file, message) },
error : function(index, file, message) { self.event_error(index, file, message) },
- data : {source : "upload"}
});
- // set element
- this.setElement('#galaxy-upload-box');
+ // update button status
+ this.modal.disable('Upload');
+ this.modal.disable('Reset');
}
-
+
// show modal
this.modal.show();
},
- // update counter
- refresh: function ()
+ // get upload item
+ get_upload_item: function(index)
{
- if (this.file_counter > 0)
- this.button_show.number(this.file_counter);
- else
- this.button_show.number('');
+ // get element
+ return $(this.el).find('#upload-' + index);
},
// to string
@@ -197,21 +363,32 @@
},
// load html template
- template: function()
+ template: function(id)
{
- return '<form id="galaxy-upload-box" class="galaxy-upload-box"></form>';
+ return '<div id="' + id + '" class="upload-box"></div>';
},
// load html template
template_file: function(id)
{
- return '<div id="' + id.substr(1) + '" class="file corner-soft shadow">' +
- '<div class="title"></div>' +
- '<div class="error"></div>' +
- '<div class="progress-frame corner-soft">' +
- '<div class="progress"></div>' +
+ return '<div id="' + id.substr(1) + '" class="panel panel-default">' +
+ '<div class="panel-heading">' +
+ '<h5 class="title"></h5>' +
+ '<h5 class="info"></h5>' +
+ '<div class="remove fa-icon-trash"></div>' +
'</div>' +
- '<div class="info"></div>' +
+ '<div class="panel-body">' +
+ '<div class="menu">' +
+ //'<input id="extension" type="hidden" width="10px"/> ' +
+ '<span><input id="space_to_tabs" type="checkbox">Convert spaces to tabs</input></span>' +
+ '</div>' +
+ '</div>' +
+ '<div class="panel-footer">' +
+ '<div class="progress">' +
+ '<div class="progress-bar progress-bar-success"></div>' +
+ '</div>' +
+ '<h6 class="error"></h6>' +
+ '</div>' +
'</div>';
}
});
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b static/scripts/packed/galaxy.upload.js
--- a/static/scripts/packed/galaxy.upload.js
+++ b/static/scripts/packed/galaxy.upload.js
@@ -1,1 +1,1 @@
-define(["utils/galaxy.css","galaxy.modal","galaxy.master","utils/galaxy.uploadbox","libs/backbone/backbone-relational"],function(c,b,d){var a=Backbone.View.extend({modal:null,button_show:null,file_counter:0,initialize:function(){c.load_file("static/style/galaxy.upload.css");var e=this;this.button_show=new d.GalaxyMasterIcon({icon:"fa-icon-upload",tooltip:"Upload Files",on_click:function(f){e.event_show(f)},with_number:true});Galaxy.master.prepend(this.button_show)},events:{mouseover:"event_mouseover",mouseleave:"event_mouseleave"},event_mouseover:function(f){$("#galaxy-upload-box").addClass("galaxy-upload-highlight")},event_mouseleave:function(f){$("#galaxy-upload-box").removeClass("galaxy-upload-highlight")},event_start:function(e,f,g){var h="#galaxy-upload-file-"+e;$("#galaxy-upload-box").append(this.template_file(h));$("#galaxy-upload-file-"+e).find(".title").html(f.name);this.event_progress(e,f,0);this.file_counter++;this.refresh()},event_progress:function(f,g,i){var h=$("#galaxy-upload-file-"+f);var e=parseInt(i);h.find(".progress").css({width:e+"%"});h.find(".info").html(e+"% of "+this.size_to_string(g.size))},event_success:function(e,f,g){Galaxy.currHistoryPanel.refresh();this.file_counter--;this.refresh()},event_error:function(e,f,h){var g=$("#galaxy-upload-file-"+e);g.find(".progress-frame").addClass("failed");g.find(".error").html("<strong>Failed:</strong> "+h);this.event_progress(e,f,0);this.file_counter--;this.refresh()},event_show:function(h){h.preventDefault();if(!Galaxy.currHistoryPanel){var g=this;window.setTimeout(function(){g.event_show(h)},200);return}if(!this.modal){this.modal=new b.GalaxyModal({title:"Upload files from your local drive",body:this.template()});var f=Galaxy.currHistoryPanel.model.get("id");var g=this;$("#galaxy-upload-box").uploadbox({url:galaxy_config.root+"api/histories/"+f+"/contents",dragover:g.event_mouseover,dragleave:g.event_mouseleave,start:function(e,i,j){g.event_start(e,i,j)},success:function(e,i,j){g.event_success(e,i,j)},progress:function(e,i,j){g.event_progress(e,i,j)},error:function(e,i,j){g.event_error(e,i,j)},data:{source:"upload"}});this.setElement("#galaxy-upload-box")}this.modal.show()},refresh:function(){if(this.file_counter>0){this.button_show.number(this.file_counter)}else{this.button_show.number("")}},size_to_string:function(e){var f="";if(e>=100000000000){e=e/100000000000;f="TB"}else{if(e>=100000000){e=e/100000000;f="GB"}else{if(e>=100000){e=e/100000;f="MB"}else{if(e>=100){e=e/100;f="KB"}else{e=e*10;f="b"}}}}return"<strong>"+(Math.round(e)/10)+"</strong> "+f},template:function(){return'<form id="galaxy-upload-box" class="galaxy-upload-box galaxy-corner"></form>'},template_file:function(e){return'<div id="'+e.substr(1)+'" class="galaxy-upload-file galaxy-corner-soft galaxy-shadow"><div class="title"></div><div class="error"></div><div class="progress-frame galaxy-corner-soft"><div class="progress"></div></div><div class="info"></div></div>'}});return{GalaxyUpload:a}});
\ No newline at end of file
+define(["galaxy.modal","galaxy.master","utils/galaxy.uploadbox","libs/backbone/backbone-relational"],function(b,c){var a=Backbone.View.extend({modal:null,button_show:null,file_counter:0,initialize:function(){var d=this;this.button_show=new c.GalaxyMasterIcon({icon:"fa-icon-upload",tooltip:"Upload Files",on_click:function(f){d.event_show(f)},with_number:true});Galaxy.master.prepend(this.button_show)},events:{mouseover:"event_mouseover",mouseleave:"event_mouseleave"},event_mouseover:function(d){$("#galaxy-upload-box").addClass("highlight")},event_mouseleave:function(d){$("#galaxy-upload-box").removeClass("highlight")},event_start:function(d,e,f){var g="#galaxy-upload-file-"+d;$("#galaxy-upload-box").append(this.template_file(g));$("#galaxy-upload-file-"+d).find(".title").html(e.name);this.event_progress(d,e,0);this.file_counter++;this.refresh()},event_progress:function(e,f,h){var g=$("#galaxy-upload-file-"+e);var d=parseInt(h);g.find(".progress").css({width:d+"%"});g.find(".info").html(d+"% of "+this.size_to_string(f.size))},event_success:function(d,e,f){Galaxy.currHistoryPanel.refresh();this.file_counter--;this.refresh()},event_error:function(d,e,g){var f=$("#galaxy-upload-file-"+d);f.find(".progress-frame").addClass("failed");f.find(".error").html("<strong>Failed:</strong> "+g);this.event_progress(d,e,0);this.file_counter--;this.refresh()},event_show:function(g){g.preventDefault();if(!Galaxy.currHistoryPanel){var f=this;window.setTimeout(function(){f.event_show(g)},200);return}if(!this.modal){var f=this;this.modal=new b.GalaxyModal({title:"Upload files from your local drive",body:this.template(),buttons:{Close:function(){f.modal.hide()}}});var d=Galaxy.currHistoryPanel.model.get("id");var f=this;$("#galaxy-upload-box").uploadbox({url:galaxy_config.root+"api/histories/"+d+"/contents",dragover:f.event_mouseover,dragleave:f.event_mouseleave,start:function(e,h,i){f.event_start(e,h,i)},success:function(e,h,i){f.event_success(e,h,i)},progress:function(e,h,i){f.event_progress(e,h,i)},error:function(e,h,i){f.event_error(e,h,i)},data:{source:"upload"}});this.setElement("#galaxy-upload-box")}this.modal.show()},refresh:function(){if(this.file_counter>0){this.button_show.number(this.file_counter)}else{this.button_show.number("")}},size_to_string:function(d){var e="";if(d>=100000000000){d=d/100000000000;e="TB"}else{if(d>=100000000){d=d/100000000;e="GB"}else{if(d>=100000){d=d/100000;e="MB"}else{if(d>=100){d=d/100;e="KB"}else{d=d*10;e="b"}}}}return"<strong>"+(Math.round(d)/10)+"</strong> "+e},template:function(){return'<form id="galaxy-upload-box" class="galaxy-upload-box"></form>'},template_file:function(d){return'<div id="'+d.substr(1)+'" class="file corner-soft shadow"><div class="title"></div><div class="error"></div><div class="progress-frame corner-soft"><div class="progress"></div></div><div class="info"></div></div>'}});return{GalaxyUpload:a}});
\ No newline at end of file
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b static/scripts/packed/galaxy.workflow_editor.canvas.js
--- a/static/scripts/packed/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/packed/galaxy.workflow_editor.canvas.js
@@ -1,1 +1,1 @@
-function Terminal(a){this.element=a;this.connectors=[]}$.extend(Terminal.prototype,{connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}});function OutputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}OutputTerminal.prototype=new Terminal();function InputTerminal(b,c,a){Terminal.call(this,b);this.datatypes=c;this.multiple=a}InputTerminal.prototype=new Terminal();$.extend(InputTerminal.prototype,{can_accept:function(a){if(this.connectors.length<1||this.multiple){for(var c in this.datatypes){var f=new Array();f=f.concat(a.datatypes);if(a.node.post_job_actions){for(var d in a.node.post_job_actions){var g=a.node.post_job_actions[d];if(g.action_type=="ChangeDatatypeAction"&&(g.output_name==""||g.output_name==a.name)&&g.action_arguments){f.push(g.action_arguments.newtype)}}}for(var b in f){if(f[b]=="input"||issubtype(f[b],this.datatypes[c])){return true}}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a){this.connect(b,a)}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;if(this.handle1){this.handle1.connect(this)}this.handle2=a;if(this.handle2){this.handle2.connect(this)}},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var n=function(c){return $(c).offset().left-d.offset().left};var i=function(c){return $(c).offset().top-d.offset().top};if(!this.handle1||!this.handle2){return}var h=n(this.handle1.element)+5;var g=i(this.handle1.element)+5;var p=n(this.handle2.element)+5;var m=i(this.handle2.element)+5;var f=100;var k=Math.min(h,p);var a=Math.max(h,p);var j=Math.min(g,m);var t=Math.max(g,m);var b=Math.min(Math.max(Math.abs(t-j)/2,100),300);var o=k-f;var s=j-f;var q=a-k+2*f;var l=t-j+2*f;this.canvas.style.left=o+"px";this.canvas.style.top=s+"px";this.canvas.setAttribute("width",q);this.canvas.setAttribute("height",l);h-=o;g-=s;p-=o;m-=s;var r=this.canvas.getContext("2d");r.lineCap="round";r.strokeStyle=this.outer_color;r.lineWidth=7;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke();r.strokeStyle=this.inner_color;r.lineWidth=5;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{enable_input_terminal:function(f,b,c,a){var d=this;$(f).each(function(){var g=this.terminal=new InputTerminal(this,c,a);g.node=d;g.name=b;$(this).bind("dropinit",function(h,i){return $(i.drag).hasClass("output-terminal")&&g.can_accept(i.drag.terminal)}).bind("dropstart",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#BBFFBB"}}).bind("dropend",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#FFFFFF"}}).bind("drop",function(h,i){(new Connector(i.drag.terminal,g)).redraw()}).bind("hover",function(){if(g.connectors.length>0){var h=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='buttons'></div>").append($("<img/>").attr("src",galaxy_config.root+"static/images/delete_icon.png").click(function(){$.each(g.connectors,function(j,i){if(i){i.destroy()}});h.remove()}))).bind("mouseleave",function(){$(this).remove()});h.css({top:$(this).offset().top-2,left:$(this).offset().left-h.width(),"padding-right":$(this).width()}).show()}});d.input_terminals[b]=g})},enable_output_terminal:function(d,a,b){var c=this;$(d).each(function(){var g=this;var f=this.terminal=new OutputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dragstart",function(j,k){$(k.available).addClass("input-terminal-active");workflow.check_changes_in_active_form();var i=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);i.terminal=new OutputTerminal(i);var l=new Connector();l.dragging=true;l.connect(this.terminal,i.terminal);return i}).bind("drag",function(i,j){var h=function(){var l=$(j.proxy).offsetParent().offset(),k=j.offsetX-l.left,m=j.offsetY-l.top;$(j.proxy).css({left:k,top:m});j.proxy.terminal.redraw();canvas_manager.update_viewport_overlay()};h();$("#canvas-container").get(0).scroll_panel.test(i,h)}).bind("dragend",function(h,i){i.proxy.terminal.connectors[0].destroy();$(i.proxy).remove();$(i.available).removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()});c.output_terminals[a]=f})},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(h){var g=this.element;if(h.type){this.type=h.type}this.name=h.name;this.form_html=h.form_html;this.tool_state=h.tool_state;this.tool_errors=h.tool_errors;this.tooltip=h.tooltip?h.tooltip:"";this.annotation=h.annotation;this.post_job_actions=h.post_job_actions?h.post_job_actions:{};this.workflow_outputs=h.workflow_outputs?h.workflow_outputs:[];if(this.tool_errors){g.addClass("tool-node-error")}else{g.removeClass("tool-node-error")}var d=this;var c=Math.max(150,g.width());var a=g.find(".toolFormBody");a.find("div").remove();var i=$("<div class='inputs'></div>").appendTo(a);$.each(h.data_inputs,function(k,f){var j=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(j,f.name,f.extensions,f.multiple);var b=$("<div class='form-row dataRow input-data-row' name='"+f.name+"'>"+f.label+"</div>");b.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(b);c=Math.max(c,b.outerWidth());b.css({position:"",left:"",top:"",display:""});b.remove();i.append(b.prepend(j))});if((h.data_inputs.length>0)&&(h.data_outputs.length>0)){a.append($("<div class='rule'></div>"))}$.each(h.data_outputs,function(k,b){var j=$("<div class='terminal output-terminal'></div>");d.enable_output_terminal(j,b.name,b.extensions);var f=b.name;if(b.extensions.indexOf("input")<0){f=f+" ("+b.extensions.join(", ")+")"}var m=$("<div class='form-row dataRow'>"+f+"</div>");if(d.type=="tool"){var l=$("<div class='callout "+f+"'></div>").css({display:"none"}).append($("<div class='buttons'></div>").append($("<img/>").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png").click(function(){if($.inArray(b.name,d.workflow_outputs)!=-1){d.workflow_outputs.splice($.inArray(b.name,d.workflow_outputs),1);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{d.workflow_outputs.push(b.name);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}workflow.has_changes=true;canvas_manager.draw_overview()}))).tooltip({delay:500,title:"Flag this as a workflow output. All non-flagged outputs will be hidden."});l.css({top:"50%",margin:"-8px 0px 0px 0px",right:8});l.show();m.append(l);if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}m.hover(function(){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-yellow.png")},function(){if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}})}m.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(m);c=Math.max(c,m.outerWidth()+17);m.css({position:"",left:"",top:"",display:""});m.detach();a.append(m.append(j))});g.css("width",Math.min(250,Math.max(g.width(),c)));workflow.node_changed(this)},update_field_data:function(f){var c=$(this.element),d=this;this.tool_state=f.tool_state;this.form_html=f.form_html;this.tool_errors=f.tool_errors;this.annotation=f.annotation;var g=$.parseJSON(f.post_job_actions);this.post_job_actions=g?g:{};if(this.tool_errors){c.addClass("tool-node-error")}else{c.removeClass("tool-node-error")}var h=c.find("div.inputs");var b=$("<div class='inputs'></div>");var a=h.find("div.input-data-row");$.each(f.data_inputs,function(l,j){var k=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(k,j.name,j.extensions,j.multiple);h.find("div[name='"+j.name+"']").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){k[0].terminal.connectors[0]=i;i.handle2=k[0].terminal}});$(this).remove()});b.append($("<div class='form-row dataRow input-data-row' name='"+j.name+"'>"+j.label+"</div>").prepend(k))});h.replaceWith(b);h.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.changed();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},changed:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false;this.active_form_has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},rectify_workflow_outputs:function(){var b=false;var a=false;$.each(this.nodes,function(c,d){if(d.workflow_outputs&&d.workflow_outputs.length>0){b=true}$.each(d.post_job_actions,function(g,f){if(f.action_type==="HideDatasetAction"){a=true}})});if(b!==false||a!==false){$.each(this.nodes,function(c,g){if(g.type==="tool"){var f=false;if(g.post_job_actions==null){g.post_job_actions={};f=true}var d=[];$.each(g.post_job_actions,function(i,h){if(h.action_type=="HideDatasetAction"){d.push(i)}});if(d.length>0){$.each(d,function(h,j){f=true;delete g.post_job_actions[j]})}if(b){$.each(g.output_terminals,function(i,j){var h=true;$.each(g.workflow_outputs,function(l,m){if(j.name===m){h=false}});if(h===true){f=true;var k={action_type:"HideDatasetAction",output_name:j.name,action_arguments:{}};g.post_job_actions["HideDatasetAction"+j.name]=null;g.post_job_actions["HideDatasetAction"+j.name]=k}})}if(workflow.active_node==g&&f===true){workflow.reload_active_node()}}})}},to_simple:function(){var a={};$.each(this.nodes,function(c,f){var g={};$.each(f.input_terminals,function(i,j){g[j.name]=null;var h=[];$.each(j.connectors,function(k,l){h[k]={id:l.handle1.node.id,output_name:l.handle1.name};g[j.name]=h})});var b={};if(f.post_job_actions){$.each(f.post_job_actions,function(j,h){var k={action_type:h.action_type,output_name:h.output_name,action_arguments:h.action_arguments};b[h.action_type+h.output_name]=null;b[h.action_type+h.output_name]=k})}if(!f.workflow_outputs){f.workflow_outputs=[]}var d={id:f.id,type:f.type,tool_id:f.tool_id,tool_state:f.tool_state,tool_errors:f.tool_errors,input_connections:g,position:$(f.element).position(),annotation:f.annotation,post_job_actions:f.post_job_actions,workflow_outputs:f.workflow_outputs};a[f.id]=d});return{steps:a}},from_simple:function(b){wf=this;var c=0;wf.name=b.name;var a=false;$.each(b.steps,function(g,f){var d=prebuild_node("tool",f.name,f.tool_id);d.init_field_data(f);if(f.position){d.element.css({top:f.position.top,left:f.position.left})}d.id=f.id;wf.nodes[d.id]=d;c=Math.max(c,parseInt(g));if(!a&&d.type==="tool"){if(d.workflow_outputs.length>0){a=true}else{$.each(d.post_job_actions,function(i,h){if(h.action_type==="HideDatasetAction"){a=true}})}}});wf.id_counter=c+1;$.each(b.steps,function(g,f){var d=wf.nodes[g];$.each(f.input_connections,function(i,h){if(h){if($.isArray(h)){$.each(h,function(m,k){var n=wf.nodes[k.id];var o=new Connector();o.connect(n.output_terminals[k.output_name],d.input_terminals[i]);o.redraw()})}else{var j=wf.nodes[h.id];var l=new Connector();l.connect(j.output_terminals[h.output_name],d.input_terminals[i]);l.redraw()}}});if(a&&d.type==="tool"){$.each(d.output_terminals,function(h,i){if(d.post_job_actions["HideDatasetAction"+i.name]===undefined){d.workflow_outputs.push(i.name);callout=$(d.element).find(".callout."+i.name);callout.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png");workflow.has_changes=true}})}})},check_changes_in_active_form:function(){if(this.active_form_has_changes){this.has_changes=true;$("#right-content").find("form").submit();this.active_form_has_changes=false}},reload_active_node:function(){if(this.active_node){var a=this.active_node;this.clear_active_node();this.activate_node(a)}},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.check_changes_in_active_form();this.clear_active_node();parent.show_form_for_tool(a.form_html+a.tooltip,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){this.check_changes_in_active_form();parent.show_form_for_tool(a.form_html+a.tooltip,a)}},layout:function(){this.check_changes_in_active_form();this.has_changes=true;var i={};var b={};$.each(this.nodes,function(l,k){if(i[l]===undefined){i[l]=0}if(b[l]===undefined){b[l]=[]}});$.each(this.nodes,function(l,k){$.each(k.input_terminals,function(m,n){$.each(n.connectors,function(p,q){var o=q.handle1.node;i[k.id]+=1;b[o.id].push(k.id)})})});node_ids_by_level=[];while(true){level_parents=[];for(var a in i){if(i[a]==0){level_parents.push(a)}}if(level_parents.length==0){break}node_ids_by_level.push(level_parents);for(var f in level_parents){var j=level_parents[f];delete i[j];for(var g in b[j]){i[b[j][g]]-=1}}}if(i.length){return}var d=this.nodes;var h=80;v_pad=30;var c=h;$.each(node_ids_by_level,function(k,l){l.sort(function(p,o){return $(d[p].element).position().top-$(d[o].element).position().top});var m=0;var n=v_pad;$.each(l,function(o,r){var q=d[r];var p=$(q.element);$(p).css({top:n,left:c});m=Math.max(m,$(p).width());n+=$(p).height()+v_pad});c+=m+h});$.each(d,function(k,l){l.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(h,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var i=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var h=fix_delta(a.ymin,100);d=Math.max(d,f.left);h=Math.max(h,f.top);var c=f.left-d;var g=f.top-h;var b=round_up(a.xmax+100,100)+d;var j=round_up(a.ymax+100,100)+h;b=Math.max(b,-c+i.width());j=Math.max(j,-g+i.height());this.canvas_container.css({left:c,top:g,width:b,height:j});this.canvas_container.children().each(function(){var k=$(this).position();$(this).css("left",k.left+d);$(this).css("top",k.top+h)})}});function fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(l,j,r){var i=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node(i);g.type=l;if(l=="tool"){g.tool_id=r}var n=$("<div class='toolFormTitle unselectable'>"+j+"</div>");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("<div class='toolFormBody'></div>");var h="<div><img height='16' align='middle' src='"+galaxy_config.root+"static/images/loading_small_white_bg.gif'/> loading tool info...</div>";m.append(h);g.form_html=h;i.append(m);var k=$("<div class='buttons' style='float: right;'></div>");k.append($("<img/>").attr("src",galaxy_config.root+"static/images/delete_icon.png").click(function(b){g.destroy()}).hover(function(){$(this).attr("src",galaxy_config.root+"static/images/delete_icon_dark.png")},function(){$(this).attr("src",galaxy_config.root+"static/images/delete_icon.png")}));i.appendTo("#canvas-container");var d=$("#canvas-container").position();var c=$("#canvas-container").parent();var a=i.width();var q=i.height();i.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(q/2)});k.prependTo(n);a+=(k.width()+10);i.css("width",a);$(i).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o,p){var f=$(this).offsetParent().offset(),b=p.offsetX-f.left,s=p.offsetY-f.top;$(this).css({left:b,top:s});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(v,d){clearTimeout(this.timeout);var k=v.pageX,j=v.pageY,l=$(this.panel),c=l.position(),b=l.width(),i=l.height(),w=l.parent(),s=w.width(),a=w.height(),r=w.offset(),p=r.left,m=r.top,A=p+w.width(),u=m+w.height(),B=-(b-(s/2)),z=-(i-(a/2)),g=(s/2),f=(a/2),h=false,q=5,o=23;if(k-q<p){if(c.left<g){var n=Math.min(o,g-c.left);l.css("left",c.left+n);h=true}}else{if(k+q>A){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-q<m){if(c.top<f){var n=Math.min(o,f-c.top);l.css("top",c.top+n);h=true}}else{if(j+q>u){if(c.top>z){var n=Math.min(o,c.top-B);l.css("top",(c.top-n)+"px");h=true}}}}}if(h){d();var l=this;this.timeout=setTimeout(function(){l.test(v,d)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(){var g=$(this).offset();var f=b.cc.position();c=f.top-g.top;d=f.left-g.left}).bind("drag",function(f,g){a(g.offsetX+d,g.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("drag",function(k,l){var h=b.cc.width(),n=b.cc.height(),m=b.oc.width(),j=b.oc.height(),f=$(this).offsetParent().offset(),i=l.offsetX-f.left,g=l.offsetY-f.top;a(-(i/m*h),-(g/j*n))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g,i){var j=$(this).offsetParent();var h=j.offset();var f=Math.max(j.width()-(i.offsetX-h.left),j.height()-(i.offsetY-h.top));$(this).css({width:f,height:f});b.draw_overview()});$("#overview-border div").bind("drag",function(){})},update_viewport_overlay:function(){var b=this.cc,f=this.cv,a=this.oc,c=this.ov,d=b.width(),j=b.height(),i=a.width(),g=a.height(),h=b.position();c.css({left:-(h.left/d*i),top:-(h.top/j*g),width:(f.width()/d*i)-2,height:(f.height()/j*g)-2})},draw_overview:function(){var j=$("#overview-canvas"),m=j.parent().parent().width(),i=j.get(0).getContext("2d"),d=$("#canvas-container").width(),l=$("#canvas-container").height();var g,a,k,f;var h=this.cv.width();var b=this.cv.height();if(d<h&&l<b){k=d/h*m;f=(m-k)/2;g=l/b*m;a=(m-g)/2}else{if(d<l){a=0;g=m;k=Math.ceil(g*d/l);f=(m-k)/2}else{k=m;f=0;g=Math.ceil(k*l/d);a=(m-g)/2}}j.parent().css({left:f,top:a,width:k,height:g});j.attr("width",k);j.attr("height",g);$.each(workflow.nodes,function(t,q){i.fillStyle="#D2C099";i.strokeStyle="#D8B365";i.lineWidth=1;var s=$(q.element),n=s.position(),c=n.left/d*k,r=n.top/l*g,o=s.width()/d*k,p=s.height()/l*g;if(q.tool_errors){i.fillStyle="#FFCCCC";i.strokeStyle="#AA6666"}else{if(q.workflow_outputs!=undefined&&q.workflow_outputs.length>0){i.fillStyle="#E8A92D";i.strokeStyle="#E8A92D"}}i.fillRect(c,r,o,p);i.strokeRect(c,r,o,p)});this.update_viewport_overlay()}});
\ No newline at end of file
+function Terminal(a){this.element=a;this.connectors=[]}$.extend(Terminal.prototype,{connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}});function OutputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}OutputTerminal.prototype=new Terminal();function InputTerminal(b,c,a){Terminal.call(this,b);this.datatypes=c;this.multiple=a}InputTerminal.prototype=new Terminal();$.extend(InputTerminal.prototype,{can_accept:function(a){if(this.connectors.length<1||this.multiple){for(var c in this.datatypes){var f=new Array();f=f.concat(a.datatypes);if(a.node.post_job_actions){for(var d in a.node.post_job_actions){var g=a.node.post_job_actions[d];if(g.action_type=="ChangeDatatypeAction"&&(g.output_name==""||g.output_name==a.name)&&g.action_arguments){f.push(g.action_arguments.newtype)}}}for(var b in f){if(f[b]=="input"||issubtype(f[b],this.datatypes[c])){return true}}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a){this.connect(b,a)}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;if(this.handle1){this.handle1.connect(this)}this.handle2=a;if(this.handle2){this.handle2.connect(this)}},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var n=function(c){return $(c).offset().left-d.offset().left};var i=function(c){return $(c).offset().top-d.offset().top};if(!this.handle1||!this.handle2){return}var h=n(this.handle1.element)+5;var g=i(this.handle1.element)+5;var p=n(this.handle2.element)+5;var m=i(this.handle2.element)+5;var f=100;var k=Math.min(h,p);var a=Math.max(h,p);var j=Math.min(g,m);var t=Math.max(g,m);var b=Math.min(Math.max(Math.abs(t-j)/2,100),300);var o=k-f;var s=j-f;var q=a-k+2*f;var l=t-j+2*f;this.canvas.style.left=o+"px";this.canvas.style.top=s+"px";this.canvas.setAttribute("width",q);this.canvas.setAttribute("height",l);h-=o;g-=s;p-=o;m-=s;var r=this.canvas.getContext("2d");r.lineCap="round";r.strokeStyle=this.outer_color;r.lineWidth=7;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke();r.strokeStyle=this.inner_color;r.lineWidth=5;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{enable_input_terminal:function(f,b,c,a){var d=this;$(f).each(function(){var g=this.terminal=new InputTerminal(this,c,a);g.node=d;g.name=b;$(this).bind("dropinit",function(h,i){return $(i.drag).hasClass("output-terminal")&&g.can_accept(i.drag.terminal)}).bind("dropstart",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#BBFFBB"}}).bind("dropend",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#FFFFFF"}}).bind("drop",function(h,i){(new Connector(i.drag.terminal,g)).redraw()}).bind("hover",function(){if(g.connectors.length>0){var h=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='button'></div>").append($("<div/>").addClass("fa-icon-button fa-icon-remove").click(function(){$.each(g.connectors,function(j,i){if(i){i.destroy()}});h.remove()}))).bind("mouseleave",function(){$(this).remove()});h.css({top:$(this).offset().top-2,left:$(this).offset().left-h.width(),"padding-right":$(this).width()}).show()}});d.input_terminals[b]=g})},enable_output_terminal:function(d,a,b){var c=this;$(d).each(function(){var g=this;var f=this.terminal=new OutputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dragstart",function(j,k){$(k.available).addClass("input-terminal-active");workflow.check_changes_in_active_form();var i=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);i.terminal=new OutputTerminal(i);var l=new Connector();l.dragging=true;l.connect(this.terminal,i.terminal);return i}).bind("drag",function(i,j){var h=function(){var l=$(j.proxy).offsetParent().offset(),k=j.offsetX-l.left,m=j.offsetY-l.top;$(j.proxy).css({left:k,top:m});j.proxy.terminal.redraw();canvas_manager.update_viewport_overlay()};h();$("#canvas-container").get(0).scroll_panel.test(i,h)}).bind("dragend",function(h,i){i.proxy.terminal.connectors[0].destroy();$(i.proxy).remove();$(i.available).removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()});c.output_terminals[a]=f})},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(h){var g=this.element;if(h.type){this.type=h.type}this.name=h.name;this.form_html=h.form_html;this.tool_state=h.tool_state;this.tool_errors=h.tool_errors;this.tooltip=h.tooltip?h.tooltip:"";this.annotation=h.annotation;this.post_job_actions=h.post_job_actions?h.post_job_actions:{};this.workflow_outputs=h.workflow_outputs?h.workflow_outputs:[];if(this.tool_errors){g.addClass("tool-node-error")}else{g.removeClass("tool-node-error")}var d=this;var c=Math.max(150,g.width());var a=g.find(".toolFormBody");a.find("div").remove();var i=$("<div class='inputs'></div>").appendTo(a);$.each(h.data_inputs,function(k,f){var j=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(j,f.name,f.extensions,f.multiple);var b=$("<div class='form-row dataRow input-data-row' name='"+f.name+"'>"+f.label+"</div>");b.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(b);c=Math.max(c,b.outerWidth());b.css({position:"",left:"",top:"",display:""});b.remove();i.append(b.prepend(j))});if((h.data_inputs.length>0)&&(h.data_outputs.length>0)){a.append($("<div class='rule'></div>"))}$.each(h.data_outputs,function(k,b){var j=$("<div class='terminal output-terminal'></div>");d.enable_output_terminal(j,b.name,b.extensions);var f=b.name;if(b.extensions.indexOf("input")<0){f=f+" ("+b.extensions.join(", ")+")"}var m=$("<div class='form-row dataRow'>"+f+"</div>");if(d.type=="tool"){var l=$("<div class='callout "+f+"'></div>").css({display:"none"}).append($("<div class='buttons'></div>").append($("<img/>").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png").click(function(){if($.inArray(b.name,d.workflow_outputs)!=-1){d.workflow_outputs.splice($.inArray(b.name,d.workflow_outputs),1);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{d.workflow_outputs.push(b.name);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}workflow.has_changes=true;canvas_manager.draw_overview()}))).tooltip({delay:500,title:"Flag this as a workflow output. All non-flagged outputs will be hidden."});l.css({top:"50%",margin:"-8px 0px 0px 0px",right:8});l.show();m.append(l);if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}m.hover(function(){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-yellow.png")},function(){if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}})}m.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(m);c=Math.max(c,m.outerWidth()+17);m.css({position:"",left:"",top:"",display:""});m.detach();a.append(m.append(j))});g.css("width",Math.min(250,Math.max(g.width(),c)));workflow.node_changed(this)},update_field_data:function(f){var c=$(this.element),d=this;this.tool_state=f.tool_state;this.form_html=f.form_html;this.tool_errors=f.tool_errors;this.annotation=f.annotation;var g=$.parseJSON(f.post_job_actions);this.post_job_actions=g?g:{};if(this.tool_errors){c.addClass("tool-node-error")}else{c.removeClass("tool-node-error")}var h=c.find("div.inputs");var b=$("<div class='inputs'></div>");var a=h.find("div.input-data-row");$.each(f.data_inputs,function(l,j){var k=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(k,j.name,j.extensions,j.multiple);h.find("div[name='"+j.name+"']").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){k[0].terminal.connectors[0]=i;i.handle2=k[0].terminal}});$(this).remove()});b.append($("<div class='form-row dataRow input-data-row' name='"+j.name+"'>"+j.label+"</div>").prepend(k))});h.replaceWith(b);h.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.changed();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},changed:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false;this.active_form_has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},rectify_workflow_outputs:function(){var b=false;var a=false;$.each(this.nodes,function(c,d){if(d.workflow_outputs&&d.workflow_outputs.length>0){b=true}$.each(d.post_job_actions,function(g,f){if(f.action_type==="HideDatasetAction"){a=true}})});if(b!==false||a!==false){$.each(this.nodes,function(c,g){if(g.type==="tool"){var f=false;if(g.post_job_actions==null){g.post_job_actions={};f=true}var d=[];$.each(g.post_job_actions,function(i,h){if(h.action_type=="HideDatasetAction"){d.push(i)}});if(d.length>0){$.each(d,function(h,j){f=true;delete g.post_job_actions[j]})}if(b){$.each(g.output_terminals,function(i,j){var h=true;$.each(g.workflow_outputs,function(l,m){if(j.name===m){h=false}});if(h===true){f=true;var k={action_type:"HideDatasetAction",output_name:j.name,action_arguments:{}};g.post_job_actions["HideDatasetAction"+j.name]=null;g.post_job_actions["HideDatasetAction"+j.name]=k}})}if(workflow.active_node==g&&f===true){workflow.reload_active_node()}}})}},to_simple:function(){var a={};$.each(this.nodes,function(c,f){var g={};$.each(f.input_terminals,function(i,j){g[j.name]=null;var h=[];$.each(j.connectors,function(k,l){h[k]={id:l.handle1.node.id,output_name:l.handle1.name};g[j.name]=h})});var b={};if(f.post_job_actions){$.each(f.post_job_actions,function(j,h){var k={action_type:h.action_type,output_name:h.output_name,action_arguments:h.action_arguments};b[h.action_type+h.output_name]=null;b[h.action_type+h.output_name]=k})}if(!f.workflow_outputs){f.workflow_outputs=[]}var d={id:f.id,type:f.type,tool_id:f.tool_id,tool_state:f.tool_state,tool_errors:f.tool_errors,input_connections:g,position:$(f.element).position(),annotation:f.annotation,post_job_actions:f.post_job_actions,workflow_outputs:f.workflow_outputs};a[f.id]=d});return{steps:a}},from_simple:function(b){wf=this;var c=0;wf.name=b.name;var a=false;$.each(b.steps,function(g,f){var d=prebuild_node("tool",f.name,f.tool_id);d.init_field_data(f);if(f.position){d.element.css({top:f.position.top,left:f.position.left})}d.id=f.id;wf.nodes[d.id]=d;c=Math.max(c,parseInt(g));if(!a&&d.type==="tool"){if(d.workflow_outputs.length>0){a=true}else{$.each(d.post_job_actions,function(i,h){if(h.action_type==="HideDatasetAction"){a=true}})}}});wf.id_counter=c+1;$.each(b.steps,function(g,f){var d=wf.nodes[g];$.each(f.input_connections,function(i,h){if(h){if($.isArray(h)){$.each(h,function(m,k){var n=wf.nodes[k.id];var o=new Connector();o.connect(n.output_terminals[k.output_name],d.input_terminals[i]);o.redraw()})}else{var j=wf.nodes[h.id];var l=new Connector();l.connect(j.output_terminals[h.output_name],d.input_terminals[i]);l.redraw()}}});if(a&&d.type==="tool"){$.each(d.output_terminals,function(h,i){if(d.post_job_actions["HideDatasetAction"+i.name]===undefined){d.workflow_outputs.push(i.name);callout=$(d.element).find(".callout."+i.name);callout.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png");workflow.has_changes=true}})}})},check_changes_in_active_form:function(){if(this.active_form_has_changes){this.has_changes=true;$("#right-content").find("form").submit();this.active_form_has_changes=false}},reload_active_node:function(){if(this.active_node){var a=this.active_node;this.clear_active_node();this.activate_node(a)}},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.check_changes_in_active_form();this.clear_active_node();parent.show_form_for_tool(a.form_html+a.tooltip,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){this.check_changes_in_active_form();parent.show_form_for_tool(a.form_html+a.tooltip,a)}},layout:function(){this.check_changes_in_active_form();this.has_changes=true;var i={};var b={};$.each(this.nodes,function(l,k){if(i[l]===undefined){i[l]=0}if(b[l]===undefined){b[l]=[]}});$.each(this.nodes,function(l,k){$.each(k.input_terminals,function(m,n){$.each(n.connectors,function(p,q){var o=q.handle1.node;i[k.id]+=1;b[o.id].push(k.id)})})});node_ids_by_level=[];while(true){level_parents=[];for(var a in i){if(i[a]==0){level_parents.push(a)}}if(level_parents.length==0){break}node_ids_by_level.push(level_parents);for(var f in level_parents){var j=level_parents[f];delete i[j];for(var g in b[j]){i[b[j][g]]-=1}}}if(i.length){return}var d=this.nodes;var h=80;v_pad=30;var c=h;$.each(node_ids_by_level,function(k,l){l.sort(function(p,o){return $(d[p].element).position().top-$(d[o].element).position().top});var m=0;var n=v_pad;$.each(l,function(o,r){var q=d[r];var p=$(q.element);$(p).css({top:n,left:c});m=Math.max(m,$(p).width());n+=$(p).height()+v_pad});c+=m+h});$.each(d,function(k,l){l.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(h,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var i=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var h=fix_delta(a.ymin,100);d=Math.max(d,f.left);h=Math.max(h,f.top);var c=f.left-d;var g=f.top-h;var b=round_up(a.xmax+100,100)+d;var j=round_up(a.ymax+100,100)+h;b=Math.max(b,-c+i.width());j=Math.max(j,-g+i.height());this.canvas_container.css({left:c,top:g,width:b,height:j});this.canvas_container.children().each(function(){var k=$(this).position();$(this).css("left",k.left+d);$(this).css("top",k.top+h)})}});function fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(l,j,r){var i=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node(i);g.type=l;if(l=="tool"){g.tool_id=r}var n=$("<div class='toolFormTitle unselectable'>"+j+"</div>");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("<div class='toolFormBody'></div>");var h="<div><img height='16' align='middle' src='"+galaxy_config.root+"static/images/loading_small_white_bg.gif'/> loading tool info...</div>";m.append(h);g.form_html=h;i.append(m);var k=$("<div class='buttons' style='float: right;'></div>");k.append($("<div>").addClass("fa-icon-button fa-icon-remove").click(function(b){g.destroy()}));i.appendTo("#canvas-container");var d=$("#canvas-container").position();var c=$("#canvas-container").parent();var a=i.width();var q=i.height();i.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(q/2)});k.prependTo(n);a+=(k.width()+10);i.css("width",a);$(i).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o,p){var f=$(this).offsetParent().offset(),b=p.offsetX-f.left,s=p.offsetY-f.top;$(this).css({left:b,top:s});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(v,d){clearTimeout(this.timeout);var k=v.pageX,j=v.pageY,l=$(this.panel),c=l.position(),b=l.width(),i=l.height(),w=l.parent(),s=w.width(),a=w.height(),r=w.offset(),p=r.left,m=r.top,A=p+w.width(),u=m+w.height(),B=-(b-(s/2)),z=-(i-(a/2)),g=(s/2),f=(a/2),h=false,q=5,o=23;if(k-q<p){if(c.left<g){var n=Math.min(o,g-c.left);l.css("left",c.left+n);h=true}}else{if(k+q>A){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-q<m){if(c.top<f){var n=Math.min(o,f-c.top);l.css("top",c.top+n);h=true}}else{if(j+q>u){if(c.top>z){var n=Math.min(o,c.top-B);l.css("top",(c.top-n)+"px");h=true}}}}}if(h){d();var l=this;this.timeout=setTimeout(function(){l.test(v,d)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(){var g=$(this).offset();var f=b.cc.position();c=f.top-g.top;d=f.left-g.left}).bind("drag",function(f,g){a(g.offsetX+d,g.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("drag",function(k,l){var h=b.cc.width(),n=b.cc.height(),m=b.oc.width(),j=b.oc.height(),f=$(this).offsetParent().offset(),i=l.offsetX-f.left,g=l.offsetY-f.top;a(-(i/m*h),-(g/j*n))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g,i){var j=$(this).offsetParent();var h=j.offset();var f=Math.max(j.width()-(i.offsetX-h.left),j.height()-(i.offsetY-h.top));$(this).css({width:f,height:f});b.draw_overview()});$("#overview-border div").bind("drag",function(){})},update_viewport_overlay:function(){var b=this.cc,f=this.cv,a=this.oc,c=this.ov,d=b.width(),j=b.height(),i=a.width(),g=a.height(),h=b.position();c.css({left:-(h.left/d*i),top:-(h.top/j*g),width:(f.width()/d*i)-2,height:(f.height()/j*g)-2})},draw_overview:function(){var j=$("#overview-canvas"),m=j.parent().parent().width(),i=j.get(0).getContext("2d"),d=$("#canvas-container").width(),l=$("#canvas-container").height();var g,a,k,f;var h=this.cv.width();var b=this.cv.height();if(d<h&&l<b){k=d/h*m;f=(m-k)/2;g=l/b*m;a=(m-g)/2}else{if(d<l){a=0;g=m;k=Math.ceil(g*d/l);f=(m-k)/2}else{k=m;f=0;g=Math.ceil(k*l/d);a=(m-g)/2}}j.parent().css({left:f,top:a,width:k,height:g});j.attr("width",k);j.attr("height",g);$.each(workflow.nodes,function(t,q){i.fillStyle="#D2C099";i.strokeStyle="#D8B365";i.lineWidth=1;var s=$(q.element),n=s.position(),c=n.left/d*k,r=n.top/l*g,o=s.width()/d*k,p=s.height()/l*g;if(q.tool_errors){i.fillStyle="#FFCCCC";i.strokeStyle="#AA6666"}else{if(q.workflow_outputs!=undefined&&q.workflow_outputs.length>0){i.fillStyle="#E8A92D";i.strokeStyle="#E8A92D"}}i.fillRect(c,r,o,p);i.strokeRect(c,r,o,p)});this.update_viewport_overlay()}});
\ No newline at end of file
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b static/scripts/utils/galaxy.uploadbox.js
--- a/static/scripts/utils/galaxy.uploadbox.js
+++ b/static/scripts/utils/galaxy.uploadbox.js
@@ -1,5 +1,5 @@
/*
- galaxy upload lib v1.0 - uses FileReader, FormData and XMLHttpRequest
+ galaxy upload lib - uses FileReader, FormData and XMLHttpRequest
*/
;(function($)
{
@@ -11,67 +11,71 @@
{
url : '',
paramname : 'content',
- maxfilesize : 2048,
- data : {},
+ maxfilesize : 250,
dragover : function() {},
dragleave : function() {},
+ announce : function() {},
initialize : function() {},
- start : function() {},
progress : function() {},
success : function() {},
error : function(index, file, message) { alert(message); },
error_browser : "Your browser does not support drag-and-drop file uploads.",
- error_filesize : "This file is too large. Please use an FTP client to upload it.",
- error_default : "The upload failed. Please make sure the file is available and accessible.",
- text_default : "Drag&drop files here or click to browse your local drive.",
- text_degrade : "Click here to browse your local drive. <br><br>Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Please upgrade to i.e. Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+."
+ error_filesize : "This file is too large (>250MB). Please use an FTP client to upload it.",
+ error_default : "Please make sure the file is available.",
+ text_default : "Drag&drop files into this box or click 'Select' to select files!",
+ text_degrade : "Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Please upgrade to i.e. Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+."
}
- // global file queue
- var queue = [];
+ // options
+ var opts = {};
+
+ // file queue
+ var queue = {};
- // global counter for file being currently processed
- var queue_index = -1;
+ // counter for file being currently processed
+ var queue_index = 0;
- // global queue status
+ // queue length
+ var queue_length = 0;
+
+ // indicates if queue is currently running
var queue_status = false;
+ // element
+ var el = null;
+
// attach to element
$.fn.uploadbox = function(options)
{
// parse options
- var opts = $.extend({}, default_opts, options);
+ opts = $.extend({}, default_opts, options);
// compatibility
var mode = window.File && window.FileReader && window.FormData && window.XMLHttpRequest;
+ // element
+ el = this;
+
// append upload button
- this.append('<input id="uploadbox_input" type="file" style="display: none" multiple>');
- this.append('<div id="uploadbox_info"></div>');
+ el.append('<input id="uploadbox_input" type="file" style="display: none" multiple>');
+ el.append('<div id="uploadbox_info"></div>');
// set info text
if (mode)
- this.find('#uploadbox_info').html(opts.text_default);
+ el.find('#uploadbox_info').html(opts.text_default);
else
- this.find('#uploadbox_info').html(opts.text_degrade);
+ el.find('#uploadbox_info').html(opts.text_degrade);
// attach events
- this.on('drop', drop);
- this.on('dragover', dragover);
- this.on('dragleave', dragleave);
-
- // attach click event
- this.on('click', function(e)
- {
- e.stopPropagation();
- $('#uploadbox_input').trigger(e);
- });
+ el.on('drop', drop);
+ el.on('dragover', dragover);
+ el.on('dragleave', dragleave);
// attach change event
$('#uploadbox_input').change(function(e)
{
- var files = e.target.files;
- upload(files);
+ // add files to queue
+ add(e.target.files);
});
// drop event
@@ -81,11 +85,8 @@
if(!e.dataTransfer)
return;
- // get files from event
- var files = e.dataTransfer.files;
-
- // start upload
- upload(files);
+ // add files to queue
+ add(e.dataTransfer.files);
// prevent default
e.preventDefault();
@@ -98,14 +99,14 @@
function dragover(e)
{
e.preventDefault();
- opts.dragover.call(this, e);
+ opts.dragover.call(e);
}
// drag leave
function dragleave(e)
{
e.stopPropagation();
- opts.dragleave.call(this, e);
+ opts.dragleave.call(e);
}
// progress
@@ -117,39 +118,61 @@
}
// respond to an upload request
- function upload(files)
+ function add(files)
{
- // get current queue size
- var queue_sofar = queue.length;
+ // add new files to queue
+ for (var i = 0; i < files.length; i++)
+ {
+ // new identifier
+ var index = String(++queue_index);
- // add new files to queue
- for (var index = 0; index < files.length; index++)
- queue.push(files[index]);
+ // add to queue
+ queue[index] = files[i];
- // tell client about new uploads
- for (var index = queue_sofar; index < queue.length; index++)
- opts.start(index, queue[index], "");
+ // increase counter
+ queue_length++;
- // initiate processing loop if process loop is not running already
- if (!queue_status)
- process();
+ // announce
+ opts.announce(index, queue[index], "");
+ }
}
+ // remove entry from queue
+ function remove(index)
+ {
+ if (queue[index])
+ {
+ // remove from queue
+ delete queue[index];
+
+ // update counter
+ queue_length--;
+ }
+ }
+
// process an upload, recursive
function process()
{
- // check if for files
- if (queue_index + 1 == queue.length)
+ // get an identifier from the queue
+ var index = -1;
+ for (var key in queue)
{
- queue_status = false;
- return;
+ index = key;
+ break;
}
- // set status
- queue_status = true;
+ // validate
+ if (queue_length == 0)
+ return;
- // identify current index
- var index = ++queue_index;
+ // get current file from queue
+ var file = queue[index];
+
+ // remove from queue
+ remove(index)
+
+ // start
+ var data = opts.initialize(index, file, length);
// add file to queue
try
@@ -158,50 +181,45 @@
var reader = new FileReader();
// identify maximum file size
- var file = queue[index];
var filesize = file.size;
var maxfilesize = 1048576 * opts.maxfilesize;
-
+
// set index
reader.index = index;
if (filesize < maxfilesize)
{
- // link loadend is always called at the end
- reader.onloadend = function(e)
+ // link load
+ reader.onload = function(e)
{
- send(index, file)
+ send(index, file, data)
};
// link error
reader.onerror = function(e)
{
- opts.error(index, file, opts.error_default);
- queue_status = false;
+ error(index, file, opts.error_default);
};
// read data
reader.readAsDataURL(file);
} else {
// skip file
- opts.error(index, file, opts.error_filesize);
-
- // restart process
- process();
+ error(index, file, opts.error_filesize);
}
} catch (err)
{
// parse error
- opts.error(index, file, err);
+ error(index, file, err);
}
}
// send file
- function send (index, file)
+ function send (index, file, data)
{
// construct form data
var formData = new FormData();
- for (var key in opts.data)
- formData.append(key, opts.data[key]);
+ for (var key in data)
+ formData.append(key, data[key]);
formData.append(opts.paramname, file, file.name);
// prepare request
@@ -237,22 +255,94 @@
// pass any error to the error option
if (xhr.status < 200 || xhr.status > 299)
{
+ // format error
+ var text = xhr.statusText;
+ if (!xhr.statusText)
+ text = opts.error_default;
+
// request error
- opts.error(index, file, xhr.statusText + " (Server Code " + xhr.status + ")");
-
- // reset status
- queue_status = false;
- } else {
+ error(index, file, text + " (Server Code " + xhr.status + ")");
+ } else
// parse response
- opts.success(index, file, response);
-
- // upload next file
- process();
- }
+ success(index, file, response);
}
}
- // return
- return this;
+ // success
+ function success (index, file, msg)
+ {
+ // parse message
+ opts.success(index, file, msg);
+
+ // restart process after success
+ process();
+ }
+
+ // error
+ function error (index, file, err)
+ {
+ // parse error
+ opts.error(index, file, err);
+
+ // restart process after error
+ process();
+ }
+
+ /*
+ public interface
+ */
+
+ // open file browser for selection
+ function select()
+ {
+ $('#uploadbox_input').trigger('click');
+ }
+
+ // remove all entries from queue
+ function reset(index)
+ {
+ for (index in queue)
+ remove(index);
+ }
+
+ // initiate upload process
+ function upload()
+ {
+ if (!queue_status)
+ process();
+ }
+
+ // current queue length
+ function length()
+ {
+ return queue_length;
+ }
+
+ // set options
+ function configure(options)
+ {
+ // update current configuration
+ opts = $.extend({}, opts, options);
+
+ // return new configuration
+ return opts;
+ }
+
+ // visibility of on screen information
+ function info()
+ {
+ return el.find('#uploadbox_info');
+ }
+
+ // export functions
+ return {
+ 'select' : select,
+ 'remove' : remove,
+ 'upload' : upload,
+ 'reset' : reset,
+ 'length' : length,
+ 'configure' : configure,
+ 'info' : info
+ };
}
})(jQuery);
\ No newline at end of file
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1123,15 +1123,12 @@
.galaxy-frame .frame .f-close{right:5px;top:1px}
.galaxy-frame .frame .f-pin{left:6px;top:1px}
.galaxy-frame .frame .f-resize{background:#fff;width:16px;height:16px;color:#2c3143;right:0px;bottom:0px;text-align:center;line-height:16px;border:0px}
-.galaxy-upload-box{width:100%;height:200px;max-height:200px;padding:10px 0px 0px 0px;text-align:center;cursor:pointer;overflow:scroll;font-size:12px;line-height:1.428571429;-moz-border-radius:5px;border-radius:5px;border:1px dashed #bfbfbf}.galaxy-upload-box .corner-soft{-moz-border-radius:3px;border-radius:3px}
-.galaxy-upload-box .shadow{-webkit-box-shadow:0 0 2px rgba(0,0,0,0.3)}
-.galaxy-upload-box .highlight{border:1px dashed #333}
-.galaxy-upload-box .file{position:relative;margin:5px 20px 5px 20px;border:1px solid #bfbfbf;color:#333}.galaxy-upload-box .file .title{margin:3px 130px 0px 5px;text-align:left;overflow:hidden;border:0px}
-.galaxy-upload-box .file .progress-frame{border:0px;margin:0px 5px 3px 5px;height:7px;background:#bfbfbf}
-.galaxy-upload-box .file .progress{background:#5cb85c;height:100%;width:0%}
-.galaxy-upload-box .file .failed{background:#d9534f}
-.galaxy-upload-box .file .error{font-size:11px;text-align:left;overflow:hidden;margin:0px 5px 0px 5px}
-.galaxy-upload-box .file .info{position:absolute;top:4px;right:5px;font-size:11px;text-align:right;overflow:hidden;max-width:100px;max-height:12px}
+.upload-box{width:100%;height:250px;max-height:250px;text-align:center;overflow:scroll;font-size:12px;line-height:1.33;-moz-border-radius:5px;border-radius:5px;border:1px dashed #bfbfbf;padding:20px}.upload-box .panel{display:none}.upload-box .panel .panel-heading{position:relative;height:19px;padding:5px}.upload-box .panel .panel-heading .title{position:absolute;top:2px;font-weight:normal;text-align:left;margin:0px;max-width:300px;overflow:hidden}
+.upload-box .panel .panel-heading .info{position:absolute;top:3px;font-weight:normal;right:20px;text-align:right;margin:0px}
+.upload-box .panel .panel-heading .remove{position:absolute;cursor:pointer;top:0px;right:3px}
+.upload-box .panel .panel-body{position:relative;padding:5px}
+.upload-box .panel .panel-footer{position:relative;height:20px;padding:0px}.upload-box .panel .panel-footer .progress{height:10px;margin:5px}
+.upload-box .panel .panel-footer .error{font-weight:normal;margin:2px}
.unselectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}
.parent-width{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:100%;*width:90%}
.clear:before,.clear:after{content:" ";display:table;}
@@ -1392,9 +1389,9 @@
div.historyItem-setting_metadata{background:#ffc}div.historyItem-setting_metadata .state-icon{background-image:url(data_running.gif)}
div.historyItem-upload{background:#a6e4f7}div.historyItem-upload .state-icon{background-image:url(data_upload.gif)}
div.historyItem-queued{background:#eee}div.historyItem-queued .state-icon{background-image:url(sprite-history-states.png);background-position:0px -45px;width:15px;height:15px;height:15px}
-div.historyItem-noPermission{filter:alpha(opacity=60);-moz-opacity:.60;opacity:.60}
-div.historyItem-paused{background:#d9edf7}div.historyItem-paused .state-icon{font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-paused .state-icon:before{content:"\f04c"}
-div.historyItem-new .state-icon{font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-new .state-icon:before{content:"\f071"}
+div.historyItem-noPermission{filter:alpha(opacity=60);-moz-opacity:.60;opacity:.60}div.historyItem-noPermission .state-icon{line-height:16px;font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-noPermission .state-icon:before{content:"\f05e"}
+div.historyItem-paused{background:#d9edf7}div.historyItem-paused .state-icon{line-height:16px;font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-paused .state-icon:before{content:"\f04c"}
+div.historyItem-new .state-icon{line-height:16px;font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-new .state-icon:before{content:"\f071"}
div.historyItemTitleBar.spinner .state-icon{background:url(data_running.gif) 0 1px no-repeat !important}
div.historyItemButtons{float:right}div.historyItemButtons .icon-button.display{background-image:url(sprite-history-buttons.png);background-position:0px -48px;width:16px;height:16px}
div.historyItemButtons .icon-button.display:hover{background-image:url(sprite-history-buttons.png);background-position:0px -64px;width:16px;height:16px}
diff -r 23abd7b603c873e6e59fe0f73e53210cf45aaa72 -r 66d484a18d198725ab5f388d4e538ac86d9f081b static/style/src/less/base.less
--- a/static/style/src/less/base.less
+++ b/static/style/src/less/base.less
@@ -1509,11 +1509,19 @@
filter: alpha(opacity=60);
-moz-opacity: .60;
opacity: .60;
+ .state-icon {
+ line-height: 16px;
+ .fa-icon();
+ &:before {
+ content: "\f05e";
+ }
+ }
}
div.historyItem-paused {
background: @state-paused-bg;
.state-icon {
+ line-height: 16px;
.fa-icon();
&:before {
content: "\f04c";
@@ -1523,6 +1531,7 @@
div.historyItem-new {
.state-icon {
+ line-height: 16px;
.fa-icon();
&:before {
content: "\f071";
This diff is so big that we needed to truncate the remainder.
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: Style: add icon to inaccessible hda state, tweak vertical align of fa-icon state icons
by commits-noreply@bitbucket.org 20 Sep '13
by commits-noreply@bitbucket.org 20 Sep '13
20 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/96c27525741b/
Changeset: 96c27525741b
User: carlfeberhard
Date: 2013-09-20 22:58:32
Summary: Style: add icon to inaccessible hda state, tweak vertical align of fa-icon state icons
Affected #: 2 files
diff -r c23fb89215ce1d36f23d4806fd04a8153fe6fbe6 -r 96c27525741b7d8773ade063e9cd829b03be211f static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1388,9 +1388,9 @@
div.historyItem-setting_metadata{background:#ffc}div.historyItem-setting_metadata .state-icon{background-image:url(data_running.gif)}
div.historyItem-upload{background:#a6e4f7}div.historyItem-upload .state-icon{background-image:url(data_upload.gif)}
div.historyItem-queued{background:#eee}div.historyItem-queued .state-icon{background-image:url(sprite-history-states.png);background-position:0px -45px;width:15px;height:15px;height:15px}
-div.historyItem-noPermission{filter:alpha(opacity=60);-moz-opacity:.60;opacity:.60}
-div.historyItem-paused{background:#d9edf7}div.historyItem-paused .state-icon{font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-paused .state-icon:before{content:"\f04c"}
-div.historyItem-new .state-icon{font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-new .state-icon:before{content:"\f071"}
+div.historyItem-noPermission{filter:alpha(opacity=60);-moz-opacity:.60;opacity:.60}div.historyItem-noPermission .state-icon{line-height:16px;font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-noPermission .state-icon:before{content:"\f05e"}
+div.historyItem-paused{background:#d9edf7}div.historyItem-paused .state-icon{line-height:16px;font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-paused .state-icon:before{content:"\f04c"}
+div.historyItem-new .state-icon{line-height:16px;font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-new .state-icon:before{content:"\f071"}
div.historyItemTitleBar.spinner .state-icon{background:url(data_running.gif) 0 1px no-repeat !important}
div.historyItemButtons{float:right}div.historyItemButtons .icon-button.display{background-image:url(sprite-history-buttons.png);background-position:0px -48px;width:16px;height:16px}
div.historyItemButtons .icon-button.display:hover{background-image:url(sprite-history-buttons.png);background-position:0px -64px;width:16px;height:16px}
diff -r c23fb89215ce1d36f23d4806fd04a8153fe6fbe6 -r 96c27525741b7d8773ade063e9cd829b03be211f static/style/src/less/base.less
--- a/static/style/src/less/base.less
+++ b/static/style/src/less/base.less
@@ -1509,11 +1509,19 @@
filter: alpha(opacity=60);
-moz-opacity: .60;
opacity: .60;
+ .state-icon {
+ line-height: 16px;
+ .fa-icon();
+ &:before {
+ content: "\f05e";
+ }
+ }
}
div.historyItem-paused {
background: @state-paused-bg;
.state-icon {
+ line-height: 16px;
.fa-icon();
&:before {
content: "\f04c";
@@ -1523,6 +1531,7 @@
div.historyItem-new {
.state-icon {
+ line-height: 16px;
.fa-icon();
&:before {
content: "\f071";
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: HDA API: re-add accessibility check
by commits-noreply@bitbucket.org 20 Sep '13
by commits-noreply@bitbucket.org 20 Sep '13
20 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/c23fb89215ce/
Changeset: c23fb89215ce
User: carlfeberhard
Date: 2013-09-20 22:12:53
Summary: HDA API: re-add accessibility check
Affected #: 1 file
diff -r 3fc486ee887aec89a75097477ba7a4acff0ced1b -r c23fb89215ce1d36f23d4806fd04a8153fe6fbe6 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -587,8 +587,10 @@
hda_dict[ 'api_type' ] = "file"
# Add additional attributes that depend on trans can hence must be added here rather than at the model level.
-
- #NOTE: access is an expensive operation - removing it and adding the precondition of access is already checked
+ can_access_hda = trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), hda.dataset )
+ can_access_hda = ( trans.user_is_admin() or can_access_hda )
+ if not can_access_hda:
+ return self.get_inaccessible_hda_dict( trans, hda )
hda_dict[ 'accessible' ] = True
# ---- return here if deleted AND purged OR can't access
@@ -634,6 +636,18 @@
return trans.security.encode_dict_ids( hda_dict )
+ def get_inaccessible_hda_dict( self, trans, hda ):
+ return trans.security.encode_dict_ids({
+ 'id' : hda.id,
+ 'history_id': hda.history.id,
+ 'hid' : hda.hid,
+ 'name' : hda.name,
+ 'state' : hda.state,
+ 'deleted' : hda.deleted,
+ 'visible' : hda.visible,
+ 'accessible': False
+ })
+
def get_hda_dict_with_error( self, trans, hda, error_msg='' ):
return trans.security.encode_dict_ids({
'id' : hda.id,
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: Saved histories: fix new history creation when deleting a current, empty history
by commits-noreply@bitbucket.org 20 Sep '13
by commits-noreply@bitbucket.org 20 Sep '13
20 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/3fc486ee887a/
Changeset: 3fc486ee887a
User: carlfeberhard
Date: 2013-09-20 20:46:26
Summary: Saved histories: fix new history creation when deleting a current, empty history
Affected #: 2 files
diff -r d4c6a250afd03a942e70f04ee7da8335dfea476b -r 3fc486ee887aec89a75097477ba7a4acff0ced1b lib/galaxy/webapps/galaxy/controllers/history.py
--- a/lib/galaxy/webapps/galaxy/controllers/history.py
+++ b/lib/galaxy/webapps/galaxy/controllers/history.py
@@ -309,7 +309,6 @@
# If deleting the current history, make a new current.
if history == trans.get_history():
deleted_current = True
- trans.get_or_create_default_history()
trans.log_event( "History (%s) marked as deleted" % history.name )
n_deleted += 1
if purge and trans.app.config.allow_user_dataset_purge:
@@ -339,6 +338,8 @@
part += " but the datasets were not removed from disk because that feature is not enabled in this Galaxy instance"
message_parts.append( "%s. " % part )
if deleted_current:
+ #note: this needs to come after commits above or will use an empty history that was deleted above
+ trans.get_or_create_default_history()
message_parts.append( "Your active history was deleted, a new empty history is now active. " )
status = INFO
return ( status, " ".join( message_parts ) )
diff -r d4c6a250afd03a942e70f04ee7da8335dfea476b -r 3fc486ee887aec89a75097477ba7a4acff0ced1b test/functional/test_get_data.py
--- a/test/functional/test_get_data.py
+++ b/test/functional/test_get_data.py
@@ -22,7 +22,7 @@
"""
# in order to remove a lot of boiler plate - and not have cascading errors
history = get_latest_history_for_user( user )
- self.delete_current_history()
+ self.delete_history( id=self.security.encode_id( history.id ) )
self.is_history_empty()
return get_latest_history_for_user( user )
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: Don't check old_style paths in the DiskObjectStore by default.
by commits-noreply@bitbucket.org 20 Sep '13
by commits-noreply@bitbucket.org 20 Sep '13
20 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d4c6a250afd0/
Changeset: d4c6a250afd0
User: natefoo
Date: 2013-09-20 17:10:31
Summary: Don't check old_style paths in the DiskObjectStore by default.
Affected #: 3 files
diff -r ab20415126a768f456314cfe587e4ce71fd2049b -r d4c6a250afd03a942e70f04ee7da8335dfea476b lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -209,6 +209,7 @@
if self.nginx_upload_store:
self.nginx_upload_store = os.path.abspath( self.nginx_upload_store )
self.object_store = kwargs.get( 'object_store', 'disk' )
+ self.object_store_check_old_style = string_as_bool( kwargs.get( 'object_store_check_old_style', False ) )
self.object_store_cache_path = resolve_path( kwargs.get( "object_store_cache_path", "database/object_store_cache" ), self.root )
# Handle AWS-specific config options for backward compatibility
if kwargs.get( 'aws_access_key', None) is not None:
diff -r ab20415126a768f456314cfe587e4ce71fd2049b -r d4c6a250afd03a942e70f04ee7da8335dfea476b lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -198,6 +198,7 @@
super(DiskObjectStore, self).__init__(config, file_path=file_path, extra_dirs=extra_dirs)
self.file_path = file_path or config.file_path
self.config = config
+ self.check_old_style = config.object_store_check_old_style
self.extra_dirs['job_work'] = config.job_working_directory
self.extra_dirs['temp'] = config.new_file_path
if extra_dirs is not None:
@@ -264,14 +265,13 @@
return os.path.abspath(path)
def exists(self, obj, **kwargs):
- path = self._construct_path(obj, old_style=True, **kwargs)
- # For backward compatibility, check root path first; otherwise, construct
- # and check hashed path
- if os.path.exists(path):
- return True
- else:
- path = self._construct_path(obj, **kwargs)
- return os.path.exists(path)
+ if self.check_old_style:
+ path = self._construct_path(obj, old_style=True, **kwargs)
+ # For backward compatibility, check root path first; otherwise, construct
+ # and check hashed path
+ if os.path.exists(path):
+ return True
+ return os.path.exists(self._construct_path(obj, **kwargs))
def create(self, obj, **kwargs):
if not self.exists(obj, **kwargs):
@@ -320,13 +320,13 @@
return content
def get_filename(self, obj, **kwargs):
- path = self._construct_path(obj, old_style=True, **kwargs)
- # For backward compatibility, check root path first; otherwise, construct
- # and return hashed path
- if os.path.exists(path):
- return path
- else:
- return self._construct_path(obj, **kwargs)
+ if self.check_old_style:
+ path = self._construct_path(obj, old_style=True, **kwargs)
+ # For backward compatibility, check root path first; otherwise, construct
+ # and return hashed path
+ if os.path.exists(path):
+ return path
+ return self._construct_path(obj, **kwargs)
def update_from_file(self, obj, file_name=None, create=False, **kwargs):
""" `create` parameter is not used in this implementation """
diff -r ab20415126a768f456314cfe587e4ce71fd2049b -r d4c6a250afd03a942e70f04ee7da8335dfea476b universe_wsgi.ini.sample
--- a/universe_wsgi.ini.sample
+++ b/universe_wsgi.ini.sample
@@ -209,6 +209,12 @@
# distributed, hierarchical)
#object_store = disk
+# *Extremely* old Galaxy instances created datasets at the root of the
+# `file_path` defined above. If your Galaxy instance has datasets at the root
+# (instead of in directories composed by hashing the dataset id), you should
+# enable this option to allow Galaxy to find them.
+#object_store_check_old_style = False
+
# Credentials used by certain (s3, swift) object store backends
#os_access_key = <your cloud object store access key>
#os_secret_key = <your cloud object store secret key>
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
20 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ab20415126a7/
Changeset: ab20415126a7
User: greg
Date: 2013-09-20 17:05:30
Summary: Additional framework support for tool dependencies that define binary installation recipes. This change set also includes several fixes, including fixes for discovering and displaying installed and missing tool dependencies when installing a repository, fixes for the remaining issue that resulted in the creation of a so-called "white ghost" when reinstalling a repository that defines certain dependencies.
Affected #: 15 files
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -25,7 +25,7 @@
from galaxy.datatypes.metadata import MetadataCollection
from galaxy.model.item_attrs import Dictifiable, UsesAnnotations
from galaxy.security import get_permitted_actions
-from galaxy.util import is_multi_byte, nice_size, Params, restore_text, send_mail
+from galaxy.util import asbool, is_multi_byte, nice_size, Params, restore_text, send_mail
from galaxy.util.bunch import Bunch
from galaxy.util.hash_util import new_secure_hash
from galaxy.web.framework.helpers import to_unicode
@@ -34,6 +34,7 @@
WorkflowMappingField)
from sqlalchemy.orm import object_session
from sqlalchemy.sql.expression import func
+from tool_shed.util import common_util
log = logging.getLogger( __name__ )
@@ -3463,7 +3464,28 @@
@property
def has_repository_dependencies( self ):
if self.metadata:
- return 'repository_dependencies' in self.metadata
+ repository_dependencies_dict = self.metadata.get( 'repository_dependencies', {} )
+ repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ # [["http://localhost:9009", "package_libgtextutils_0_6", "test", "e2003cbf18cd", "True", "True"]]
+ for rd_tup in repository_dependencies:
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
+ if not asbool( only_if_compiling_contained_td ):
+ return True
+ return False
+
+ @property
+ def has_repository_dependencies_only_if_compiling_contained_td( self ):
+ if self.metadata:
+ repository_dependencies_dict = self.metadata.get( 'repository_dependencies', {} )
+ repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ # [["http://localhost:9009", "package_libgtextutils_0_6", "test", "e2003cbf18cd", "True", "True"]]
+ for rd_tup in repository_dependencies:
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
+ if not asbool( only_if_compiling_contained_td ):
+ return False
+ return True
return False
@property
@@ -3695,10 +3717,14 @@
@property
def tuples_of_repository_dependencies_needed_for_compiling_td( self ):
- """Return this repository's repository dependencies that are necessary only for compiling this repository's tool dependencies."""
+ """
+ Return tuples defining this repository's repository dependencies that are necessary only for compiling this repository's tool
+ dependencies.
+ """
rd_tups_of_repositories_needed_for_compiling_td = []
- if self.has_repository_dependencies:
- rd_tups = self.metadata[ 'repository_dependencies' ][ 'repository_dependencies' ]
+ if self.metadata:
+ repository_dependencies = self.metadata.get( 'repository_dependencies', None )
+ rd_tups = repository_dependencies[ 'repository_dependencies' ]
for rd_tup in rd_tups:
if len( rd_tup ) == 6:
tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = rd_tup
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -812,7 +812,7 @@
status = kwd.get( 'status', 'done' )
shed_tool_conf = kwd.get( 'shed_tool_conf', None )
tool_shed_url = kwd[ 'tool_shed_url' ]
- # Handle repository dependencies.
+ # Handle repository dependencies, which do not include those that are required only for compiling a dependent repository's tool dependencies.
has_repository_dependencies = util.string_as_bool( kwd.get( 'has_repository_dependencies', False ) )
install_repository_dependencies = kwd.get( 'install_repository_dependencies', '' )
# Every repository will be installed into the same tool panel section or all will be installed outside of any sections.
@@ -1061,7 +1061,7 @@
repository_clone_url,
metadata,
trans.model.ToolShedRepository.installation_status.NEW,
- tool_shed_repository.installed_changeset_revision,
+ tool_shed_repository.changeset_revision,
tool_shed_repository.owner,
tool_shed_repository.dist_to_shed )
ctx_rev = suc.get_ctx_rev( trans.app,
@@ -1320,7 +1320,6 @@
missing_tool_dependencies = dependencies_for_repository_dict.get( 'missing_tool_dependencies', None )
repository_name = dependencies_for_repository_dict.get( 'name', None )
repository_owner = dependencies_for_repository_dict.get( 'repository_owner', None )
-
if installed_repository_dependencies or missing_repository_dependencies:
has_repository_dependencies = True
else:
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/galaxy/webapps/tool_shed/api/repositories.py
--- a/lib/galaxy/webapps/tool_shed/api/repositories.py
+++ b/lib/galaxy/webapps/tool_shed/api/repositories.py
@@ -73,6 +73,7 @@
"changeset_revision": "3a08cc21466f",
"downloadable": true,
"has_repository_dependencies": false,
+ "has_repository_dependencies_only_if_compiling_contained_td": false,
"id": "f9cad7b01a472135",
"includes_datatypes": false,
"includes_tool_dependencies": false,
@@ -125,7 +126,8 @@
action='show',
id=encoded_repository_metadata_id )
# Get the repo_info_dict for installing the repository.
- repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, has_repository_dependencies = \
+ repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, \
+ has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \
repository_util.get_repo_info_dict( trans, encoded_repository_id, changeset_revision )
return repository_dict, repository_metadata_dict, repo_info_dict
else:
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/galaxy/webapps/tool_shed/controllers/repository.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py
@@ -1343,32 +1343,36 @@
def get_changeset_revision_and_ctx_rev( self, trans, **kwd ):
"""Handle a request from a local Galaxy instance to retrieve the changeset revision hash to which an installed repository can be updated."""
def has_galaxy_utilities( repository_metadata ):
- includes_data_managers = False
- includes_datatypes = False
- includes_tools = False
- includes_tools_for_display_in_tool_panel = False
- has_repository_dependencies = False
- includes_tool_dependencies = False
- includes_workflows = False
+ has_galaxy_utilities_dict = dict( includes_data_managers=False,
+ includes_datatypes=False,
+ includes_tools=False,
+ includes_tools_for_display_in_tool_panel=False,
+ has_repository_dependencies=False,
+ has_repository_dependencies_only_if_compiling_contained_td=False,
+ includes_tool_dependencies=False,
+ includes_workflows=False )
if repository_metadata:
includes_tools_for_display_in_tool_panel = repository_metadata.includes_tools_for_display_in_tool_panel
metadata = repository_metadata.metadata
if metadata:
if 'data_manager' in metadata:
- includes_data_managers = True
+ has_galaxy_utilities_dict[ 'includes_data_managers' ] = True
if 'datatypes' in metadata:
- includes_datatypes = True
+ has_galaxy_utilities_dict[ 'includes_datatypes' ] = True
if 'tools' in metadata:
- includes_tools = True
+ has_galaxy_utilities_dict[ 'includes_tools' ] = True
if 'tool_dependencies' in metadata:
- includes_tool_dependencies = True
- if 'repository_dependencies' in metadata:
- has_repository_dependencies = True
+ has_galaxy_utilities_dict[ 'includes_tool_dependencies' ] = True
+ repository_dependencies_dict = metadata.get( 'repository_dependencies', {} )
+ repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \
+ suc.get_repository_dependency_types( repository_dependencies )
+ has_galaxy_utilities_dict[ 'has_repository_dependencies' ] = has_repository_dependencies
+ has_galaxy_utilities_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = \
+ has_repository_dependencies_only_if_compiling_contained_td
if 'workflows' in metadata:
- includes_workflows = True
- return includes_data_managers, includes_datatypes, includes_tools, includes_tools_for_display_in_tool_panel, includes_tool_dependencies, has_repository_dependencies, includes_workflows
- message = kwd.get( 'message', '' )
- status = kwd.get( 'status', 'done' )
+ has_galaxy_utilities_dict[ 'includes_workflows' ] = True
+ return has_galaxy_utilities_dict
name = kwd.get( 'name', None )
owner = kwd.get( 'owner', None )
changeset_revision = kwd.get( 'changeset_revision', None )
@@ -1376,8 +1380,15 @@
repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans,
trans.security.encode_id( repository.id ),
changeset_revision )
- includes_data_managers, includes_datatypes, includes_tools, includes_tools_for_display_in_tool_panel, includes_tool_dependencies, has_repository_dependencies, includes_workflows = \
- has_galaxy_utilities( repository_metadata )
+ has_galaxy_utilities_dict = has_galaxy_utilities( repository_metadata )
+ includes_data_managers = has_galaxy_utilities_dict[ 'includes_data_managers' ]
+ includes_datatypes = has_galaxy_utilities_dict[ 'includes_datatypes' ]
+ includes_tools = has_galaxy_utilities_dict[ 'includes_tools' ]
+ includes_tools_for_display_in_tool_panel = has_galaxy_utilities_dict[ 'includes_tools_for_display_in_tool_panel' ]
+ includes_tool_dependencies = has_galaxy_utilities_dict[ 'includes_tool_dependencies' ]
+ has_repository_dependencies = has_galaxy_utilities_dict[ 'has_repository_dependencies' ]
+ has_repository_dependencies_only_if_compiling_contained_td = has_galaxy_utilities_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ]
+ includes_workflows = has_galaxy_utilities_dict[ 'includes_workflows' ]
repo_dir = repository.repo_path( trans.app )
repo = hg.repository( suc.get_configured_ui(), repo_dir )
# Default to the received changeset revision and ctx_rev.
@@ -1392,6 +1403,7 @@
includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
includes_tool_dependencies=includes_tool_dependencies,
has_repository_dependencies=has_repository_dependencies,
+ has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td,
includes_workflows=includes_workflows )
if changeset_revision == repository.tip( trans.app ):
# If changeset_revision is the repository tip, there are no additional updates.
@@ -1407,6 +1419,7 @@
for changeset in repo.changelog:
includes_tools = False
has_repository_dependencies = False
+ has_repository_dependencies_only_if_compiling_contained_td = False
changeset_hash = str( repo.changectx( changeset ) )
ctx = suc.get_changectx_for_changeset( repo, changeset_hash )
if update_to_changeset_hash:
@@ -1414,8 +1427,15 @@
trans.security.encode_id( repository.id ),
changeset_hash )
if update_to_repository_metadata:
- includes_data_managers, includes_datatypes, includes_tools, includes_tools_for_display_in_tool_panel, includes_tool_dependencies, has_repository_dependencies, includes_workflows = \
- has_galaxy_utilities( update_to_repository_metadata )
+ has_galaxy_utilities_dict = has_galaxy_utilities( repository_metadata )
+ includes_data_managers = has_galaxy_utilities_dict[ 'includes_data_managers' ]
+ includes_datatypes = has_galaxy_utilities_dict[ 'includes_datatypes' ]
+ includes_tools = has_galaxy_utilities_dict[ 'includes_tools' ]
+ includes_tools_for_display_in_tool_panel = has_galaxy_utilities_dict[ 'includes_tools_for_display_in_tool_panel' ]
+ includes_tool_dependencies = has_galaxy_utilities_dict[ 'includes_tool_dependencies' ]
+ has_repository_dependencies = has_galaxy_utilities_dict[ 'has_repository_dependencies' ]
+ has_repository_dependencies_only_if_compiling_contained_td = has_galaxy_utilities_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ]
+ includes_workflows = has_galaxy_utilities_dict[ 'includes_workflows' ]
# We found a RepositoryMetadata record.
if changeset_hash == repository.tip( trans.app ):
# The current ctx is the repository tip, so use it.
@@ -1435,6 +1455,7 @@
update_dict[ 'includes_tool_dependencies' ] = includes_tool_dependencies
update_dict[ 'includes_workflows' ] = includes_workflows
update_dict[ 'has_repository_dependencies' ] = has_repository_dependencies
+ update_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = has_repository_dependencies_only_if_compiling_contained_td
update_dict[ 'changeset_revision' ] = str( latest_changeset_revision )
update_dict[ 'ctx_rev' ] = str( update_to_ctx.rev() )
return encoding_util.tool_shed_encode( update_dict )
@@ -1611,14 +1632,18 @@
includes_tools = False
includes_tools_for_display_in_tool_panel = False
has_repository_dependencies = False
+ has_repository_dependencies_only_if_compiling_contained_td = False
includes_tool_dependencies = False
repo_info_dicts = []
for tup in zip( util.listify( repository_ids ), util.listify( changeset_revisions ) ):
repository_id, changeset_revision = tup
- repo_info_dict, cur_includes_tools, cur_includes_tool_dependencies, cur_includes_tools_for_display_in_tool_panel, cur_has_repository_dependencies = \
+ repo_info_dict, cur_includes_tools, cur_includes_tool_dependencies, cur_includes_tools_for_display_in_tool_panel, \
+ cur_has_repository_dependencies, cur_has_repository_dependencies_only_if_compiling_contained_td = \
repository_util.get_repo_info_dict( trans, repository_id, changeset_revision )
if cur_has_repository_dependencies and not has_repository_dependencies:
has_repository_dependencies = True
+ if cur_has_repository_dependencies_only_if_compiling_contained_td and not has_repository_dependencies_only_if_compiling_contained_td:
+ has_repository_dependencies_only_if_compiling_contained_td = True
if cur_includes_tools and not includes_tools:
includes_tools = True
if cur_includes_tool_dependencies and not includes_tool_dependencies:
@@ -1629,6 +1654,7 @@
return dict( includes_tools=includes_tools,
includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
has_repository_dependencies=has_repository_dependencies,
+ has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td,
includes_tool_dependencies=includes_tool_dependencies,
repo_info_dicts=repo_info_dicts )
@@ -1708,7 +1734,9 @@
tool_version_dicts = []
for changeset in repo.changelog:
current_changeset_revision = str( repo.changectx( changeset ) )
- repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, trans.security.encode_id( repository.id ), current_changeset_revision )
+ repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans,
+ trans.security.encode_id( repository.id ),
+ current_changeset_revision )
if repository_metadata and repository_metadata.tool_versions:
tool_version_dicts.append( repository_metadata.tool_versions )
if current_changeset_revision == changeset_revision:
@@ -1766,22 +1794,30 @@
includes_workflows = True
readme_files_dict = readme_util.build_readme_files_dict( metadata )
# See if the repo_info_dict was populated with repository_dependencies or tool_dependencies.
+ has_repository_dependencies = False
+ has_repository_dependencies_only_if_compiling_contained_td = False
+ includes_tool_dependencies = False
for name, repo_info_tuple in repo_info_dict.items():
- description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
- suc.get_repo_info_tuple_contents( repo_info_tuple )
- if repository_dependencies:
- has_repository_dependencies = True
- else:
- has_repository_dependencies = False
- if tool_dependencies:
- includes_tool_dependencies = True
- else:
- includes_tool_dependencies = False
+ if not has_repository_dependencies or not has_repository_dependencies_only_if_compiling_contained_td or not includes_tool_dependencies:
+ description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
+ suc.get_repo_info_tuple_contents( repo_info_tuple )
+ for rd_key, rd_tups in repository_dependencies.items():
+ if rd_key in [ 'root_key', 'description' ]:
+ continue
+ curr_has_repository_dependencies, curr_has_repository_dependencies_only_if_compiling_contained_td = \
+ suc.get_repository_dependency_types( rd_tups )
+ if curr_has_repository_dependencies and not has_repository_dependencies:
+ has_repository_dependencies = True
+ if curr_has_repository_dependencies_only_if_compiling_contained_td and not has_repository_dependencies_only_if_compiling_contained_td:
+ has_repository_dependencies_only_if_compiling_contained_td = True
+ if tool_dependencies and not includes_tool_dependencies:
+ includes_tool_dependencies = True
return dict( includes_data_managers=includes_data_managers,
includes_datatypes=includes_datatypes,
includes_tools=includes_tools,
includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
has_repository_dependencies=has_repository_dependencies,
+ has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td,
includes_tool_dependencies=includes_tool_dependencies,
includes_workflows=includes_workflows,
readme_files_dict=readme_files_dict,
@@ -2434,7 +2470,9 @@
try:
commands.remove( repo.ui, repo, selected_file, force=True )
except Exception, e:
- log.debug( "Error removing files using the mercurial API, so trying a different approach, the error was: %s" % str( e ))
+ log.debug( "Error removing the following file using the mercurial API:\n %s" % str( selected_file ) )
+ log.debug( "The error was: %s" % str( e ))
+ log.debug( "Attempting to remove the file using a different approach." )
relative_selected_file = selected_file.split( 'repo_%d' % repository.id )[1].lstrip( '/' )
repo.dirstate.remove( relative_selected_file )
repo.dirstate.write()
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/galaxy/webapps/tool_shed/model/__init__.py
--- a/lib/galaxy/webapps/tool_shed/model/__init__.py
+++ b/lib/galaxy/webapps/tool_shed/model/__init__.py
@@ -253,6 +253,7 @@
self.time_last_tested = time_last_tested
self.tool_test_results = tool_test_results
self.has_repository_dependencies = has_repository_dependencies
+ # We don't consider the special case has_repository_dependencies_only_if_compiling_contained_td here.
self.includes_datatypes = includes_datatypes
self.includes_tools = includes_tools
self.includes_tool_dependencies = includes_tool_dependencies
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/galaxy_install/repository_util.py
--- a/lib/tool_shed/galaxy_install/repository_util.py
+++ b/lib/tool_shed/galaxy_install/repository_util.py
@@ -234,10 +234,10 @@
else:
includes_tools = False
includes_tools_for_display_in_tool_panel = repository_metadata.includes_tools_for_display_in_tool_panel
- if 'repository_dependencies' in metadata:
- has_repository_dependencies = True
- else:
- has_repository_dependencies = False
+ repository_dependencies_dict = metadata.get( 'repository_dependencies', {} )
+ repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \
+ suc.get_repository_dependency_types( repository_dependencies )
if 'tool_dependencies' in metadata:
includes_tool_dependencies = True
else:
@@ -246,6 +246,7 @@
# Here's where we may have to handle enhancements to the callers. See above comment.
includes_tools = False
has_repository_dependencies = False
+ has_repository_dependencies_only_if_compiling_contained_td = False
includes_tool_dependencies = False
includes_tools_for_display_in_tool_panel = False
ctx = suc.get_changectx_for_changeset( repo, changeset_revision )
@@ -259,7 +260,8 @@
repository_metadata=repository_metadata,
tool_dependencies=None,
repository_dependencies=None )
- return repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, has_repository_dependencies
+ return repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, \
+ has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td
def get_repository_components_for_installation( encoded_tsr_id, encoded_tsr_ids, repo_info_dicts, tool_panel_section_keys ):
"""
@@ -311,6 +313,7 @@
includes_tool_dependencies = update_dict.get( 'includes_tool_dependencies', False )
includes_workflows = update_dict.get( 'includes_workflows', False )
has_repository_dependencies = update_dict.get( 'has_repository_dependencies', False )
+ has_repository_dependencies_only_if_compiling_contained_td = update_dict.get( 'has_repository_dependencies_only_if_compiling_contained_td', False )
changeset_revision = update_dict.get( 'changeset_revision', None )
ctx_rev = update_dict.get( 'ctx_rev', None )
changeset_revision_dict[ 'includes_data_managers' ] = includes_data_managers
@@ -320,6 +323,7 @@
changeset_revision_dict[ 'includes_tool_dependencies' ] = includes_tool_dependencies
changeset_revision_dict[ 'includes_workflows' ] = includes_workflows
changeset_revision_dict[ 'has_repository_dependencies' ] = has_repository_dependencies
+ changeset_revision_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = has_repository_dependencies_only_if_compiling_contained_td
changeset_revision_dict[ 'changeset_revision' ] = changeset_revision
changeset_revision_dict[ 'ctx_rev' ] = ctx_rev
except Exception, e:
@@ -331,6 +335,7 @@
changeset_revision_dict[ 'includes_tool_dependencies' ] = False
changeset_revision_dict[ 'includes_workflows' ] = False
changeset_revision_dict[ 'has_repository_dependencies' ] = False
+ changeset_revision_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = False
changeset_revision_dict[ 'changeset_revision' ] = None
changeset_revision_dict[ 'ctx_rev' ] = None
return changeset_revision_dict
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
@@ -394,7 +394,7 @@
if not binary_installed:
print 'Binary installation did not occur, so proceeding with install and compile recipe.'
# Make sure to reset for installation if attempt at binary installation resulted in an error.
- if tool_dependency.status != app.model.ToolDependency.installation_status.NEW:
+ if tool_dependency.status != app.model.ToolDependency.installation_status.NEVER_INSTALLED:
removed, error_message = tool_dependency_util.remove_tool_dependency( app, tool_dependency )
install_via_fabric( app,
tool_dependency,
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/common_install_util.py
--- a/lib/tool_shed/util/common_install_util.py
+++ b/lib/tool_shed/util/common_install_util.py
@@ -12,6 +12,7 @@
from tool_shed.util import encoding_util
from tool_shed.util import data_manager_util
from tool_shed.util import datatype_util
+from tool_shed.util import tool_dependency_util
from tool_shed.util import tool_util
from tool_shed.util import xml_util
from tool_shed.galaxy_install.tool_dependencies.install_util import install_package
@@ -69,16 +70,28 @@
Return dictionaries containing the sets of installed and missing tool dependencies and repository dependencies associated with the repository defined
by the received repo_info_dict.
"""
+ repository = None
+ installed_rd = {}
+ installed_td = {}
+ missing_rd = {}
+ missing_td = {}
name = repo_info_dict.keys()[ 0 ]
repo_info_tuple = repo_info_dict[ name ]
- description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td = \
+ description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
suc.get_repo_info_tuple_contents( repo_info_tuple )
+ if tool_dependencies:
+ if not includes_tool_dependencies:
+ includes_tool_dependencies = True
+ # Inspect the tool_dependencies dictionary to separate the installed and missing tool dependencies. We don't add to installed_td
+ # and missing_td here because at this point they are empty.
+ installed_td, missing_td = get_installed_and_missing_tool_dependencies( trans, tool_shed_url, tool_dependencies )
+ # In cases where a repository dependency is required only for compiling a dependent repository's tool dependency, the value of
+ # repository_dependencies will be an empty dictionary here.
if repository_dependencies:
# We have a repository with one or more defined repository dependencies.
missing_td = {}
- # Handle the scenario where a repository was installed, then uninstalled and an error occurred during the re-installation process.
- # In this case, a record for the repository will exist in the database with the status of 'New'.
- repository = suc.get_repository_for_dependency_relationship( trans.app, tool_shed_url, name, repository_owner, changeset_revision )
+ if not repository:
+ repository = suc.get_repository_for_dependency_relationship( trans.app, tool_shed_url, name, repository_owner, changeset_revision )
if repository and repository.metadata:
installed_rd, missing_rd = get_installed_and_missing_repository_dependencies( trans, repository )
else:
@@ -86,73 +99,70 @@
# Discover all repository dependencies and retrieve information for installing them.
all_repo_info_dict = get_required_repo_info_dicts( trans, tool_shed_url, util.listify( repo_info_dict ) )
has_repository_dependencies = all_repo_info_dict.get( 'has_repository_dependencies', False )
+ has_repository_dependencies_only_if_compiling_contained_td = all_repo_info_dict.get( 'has_repository_dependencies_only_if_compiling_contained_td', False )
includes_tools_for_display_in_tool_panel = all_repo_info_dict.get( 'includes_tools_for_display_in_tool_panel', False )
includes_tool_dependencies = all_repo_info_dict.get( 'includes_tool_dependencies', False )
includes_tools = all_repo_info_dict.get( 'includes_tools', False )
required_repo_info_dicts = all_repo_info_dict.get( 'all_repo_info_dicts', [] )
# Display tool dependencies defined for each of the repository dependencies.
if required_repo_info_dicts:
- all_tool_dependencies = {}
+ required_tool_dependencies = {}
for rid in required_repo_info_dicts:
for name, repo_info_tuple in rid.items():
- description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, rid_installed_td = \
+ description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, rid_repository_dependencies, rid_tool_dependencies = \
suc.get_repo_info_tuple_contents( repo_info_tuple )
- if rid_installed_td:
- for td_key, td_dict in rid_installed_td.items():
- if td_key not in all_tool_dependencies:
- all_tool_dependencies[ td_key ] = td_dict
- if all_tool_dependencies:
- if installed_td is None:
- installed_td = {}
- else:
- # Move all tool dependencies to the missing_tool_dependencies container.
- for td_key, td_dict in installed_td.items():
- if td_key not in missing_td:
- missing_td[ td_key ] = td_dict
- installed_td = {}
+ if rid_tool_dependencies:
+ for td_key, td_dict in rid_tool_dependencies.items():
+ if td_key not in required_tool_dependencies:
+ required_tool_dependencies[ td_key ] = td_dict
+ if required_tool_dependencies:
# Discover and categorize all tool dependencies defined for this repository's repository dependencies.
- required_tool_dependencies, required_missing_tool_dependencies = \
- get_installed_and_missing_tool_dependencies_for_new_install( trans, all_tool_dependencies )
- if required_tool_dependencies:
+ required_installed_td, required_missing_td = get_installed_and_missing_tool_dependencies( trans,
+ tool_shed_url,
+ required_tool_dependencies )
+ if required_installed_td:
if not includes_tool_dependencies:
includes_tool_dependencies = True
- for td_key, td_dict in required_tool_dependencies.items():
+ for td_key, td_dict in required_installed_td.items():
if td_key not in installed_td:
installed_td[ td_key ] = td_dict
- if required_missing_tool_dependencies:
+ if required_missing_td:
if not includes_tool_dependencies:
includes_tool_dependencies = True
- for td_key, td_dict in required_missing_tool_dependencies.items():
+ for td_key, td_dict in required_missing_td.items():
if td_key not in missing_td:
missing_td[ td_key ] = td_dict
else:
- # We have a single repository with no defined repository dependencies.
+ # We have a single repository with (possibly) no defined repository dependencies.
all_repo_info_dict = get_required_repo_info_dicts( trans, tool_shed_url, util.listify( repo_info_dict ) )
has_repository_dependencies = all_repo_info_dict.get( 'has_repository_dependencies', False )
+ has_repository_dependencies_only_if_compiling_contained_td = all_repo_info_dict.get( 'has_repository_dependencies_only_if_compiling_contained_td', False )
includes_tools_for_display_in_tool_panel = all_repo_info_dict.get( 'includes_tools_for_display_in_tool_panel', False )
includes_tool_dependencies = all_repo_info_dict.get( 'includes_tool_dependencies', False )
includes_tools = all_repo_info_dict.get( 'includes_tools', False )
required_repo_info_dicts = all_repo_info_dict.get( 'all_repo_info_dicts', [] )
- installed_rd = None
- missing_rd = None
- missing_td = None
- dependencies_for_repository_dict = dict( changeset_revision=changeset_revision,
- has_repository_dependencies=has_repository_dependencies,
- includes_tool_dependencies=includes_tool_dependencies,
- includes_tools=includes_tools,
- includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
- installed_repository_dependencies=installed_rd,
- installed_tool_dependencies=installed_td,
- missing_repository_dependencies=missing_rd,
- missing_tool_dependencies=missing_td,
- name=name,
- repository_owner=repository_owner )
+ dependencies_for_repository_dict = \
+ dict( changeset_revision=changeset_revision,
+ has_repository_dependencies=has_repository_dependencies,
+ has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td,
+ includes_tool_dependencies=includes_tool_dependencies,
+ includes_tools=includes_tools,
+ includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
+ installed_repository_dependencies=installed_rd,
+ installed_tool_dependencies=installed_td,
+ missing_repository_dependencies=missing_rd,
+ missing_tool_dependencies=missing_td,
+ name=name,
+ repository_owner=repository_owner )
return dependencies_for_repository_dict
def get_installed_and_missing_repository_dependencies( trans, repository ):
"""
Return the installed and missing repository dependencies for a tool shed repository that has a record in the Galaxy database, but
- may or may not be installed. In this case, the repository dependencies are associated with the repository in the database.
+ may or may not be installed. In this case, the repository dependencies are associated with the repository in the database. Do not
+ include a repository dependency if it is required only to compile a tool dependency defined for the dependent repository since these
+ special kinds of repository dependencies are really a dependency of the dependent repository's contained tool dependency, and only if
+ that tool dependency requires compilation.
"""
missing_repository_dependencies = {}
installed_repository_dependencies = {}
@@ -166,7 +176,14 @@
for tsr in repository.repository_dependencies:
prior_installation_required = suc.set_prior_installation_required( repository, tsr )
only_if_compiling_contained_td = suc.set_only_if_compiling_contained_td( repository, tsr )
- rd_tup = [ tsr.tool_shed, tsr.name, tsr.owner, tsr.changeset_revision, prior_installation_required, only_if_compiling_contained_td, tsr.id, tsr.status ]
+ rd_tup = [ tsr.tool_shed,
+ tsr.name,
+ tsr.owner,
+ tsr.changeset_revision,
+ prior_installation_required,
+ only_if_compiling_contained_td,
+ tsr.id,
+ tsr.status ]
if tsr.status == trans.model.ToolShedRepository.installation_status.INSTALLED:
installed_rd_tups.append( rd_tup )
else:
@@ -184,7 +201,7 @@
repository_dependencies = metadata.get( 'repository_dependencies', {} )
description = repository_dependencies.get( 'description', None )
# We need to add a root_key entry to one or both of installed_repository_dependencies dictionary and the missing_repository_dependencies
- # dictionary for proper display parsing.
+ # dictionaries for proper display parsing.
root_key = container_util.generate_repository_dependencies_key_for_repository( repository.tool_shed,
repository.name,
repository.owner,
@@ -210,7 +227,7 @@
installed_repository_dependencies = {}
missing_rd_tups = []
installed_rd_tups = []
- description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td = \
+ description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
suc.get_repo_info_tuple_contents( repo_info_tuple )
if repository_dependencies:
description = repository_dependencies[ 'description' ]
@@ -228,7 +245,7 @@
# tuple looks like: ( description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td )
tmp_clone_url = suc.generate_clone_url_from_repo_info_tup( rd_tup )
tmp_repo_info_tuple = ( None, tmp_clone_url, changeset_revision, None, owner, None, None )
- repository, current_changeset_revision = suc.repository_was_previously_installed( trans, tool_shed, name, tmp_repo_info_tuple )
+ repository, installed_changeset_revision = suc.repository_was_previously_installed( trans, tool_shed, name, tmp_repo_info_tuple )
if repository:
new_rd_tup = [ tool_shed,
name,
@@ -273,29 +290,46 @@
missing_repository_dependencies[ 'description' ] = description
return installed_repository_dependencies, missing_repository_dependencies
-def get_installed_and_missing_tool_dependencies_for_new_install( trans, all_tool_dependencies ):
+def get_installed_and_missing_tool_dependencies( trans, tool_shed_url, tool_dependencies_dict ):
"""Return the lists of installed tool dependencies and missing tool dependencies for a set of repositories being installed into Galaxy."""
- # FIXME: confirm that this method currently populates and returns only missing tool dependencies. If so, this method should be enhanced to search for
- # installed tool dependencies defined as complex repository dependency relationships.
- if all_tool_dependencies:
- tool_dependencies = {}
- missing_tool_dependencies = {}
- for td_key, val in all_tool_dependencies.items():
- # Set environment tool dependencies are a list, set each member to never installed.
+ installed_tool_dependencies = {}
+ missing_tool_dependencies = {}
+ if tool_dependencies_dict:
+ for td_key, val in tool_dependencies_dict.items():
+ # Default the status to NEVER_INSTALLED.
+ tool_dependency_status = trans.model.ToolDependency.installation_status.NEVER_INSTALLED
+ # Set environment tool dependencies are a list.
if td_key == 'set_environment':
new_val = []
for requirement_dict in val:
- requirement_dict[ 'status' ] = trans.model.ToolDependency.installation_status.NEVER_INSTALLED
+ # {'repository_name': 'xx', 'name': 'bwa', 'version': '0.5.9', 'repository_owner': 'yy', 'changeset_revision': 'zz', 'type': 'package'}
+ tool_dependency = tool_dependency_util.get_tool_dependency_by_name_version_type( trans.app,
+ requirement_dict.get( 'name', None ),
+ requirement_dict.get( 'version', None ),
+ requirement_dict.get( 'type', 'package' ) )
+ if tool_dependency:
+ tool_dependency_status = tool_dependency.status
+ requirement_dict[ 'status' ] = tool_dependency_status
new_val.append( requirement_dict )
- missing_tool_dependencies[ td_key ] = new_val
+ if tool_dependency_status in [ trans.model.ToolDependency.installation_status.INSTALLED ]:
+ installed_tool_dependencies[ td_key ] = new_val
+ else:
+ missing_tool_dependencies[ td_key ] = new_val
else:
- # Since we have a new install, missing tool dependencies have never been installed.
- val[ 'status' ] = trans.model.ToolDependency.installation_status.NEVER_INSTALLED
+ # The val dictionary looks something like this:
+ # {'repository_name': 'xx', 'name': 'bwa', 'version': '0.5.9', 'repository_owner': 'yy', 'changeset_revision': 'zz', 'type': 'package'}
+ tool_dependency = tool_dependency_util.get_tool_dependency_by_name_version_type( trans.app,
+ val.get( 'name', None ),
+ val.get( 'version', None ),
+ val.get( 'type', 'package' ) )
+ if tool_dependency:
+ tool_dependency_status = tool_dependency.status
+ val[ 'status' ] = tool_dependency_status
+ if tool_dependency_status in [ trans.model.ToolDependency.installation_status.INSTALLED ]:
+ installed_tool_dependencies[ td_key ] = val
+ else:
missing_tool_dependencies[ td_key ] = val
- else:
- tool_dependencies = None
- missing_tool_dependencies = None
- return tool_dependencies, missing_tool_dependencies
+ return installed_tool_dependencies, missing_tool_dependencies
def get_required_repo_info_dicts( trans, tool_shed_url, repo_info_dicts ):
"""
@@ -328,7 +362,9 @@
toolshed, name, owner, changeset_revision = container_util.get_components_from_key( key )
components_list = [ toolshed, name, owner, changeset_revision ]
only_if_compiling_contained_td = 'False'
- # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository.
+ # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository since
+ # in this case, the repository dependency is really a dependency of the dependent repository's contained tool dependency, and only if
+ # that tool dependency requires compilation.
if not util.asbool( only_if_compiling_contained_td ):
if components_list not in required_repository_tups:
required_repository_tups.append( components_list )
@@ -337,8 +373,8 @@
only_if_compiling_contained_td = components_list[ 5 ]
except:
only_if_compiling_contained_td = 'False'
- # TODO: Fix this to display the tool dependency if only_if_compiling_contained_td is True, but clarify that installation may not
- # happen.
+ # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository
+ # (see above comment).
if not util.asbool( only_if_compiling_contained_td ):
if components_list not in required_repository_tups:
required_repository_tups.append( components_list )
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/common_util.py
--- a/lib/tool_shed/util/common_util.py
+++ b/lib/tool_shed/util/common_util.py
@@ -1,3 +1,4 @@
+import logging
import os
import urllib2
from galaxy.util import json
@@ -5,6 +6,8 @@
from tool_shed.util import encoding_util
from tool_shed.util import xml_util
+log = logging.getLogger( __name__ )
+
REPOSITORY_OWNER = 'devteam'
def accumulate_tool_dependencies( tool_shed_accessible, tool_dependencies, all_tool_dependencies ):
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/metadata_util.py
--- a/lib/tool_shed/util/metadata_util.py
+++ b/lib/tool_shed/util/metadata_util.py
@@ -280,13 +280,16 @@
def create_or_update_repository_metadata( trans, id, repository, changeset_revision, metadata_dict ):
"""Create or update a repository_metadatqa record in the tool shed."""
has_repository_dependencies = False
+ has_repository_dependencies_only_if_compiling_contained_td = False
includes_datatypes = False
includes_tools = False
includes_tool_dependencies = False
includes_workflows = False
if metadata_dict:
- if 'repository_dependencies' in metadata_dict:
- has_repository_dependencies = True
+ repository_dependencies_dict = metadata_dict.get( 'repository_dependencies', {} )
+ repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \
+ suc.get_repository_dependency_types( repository_dependencies )
if 'datatypes' in metadata_dict:
includes_datatypes = True
if 'tools' in metadata_dict:
@@ -295,7 +298,11 @@
includes_tool_dependencies = True
if 'workflows' in metadata_dict:
includes_workflows = True
- downloadable = has_repository_dependencies or includes_datatypes or includes_tools or includes_tool_dependencies or includes_workflows
+ if has_repository_dependencies or has_repository_dependencies_only_if_compiling_contained_td or includes_datatypes or \
+ includes_tools or includes_tool_dependencies or includes_workflows:
+ downloadable = True
+ else:
+ downloadable = False
repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, id, changeset_revision )
if repository_metadata:
# A repository metadata record already exists with the received changeset_revision, so we don't need to check the skip_tool_test table.
@@ -1851,10 +1858,13 @@
repository_metadata.includes_datatypes = True
else:
repository_metadata.includes_datatypes = False
- if 'repository_dependencies' in metadata_dict:
- repository_metadata.has_repository_dependencies = True
- else:
- repository_metadata.has_repository_dependencies = False
+ # We don't store information about the special type of repository dependency that is needed only for compiling a tool dependency
+ # defined for the dependent repository.
+ repository_dependencies_dict = metadata_dict.get( 'repository_dependencies', {} )
+ repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \
+ suc.get_repository_dependency_types( repository_dependencies )
+ repository_metadata.has_repository_dependencies = has_repository_dependencies
if 'tool_dependencies' in metadata_dict:
repository_metadata.includes_tool_dependencies = True
else:
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/repository_dependency_util.py
--- a/lib/tool_shed/util/repository_dependency_util.py
+++ b/lib/tool_shed/util/repository_dependency_util.py
@@ -139,6 +139,7 @@
# repository dependencies are not to be installed, only those items contained in the received repo_info_dicts list will be processed.
if is_in_repo_info_dicts( repo_info_dict, repo_info_dicts ) or install_repository_dependencies:
if installed_tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.ERROR,
+ trans.model.ToolShedRepository.installation_status.NEW,
trans.model.ToolShedRepository.installation_status.UNINSTALLED ]:
# The current tool shed repository is not currently installed, so we can update it's record in the database.
can_update = True
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/shed_util_common.py
--- a/lib/tool_shed/util/shed_util_common.py
+++ b/lib/tool_shed/util/shed_util_common.py
@@ -868,6 +868,31 @@
.first()
return None
+def get_repository_dependency_types( repository_dependencies ):
+ """
+ Inspect the received list of repository_dependencies tuples and return boolean values for has_repository_dependencies and
+ has_repository_dependencies_only_if_compiling_contained_td.
+ """
+ # Set has_repository_dependencies, which will be True only if at least one repository_dependency is defined with the value of
+ # only_if_compiling_contained_td as False.
+ has_repository_dependencies = False
+ for rd_tup in repository_dependencies:
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
+ if not asbool( only_if_compiling_contained_td ):
+ has_repository_dependencies = True
+ break
+ # Set has_repository_dependencies_only_if_compiling_contained_td, which will be True only if at least one repository_dependency is
+ # defined with the value of only_if_compiling_contained_td as True.
+ has_repository_dependencies_only_if_compiling_contained_td = False
+ for rd_tup in repository_dependencies:
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
+ if asbool( only_if_compiling_contained_td ):
+ has_repository_dependencies_only_if_compiling_contained_td = True
+ break
+ return has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td
+
def get_repository_for_dependency_relationship( app, tool_shed, name, owner, changeset_revision ):
"""Return an installed tool_shed_repository database record that is defined by either the current changeset revision or the installed_changeset_revision."""
# This method is used only in Galaxy, not the tool shed.
@@ -1389,14 +1414,23 @@
def repository_was_previously_installed( trans, tool_shed_url, repository_name, repo_info_tuple ):
"""
- Handle the case where the repository was previously installed using an older changeset_revsion, but later the repository was updated
- in the tool shed and now we're trying to install the latest changeset revision of the same repository instead of updating the one
- that was previously installed. We'll look in the database instead of on disk since the repository may be uninstalled.
+ Find out if a repository is already installed into Galaxy - there are several scenarios where this is necessary. For example, this method
+ will handle the case where the repository was previously installed using an older changeset_revsion, but later the repository was updated
+ in the tool shed and now we're trying to install the latest changeset revision of the same repository instead of updating the one that was
+ previously installed. We'll look in the database instead of on disk since the repository may be currently uninstalled.
"""
description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
get_repo_info_tuple_contents( repo_info_tuple )
tool_shed = get_tool_shed_from_clone_url( repository_clone_url )
- # Get all previous change set revisions from the tool shed for the repository back to, but excluding, the previous valid changeset
+ # See if we can locate the repository using the value of changeset_revision.
+ tool_shed_repository = get_tool_shed_repository_by_shed_name_owner_installed_changeset_revision( trans.app,
+ tool_shed,
+ repository_name,
+ repository_owner,
+ changeset_revision )
+ if tool_shed_repository:
+ return tool_shed_repository, changeset_revision
+ # Get all previous changeset revisions from the tool shed for the repository back to, but excluding, the previous valid changeset
# revision to see if it was previously installed using one of them.
url = url_join( tool_shed_url,
'repository/previous_changeset_revisions?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s' % \
@@ -1410,14 +1444,14 @@
repository_name,
repository_owner,
previous_changeset_revision )
- if tool_shed_repository and tool_shed_repository.status not in [ trans.model.ToolShedRepository.installation_status.NEW ]:
+ if tool_shed_repository:
return tool_shed_repository, previous_changeset_revision
return None, None
def reset_previously_installed_repository( trans, repository ):
"""
Reset the atrributes of a tool_shed_repository that was previsouly installed. The repository will be in some state other than with a
- status of INSTALLED, so all atributes will be set to the default (NEW( state. This will enable the repository to be freshly installed.
+ status of INSTALLED, so all atributes will be set to the default NEW state. This will enable the repository to be freshly installed.
"""
repository.deleted = False
repository.tool_shed_status = None
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/tool_dependency_util.py
--- a/lib/tool_shed/util/tool_dependency_util.py
+++ b/lib/tool_shed/util/tool_dependency_util.py
@@ -258,6 +258,14 @@
app.model.ToolDependency.table.c.type == type ) ) \
.first()
+def get_tool_dependency_by_name_version_type( app, name, version, type ):
+ sa_session = app.model.context.current
+ return sa_session.query( app.model.ToolDependency ) \
+ .filter( and_( app.model.ToolDependency.table.c.name == name,
+ app.model.ToolDependency.table.c.version == version,
+ app.model.ToolDependency.table.c.type == type ) ) \
+ .first()
+
def get_tool_dependency_by_name_version_type_repository( app, repository, name, version, type ):
sa_session = app.model.context.current
return sa_session.query( app.model.ToolDependency ) \
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/tool_util.py
--- a/lib/tool_shed/util/tool_util.py
+++ b/lib/tool_shed/util/tool_util.py
@@ -962,7 +962,7 @@
suc.config_elems_to_xml_file( trans.app, config_elems, shed_tool_conf, tool_path )
def remove_from_tool_panel( trans, repository, shed_tool_conf, uninstall ):
- """A tool shed repository is being deactivated or uninstalled so handle tool panel alterations accordingly."""
+ """A tool shed repository is being deactivated or uninstalled, so handle tool panel alterations accordingly."""
# Determine where the tools are currently defined in the tool panel and store this information so the tools can be displayed
# in the same way when the repository is activated or reinstalled.
tool_panel_dict = suc.generate_tool_panel_dict_from_shed_tool_conf_entries( trans.app, repository )
diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b test/tool_shed/base/twilltestcase.py
--- a/test/tool_shed/base/twilltestcase.py
+++ b/test/tool_shed/base/twilltestcase.py
@@ -114,7 +114,7 @@
# version=section_version )
# This dict is appended to tool_panel_section_metadata[ tool_guid ]
tool_panel_section = tool_panel_section_metadata[ tool_guid ][ 0 ][ 'name' ]
- assert tool_panel_section == expected_tool_panel_section, 'Expected tool panel section %s, found %s\nMetadata: %s\n' % \
+ assert tool_panel_section == expected_tool_panel_section, 'Expected to find tool panel section *%s*, but instead found *%s*\nMetadata: %s\n' % \
( expected_tool_panel_section, tool_panel_section, metadata )
def check_installed_repository_tool_dependencies( 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: guerler: Drag&drop multiple file upload: updates and fixes
by commits-noreply@bitbucket.org 20 Sep '13
by commits-noreply@bitbucket.org 20 Sep '13
20 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/93215e7e74d0/
Changeset: 93215e7e74d0
User: guerler
Date: 2013-09-20 04:53:34
Summary: Drag&drop multiple file upload: updates and fixes
Affected #: 9 files
diff -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a -r 93215e7e74d020b478803ce2755f76c7e5236f16 lib/galaxy/webapps/galaxy/api/history_contents.py
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -235,8 +235,15 @@
# get file destination
file_destination = dataset.get_file_name()
+ # check if the directory exists
+ dn = os.path.dirname(file_destination)
+ if not os.path.exists(dn):
+ os.makedirs(dn)
+
+ # get file and directory names
+ fn = os.path.basename(content.filename)
+
# save file locally
- fn = os.path.basename(content.filename)
open(file_destination, 'wb').write(content.file.read())
# log
diff -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a -r 93215e7e74d020b478803ce2755f76c7e5236f16 static/scripts/galaxy.modal.js
--- a/static/scripts/galaxy.modal.js
+++ b/static/scripts/galaxy.modal.js
@@ -77,13 +77,25 @@
// link functions
$.each(options.buttons, function(name, value)
{
- footer.append($('<button></button>').text(name).click(value)).append(" ");
+ footer.append($('<button id="' + String(name).toLowerCase() + '"></button>').text(name).click(value)).append(" ");
});
} else
// default close button
footer.append($('<button></button>').text('Close').click(function() { self.hide() })).append(" ");
},
+ // enable buttons
+ enable: function(name)
+ {
+ $(this.el).find('#' + String(name).toLowerCase()).prop('disabled', false);
+ },
+
+ // disable buttons
+ disable: function(name)
+ {
+ $(this.el).find('#' + String(name).toLowerCase()).prop('disabled', true);
+ },
+
/*
HTML TEMPLATES
*/
diff -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a -r 93215e7e74d020b478803ce2755f76c7e5236f16 static/scripts/galaxy.upload.js
--- a/static/scripts/galaxy.upload.js
+++ b/static/scripts/galaxy.upload.js
@@ -1,5 +1,5 @@
/*
- galaxy upload v1.0
+ galaxy upload
*/
// dependencies
@@ -14,12 +14,20 @@
// button
button_show : null,
- // file counter
- file_counter: 0,
+ // upload mod
+ uploadbox: null,
// initialize
initialize : function()
{
+ // wait for galaxy history panel (workaround due to the use of iframes)
+ if (!Galaxy.currHistoryPanel)
+ {
+ var self = this;
+ window.setTimeout(function() { self.initialize() }, 500)
+ return;
+ }
+
// add activate icon
var self = this;
this.button_show = new mod_master.GalaxyMasterIcon (
@@ -37,87 +45,252 @@
// events
events :
{
- 'mouseover' : 'event_mouseover',
- 'mouseleave' : 'event_mouseleave'
+ 'mouseover' : 'event_mouseover',
+ 'mouseleave' : 'event_mouseleave'
},
// mouse over
event_mouseover : function (e)
{
- $('#galaxy-upload-box').addClass('highlight');
},
// mouse left
event_mouseleave : function (e)
{
- $('#galaxy-upload-box').removeClass('highlight');
},
// start
- event_start : function(index, file, message)
+ event_announce : function(index, file, message)
{
+ // hide info
+ this.uploadbox.info().hide();
+
// make id
- var id = '#galaxy-upload-file-' + index;
+ var id = '#upload-' + index;
- // add tag
- $('#galaxy-upload-box').append(this.template_file(id));
+ // add upload item
+ $(this.el).append(this.template_file(id));
+
+ // scroll to bottom
+ $(this.el).scrollTop($(this.el).prop('scrollHeight'));
+
+ // access upload item
+ var it = this.get_upload_item(index);
+
+ // fade in
+ it.fadeIn();
// update title
- $('#galaxy-upload-file-' + index).find('.title').html(file.name);
+ it.find('.title').html(file.name);
+ // configure select field
+ it.find('#extension').select2(
+ {
+ placeholder: 'Auto-detect',
+ width: 'copy',
+ ajax: {
+ url: "http://www.weighttraining.com/sm/search",
+ dataType: 'jsonp',
+ quietMillis: 100,
+ data: function(term, page)
+ {
+ return {
+ types: ["exercise"],
+ limit: -1,
+ term: term
+ };
+ },
+ results: function(data, page)
+ {
+ return { results: data.results.exercise }
+ }
+ },
+ formatResult: function(exercise)
+ {
+ return "<div class='select2-user-result'>" + exercise.term + "</div>";
+ },
+ formatSelection: function(exercise)
+ {
+ return exercise.term;
+ },
+ initSelection : function (element, callback)
+ {
+ var elementText = $(element).attr('data-init-text');
+ callback({"term":elementText});
+ }
+ });
+
+ // add functionality to remove button
+ var self = this;
+ it.find('.remove').on('click', function() { self.event_remove (index) });
+
// initialize progress
this.event_progress(index, file, 0);
- // update counter
- this.file_counter++;
- this.refresh();
+ // update button status
+ this.modal.enable('Upload');
+ this.modal.enable('Reset');
+ },
+
+ // start
+ event_initialize : function(index, file, message)
+ {
+ // update on screen counter
+ this.button_show.number(message);
+
+ // get element
+ var it = this.get_upload_item(index);
+
+ // read in configuration
+ var data = {
+ source : "upload",
+ space_to_tabs : it.find('#space_to_tabs').is(':checked'),
+ extension : it.find('#extension').val()
+ }
+
+ // return additional data to be send with file
+ return data;
},
// progress
event_progress : function(index, file, message)
{
- // get progress bar
- var el = $('#galaxy-upload-file-' + index);
+ // get element
+ var it = this.get_upload_item(index);
// get value
var percentage = parseInt(message);
// update progress
- el.find('.progress').css({ width : percentage + '%' });
+ it.find('.progress-bar').css({ width : percentage + '%' });
// update info
- el.find('.info').html(percentage + '% of ' + this.size_to_string (file.size));
+ it.find('.info').html(percentage + '% of ' + this.size_to_string (file.size));
},
// end
event_success : function(index, file, message)
- {
+ {
+ // get element
+ var it = this.get_upload_item(index);
+
+ // update progress frame
+ it.addClass('panel-success');
+ it.removeClass('panel-default');
+
// update galaxy history
Galaxy.currHistoryPanel.refresh();
- // update counter
- this.file_counter--;
- this.refresh();
+ // make sure progress is shown correctly
+ this.event_progress(index, file, 100);
+
+ // update on screen counter
+ this.button_show.number('');
},
// end
event_error : function(index, file, message)
{
- // get file box
- var el = $('#galaxy-upload-file-' + index);
+ // get element
+ var it = this.get_upload_item(index);
// update progress frame
- el.find('.progress-frame').addClass('failed');
+ it.addClass('panel-danger');
+ it.removeClass('panel-default');
- // update error message
- el.find('.error').html("<strong>Failed:</strong> " + message);
-
- // update progress
+ // remove progress bar
+ it.find('.progress').remove();
+
+ // write error message
+ it.find('.error').html('<strong>Failed:</strong> ' + message);
+
+ // make sure progress is shown correctly
this.event_progress(index, file, 0);
- // update counter
- this.file_counter--;
- this.refresh();
+ // update on screen counter
+ this.button_show.number('');
+ },
+
+ // start upload process
+ event_upload : function()
+ {
+ // hide configuration
+ $(this.el).find('.panel-body').hide();
+
+ // switch icon
+ $(this.el).find('.remove').each(function()
+ {
+ $(this).removeClass('fa-icon-trash');
+ $(this).addClass('fa-icon-caret-down');
+ });
+
+ // update button status
+ this.modal.disable('Upload');
+
+ // configure url
+ var current_history = Galaxy.currHistoryPanel.model.get('id');
+ this.uploadbox.configure({url : galaxy_config.root + "api/histories/" + current_history + "/contents"});
+
+ // initiate upload procedure in plugin
+ this.uploadbox.upload();
+ },
+
+ // remove all
+ event_reset : function()
+ {
+ // remove from screen
+ var panels = $(this.el).find('.panel');
+ var self = this;
+ panels.fadeOut({complete: function()
+ {
+ // remove panels
+ panels.remove();
+
+ // show on screen info
+ self.uploadbox.info().fadeIn();
+ }});
+
+ // update button status
+ this.modal.disable('Upload');
+ this.modal.disable('Reset');
+
+ // remove from queue
+ this.uploadbox.reset();
+ },
+
+ // remove item from upload list
+ event_remove : function(index)
+ {
+ // remove
+ var self = this;
+ var it = this.get_upload_item(index);
+
+ // fade out and update button status
+ it.fadeOut({complete: function()
+ {
+ // remove from screen
+ it.remove();
+
+ // remove from queue
+ self.uploadbox.remove(index);
+
+ // update reset button
+ if ($(self.el).find('.panel').length > 0)
+ self.modal.enable('Reset');
+ else {
+ // disable reset button
+ self.modal.disable('Reset');
+
+ // show on screen info
+ self.uploadbox.info().fadeIn();
+ }
+
+ // update upload button
+ if (self.uploadbox.length() > 0)
+ self.modal.enable('Upload');
+ else
+ self.modal.disable('Upload');
+ }});
},
// show/hide upload frame
@@ -126,14 +299,6 @@
// prevent default
e.preventDefault();
- // wait for galaxy history panel (workaround due to the use of iframes)
- if (!Galaxy.currHistoryPanel)
- {
- var self = this;
- window.setTimeout(function() { self.event_show(e) }, 200)
- return;
- }
-
// create modal
if (!this.modal)
{
@@ -142,44 +307,45 @@
this.modal = new mod_modal.GalaxyModal(
{
title : 'Upload files from your local drive',
- body : this.template(),
+ body : this.template('upload-box'),
buttons : {
- 'Close' : function() {self.modal.hide()}
+ 'Select' : function() {self.uploadbox.select()},
+ 'Upload' : function() {self.event_upload()},
+ 'Reset' : function() {self.event_reset()},
+ 'Close' : function() {self.modal.hide()}
}
});
- // get current history
- var current_history = Galaxy.currHistoryPanel.model.get('id');
-
+ // set element
+ this.setElement('#upload-box');
+
// file upload
var self = this;
- $('#galaxy-upload-box').uploadbox(
+ this.uploadbox = this.$el.uploadbox(
{
- url : galaxy_config.root + "api/histories/" + current_history + "/contents",
dragover : self.event_mouseover,
dragleave : self.event_mouseleave,
- start : function(index, file, message) { self.event_start(index, file, message) },
+ announce : function(index, file, message) { self.event_announce(index, file, message) },
+ initialize : function(index, file, message) { return self.event_initialize(index, file, message) },
success : function(index, file, message) { self.event_success(index, file, message) },
progress : function(index, file, message) { self.event_progress(index, file, message) },
error : function(index, file, message) { self.event_error(index, file, message) },
- data : {source : "upload"}
});
- // set element
- this.setElement('#galaxy-upload-box');
+ // update button status
+ this.modal.disable('Upload');
+ this.modal.disable('Reset');
}
-
+
// show modal
this.modal.show();
},
- // update counter
- refresh: function ()
+ // get upload item
+ get_upload_item: function(index)
{
- if (this.file_counter > 0)
- this.button_show.number(this.file_counter);
- else
- this.button_show.number('');
+ // get element
+ return $(this.el).find('#upload-' + index);
},
// to string
@@ -197,21 +363,32 @@
},
// load html template
- template: function()
+ template: function(id)
{
- return '<form id="galaxy-upload-box" class="galaxy-upload-box"></form>';
+ return '<div id="' + id + '" class="upload-box"></div>';
},
// load html template
template_file: function(id)
{
- return '<div id="' + id.substr(1) + '" class="file corner-soft shadow">' +
- '<div class="title"></div>' +
- '<div class="error"></div>' +
- '<div class="progress-frame corner-soft">' +
- '<div class="progress"></div>' +
+ return '<div id="' + id.substr(1) + '" class="panel panel-default">' +
+ '<div class="panel-heading">' +
+ '<h5 class="title"></h5>' +
+ '<h5 class="info"></h5>' +
+ '<div class="remove fa-icon-trash"></div>' +
'</div>' +
- '<div class="info"></div>' +
+ '<div class="panel-body">' +
+ '<div class="menu">' +
+ //'<input id="extension" type="hidden" width="10px"/> ' +
+ '<span><input id="space_to_tabs" type="checkbox">Convert spaces to tabs</input></span>' +
+ '</div>' +
+ '</div>' +
+ '<div class="panel-footer">' +
+ '<div class="progress">' +
+ '<div class="progress-bar progress-bar-success"></div>' +
+ '</div>' +
+ '<h6 class="error"></h6>' +
+ '</div>' +
'</div>';
}
});
diff -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a -r 93215e7e74d020b478803ce2755f76c7e5236f16 static/scripts/utils/galaxy.uploadbox.js
--- a/static/scripts/utils/galaxy.uploadbox.js
+++ b/static/scripts/utils/galaxy.uploadbox.js
@@ -1,5 +1,5 @@
/*
- galaxy upload lib v1.0 - uses FileReader, FormData and XMLHttpRequest
+ galaxy upload lib - uses FileReader, FormData and XMLHttpRequest
*/
;(function($)
{
@@ -11,67 +11,71 @@
{
url : '',
paramname : 'content',
- maxfilesize : 2048,
- data : {},
+ maxfilesize : 250,
dragover : function() {},
dragleave : function() {},
+ announce : function() {},
initialize : function() {},
- start : function() {},
progress : function() {},
success : function() {},
error : function(index, file, message) { alert(message); },
error_browser : "Your browser does not support drag-and-drop file uploads.",
- error_filesize : "This file is too large. Please use an FTP client to upload it.",
- error_default : "The upload failed. Please make sure the file is available and accessible.",
- text_default : "Drag&drop files here or click to browse your local drive.",
- text_degrade : "Click here to browse your local drive. <br><br>Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Please upgrade to i.e. Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+."
+ error_filesize : "This file is too large (>250MB). Please use an FTP client to upload it.",
+ error_default : "Please make sure the file is available.",
+ text_default : "Drag&drop files into this box or click 'Select' to select files!",
+ text_degrade : "Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Please upgrade to i.e. Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+."
}
- // global file queue
- var queue = [];
+ // options
+ var opts = {};
+
+ // file queue
+ var queue = {};
- // global counter for file being currently processed
- var queue_index = -1;
+ // counter for file being currently processed
+ var queue_index = 0;
- // global queue status
+ // queue length
+ var queue_length = 0;
+
+ // indicates if queue is currently running
var queue_status = false;
+ // element
+ var el = null;
+
// attach to element
$.fn.uploadbox = function(options)
{
// parse options
- var opts = $.extend({}, default_opts, options);
+ opts = $.extend({}, default_opts, options);
// compatibility
var mode = window.File && window.FileReader && window.FormData && window.XMLHttpRequest;
+ // element
+ el = this;
+
// append upload button
- this.append('<input id="uploadbox_input" type="file" style="display: none" multiple>');
- this.append('<div id="uploadbox_info"></div>');
+ el.append('<input id="uploadbox_input" type="file" style="display: none" multiple>');
+ el.append('<div id="uploadbox_info"></div>');
// set info text
if (mode)
- this.find('#uploadbox_info').html(opts.text_default);
+ el.find('#uploadbox_info').html(opts.text_default);
else
- this.find('#uploadbox_info').html(opts.text_degrade);
+ el.find('#uploadbox_info').html(opts.text_degrade);
// attach events
- this.on('drop', drop);
- this.on('dragover', dragover);
- this.on('dragleave', dragleave);
-
- // attach click event
- this.on('click', function(e)
- {
- e.stopPropagation();
- $('#uploadbox_input').trigger(e);
- });
+ el.on('drop', drop);
+ el.on('dragover', dragover);
+ el.on('dragleave', dragleave);
// attach change event
$('#uploadbox_input').change(function(e)
{
- var files = e.target.files;
- upload(files);
+ // add files to queue
+ add(e.target.files);
});
// drop event
@@ -81,11 +85,8 @@
if(!e.dataTransfer)
return;
- // get files from event
- var files = e.dataTransfer.files;
-
- // start upload
- upload(files);
+ // add files to queue
+ add(e.dataTransfer.files);
// prevent default
e.preventDefault();
@@ -98,14 +99,14 @@
function dragover(e)
{
e.preventDefault();
- opts.dragover.call(this, e);
+ opts.dragover.call(e);
}
// drag leave
function dragleave(e)
{
e.stopPropagation();
- opts.dragleave.call(this, e);
+ opts.dragleave.call(e);
}
// progress
@@ -117,39 +118,61 @@
}
// respond to an upload request
- function upload(files)
+ function add(files)
{
- // get current queue size
- var queue_sofar = queue.length;
+ // add new files to queue
+ for (var i = 0; i < files.length; i++)
+ {
+ // new identifier
+ var index = String(++queue_index);
- // add new files to queue
- for (var index = 0; index < files.length; index++)
- queue.push(files[index]);
+ // add to queue
+ queue[index] = files[i];
- // tell client about new uploads
- for (var index = queue_sofar; index < queue.length; index++)
- opts.start(index, queue[index], "");
+ // increase counter
+ queue_length++;
- // initiate processing loop if process loop is not running already
- if (!queue_status)
- process();
+ // announce
+ opts.announce(index, queue[index], "");
+ }
}
+ // remove entry from queue
+ function remove(index)
+ {
+ if (queue[index])
+ {
+ // remove from queue
+ delete queue[index];
+
+ // update counter
+ queue_length--;
+ }
+ }
+
// process an upload, recursive
function process()
{
- // check if for files
- if (queue_index + 1 == queue.length)
+ // get an identifier from the queue
+ var index = -1;
+ for (var key in queue)
{
- queue_status = false;
- return;
+ index = key;
+ break;
}
- // set status
- queue_status = true;
+ // validate
+ if (queue_length == 0)
+ return;
- // identify current index
- var index = ++queue_index;
+ // get current file from queue
+ var file = queue[index];
+
+ // remove from queue
+ remove(index)
+
+ // start
+ var data = opts.initialize(index, file, length);
// add file to queue
try
@@ -158,50 +181,45 @@
var reader = new FileReader();
// identify maximum file size
- var file = queue[index];
var filesize = file.size;
var maxfilesize = 1048576 * opts.maxfilesize;
-
+
// set index
reader.index = index;
if (filesize < maxfilesize)
{
- // link loadend is always called at the end
- reader.onloadend = function(e)
+ // link load
+ reader.onload = function(e)
{
- send(index, file)
+ send(index, file, data)
};
// link error
reader.onerror = function(e)
{
- opts.error(index, file, opts.error_default);
- queue_status = false;
+ error(index, file, opts.error_default);
};
// read data
reader.readAsDataURL(file);
} else {
// skip file
- opts.error(index, file, opts.error_filesize);
-
- // restart process
- process();
+ error(index, file, opts.error_filesize);
}
} catch (err)
{
// parse error
- opts.error(index, file, err);
+ error(index, file, err);
}
}
// send file
- function send (index, file)
+ function send (index, file, data)
{
// construct form data
var formData = new FormData();
- for (var key in opts.data)
- formData.append(key, opts.data[key]);
+ for (var key in data)
+ formData.append(key, data[key]);
formData.append(opts.paramname, file, file.name);
// prepare request
@@ -237,22 +255,94 @@
// pass any error to the error option
if (xhr.status < 200 || xhr.status > 299)
{
+ // format error
+ var text = xhr.statusText;
+ if (!xhr.statusText)
+ text = opts.error_default;
+
// request error
- opts.error(index, file, xhr.statusText + " (Server Code " + xhr.status + ")");
-
- // reset status
- queue_status = false;
- } else {
+ error(index, file, text + " (Server Code " + xhr.status + ")");
+ } else
// parse response
- opts.success(index, file, response);
-
- // upload next file
- process();
- }
+ success(index, file, response);
}
}
- // return
- return this;
+ // success
+ function success (index, file, msg)
+ {
+ // parse message
+ opts.success(index, file, msg);
+
+ // restart process after success
+ process();
+ }
+
+ // error
+ function error (index, file, err)
+ {
+ // parse error
+ opts.error(index, file, err);
+
+ // restart process after error
+ process();
+ }
+
+ /*
+ public interface
+ */
+
+ // open file browser for selection
+ function select()
+ {
+ $('#uploadbox_input').trigger('click');
+ }
+
+ // remove all entries from queue
+ function reset(index)
+ {
+ for (index in queue)
+ remove(index);
+ }
+
+ // initiate upload process
+ function upload()
+ {
+ if (!queue_status)
+ process();
+ }
+
+ // current queue length
+ function length()
+ {
+ return queue_length;
+ }
+
+ // set options
+ function configure(options)
+ {
+ // update current configuration
+ opts = $.extend({}, opts, options);
+
+ // return new configuration
+ return opts;
+ }
+
+ // visibility of on screen information
+ function info()
+ {
+ return el.find('#uploadbox_info');
+ }
+
+ // export functions
+ return {
+ 'select' : select,
+ 'remove' : remove,
+ 'upload' : upload,
+ 'reset' : reset,
+ 'length' : length,
+ 'configure' : configure,
+ 'info' : info
+ };
}
})(jQuery);
\ No newline at end of file
diff -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a -r 93215e7e74d020b478803ce2755f76c7e5236f16 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1122,15 +1122,12 @@
.galaxy-frame .frame .f-close{right:5px;top:1px}
.galaxy-frame .frame .f-pin{left:6px;top:1px}
.galaxy-frame .frame .f-resize{background:#fff;width:16px;height:16px;color:#2c3143;right:0px;bottom:0px;text-align:center;line-height:16px;border:0px}
-.galaxy-upload-box{width:100%;height:200px;max-height:200px;padding:10px 0px 0px 0px;text-align:center;cursor:pointer;overflow:scroll;font-size:12px;line-height:1.428571429;-moz-border-radius:5px;border-radius:5px;border:1px dashed #bfbfbf}.galaxy-upload-box .corner-soft{-moz-border-radius:3px;border-radius:3px}
-.galaxy-upload-box .shadow{-webkit-box-shadow:0 0 2px rgba(0,0,0,0.3)}
-.galaxy-upload-box .highlight{border:1px dashed #333}
-.galaxy-upload-box .file{position:relative;margin:5px 20px 5px 20px;border:1px solid #bfbfbf;color:#333}.galaxy-upload-box .file .title{margin:3px 130px 0px 5px;text-align:left;overflow:hidden;border:0px}
-.galaxy-upload-box .file .progress-frame{border:0px;margin:0px 5px 3px 5px;height:7px;background:#bfbfbf}
-.galaxy-upload-box .file .progress{background:#5cb85c;height:100%;width:0%}
-.galaxy-upload-box .file .failed{background:#d9534f}
-.galaxy-upload-box .file .error{font-size:11px;text-align:left;overflow:hidden;margin:0px 5px 0px 5px}
-.galaxy-upload-box .file .info{position:absolute;top:4px;right:5px;font-size:11px;text-align:right;overflow:hidden;max-width:100px;max-height:12px}
+.upload-box{width:100%;height:250px;max-height:250px;text-align:center;overflow:scroll;font-size:12px;line-height:1.33;-moz-border-radius:5px;border-radius:5px;border:1px dashed #bfbfbf;padding:20px}.upload-box .panel{display:none}.upload-box .panel .panel-heading{position:relative;height:19px;padding:5px}.upload-box .panel .panel-heading .title{position:absolute;top:2px;font-weight:normal;text-align:left;margin:0px;max-width:300px;overflow:hidden}
+.upload-box .panel .panel-heading .info{position:absolute;top:3px;font-weight:normal;right:20px;text-align:right;margin:0px}
+.upload-box .panel .panel-heading .remove{position:absolute;cursor:pointer;top:0px;right:3px}
+.upload-box .panel .panel-body{position:relative;padding:5px}
+.upload-box .panel .panel-footer{position:relative;height:20px;padding:0px}.upload-box .panel .panel-footer .progress{height:10px;margin:5px}
+.upload-box .panel .panel-footer .error{font-weight:normal;margin:2px}
.unselectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}
.parent-width{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:100%;*width:90%}
.clear:before,.clear:after{content:" ";display:table;}
diff -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a -r 93215e7e74d020b478803ce2755f76c7e5236f16 static/style/blue/sprite-fugue.png
Binary file static/style/blue/sprite-fugue.png has changed
diff -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a -r 93215e7e74d020b478803ce2755f76c7e5236f16 static/style/blue/sprite-history-buttons.png
Binary file static/style/blue/sprite-history-buttons.png has changed
diff -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a -r 93215e7e74d020b478803ce2755f76c7e5236f16 static/style/blue/sprite-history-states.png
Binary file static/style/blue/sprite-history-states.png has changed
diff -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a -r 93215e7e74d020b478803ce2755f76c7e5236f16 static/style/src/less/upload.less
--- a/static/style/src/less/upload.less
+++ b/static/style/src/less/upload.less
@@ -1,87 +1,80 @@
-.galaxy-upload-box
+.upload-box
{
width : 100%;
- height : 200px;
- max-height : 200px;
- padding : 10px 0px 0px 0px;
+ height : 250px;
+ max-height : 250px;
text-align : center;
- cursor : pointer;
overflow : scroll;
font-size : @font-size-base;
- line-height : @line-height-base;
+ line-height : @line-height-large;
-moz-border-radius: @border-radius-large;
- border-radius: @border-radius-large;
+ border-radius : @border-radius-large;
border : 1px dashed @btn-default-border;
+ padding : 20px;
- .corner-soft
+ .panel
{
- -moz-border-radius: @border-radius-base;
- border-radius: @border-radius-base;
- }
+ display: none;
- .shadow
- {
- -webkit-box-shadow: 0 0 2px rgba(0,0,0,0.3);
- }
+ .panel-heading
+ {
+ position: relative;
+ height: 19px;
+ padding: 5px;
- .highlight
- {
- border : 1px dashed @btn-default-color;
- }
+ .title
+ {
+ position: absolute;
+ top: 2px;
+ font-weight: normal;
+ text-align: left;
+ margin: 0px;
+ max-width: 300px;
+ overflow: hidden;
+ }
- .file
- {
- position : relative;
- margin : 5px 20px 5px 20px;
- border : 1px solid @btn-default-border;
- color : @btn-default-color;
+ .info
+ {
+ position: absolute;
+ top: 3px;
+ font-weight: normal;
+ right: 20px;
+ text-align: right;
+ margin: 0px;
+ }
- .title
- {
- margin : 3px 130px 0px 5px;
- text-align : left;
- overflow : hidden;
- border : 0px;
+ .remove
+ {
+ position: absolute;
+ cursor: pointer;
+ top: 0px;
+ right: 3px;
+ }
}
- .progress-frame
+ .panel-body
{
- border : 0px;
- margin : 0px 5px 3px 5px;
- height : 7px;
- background : @btn-default-border;
+ position: relative;
+ padding: 5px;
}
- .progress
+ .panel-footer
{
- background : @bs-success;
- height : 100%;
- width : 0%;
- }
-
- .failed
- {
- background : @bs-danger;
- }
-
- .error
- {
- font-size : @font-size-small;
- text-align : left;
- overflow : hidden;
- margin : 0px 5px 0px 5px;
- }
-
- .info
- {
- position : absolute;
- top : 4px;
- right : 5px;
- font-size : @font-size-small;
- text-align : right;
- overflow : hidden;
- max-width : 100px;
- max-height : 12px;
+ position:relative;
+ height: 20px;
+ padding: 0px;
+
+ .progress
+ {
+ height: 10px;
+ margin: 5px;
+ }
+
+ .error
+ {
+ font-weight: normal;
+ margin: 2px;
+ }
}
}
}
\ 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: Saved histories grid: fix to persistant adv. search, use location.pathname for Grid.base_url to prevent mixed-content; pack scripts
by commits-noreply@bitbucket.org 19 Sep '13
by commits-noreply@bitbucket.org 19 Sep '13
19 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6f77298e8d16/
Changeset: 6f77298e8d16
User: carlfeberhard
Date: 2013-09-20 00:32:00
Summary: Saved histories grid: fix to persistant adv. search, use location.pathname for Grid.base_url to prevent mixed-content; pack scripts
Affected #: 6 files
diff -r 5cbf058d648db06541540d11e6dd1d1535a12292 -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a lib/galaxy/web/framework/helpers/grids.py
--- a/lib/galaxy/web/framework/helpers/grids.py
+++ b/lib/galaxy/web/framework/helpers/grids.py
@@ -198,7 +198,10 @@
if page_num == 0:
# Show all rows in page.
total_num_rows = query.count()
+ # persistant page='all'
page_num = 1
+ #page_num = 'all'
+ #extra_url_args['page'] = page_num
num_pages = 1
else:
# Show a limited number of rows. Before modifying query, get the total number of rows that query
diff -r 5cbf058d648db06541540d11e6dd1d1535a12292 -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a static/scripts/galaxy.grids.js
--- a/static/scripts/galaxy.grids.js
+++ b/static/scripts/galaxy.grids.js
@@ -472,7 +472,7 @@
go_to_URL();
return;
}
-
+
// If there's an operation, do POST; otherwise, do GET.
var method = (grid.get('operation') ? "POST" : "GET" );
$('.loading-elt-overlay').show(); // Show overlay to indicate loading and prevent user actions.
@@ -565,4 +565,4 @@
// return
return true;
-}
\ No newline at end of file
+}
diff -r 5cbf058d648db06541540d11e6dd1d1535a12292 -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a static/scripts/packed/galaxy.upload.js
--- a/static/scripts/packed/galaxy.upload.js
+++ b/static/scripts/packed/galaxy.upload.js
@@ -1,1 +1,1 @@
-define(["utils/galaxy.css","galaxy.modal","galaxy.master","utils/galaxy.uploadbox","libs/backbone/backbone-relational"],function(c,b,d){var a=Backbone.View.extend({modal:null,button_show:null,file_counter:0,initialize:function(){c.load_file("static/style/galaxy.upload.css");var e=this;this.button_show=new d.GalaxyMasterIcon({icon:"fa-icon-upload",tooltip:"Upload Files",on_click:function(f){e.event_show(f)},with_number:true});Galaxy.master.prepend(this.button_show)},events:{mouseover:"event_mouseover",mouseleave:"event_mouseleave"},event_mouseover:function(f){$("#galaxy-upload-box").addClass("galaxy-upload-highlight")},event_mouseleave:function(f){$("#galaxy-upload-box").removeClass("galaxy-upload-highlight")},event_start:function(e,f,g){var h="#galaxy-upload-file-"+e;$("#galaxy-upload-box").append(this.template_file(h));$("#galaxy-upload-file-"+e).find(".title").html(f.name);this.event_progress(e,f,0);this.file_counter++;this.refresh()},event_progress:function(f,g,i){var h=$("#galaxy-upload-file-"+f);var e=parseInt(i);h.find(".progress").css({width:e+"%"});h.find(".info").html(e+"% of "+this.size_to_string(g.size))},event_success:function(e,f,g){Galaxy.currHistoryPanel.refresh();this.file_counter--;this.refresh()},event_error:function(e,f,h){var g=$("#galaxy-upload-file-"+e);g.find(".progress-frame").addClass("failed");g.find(".error").html("<strong>Failed:</strong> "+h);this.event_progress(e,f,0);this.file_counter--;this.refresh()},event_show:function(h){h.preventDefault();if(!Galaxy.currHistoryPanel){var g=this;window.setTimeout(function(){g.event_show(h)},200);return}if(!this.modal){this.modal=new b.GalaxyModal({title:"Upload files from your local drive",body:this.template()});var f=Galaxy.currHistoryPanel.model.get("id");var g=this;$("#galaxy-upload-box").uploadbox({url:galaxy_config.root+"api/histories/"+f+"/contents",dragover:g.event_mouseover,dragleave:g.event_mouseleave,start:function(e,i,j){g.event_start(e,i,j)},success:function(e,i,j){g.event_success(e,i,j)},progress:function(e,i,j){g.event_progress(e,i,j)},error:function(e,i,j){g.event_error(e,i,j)},data:{source:"upload"}});this.setElement("#galaxy-upload-box")}this.modal.show()},refresh:function(){if(this.file_counter>0){this.button_show.number(this.file_counter)}else{this.button_show.number("")}},size_to_string:function(e){var f="";if(e>=100000000000){e=e/100000000000;f="TB"}else{if(e>=100000000){e=e/100000000;f="GB"}else{if(e>=100000){e=e/100000;f="MB"}else{if(e>=100){e=e/100;f="KB"}else{e=e*10;f="b"}}}}return"<strong>"+(Math.round(e)/10)+"</strong> "+f},template:function(){return'<form id="galaxy-upload-box" class="galaxy-upload-box galaxy-corner"></form>'},template_file:function(e){return'<div id="'+e.substr(1)+'" class="galaxy-upload-file galaxy-corner-soft galaxy-shadow"><div class="title"></div><div class="error"></div><div class="progress-frame galaxy-corner-soft"><div class="progress"></div></div><div class="info"></div></div>'}});return{GalaxyUpload:a}});
\ No newline at end of file
+define(["galaxy.modal","galaxy.master","utils/galaxy.uploadbox","libs/backbone/backbone-relational"],function(b,c){var a=Backbone.View.extend({modal:null,button_show:null,file_counter:0,initialize:function(){var d=this;this.button_show=new c.GalaxyMasterIcon({icon:"fa-icon-upload",tooltip:"Upload Files",on_click:function(f){d.event_show(f)},with_number:true});Galaxy.master.prepend(this.button_show)},events:{mouseover:"event_mouseover",mouseleave:"event_mouseleave"},event_mouseover:function(d){$("#galaxy-upload-box").addClass("highlight")},event_mouseleave:function(d){$("#galaxy-upload-box").removeClass("highlight")},event_start:function(d,e,f){var g="#galaxy-upload-file-"+d;$("#galaxy-upload-box").append(this.template_file(g));$("#galaxy-upload-file-"+d).find(".title").html(e.name);this.event_progress(d,e,0);this.file_counter++;this.refresh()},event_progress:function(e,f,h){var g=$("#galaxy-upload-file-"+e);var d=parseInt(h);g.find(".progress").css({width:d+"%"});g.find(".info").html(d+"% of "+this.size_to_string(f.size))},event_success:function(d,e,f){Galaxy.currHistoryPanel.refresh();this.file_counter--;this.refresh()},event_error:function(d,e,g){var f=$("#galaxy-upload-file-"+d);f.find(".progress-frame").addClass("failed");f.find(".error").html("<strong>Failed:</strong> "+g);this.event_progress(d,e,0);this.file_counter--;this.refresh()},event_show:function(g){g.preventDefault();if(!Galaxy.currHistoryPanel){var f=this;window.setTimeout(function(){f.event_show(g)},200);return}if(!this.modal){var f=this;this.modal=new b.GalaxyModal({title:"Upload files from your local drive",body:this.template(),buttons:{Close:function(){f.modal.hide()}}});var d=Galaxy.currHistoryPanel.model.get("id");var f=this;$("#galaxy-upload-box").uploadbox({url:galaxy_config.root+"api/histories/"+d+"/contents",dragover:f.event_mouseover,dragleave:f.event_mouseleave,start:function(e,h,i){f.event_start(e,h,i)},success:function(e,h,i){f.event_success(e,h,i)},progress:function(e,h,i){f.event_progress(e,h,i)},error:function(e,h,i){f.event_error(e,h,i)},data:{source:"upload"}});this.setElement("#galaxy-upload-box")}this.modal.show()},refresh:function(){if(this.file_counter>0){this.button_show.number(this.file_counter)}else{this.button_show.number("")}},size_to_string:function(d){var e="";if(d>=100000000000){d=d/100000000000;e="TB"}else{if(d>=100000000){d=d/100000000;e="GB"}else{if(d>=100000){d=d/100000;e="MB"}else{if(d>=100){d=d/100;e="KB"}else{d=d*10;e="b"}}}}return"<strong>"+(Math.round(d)/10)+"</strong> "+e},template:function(){return'<form id="galaxy-upload-box" class="galaxy-upload-box"></form>'},template_file:function(d){return'<div id="'+d.substr(1)+'" class="file corner-soft shadow"><div class="title"></div><div class="error"></div><div class="progress-frame corner-soft"><div class="progress"></div></div><div class="info"></div></div>'}});return{GalaxyUpload:a}});
\ No newline at end of file
diff -r 5cbf058d648db06541540d11e6dd1d1535a12292 -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a static/scripts/packed/galaxy.workflow_editor.canvas.js
--- a/static/scripts/packed/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/packed/galaxy.workflow_editor.canvas.js
@@ -1,1 +1,1 @@
-function Terminal(a){this.element=a;this.connectors=[]}$.extend(Terminal.prototype,{connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}});function OutputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}OutputTerminal.prototype=new Terminal();function InputTerminal(b,c,a){Terminal.call(this,b);this.datatypes=c;this.multiple=a}InputTerminal.prototype=new Terminal();$.extend(InputTerminal.prototype,{can_accept:function(a){if(this.connectors.length<1||this.multiple){for(var c in this.datatypes){var f=new Array();f=f.concat(a.datatypes);if(a.node.post_job_actions){for(var d in a.node.post_job_actions){var g=a.node.post_job_actions[d];if(g.action_type=="ChangeDatatypeAction"&&(g.output_name==""||g.output_name==a.name)&&g.action_arguments){f.push(g.action_arguments.newtype)}}}for(var b in f){if(f[b]=="input"||issubtype(f[b],this.datatypes[c])){return true}}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a){this.connect(b,a)}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;if(this.handle1){this.handle1.connect(this)}this.handle2=a;if(this.handle2){this.handle2.connect(this)}},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var n=function(c){return $(c).offset().left-d.offset().left};var i=function(c){return $(c).offset().top-d.offset().top};if(!this.handle1||!this.handle2){return}var h=n(this.handle1.element)+5;var g=i(this.handle1.element)+5;var p=n(this.handle2.element)+5;var m=i(this.handle2.element)+5;var f=100;var k=Math.min(h,p);var a=Math.max(h,p);var j=Math.min(g,m);var t=Math.max(g,m);var b=Math.min(Math.max(Math.abs(t-j)/2,100),300);var o=k-f;var s=j-f;var q=a-k+2*f;var l=t-j+2*f;this.canvas.style.left=o+"px";this.canvas.style.top=s+"px";this.canvas.setAttribute("width",q);this.canvas.setAttribute("height",l);h-=o;g-=s;p-=o;m-=s;var r=this.canvas.getContext("2d");r.lineCap="round";r.strokeStyle=this.outer_color;r.lineWidth=7;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke();r.strokeStyle=this.inner_color;r.lineWidth=5;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{enable_input_terminal:function(f,b,c,a){var d=this;$(f).each(function(){var g=this.terminal=new InputTerminal(this,c,a);g.node=d;g.name=b;$(this).bind("dropinit",function(h,i){return $(i.drag).hasClass("output-terminal")&&g.can_accept(i.drag.terminal)}).bind("dropstart",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#BBFFBB"}}).bind("dropend",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#FFFFFF"}}).bind("drop",function(h,i){(new Connector(i.drag.terminal,g)).redraw()}).bind("hover",function(){if(g.connectors.length>0){var h=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='buttons'></div>").append($("<img/>").attr("src",galaxy_config.root+"static/images/delete_icon.png").click(function(){$.each(g.connectors,function(j,i){if(i){i.destroy()}});h.remove()}))).bind("mouseleave",function(){$(this).remove()});h.css({top:$(this).offset().top-2,left:$(this).offset().left-h.width(),"padding-right":$(this).width()}).show()}});d.input_terminals[b]=g})},enable_output_terminal:function(d,a,b){var c=this;$(d).each(function(){var g=this;var f=this.terminal=new OutputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dragstart",function(j,k){$(k.available).addClass("input-terminal-active");workflow.check_changes_in_active_form();var i=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);i.terminal=new OutputTerminal(i);var l=new Connector();l.dragging=true;l.connect(this.terminal,i.terminal);return i}).bind("drag",function(i,j){var h=function(){var l=$(j.proxy).offsetParent().offset(),k=j.offsetX-l.left,m=j.offsetY-l.top;$(j.proxy).css({left:k,top:m});j.proxy.terminal.redraw();canvas_manager.update_viewport_overlay()};h();$("#canvas-container").get(0).scroll_panel.test(i,h)}).bind("dragend",function(h,i){i.proxy.terminal.connectors[0].destroy();$(i.proxy).remove();$(i.available).removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()});c.output_terminals[a]=f})},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(h){var g=this.element;if(h.type){this.type=h.type}this.name=h.name;this.form_html=h.form_html;this.tool_state=h.tool_state;this.tool_errors=h.tool_errors;this.tooltip=h.tooltip?h.tooltip:"";this.annotation=h.annotation;this.post_job_actions=h.post_job_actions?h.post_job_actions:{};this.workflow_outputs=h.workflow_outputs?h.workflow_outputs:[];if(this.tool_errors){g.addClass("tool-node-error")}else{g.removeClass("tool-node-error")}var d=this;var c=Math.max(150,g.width());var a=g.find(".toolFormBody");a.find("div").remove();var i=$("<div class='inputs'></div>").appendTo(a);$.each(h.data_inputs,function(k,f){var j=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(j,f.name,f.extensions,f.multiple);var b=$("<div class='form-row dataRow input-data-row' name='"+f.name+"'>"+f.label+"</div>");b.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(b);c=Math.max(c,b.outerWidth());b.css({position:"",left:"",top:"",display:""});b.remove();i.append(b.prepend(j))});if((h.data_inputs.length>0)&&(h.data_outputs.length>0)){a.append($("<div class='rule'></div>"))}$.each(h.data_outputs,function(k,b){var j=$("<div class='terminal output-terminal'></div>");d.enable_output_terminal(j,b.name,b.extensions);var f=b.name;if(b.extensions.indexOf("input")<0){f=f+" ("+b.extensions.join(", ")+")"}var m=$("<div class='form-row dataRow'>"+f+"</div>");if(d.type=="tool"){var l=$("<div class='callout "+f+"'></div>").css({display:"none"}).append($("<div class='buttons'></div>").append($("<img/>").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png").click(function(){if($.inArray(b.name,d.workflow_outputs)!=-1){d.workflow_outputs.splice($.inArray(b.name,d.workflow_outputs),1);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{d.workflow_outputs.push(b.name);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}workflow.has_changes=true;canvas_manager.draw_overview()}))).tooltip({delay:500,title:"Flag this as a workflow output. All non-flagged outputs will be hidden."});l.css({top:"50%",margin:"-8px 0px 0px 0px",right:8});l.show();m.append(l);if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}m.hover(function(){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-yellow.png")},function(){if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}})}m.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(m);c=Math.max(c,m.outerWidth()+17);m.css({position:"",left:"",top:"",display:""});m.detach();a.append(m.append(j))});g.css("width",Math.min(250,Math.max(g.width(),c)));workflow.node_changed(this)},update_field_data:function(f){var c=$(this.element),d=this;this.tool_state=f.tool_state;this.form_html=f.form_html;this.tool_errors=f.tool_errors;this.annotation=f.annotation;var g=$.parseJSON(f.post_job_actions);this.post_job_actions=g?g:{};if(this.tool_errors){c.addClass("tool-node-error")}else{c.removeClass("tool-node-error")}var h=c.find("div.inputs");var b=$("<div class='inputs'></div>");var a=h.find("div.input-data-row");$.each(f.data_inputs,function(l,j){var k=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(k,j.name,j.extensions,j.multiple);h.find("div[name='"+j.name+"']").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){k[0].terminal.connectors[0]=i;i.handle2=k[0].terminal}});$(this).remove()});b.append($("<div class='form-row dataRow input-data-row' name='"+j.name+"'>"+j.label+"</div>").prepend(k))});h.replaceWith(b);h.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.changed();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},changed:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false;this.active_form_has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},rectify_workflow_outputs:function(){var b=false;var a=false;$.each(this.nodes,function(c,d){if(d.workflow_outputs&&d.workflow_outputs.length>0){b=true}$.each(d.post_job_actions,function(g,f){if(f.action_type==="HideDatasetAction"){a=true}})});if(b!==false||a!==false){$.each(this.nodes,function(c,g){if(g.type==="tool"){var f=false;if(g.post_job_actions==null){g.post_job_actions={};f=true}var d=[];$.each(g.post_job_actions,function(i,h){if(h.action_type=="HideDatasetAction"){d.push(i)}});if(d.length>0){$.each(d,function(h,j){f=true;delete g.post_job_actions[j]})}if(b){$.each(g.output_terminals,function(i,j){var h=true;$.each(g.workflow_outputs,function(l,m){if(j.name===m){h=false}});if(h===true){f=true;var k={action_type:"HideDatasetAction",output_name:j.name,action_arguments:{}};g.post_job_actions["HideDatasetAction"+j.name]=null;g.post_job_actions["HideDatasetAction"+j.name]=k}})}if(workflow.active_node==g&&f===true){workflow.reload_active_node()}}})}},to_simple:function(){var a={};$.each(this.nodes,function(c,f){var g={};$.each(f.input_terminals,function(i,j){g[j.name]=null;var h=[];$.each(j.connectors,function(k,l){h[k]={id:l.handle1.node.id,output_name:l.handle1.name};g[j.name]=h})});var b={};if(f.post_job_actions){$.each(f.post_job_actions,function(j,h){var k={action_type:h.action_type,output_name:h.output_name,action_arguments:h.action_arguments};b[h.action_type+h.output_name]=null;b[h.action_type+h.output_name]=k})}if(!f.workflow_outputs){f.workflow_outputs=[]}var d={id:f.id,type:f.type,tool_id:f.tool_id,tool_state:f.tool_state,tool_errors:f.tool_errors,input_connections:g,position:$(f.element).position(),annotation:f.annotation,post_job_actions:f.post_job_actions,workflow_outputs:f.workflow_outputs};a[f.id]=d});return{steps:a}},from_simple:function(b){wf=this;var c=0;wf.name=b.name;var a=false;$.each(b.steps,function(g,f){var d=prebuild_node("tool",f.name,f.tool_id);d.init_field_data(f);if(f.position){d.element.css({top:f.position.top,left:f.position.left})}d.id=f.id;wf.nodes[d.id]=d;c=Math.max(c,parseInt(g));if(!a&&d.type==="tool"){if(d.workflow_outputs.length>0){a=true}else{$.each(d.post_job_actions,function(i,h){if(h.action_type==="HideDatasetAction"){a=true}})}}});wf.id_counter=c+1;$.each(b.steps,function(g,f){var d=wf.nodes[g];$.each(f.input_connections,function(i,h){if(h){if($.isArray(h)){$.each(h,function(m,k){var n=wf.nodes[k.id];var o=new Connector();o.connect(n.output_terminals[k.output_name],d.input_terminals[i]);o.redraw()})}else{var j=wf.nodes[h.id];var l=new Connector();l.connect(j.output_terminals[h.output_name],d.input_terminals[i]);l.redraw()}}});if(a&&d.type==="tool"){$.each(d.output_terminals,function(h,i){if(d.post_job_actions["HideDatasetAction"+i.name]===undefined){d.workflow_outputs.push(i.name);callout=$(d.element).find(".callout."+i.name);callout.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png");workflow.has_changes=true}})}})},check_changes_in_active_form:function(){if(this.active_form_has_changes){this.has_changes=true;$("#right-content").find("form").submit();this.active_form_has_changes=false}},reload_active_node:function(){if(this.active_node){var a=this.active_node;this.clear_active_node();this.activate_node(a)}},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.check_changes_in_active_form();this.clear_active_node();parent.show_form_for_tool(a.form_html+a.tooltip,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){this.check_changes_in_active_form();parent.show_form_for_tool(a.form_html+a.tooltip,a)}},layout:function(){this.check_changes_in_active_form();this.has_changes=true;var i={};var b={};$.each(this.nodes,function(l,k){if(i[l]===undefined){i[l]=0}if(b[l]===undefined){b[l]=[]}});$.each(this.nodes,function(l,k){$.each(k.input_terminals,function(m,n){$.each(n.connectors,function(p,q){var o=q.handle1.node;i[k.id]+=1;b[o.id].push(k.id)})})});node_ids_by_level=[];while(true){level_parents=[];for(var a in i){if(i[a]==0){level_parents.push(a)}}if(level_parents.length==0){break}node_ids_by_level.push(level_parents);for(var f in level_parents){var j=level_parents[f];delete i[j];for(var g in b[j]){i[b[j][g]]-=1}}}if(i.length){return}var d=this.nodes;var h=80;v_pad=30;var c=h;$.each(node_ids_by_level,function(k,l){l.sort(function(p,o){return $(d[p].element).position().top-$(d[o].element).position().top});var m=0;var n=v_pad;$.each(l,function(o,r){var q=d[r];var p=$(q.element);$(p).css({top:n,left:c});m=Math.max(m,$(p).width());n+=$(p).height()+v_pad});c+=m+h});$.each(d,function(k,l){l.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(h,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var i=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var h=fix_delta(a.ymin,100);d=Math.max(d,f.left);h=Math.max(h,f.top);var c=f.left-d;var g=f.top-h;var b=round_up(a.xmax+100,100)+d;var j=round_up(a.ymax+100,100)+h;b=Math.max(b,-c+i.width());j=Math.max(j,-g+i.height());this.canvas_container.css({left:c,top:g,width:b,height:j});this.canvas_container.children().each(function(){var k=$(this).position();$(this).css("left",k.left+d);$(this).css("top",k.top+h)})}});function fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(l,j,r){var i=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node(i);g.type=l;if(l=="tool"){g.tool_id=r}var n=$("<div class='toolFormTitle unselectable'>"+j+"</div>");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("<div class='toolFormBody'></div>");var h="<div><img height='16' align='middle' src='"+galaxy_config.root+"static/images/loading_small_white_bg.gif'/> loading tool info...</div>";m.append(h);g.form_html=h;i.append(m);var k=$("<div class='buttons' style='float: right;'></div>");k.append($("<img/>").attr("src",galaxy_config.root+"static/images/delete_icon.png").click(function(b){g.destroy()}).hover(function(){$(this).attr("src",galaxy_config.root+"static/images/delete_icon_dark.png")},function(){$(this).attr("src",galaxy_config.root+"static/images/delete_icon.png")}));i.appendTo("#canvas-container");var d=$("#canvas-container").position();var c=$("#canvas-container").parent();var a=i.width();var q=i.height();i.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(q/2)});k.prependTo(n);a+=(k.width()+10);i.css("width",a);$(i).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o,p){var f=$(this).offsetParent().offset(),b=p.offsetX-f.left,s=p.offsetY-f.top;$(this).css({left:b,top:s});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(v,d){clearTimeout(this.timeout);var k=v.pageX,j=v.pageY,l=$(this.panel),c=l.position(),b=l.width(),i=l.height(),w=l.parent(),s=w.width(),a=w.height(),r=w.offset(),p=r.left,m=r.top,A=p+w.width(),u=m+w.height(),B=-(b-(s/2)),z=-(i-(a/2)),g=(s/2),f=(a/2),h=false,q=5,o=23;if(k-q<p){if(c.left<g){var n=Math.min(o,g-c.left);l.css("left",c.left+n);h=true}}else{if(k+q>A){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-q<m){if(c.top<f){var n=Math.min(o,f-c.top);l.css("top",c.top+n);h=true}}else{if(j+q>u){if(c.top>z){var n=Math.min(o,c.top-B);l.css("top",(c.top-n)+"px");h=true}}}}}if(h){d();var l=this;this.timeout=setTimeout(function(){l.test(v,d)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(){var g=$(this).offset();var f=b.cc.position();c=f.top-g.top;d=f.left-g.left}).bind("drag",function(f,g){a(g.offsetX+d,g.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("drag",function(k,l){var h=b.cc.width(),n=b.cc.height(),m=b.oc.width(),j=b.oc.height(),f=$(this).offsetParent().offset(),i=l.offsetX-f.left,g=l.offsetY-f.top;a(-(i/m*h),-(g/j*n))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g,i){var j=$(this).offsetParent();var h=j.offset();var f=Math.max(j.width()-(i.offsetX-h.left),j.height()-(i.offsetY-h.top));$(this).css({width:f,height:f});b.draw_overview()});$("#overview-border div").bind("drag",function(){})},update_viewport_overlay:function(){var b=this.cc,f=this.cv,a=this.oc,c=this.ov,d=b.width(),j=b.height(),i=a.width(),g=a.height(),h=b.position();c.css({left:-(h.left/d*i),top:-(h.top/j*g),width:(f.width()/d*i)-2,height:(f.height()/j*g)-2})},draw_overview:function(){var j=$("#overview-canvas"),m=j.parent().parent().width(),i=j.get(0).getContext("2d"),d=$("#canvas-container").width(),l=$("#canvas-container").height();var g,a,k,f;var h=this.cv.width();var b=this.cv.height();if(d<h&&l<b){k=d/h*m;f=(m-k)/2;g=l/b*m;a=(m-g)/2}else{if(d<l){a=0;g=m;k=Math.ceil(g*d/l);f=(m-k)/2}else{k=m;f=0;g=Math.ceil(k*l/d);a=(m-g)/2}}j.parent().css({left:f,top:a,width:k,height:g});j.attr("width",k);j.attr("height",g);$.each(workflow.nodes,function(t,q){i.fillStyle="#D2C099";i.strokeStyle="#D8B365";i.lineWidth=1;var s=$(q.element),n=s.position(),c=n.left/d*k,r=n.top/l*g,o=s.width()/d*k,p=s.height()/l*g;if(q.tool_errors){i.fillStyle="#FFCCCC";i.strokeStyle="#AA6666"}else{if(q.workflow_outputs!=undefined&&q.workflow_outputs.length>0){i.fillStyle="#E8A92D";i.strokeStyle="#E8A92D"}}i.fillRect(c,r,o,p);i.strokeRect(c,r,o,p)});this.update_viewport_overlay()}});
\ No newline at end of file
+function Terminal(a){this.element=a;this.connectors=[]}$.extend(Terminal.prototype,{connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}});function OutputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}OutputTerminal.prototype=new Terminal();function InputTerminal(b,c,a){Terminal.call(this,b);this.datatypes=c;this.multiple=a}InputTerminal.prototype=new Terminal();$.extend(InputTerminal.prototype,{can_accept:function(a){if(this.connectors.length<1||this.multiple){for(var c in this.datatypes){var f=new Array();f=f.concat(a.datatypes);if(a.node.post_job_actions){for(var d in a.node.post_job_actions){var g=a.node.post_job_actions[d];if(g.action_type=="ChangeDatatypeAction"&&(g.output_name==""||g.output_name==a.name)&&g.action_arguments){f.push(g.action_arguments.newtype)}}}for(var b in f){if(f[b]=="input"||issubtype(f[b],this.datatypes[c])){return true}}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a){this.connect(b,a)}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;if(this.handle1){this.handle1.connect(this)}this.handle2=a;if(this.handle2){this.handle2.connect(this)}},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var n=function(c){return $(c).offset().left-d.offset().left};var i=function(c){return $(c).offset().top-d.offset().top};if(!this.handle1||!this.handle2){return}var h=n(this.handle1.element)+5;var g=i(this.handle1.element)+5;var p=n(this.handle2.element)+5;var m=i(this.handle2.element)+5;var f=100;var k=Math.min(h,p);var a=Math.max(h,p);var j=Math.min(g,m);var t=Math.max(g,m);var b=Math.min(Math.max(Math.abs(t-j)/2,100),300);var o=k-f;var s=j-f;var q=a-k+2*f;var l=t-j+2*f;this.canvas.style.left=o+"px";this.canvas.style.top=s+"px";this.canvas.setAttribute("width",q);this.canvas.setAttribute("height",l);h-=o;g-=s;p-=o;m-=s;var r=this.canvas.getContext("2d");r.lineCap="round";r.strokeStyle=this.outer_color;r.lineWidth=7;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke();r.strokeStyle=this.inner_color;r.lineWidth=5;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{enable_input_terminal:function(f,b,c,a){var d=this;$(f).each(function(){var g=this.terminal=new InputTerminal(this,c,a);g.node=d;g.name=b;$(this).bind("dropinit",function(h,i){return $(i.drag).hasClass("output-terminal")&&g.can_accept(i.drag.terminal)}).bind("dropstart",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#BBFFBB"}}).bind("dropend",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#FFFFFF"}}).bind("drop",function(h,i){(new Connector(i.drag.terminal,g)).redraw()}).bind("hover",function(){if(g.connectors.length>0){var h=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='button'></div>").append($("<div/>").addClass("fa-icon-button fa-icon-remove").click(function(){$.each(g.connectors,function(j,i){if(i){i.destroy()}});h.remove()}))).bind("mouseleave",function(){$(this).remove()});h.css({top:$(this).offset().top-2,left:$(this).offset().left-h.width(),"padding-right":$(this).width()}).show()}});d.input_terminals[b]=g})},enable_output_terminal:function(d,a,b){var c=this;$(d).each(function(){var g=this;var f=this.terminal=new OutputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dragstart",function(j,k){$(k.available).addClass("input-terminal-active");workflow.check_changes_in_active_form();var i=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);i.terminal=new OutputTerminal(i);var l=new Connector();l.dragging=true;l.connect(this.terminal,i.terminal);return i}).bind("drag",function(i,j){var h=function(){var l=$(j.proxy).offsetParent().offset(),k=j.offsetX-l.left,m=j.offsetY-l.top;$(j.proxy).css({left:k,top:m});j.proxy.terminal.redraw();canvas_manager.update_viewport_overlay()};h();$("#canvas-container").get(0).scroll_panel.test(i,h)}).bind("dragend",function(h,i){i.proxy.terminal.connectors[0].destroy();$(i.proxy).remove();$(i.available).removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()});c.output_terminals[a]=f})},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(h){var g=this.element;if(h.type){this.type=h.type}this.name=h.name;this.form_html=h.form_html;this.tool_state=h.tool_state;this.tool_errors=h.tool_errors;this.tooltip=h.tooltip?h.tooltip:"";this.annotation=h.annotation;this.post_job_actions=h.post_job_actions?h.post_job_actions:{};this.workflow_outputs=h.workflow_outputs?h.workflow_outputs:[];if(this.tool_errors){g.addClass("tool-node-error")}else{g.removeClass("tool-node-error")}var d=this;var c=Math.max(150,g.width());var a=g.find(".toolFormBody");a.find("div").remove();var i=$("<div class='inputs'></div>").appendTo(a);$.each(h.data_inputs,function(k,f){var j=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(j,f.name,f.extensions,f.multiple);var b=$("<div class='form-row dataRow input-data-row' name='"+f.name+"'>"+f.label+"</div>");b.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(b);c=Math.max(c,b.outerWidth());b.css({position:"",left:"",top:"",display:""});b.remove();i.append(b.prepend(j))});if((h.data_inputs.length>0)&&(h.data_outputs.length>0)){a.append($("<div class='rule'></div>"))}$.each(h.data_outputs,function(k,b){var j=$("<div class='terminal output-terminal'></div>");d.enable_output_terminal(j,b.name,b.extensions);var f=b.name;if(b.extensions.indexOf("input")<0){f=f+" ("+b.extensions.join(", ")+")"}var m=$("<div class='form-row dataRow'>"+f+"</div>");if(d.type=="tool"){var l=$("<div class='callout "+f+"'></div>").css({display:"none"}).append($("<div class='buttons'></div>").append($("<img/>").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png").click(function(){if($.inArray(b.name,d.workflow_outputs)!=-1){d.workflow_outputs.splice($.inArray(b.name,d.workflow_outputs),1);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{d.workflow_outputs.push(b.name);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}workflow.has_changes=true;canvas_manager.draw_overview()}))).tooltip({delay:500,title:"Flag this as a workflow output. All non-flagged outputs will be hidden."});l.css({top:"50%",margin:"-8px 0px 0px 0px",right:8});l.show();m.append(l);if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}m.hover(function(){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-yellow.png")},function(){if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}})}m.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(m);c=Math.max(c,m.outerWidth()+17);m.css({position:"",left:"",top:"",display:""});m.detach();a.append(m.append(j))});g.css("width",Math.min(250,Math.max(g.width(),c)));workflow.node_changed(this)},update_field_data:function(f){var c=$(this.element),d=this;this.tool_state=f.tool_state;this.form_html=f.form_html;this.tool_errors=f.tool_errors;this.annotation=f.annotation;var g=$.parseJSON(f.post_job_actions);this.post_job_actions=g?g:{};if(this.tool_errors){c.addClass("tool-node-error")}else{c.removeClass("tool-node-error")}var h=c.find("div.inputs");var b=$("<div class='inputs'></div>");var a=h.find("div.input-data-row");$.each(f.data_inputs,function(l,j){var k=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(k,j.name,j.extensions,j.multiple);h.find("div[name='"+j.name+"']").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){k[0].terminal.connectors[0]=i;i.handle2=k[0].terminal}});$(this).remove()});b.append($("<div class='form-row dataRow input-data-row' name='"+j.name+"'>"+j.label+"</div>").prepend(k))});h.replaceWith(b);h.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.changed();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},changed:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false;this.active_form_has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},rectify_workflow_outputs:function(){var b=false;var a=false;$.each(this.nodes,function(c,d){if(d.workflow_outputs&&d.workflow_outputs.length>0){b=true}$.each(d.post_job_actions,function(g,f){if(f.action_type==="HideDatasetAction"){a=true}})});if(b!==false||a!==false){$.each(this.nodes,function(c,g){if(g.type==="tool"){var f=false;if(g.post_job_actions==null){g.post_job_actions={};f=true}var d=[];$.each(g.post_job_actions,function(i,h){if(h.action_type=="HideDatasetAction"){d.push(i)}});if(d.length>0){$.each(d,function(h,j){f=true;delete g.post_job_actions[j]})}if(b){$.each(g.output_terminals,function(i,j){var h=true;$.each(g.workflow_outputs,function(l,m){if(j.name===m){h=false}});if(h===true){f=true;var k={action_type:"HideDatasetAction",output_name:j.name,action_arguments:{}};g.post_job_actions["HideDatasetAction"+j.name]=null;g.post_job_actions["HideDatasetAction"+j.name]=k}})}if(workflow.active_node==g&&f===true){workflow.reload_active_node()}}})}},to_simple:function(){var a={};$.each(this.nodes,function(c,f){var g={};$.each(f.input_terminals,function(i,j){g[j.name]=null;var h=[];$.each(j.connectors,function(k,l){h[k]={id:l.handle1.node.id,output_name:l.handle1.name};g[j.name]=h})});var b={};if(f.post_job_actions){$.each(f.post_job_actions,function(j,h){var k={action_type:h.action_type,output_name:h.output_name,action_arguments:h.action_arguments};b[h.action_type+h.output_name]=null;b[h.action_type+h.output_name]=k})}if(!f.workflow_outputs){f.workflow_outputs=[]}var d={id:f.id,type:f.type,tool_id:f.tool_id,tool_state:f.tool_state,tool_errors:f.tool_errors,input_connections:g,position:$(f.element).position(),annotation:f.annotation,post_job_actions:f.post_job_actions,workflow_outputs:f.workflow_outputs};a[f.id]=d});return{steps:a}},from_simple:function(b){wf=this;var c=0;wf.name=b.name;var a=false;$.each(b.steps,function(g,f){var d=prebuild_node("tool",f.name,f.tool_id);d.init_field_data(f);if(f.position){d.element.css({top:f.position.top,left:f.position.left})}d.id=f.id;wf.nodes[d.id]=d;c=Math.max(c,parseInt(g));if(!a&&d.type==="tool"){if(d.workflow_outputs.length>0){a=true}else{$.each(d.post_job_actions,function(i,h){if(h.action_type==="HideDatasetAction"){a=true}})}}});wf.id_counter=c+1;$.each(b.steps,function(g,f){var d=wf.nodes[g];$.each(f.input_connections,function(i,h){if(h){if($.isArray(h)){$.each(h,function(m,k){var n=wf.nodes[k.id];var o=new Connector();o.connect(n.output_terminals[k.output_name],d.input_terminals[i]);o.redraw()})}else{var j=wf.nodes[h.id];var l=new Connector();l.connect(j.output_terminals[h.output_name],d.input_terminals[i]);l.redraw()}}});if(a&&d.type==="tool"){$.each(d.output_terminals,function(h,i){if(d.post_job_actions["HideDatasetAction"+i.name]===undefined){d.workflow_outputs.push(i.name);callout=$(d.element).find(".callout."+i.name);callout.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png");workflow.has_changes=true}})}})},check_changes_in_active_form:function(){if(this.active_form_has_changes){this.has_changes=true;$("#right-content").find("form").submit();this.active_form_has_changes=false}},reload_active_node:function(){if(this.active_node){var a=this.active_node;this.clear_active_node();this.activate_node(a)}},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.check_changes_in_active_form();this.clear_active_node();parent.show_form_for_tool(a.form_html+a.tooltip,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){this.check_changes_in_active_form();parent.show_form_for_tool(a.form_html+a.tooltip,a)}},layout:function(){this.check_changes_in_active_form();this.has_changes=true;var i={};var b={};$.each(this.nodes,function(l,k){if(i[l]===undefined){i[l]=0}if(b[l]===undefined){b[l]=[]}});$.each(this.nodes,function(l,k){$.each(k.input_terminals,function(m,n){$.each(n.connectors,function(p,q){var o=q.handle1.node;i[k.id]+=1;b[o.id].push(k.id)})})});node_ids_by_level=[];while(true){level_parents=[];for(var a in i){if(i[a]==0){level_parents.push(a)}}if(level_parents.length==0){break}node_ids_by_level.push(level_parents);for(var f in level_parents){var j=level_parents[f];delete i[j];for(var g in b[j]){i[b[j][g]]-=1}}}if(i.length){return}var d=this.nodes;var h=80;v_pad=30;var c=h;$.each(node_ids_by_level,function(k,l){l.sort(function(p,o){return $(d[p].element).position().top-$(d[o].element).position().top});var m=0;var n=v_pad;$.each(l,function(o,r){var q=d[r];var p=$(q.element);$(p).css({top:n,left:c});m=Math.max(m,$(p).width());n+=$(p).height()+v_pad});c+=m+h});$.each(d,function(k,l){l.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(h,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var i=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var h=fix_delta(a.ymin,100);d=Math.max(d,f.left);h=Math.max(h,f.top);var c=f.left-d;var g=f.top-h;var b=round_up(a.xmax+100,100)+d;var j=round_up(a.ymax+100,100)+h;b=Math.max(b,-c+i.width());j=Math.max(j,-g+i.height());this.canvas_container.css({left:c,top:g,width:b,height:j});this.canvas_container.children().each(function(){var k=$(this).position();$(this).css("left",k.left+d);$(this).css("top",k.top+h)})}});function fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(l,j,r){var i=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node(i);g.type=l;if(l=="tool"){g.tool_id=r}var n=$("<div class='toolFormTitle unselectable'>"+j+"</div>");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("<div class='toolFormBody'></div>");var h="<div><img height='16' align='middle' src='"+galaxy_config.root+"static/images/loading_small_white_bg.gif'/> loading tool info...</div>";m.append(h);g.form_html=h;i.append(m);var k=$("<div class='buttons' style='float: right;'></div>");k.append($("<div>").addClass("fa-icon-button fa-icon-remove").click(function(b){g.destroy()}));i.appendTo("#canvas-container");var d=$("#canvas-container").position();var c=$("#canvas-container").parent();var a=i.width();var q=i.height();i.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(q/2)});k.prependTo(n);a+=(k.width()+10);i.css("width",a);$(i).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o,p){var f=$(this).offsetParent().offset(),b=p.offsetX-f.left,s=p.offsetY-f.top;$(this).css({left:b,top:s});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(v,d){clearTimeout(this.timeout);var k=v.pageX,j=v.pageY,l=$(this.panel),c=l.position(),b=l.width(),i=l.height(),w=l.parent(),s=w.width(),a=w.height(),r=w.offset(),p=r.left,m=r.top,A=p+w.width(),u=m+w.height(),B=-(b-(s/2)),z=-(i-(a/2)),g=(s/2),f=(a/2),h=false,q=5,o=23;if(k-q<p){if(c.left<g){var n=Math.min(o,g-c.left);l.css("left",c.left+n);h=true}}else{if(k+q>A){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-q<m){if(c.top<f){var n=Math.min(o,f-c.top);l.css("top",c.top+n);h=true}}else{if(j+q>u){if(c.top>z){var n=Math.min(o,c.top-B);l.css("top",(c.top-n)+"px");h=true}}}}}if(h){d();var l=this;this.timeout=setTimeout(function(){l.test(v,d)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(){var g=$(this).offset();var f=b.cc.position();c=f.top-g.top;d=f.left-g.left}).bind("drag",function(f,g){a(g.offsetX+d,g.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("drag",function(k,l){var h=b.cc.width(),n=b.cc.height(),m=b.oc.width(),j=b.oc.height(),f=$(this).offsetParent().offset(),i=l.offsetX-f.left,g=l.offsetY-f.top;a(-(i/m*h),-(g/j*n))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g,i){var j=$(this).offsetParent();var h=j.offset();var f=Math.max(j.width()-(i.offsetX-h.left),j.height()-(i.offsetY-h.top));$(this).css({width:f,height:f});b.draw_overview()});$("#overview-border div").bind("drag",function(){})},update_viewport_overlay:function(){var b=this.cc,f=this.cv,a=this.oc,c=this.ov,d=b.width(),j=b.height(),i=a.width(),g=a.height(),h=b.position();c.css({left:-(h.left/d*i),top:-(h.top/j*g),width:(f.width()/d*i)-2,height:(f.height()/j*g)-2})},draw_overview:function(){var j=$("#overview-canvas"),m=j.parent().parent().width(),i=j.get(0).getContext("2d"),d=$("#canvas-container").width(),l=$("#canvas-container").height();var g,a,k,f;var h=this.cv.width();var b=this.cv.height();if(d<h&&l<b){k=d/h*m;f=(m-k)/2;g=l/b*m;a=(m-g)/2}else{if(d<l){a=0;g=m;k=Math.ceil(g*d/l);f=(m-k)/2}else{k=m;f=0;g=Math.ceil(k*l/d);a=(m-g)/2}}j.parent().css({left:f,top:a,width:k,height:g});j.attr("width",k);j.attr("height",g);$.each(workflow.nodes,function(t,q){i.fillStyle="#D2C099";i.strokeStyle="#D8B365";i.lineWidth=1;var s=$(q.element),n=s.position(),c=n.left/d*k,r=n.top/l*g,o=s.width()/d*k,p=s.height()/l*g;if(q.tool_errors){i.fillStyle="#FFCCCC";i.strokeStyle="#AA6666"}else{if(q.workflow_outputs!=undefined&&q.workflow_outputs.length>0){i.fillStyle="#E8A92D";i.strokeStyle="#E8A92D"}}i.fillRect(c,r,o,p);i.strokeRect(c,r,o,p)});this.update_viewport_overlay()}});
\ No newline at end of file
diff -r 5cbf058d648db06541540d11e6dd1d1535a12292 -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a templates/grid_base.mako
--- a/templates/grid_base.mako
+++ b/templates/grid_base.mako
@@ -84,10 +84,9 @@
/** Returns true if string denotes true. */
var is_true = function(s) { return _.indexOf(['True', 'true', 't'], s) !== -1; };
-
// Create grid.
var grid = new Grid({
- url_base: '${trans.request.path_url}',
+ url_base: location.pathname,
async: is_true('${grid.use_async}'),
async_ops: async_ops,
categorical_filters: categorical_filters,
@@ -95,6 +94,8 @@
sort_key: '${sort_key}',
show_item_checkboxes: is_true('${context.get('show_item_checkboxes', False)}'),
cur_page: ${cur_page_num},
+ // persistant page="all"
+ //cur_page: ('${cur_page_num}' === 'all')?('all'):(Number('${cur_page_num}')),
num_pages: ${num_pages}
});
diff -r 5cbf058d648db06541540d11e6dd1d1535a12292 -r 6f77298e8d1628fb55d8ba72a69ab62b7864bb7a templates/grid_common.mako
--- a/templates/grid_common.mako
+++ b/templates/grid_common.mako
@@ -102,8 +102,26 @@
## Print grid search/filtering UI.
<%def name="render_grid_filters( grid, render_advanced_search=True )">
+ <%
+ # Show advanced search if flag set or if there are filters for advanced search fields.
+ advanced_search_display = "none"
+ if 'advanced-search' in kwargs and kwargs['advanced-search'] in ['True', 'true']:
+ advanced_search_display = "block"
+
+ for column in grid.columns:
+ if column.filterable == "advanced":
+ ## Show div if current filter has value that is different from the default filter.
+ if column.key in cur_filter_dict and column.key in default_filter_dict and \
+ cur_filter_dict[column.key] != default_filter_dict[column.key]:
+ advanced_search_display = "block"
+
+ # do not show standard search if showing adv.
+ standard_search_display = "block"
+ if advanced_search_display == "block":
+ standard_search_display = "none"
+ %>
## Standard search.
- <div id="standard-search">
+ <div id="standard-search" style="display: ${standard_search_display};"><table><tr><td style="padding: 0;"><table>
@@ -139,19 +157,6 @@
</div>
## Advanced search.
- <%
- # Show advanced search if flag set or if there are filters for advanced search fields.
- advanced_search_display = "none"
- if 'advanced-search' in kwargs and kwargs['advanced-search'] in ['True', 'true']:
- advanced_search_display = "block"
-
- for column in grid.columns:
- if column.filterable == "advanced":
- ## Show div if current filter has value that is different from the default filter.
- if column.key in cur_filter_dict and column.key in default_filter_dict and \
- cur_filter_dict[column.key] != default_filter_dict[column.key]:
- advanced_search_display = "block"
- %><div id="advanced-search" style="display: ${advanced_search_display}; margin-top: 5px; border: 1px solid #ccc;"><table><tr><td style="text-align: left" colspan="100">
@@ -170,7 +175,7 @@
%if column.key in cur_filter_dict and column.key in default_filter_dict and \
cur_filter_dict[column.key] != default_filter_dict[column.key]:
<script type="text/javascript">
- $('#advanced-search').css("display", "none");
+ $('#advanced-search').css("display", "block");
</script>
%endif
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: QA: fix to deleting current history in test_get_data
by commits-noreply@bitbucket.org 19 Sep '13
by commits-noreply@bitbucket.org 19 Sep '13
19 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5cbf058d648d/
Changeset: 5cbf058d648d
User: carlfeberhard
Date: 2013-09-20 00:28:24
Summary: QA: fix to deleting current history in test_get_data
Affected #: 1 file
diff -r cb95dad5175ec10cf191bddcaf2e1d115546dd7c -r 5cbf058d648db06541540d11e6dd1d1535a12292 test/functional/test_get_data.py
--- a/test/functional/test_get_data.py
+++ b/test/functional/test_get_data.py
@@ -22,7 +22,7 @@
"""
# in order to remove a lot of boiler plate - and not have cascading errors
history = get_latest_history_for_user( user )
- self.delete_history( id=self.security.encode_id( history.id ) )
+ self.delete_current_history()
self.is_history_empty()
return get_latest_history_for_user( user )
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: QA, browser tests: dump stdout if casper didn't return good JSON
by commits-noreply@bitbucket.org 19 Sep '13
by commits-noreply@bitbucket.org 19 Sep '13
19 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/cb95dad5175e/
Changeset: cb95dad5175e
User: carlfeberhard
Date: 2013-09-19 21:56:29
Summary: QA, browser tests: dump stdout if casper didn't return good JSON
Affected #: 1 file
diff -r 3a15758ba67e2429698184a4300c9608c65ce06d -r cb95dad5175ec10cf191bddcaf2e1d115546dd7c test/casperjs/casperjs_runner.py
--- a/test/casperjs/casperjs_runner.py
+++ b/test/casperjs/casperjs_runner.py
@@ -176,7 +176,14 @@
err_string = ( "%s\n%s" %( get_msg( last_error ),
self.browser_backtrace_to_string( get_trace( last_error ) ) ) )
- # if we couldn't parse json from what's returned on the error, raise a vanilla exc
+ # if we couldn't parse json from what's returned on the error, dump stdout
+ except ValueError, val_err:
+ if str( val_err ) == 'No JSON object could be decoded':
+ log.debug( '(error parsing returned JSON from casperjs, dumping stdout...)\n:%s', stdout_output )
+ else:
+ raise
+
+ # otherwise, raise a vanilla exc
except Exception, exc:
log.debug( '(failed to parse error returned from %s: %s)', _PATH_TO_HEADLESS, str( exc ) )
return HeadlessJSJavascriptError(
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: Visualizations registry, QA: initial unit tests; Plugin framework unit tests: remove unneeded tests
by commits-noreply@bitbucket.org 19 Sep '13
by commits-noreply@bitbucket.org 19 Sep '13
19 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/3a15758ba67e/
Changeset: 3a15758ba67e
User: carlfeberhard
Date: 2013-09-19 16:09:19
Summary: Visualizations registry, QA: initial unit tests; Plugin framework unit tests: remove unneeded tests
Affected #: 6 files
diff -r 285453d3908440a10c8863fe90f9833df5a5e261 -r 3a15758ba67e2429698184a4300c9608c65ce06d lib/galaxy/visualization/registry.py
--- a/lib/galaxy/visualization/registry.py
+++ b/lib/galaxy/visualization/registry.py
@@ -82,8 +82,9 @@
:rtype: bool
:returns: True if the path contains a plugin
"""
- # plugin_path must be a directory, have a config dir
+ # plugin_path must be a directory, have a config dir, and a config file matching the plugin dir name
if not os.path.isdir( plugin_path ):
+ # super won't work here - different criteria
return False
if not 'config' in os.listdir( plugin_path ):
return False
@@ -112,6 +113,7 @@
# config file is required, otherwise skip this visualization
plugin[ 'config_file' ] = os.path.join( plugin_path, 'config', ( plugin.name + '.xml' ) )
config = self.config_parser.parse_file( plugin.config_file )
+
if not config:
return None
plugin[ 'config' ] = config
diff -r 285453d3908440a10c8863fe90f9833df5a5e261 -r 3a15758ba67e2429698184a4300c9608c65ce06d test/unit/visualizations/registry/test_VisualizationsRegistry.py
--- /dev/null
+++ b/test/unit/visualizations/registry/test_VisualizationsRegistry.py
@@ -0,0 +1,156 @@
+"""
+"""
+import os
+import imp
+import unittest
+
+utility = imp.load_source( 'utility', '../../util/utility.py' )
+log = utility.set_up_filelogger( __name__ + '.log' )
+
+relative_test_path = '/test/unit/visualizations/registry'
+utility.add_galaxy_lib_to_path( relative_test_path )
+
+from galaxy.visualization.registry import VisualizationsRegistry
+
+base_mock = imp.load_source( 'mock', '../../web/base/mock.py' )
+
+# ----------------------------------------------------------------------------- globals
+glx_dir = os.getcwd().replace( relative_test_path, '' )
+template_cache_dir = os.path.join( glx_dir, 'database', 'compiled_templates' )
+vis_reg_path = 'config/plugins/visualizations'
+
+config1 = """\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE visualization SYSTEM "../../visualization.dtd">
+<visualization name="scatterplot">
+ <data_sources>
+ <data_source>
+ <model_class>HistoryDatasetAssociation</model_class>
+ <test type="isinstance" test_attr="datatype" result_type="datatype">tabular.Tabular</test>
+ <to_param param_attr="id">dataset_id</to_param>
+ </data_source>
+ </data_sources>
+ <params>
+ <param type="dataset" var_name_in_template="hda" required="true">dataset_id</param>
+ </params>
+ <template>scatterplot.mako</template>
+</visualization>
+"""
+
+# -----------------------------------------------------------------------------
+class VisualizationsRegistry_TestCase( unittest.TestCase ):
+
+ # ------------------------------------------------------------------------- vis plugin discovery
+ def test_plugin_load_from_repo( self ):
+ """should attempt load if criteria met"""
+ mock_app = base_mock.MockApp( glx_dir )
+ plugin_mgr = VisualizationsRegistry( mock_app,
+ directories_setting=vis_reg_path,
+ template_cache_dir=template_cache_dir )
+
+ expected_plugins_path = os.path.join( glx_dir, vis_reg_path )
+ expected_plugin_names = [
+ 'circster',
+ 'graphview',
+ 'phyloviz',
+ 'scatterplot',
+ 'sweepster',
+ 'trackster',
+ ]
+
+ self.assertEqual( plugin_mgr.base_url, 'visualizations' )
+ self.assertItemsEqual( plugin_mgr.directories, [ expected_plugins_path ] )
+ self.assertItemsEqual( plugin_mgr.plugins.keys(), expected_plugin_names )
+
+ scatterplot = plugin_mgr.plugins[ 'scatterplot' ]
+ self.assertEqual( scatterplot.name, 'scatterplot' )
+ self.assertEqual( scatterplot.path, os.path.join( expected_plugins_path, 'scatterplot' ) )
+ self.assertEqual( scatterplot.base_url, '/'.join([ plugin_mgr.base_url, scatterplot.name ]) )
+ self.assertTrue( scatterplot.serves_static )
+ self.assertEqual( scatterplot.static_path, os.path.join( scatterplot.path, 'static' ) )
+ self.assertEqual( scatterplot.static_url, '/'.join([ scatterplot.base_url, 'static' ]) )
+ self.assertTrue( scatterplot.serves_templates )
+ self.assertEqual( scatterplot.template_path, os.path.join( scatterplot.path, 'templates' ) )
+ self.assertEqual( scatterplot.template_lookup.__class__.__name__, 'TemplateLookup' )
+
+ trackster = plugin_mgr.plugins[ 'trackster' ]
+ self.assertEqual( trackster.name, 'trackster' )
+ self.assertEqual( trackster.path, os.path.join( expected_plugins_path, 'trackster' ) )
+ self.assertEqual( trackster.base_url, '/'.join([ plugin_mgr.base_url, trackster.name ]) )
+ self.assertFalse( trackster.serves_static )
+ self.assertFalse( trackster.serves_templates )
+
+ def test_plugin_load( self ):
+ """"""
+ mock_app_dir = base_mock.MockDir({
+ 'plugins' : {
+ 'vis1' : {
+ 'config' : {
+ 'vis1.xml' : config1
+ },
+ 'static' : {},
+ 'templates' : {},
+ },
+ 'vis2' : {
+ 'config' : {
+ 'vis2.xml' : config1
+ }
+ },
+ 'not_a_vis1' : {
+ 'config' : {
+ 'vis1.xml' : 'blerbler'
+ },
+ },
+ 'not_a_vis1' : {
+ # no config
+ 'static' : {},
+ 'templates' : {},
+ },
+ # empty
+ 'not_a_vis2' : {},
+ 'not_a_vis3' : 'blerbler',
+ # bad config
+ 'not_a_vis4' : {
+ 'config' : {
+ 'not_a_vis4.xml' : 'blerbler'
+ }
+ },
+ }
+ })
+ mock_app = base_mock.MockApp( mock_app_dir.root_path )
+ plugin_mgr = VisualizationsRegistry( mock_app,
+ directories_setting='plugins',
+ template_cache_dir='bler' )
+
+ expected_plugins_path = os.path.join( mock_app_dir.root_path, 'plugins' )
+ expected_plugin_names = [ 'vis1', 'vis2' ]
+
+ self.assertEqual( plugin_mgr.base_url, 'visualizations' )
+ self.assertItemsEqual( plugin_mgr.directories, [ expected_plugins_path ] )
+ self.assertItemsEqual( plugin_mgr.plugins.keys(), expected_plugin_names )
+
+ vis1 = plugin_mgr.plugins[ 'vis1' ]
+ self.assertEqual( vis1.name, 'vis1' )
+ self.assertEqual( vis1.path, os.path.join( expected_plugins_path, 'vis1' ) )
+ self.assertEqual( vis1.base_url, '/'.join([ plugin_mgr.base_url, vis1.name ]) )
+ self.assertTrue( vis1.serves_static )
+ self.assertEqual( vis1.static_path, os.path.join( vis1.path, 'static' ) )
+ self.assertEqual( vis1.static_url, '/'.join([ vis1.base_url, 'static' ]) )
+ self.assertTrue( vis1.serves_templates )
+ self.assertEqual( vis1.template_path, os.path.join( vis1.path, 'templates' ) )
+ self.assertEqual( vis1.template_lookup.__class__.__name__, 'TemplateLookup' )
+
+ vis2 = plugin_mgr.plugins[ 'vis2' ]
+ self.assertEqual( vis2.name, 'vis2' )
+ self.assertEqual( vis2.path, os.path.join( expected_plugins_path, 'vis2' ) )
+ self.assertEqual( vis2.base_url, '/'.join([ plugin_mgr.base_url, vis2.name ]) )
+ self.assertFalse( vis2.serves_static )
+ self.assertFalse( vis2.serves_templates )
+
+ mock_app_dir.remove()
+
+
+#TODO: config parser tests (in separate file)
+
+if __name__ == '__main__':
+ unittest.main()
diff -r 285453d3908440a10c8863fe90f9833df5a5e261 -r 3a15758ba67e2429698184a4300c9608c65ce06d test/unit/visualizations/registry/test_plugins.py
--- a/test/unit/visualizations/registry/test_plugins.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from os import makedirs
-from os.path import join, dirname, basename
-from tempfile import mkdtemp
-from shutil import rmtree
-
-from galaxy.visualization.registry import VisualizationsRegistry
-
-
-def test_visualization_loading():
- visualizations = __default_viz_root()
- registry = VisualizationsRegistry(visualizations, 'foo')
- assert "VisualizationsRegistry" in str(registry)
- assert visualizations in str(registry)
- assert registry.name == "visualizations"
- __assert_scatterplot_registered(registry)
- assert registry._get_template_paths() == [visualizations]
-
-
-def test_multiple_visualization_roots():
- temp_dir = mkdtemp()
- try:
- makedirs(join(temp_dir, "coolplugin5"))
- visualization_dirs = "%s,%s" % (__default_viz_root(), temp_dir)
- registry = VisualizationsRegistry(visualization_dirs, 'foo')
- __assert_scatterplot_registered(registry)
- assert "coolplugin5" in \
- [basename(path) for path in registry.get_plugin_directories()]
- assert registry._get_template_paths() == \
- [__default_viz_root(), temp_dir]
- finally:
- rmtree(temp_dir)
-
-
-def __assert_scatterplot_registered(registry):
- assert 'scatterplot' in \
- [basename(path) for path in registry.get_plugin_directories()]
-
-
-def __default_viz_root():
- galaxy_root = join(dirname(__file__), '..', '..')
- visualizations = join(galaxy_root, 'config', 'plugins', 'visualizations')
- return visualizations
diff -r 285453d3908440a10c8863fe90f9833df5a5e261 -r 3a15758ba67e2429698184a4300c9608c65ce06d test/unit/web/base/test_HookPluginManager.py
--- a/test/unit/web/base/test_HookPluginManager.py
+++ b/test/unit/web/base/test_HookPluginManager.py
@@ -88,7 +88,6 @@
self.assertItemsEqual( plugin_mgr.directories, [ expected_plugins_path ] )
self.assertItemsEqual( plugin_mgr.plugins.keys(), [ 'plugin1' ] )
- self.assertFalse( plugin_mgr.plugins.get( 'not_a_plugin', False ) )
plugin = plugin_mgr.plugins[ 'plugin1' ]
self.assertEqual( plugin.name, 'plugin1' )
@@ -249,6 +248,5 @@
mock_app_dir.remove()
-
if __name__ == '__main__':
unittest.main()
diff -r 285453d3908440a10c8863fe90f9833df5a5e261 -r 3a15758ba67e2429698184a4300c9608c65ce06d test/unit/web/base/test_PageServingPluginManager.py
--- a/test/unit/web/base/test_PageServingPluginManager.py
+++ b/test/unit/web/base/test_PageServingPluginManager.py
@@ -45,7 +45,6 @@
self.assertEqual( plugin_mgr.base_url, 'test' )
self.assertItemsEqual( plugin_mgr.directories, [ expected_plugins_path ] )
self.assertItemsEqual( plugin_mgr.plugins.keys(), [ 'plugin1', 'plugin2', 'plugin3' ] )
- self.assertFalse( plugin_mgr.plugins.get( 'not_a_plugin', False ) )
plugin1 = plugin_mgr.plugins[ 'plugin1' ]
self.assertEqual( plugin1.name, 'plugin1' )
diff -r 285453d3908440a10c8863fe90f9833df5a5e261 -r 3a15758ba67e2429698184a4300c9608c65ce06d test/unit/web/base/test_PluginManager.py
--- a/test/unit/web/base/test_PluginManager.py
+++ b/test/unit/web/base/test_PluginManager.py
@@ -36,7 +36,6 @@
self.assertEqual( plugin_mgr.plugins[ 'plugin1' ].path, os.path.join( expected_plugins_path, 'plugin1' ) )
self.assertEqual( plugin_mgr.plugins[ 'plugin2' ].name, 'plugin2' )
self.assertEqual( plugin_mgr.plugins[ 'plugin2' ].path, os.path.join( expected_plugins_path, 'plugin2' ) )
- self.assertFalse( plugin_mgr.plugins.get( 'file1', False ) )
mock_app_dir.remove()
@@ -60,7 +59,6 @@
self.assertEqual( plugin_mgr.plugins[ 'plugin1' ].path, os.path.join( expected_plugins_path, 'plugin1' ) )
self.assertEqual( plugin_mgr.plugins[ 'plugin2' ].name, 'plugin2' )
self.assertEqual( plugin_mgr.plugins[ 'plugin2' ].path, os.path.join( expected_plugins_path, 'plugin2' ) )
- self.assertFalse( plugin_mgr.plugins.get( 'file1', False ) )
def test_multiple_dirs( self ):
"""should search in multiple directories"""
@@ -94,8 +92,6 @@
self.assertEqual( plugin_mgr.plugins[ 'plugin3' ].path, os.path.join( expected_plugins_abs_path, 'plugin3' ) )
self.assertEqual( plugin_mgr.plugins[ 'plugin4' ].name, 'plugin4' )
self.assertEqual( plugin_mgr.plugins[ 'plugin4' ].path, os.path.join( expected_plugins_abs_path, 'plugin4' ) )
- self.assertFalse( plugin_mgr.plugins.get( 'file1', False ) )
- self.assertFalse( plugin_mgr.plugins.get( 'file2', False ) )
if __name__ == '__main__':
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: Include hg19 in ucsc_build_sites.txt
by commits-noreply@bitbucket.org 19 Sep '13
by commits-noreply@bitbucket.org 19 Sep '13
19 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/285453d39084/
Changeset: 285453d39084
User: dannon
Date: 2013-09-19 15:59:49
Summary: Include hg19 in ucsc_build_sites.txt
Affected #: 1 file
diff -r 6eb358cc82c15782abc2c4e912f935830dfc2ece -r 285453d3908440a10c8863fe90f9833df5a5e261 tool-data/shared/ucsc/ucsc_build_sites.txt
--- a/tool-data/shared/ucsc/ucsc_build_sites.txt
+++ b/tool-data/shared/ucsc/ucsc_build_sites.txt
@@ -1,5 +1,5 @@
#Harvested from http://genome.ucsc.edu/cgi-bin/das/dsn
-main http://genome.ucsc.edu/cgi-bin/hgTracks? priPac1,danRer4,mm9,mm8,droAna1,mm5,caeRem2,mm7,mm6,panTro1,dm3,panTro2,anoCar1,ce4,galGal3,galGal2,ce1,rn3,rn2,droMoj1,droMoj2,rn4,droYak1,droYak2,dp3,dp2,dm1,canFam1,danRer5,canFam2,danRer3,danRer2,ornAna1,ci2,ci1,tetNig1,bosTau1,bosTau3,bosTau2,equCab1,oryLat1,droAna2,droEre1,ponAbe2,rheMac2,sacCer1,droPer1,droSim1,monDom1,cb1,dm2,droSec1,strPur1,droVir2,droVir1,strPur2,sc1,xenTro1,droGri1,xenTro2,cb3,gasAcu1,caePb1,anoGam1,fr2,fr1,hg15,hg16,hg17,hg18,felCat3,apiMel2,monDom4,apiMel1,ce2
+main http://genome.ucsc.edu/cgi-bin/hgTracks? priPac1,danRer4,mm9,mm8,droAna1,mm5,caeRem2,mm7,mm6,panTro1,dm3,panTro2,anoCar1,ce4,galGal3,galGal2,ce1,rn3,rn2,droMoj1,droMoj2,rn4,droYak1,droYak2,dp3,dp2,dm1,canFam1,danRer5,canFam2,danRer3,danRer2,ornAna1,ci2,ci1,tetNig1,bosTau1,bosTau3,bosTau2,equCab1,oryLat1,droAna2,droEre1,ponAbe2,rheMac2,sacCer1,droPer1,droSim1,monDom1,cb1,dm2,droSec1,strPur1,droVir2,droVir1,strPur2,sc1,xenTro1,droGri1,xenTro2,cb3,gasAcu1,caePb1,anoGam1,fr2,fr1,hg15,hg16,hg17,hg18,hg19,felCat3,apiMel2,monDom4,apiMel1,ce2
#Harvested from http://archaea.ucsc.edu/cgi-bin/das/dsn
archaea http://archaea.ucsc.edu/cgi-bin/hgTracks? alkaEhrl_MLHE_1,shewW318,idioLoih_L2TR,sulSol1,erwiCaro_ATROSEPTICA,symbTher_IAM14863,moorTher_ATCC39073,therFusc_YX,methHung1,bradJapo,therElon,shewPutrCN32,pediPent_ATCC25745,mariMari_MCS10,nanEqu1,baciSubt,chlaTrac,magnMagn_AMB_1,chroViol,ralsSola,acidCryp_JF_5,erytLito_HTCC2594,desuVulg_HILDENBOROUG,pyrAer1,sulfToko1,shewANA3,paraSp_UWE25,geobKaus_HTA426,rhizEtli_CFN_42,uncuMeth_RCI,candBloc_FLORIDANUS,deinRadi,yersPest_CO92,saccEryt_NRRL_2338,rhodRHA1,candCars_RUDDII,burkMall_ATCC23344,eschColi_O157H7,burk383,psycIngr_37,rhodSpha_2_4_1,wolbEndo_OF_DROSOPHIL,burkViet_G4,propAcne_KPA171202,enteFaec_V583,campJeju_81_176,acidJS42,heliPylo_26695,pseuHalo_TAC125,chroSale_DSM3043,methVann1,archFulg1,neisMeni_Z2491_1,fusoNucl,vermEise_EF01_2,anabVari_ATCC29413,tropWhip_TW08_27,heliHepa,acinSp_ADP1,anapMarg_ST_MARIES,natrPhar1,haheChej_KCTC_2396,therPetr_RKU_1,neisGono_FA1090_1,colwPsyc_34H,desuPsyc_LSV54,hyphNept_ATCC15444,vibrChol1,deinGeot_DSM11300,strePyog_M1_GAS,franCcI3,salmTyph,metaSedu,lactSali_UCC118,trepPall,neisMeni_MC58_1,syntWolf_GOETTINGEN,flavJohn_UW101,methBoon1,haemSomn_129PT,shewLoihPV4,igniHosp1,haemInfl_KW20,haloHalo_SL1,ferrAcid1,sphiAlas_RB2256,candPela_UBIQUE_HTCC1,caldSacc_DSM8903,aerPer1,lactPlan,carbHydr_Z_2901,therTher_HB8,vibrVuln_YJ016_1,rhodPalu_CGA009,acidCell_11B,siliPome_DSS_3,therVolc1,haloWals1,rubrXyla_DSM9941,shewAmaz,nocaJS61,vibrVuln_CMCP6_1,sinoMeli,ureaUrea,baciHalo,bartHens_HOUSTON_1,nitrWino_NB_255,hypeButy1,methBurt2,polaJS66,mesoLoti,methMari_C7,caulCres,neisMeni_FAM18_1,acidBact_ELLIN345,caldMaqu1,salmEnte_PARATYPI_ATC,glucOxyd_621H,cytoHutc_ATCC33406,nitrEuro,therMari,coxiBurn,woliSucc,heliPylo_HPAG1,mesoFlor_L1,pyrHor1,methAeol1,procMari_CCMP1375,pyroArse1,oenoOeni_PSU_1,alcaBork_SK2,wiggBrev,actiPleu_L20,lactLact,methJann1,paraDeni_PD1222,borrBurg,pyroIsla1,orieTsut_BORYONG,shewMR4,methKand1,methCaps_BATH,onioYell_PHYTOPLASMA,bordBron,cenaSymb1,burkCeno_HI2424,franTula_TULARENSIS,pyrFur2,mariAqua_VT8,heliPylo_J99,psycArct_273_4,vibrChol_MO10_1,vibrPara1,rickBell_RML369_C,metAce1,buchSp,ehrlRumi_WELGEVONDEN,methLabrZ_1,chlaPneu_CWL029,thioCrun_XCL_2,pyroCali1,chloTepi_TLS,stapAure_MU50,novoArom_DSM12444,magnMC1,zymoMobi_ZM4,salmTyph_TY2,chloChlo_CAD3,azoaSp_EBN1,therTher_HB27,bifiLong,picrTorr1,listInno,bdelBact,gramFors_KT0803,sulfAcid1,geobTher_NG80_2,peloCarb,ralsEutr_JMP134,mannSucc_MBEL55E,syneSp_WH8102,methTherPT1,clavMich_NCPPB_382,therAcid1,syntAcid_SB,porpGing_W83,therNeut0,leifXyli_XYLI_CTCB0,shewFrig,photProf_SS9,thioDeni_ATCC25259,methMaze1,desuRedu_MI_1,burkThai_E264,campFetu_82_40,blocFlor,jannCCS1,nitrMult_ATCC25196,streCoel,soliUsit_ELLIN6076,pastMult,saliRube_DSM13855,methTher1,nostSp,shigFlex_2A,saccDegr_2_40,oceaIhey,dehaEthe_195,rhodRubr_ATCC11170,arthFB24,shewMR7,pireSp,anaeDeha_2CP_C,haloVolc1,dichNodo_VCS1703A,tricEryt_IMS101,mycoGeni,thioDeni_ATCC33889,methSmit1,geobUran_RF4,shewDeni,halMar1,desuHafn_Y51,methStad1,granBeth_CGDNIH1,therPend1,legiPneu_PHILADELPHIA,vibrChol_O395_1,nitrOcea_ATCC19707,campJeju_RM1221,methPetr_PM1,heliAcin_SHEEBA,eschColi_APEC_O1,peloTher_SI,haloHalo1,syntFuma_MPOB,xyleFast,gloeViol,leucMese_ATCC8293,bactThet_VPI_5482,xantCamp,sodaGlos_MORSITANS,geobSulf,roseDeni_OCH_114,coryEffi_YS_314,brucMeli,mycoTube_H37RV,vibrFisc_ES114_1,pyrAby1,burkXeno_LB400,polyQLWP,stapMari1,peloLute_DSM273,burkCeno_AU_1054,shewBalt,nocaFarc_IFM10152,ente638,mculMari1,saliTrop_CNB_440,neorSenn_MIYAYAMA,aquiAeol,dechArom_RCB,myxoXant_DK_1622,burkPseu_1106A,burkCepa_AMMD,methMari_C5_1,azorCaul2,methFlag_KT,leptInte,eschColi_K12,synePCC6,baumCica_HOMALODISCA,methBark1,pseuAeru,geobMeta_GS15,eschColi_CFT073,photLumi,metMar1,hermArse,campJeju,therKoda1,aeroHydr_ATCC7966,baciAnth_AMES,shewOnei,therTeng,lawsIntr_PHE_MN1_00
#Harvested from http://genome-test.cse.ucsc.edu/cgi-bin/das/dsn
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: Plugin frameworks, QA: add unit tests for PluginManager, HookPluginManager, and PageServingPluginManager
by commits-noreply@bitbucket.org 18 Sep '13
by commits-noreply@bitbucket.org 18 Sep '13
18 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6eb358cc82c1/
Changeset: 6eb358cc82c1
User: carlfeberhard
Date: 2013-09-19 00:24:00
Summary: Plugin frameworks, QA: add unit tests for PluginManager, HookPluginManager, and PageServingPluginManager
Affected #: 12 files
diff -r 40fb094fe82b6518a8138311a6427c539c6be8f8 -r 6eb358cc82c15782abc2c4e912f935830dfc2ece lib/galaxy/web/base/pluginframework.py
--- a/lib/galaxy/web/base/pluginframework.py
+++ b/lib/galaxy/web/base/pluginframework.py
@@ -280,28 +280,65 @@
Search all plugins for a function named ``hook_fn_prefix`` + ``hook_name``
and run it passing in args and kwargs.
+ Return values from each hook are returned in a dictionary keyed with the
+ plugin names.
+
:type hook_name: string
:param hook_name: name (suffix) of the hook to run
- :rtype: 2-tuple containing (list, dict)
- :returns: (possibly modified) args, kwargs
+ :rtype: dictionary
+ :returns: where keys are plugin.names and
+ values return values from the hooks
"""
#TODO: is hook prefix necessary?
#TODO: could be made more efficient if cached by hook_name in the manager on load_plugin
# (low maint. overhead since no dynamic loading/unloading of plugins)
hook_fn_name = ''.join([ self.hook_fn_prefix, hook_name ])
+ returned = {}
+ for plugin_name, plugin in self.plugins.items():
+ hook_fn = getattr( plugin.module, hook_fn_name, None )
+
+ if hook_fn and hasattr( hook_fn, '__call__' ):
+ try:
+ #log.debug( 'calling %s from %s(%s)', hook_fn.func_name, plugin.name, plugin.module )
+ fn_returned = hook_fn( *args, **kwargs )
+ returned[ plugin.name ] = fn_returned
+ except Exception, exc:
+ # fail gracefully and continue with other plugins
+ log.exception( 'Hook function "%s" failed for plugin "%s"', hook_name, plugin.name )
+
+ # not sure of utility of this - seems better to be fire-and-forget pub-sub
+ return returned
+
+ def filter_hook( self, hook_name, hook_arg, *args, **kwargs ):
+ """
+ Search all plugins for a function named ``hook_fn_prefix`` + ``hook_name``
+ and run the first with ``hook_arg`` and every function after with the
+ return value of the previous.
+
+ ..note:
+ This makes plugin load order very important.
+
+ :type hook_name: string
+ :param hook_name: name (suffix) of the hook to run
+ :type hook_arg: any
+ :param hook_arg: the arg to be passed between hook functions
+ :rtype: any
+ :returns: the modified hook_arg
+ """
+ hook_fn_name = ''.join([ self.hook_fn_prefix, hook_name ])
for plugin_name, plugin in self.plugins.items():
hook_fn = getattr( plugin.module, hook_fn_name, None )
if hook_fn and hasattr( hook_fn, '__call__' ):
try:
- #log.debug( 'calling %s from %s(%s)', hook_fn.func_name, plugin.name, plugin.module )
- hook_fn( *args, **kwargs )
+ hook_arg = hook_fn( hook_arg, *args, **kwargs )
+
except Exception, exc:
# fail gracefully and continue with other plugins
- log.exception( 'Hook function "%s" failed for plugin "%s"', hook_name, plugin.name )
+ log.exception( 'Filter hook function "%s" failed for plugin "%s"', hook_name, plugin.name )
- # may have been altered by hook fns, return in order to act like filter
- return args, kwargs
+ # may have been altered by hook fns, return
+ return hook_arg
# ============================================================================= exceptions
@@ -370,12 +407,12 @@
:rtype: bool
:returns: True if the path contains a plugin
"""
- if not os.path.isdir( plugin_path ):
+ if not super( PageServingPluginManager, self ).is_plugin( plugin_path ):
return False
- #TODO: this is not reliable and forces the inclusion of empty dirs in some situations
- if self.serves_templates and not 'templates' in os.listdir( plugin_path ):
- return False
- if self.serves_static and not 'static' in os.listdir( plugin_path ):
+ # reject only if we don't have either
+ listdir = os.listdir( plugin_path )
+ if( ( 'templates' not in listdir )
+ and ( 'static' not in listdir ) ):
return False
return True
diff -r 40fb094fe82b6518a8138311a6427c539c6be8f8 -r 6eb358cc82c15782abc2c4e912f935830dfc2ece test/unit/datatypes/dataproviders/test_base_dataproviders.py
--- a/test/unit/datatypes/dataproviders/test_base_dataproviders.py
+++ b/test/unit/datatypes/dataproviders/test_base_dataproviders.py
@@ -7,15 +7,16 @@
#TODO: fix off by ones in FilteredDataProvider counters
+import imp
import unittest
import StringIO
import tempfilecache
-import utility
+utility = imp.load_source( 'utility', '../../util/utility.py' )
log = utility.set_up_filelogger( __name__ + '.log' )
+utility.add_galaxy_lib_to_path( 'test/unit/datatypes/dataproviders' )
-utility.add_galaxy_lib_to_path( 'test/unit/datatypes/dataproviders' )
from galaxy.datatypes.dataproviders import base, exceptions
from galaxy import eggs
diff -r 40fb094fe82b6518a8138311a6427c539c6be8f8 -r 6eb358cc82c15782abc2c4e912f935830dfc2ece test/unit/datatypes/dataproviders/test_line_dataproviders.py
--- a/test/unit/datatypes/dataproviders/test_line_dataproviders.py
+++ b/test/unit/datatypes/dataproviders/test_line_dataproviders.py
@@ -7,17 +7,17 @@
#TODO: fix off by ones in FilteredDataProvider counters
+import imp
import unittest
import StringIO
import tempfilecache
-import utility
-
import test_base_dataproviders
+utility = imp.load_source( 'utility', '../../util/utility.py' )
log = utility.set_up_filelogger( __name__ + '.log' )
+utility.add_galaxy_lib_to_path( 'test/unit/datatypes/dataproviders' )
-utility.add_galaxy_lib_to_path( 'test/unit/datatypes/dataproviders' )
from galaxy import eggs
from galaxy.datatypes.dataproviders import line
diff -r 40fb094fe82b6518a8138311a6427c539c6be8f8 -r 6eb358cc82c15782abc2c4e912f935830dfc2ece test/unit/datatypes/dataproviders/utility.py
--- a/test/unit/datatypes/dataproviders/utility.py
+++ /dev/null
@@ -1,45 +0,0 @@
-"""
-Unit test utilities.
-"""
-
-import os
-import sys
-import logging
-import textwrap
-
-def set_up_filelogger( logname, level=logging.DEBUG ):
- """
- Sets up logging to a file named `logname`
- (removing it first if it already exists).
-
- Usable with 'nosetests' to get logging msgs from failed tests
- (no logfile created).
- Usable with 'nosetests --nologcapture' to get logging msgs for all tests
- (in logfile).
- """
- if os.path.exists( logname ): os.unlink( logname )
- logging.basicConfig( filename=logname, level=logging.DEBUG )
- return logging
-
-def add_galaxy_lib_to_path( this_dir_relative_to_root ):
- """
- Adds `<galaxy>/lib` to `sys.path` given the scripts directory relative
- to `<galaxy>`.
- .. example::
- utility.add_galaxy_lib_to_path( '/test/unit/datatypes/dataproviders' )
- """
- glx_lib = os.path.join( os.getcwd().replace( this_dir_relative_to_root, '' ), 'lib' )
- sys.path.append( glx_lib )
-
-def clean_multiline_string( multiline_string, sep='\n' ):
- """
- Dedent, split, remove first and last empty lines, rejoin.
- """
- multiline_string = textwrap.dedent( multiline_string )
- string_list = multiline_string.split( sep )
- if not string_list[0]:
- string_list = string_list[1:]
- if not string_list[-1]:
- string_list = string_list[:-1]
- #return '\n'.join( docstrings )
- return ''.join([ ( s + '\n' ) for s in string_list ])
diff -r 40fb094fe82b6518a8138311a6427c539c6be8f8 -r 6eb358cc82c15782abc2c4e912f935830dfc2ece test/unit/test_dataproviders.pyc
Binary file test/unit/test_dataproviders.pyc has changed
diff -r 40fb094fe82b6518a8138311a6427c539c6be8f8 -r 6eb358cc82c15782abc2c4e912f935830dfc2ece test/unit/test_plugins.py
--- a/test/unit/test_plugins.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from os import makedirs
-from os.path import join, dirname, basename
-from tempfile import mkdtemp
-from shutil import rmtree
-
-from galaxy.visualization.registry import VisualizationsRegistry
-
-
-def test_visualization_loading():
- visualizations = __default_viz_root()
- registry = VisualizationsRegistry(visualizations, 'foo')
- assert "VisualizationsRegistry" in str(registry)
- assert visualizations in str(registry)
- assert registry.name == "visualizations"
- __assert_scatterplot_registered(registry)
- assert registry._get_template_paths() == [visualizations]
-
-
-def test_multiple_visualization_roots():
- temp_dir = mkdtemp()
- try:
- makedirs(join(temp_dir, "coolplugin5"))
- visualization_dirs = "%s,%s" % (__default_viz_root(), temp_dir)
- registry = VisualizationsRegistry(visualization_dirs, 'foo')
- __assert_scatterplot_registered(registry)
- assert "coolplugin5" in \
- [basename(path) for path in registry.get_plugin_directories()]
- assert registry._get_template_paths() == \
- [__default_viz_root(), temp_dir]
- finally:
- rmtree(temp_dir)
-
-
-def __assert_scatterplot_registered(registry):
- assert 'scatterplot' in \
- [basename(path) for path in registry.get_plugin_directories()]
-
-
-def __default_viz_root():
- galaxy_root = join(dirname(__file__), '..', '..')
- visualizations = join(galaxy_root, 'config', 'plugins', 'visualizations')
- return visualizations
diff -r 40fb094fe82b6518a8138311a6427c539c6be8f8 -r 6eb358cc82c15782abc2c4e912f935830dfc2ece test/unit/util/utility.py
--- /dev/null
+++ b/test/unit/util/utility.py
@@ -0,0 +1,45 @@
+"""
+Unit test utilities.
+"""
+
+import os
+import sys
+import logging
+import textwrap
+
+def set_up_filelogger( logname, level=logging.DEBUG ):
+ """
+ Sets up logging to a file named `logname`
+ (removing it first if it already exists).
+
+ Usable with 'nosetests' to get logging msgs from failed tests
+ (no logfile created).
+ Usable with 'nosetests --nologcapture' to get logging msgs for all tests
+ (in logfile).
+ """
+ if os.path.exists( logname ): os.unlink( logname )
+ logging.basicConfig( filename=logname, level=logging.DEBUG )
+ return logging
+
+def add_galaxy_lib_to_path( this_dir_relative_to_root ):
+ """
+ Adds `<galaxy>/lib` to `sys.path` given the scripts directory relative
+ to `<galaxy>`.
+ .. example::
+ utility.add_galaxy_lib_to_path( '/test/unit/datatypes/dataproviders' )
+ """
+ glx_lib = os.path.join( os.getcwd().replace( this_dir_relative_to_root, '' ), 'lib' )
+ sys.path.append( glx_lib )
+
+def clean_multiline_string( multiline_string, sep='\n' ):
+ """
+ Dedent, split, remove first and last empty lines, rejoin.
+ """
+ multiline_string = textwrap.dedent( multiline_string )
+ string_list = multiline_string.split( sep )
+ if not string_list[0]:
+ string_list = string_list[1:]
+ if not string_list[-1]:
+ string_list = string_list[:-1]
+ #return '\n'.join( docstrings )
+ return ''.join([ ( s + '\n' ) for s in string_list ])
diff -r 40fb094fe82b6518a8138311a6427c539c6be8f8 -r 6eb358cc82c15782abc2c4e912f935830dfc2ece test/unit/visualizations/registry/test_plugins.py
--- /dev/null
+++ b/test/unit/visualizations/registry/test_plugins.py
@@ -0,0 +1,42 @@
+from os import makedirs
+from os.path import join, dirname, basename
+from tempfile import mkdtemp
+from shutil import rmtree
+
+from galaxy.visualization.registry import VisualizationsRegistry
+
+
+def test_visualization_loading():
+ visualizations = __default_viz_root()
+ registry = VisualizationsRegistry(visualizations, 'foo')
+ assert "VisualizationsRegistry" in str(registry)
+ assert visualizations in str(registry)
+ assert registry.name == "visualizations"
+ __assert_scatterplot_registered(registry)
+ assert registry._get_template_paths() == [visualizations]
+
+
+def test_multiple_visualization_roots():
+ temp_dir = mkdtemp()
+ try:
+ makedirs(join(temp_dir, "coolplugin5"))
+ visualization_dirs = "%s,%s" % (__default_viz_root(), temp_dir)
+ registry = VisualizationsRegistry(visualization_dirs, 'foo')
+ __assert_scatterplot_registered(registry)
+ assert "coolplugin5" in \
+ [basename(path) for path in registry.get_plugin_directories()]
+ assert registry._get_template_paths() == \
+ [__default_viz_root(), temp_dir]
+ finally:
+ rmtree(temp_dir)
+
+
+def __assert_scatterplot_registered(registry):
+ assert 'scatterplot' in \
+ [basename(path) for path in registry.get_plugin_directories()]
+
+
+def __default_viz_root():
+ galaxy_root = join(dirname(__file__), '..', '..')
+ visualizations = join(galaxy_root, 'config', 'plugins', 'visualizations')
+ return visualizations
diff -r 40fb094fe82b6518a8138311a6427c539c6be8f8 -r 6eb358cc82c15782abc2c4e912f935830dfc2ece test/unit/web/base/mock.py
--- /dev/null
+++ b/test/unit/web/base/mock.py
@@ -0,0 +1,61 @@
+"""
+"""
+import tempfile
+import os
+import shutil
+
+class MockDir( object ):
+
+ def __init__( self, structure_dict, where=None ):
+ self.structure_dict = structure_dict
+ self.create_root( structure_dict, where )
+
+ def create_root( self, structure_dict, where=None ):
+ self.root_path = tempfile.mkdtemp( dir=where )
+ #print 'created root:', self.root_path
+ self.create_structure( self.root_path, structure_dict )
+
+ def create_structure( self, current_path, structure_dict ):
+ for k, v in structure_dict.items():
+ # if value is string, create a file in the current path and write v as file contents
+ if isinstance( v, str ):
+ self.create_file( os.path.join( current_path, k ), v )
+ # if it's a dict, create a dir here named k and recurse into it
+ if isinstance( v, dict ):
+ subdir_path = os.path.join( current_path, k )
+ #print 'subdir:', subdir_path
+ os.mkdir( subdir_path )
+ self.create_structure( subdir_path, v )
+
+ def create_file( self, path, contents ):
+ #print 'file:', path
+ with open( path, 'w' ) as newfile:
+ newfile.write( contents )
+
+ def remove( self ):
+ #print 'removing:', self.root_path
+ shutil.rmtree( self.root_path )
+
+
+class MockAppConfig( object ):
+ def __init__( self, root ):
+ self.root = root
+
+class MockApp( object ):
+ def __init__( self, root ):
+ self.config = MockAppConfig( root )
+
+class MockTrans( object ):
+ def fill_template( self, filename, template_lookup=None, **kwargs ):
+ template = template_lookup.get_template( filename )
+ template.output_encoding = 'utf-8'
+ return template.render( **kwargs )
+
+if __name__ == '__main__':
+ td = MockDir({
+ 'file1' : 'Hello\nthere,\t...you',
+ 'dir1' : {
+ 'file2' : 'Blerbler',
+ }
+ })
+ td.remove()
diff -r 40fb094fe82b6518a8138311a6427c539c6be8f8 -r 6eb358cc82c15782abc2c4e912f935830dfc2ece test/unit/web/base/test_HookPluginManager.py
--- /dev/null
+++ b/test/unit/web/base/test_HookPluginManager.py
@@ -0,0 +1,254 @@
+"""
+"""
+import os
+import imp
+import unittest
+import types
+
+utility = imp.load_source( 'utility', '../../util/utility.py' )
+log = utility.set_up_filelogger( __name__ + '.log' )
+utility.add_galaxy_lib_to_path( 'test/unit/web/base' )
+
+from galaxy.web.base.pluginframework import HookPluginManager
+
+import mock
+
+# ----------------------------------------------------------------------------- globals
+loading_point = HookPluginManager.loading_point_filename
+
+contents1 = """
+import os
+
+def bler( x, y=3 ):
+ return ( x, y )
+"""
+
+contents2 = """
+raise Exception( 'Bler' )
+"""
+
+contents3 = """
+import contents1
+
+def blah( w ):
+ return tuple( [ w ] + list( contents1.bler( 2 ) ) )
+"""
+
+contents4 = """
+from galaxy import util
+
+def blah( s ):
+ return util.listify( s )
+"""
+
+contents5 = """
+def hook_blah( s ):
+ return s.title()
+
+def hook_filter_test( s ):
+ s += ' one'
+ return s
+"""
+
+contents6 = """
+def hook_blah( s ):
+ return s.upper()
+
+def hook_filter_test( s ):
+ s += ' two'
+ return s
+"""
+
+contents7 = """
+def hook_blah( s ):
+ raise Exception( 'bler' )
+
+def hook_filter_test( s ):
+ raise Exception( 'bler' )
+"""
+
+# -----------------------------------------------------------------------------
+class HookPluginManager_TestCase( unittest.TestCase ):
+
+ def test_loading_point( self ):
+ """should attempt load on dirs containing loading_point file"""
+ mock_app_dir = mock.MockDir({
+ 'plugins' : {
+ 'plugin1' : {
+ loading_point : contents1
+ },
+ 'not_a_plugin' : 'blerbler'
+ }
+ })
+ mock_app = mock.MockApp( mock_app_dir.root_path )
+ plugin_mgr = HookPluginManager( mock_app, directories_setting='plugins' )
+
+ app_path = mock_app_dir.root_path
+ expected_plugins_path = os.path.join( app_path, 'plugins' )
+
+ self.assertItemsEqual( plugin_mgr.directories, [ expected_plugins_path ] )
+ self.assertItemsEqual( plugin_mgr.plugins.keys(), [ 'plugin1' ] )
+ self.assertFalse( plugin_mgr.plugins.get( 'not_a_plugin', False ) )
+
+ plugin = plugin_mgr.plugins[ 'plugin1' ]
+ self.assertEqual( plugin.name, 'plugin1' )
+ self.assertEqual( plugin.path, os.path.join( expected_plugins_path, 'plugin1' ) )
+ self.assertIsInstance( plugin.module, types.ModuleType )
+ self.assertEqual( plugin.module.bler( 2 ), ( 2, 3 ) )
+
+ mock_app_dir.remove()
+
+ def test_bad_loading_points( self ):
+ """should NOT attempt load on dirs NOT containing loading_point file"""
+ mock_app_dir = mock.MockDir({
+ 'plugins' : {
+ 'plugin1' : {},
+ 'plugin2' : {
+ 'plogin.py' : 'wot'
+ }
+ }
+ })
+ mock_app = mock.MockApp( mock_app_dir.root_path )
+ plugin_mgr = HookPluginManager( mock_app, directories_setting='plugins' )
+
+ app_path = mock_app_dir.root_path
+ expected_plugins_path = os.path.join( app_path, 'plugins' )
+
+ self.assertItemsEqual( plugin_mgr.directories, [ expected_plugins_path ] )
+ self.assertEqual( plugin_mgr.plugins.keys(), [] )
+
+ mock_app_dir.remove()
+
+ def test_bad_import( self ):
+ """should error gracefully (skip) on bad import"""
+ mock_app_dir = mock.MockDir({
+ 'plugins' : {
+ 'plugin1' : {
+ loading_point : contents2
+ }
+ }
+ })
+ mock_app = mock.MockApp( mock_app_dir.root_path )
+ plugin_mgr = HookPluginManager( mock_app, directories_setting='plugins' )
+
+ app_path = mock_app_dir.root_path
+ expected_plugins_path = os.path.join( app_path, 'plugins' )
+
+ self.assertItemsEqual( plugin_mgr.directories, [ expected_plugins_path ] )
+ self.assertEqual( plugin_mgr.plugins.keys(), [] )
+
+ mock_app_dir.remove()
+
+ def test_import_w_rel_import( self ):
+ """should allow loading_point to rel. import other modules"""
+ mock_app_dir = mock.MockDir({
+ 'plugins' : {
+ 'plugin1' : {
+ 'contents1.py': contents1,
+ loading_point : contents3
+ }
+ }
+ })
+ mock_app = mock.MockApp( mock_app_dir.root_path )
+ plugin_mgr = HookPluginManager( mock_app, directories_setting='plugins', skip_bad_plugins=False )
+
+ app_path = mock_app_dir.root_path
+ expected_plugins_path = os.path.join( app_path, 'plugins' )
+
+ self.assertItemsEqual( plugin_mgr.directories, [ expected_plugins_path ] )
+ self.assertItemsEqual( plugin_mgr.plugins.keys(), [ 'plugin1' ] )
+
+ plugin = plugin_mgr.plugins[ 'plugin1' ]
+ self.assertEqual( plugin.name, 'plugin1' )
+ self.assertEqual( plugin.path, os.path.join( expected_plugins_path, 'plugin1' ) )
+ self.assertIsInstance( plugin.module, types.ModuleType )
+ self.assertEqual( plugin.module.blah( 1 ), ( 1, 2, 3 ) )
+
+ mock_app_dir.remove()
+
+ def test_import_w_galaxy_import( self ):
+ """should allow loading_point to rel. import GALAXY modules"""
+ mock_app_dir = mock.MockDir({
+ 'plugins' : {
+ 'plugin1' : {
+ loading_point : contents4
+ }
+ }
+ })
+ mock_app = mock.MockApp( mock_app_dir.root_path )
+ plugin_mgr = HookPluginManager( mock_app, directories_setting='plugins', skip_bad_plugins=False )
+
+ app_path = mock_app_dir.root_path
+ expected_plugins_path = os.path.join( app_path, 'plugins' )
+
+ self.assertItemsEqual( plugin_mgr.directories, [ expected_plugins_path ] )
+ self.assertItemsEqual( plugin_mgr.plugins.keys(), [ 'plugin1' ] )
+
+ plugin = plugin_mgr.plugins[ 'plugin1' ]
+ self.assertEqual( plugin.name, 'plugin1' )
+ self.assertEqual( plugin.path, os.path.join( expected_plugins_path, 'plugin1' ) )
+ self.assertIsInstance( plugin.module, types.ModuleType )
+
+ self.assertEqual( plugin.module.blah( 'one,two' ), [ 'one', 'two' ] )
+
+ mock_app_dir.remove()
+
+ def test_run_hooks( self ):
+ """should run hooks of loaded plugins"""
+ mock_app_dir = mock.MockDir({
+ 'plugins' : {
+ 'plugin1' : {
+ loading_point : contents5
+ },
+ 'plugin2' : {
+ loading_point : contents6
+ }
+ }
+ })
+ mock_app = mock.MockApp( mock_app_dir.root_path )
+ plugin_mgr = HookPluginManager( mock_app, directories_setting='plugins', skip_bad_plugins=False )
+ app_path = mock_app_dir.root_path
+ expected_plugins_path = os.path.join( app_path, 'plugins' )
+ self.assertItemsEqual( plugin_mgr.plugins.keys(), [ 'plugin1', 'plugin2' ] )
+
+ return_val_dict = plugin_mgr.run_hook( 'blah', 'one two check' )
+ self.assertEqual( return_val_dict, { 'plugin1' : 'One Two Check', 'plugin2' : 'ONE TWO CHECK' } )
+
+ result = plugin_mgr.filter_hook( 'filter_test', 'check' )
+ self.assertEqual( result, 'check one two' )
+
+ mock_app_dir.remove()
+
+ def test_hook_errs( self ):
+ """should fail gracefully if hook fails (and continue with other plugins)"""
+ mock_app_dir = mock.MockDir({
+ 'plugins' : {
+ 'plugin1' : {
+ loading_point : contents5
+ },
+ 'plugin2' : {
+ loading_point : contents6
+ },
+ 'plugin3' : {
+ loading_point : contents7
+ }
+ }
+ })
+ mock_app = mock.MockApp( mock_app_dir.root_path )
+ plugin_mgr = HookPluginManager( mock_app, directories_setting='plugins', skip_bad_plugins=False )
+ app_path = mock_app_dir.root_path
+ expected_plugins_path = os.path.join( app_path, 'plugins' )
+ self.assertItemsEqual( plugin_mgr.plugins.keys(), [ 'plugin1', 'plugin2', 'plugin3' ] )
+
+ return_val_dict = plugin_mgr.run_hook( 'blah', 'one two check' )
+ self.assertEqual( return_val_dict, { 'plugin1' : 'One Two Check', 'plugin2' : 'ONE TWO CHECK' } )
+
+ result = plugin_mgr.filter_hook( 'filter_test', 'check' )
+ self.assertEqual( result, 'check one two' )
+
+ mock_app_dir.remove()
+
+
+
+if __name__ == '__main__':
+ unittest.main()
diff -r 40fb094fe82b6518a8138311a6427c539c6be8f8 -r 6eb358cc82c15782abc2c4e912f935830dfc2ece test/unit/web/base/test_PageServingPluginManager.py
--- /dev/null
+++ b/test/unit/web/base/test_PageServingPluginManager.py
@@ -0,0 +1,129 @@
+"""
+"""
+import os
+import imp
+import unittest
+
+utility = imp.load_source( 'utility', '../../util/utility.py' )
+log = utility.set_up_filelogger( __name__ + '.log' )
+utility.add_galaxy_lib_to_path( 'test/unit/web/base' )
+
+from galaxy.web.base.pluginframework import PageServingPluginManager
+
+import mock
+
+# ----------------------------------------------------------------------------- globals
+contents1 = """${what} ${you} ${say}"""
+
+# -----------------------------------------------------------------------------
+class PageServingPluginManager_TestCase( unittest.TestCase ):
+
+ def test_plugin_load( self ):
+ """should attempt load if criteria met"""
+ mock_app_dir = mock.MockDir({
+ 'plugins' : {
+ 'plugin1' : {
+ 'templates' : {},
+ 'static' : {}
+ },
+ 'plugin2' : {
+ 'static' : {}
+ },
+ 'plugin3' : {
+ 'templates' : {}
+ },
+ 'not_a_plugin1' : 'blerbler',
+ 'not_a_plugin2' : {},
+ }
+ })
+ mock_app = mock.MockApp( mock_app_dir.root_path )
+ plugin_mgr = PageServingPluginManager( mock_app, 'test', directories_setting='plugins' )
+
+ app_path = mock_app_dir.root_path
+ expected_plugins_path = os.path.join( app_path, 'plugins' )
+
+ self.assertEqual( plugin_mgr.base_url, 'test' )
+ self.assertItemsEqual( plugin_mgr.directories, [ expected_plugins_path ] )
+ self.assertItemsEqual( plugin_mgr.plugins.keys(), [ 'plugin1', 'plugin2', 'plugin3' ] )
+ self.assertFalse( plugin_mgr.plugins.get( 'not_a_plugin', False ) )
+
+ plugin1 = plugin_mgr.plugins[ 'plugin1' ]
+ self.assertEqual( plugin1.name, 'plugin1' )
+ self.assertEqual( plugin1.path, os.path.join( expected_plugins_path, 'plugin1' ) )
+ self.assertEqual( plugin1.base_url, '/'.join([ plugin_mgr.base_url, plugin1.name ]) )
+ self.assertTrue( plugin1.serves_static )
+ self.assertEqual( plugin1.static_path, os.path.join( plugin1.path, 'static' ) )
+ self.assertEqual( plugin1.static_url, '/'.join([ plugin1.base_url, 'static' ]) )
+ self.assertTrue( plugin1.serves_templates )
+ self.assertEqual( plugin1.template_path, os.path.join( plugin1.path, 'templates' ) )
+ self.assertEqual( plugin1.template_lookup.__class__.__name__, 'TemplateLookup' )
+
+ plugin2 = plugin_mgr.plugins[ 'plugin2' ]
+ self.assertEqual( plugin2.name, 'plugin2' )
+ self.assertEqual( plugin2.path, os.path.join( expected_plugins_path, 'plugin2' ) )
+ self.assertEqual( plugin2.base_url, '/'.join([ plugin_mgr.base_url, plugin2.name ]) )
+ self.assertTrue( plugin2.serves_static )
+ self.assertEqual( plugin2.static_path, os.path.join( plugin2.path, 'static' ) )
+ self.assertEqual( plugin2.static_url, '/'.join([ plugin2.base_url, 'static' ]) )
+ self.assertFalse( plugin2.serves_templates )
+
+ plugin3 = plugin_mgr.plugins[ 'plugin3' ]
+ self.assertEqual( plugin3.name, 'plugin3' )
+ self.assertEqual( plugin3.path, os.path.join( expected_plugins_path, 'plugin3' ) )
+ self.assertEqual( plugin3.base_url, '/'.join([ plugin_mgr.base_url, plugin3.name ]) )
+ self.assertFalse( plugin3.serves_static )
+ self.assertTrue( plugin3.serves_templates )
+ self.assertEqual( plugin1.template_path, os.path.join( plugin1.path, 'templates' ) )
+ self.assertEqual( plugin1.template_lookup.__class__.__name__, 'TemplateLookup' )
+
+ mock_app_dir.remove()
+
+ def test_plugin_static_map( self ):
+ """"""
+ mock_app_dir = mock.MockDir({
+ 'plugins' : {
+ 'plugin1' : {
+ 'templates' : {},
+ 'static' : {}
+ }
+ }
+ })
+ mock_app = mock.MockApp( mock_app_dir.root_path )
+ plugin_mgr = PageServingPluginManager( mock_app, 'test', directories_setting='plugins' )
+
+ app_path = mock_app_dir.root_path
+ expected_plugins_path = os.path.join( app_path, 'plugins' )
+ self.assertItemsEqual( plugin_mgr.plugins.keys(), [ 'plugin1' ] )
+ plugin = plugin_mgr.plugins[ 'plugin1' ]
+ self.assertEqual( plugin_mgr.get_static_urls_and_paths(), [( plugin.static_url, plugin.static_path )] )
+
+ mock_app_dir.remove()
+
+ def test_plugin_templates( self ):
+ """"""
+ mock_app_dir = mock.MockDir({
+ 'plugins' : {
+ 'plugin1' : {
+ 'templates' : {
+ 'test.mako' : contents1
+ },
+ }
+ }
+ })
+ mock_app = mock.MockApp( mock_app_dir.root_path )
+ plugin_mgr = PageServingPluginManager( mock_app, 'test', directories_setting='plugins' )
+
+ app_path = mock_app_dir.root_path
+ expected_plugins_path = os.path.join( app_path, 'plugins' )
+ self.assertItemsEqual( plugin_mgr.plugins.keys(), [ 'plugin1' ] )
+
+ plugin = plugin_mgr.plugins[ 'plugin1' ]
+ rendered = plugin_mgr.fill_template( mock.MockTrans(), plugin, 'test.mako',
+ what='Hey', you='Ho', say='HeyHey HoHo' )
+ self.assertEqual( rendered, 'Hey Ho HeyHey HoHo' )
+
+ mock_app_dir.remove()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff -r 40fb094fe82b6518a8138311a6427c539c6be8f8 -r 6eb358cc82c15782abc2c4e912f935830dfc2ece test/unit/web/base/test_PluginManager.py
--- /dev/null
+++ b/test/unit/web/base/test_PluginManager.py
@@ -0,0 +1,103 @@
+"""
+Unit tests for ``galaxy.web.base.pluginframework.PluginManager``
+"""
+import os
+import imp
+import unittest
+
+utility = imp.load_source( 'utility', '../../util/utility.py' )
+log = utility.set_up_filelogger( __name__ + '.log' )
+utility.add_galaxy_lib_to_path( 'test/unit/web/base' )
+
+from galaxy.web.base.pluginframework import PluginManager
+
+import mock
+
+class PluginManager_TestCase( unittest.TestCase ):
+
+ def test_rel_path_search( self ):
+ """should be able to search given rel. path"""
+ mock_app_dir = mock.MockDir({
+ 'plugins' : {
+ 'plugin1' : {},
+ 'plugin2' : {},
+ 'file1' : 'blerbler'
+ }
+ })
+ mock_app = mock.MockApp( mock_app_dir.root_path )
+ plugin_mgr = PluginManager( mock_app, directories_setting='plugins' )
+
+ app_path = mock_app_dir.root_path
+ expected_plugins_path = os.path.join( app_path, 'plugins' )
+
+ self.assertItemsEqual( plugin_mgr.directories, [ expected_plugins_path ] )
+ self.assertItemsEqual( plugin_mgr.plugins.keys(), [ 'plugin1', 'plugin2' ] )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin1' ].name, 'plugin1' )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin1' ].path, os.path.join( expected_plugins_path, 'plugin1' ) )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin2' ].name, 'plugin2' )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin2' ].path, os.path.join( expected_plugins_path, 'plugin2' ) )
+ self.assertFalse( plugin_mgr.plugins.get( 'file1', False ) )
+
+ mock_app_dir.remove()
+
+ def test_abs_path_search( self ):
+ """should be able to search given abs. path"""
+ mock_app_dir = mock.MockDir({})
+ mock_plugin_dir = mock.MockDir({
+ 'plugin1' : {},
+ 'plugin2' : {},
+ 'file1' : 'blerbler'
+ })
+ mock_app = mock.MockApp( mock_app_dir.root_path )
+ plugin_mgr = PluginManager( mock_app, directories_setting=mock_plugin_dir.root_path )
+
+ app_path = mock_app_dir.root_path
+ expected_plugins_path = mock_plugin_dir.root_path
+
+ self.assertItemsEqual( plugin_mgr.directories, [ expected_plugins_path ] )
+ self.assertItemsEqual( plugin_mgr.plugins.keys(), [ 'plugin1', 'plugin2' ] )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin1' ].name, 'plugin1' )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin1' ].path, os.path.join( expected_plugins_path, 'plugin1' ) )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin2' ].name, 'plugin2' )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin2' ].path, os.path.join( expected_plugins_path, 'plugin2' ) )
+ self.assertFalse( plugin_mgr.plugins.get( 'file1', False ) )
+
+ def test_multiple_dirs( self ):
+ """should search in multiple directories"""
+ mock_app_dir = mock.MockDir({
+ 'plugins' : {
+ 'plugin1' : {},
+ 'plugin2' : {},
+ 'file1' : 'blerbler'
+ }
+ })
+ mock_abs_plugin_dir = mock.MockDir({
+ 'plugin3' : {},
+ 'plugin4' : {},
+ 'file2' : 'blerbler'
+ })
+ mock_app = mock.MockApp( mock_app_dir.root_path )
+ directories_setting=','.join([ 'plugins', mock_abs_plugin_dir.root_path ])
+ plugin_mgr = PluginManager( mock_app, directories_setting=directories_setting )
+
+ app_path = mock_app_dir.root_path
+ expected_plugins_rel_path = os.path.join( app_path, 'plugins' )
+ expected_plugins_abs_path = mock_abs_plugin_dir.root_path
+
+ self.assertItemsEqual( plugin_mgr.directories, [ expected_plugins_rel_path, expected_plugins_abs_path ] )
+ self.assertItemsEqual( plugin_mgr.plugins.keys(), [ 'plugin1', 'plugin2', 'plugin3', 'plugin4' ] )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin1' ].name, 'plugin1' )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin1' ].path, os.path.join( expected_plugins_rel_path, 'plugin1' ) )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin2' ].name, 'plugin2' )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin2' ].path, os.path.join( expected_plugins_rel_path, 'plugin2' ) )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin3' ].name, 'plugin3' )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin3' ].path, os.path.join( expected_plugins_abs_path, 'plugin3' ) )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin4' ].name, 'plugin4' )
+ self.assertEqual( plugin_mgr.plugins[ 'plugin4' ].path, os.path.join( expected_plugins_abs_path, 'plugin4' ) )
+ self.assertFalse( plugin_mgr.plugins.get( 'file1', False ) )
+ self.assertFalse( plugin_mgr.plugins.get( 'file2', False ) )
+
+
+if __name__ == '__main__':
+ unittest.main()
+
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: Plugin framework: fix relative path parsing in PluginManager
by commits-noreply@bitbucket.org 18 Sep '13
by commits-noreply@bitbucket.org 18 Sep '13
18 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/40fb094fe82b/
Changeset: 40fb094fe82b
User: carlfeberhard
Date: 2013-09-18 20:49:58
Summary: Plugin framework: fix relative path parsing in PluginManager
Affected #: 1 file
diff -r eb69169a04efb1fba610b943fd38a8ceb991d315 -r 40fb094fe82b6518a8138311a6427c539c6be8f8 lib/galaxy/web/base/pluginframework.py
--- a/lib/galaxy/web/base/pluginframework.py
+++ b/lib/galaxy/web/base/pluginframework.py
@@ -93,7 +93,7 @@
for directory in util.listify( directories_setting ):
directory = directory.strip()
- if directory.startswith( '/' ):
+ if not directory.startswith( '/' ):
directory = os.path.join( galaxy_root, directory )
if not os.path.exists( directory ):
log.warn( '%s, directory not found: %s', self, directory )
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: james_taylor: style: Restore margin to bottom of nav-tabs, normalize tab border colors
by commits-noreply@bitbucket.org 18 Sep '13
by commits-noreply@bitbucket.org 18 Sep '13
18 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/eb69169a04ef/
Changeset: eb69169a04ef
User: james_taylor
Date: 2013-09-18 20:13:36
Summary: style: Restore margin to bottom of nav-tabs, normalize tab border colors
Affected #: 3 files
diff -r 01f603a2179fce1cb39f5cfde973744585c73918 -r eb69169a04efb1fba610b943fd38a8ceb991d315 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -505,12 +505,12 @@
.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#303030}
.nav .nav-divider{height:1px;margin:7.5px 0;overflow:hidden;background-color:#e5e5e5}
.nav>li>a>img{max-width:none}
-.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:3px 3px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}
-.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}
+.nav-tabs{border-bottom:1px solid #bfbfbf}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:3px 3px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #bfbfbf}
+.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fff;border:1px solid #bfbfbf;border-bottom-color:transparent;cursor:default}
.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}
@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:3px}
-.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}
-@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:3px 3px 0 0} .nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}
+.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #bfbfbf}
+@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #bfbfbf;border-radius:3px 3px 0 0} .nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}
.nav-pills>li{float:left}.nav-pills>li>a{border-radius:5px}
.nav-pills>li+li{margin-left:2px}
.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#303030}
@@ -518,8 +518,8 @@
.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}
@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}
.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:3px}
-.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}
-@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:3px 3px 0 0} .nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}
+.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #bfbfbf}
+@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #bfbfbf;border-radius:3px 3px 0 0} .nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}
.tabbable:before,.tabbable:after{content:" ";display:table;}
.tabbable:after{clear:both}
.tabbable:before,.tabbable:after{content:" ";display:table;}
@@ -756,9 +756,7 @@
.btn.active,.btn:active{color:inherit}
.dropdown-menu{max-width:auto}
input[type="checkbox"],input[type="radio"]{margin-left:0.5ex;margin-right:0.5ex}
-.nav-tabs{border-bottom:1px solid #bfbfbf}
-.nav-tabs>li>a:hover{border-color:#eee #eee #bfbfbf}
-.nav-tabs>.active>a,.nav-tabs>.active>a:hover{border:1px solid #bfbfbf;border-bottom-color:transparent}
+.nav-tabs{margin-bottom:15px}
a{text-decoration:underline}
label{font-weight:normal}
@font-face{font-family:'FontAwesome';src:url('../images/fonts/fontawesome-webfont.eot');src:url('../images/fonts/fontawesome-webfont.eot?#iefix') format('embedded-opentype'),url('../images/fonts/fontawesome-webfont.woff') format('woff'),url('../images/fonts/fontawesome-webfont.ttf') format('truetype');font-weight:normal;font-style:normal}.fa-icon,[class^="fa-icon-"],[class*=" fa-icon-"]{font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}
diff -r 01f603a2179fce1cb39f5cfde973744585c73918 -r eb69169a04efb1fba610b943fd38a8ceb991d315 static/style/src/less/galaxy_bootstrap/overrides.less
--- a/static/style/src/less/galaxy_bootstrap/overrides.less
+++ b/static/style/src/less/galaxy_bootstrap/overrides.less
@@ -57,15 +57,5 @@
// Tabs -- border color is hardcoded in navs.less, change to @btnBorder here
.nav-tabs {
- border-bottom: 1px solid @btn-default-border;
-}
-.nav-tabs > li > a {
- &:hover {
- border-color: @gray-lighter @gray-lighter @btn-default-border;
- }
-}
-.nav-tabs > .active > a,
-.nav-tabs > .active > a:hover {
- border: 1px solid @btn-default-border;
- border-bottom-color: transparent;
+ margin-bottom: 15px;
}
\ No newline at end of file
diff -r 01f603a2179fce1cb39f5cfde973744585c73918 -r eb69169a04efb1fba610b943fd38a8ceb991d315 static/style/src/less/galaxy_bootstrap/variables.less
--- a/static/style/src/less/galaxy_bootstrap/variables.less
+++ b/static/style/src/less/galaxy_bootstrap/variables.less
@@ -373,15 +373,15 @@
@nav-open-caret-border-color: @white;
// Tabs
-@nav-tabs-border-color: #ddd;
+@nav-tabs-border-color: @border-default-color;
@nav-tabs-link-hover-border-color: @gray-lighter;
@nav-tabs-active-link-hover-bg: @body-bg;
@nav-tabs-active-link-hover-color: @gray;
-@nav-tabs-active-link-hover-border-color: #ddd;
+@nav-tabs-active-link-hover-border-color: @border-default-color;
-@nav-tabs-justified-link-border-color: #ddd;
+@nav-tabs-justified-link-border-color: @border-default-color;
@nav-tabs-justified-active-link-border-color: @body-bg;
// Pills
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: james_taylor: Buttons and submit inputs always get the default .btn style
by commits-noreply@bitbucket.org 18 Sep '13
by commits-noreply@bitbucket.org 18 Sep '13
18 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/01f603a2179f/
Changeset: 01f603a2179f
User: james_taylor
Date: 2013-09-18 19:52:07
Summary: Buttons and submit inputs always get the default .btn style
Affected #: 5 files
diff -r 2d0bcb07596c4c688ed3908391d866831c65c042 -r 01f603a2179fce1cb39f5cfde973744585c73918 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1218,6 +1218,16 @@
select,input,textarea{font:inherit}
.form-row select,.form-row textarea,.form-row input[type="text"],.form-row input[type="file"],.form-row input[type="password"]{max-width:90%}
textarea,input[type="text"],input[type="password"]{font-size:12px;line-height:1.428571429;border:1px solid #aaa;padding:3px}
+input[type="submit"],button{display:inline-block;padding:4px 10px;margin-bottom:0;font-size:12px;font-weight:normal;line-height:1.428571429;text-align:center;vertical-align:middle;cursor:pointer;border:1px solid transparent;border-radius:3px;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;color:#333;background-color:#fff;border-color:#bfbfbf}input[type="submit"]:focus,button:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
+input[type="submit"]:hover,button:hover,input[type="submit"]:focus,button:focus{color:#333;text-decoration:none}
+input[type="submit"]:active,button:active,input[type="submit"].active,button.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}
+input[type="submit"].disabled,button.disabled,input[type="submit"][disabled],button[disabled],fieldset[disabled] input[type="submit"],fieldset[disabled] button{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}
+input[type="submit"] [class^="fa-icon-"],button [class^="fa-icon-"],input[type="submit"] [class*=" fa-icon-"],button [class*=" fa-icon-"]{display:inline;line-height:.6em}input[type="submit"] [class^="fa-icon-"].fa-icon-spin,button [class^="fa-icon-"].fa-icon-spin,input[type="submit"] [class*=" fa-icon-"].fa-icon-spin,button [class*=" fa-icon-"].fa-icon-spin{display:inline-block}
+input[type="submit"] [class^="fa-icon-"].pull-left.fa-icon-2x,button [class^="fa-icon-"].pull-left.fa-icon-2x,input[type="submit"] [class*=" fa-icon-"].pull-left.fa-icon-2x,button [class*=" fa-icon-"].pull-left.fa-icon-2x,input[type="submit"] [class^="fa-icon-"].pull-right.fa-icon-2x,button [class^="fa-icon-"].pull-right.fa-icon-2x,input[type="submit"] [class*=" fa-icon-"].pull-right.fa-icon-2x,button [class*=" fa-icon-"].pull-right.fa-icon-2x{margin-top:.35em}
+input[type="submit"] [class^="fa-icon-"].fa-icon-spin.icon-large,button [class^="fa-icon-"].fa-icon-spin.icon-large,input[type="submit"] [class*=" fa-icon-"].fa-icon-spin.icon-large,button [class*=" fa-icon-"].fa-icon-spin.icon-large{height:.75em}
+input[type="submit"]:hover,button:hover,input[type="submit"]:focus,button:focus,input[type="submit"]:active,button:active,input[type="submit"].active,button.active,.open .dropdown-toggleinput[type="submit"],.open .dropdown-togglebutton{color:#333;background-color:#ebebeb;border-color:#a1a1a1}
+input[type="submit"]:active,button:active,input[type="submit"].active,button.active,.open .dropdown-toggleinput[type="submit"],.open .dropdown-togglebutton{background-image:none}
+input[type="submit"].disabled,button.disabled,input[type="submit"][disabled],button[disabled],fieldset[disabled] input[type="submit"],fieldset[disabled] button,input[type="submit"].disabled:hover,button.disabled:hover,input[type="submit"][disabled]:hover,button[disabled]:hover,fieldset[disabled] input[type="submit"]:hover,fieldset[disabled] button:hover,input[type="submit"].disabled:focus,button.disabled:focus,input[type="submit"][disabled]:focus,button[disabled]:focus,fieldset[disabled] input[type="submit"]:focus,fieldset[disabled] button:focus,input[type="submit"].disabled:active,button.disabled:active,input[type="submit"][disabled]:active,button[disabled]:active,fieldset[disabled] input[type="submit"]:active,fieldset[disabled] button:active,input[type="submit"].disabled.active,button.disabled.active,input[type="submit"][disabled].active,button[disabled].active,fieldset[disabled] input[type="submit"].active,fieldset[disabled] button.active{background-color:#fff;border-color:#bfbfbf}
.search-query{display:inline-block;padding:4px;font-size:12px;line-height:1.428571429;color:#555;border:1px solid #aaa;padding-left:14px !important;padding-right:14px !important;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;max-width:auto}
.search-query:focus{border-color:rgba(24,132,218,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);outline:0;outline:thin dotted \9;}
.search-spinner{position:absolute;display:none;right:6px;top:9px}
diff -r 2d0bcb07596c4c688ed3908391d866831c65c042 -r 01f603a2179fce1cb39f5cfde973744585c73918 static/style/blue/sprite-fugue.png
Binary file static/style/blue/sprite-fugue.png has changed
diff -r 2d0bcb07596c4c688ed3908391d866831c65c042 -r 01f603a2179fce1cb39f5cfde973744585c73918 static/style/blue/sprite-history-buttons.png
Binary file static/style/blue/sprite-history-buttons.png has changed
diff -r 2d0bcb07596c4c688ed3908391d866831c65c042 -r 01f603a2179fce1cb39f5cfde973744585c73918 static/style/blue/sprite-history-states.png
Binary file static/style/blue/sprite-history-states.png has changed
diff -r 2d0bcb07596c4c688ed3908391d866831c65c042 -r 01f603a2179fce1cb39f5cfde973744585c73918 static/style/src/less/base.less
--- a/static/style/src/less/base.less
+++ b/static/style/src/less/base.less
@@ -660,6 +660,11 @@
padding: 3px;
}
+input[type="submit"], button {
+ .btn();
+ .btn-default();
+}
+
.search-query {
display: inline-block;
padding: 4px;
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: Plugin framework: factor out page serving responsibility, add HookPluginManager subclass and PageServingPluginManager subclass; Visualization registry: inherit from PageServingPluginManager
by commits-noreply@bitbucket.org 18 Sep '13
by commits-noreply@bitbucket.org 18 Sep '13
18 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2d0bcb07596c/
Changeset: 2d0bcb07596c
User: carlfeberhard
Date: 2013-09-18 16:53:12
Summary: Plugin framework: factor out page serving responsibility, add HookPluginManager subclass and PageServingPluginManager subclass; Visualization registry: inherit from PageServingPluginManager
Affected #: 8 files
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 config/plugins/visualizations/graphview/config/graphview.xml
--- a/config/plugins/visualizations/graphview/config/graphview.xml
+++ b/config/plugins/visualizations/graphview/config/graphview.xml
@@ -16,5 +16,5 @@
<params><param type="dataset" var_name_in_template="hda" required="true">dataset_id</param></params>
- <template>graphview/templates/graphview.mako</template>
+ <template>graphview.mako</template></visualization>
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 config/plugins/visualizations/scatterplot/config/scatterplot.xml
--- a/config/plugins/visualizations/scatterplot/config/scatterplot.xml
+++ b/config/plugins/visualizations/scatterplot/config/scatterplot.xml
@@ -11,5 +11,5 @@
<params><param type="dataset" var_name_in_template="hda" required="true">dataset_id</param></params>
- <template>scatterplot/templates/scatterplot.mako</template>
+ <template>scatterplot.mako</template></visualization>
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -22,6 +22,8 @@
from galaxy.openid.providers import OpenIDProviders
from galaxy.tools.data_manager.manager import DataManagers
+from galaxy.web.base import pluginframework
+
import logging
log = logging.getLogger( __name__ )
@@ -123,8 +125,11 @@
# Load genome indexer tool.
load_genome_index_tools( self.toolbox )
# visualizations registry: associates resources with visualizations, controls how to render
- self.visualizations_registry = VisualizationsRegistry.from_config(
- self.config.visualizations_plugins_directory, self.config )
+ self.visualizations_registry = None
+ if self.config.visualizations_plugins_directory:
+ self.visualizations_registry = VisualizationsRegistry( self,
+ directories_setting=self.config.visualizations_plugins_directory,
+ template_cache_dir=self.config.template_cache )
# Load security policy.
self.security_agent = self.model.security_agent
self.host_security_agent = galaxy.security.HostAgent( model=self.security_agent.model, permitted_actions=self.security_agent.permitted_actions )
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -294,9 +294,7 @@
self.fluent_log = string_as_bool( kwargs.get( 'fluent_log', False ) )
self.fluent_host = kwargs.get( 'fluent_host', 'localhost' )
self.fluent_port = int( kwargs.get( 'fluent_port', 24224 ) )
- # PLUGINS:
- self.plugin_frameworks = []
- # visualization framework
+ # visualization plugin framework
self.visualizations_plugins_directory = kwargs.get( 'visualizations_plugins_directory', None )
@property
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 lib/galaxy/visualization/registry.py
--- a/lib/galaxy/visualization/registry.py
+++ b/lib/galaxy/visualization/registry.py
@@ -39,9 +39,10 @@
"""
# ------------------------------------------------------------------- the registry
-class VisualizationsRegistry( pluginframework.PluginFramework ):
+class VisualizationsRegistry( pluginframework.PageServingPluginManager ):
"""
Main responsibilities are:
+ - discovering visualization plugins in the filesystem
- testing if an object has a visualization that can be applied to it
- generating a link to controllers.visualization.render with
the appropriate params
@@ -58,31 +59,79 @@
'sweepster',
'phyloviz'
]
- #: directories under plugin_directory that aren't plugins
- non_plugin_directories = []
- def __init__( self, registry_filepath, template_cache_dir ):
- super( VisualizationsRegistry, self ).__init__( registry_filepath, 'visualizations', template_cache_dir )
+ def __str__( self ):
+ return self.__class__.__name__
+ def __init__( self, app, **kwargs ):
+ self.config_parser = VisualizationsConfigParser()
+ super( VisualizationsRegistry, self ).__init__( app, 'visualizations', **kwargs )
# what to use to parse query strings into resources/vars for the template
self.resource_parser = ResourceParser()
log.debug( '%s loaded', str( self ) )
- def load_configuration( self ):
+ def is_plugin( self, plugin_path ):
"""
- Builds the registry by parsing the `config/*.xml` files for every plugin
- in ``get_plugin_directories`` and stores the results in ``self.listings``.
+ Determines whether the given filesystem path contains a plugin.
- ..note::
- This could be used to re-load a new configuration without restarting
- the instance.
+ In this base class, all sub-directories are considered plugins.
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the
+ potential plugin
+ :rtype: bool
+ :returns: True if the path contains a plugin
"""
- try:
- self.listings = VisualizationsConfigParser.parse( self.get_plugin_directories() )
+ # plugin_path must be a directory, have a config dir
+ if not os.path.isdir( plugin_path ):
+ return False
+ if not 'config' in os.listdir( plugin_path ):
+ return False
+ expected_config_filename = '%s.xml' %( os.path.split( plugin_path )[1] )
+ if not os.path.isfile( os.path.join( plugin_path, 'config', expected_config_filename ) ):
+ return False
+ return True
- except Exception, exc:
- log.exception( 'Error parsing visualizations plugins %s', self.plugin_directories )
- raise
+ def load_plugin( self, plugin_path ):
+ """
+ Create the visualization plugin object, parse its configuration file,
+ and return it.
+
+ Plugin bunches are decorated with:
+ * config_file : the path to this visualization's config file
+ * config : the parsed configuration for this visualization
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the plugin
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ #TODO: possibly move this after the config parsing to allow config to override?
+ plugin = super( VisualizationsRegistry, self ).load_plugin( plugin_path )
+
+ # config file is required, otherwise skip this visualization
+ plugin[ 'config_file' ] = os.path.join( plugin_path, 'config', ( plugin.name + '.xml' ) )
+ config = self.config_parser.parse_file( plugin.config_file )
+ if not config:
+ return None
+ plugin[ 'config' ] = config
+
+ return plugin
+
+ # -- getting resources for visualization templates from link query strings --
+ # -- building links to visualizations from objects --
+ def get_visualizations( self, trans, target_object ):
+ """
+ Get the names of visualizations usable on the `target_object` and
+ the urls to call in order to render the visualizations.
+ """
+ #TODO:?? a list of objects? YAGNI?
+ applicable_visualizations = []
+ for vis_name in self.plugins:
+ url_data = self.get_visualization( trans, vis_name, target_object )
+ if url_data:
+ applicable_visualizations.append( url_data )
+ return applicable_visualizations
def get_visualization( self, trans, visualization_name, target_object ):
"""
@@ -90,12 +139,11 @@
`visualization_name` if it's applicable to `target_object` or
`None` if it's not.
"""
- # a little weird to pass trans because this registry is part of the trans.app
- listing_data = self.listings.get( visualization_name, None )
- if not listing_data:
+ visualization = self.plugins.get( visualization_name, None )
+ if not visualization:
return None
- data_sources = listing_data[ 'data_sources' ]
+ data_sources = visualization.config[ 'data_sources' ]
for data_source in data_sources:
# currently a model class is required
model_class = data_source[ 'model_class' ]
@@ -109,11 +157,11 @@
param_data = data_source[ 'to_params' ]
url = self.get_visualization_url( trans, target_object, visualization_name, param_data )
- link_text = listing_data.get( 'link_text', None )
+ link_text = visualization.config.get( 'link_text', None )
if not link_text:
# default to visualization name, titlecase, and replace underscores
link_text = visualization_name.title().replace( '_', ' ' )
- render_location = listing_data.get( 'render_location' )
+ render_location = visualization.config.get( 'render_location' )
# remap some of these vars for direct use in ui.js, PopupMenu (e.g. text->html)
return {
'href' : url,
@@ -123,25 +171,12 @@
return None
- # -- building links to visualizations from objects --
- def get_visualizations( self, trans, target_object ):
- """
- Get the names of visualizations usable on the `target_object` and
- the urls to call in order to render the visualizations.
- """
- #TODO:?? a list of objects? YAGNI?
- applicable_visualizations = []
- for vis_name in self.listings:
- url_data = self.get_visualization( trans, vis_name, target_object )
- if url_data:
- applicable_visualizations.append( url_data )
- return applicable_visualizations
-
def is_object_applicable( self, trans, target_object, data_source_tests ):
"""
Run a visualization's data_source tests to find out if
it be applied to the target_object.
"""
+ #log.debug( 'is_object_applicable( self, trans, %s, %s )', target_object, data_source_tests )
for test in data_source_tests:
test_type = test[ 'type' ]
result_type = test[ 'result_type' ]
@@ -164,7 +199,6 @@
if test_fn( target_object, test_result ):
#log.debug( 'test passed' )
return True
-
return False
def get_visualization_url( self, trans, target_object, visualization_name, param_data ):
@@ -219,9 +253,9 @@
Both `params` and `param_modifiers` default to an empty dictionary.
"""
- visualization = self.listings.get( visualization_name )
- expected_params = visualization.get( 'params', {} )
- param_modifiers = visualization.get( 'param_modifiers', {} )
+ visualization = self.plugins.get( visualization_name )
+ expected_params = visualization.config.get( 'params', {} )
+ param_modifiers = visualization.config.get( 'param_modifiers', {} )
return ( expected_params, param_modifiers )
def query_dict_to_resources( self, trans, controller, visualization_name, query_dict ):
@@ -259,13 +293,6 @@
"""
VALID_RENDER_LOCATIONS = [ 'galaxy_main', '_top', '_blank' ]
- @classmethod
- def parse( cls, plugin_directories, debug=False ):
- """
- Static class interface.
- """
- return cls( debug ).parse_plugins( plugin_directories )
-
def __init__( self, debug=False ):
self.debug = debug
@@ -274,58 +301,19 @@
self.param_parser = ParamParser()
self.param_modifier_parser = ParamModifierParser()
- def parse_plugins( self, plugin_directories ):
- """
- Parses the config files for each plugin sub-dir in `base_path`.
-
- :param plugin_directories: a list of paths to enabled plugins.
-
- :returns: registry data in dictionary form
- """
- returned = {}
- for plugin_path in plugin_directories:
- returned.update( self.parse_plugin( plugin_path ) )
- return returned
-
- def parse_plugin( self, plugin_path ):
- """
- Parses any XML files in ``<plugin_path>/config``.
-
- If an error occurs while parsing a visualizations entry, it is skipped.
- :returns: registry data in dictionary form
- ..note::
- assumes config files are in a 'config' sub-dir of each plugin
- """
- returned = {}
-
- plugin_config_path = os.path.join( plugin_path, 'config' )
- if not os.path.isdir( plugin_config_path ):
- return returned
-
- for xml_filepath in glob.glob( os.path.join( plugin_config_path, '*.xml' ) ):
- try:
- visualization_name, visualization = self.parse_file( xml_filepath )
- # skip vis' with parsing errors - don't shutdown the startup
- except ParsingException, parse_exc:
- log.error( 'Skipped visualization config "%s" due to parsing errors: %s',
- xml_filepath, str( parse_exc ), exc_info=self.debug )
-
- if visualization:
- returned[ visualization_name ] = visualization
- log.debug( 'Visualization config loaded for: %s', visualization_name )
-
- return returned
-
def parse_file( self, xml_filepath ):
"""
Parse the given XML file for visualizations data.
:returns: tuple of ( `visualization_name`, `visualization` )
"""
- xml_tree = galaxy.util.parse_xml( xml_filepath )
- visualization_conf = xml_tree.getroot()
- visualization_name = visualization_conf.get( 'name' )
- visualization = self.parse_visualization( visualization_conf )
- return visualization_name, visualization
+ try:
+ xml_tree = galaxy.util.parse_xml( xml_filepath )
+ visualization = self.parse_visualization( xml_tree.getroot() )
+ return visualization
+ # skip vis' with parsing errors - don't shutdown the startup
+ except ParsingException, parse_exc:
+ log.exception( 'Skipped visualization config "%s" due to parsing errors', xml_filepath )
+ return None
def parse_visualization( self, xml_tree ):
"""
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 lib/galaxy/web/base/pluginframework.py
--- a/lib/galaxy/web/base/pluginframework.py
+++ b/lib/galaxy/web/base/pluginframework.py
@@ -1,150 +1,106 @@
"""
Base class for plugins - frameworks or systems that may:
+ * add code at startup
+ * allow hooks to be called
+and base class for plugins that:
* serve static content
* serve templated html
* have some configuration at startup
"""
import os.path
-import glob
import sys
+import imp
import pkg_resources
pkg_resources.require( 'MarkupSafe' )
pkg_resources.require( 'Mako' )
import mako
-from galaxy.util import listify
+from galaxy import util
+from galaxy.util import odict
+from galaxy.util import bunch
import logging
log = logging.getLogger( __name__ )
# ============================================================================= exceptions
-class PluginFrameworkException( Exception ):
+class PluginManagerException( Exception ):
"""Base exception for plugin frameworks.
"""
pass
-class PluginFrameworkConfigException( PluginFrameworkException ):
+class PluginManagerConfigException( PluginManagerException ):
"""Exception for plugin framework configuration errors.
"""
pass
-class PluginFrameworkStaticException( PluginFrameworkException ):
- """Exception for plugin framework static directory set up errors.
- """
- pass
-class PluginFrameworkTemplateException( PluginFrameworkException ):
- """Exception for plugin framework template directory
- and template rendering errors.
- """
- pass
# ============================================================================= base
-class PluginFramework( object ):
+class PluginManager( object ):
"""
- Plugins are files/directories living outside the Galaxy ``lib`` directory
- that serve static files (css, js, images, etc.), use and serve mako templates,
- and have some configuration to control the rendering.
+ Plugins represents an section of code that is not tracked in the
+ Galaxy repository, allowing the addition of custom code to a Galaxy
+ installation without changing the code base.
- A plugin framework sets up all the above components.
+ A PluginManager discovers and manages these plugins.
+
+ This is an non-abstract class but it's usefulness is limited and is meant
+ to be inherited.
"""
- #: does the class need a config file(s) to be parsed?
- has_config = True
- #: does the class need static files served?
- serves_static = True
- #: does the class need template files served?
- serves_templates = True
- #TODO: allow plugin mako inheritance from existing ``/templates`` files
- #uses_galaxy_templates = True
- #TODO: possibly better as instance var (or a combo)
- #: the directories in ``plugin_directory`` with basenames listed here will
- #: be ignored for config, static, and templates
- non_plugin_directories = []
- # ------------------------------------------------------------------------- setup
- @classmethod
- def from_config( cls, config_plugin_directory, config ):
+ def __init__( self, app, directories_setting=None, skip_bad_plugins=True, **kwargs ):
"""
- Set up the framework based on data from some config object by:
- * constructing it's absolute plugin_directory filepath
- * getting a template_cache
- * and appending itself to the config object's ``plugin_frameworks`` list
+ Set up the manager and load all plugins.
- .. note::
- precondition: config obj should have attributes:
- root, template_cache, and (list) plugin_frameworks
+ :type app: UniverseApplication
+ :param app: the application (and it's configuration) using this manager
+ :type directories_setting: string (default: None)
+ :param directories_setting: the filesystem path (or paths)
+ to search for plugins. Can be CSV string of paths. Will be treated as
+ absolute if a path starts with '/', relative otherwise.
+ :type skip_bad_plugins: boolean (default: True)
+ :param skip_bad_plugins: whether to skip plugins that cause
+ exceptions when loaded or to raise that exception
"""
- # currently called from (base) app.py - defined here to allow override if needed
- if not config_plugin_directory:
- return None
- try:
- # create the plugin path and if plugin dir begins with '/' assume absolute path
- full_plugin_filepath = os.path.join( config.root, config_plugin_directory )
- if config_plugin_directory.startswith( os.path.sep ):
- full_plugin_filepath = config_plugin_directory
- if not os.path.exists( full_plugin_filepath ):
- raise PluginFrameworkException( 'Plugin path not found: %s' %( full_plugin_filepath ) )
+ log.debug( 'PluginManager.init: %s, %s', directories_setting, kwargs )
+ self.directories = []
+ self.skip_bad_plugins = skip_bad_plugins
+ self.plugins = odict.odict()
- template_cache = config.template_cache if cls.serves_static else None
- plugin = cls( full_plugin_filepath, template_cache )
+ self.directories = self.parse_directories_setting( app.config.root, directories_setting )
+ #log.debug( '\t directories: %s', self.directories )
- config.plugin_frameworks.append( plugin )
- return plugin
+ self.load_configuration()
+ self.load_plugins()
- except PluginFrameworkException, plugin_exc:
- log.exception( "Error loading framework %s. Skipping...", cls.__class__.__name__ )
- return None
+ def parse_directories_setting( self, galaxy_root, directories_setting ):
+ """
+ Parse the ``directories_setting`` into a list of relative or absolute
+ filesystem paths that will be searched to discover plugins.
- def __str__( self ):
- return '%s(%s)' %( self.__class__.__name__, self.plugin_directories )
+ :type galaxy_root: string
+ :param galaxy_root: the root path of this galaxy installation
+ :type directories_setting: string (default: None)
+ :param directories_setting: the filesystem path (or paths)
+ to search for plugins. Can be CSV string of paths. Will be treated as
+ absolute if a path starts with '/', relative otherwise.
+ :rtype: list of strings
+ :returns: list of filesystem paths
+ """
+ directories = []
+ if not directories_setting:
+ return directories
- def __init__( self, plugin_directories, name=None, template_cache_dir=None, debug=False, assert_exists=True ):
- """
- :type plugin_directories: string or list
- :param plugin_directories: the base directory where plugin code is kept
- :type name: (optional) string (default: None)
- :param name: the name of this plugin
- (that will appear in url pathing, etc.)
- :type template_cache_dir: (optional) string (default: None)
- :param template_cache_dir: the cache directory to store compiled mako
- :type assert_exists: (optional) bool (default: False)
- :param assert_exists: If True, each configured plugin directory must exist.
- """
- self.plugin_directories = listify( plugin_directories )
- if assert_exists:
- for plugin_directory in self.plugin_directories:
- if not os.path.isdir( plugin_directory ):
- raise PluginFrameworkException( 'Framework plugin directory not found: %s, %s'
- % ( self.__class__.__name__, plugin_directory ) )
+ for directory in util.listify( directories_setting ):
+ directory = directory.strip()
+ if directory.startswith( '/' ):
+ directory = os.path.join( galaxy_root, directory )
+ if not os.path.exists( directory ):
+ log.warn( '%s, directory not found: %s', self, directory )
+ continue
+ directories.append( directory )
+ return directories
- #TODO: or pass in from config
- self.name = name or os.path.basename( self.plugin_directories[0] )
-
- if self.has_config:
- self.load_configuration()
- # set_up_static_urls will be called during the static middleware creation (if serves_static)
- if self.serves_templates:
- self.set_up_templates( template_cache_dir )
-
- def get_plugin_directories( self ):
- """
- Return the plugin directory paths for this plugin.
-
- Gets any directories within ``plugin_directory`` that are directories
- themselves and whose ``basename`` is not in ``plugin_directory``.
- """
- # could instead explicitly list on/off in master config file
- for plugin_directory in self.plugin_directories:
- for plugin_path in glob.glob( os.path.join( plugin_directory, '*' ) ):
- if not os.path.isdir( plugin_path ):
- continue
-
- if os.path.basename( plugin_path ) in self.non_plugin_directories:
- continue
-
- yield plugin_path
-
- # ------------------------------------------------------------------------- config
def load_configuration( self ):
"""
Override to load some framework/plugin specifc configuration.
@@ -152,6 +108,348 @@
# Abstract method
return True
+ def load_plugins( self ):
+ """
+ Search ``self.directories`` for potential plugins, load them, and cache
+ in ``self.plugins``.
+ :rtype: odict
+ :returns: ``self.plugins``
+ """
+ for plugin_path in self.find_plugins():
+ try:
+ plugin = self.load_plugin( plugin_path )
+ if not plugin:
+ log.warn( '%s, plugin load failed: %s. Skipping...', self, plugin_path )
+ #NOTE: prevent silent, implicit overwrite here (two plugins in two diff directories)
+ #TODO: overwriting may be desired
+ elif plugin.name in self.plugins:
+ log.warn( '%s, plugin with name already exists: %s. Skipping...', self, plugin.name )
+ else:
+ self.plugins[ plugin.name ] = plugin
+ log.info( '%s, loaded plugin: %s', self, plugin.name )
+
+ except Exception, exc:
+ if not self.skip_bad_plugins:
+ raise
+ log.exception( 'Plugin loading raised exception: %s. Skipping...', plugin_path )
+
+ return self.plugins
+
+ def find_plugins( self ):
+ """
+ Return the directory paths of plugins within ``self.directories``.
+
+ Paths are considered a plugin path if they pass ``self.is_plugin``.
+ :rtype: string generator
+ :returns: paths of valid plugins
+ """
+ # due to the ordering of listdir, there is an implicit plugin loading order here
+ # could instead explicitly list on/off in master config file
+ for directory in self.directories:
+ for plugin_dir in os.listdir( directory ):
+ plugin_path = os.path.join( directory, plugin_dir )
+ if self.is_plugin( plugin_path ):
+ yield plugin_path
+
+ def is_plugin( self, plugin_path ):
+ """
+ Determines whether the given filesystem path contains a plugin.
+
+ In this base class, all sub-directories are considered plugins.
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the
+ potential plugin
+ :rtype: bool
+ :returns: True if the path contains a plugin
+ """
+ if not os.path.isdir( plugin_path ):
+ return False
+ return True
+
+ def load_plugin( self, plugin_path ):
+ """
+ Create, load, and/or initialize the plugin and return it.
+
+ Plugin bunches are decorated with:
+ * name : the plugin name
+ * path : the plugin path
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the plugin
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ plugin = bunch.Bunch(
+ #TODO: need a better way to define plugin names
+ # pro: filesystem name ensures uniqueness
+ # con: rel. inflexible
+ name = os.path.split( plugin_path )[1],
+ path = plugin_path
+ )
+ return plugin
+
+
+# ============================================================================= plugin managers using hooks
+class HookPluginManager( PluginManager ):
+ """
+ A hook plugin is a directory containing python modules or packages that:
+ * allow creating, including, and running custom code at specific 'hook'
+ points/events
+ * are not tracked in the Galaxy repository and allow adding custom code
+ to a Galaxy installation
+
+ A HookPluginManager imports the plugin code needed and calls the plugin's
+ hook functions at the specified time.
+ """
+ #: the python file that will be imported - hook functions should be contained here
+ loading_point_filename = 'plugin.py'
+ hook_fn_prefix = 'hook_'
+
+ def is_plugin( self, plugin_path ):
+ """
+ Determines whether the given filesystem path contains a hookable plugin.
+
+ All sub-directories that contain ``loading_point_filename`` are considered
+ plugins.
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the
+ potential plugin
+ :rtype: bool
+ :returns: True if the path contains a plugin
+ """
+ if not super( HookPluginManager, self ).is_plugin( plugin_path ):
+ return False
+ #TODO: possibly switch to <plugin.name>.py or __init__.py
+ if self.loading_point_filename not in os.listdir( plugin_path ):
+ return False
+ return True
+
+ def load_plugin( self, plugin_path ):
+ """
+ Import the plugin ``loading_point_filename`` and attach to the plugin bunch.
+
+ Plugin bunches are decorated with:
+ * name : the plugin name
+ * path : the plugin path
+ * module : the plugin code
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the plugin
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ plugin = super( HookPluginManager, self ).load_plugin( plugin_path )
+
+ loading_point_name = self.loading_point_filename[:-3]
+ plugin[ 'module' ] = self.import_plugin_module( loading_point_name, plugin )
+ return plugin
+
+ def import_plugin_module( self, loading_point_name, plugin, import_as=None ):
+ """
+ Import the plugin code and cache the module in the plugin object.
+
+ :type loading_point_name: string
+ :param loading_point_name: name of the python file to import (w/o extension)
+ :type plugin: ``util.bunch.Bunch``
+ :param plugin: the plugin containing the template to render
+ :type import_as: string
+ :param import_as: namespace to use for imported module
+ This will be prepended with the ``__name__`` of this file.
+ Defaults to ``plugin.name``
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ # add this name to import_as (w/ default to plugin.name) to prevent namespace pollution in sys.modules
+ import_as = '%s.%s' %( __name__, ( import_as or plugin.name ) )
+ module_file, pathname, description = imp.find_module( loading_point_name, [ plugin.path ] )
+ try:
+ #TODO: hate this hack but only way to get package imports inside the plugin to work?
+ sys.path.append( plugin.path )
+ # sys.modules will now have import_as in it's list
+ module = imp.load_module( import_as, module_file, pathname, description )
+ finally:
+ module_file.close()
+ if plugin.path in sys.path:
+ sys.path.remove( plugin.path )
+ return module
+
+ def run_hook( self, hook_name, *args, **kwargs ):
+ """
+ Search all plugins for a function named ``hook_fn_prefix`` + ``hook_name``
+ and run it passing in args and kwargs.
+
+ :type hook_name: string
+ :param hook_name: name (suffix) of the hook to run
+ :rtype: 2-tuple containing (list, dict)
+ :returns: (possibly modified) args, kwargs
+ """
+ #TODO: is hook prefix necessary?
+ #TODO: could be made more efficient if cached by hook_name in the manager on load_plugin
+ # (low maint. overhead since no dynamic loading/unloading of plugins)
+ hook_fn_name = ''.join([ self.hook_fn_prefix, hook_name ])
+ for plugin_name, plugin in self.plugins.items():
+ hook_fn = getattr( plugin.module, hook_fn_name, None )
+
+ if hook_fn and hasattr( hook_fn, '__call__' ):
+ try:
+ #log.debug( 'calling %s from %s(%s)', hook_fn.func_name, plugin.name, plugin.module )
+ hook_fn( *args, **kwargs )
+ except Exception, exc:
+ # fail gracefully and continue with other plugins
+ log.exception( 'Hook function "%s" failed for plugin "%s"', hook_name, plugin.name )
+
+ # may have been altered by hook fns, return in order to act like filter
+ return args, kwargs
+
+
+# ============================================================================= exceptions
+class PluginManagerStaticException( PluginManagerException ):
+ """Exception for plugin framework static directory set up errors.
+ """
+ pass
+class PluginManagerTemplateException( PluginManagerException ):
+ """Exception for plugin framework template directory
+ and template rendering errors.
+ """
+ pass
+
+
+# ============================================================================= base
+class PageServingPluginManager( PluginManager ):
+ """
+ Page serving plugins are files/directories that:
+ * are not tracked in the Galaxy repository and allow adding custom code
+ to a Galaxy installation
+ * serve static files (css, js, images, etc.),
+ * render templates
+
+ A PageServingPluginManager sets up all the above components.
+ """
+ #TODO: I'm unclear of the utility of this class - it prob. will only have one subclass (vis reg). Fold into?
+
+ #: does the class need static files served?
+ serves_static = True
+ #: does the class need template files served?
+ serves_templates = True
+ #: default number of templates to search for plugin template lookup
+ DEFAULT_TEMPLATE_COLLECTION_SIZE = 10
+ #: default encoding of plugin templates
+ DEFAULT_TEMPLATE_ENCODING = 'utf-8'
+
+ def __init__( self, app, base_url, template_cache_dir=None, **kwargs ):
+ """
+ Set up the manager and load all plugins.
+
+ :type app: UniverseApplication
+ :param app: the application (and it's configuration) using this manager
+ :type base_url: string
+ :param base_url: url to prefix all plugin urls with
+ :type template_cache_dir: string
+ :param template_cache_dir: filesytem path to the directory where cached
+ templates are kept
+ """
+ self.base_url = base_url
+ self.template_cache_dir = template_cache_dir
+
+ super( PageServingPluginManager, self ).__init__( app, **kwargs )
+
+ def is_plugin( self, plugin_path ):
+ """
+ Determines whether the given filesystem path contains a plugin.
+
+ If the manager ``serves_templates`` and a sub-directory contains another
+ sub-directory named 'templates' it's considered valid.
+ If the manager ``serves_static`` and a sub-directory contains another
+ sub-directory named 'static' it's considered valid.
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the
+ potential plugin
+ :rtype: bool
+ :returns: True if the path contains a plugin
+ """
+ if not os.path.isdir( plugin_path ):
+ return False
+ #TODO: this is not reliable and forces the inclusion of empty dirs in some situations
+ if self.serves_templates and not 'templates' in os.listdir( plugin_path ):
+ return False
+ if self.serves_static and not 'static' in os.listdir( plugin_path ):
+ return False
+ return True
+
+ def load_plugin( self, plugin_path ):
+ """
+ Create the plugin and decorate with static and/or template paths and urls.
+
+ Plugin bunches are decorated with:
+ * name : the plugin name
+ * path : the plugin path
+ * base_url : a url to the plugin
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the plugin
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ plugin = super( PageServingPluginManager, self ).load_plugin( plugin_path )
+ #TODO: urlencode?
+ plugin[ 'base_url' ] = '/'.join([ self.base_url, plugin.name ])
+ plugin = self._set_up_static_plugin( plugin )
+ plugin = self._set_up_template_plugin( plugin )
+
+ return plugin
+
+ def _set_up_static_plugin( self, plugin ):
+ """
+ Decorate the plugin with paths and urls needed to serve static content.
+
+ Plugin bunches are decorated with:
+ * serves_static : whether this plugin will serve static content
+
+ If the plugin path contains a 'static' sub-dir, the following are added:
+ * static_path : the filesystem path to the static content
+ * static_url : the url to use when serving static content
+
+ :type plugin: ``util.bunch.Bunch``
+ :param plugin: the plugin to decorate
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ plugin[ 'serves_static' ] = False
+ static_path = os.path.join( plugin.path, 'static' )
+ if self.serves_static and os.path.isdir( static_path ):
+ plugin.serves_static = True
+ plugin[ 'static_path' ] = static_path
+ plugin[ 'static_url' ] = '/'.join([ plugin.base_url, 'static' ])
+ return plugin
+
+ def _set_up_template_plugin( self, plugin ):
+ """
+ Decorate the plugin with paths needed to fill templates.
+
+ Plugin bunches are decorated with:
+ * serves_templates : whether this plugin will use templates
+
+ If the plugin path contains a 'static' sub-dir, the following are added:
+ * template_path : the filesystem path to the template sub-dir
+ * template_lookup : the (currently Mako) TemplateLookup used to search
+ for templates
+
+ :type plugin: ``util.bunch.Bunch``
+ :param plugin: the plugin to decorate
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ plugin[ 'serves_templates' ] = False
+ template_path = os.path.join( plugin.path, 'templates' )
+ if self.serves_templates and os.path.isdir( template_path ):
+ plugin.serves_templates = True
+ plugin[ 'template_path' ] = template_path
+ plugin[ 'template_lookup' ] = self.build_plugin_template_lookup( plugin )
+ return plugin
+
# ------------------------------------------------------------------------- serving static files
def get_static_urls_and_paths( self ):
"""
@@ -160,81 +458,63 @@
same files.
Meant to be passed to a Static url map.
+
+ :rtype: list of 2-tuples
+ :returns: all urls and paths for each plugin serving static content
"""
- url_and_paths = []
# called during the static middleware creation (buildapp.py, wrap_in_static)
-
- # NOTE: this only searches for static dirs two levels deep (i.e. <plugin_directory>/<plugin-name>/static)
- for plugin_path in self.get_plugin_directories():
- # that path is a plugin, search for subdirs named static in THAT dir
- plugin_static_path = os.path.join( plugin_path, 'static' )
- if not os.path.isdir( plugin_static_path ):
- continue
-
- # build a url for that static subdir and create a Static urlmap entry for it
- plugin_name = os.path.splitext( os.path.basename( plugin_path ) )[0]
- plugin_url = self.name + '/' + plugin_name + '/static'
- url_and_paths.append( ( plugin_url, plugin_static_path ) )
-
- return url_and_paths
+ urls_and_paths = []
+ for plugin in self.plugins.values():
+ if plugin.serves_static:
+ urls_and_paths.append( ( plugin.static_url, plugin.static_path ) )
+ return urls_and_paths
# ------------------------------------------------------------------------- templates
- def set_up_templates( self, template_cache_dir ):
+ def build_plugin_template_lookup( self, plugin ):
"""
- Add a ``template_lookup`` attribute to the framework that can be passed
- to the mako renderer to find templates.
+ Builds the object that searches for templates (cached or not) when rendering.
+
+ :type plugin: ``util.bunch.Bunch``
+ :param plugin: the plugin containing the templates
+ :rtype: ``Mako.lookup.TemplateLookup``
+ :returns: template lookup for this plugin
"""
- if not template_cache_dir:
- raise PluginFrameworkTemplateException( 'Plugins that serve templates require a template_cache_dir' )
- self.template_lookup = self._create_mako_template_lookup( template_cache_dir, self._get_template_paths() )
- return self.template_lookup
+ if not plugin.serves_templates:
+ return None
+ template_lookup = self._create_mako_template_lookup( self.template_cache_dir, plugin.template_path )
+ return template_lookup
- def _get_template_paths( self ):
- """
- Get the paths that will be searched for templates.
- """
- return self.plugin_directories
-
- def _create_mako_template_lookup( self, cache_dir, paths, collection_size=500, output_encoding='utf-8' ):
+ def _create_mako_template_lookup( self, cache_dir, paths,
+ collection_size=DEFAULT_TEMPLATE_COLLECTION_SIZE, output_encoding=DEFAULT_TEMPLATE_ENCODING ):
"""
Create a ``TemplateLookup`` with defaults.
+
+ :rtype: ``Mako.lookup.TemplateLookup``
+ :returns: all urls and paths for each plugin serving static content
"""
+ #TODO: possible to add galaxy/templates into the lookup here?
return mako.lookup.TemplateLookup(
directories = paths,
module_directory = cache_dir,
collection_size = collection_size,
output_encoding = output_encoding )
- #TODO: do we want to remove trans and app from the plugin template context?
- def fill_template( self, trans, template_filename, **kwargs ):
+ def fill_template( self, trans, plugin, template_filename, **kwargs ):
"""
- Pass control over to trans and render the ``template_filename``.
+ Pass control over to trans and render ``template_filename``.
+
+ :type trans: ``galaxy.web.framework.GalaxyWebTransaction``
+ :param trans: transaction doing the rendering
+ :type plugin: ``util.bunch.Bunch``
+ :param plugin: the plugin containing the template to render
+ :type template_filename: string
+ :param template_filename: the path of the template to render relative to
+ ``plugin.template_path``
+ :returns: rendered template
"""
# defined here to be overridden
- return trans.fill_template( template_filename, template_lookup=self.template_lookup, **kwargs )
+ return trans.fill_template( template_filename, template_lookup=plugin.template_lookup, **kwargs )
- def fill_template_with_plugin_imports( self, trans, template_filename, **kwargs ):
- """
- Returns a rendered plugin template but allows importing modules from inside
- the plugin directory within the template.
-
- ..example:: I.e. given this layout for a plugin:
- bler/
- template/
- bler.mako
- static/
- conifg/
- my_script.py
- this version of `fill_template` allows `bler.mako` to call `import my_script`.
- """
- try:
- plugin_path = os.path.dirname( os.path.dirname( template_filename ) )
- sys.path.append( plugin_path )
- filled_template = self.fill_template( trans, template_filename, **kwargs )
-
- finally:
- sys.path.remove( plugin_path )
-
- return filled_template
-
- #TODO: could add plugin template helpers here
+ #TODO: add fill_template fn that is able to load extra libraries beforehand (and remove after)
+ #TODO: add template helpers specific to the plugins
+ #TODO: some sort of url_for for these plugins
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 lib/galaxy/webapps/galaxy/buildapp.py
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -193,7 +193,8 @@
if kwargs.get( 'middleware', True ):
webapp = wrap_in_middleware( webapp, global_conf, **kwargs )
if asbool( kwargs.get( 'static_enabled', True ) ):
- webapp = wrap_in_static( webapp, global_conf, plugin_frameworks=app.config.plugin_frameworks, **kwargs )
+ webapp = wrap_in_static( webapp, global_conf, plugin_frameworks=[ app.visualizations_registry ], **kwargs )
+ #webapp = wrap_in_static( webapp, global_conf, plugin_frameworks=None, **kwargs )
if asbool(kwargs.get('pack_scripts', False)):
pack_scripts()
# Close any pooled database connections before forking
@@ -362,12 +363,13 @@
# wrap any static dirs for plugins
plugin_frameworks = plugin_frameworks or []
- for static_serving_framework in ( framework for framework in plugin_frameworks if framework.serves_static ):
- # invert control to each plugin for finding their own static dirs
- for plugin_url, plugin_static_path in static_serving_framework.get_static_urls_and_paths():
- plugin_url = '/plugins/' + plugin_url
- urlmap[( plugin_url )] = Static( plugin_static_path, cache_time )
- log.debug( 'added url, path to static middleware: %s, %s', plugin_url, plugin_static_path )
+ for framework in plugin_frameworks:
+ if framework and framework.serves_static:
+ # invert control to each plugin for finding their own static dirs
+ for plugin_url, plugin_static_path in framework.get_static_urls_and_paths():
+ plugin_url = '/plugins/' + plugin_url
+ urlmap[( plugin_url )] = Static( plugin_static_path, cache_time )
+ log.debug( 'added url, path to static middleware: %s, %s', plugin_url, plugin_static_path )
# URL mapper becomes the root webapp
return urlmap
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 lib/galaxy/webapps/galaxy/controllers/visualization.py
--- a/lib/galaxy/webapps/galaxy/controllers/visualization.py
+++ b/lib/galaxy/webapps/galaxy/controllers/visualization.py
@@ -698,10 +698,10 @@
registry = trans.app.visualizations_registry
if not registry:
raise HTTPNotFound( 'No visualization registry (possibly disabled in universe_wsgi.ini)' )
- if visualization_name not in registry.listings:
+ if visualization_name not in registry.plugins:
raise HTTPNotFound( 'Unknown or invalid visualization: ' + visualization_name )
# or redirect to list?
- registry_listing = registry.listings[ visualization_name ]
+ plugin = registry.plugins[ visualization_name ]
returned = None
try:
@@ -711,8 +711,8 @@
resources = registry.query_dict_to_resources( trans, self, visualization_name, kwargs )
# look up template and render
- template_path = registry_listing[ 'template' ]
- returned = registry.fill_template( trans, template_path,
+ template_path = plugin.config[ 'template' ]
+ returned = registry.fill_template( trans, plugin, template_path,
visualization_name=visualization_name, query_args=kwargs,
embedded=embedded, shared_vars={}, **resources )
#NOTE: passing *unparsed* kwargs as query_args
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: Typo in toolshed util common.
by commits-noreply@bitbucket.org 17 Sep '13
by commits-noreply@bitbucket.org 17 Sep '13
17 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/b5c08cc6adbb/
Changeset: b5c08cc6adbb
User: dannon
Date: 2013-09-17 23:31:16
Summary: Typo in toolshed util common.
Affected #: 1 file
diff -r 1e664910d749be12d6f0ece29028f18b820476a1 -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 lib/tool_shed/util/shed_util_common.py
--- a/lib/tool_shed/util/shed_util_common.py
+++ b/lib/tool_shed/util/shed_util_common.py
@@ -1186,7 +1186,7 @@
encoded_tool_shed_status_dict = common_util.tool_shed_get( app, tool_shed_url, url )
tool_shed_status_dict = encoding_util.tool_shed_decode( encoded_tool_shed_status_dict )
except Exception, e:
- log.exception( "Error attemtping to get tool shed status for installed repository %s: %s" % ( str( repository.name ), str( e ) ) )
+ log.exception( "Error attempting to get tool shed status for installed repository %s: %s" % ( str( repository.name ), str( e ) ) )
return {}
return tool_shed_status_dict
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/commits/1c9adf19f128/
Changeset: 1c9adf19f128
User: mdshw5
Date: 2013-09-04 16:42:56
Summary: fixed it's > its typos
Affected #: 1 file
diff -r b9da077a79c3ce0323bd8f8e5aed3e311d1fd8ae -r 1c9adf19f12813b9802e84bbde73ca1e7758a498 templates/webapps/tool_shed/repository/common.mako
--- a/templates/webapps/tool_shed/repository/common.mako
+++ b/templates/webapps/tool_shed/repository/common.mako
@@ -1,4 +1,3 @@
-
<%def name="common_javascripts(repository)"><script type="text/javascript">
$(function(){
@@ -180,7 +179,7 @@
${repository_type | h}
%if render_help:
<div class="toolParamHelp" style="clear: both;">
- This repository's type cannot be changed because it's contents are valid only for it's current type or it has been cloned.
+ This repository's type cannot be changed because its contents are valid only for its current type or it has been cloned.
</div>
%endif
%else:
https://bitbucket.org/galaxy/galaxy-central/commits/1e664910d749/
Changeset: 1e664910d749
User: dannon
Date: 2013-09-17 22:46:32
Summary: Merged in mdshw5/galaxy-central-toolshed-typos (pull request #210)
fixed it's > its typos
Affected #: 1 file
diff -r 47798b37aed096b344c43c6796b7aae27ef11e90 -r 1e664910d749be12d6f0ece29028f18b820476a1 templates/webapps/tool_shed/repository/common.mako
--- a/templates/webapps/tool_shed/repository/common.mako
+++ b/templates/webapps/tool_shed/repository/common.mako
@@ -1,4 +1,3 @@
-
<%def name="common_javascripts(repository)"><script type="text/javascript">
$(function(){
@@ -180,7 +179,7 @@
${repository_type | h}
%if render_help:
<div class="toolParamHelp" style="clear: both;">
- This repository's type cannot be changed because it's contents are valid only for it's current type or it has been cloned.
+ This repository's type cannot be changed because its contents are valid only for its current type or it has been cloned.
</div>
%endif
%else:
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/commits/edc5e6ad3d54/
Changeset: edc5e6ad3d54
User: james_taylor
Date: 2013-09-11 22:24:44
Summary: style: use link color for active bg, update tooltip JS
Affected #: 5 files
diff -r 6cf5d0cbaf96c9910b7e72a83f16d5c6a9f2f34a -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b static/scripts/libs/bootstrap.js
--- a/static/scripts/libs/bootstrap.js
+++ b/static/scripts/libs/bootstrap.js
@@ -1,8 +1,63 @@
+/* ========================================================================
+ * Bootstrap: transition.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#transitions
+ * ========================================================================
+ * Copyright 2013 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================================== */
-/* ===================================================
- * bootstrap-transition.js v2.0.4
- * http://twitter.github.com/bootstrap/javascript.html#transitions
- * ===================================================
+
++function ($) { "use strict";
+
+ // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
+ // ============================================================
+
+ function transitionEnd() {
+ var el = document.createElement('bootstrap')
+
+ var transEndEventNames = {
+ 'WebkitTransition' : 'webkitTransitionEnd'
+ , 'MozTransition' : 'transitionend'
+ , 'OTransition' : 'oTransitionEnd otransitionend'
+ , 'transition' : 'transitionend'
+ }
+
+ for (var name in transEndEventNames) {
+ if (el.style[name] !== undefined) {
+ return { end: transEndEventNames[name] }
+ }
+ }
+ }
+
+ // http://blog.alexmaccaw.com/css-transitions
+ $.fn.emulateTransitionEnd = function (duration) {
+ var called = false, $el = this
+ $(this).one($.support.transition.end, function () { called = true })
+ var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
+ setTimeout(callback, duration)
+ return this
+ }
+
+ $(function () {
+ $.support.transition = transitionEnd()
+ })
+
+}(window.jQuery);
+/* ========================================================================
+ * Bootstrap: tab.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#tabs
+ * ========================================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,55 +71,129 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- * ========================================================== */
+ * ======================================================================== */
-!function ($) {
++function ($) { "use strict";
- $(function () {
+ // TAB CLASS DEFINITION
+ // ====================
- "use strict"; // jshint ;_;
+ var Tab = function (element) {
+ this.element = $(element)
+ }
+ Tab.prototype.show = function () {
+ var $this = this.element
+ var $ul = $this.closest('ul:not(.dropdown-menu)')
+ var selector = $this.attr('data-target')
- /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
- * ======================================================= */
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
- $.support.transition = (function () {
+ if ($this.parent('li').hasClass('active')) return
- var transitionEnd = (function () {
+ var previous = $ul.find('.active:last a')[0]
+ var e = $.Event('show.bs.tab', {
+ relatedTarget: previous
+ })
- var el = document.createElement('bootstrap')
- , transEndEventNames = {
- 'WebkitTransition' : 'webkitTransitionEnd'
- , 'MozTransition' : 'transitionend'
- , 'OTransition' : 'oTransitionEnd'
- , 'msTransition' : 'MSTransitionEnd'
- , 'transition' : 'transitionend'
- }
- , name
+ $this.trigger(e)
- for (name in transEndEventNames){
- if (el.style[name] !== undefined) {
- return transEndEventNames[name]
- }
- }
+ if (e.isDefaultPrevented()) return
- }())
+ var $target = $(selector)
- return transitionEnd && {
- end: transitionEnd
+ this.activate($this.parent('li'), $ul)
+ this.activate($target, $target.parent(), function () {
+ $this.trigger({
+ type: 'shown.bs.tab'
+ , relatedTarget: previous
+ })
+ })
+ }
+
+ Tab.prototype.activate = function (element, container, callback) {
+ var $active = container.find('> .active')
+ var transition = callback
+ && $.support.transition
+ && $active.hasClass('fade')
+
+ function next() {
+ $active
+ .removeClass('active')
+ .find('> .dropdown-menu > .active')
+ .removeClass('active')
+
+ element.addClass('active')
+
+ if (transition) {
+ element[0].offsetWidth // reflow for transition
+ element.addClass('in')
+ } else {
+ element.removeClass('fade')
}
- })()
+ if (element.parent('.dropdown-menu')) {
+ element.closest('li.dropdown').addClass('active')
+ }
+ callback && callback()
+ }
+
+ transition ?
+ $active
+ .one($.support.transition.end, next)
+ .emulateTransitionEnd(150) :
+ next()
+
+ $active.removeClass('in')
+ }
+
+
+ // TAB PLUGIN DEFINITION
+ // =====================
+
+ var old = $.fn.tab
+
+ $.fn.tab = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tab')
+
+ if (!data) $this.data('bs.tab', (data = new Tab(this)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.tab.Constructor = Tab
+
+
+ // TAB NO CONFLICT
+ // ===============
+
+ $.fn.tab.noConflict = function () {
+ $.fn.tab = old
+ return this
+ }
+
+
+ // TAB DATA-API
+ // ============
+
+ $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
+ e.preventDefault()
+ $(this).tab('show')
})
}(window.jQuery);
-
-/* ========================================================
- * bootstrap-tab.js v2.0.4
- * http://twitter.github.com/bootstrap/javascript.html#tabs
- * ========================================================
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -78,452 +207,371 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- * ======================================================== */
+ * ======================================================================== */
-!function ($) {
++function ($) { "use strict";
- "use strict"; // jshint ;_;
+ // TOOLTIP PUBLIC CLASS DEFINITION
+ // ===============================
+ var Tooltip = function (element, options) {
+ this.type =
+ this.options =
+ this.enabled =
+ this.timeout =
+ this.hoverState =
+ this.$element = null
- /* TAB CLASS DEFINITION
- * ==================== */
-
- var Tab = function ( element ) {
- this.element = $(element)
+ this.init('tooltip', element, options)
}
- Tab.prototype = {
+ Tooltip.DEFAULTS = {
+ animation: true
+ , placement: 'top'
+ , selector: false
+ , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
+ , trigger: 'hover focus'
+ , title: ''
+ , delay: 0
+ , html: false
+ , container: 'body'
+ }
- constructor: Tab
+ Tooltip.prototype.init = function (type, element, options) {
+ this.enabled = true
+ this.type = type
+ this.$element = $(element)
+ this.options = this.getOptions(options)
- , show: function () {
- var $this = this.element
- , $ul = $this.closest('ul:not(.dropdown-menu)')
- , selector = $this.attr('data-target')
- , previous
- , $target
- , e
+ var triggers = this.options.trigger.split(' ')
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ for (var i = triggers.length; i--;) {
+ var trigger = triggers[i]
+
+ if (trigger == 'click') {
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+ } else if (trigger != 'manual') {
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
+
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
}
+ }
- if ( $this.parent('li').hasClass('active') ) return
+ this.options.selector ?
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+ this.fixTitle()
+ }
- previous = $ul.find('.active a').last()[0]
+ Tooltip.prototype.getDefaults = function () {
+ return Tooltip.DEFAULTS
+ }
- e = $.Event('show', {
- relatedTarget: previous
- })
+ Tooltip.prototype.getOptions = function (options) {
+ options = $.extend({}, this.getDefaults(), this.$element.data(), options)
- $this.trigger(e)
+ if (options.delay && typeof options.delay == 'number') {
+ options.delay = {
+ show: options.delay
+ , hide: options.delay
+ }
+ }
+
+ return options
+ }
+
+ Tooltip.prototype.getDelegateOptions = function () {
+ var options = {}
+ var defaults = this.getDefaults()
+
+ this._options && $.each(this._options, function (key, value) {
+ if (defaults[key] != value) options[key] = value
+ })
+
+ return options
+ }
+
+ Tooltip.prototype.enter = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'in'
+
+ if (!self.options.delay || !self.options.delay.show) return self.show()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'in') self.show()
+ }, self.options.delay.show)
+ }
+
+ Tooltip.prototype.leave = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'out'
+
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'out') self.hide()
+ }, self.options.delay.hide)
+ }
+
+ Tooltip.prototype.show = function () {
+ var e = $.Event('show.bs.'+ this.type)
+
+ if (this.hasContent() && this.enabled) {
+ this.$element.trigger(e)
if (e.isDefaultPrevented()) return
- $target = $(selector)
+ var $tip = this.tip()
- this.activate($this.parent('li'), $ul)
- this.activate($target, $target.parent(), function () {
- $this.trigger({
- type: 'shown'
- , relatedTarget: previous
- })
- })
- }
+ this.setContent()
- , activate: function ( element, container, callback) {
- var $active = container.find('> .active')
- , transition = callback
- && $.support.transition
- && $active.hasClass('fade')
+ if (this.options.animation) $tip.addClass('fade')
- function next() {
- $active
- .removeClass('active')
- .find('> .dropdown-menu > .active')
- .removeClass('active')
+ var placement = typeof this.options.placement == 'function' ?
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
+ this.options.placement
- element.addClass('active')
+ var autoToken = /\s?auto?\s?/i
+ var autoPlace = autoToken.test(placement)
+ if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
- if (transition) {
- element[0].offsetWidth // reflow for transition
- element.addClass('in')
- } else {
- element.removeClass('fade')
- }
+ $tip
+ .detach()
+ .css({ top: 0, left: 0, display: 'block' })
+ .addClass(placement)
- if ( element.parent('.dropdown-menu') ) {
- element.closest('li.dropdown').addClass('active')
- }
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
- callback && callback()
+ var pos = this.getPosition()
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (autoPlace) {
+ var $parent = this.$element.parent()
+
+ var orgPlacement = placement
+ var docScroll = document.documentElement.scrollTop || document.body.scrollTop
+ var parentWidth = this.options.container == 'body' ? window.innerWidth : $parent.outerWidth()
+ var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
+ var parentLeft = this.options.container == 'body' ? 0 : $parent.offset().left
+
+ placement = placement == 'bottom' && pos.top + pos.height + actualHeight - docScroll > parentHeight ? 'top' :
+ placement == 'top' && pos.top - docScroll - actualHeight < 0 ? 'bottom' :
+ placement == 'right' && pos.right + actualWidth > parentWidth ? 'left' :
+ placement == 'left' && pos.left - actualWidth < parentLeft ? 'right' :
+ placement
+
+ $tip
+ .removeClass(orgPlacement)
+ .addClass(placement)
}
- transition ?
- $active.one($.support.transition.end, next) :
- next()
+ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
- $active.removeClass('in')
+ this.applyPlacement(calculatedOffset, placement)
+ this.$element.trigger('shown.bs.' + this.type)
}
}
+ Tooltip.prototype.applyPlacement = function(offset, placement) {
+ var replace
+ var $tip = this.tip()
+ var width = $tip[0].offsetWidth
+ var height = $tip[0].offsetHeight
- /* TAB PLUGIN DEFINITION
- * ===================== */
+ // manually read margins because getBoundingClientRect includes difference
+ var marginTop = parseInt($tip.css('margin-top'), 10)
+ var marginLeft = parseInt($tip.css('margin-left'), 10)
- $.fn.tab = function ( option ) {
- return this.each(function () {
- var $this = $(this)
- , data = $this.data('tab')
- if (!data) $this.data('tab', (data = new Tab(this)))
- if (typeof option == 'string') data[option]()
- })
+ // we must check for NaN for ie 8/9
+ if (isNaN(marginTop)) marginTop = 0
+ if (isNaN(marginLeft)) marginLeft = 0
+
+ offset.top = offset.top + marginTop
+ offset.left = offset.left + marginLeft
+
+ $tip
+ .offset(offset)
+ .addClass('in')
+
+ // check to see if placing tip in new offset caused the tip to resize itself
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (placement == 'top' && actualHeight != height) {
+ replace = true
+ offset.top = offset.top + height - actualHeight
+ }
+
+ if (/bottom|top/.test(placement)) {
+ var delta = 0
+
+ if (offset.left < 0) {
+ delta = offset.left * -2
+ offset.left = 0
+
+ $tip.offset(offset)
+
+ actualWidth = $tip[0].offsetWidth
+ actualHeight = $tip[0].offsetHeight
+ }
+
+ this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
+ } else {
+ this.replaceArrow(actualHeight - height, actualHeight, 'top')
+ }
+
+ if (replace) $tip.offset(offset)
}
- $.fn.tab.Constructor = Tab
-
-
- /* TAB DATA-API
- * ============ */
-
- $(function () {
- $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
- e.preventDefault()
- $(this).tab('show')
- })
- })
-
-}(window.jQuery);
-
-/* ===========================================================
- * bootstrap-tooltip.js v2.0.4
- * http://twitter.github.com/bootstrap/javascript.html#tooltips
- * Inspired by the original jQuery.tipsy by Jason Frame
- * ===========================================================
- * Copyright 2012 Twitter, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ========================================================== */
-
-
-!function ($) {
-
- "use strict"; // jshint ;_;
-
- // Add a special event that is called when an element is destroyed
- (function($){
- jQuery.event.special.destroyed = {
- remove: function(o) {
- if (o.handler) {
- o.handler()
- }
- }
- }
- })(jQuery)
-
- /* TOOLTIP PUBLIC CLASS DEFINITION
- * =============================== */
-
- var Tooltip = function (element, options) {
- this.init('tooltip', element, options)
+ Tooltip.prototype.replaceArrow = function(delta, dimension, position) {
+ this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
}
- Tooltip.prototype = {
+ Tooltip.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
- constructor: Tooltip
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+ $tip.removeClass('fade in top bottom left right')
+ }
- , init: function (type, element, options) {
- var eventIn
- , eventOut
+ Tooltip.prototype.hide = function () {
+ var that = this
+ var $tip = this.tip()
+ var e = $.Event('hide.bs.' + this.type)
- this.type = type
- this.$element = $(element)
- this.options = this.getOptions(options)
- this.enabled = true
-
- if (this.options.trigger != 'manual') {
- eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
- eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
- this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
- this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
- }
-
- // Make sure tooltip is hidden when element is destroyed
- this.$element.on( 'destroyed', $.proxy( this.hide, this ) );
-
- this.options.selector ?
- (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
- this.fixTitle()
+ function complete() {
+ if (that.hoverState != 'in') $tip.detach()
}
- , getOptions: function (options) {
- options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
+ this.$element.trigger(e)
- if (options.delay && typeof options.delay == 'number') {
- options.delay = {
- show: options.delay
- , hide: options.delay
- }
- }
+ if (e.isDefaultPrevented()) return
- return options
- }
+ $tip.removeClass('in')
- , enter: function (e) {
- var self = $(e.currentTarget)[this.type](this._options).data(this.type)
+ $.support.transition && this.$tip.hasClass('fade') ?
+ $tip
+ .one($.support.transition.end, complete)
+ .emulateTransitionEnd(150) :
+ complete()
- if (!self.options.delay || !self.options.delay.show) return self.show()
+ this.$element.trigger('hidden.bs.' + this.type)
- clearTimeout(this.timeout)
- self.hoverState = 'in'
- this.timeout = setTimeout(function() {
- if (self.hoverState == 'in') self.show()
- }, self.options.delay.show)
- }
-
- , leave: function (e) {
- var self = $(e.currentTarget)[this.type](this._options).data(this.type)
-
- if (this.timeout) clearTimeout(this.timeout)
- if (!self.options.delay || !self.options.delay.hide) return self.hide()
-
- self.hoverState = 'out'
- this.timeout = setTimeout(function() {
- if (self.hoverState == 'out') self.hide()
- }, self.options.delay.hide)
- }
-
- , show: function () {
- var $tip
- , inside
- , pos
- , actualWidth
- , actualHeight
- , placement
- , placementPosition
- , $window
- , tp
-
- if (this.hasContent() && this.enabled) {
- $tip = this.tip()
- this.setContent()
-
- if (this.options.animation) {
- $tip.addClass('fade')
- }
-
- placement = typeof this.options.placement == 'function' ?
- this.options.placement.call(this, $tip[0], this.$element[0]) :
- this.options.placement
-
- placementPosition = inside ? placement.split(' ')[1] : placement;
-
- inside = /in/.test(placement)
-
- $tip
- .remove()
- .css({ top: 0, left: 0, display: 'block' })
- .appendTo(inside ? this.$element : document.body)
-
- pos = this.getPosition(inside)
-
- actualWidth = $tip[0].offsetWidth
- actualHeight = $tip[0].offsetHeight
-
- switch (placementPosition) {
- case 'bottom':
- tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
- break
- case 'top':
- tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
- break
- case 'left':
- tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
- break
- case 'right':
- tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
- break
- }
-
- // Shift if off screen
- $window = $(window)
-
- // If off the top of the screen, flip
- if ( tp.top < $window.scrollTop() && placementPosition == 'top' ) {
- tp.top = pos.top + pos.height;
- placement = inside ? 'inside bottom' : 'bottom';
- }
-
- // Shift left or right
- var leftShift = 0;
- if ( tp.left < $window.scrollLeft() ) {
- leftShift = tp.left - $window.scrollLeft();
- }
- var t = $window.scrollLeft() + $window.width() - $tip.outerWidth();
- if ( tp.left > t ) {
- leftShift = tp.left - t;
- }
-
- tp.left -= leftShift;
-
- // Shift background to center over element (not implemented for east/west)
- switch (inside ? placement.split(' ')[1] : placement) {
- case 'bottom':
- $tip.find('.tooltip-arrow').css( 'left', ( $tip.outerWidth() / 2 ) + leftShift + "px" );
- break;
- case 'top':
- $tip.find('.tooltip-arrow').css( 'left', ( $tip.outerWidth() / 2 ) + leftShift + "px" );
- break;
- case 'left':
- break;
- case 'right':
- break;
- }
-
- // END GALAXY MODIFICATION
-
-
- $tip
- .css(tp)
- .addClass(placement)
- .addClass('in')
- }
- }
-
- , isHTML: function(text) {
- // html string detection logic adapted from jQuery
- return typeof text != 'string'
- || ( text.charAt(0) === "<"
- && text.charAt( text.length - 1 ) === ">"
- && text.length >= 3
- ) || /^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(text)
- }
-
- , setContent: function () {
- var $tip = this.tip()
- , title = this.getTitle()
-
- $tip.find('.tooltip-inner')[this.isHTML(title) ? 'html' : 'text'](title)
- $tip.removeClass('fade in top bottom left right')
- }
-
- , hide: function () {
- var that = this
- , $tip = this.tip()
-
- $tip.removeClass('in')
-
- function removeWithAnimation() {
- var timeout = setTimeout(function () {
- $tip.off($.support.transition.end).remove()
- }, 500)
-
- $tip.one($.support.transition.end, function () {
- clearTimeout(timeout)
- $tip.remove()
- })
- }
-
- $.support.transition && this.$tip.hasClass('fade') ?
- removeWithAnimation() :
- $tip.remove()
- }
-
- , fixTitle: function () {
- var $e = this.$element
- if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
- $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
- }
- }
-
- , hasContent: function () {
- return this.getTitle()
- }
-
- , getPosition: function (inside) {
- return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
- width: this.$element[0].offsetWidth
- , height: this.$element[0].offsetHeight
- })
- }
-
- , getTitle: function () {
- var title
- , $e = this.$element
- , o = this.options
-
- title = $e.attr('data-original-title')
- || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
-
- return title
- }
-
- , tip: function () {
- return this.$tip = this.$tip || $(this.options.template)
- }
-
- , validate: function () {
- if (!this.$element[0].parentNode) {
- this.hide()
- this.$element = null
- this.options = null
- }
- }
-
- , enable: function () {
- this.enabled = true
- }
-
- , disable: function () {
- this.enabled = false
- }
-
- , toggleEnabled: function () {
- this.enabled = !this.enabled
- }
-
- , toggle: function () {
- this[this.tip().hasClass('in') ? 'hide' : 'show']()
- }
-
+ return this
}
+ Tooltip.prototype.fixTitle = function () {
+ var $e = this.$element
+ if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+ }
+ }
- /* TOOLTIP PLUGIN DEFINITION
- * ========================= */
+ Tooltip.prototype.hasContent = function () {
+ return this.getTitle()
+ }
- $.fn.tooltip = function ( option ) {
+ Tooltip.prototype.getPosition = function () {
+ var el = this.$element[0]
+ return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
+ width: el.offsetWidth
+ , height: el.offsetHeight
+ }, this.$element.offset())
+ }
+
+ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
+ }
+
+ Tooltip.prototype.getTitle = function () {
+ var title
+ var $e = this.$element
+ var o = this.options
+
+ title = $e.attr('data-original-title')
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
+
+ return title
+ }
+
+ Tooltip.prototype.tip = function () {
+ return this.$tip = this.$tip || $(this.options.template)
+ }
+
+ Tooltip.prototype.arrow = function () {
+ return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
+ }
+
+ Tooltip.prototype.validate = function () {
+ if (!this.$element[0].parentNode) {
+ this.hide()
+ this.$element = null
+ this.options = null
+ }
+ }
+
+ Tooltip.prototype.enable = function () {
+ this.enabled = true
+ }
+
+ Tooltip.prototype.disable = function () {
+ this.enabled = false
+ }
+
+ Tooltip.prototype.toggleEnabled = function () {
+ this.enabled = !this.enabled
+ }
+
+ Tooltip.prototype.toggle = function (e) {
+ var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+ }
+
+ Tooltip.prototype.destroy = function () {
+ this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
+ }
+
+
+ // TOOLTIP PLUGIN DEFINITION
+ // =========================
+
+ var old = $.fn.tooltip
+
+ $.fn.tooltip = function (option) {
return this.each(function () {
- var $this = $(this)
- , data = $this.data('tooltip')
- , options = typeof option == 'object' && option
- if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
+ var $this = $(this)
+ var data = $this.data('bs.tooltip')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.tooltip.Constructor = Tooltip
- $.fn.tooltip.defaults = {
- animation: false
- , placement: 'top'
- , selector: false
- , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
- , trigger: 'hover'
- , title: ''
- , delay: 0
+
+ // TOOLTIP NO CONFLICT
+ // ===================
+
+ $.fn.tooltip.noConflict = function () {
+ $.fn.tooltip = old
+ return this
}
}(window.jQuery);
diff -r 6cf5d0cbaf96c9910b7e72a83f16d5c6a9f2f34a -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b static/scripts/packed/galaxy.modal.js
--- a/static/scripts/packed/galaxy.modal.js
+++ b/static/scripts/packed/galaxy.modal.js
@@ -1,1 +1,1 @@
-define(["libs/backbone/backbone-relational"],function(){var a=Backbone.View.extend({el_main:"#everything",options:{title:"galaxy-modal",body:"No content available."},initialize:function(b){if(b){this.create(b);$(this.el).hide()}},show:function(b){if(b){this.create(b)}this.$el.fadeIn("fast")},hide:function(){this.$el.fadeOut("fast")},create:function(c){this.$el.remove();if(!c){c=this.options}else{c=_.defaults(c,this.options)}this.setElement(this.template(c.title,c.body));$(this.el_main).append($(this.el));var d=(this.$el).find(".footer");var b=this;if(c.buttons){$.each(c.buttons,function(e,f){d.append($("<button></button>").text(e).click(f)).append(" ")})}else{d.append($("<button></button>").text("Close").click(function(){b.hide()})).append(" ")}},template:function(c,b){return'<div class="modal"><div class="modal-backdrop"></div><div class="modal-dialog galaxy-corner"><div class="modal-content"><div class="header"><span><h3 class="title">'+c+'</h3></span></div><div class="body">'+b+'</div><div class="footer"></div></div</div></div>'}});return{GalaxyModal:a}});
\ No newline at end of file
+define(["libs/backbone/backbone-relational"],function(){var a=Backbone.View.extend({el_main:"#everything",options:{title:"galaxy-modal",body:"No content available."},initialize:function(b){if(b){this.create(b);$(this.el).hide()}},show:function(b){if(b){this.create(b)}this.$el.fadeIn("fast")},hide:function(){this.$el.fadeOut("fast")},create:function(c){this.$el.remove();if(!c){c=this.options}else{c=_.defaults(c,this.options)}this.setElement(this.template(c.title,c.body));$(this.el_main).append($(this.el));var d=(this.$el).find(".buttons");var b=this;if(c.buttons){$.each(c.buttons,function(e,f){d.append($("<button></button>").text(e).click(f)).append(" ")})}else{d.append($("<button></button>").text("Close").click(function(){b.hide()})).append(" ")}},template:function(c,b){return'<div class="modal in"><div class="modal-backdrop in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><span><h3 class="title">'+c+'</h3></span></div><div class="modal-body style="min-width: 540px; max-height: 445px;">'+b+'</div><div class="modal-footer"><div class="buttons" style="float: right;"></div></div></div</div></div>'}});return{GalaxyModal:a}});
\ No newline at end of file
diff -r 6cf5d0cbaf96c9910b7e72a83f16d5c6a9f2f34a -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b static/scripts/packed/libs/bootstrap.js
--- a/static/scripts/packed/libs/bootstrap.js
+++ b/static/scripts/packed/libs/bootstrap.js
@@ -1,1 +1,1 @@
-!function(a){a(function(){a.support.transition=(function(){var b=(function(){var e=document.createElement("bootstrap"),d={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},c;for(c in d){if(e.style[c]!==undefined){return d[c]}}}());return b&&{end:b}})()})}(window.jQuery);!function(b){var a=function(c){this.element=b(c)};a.prototype={constructor:a,show:function(){var i=this.element,f=i.closest("ul:not(.dropdown-menu)"),d=i.attr("data-target"),g,c,h;if(!d){d=i.attr("href");d=d&&d.replace(/.*(?=#[^\s]*$)/,"")}if(i.parent("li").hasClass("active")){return}g=f.find(".active a").last()[0];h=b.Event("show",{relatedTarget:g});i.trigger(h);if(h.isDefaultPrevented()){return}c=b(d);this.activate(i.parent("li"),f);this.activate(c,c.parent(),function(){i.trigger({type:"shown",relatedTarget:g})})},activate:function(e,d,h){var c=d.find("> .active"),g=h&&b.support.transition&&c.hasClass("fade");function f(){c.removeClass("active").find("> .dropdown-menu > .active").removeClass("active");e.addClass("active");if(g){e[0].offsetWidth;e.addClass("in")}else{e.removeClass("fade")}if(e.parent(".dropdown-menu")){e.closest("li.dropdown").addClass("active")}h&&h()}g?c.one(b.support.transition.end,f):f();c.removeClass("in")}};b.fn.tab=function(c){return this.each(function(){var e=b(this),d=e.data("tab");if(!d){e.data("tab",(d=new a(this)))}if(typeof c=="string"){d[c]()}})};b.fn.tab.Constructor=a;b(function(){b("body").on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(c){c.preventDefault();b(this).tab("show")})})}(window.jQuery);!function(b){(function(c){jQuery.event.special.destroyed={remove:function(d){if(d.handler){d.handler()}}}})(jQuery);var a=function(d,c){this.init("tooltip",d,c)};a.prototype={constructor:a,init:function(f,e,d){var g,c;this.type=f;this.$element=b(e);this.options=this.getOptions(d);this.enabled=true;if(this.options.trigger!="manual"){g=this.options.trigger=="hover"?"mouseenter":"focus";c=this.options.trigger=="hover"?"mouseleave":"blur";this.$element.on(g,this.options.selector,b.proxy(this.enter,this));this.$element.on(c,this.options.selector,b.proxy(this.leave,this))}this.$element.on("destroyed",b.proxy(this.hide,this));this.options.selector?(this._options=b.extend({},this.options,{trigger:"manual",selector:""})):this.fixTitle()},getOptions:function(c){c=b.extend({},b.fn[this.type].defaults,c,this.$element.data());if(c.delay&&typeof c.delay=="number"){c.delay={show:c.delay,hide:c.delay}}return c},enter:function(d){var c=b(d.currentTarget)[this.type](this._options).data(this.type);if(!c.options.delay||!c.options.delay.show){return c.show()}clearTimeout(this.timeout);c.hoverState="in";this.timeout=setTimeout(function(){if(c.hoverState=="in"){c.show()}},c.options.delay.show)},leave:function(d){var c=b(d.currentTarget)[this.type](this._options).data(this.type);if(this.timeout){clearTimeout(this.timeout)}if(!c.options.delay||!c.options.delay.hide){return c.hide()}c.hoverState="out";this.timeout=setTimeout(function(){if(c.hoverState=="out"){c.hide()}},c.options.delay.hide)},show:function(){var i,f,k,c,j,h,e,d,l;if(this.hasContent()&&this.enabled){i=this.tip();this.setContent();if(this.options.animation){i.addClass("fade")}h=typeof this.options.placement=="function"?this.options.placement.call(this,i[0],this.$element[0]):this.options.placement;e=f?h.split(" ")[1]:h;f=/in/.test(h);i.remove().css({top:0,left:0,display:"block"}).appendTo(f?this.$element:document.body);k=this.getPosition(f);c=i[0].offsetWidth;j=i[0].offsetHeight;switch(e){case"bottom":l={top:k.top+k.height,left:k.left+k.width/2-c/2};break;case"top":l={top:k.top-j,left:k.left+k.width/2-c/2};break;case"left":l={top:k.top+k.height/2-j/2,left:k.left-c};break;case"right":l={top:k.top+k.height/2-j/2,left:k.left+k.width};break}d=b(window);if(l.top<d.scrollTop()&&e=="top"){l.top=k.top+k.height;h=f?"inside bottom":"bottom"}var g=0;if(l.left<d.scrollLeft()){g=l.left-d.scrollLeft()}var m=d.scrollLeft()+d.width()-i.outerWidth();if(l.left>m){g=l.left-m}l.left-=g;switch(f?h.split(" ")[1]:h){case"bottom":i.find(".tooltip-arrow").css("left",(i.outerWidth()/2)+g+"px");break;case"top":i.find(".tooltip-arrow").css("left",(i.outerWidth()/2)+g+"px");break;case"left":break;case"right":break}i.css(l).addClass(h).addClass("in")}},isHTML:function(c){return typeof c!="string"||(c.charAt(0)==="<"&&c.charAt(c.length-1)===">"&&c.length>=3)||/^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(c)},setContent:function(){var d=this.tip(),c=this.getTitle();d.find(".tooltip-inner")[this.isHTML(c)?"html":"text"](c);d.removeClass("fade in top bottom left right")},hide:function(){var c=this,d=this.tip();d.removeClass("in");function e(){var f=setTimeout(function(){d.off(b.support.transition.end).remove()},500);d.one(b.support.transition.end,function(){clearTimeout(f);d.remove()})}b.support.transition&&this.$tip.hasClass("fade")?e():d.remove()},fixTitle:function(){var c=this.$element;if(c.attr("title")||typeof(c.attr("data-original-title"))!="string"){c.attr("data-original-title",c.attr("title")||"").removeAttr("title")}},hasContent:function(){return this.getTitle()},getPosition:function(c){return b.extend({},(c?{top:0,left:0}:this.$element.offset()),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var e,c=this.$element,d=this.options;e=c.attr("data-original-title")||(typeof d.title=="function"?d.title.call(c[0]):d.title);return e},tip:function(){return this.$tip=this.$tip||b(this.options.template)},validate:function(){if(!this.$element[0].parentNode){this.hide();this.$element=null;this.options=null}},enable:function(){this.enabled=true},disable:function(){this.enabled=false},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(){this[this.tip().hasClass("in")?"hide":"show"]()}};b.fn.tooltip=function(c){return this.each(function(){var f=b(this),e=f.data("tooltip"),d=typeof c=="object"&&c;if(!e){f.data("tooltip",(e=new a(this,d)))}if(typeof c=="string"){e[c]()}})};b.fn.tooltip.Constructor=a;b.fn.tooltip.defaults={animation:false,placement:"top",selector:false,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover",title:"",delay:0}}(window.jQuery);
\ No newline at end of file
++function(b){function a(){var e=document.createElement("bootstrap");var d={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in d){if(e.style[c]!==undefined){return{end:d[c]}}}}b.fn.emulateTransitionEnd=function(e){var d=false,c=this;b(this).one(b.support.transition.end,function(){d=true});var f=function(){if(!d){b(c).trigger(b.support.transition.end)}};setTimeout(f,e);return this};b(function(){b.support.transition=a()})}(window.jQuery);+function(c){var b=function(d){this.element=c(d)};b.prototype.show=function(){var j=this.element;var g=j.closest("ul:not(.dropdown-menu)");var f=j.attr("data-target");if(!f){f=j.attr("href");f=f&&f.replace(/.*(?=#[^\s]*$)/,"")}if(j.parent("li").hasClass("active")){return}var h=g.find(".active:last a")[0];var i=c.Event("show.bs.tab",{relatedTarget:h});j.trigger(i);if(i.isDefaultPrevented()){return}var d=c(f);this.activate(j.parent("li"),g);this.activate(d,d.parent(),function(){j.trigger({type:"shown.bs.tab",relatedTarget:h})})};b.prototype.activate=function(f,e,i){var d=e.find("> .active");var h=i&&c.support.transition&&d.hasClass("fade");function g(){d.removeClass("active").find("> .dropdown-menu > .active").removeClass("active");f.addClass("active");if(h){f[0].offsetWidth;f.addClass("in")}else{f.removeClass("fade")}if(f.parent(".dropdown-menu")){f.closest("li.dropdown").addClass("active")}i&&i()}h?d.one(c.support.transition.end,g).emulateTransitionEnd(150):g();d.removeClass("in")};var a=c.fn.tab;c.fn.tab=function(d){return this.each(function(){var f=c(this);var e=f.data("bs.tab");if(!e){f.data("bs.tab",(e=new b(this)))}if(typeof d=="string"){e[d]()}})};c.fn.tab.Constructor=b;c.fn.tab.noConflict=function(){c.fn.tab=a;return this};c(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(d){d.preventDefault();c(this).tab("show")})}(window.jQuery);+function(c){var b=function(e,d){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null;this.init("tooltip",e,d)};b.DEFAULTS={animation:true,placement:"top",selector:false,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:false,container:"body"};b.prototype.init=function(k,h,f){this.enabled=true;this.type=k;this.$element=c(h);this.options=this.getOptions(f);var j=this.options.trigger.split(" ");for(var g=j.length;g--;){var e=j[g];if(e=="click"){this.$element.on("click."+this.type,this.options.selector,c.proxy(this.toggle,this))}else{if(e!="manual"){var l=e=="hover"?"mouseenter":"focus";var d=e=="hover"?"mouseleave":"blur";this.$element.on(l+"."+this.type,this.options.selector,c.proxy(this.enter,this));this.$element.on(d+"."+this.type,this.options.selector,c.proxy(this.leave,this))}}}this.options.selector?(this._options=c.extend({},this.options,{trigger:"manual",selector:""})):this.fixTitle()};b.prototype.getDefaults=function(){return b.DEFAULTS};b.prototype.getOptions=function(d){d=c.extend({},this.getDefaults(),this.$element.data(),d);if(d.delay&&typeof d.delay=="number"){d.delay={show:d.delay,hide:d.delay}}return d};b.prototype.getDelegateOptions=function(){var d={};var e=this.getDefaults();this._options&&c.each(this._options,function(f,g){if(e[f]!=g){d[f]=g}});return d};b.prototype.enter=function(e){var d=e instanceof this.constructor?e:c(e.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);clearTimeout(d.timeout);d.hoverState="in";if(!d.options.delay||!d.options.delay.show){return d.show()}d.timeout=setTimeout(function(){if(d.hoverState=="in"){d.show()}},d.options.delay.show)};b.prototype.leave=function(e){var d=e instanceof this.constructor?e:c(e.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);clearTimeout(d.timeout);d.hoverState="out";if(!d.options.delay||!d.options.delay.hide){return d.hide()}d.timeout=setTimeout(function(){if(d.hoverState=="out"){d.hide()}},d.options.delay.hide)};b.prototype.show=function(){var n=c.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(n);if(n.isDefaultPrevented()){return}var j=this.tip();this.setContent();if(this.options.animation){j.addClass("fade")}var i=typeof this.options.placement=="function"?this.options.placement.call(this,j[0],this.$element[0]):this.options.placement;var r=/\s?auto?\s?/i;var s=r.test(i);if(s){i=i.replace(r,"")||"top"}j.detach().css({top:0,left:0,display:"block"}).addClass(i);this.options.container?j.appendTo(this.options.container):j.insertAfter(this.$element);var o=this.getPosition();var d=j[0].offsetWidth;var l=j[0].offsetHeight;if(s){var h=this.$element.parent();var g=i;var p=document.documentElement.scrollTop||document.body.scrollTop;var q=this.options.container=="body"?window.innerWidth:h.outerWidth();var m=this.options.container=="body"?window.innerHeight:h.outerHeight();var k=this.options.container=="body"?0:h.offset().left;i=i=="bottom"&&o.top+o.height+l-p>m?"top":i=="top"&&o.top-p-l<0?"bottom":i=="right"&&o.right+d>q?"left":i=="left"&&o.left-d<k?"right":i;j.removeClass(g).addClass(i)}var f=this.getCalculatedOffset(i,o,d,l);this.applyPlacement(f,i);this.$element.trigger("shown.bs."+this.type)}};b.prototype.applyPlacement=function(i,j){var g;var k=this.tip();var f=k[0].offsetWidth;var n=k[0].offsetHeight;var e=parseInt(k.css("margin-top"),10);var h=parseInt(k.css("margin-left"),10);if(isNaN(e)){e=0}if(isNaN(h)){h=0}i.top=i.top+e;i.left=i.left+h;k.offset(i).addClass("in");var d=k[0].offsetWidth;var l=k[0].offsetHeight;if(j=="top"&&l!=n){g=true;i.top=i.top+n-l}if(/bottom|top/.test(j)){var m=0;if(i.left<0){m=i.left*-2;i.left=0;k.offset(i);d=k[0].offsetWidth;l=k[0].offsetHeight}this.replaceArrow(m-f+d,d,"left")}else{this.replaceArrow(l-n,l,"top")}if(g){k.offset(i)}};b.prototype.replaceArrow=function(f,e,d){this.arrow().css(d,f?(50*(1-f/e)+"%"):"")};b.prototype.setContent=function(){var e=this.tip();var d=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](d);e.removeClass("fade in top bottom left right")};b.prototype.hide=function(){var f=this;var h=this.tip();var g=c.Event("hide.bs."+this.type);function d(){if(f.hoverState!="in"){h.detach()}}this.$element.trigger(g);if(g.isDefaultPrevented()){return}h.removeClass("in");c.support.transition&&this.$tip.hasClass("fade")?h.one(c.support.transition.end,d).emulateTransitionEnd(150):d();this.$element.trigger("hidden.bs."+this.type);return this};b.prototype.fixTitle=function(){var d=this.$element;if(d.attr("title")||typeof(d.attr("data-original-title"))!="string"){d.attr("data-original-title",d.attr("title")||"").attr("title","")}};b.prototype.hasContent=function(){return this.getTitle()};b.prototype.getPosition=function(){var d=this.$element[0];return c.extend({},(typeof d.getBoundingClientRect=="function")?d.getBoundingClientRect():{width:d.offsetWidth,height:d.offsetHeight},this.$element.offset())};b.prototype.getCalculatedOffset=function(d,g,e,f){return d=="bottom"?{top:g.top+g.height,left:g.left+g.width/2-e/2}:d=="top"?{top:g.top-f,left:g.left+g.width/2-e/2}:d=="left"?{top:g.top+g.height/2-f/2,left:g.left-e}:{top:g.top+g.height/2-f/2,left:g.left+g.width}};b.prototype.getTitle=function(){var f;var d=this.$element;var e=this.options;f=d.attr("data-original-title")||(typeof e.title=="function"?e.title.call(d[0]):e.title);return f};b.prototype.tip=function(){return this.$tip=this.$tip||c(this.options.template)};b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")};b.prototype.validate=function(){if(!this.$element[0].parentNode){this.hide();this.$element=null;this.options=null}};b.prototype.enable=function(){this.enabled=true};b.prototype.disable=function(){this.enabled=false};b.prototype.toggleEnabled=function(){this.enabled=!this.enabled};b.prototype.toggle=function(f){var d=f?c(f.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type):this;d.tip().hasClass("in")?d.leave(d):d.enter(d)};b.prototype.destroy=function(){this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var a=c.fn.tooltip;c.fn.tooltip=function(d){return this.each(function(){var g=c(this);var f=g.data("bs.tooltip");var e=typeof d=="object"&&d;if(!f){g.data("bs.tooltip",(f=new b(this,e)))}if(typeof d=="string"){f[d]()}})};c.fn.tooltip.Constructor=b;c.fn.tooltip.noConflict=function(){c.fn.tooltip=a;return this}}(window.jQuery);
\ No newline at end of file
diff -r 6cf5d0cbaf96c9910b7e72a83f16d5c6a9f2f34a -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -422,8 +422,8 @@
.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:12px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:3px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}
.dropdown-menu .divider{height:1px;margin:7.5px 0;overflow:hidden;background-color:#e5e5e5}
.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}
-.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#fff;background-color:#00f}
-.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#00f}
+.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#fff;background-color:#303030}
+.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#303030}
.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}
.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:not-allowed}
.open>.dropdown-menu{display:block}
@@ -513,7 +513,7 @@
@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:3px 3px 0 0} .nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}
.nav-pills>li{float:left}.nav-pills>li>a{border-radius:5px}
.nav-pills>li+li{margin-left:2px}
-.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#00f}
+.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#303030}
.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}
.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}
@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}
@@ -659,8 +659,8 @@
.list-group-item>.badge+.badge{margin-right:5px}
a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}
a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}
-.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#00f;border-color:#00f}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading{color:inherit}
-.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#ccf}
+.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#303030;border-color:#303030}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading{color:inherit}
+.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#969696}
.list-group-item-heading{margin-top:0;margin-bottom:5px}
.list-group-item-text{margin-bottom:0;line-height:1.3}
.panel{margin-bottom:17px;background-color:#fff;border:1px solid transparent;border-radius:3px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}
diff -r 6cf5d0cbaf96c9910b7e72a83f16d5c6a9f2f34a -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b static/style/src/less/theme/blue.less
--- a/static/style/src/less/theme/blue.less
+++ b/static/style/src/less/theme/blue.less
@@ -11,6 +11,7 @@
@table-border-color: darken(@table-heading-bg,20%);
@link-color: #303030;
+@component-active-bg: @link-color;
@brand-primary: blue;
https://bitbucket.org/galaxy/galaxy-central/commits/47798b37aed0/
Changeset: 47798b37aed0
User: james_taylor
Date: 2013-09-17 21:18:51
Summary: Fix close/delete icons in workflow editor.
Affected #: 3 files
diff -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b -r 47798b37aed096b344c43c6796b7aae27ef11e90 static/scripts/galaxy.workflow_editor.canvas.js
--- a/static/scripts/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/galaxy.workflow_editor.canvas.js
@@ -199,8 +199,8 @@
.css( { display: 'none' } )
.appendTo( "body" )
.append(
- $("<div class='buttons'></div>").append(
- $("<img/>").attr("src", galaxy_config.root + 'static/images/delete_icon.png').click( function() {
+ $("<div class='button'></div>").append(
+ $("<div/>").addClass("fa-icon-button fa-icon-remove").click( function() {
$.each( terminal.connectors, function( _, x ) {
if (x) {
x.destroy();
@@ -859,12 +859,9 @@
// Fix width to computed width
// Now add floats
var buttons = $("<div class='buttons' style='float: right;'></div>");
- buttons.append( $("<img/>").attr("src", galaxy_config.root + 'static/images/delete_icon.png').click( function( e ) {
+ buttons.append( $("<div>").addClass("fa-icon-button fa-icon-remove").click( function( e ) {
node.destroy();
- } ).hover(
- function() { $(this).attr( "src", galaxy_config.root + "static/images/delete_icon_dark.png" ); },
- function() { $(this).attr( "src", galaxy_config.root + "static/images/delete_icon.png" ); }
- ) );
+ }));
// Place inside container
f.appendTo( "#canvas-container" );
// Position in container
diff -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b -r 47798b37aed096b344c43c6796b7aae27ef11e90 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1362,6 +1362,7 @@
.text-content th,.text-content td{border-bottom:1px solid #ddd;border-right:1px solid #ccc}
.text-content th,.text-content td{padding:.8em}
.icon-button{width:16px;height:16px;display:block;float:left;margin-left:2px;text-indent:20px;background-repeat:no-repeat;background-position:0px 0px;padding:0}
+.fa-icon-button{text-align:center;text-decoration:none;display:inline-block;cursor:pointer;width:16px;height:16px;line-height:8px}.fa-icon-button:hover{color:maroon;-webkit-transition:color .25s linear;transition:color .25s linear}
.editable-text{cursor:pointer}
.editable-text:hover{cursor:text;border:dotted #999999 1px}
.icon-button.multiinput{background:url(../images/documents-stack.png) no-repeat;cursor:pointer;float:none;display:inline-block;margin-left:10px}
diff -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b -r 47798b37aed096b344c43c6796b7aae27ef11e90 static/style/src/less/base.less
--- a/static/style/src/less/base.less
+++ b/static/style/src/less/base.less
@@ -1339,6 +1339,21 @@
padding: 0;
}
+.fa-icon-button {
+ text-align: center;
+ text-decoration: none;
+ display: inline-block;
+ cursor: pointer;
+ width: 16px;
+ height: 16px;
+ line-height: 8px;
+ // Fade to maroon on hover
+ &:hover {
+ color: maroon;
+ .transition(color .25s linear);
+ }
+}
+
.editable-text {
cursor:pointer;
}
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: MetadataFile shouldn't attempt to create by default without checking exists() first.
by commits-noreply@bitbucket.org 17 Sep '13
by commits-noreply@bitbucket.org 17 Sep '13
17 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6cf5d0cbaf96/
Changeset: 6cf5d0cbaf96
User: dannon
Date: 2013-09-17 20:56:56
Summary: MetadataFile shouldn't attempt to create by default without checking exists() first.
Affected #: 1 file
diff -r 96a2ab47b882690df5a2a962d3689474e4312e3a -r 6cf5d0cbaf96c9910b7e72a83f16d5c6a9f2f34a lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2416,7 +2416,8 @@
da = self.history_dataset or self.library_dataset
if self.object_store_id is None and da is not None:
self.object_store_id = da.dataset.object_store_id
- da.dataset.object_store.create( self, extra_dir='_metadata_files', extra_dir_at_root=True, alt_name="metadata_%d.dat" % self.id )
+ if not da.dataset.object_store.exists( self, extra_dir='_metadata_files', extra_dir_at_root=True, alt_name="metadata_%d.dat" % self.id ):
+ da.dataset.object_store.create( self, extra_dir='_metadata_files', extra_dir_at_root=True, alt_name="metadata_%d.dat" % self.id )
path = da.dataset.object_store.get_filename( self, extra_dir='_metadata_files', extra_dir_at_root=True, alt_name="metadata_%d.dat" % self.id )
return path
except AttributeError:
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: Fix integrated_tool_panel dictionary before writing integrated_tool_panel.xml to keep tools/workflows in multiple sections
by commits-noreply@bitbucket.org 17 Sep '13
by commits-noreply@bitbucket.org 17 Sep '13
17 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/96a2ab47b882/
Changeset: 96a2ab47b882
User: Richard Burhans
Date: 2013-09-17 20:37:36
Summary: Fix integrated_tool_panel dictionary before writing integrated_tool_panel.xml to keep tools/workflows in multiple sections
Affected #: 1 file
diff -r 48fad71361b3075c85c7d365dd52c106cabad73a -r 96a2ab47b882690df5a2a962d3689474e4312e3a lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -154,8 +154,24 @@
# This will cover cases where the Galaxy administrator manually edited one or more of the tool panel
# config files, adding or removing locally developed tools or workflows. The value of integrated_tool_panel
# will be False when things like functional tests are the caller.
+ self.fix_integrated_tool_panel_dict()
self.write_integrated_tool_panel_config_file()
+ def fix_integrated_tool_panel_dict( self ):
+ # HACK: instead of fixing after the fact, I suggest some combination of:
+ # 1) adjusting init_tools() and called methods to get this right
+ # 2) redesigning the code and/or data structure used to read/write integrated_tool_panel.xml
+ for key, value in self.integrated_tool_panel.iteritems():
+ if key.startswith( 'section_' ):
+ for section_key, section_value in value.elems.iteritems():
+ if section_value is None:
+ if section_key.startswith( 'tool_' ):
+ tool_id = section_key[5:]
+ value.elems[section_key] = self.tools_by_id.get( tool_id )
+ elif section_key.startswith( 'workflow_' ):
+ workflow_id = section_key[9:]
+ value.elems[section_key] = self.workflows_by_id.get( workflow_id )
+
def init_tools( self, config_filename ):
"""
Read the configuration file and load each tool. The following tags are currently supported:
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
8 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5196dc5182f6/
Changeset: 5196dc5182f6
Branch: tool_api_submit
User: Kyle Ellrott
Date: 2013-06-27 23:23:12
Summary: Adding 'history' parameter to 'get_initial_value' method calls. This allows api based tool requests to build default parameters without having a fixed history attached to the 'trans' class
Affected #: 3 files
diff -r 63b58d89dedd942ad9842958476dd9d364fe1fe0 -r 5196dc5182f6595b1978cc52359f49547a4a2706 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1814,7 +1814,7 @@
# TODO: Anyway to capture tools that dynamically change their own
# outputs?
return True
- def new_state( self, trans, all_pages=False ):
+ def new_state( self, trans, all_pages=False, history=None ):
"""
Create a new `DefaultToolState` for this tool. It will be initialized
with default values for inputs.
@@ -1828,16 +1828,16 @@
inputs = self.inputs
else:
inputs = self.inputs_by_page[ 0 ]
- self.fill_in_new_state( trans, inputs, state.inputs )
+ self.fill_in_new_state( trans, inputs, state.inputs, history=history )
return state
- def fill_in_new_state( self, trans, inputs, state, context=None ):
+ def fill_in_new_state( self, trans, inputs, state, context=None, history=None ):
"""
Fill in a tool state dictionary with default values for all parameters
in the dictionary `inputs`. Grouping elements are filled in recursively.
"""
context = ExpressionContext( state, context )
for input in inputs.itervalues():
- state[ input.name ] = input.get_initial_value( trans, context )
+ state[ input.name ] = input.get_initial_value( trans, context, history=history )
def get_param_html_map( self, trans, page=0, other_values={} ):
"""
Return a dictionary containing the HTML representation of each
@@ -1900,7 +1900,7 @@
state = DefaultToolState()
state.decode( encoded_state, self, trans.app )
else:
- state = self.new_state( trans )
+ state = self.new_state( trans, history=history )
# This feels a bit like a hack. It allows forcing full processing
# of inputs even when there is no state in the incoming dictionary
# by providing either 'runtool_btn' (the name of the submit button
diff -r 63b58d89dedd942ad9842958476dd9d364fe1fe0 -r 5196dc5182f6595b1978cc52359f49547a4a2706 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -69,13 +69,13 @@
"""
return value
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
"""
Return the starting value of the parameter
"""
return None
- def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used ):
+ def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used, history=None ):
"""
Get the starting value for the parameter, but if fetching from the history, try
to find a value that has not yet been used. already_used is a list of objects that
@@ -83,7 +83,7 @@
if a value has already been chosen from the history. This is to support the capability to
choose each dataset once
"""
- return self.get_initial_value(trans, context);
+ return self.get_initial_value(trans, context, history=history);
def get_required_enctype( self ):
"""
@@ -204,7 +204,7 @@
return form_builder.TextArea( self.name, self.size, value )
else:
return form_builder.TextField( self.name, self.size, value )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.value
class IntegerToolParameter( TextToolParameter ):
@@ -271,7 +271,7 @@
if not value and self.optional:
return None
raise err
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
if self.value:
return int( self.value )
else:
@@ -340,7 +340,7 @@
if not value and self.optional:
return None
raise err
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
try:
return float( self.value )
except:
@@ -383,7 +383,7 @@
return [ 'true' ]
def to_python( self, value, app ):
return ( value == 'True' )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.checked
def to_param_dict_string( self, value, other_values={} ):
if value:
@@ -456,7 +456,7 @@
return value
else:
raise Exception( "FileToolParameter cannot be persisted" )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return None
class FTPFileToolParameter( ToolParameter ):
@@ -495,7 +495,7 @@
return None
elif isinstance( value, unicode ) or isinstance( value, str ) or isinstance( value, list ):
return value
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return None
class HiddenToolParameter( ToolParameter ):
@@ -516,7 +516,7 @@
self.value = elem.get( 'value' )
def get_html_field( self, trans=None, value=None, other_values={} ):
return form_builder.HiddenField( self.name, self.value )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.value
def get_label( self ):
return None
@@ -539,7 +539,7 @@
return url
def get_html_field( self, trans=None, value=None, other_values={} ):
return form_builder.HiddenField( self.name, self.get_value( trans ) )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.value
def get_label( self ):
# BaseURLToolParameters are ultimately "hidden" parameters
@@ -805,7 +805,7 @@
return True
# Dynamic, but all dependenceis are known and have values
return False
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
# More working around dynamic options for workflow
if self.need_late_validation( trans, context ):
# Really the best we can do?
@@ -1035,7 +1035,7 @@
options.append( ( 'c' + col, col, False ) )
return options
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
if self.default_value is not None:
# dataset not ready / in workflow / etc
if self.need_late_validation( trans, context ):
@@ -1315,7 +1315,7 @@
rval = sanitize_param( rval )
return rval
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
def recurse_options( initial_values, options ):
for option in options:
if option['selected']:
@@ -1503,10 +1503,10 @@
field.add_option( "Selection is Optional", 'None', False )
return field
- def get_initial_value( self, trans, context ):
- return self.get_initial_value_from_history_prevent_repeats(trans, context, None);
+ def get_initial_value( self, trans, context, history=None ):
+ return self.get_initial_value_from_history_prevent_repeats(trans, context, None, history=history);
- def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used ):
+ def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used, history=None ):
"""
NOTE: This is wasteful since dynamic options and dataset collection
happens twice (here and when generating HTML).
@@ -1515,7 +1515,8 @@
if trans is None or trans.workflow_building_mode:
return DummyDataset()
assert trans is not None, "DataToolParameter requires a trans"
- history = trans.get_history()
+ if history is None:
+ history = trans.get_history()
assert history is not None, "DataToolParameter requires a history"
if self.optional:
return None
@@ -1687,7 +1688,7 @@
DataToolParameter.__init__( self, tool, elem )
self.value = "None"
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return None
def get_html_field( self, trans=None, value=None, other_values={} ):
diff -r 63b58d89dedd942ad9842958476dd9d364fe1fe0 -r 5196dc5182f6595b1978cc52359f49547a4a2706 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -34,7 +34,7 @@
into the preferred value form.
"""
return value
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
"""
Return the initial state/value for this group
"""
@@ -96,7 +96,7 @@
callback( new_prefix, input, d[input.name], parent = d )
else:
input.visit_inputs( new_prefix, d[input.name], callback )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
rval = []
for i in range( self.default ):
rval_dict = { '__index__': i}
@@ -189,14 +189,14 @@
callback( new_prefix, input, d[input.name], parent = d )
else:
input.visit_inputs( new_prefix, d[input.name], callback )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
d_type = self.get_datatype( trans, context )
rval = []
for i, ( composite_name, composite_file ) in enumerate( d_type.writable_files.iteritems() ):
rval_dict = {}
rval_dict['__index__'] = i # create __index__
for input in self.inputs.itervalues():
- rval_dict[ input.name ] = input.get_initial_value( trans, context ) #input.value_to_basic( d[input.name], app )
+ rval_dict[ input.name ] = input.get_initial_value( trans, context, history=history ) #input.value_to_basic( d[input.name], app )
rval.append( rval_dict )
return rval
def get_uploaded_datasets( self, trans, context, override_name = None, override_info = None ):
@@ -476,12 +476,12 @@
callback( prefix, input, value[input.name], parent = value )
else:
input.visit_inputs( prefix, value[input.name], callback )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
# State for a conditional is a plain dictionary.
rval = {}
# Get the default value for the 'test element' and use it
# to determine the current case
- test_value = self.test_param.get_initial_value( trans, context )
+ test_value = self.test_param.get_initial_value( trans, context, history=None )
current_case = self.get_current_case( test_value, trans )
# Store the current case in a special value
rval['__current_case__'] = current_case
@@ -490,7 +490,7 @@
# Fill in state for selected case
child_context = ExpressionContext( rval, context )
for child_input in self.cases[current_case].inputs.itervalues():
- rval[ child_input.name ] = child_input.get_initial_value( trans, child_context )
+ rval[ child_input.name ] = child_input.get_initial_value( trans, child_context, history=None )
return rval
class ConditionalWhen( object ):
https://bitbucket.org/galaxy/galaxy-central/commits/7ac0ed6f42d6/
Changeset: 7ac0ed6f42d6
Branch: tool_api_submit
User: Kyle Ellrott
Date: 2013-06-27 23:58:14
Summary: Removing stray print statement
Affected #: 1 file
diff -r 5196dc5182f6595b1978cc52359f49547a4a2706 -r 7ac0ed6f42d64e24f7bd851193368184a5e28def lib/galaxy/model/migrate/check.py
--- a/lib/galaxy/model/migrate/check.py
+++ b/lib/galaxy/model/migrate/check.py
@@ -44,7 +44,6 @@
# Let this go, it could possibly work with db's we don't support
log.error( "database_connection contains an unknown SQLAlchemy database dialect: %s" % dialect )
# Create engine and metadata
- print url, engine_options
engine = create_engine( url, **engine_options )
meta = MetaData( bind=engine )
# Try to load dataset table
https://bitbucket.org/galaxy/galaxy-central/commits/371e3b451448/
Changeset: 371e3b451448
Branch: tool_api_submit
User: Kyle Ellrott
Date: 2013-06-28 00:52:08
Summary: The /api/tool submit can define inputs in the payload in the format {'id' : <encoded_id>, 'src' : 'hda'}
Affected #: 1 file
diff -r 7ac0ed6f42d64e24f7bd851193368184a5e28def -r 371e3b451448bfb7a70139faafc33072a7d2b468 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -1575,6 +1575,9 @@
rval = [ trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( v ) for v in value ]
elif isinstance( value, trans.app.model.HistoryDatasetAssociation ):
rval = value
+ elif isinstance( value, dict ) and 'src' in value and 'id' in value:
+ if value['src'] == 'hda':
+ rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.app.security.decode_id(value['id']) )
else:
rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( value )
if isinstance( rval, list ):
https://bitbucket.org/galaxy/galaxy-central/commits/abb889f8c5b7/
Changeset: abb889f8c5b7
Branch: tool_api_submit
User: Kyle Ellrott
Date: 2013-07-03 22:38:40
Summary: Adding way for API based tools job submissions to copy library dataset into history
Affected #: 1 file
diff -r 371e3b451448bfb7a70139faafc33072a7d2b468 -r abb889f8c5b75e8b90e8a35617e95ec7c05d28e7 lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -30,10 +30,10 @@
# Read params.
in_panel = util.string_as_bool( kwds.get( 'in_panel', 'True' ) )
trackster = util.string_as_bool( kwds.get( 'trackster', 'False' ) )
-
+
# Create return value.
try:
- return self.app.toolbox.to_dict( trans, in_panel=in_panel, trackster=trackster )
+ return self.app.toolbox.to_dict( trans, in_panel=in_panel, trackster=trackster)
except Exception, exc:
log.error( 'could not convert toolbox to dictionary: %s', str( exc ), exc_info=True )
trans.response.status = 500
@@ -87,6 +87,17 @@
for k, v in payload.iteritems():
if k.startswith("files_"):
inputs[k] = v
+
+ #for inputs that are coming from the Library, copy them into the history
+ input_patch = {}
+ for k, v in inputs.iteritems():
+ if isinstance(v, dict) and v.get('src', '') == 'ldda' and 'id' in v:
+ ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id(v['id']) )
+ if trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), ldda.dataset ):
+ input_patch[k] = ldda.to_history_dataset_association(target_history, add_to_history=True)
+
+ for k, v in input_patch.iteritems():
+ inputs[k] = v
# HACK: add run button so that tool.handle_input will run tool.
inputs['runtool_btn'] = 'Execute'
https://bitbucket.org/galaxy/galaxy-central/commits/d370b6ba1443/
Changeset: d370b6ba1443
User: Kyle Ellrott
Date: 2013-06-27 23:23:12
Summary: Adding 'history' parameter to 'get_initial_value' method calls. This allows api based tool requests to build default parameters without having a fixed history attached to the 'trans' class
Affected #: 3 files
diff -r 44214ff2a8801dea8714b6cfc7f2d7bd6545e229 -r d370b6ba1443adf67390ae8ca7b8d71a9746b3f6 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1852,7 +1852,7 @@
# TODO: Anyway to capture tools that dynamically change their own
# outputs?
return True
- def new_state( self, trans, all_pages=False ):
+ def new_state( self, trans, all_pages=False, history=None ):
"""
Create a new `DefaultToolState` for this tool. It will be initialized
with default values for inputs.
@@ -1866,16 +1866,16 @@
inputs = self.inputs
else:
inputs = self.inputs_by_page[ 0 ]
- self.fill_in_new_state( trans, inputs, state.inputs )
+ self.fill_in_new_state( trans, inputs, state.inputs, history=history )
return state
- def fill_in_new_state( self, trans, inputs, state, context=None ):
+ def fill_in_new_state( self, trans, inputs, state, context=None, history=None ):
"""
Fill in a tool state dictionary with default values for all parameters
in the dictionary `inputs`. Grouping elements are filled in recursively.
"""
context = ExpressionContext( state, context )
for input in inputs.itervalues():
- state[ input.name ] = input.get_initial_value( trans, context )
+ state[ input.name ] = input.get_initial_value( trans, context, history=history )
def get_param_html_map( self, trans, page=0, other_values={} ):
"""
Return a dictionary containing the HTML representation of each
@@ -1938,7 +1938,7 @@
state = DefaultToolState()
state.decode( encoded_state, self, trans.app )
else:
- state = self.new_state( trans )
+ state = self.new_state( trans, history=history )
# This feels a bit like a hack. It allows forcing full processing
# of inputs even when there is no state in the incoming dictionary
# by providing either 'runtool_btn' (the name of the submit button
diff -r 44214ff2a8801dea8714b6cfc7f2d7bd6545e229 -r d370b6ba1443adf67390ae8ca7b8d71a9746b3f6 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -72,13 +72,13 @@
"""
return value
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
"""
Return the starting value of the parameter
"""
return None
- def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used ):
+ def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used, history=None ):
"""
Get the starting value for the parameter, but if fetching from the history, try
to find a value that has not yet been used. already_used is a list of objects that
@@ -86,7 +86,7 @@
if a value has already been chosen from the history. This is to support the capability to
choose each dataset once
"""
- return self.get_initial_value(trans, context);
+ return self.get_initial_value(trans, context, history=history);
def get_required_enctype( self ):
"""
@@ -216,7 +216,7 @@
return form_builder.TextArea( self.name, self.size, value )
else:
return form_builder.TextField( self.name, self.size, value )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.value
class IntegerToolParameter( TextToolParameter ):
@@ -286,7 +286,7 @@
if not value and self.optional:
return None
raise err
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
if self.value:
return int( self.value )
else:
@@ -358,7 +358,7 @@
if not value and self.optional:
return None
raise err
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
try:
return float( self.value )
except:
@@ -401,7 +401,7 @@
return [ 'true' ]
def to_python( self, value, app ):
return ( value == 'True' )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.checked
def to_param_dict_string( self, value, other_values={} ):
if value:
@@ -474,7 +474,7 @@
return value
else:
raise Exception( "FileToolParameter cannot be persisted" )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return None
class FTPFileToolParameter( ToolParameter ):
@@ -513,7 +513,7 @@
return None
elif isinstance( value, unicode ) or isinstance( value, str ) or isinstance( value, list ):
return value
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return None
class HiddenToolParameter( ToolParameter ):
@@ -534,7 +534,7 @@
self.value = elem.get( 'value' )
def get_html_field( self, trans=None, value=None, other_values={} ):
return form_builder.HiddenField( self.name, self.value )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.value
def get_label( self ):
return None
@@ -557,7 +557,7 @@
return url
def get_html_field( self, trans=None, value=None, other_values={} ):
return form_builder.HiddenField( self.name, self.get_value( trans ) )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.value
def get_label( self ):
# BaseURLToolParameters are ultimately "hidden" parameters
@@ -826,7 +826,7 @@
return True
# Dynamic, but all dependenceis are known and have values
return False
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
# More working around dynamic options for workflow
if self.need_late_validation( trans, context ):
# Really the best we can do?
@@ -1074,7 +1074,7 @@
options.append( ( 'c' + col, col, False ) )
return options
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
if self.default_value is not None:
# dataset not ready / in workflow / etc
if self.need_late_validation( trans, context ):
@@ -1353,8 +1353,7 @@
else:
rval = sanitize_param( rval )
return rval
-
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
def recurse_options( initial_values, options ):
for option in options:
if option['selected']:
@@ -1542,10 +1541,10 @@
field.add_option( "Selection is Optional", 'None', False )
return field
- def get_initial_value( self, trans, context ):
- return self.get_initial_value_from_history_prevent_repeats(trans, context, None);
+ def get_initial_value( self, trans, context, history=None ):
+ return self.get_initial_value_from_history_prevent_repeats(trans, context, None, history=history);
- def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used ):
+ def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used, history=None ):
"""
NOTE: This is wasteful since dynamic options and dataset collection
happens twice (here and when generating HTML).
@@ -1554,7 +1553,8 @@
if trans is None or trans.workflow_building_mode or trans.webapp.name == 'tool_shed':
return DummyDataset()
assert trans is not None, "DataToolParameter requires a trans"
- history = trans.get_history()
+ if history is None:
+ history = trans.get_history()
assert history is not None, "DataToolParameter requires a history"
if self.optional:
return None
@@ -1727,7 +1727,7 @@
self.value = "None"
self.type = "hidden_data"
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return None
def get_html_field( self, trans=None, value=None, other_values={} ):
diff -r 44214ff2a8801dea8714b6cfc7f2d7bd6545e229 -r d370b6ba1443adf67390ae8ca7b8d71a9746b3f6 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -41,8 +41,7 @@
into the preferred value form.
"""
return value
-
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
"""
Return the initial state/value for this group
"""
@@ -109,7 +108,7 @@
callback( new_prefix, input, d[input.name], parent = d )
else:
input.visit_inputs( new_prefix, d[input.name], callback )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
rval = []
for i in range( self.default ):
rval_dict = { '__index__': i}
@@ -202,14 +201,14 @@
callback( new_prefix, input, d[input.name], parent = d )
else:
input.visit_inputs( new_prefix, d[input.name], callback )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
d_type = self.get_datatype( trans, context )
rval = []
for i, ( composite_name, composite_file ) in enumerate( d_type.writable_files.iteritems() ):
rval_dict = {}
rval_dict['__index__'] = i # create __index__
for input in self.inputs.itervalues():
- rval_dict[ input.name ] = input.get_initial_value( trans, context ) #input.value_to_basic( d[input.name], app )
+ rval_dict[ input.name ] = input.get_initial_value( trans, context, history=history ) #input.value_to_basic( d[input.name], app )
rval.append( rval_dict )
return rval
def get_uploaded_datasets( self, trans, context, override_name = None, override_info = None ):
@@ -489,12 +488,12 @@
callback( prefix, input, value[input.name], parent = value )
else:
input.visit_inputs( prefix, value[input.name], callback )
- def get_initial_value( self, trans, context ):
- # State for a conditional is a plain dictionary.
+ def get_initial_value( self, trans, context, history=None ):
+ # State for a conditional is a plain dictionary.
rval = {}
# Get the default value for the 'test element' and use it
# to determine the current case
- test_value = self.test_param.get_initial_value( trans, context )
+ test_value = self.test_param.get_initial_value( trans, context, history=None )
current_case = self.get_current_case( test_value, trans )
# Store the current case in a special value
rval['__current_case__'] = current_case
@@ -503,7 +502,7 @@
# Fill in state for selected case
child_context = ExpressionContext( rval, context )
for child_input in self.cases[current_case].inputs.itervalues():
- rval[ child_input.name ] = child_input.get_initial_value( trans, child_context )
+ rval[ child_input.name ] = child_input.get_initial_value( trans, child_context, history=None )
return rval
class ConditionalWhen( object ):
https://bitbucket.org/galaxy/galaxy-central/commits/3e086bca9f63/
Changeset: 3e086bca9f63
User: Kyle Ellrott
Date: 2013-06-28 00:52:08
Summary: The /api/tool submit can define inputs in the payload in the format {'id' : <encoded_id>, 'src' : 'hda'}
Affected #: 1 file
diff -r d370b6ba1443adf67390ae8ca7b8d71a9746b3f6 -r 3e086bca9f63e270da8cbd7e65feb0b22a0ae085 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -1613,6 +1613,9 @@
rval = [ trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( v ) for v in value ]
elif isinstance( value, trans.app.model.HistoryDatasetAssociation ):
rval = value
+ elif isinstance( value, dict ) and 'src' in value and 'id' in value:
+ if value['src'] == 'hda':
+ rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.app.security.decode_id(value['id']) )
else:
rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( value )
if isinstance( rval, list ):
https://bitbucket.org/galaxy/galaxy-central/commits/48fad71361b3/
Changeset: 48fad71361b3
User: Kyle Ellrott
Date: 2013-07-03 22:38:40
Summary: Adding way for API based tools job submissions to copy library dataset into history
Affected #: 1 file
diff -r 3e086bca9f63e270da8cbd7e65feb0b22a0ae085 -r 48fad71361b3075c85c7d365dd52c106cabad73a lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -32,7 +32,7 @@
# Create return value.
try:
- return self.app.toolbox.to_dict( trans, in_panel=in_panel, trackster=trackster )
+ return self.app.toolbox.to_dict( trans, in_panel=in_panel, trackster=trackster)
except Exception, exc:
log.error( 'could not convert toolbox to dictionary: %s', str( exc ), exc_info=True )
trans.response.status = 500
@@ -86,6 +86,17 @@
for k, v in payload.iteritems():
if k.startswith("files_"):
inputs[k] = v
+
+ #for inputs that are coming from the Library, copy them into the history
+ input_patch = {}
+ for k, v in inputs.iteritems():
+ if isinstance(v, dict) and v.get('src', '') == 'ldda' and 'id' in v:
+ ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id(v['id']) )
+ if trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), ldda.dataset ):
+ input_patch[k] = ldda.to_history_dataset_association(target_history, add_to_history=True)
+
+ for k, v in input_patch.iteritems():
+ inputs[k] = v
# HACK: add run button so that tool.handle_input will run tool.
inputs['runtool_btn'] = 'Execute'
https://bitbucket.org/galaxy/galaxy-central/commits/e3e7b034cb0b/
Changeset: e3e7b034cb0b
Branch: tool_api_submit
User: carlfeberhard
Date: 2013-09-16 21:45:04
Summary: Close branch tool_api_submit
Affected #: 0 files
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