galaxy-commits
Threads by month
- ----- 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
September 2013
- 1 participants
- 149 discussions
commit/galaxy-central: guerler: Ensure availability of window.Galaxy variable
by commits-noreply@bitbucket.org 11 Sep '13
by commits-noreply@bitbucket.org 11 Sep '13
11 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/228f1b4066be/
Changeset: 228f1b4066be
User: guerler
Date: 2013-09-11 18:15:13
Summary: Ensure availability of window.Galaxy variable
Affected #: 2 files
diff -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 -r 228f1b4066be9fc49f6f07ff6867566836134c67 templates/base/base_panels.mako
--- a/templates/base/base_panels.mako
+++ b/templates/base/base_panels.mako
@@ -81,6 +81,9 @@
if (window != window.top)
$('<link href="' + galaxy_config.root + 'static/style/galaxy.frame.masthead.css" rel="stylesheet">').appendTo('head');
+ // start a Galaxy namespace for objects created
+ window.Galaxy = window.Galaxy || {};
+
// console protection
window.console = window.console || {
log : function(){},
diff -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 -r 228f1b4066be9fc49f6f07ff6867566836134c67 templates/webapps/galaxy/galaxy.panels.mako
--- a/templates/webapps/galaxy/galaxy.panels.mako
+++ b/templates/webapps/galaxy/galaxy.panels.mako
@@ -58,6 +58,9 @@
## make sure console exists
<script type="text/javascript">
+ // start a Galaxy namespace for objects created
+ window.Galaxy = window.Galaxy || {};
+
// console protection
window.console = window.console ||
{
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, new js-based modal window and dynamic icon menu for master head
by commits-noreply@bitbucket.org 11 Sep '13
by commits-noreply@bitbucket.org 11 Sep '13
11 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/99cc1ee095c3/
Changeset: 99cc1ee095c3
User: guerler
Date: 2013-09-11 17:25:00
Summary: Drag&drop multiple file upload, new js-based modal window and dynamic icon menu for master head
Affected #: 26 files
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 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
@@ -6,7 +6,9 @@
from galaxy.web.base.controller import BaseAPIController, url_for
from galaxy.web.base.controller import UsesHistoryDatasetAssociationMixin, UsesHistoryMixin
from galaxy.web.base.controller import UsesLibraryMixin, UsesLibraryMixinItems
+from galaxy.datatypes import sniff
+import os
import logging
log = logging.getLogger( __name__ )
@@ -160,42 +162,118 @@
:param history_id: encoded id string of the new HDA's History
:type payload: dict
:param payload: dictionary structure containing::
- 'from_ld_id': the encoded id of the LibraryDataset to copy
-
+ copy from library:
+ 'source' = 'library'
+ 'content' = [the encoded id from the library dataset]
+
+ copy from url:
+ 'source' = 'url'
+ 'content' = [the url of the dataset]
+
+ copy from file:
+ 'source' = 'upload'
+ 'content' = [the uploaded file content]
:rtype: dict
:returns: dictionary containing detailed information for the new HDA
"""
+
#TODO: copy existing, accessible hda - dataset controller, copy_datasets
#TODO: convert existing, accessible hda - model.DatasetInstance(or hda.datatype).get_converter_types
- from_ld_id = payload.get( 'from_ld_id', None )
+
+ # check parameters
+ source = payload.get('source', None)
+ content = payload.get('content', None)
+ if source not in ['library', 'url', 'upload']:
+ trans.response.status = 400
+ return "history_contents:create() : Please define the source ['library', 'url' or 'upload'] and the content."
+
+ # retrieve history
try:
history = self.get_history( trans, history_id, check_ownership=True, check_accessible=False )
except Exception, e:
- #TODO: no way to tell if it failed bc of perms or other (all MessageExceptions)
+ # no way to tell if it failed bc of perms or other (all MessageExceptions)
trans.response.status = 500
return str( e )
- if from_ld_id:
+ # copy from library dataset
+ if source == 'library':
+
+ # get library data set
try:
- ld = self.get_library_dataset( trans, from_ld_id, check_ownership=False, check_accessible=False )
+ ld = self.get_library_dataset( trans, content, check_ownership=False, check_accessible=False )
assert type( ld ) is trans.app.model.LibraryDataset, (
- "Library content id ( %s ) is not a dataset" % from_ld_id )
-
+ "Library content id ( %s ) is not a dataset" % content )
except AssertionError, e:
trans.response.status = 400
return str( e )
-
except Exception, e:
return str( e )
+ # insert into history
hda = ld.library_dataset_dataset_association.to_history_dataset_association( history, add_to_history=True )
trans.sa_session.flush()
return hda.to_dict()
+ # copy from upload
+ if source == 'upload':
+
+ # get upload specific features
+ dbkey = payload.get('dbkey', None)
+ extension = payload.get('extension', None)
+ space_to_tabs = payload.get('space_to_tabs', False)
+
+ # check for filename
+ if content.filename is None:
+ trans.response.status = 400
+ return "history_contents:create() : The contents parameter needs to contain the uploaded file content."
+
+ # create a dataset
+ dataset = trans.app.model.Dataset()
+ trans.sa_session.add(dataset)
+ trans.sa_session.flush()
+
+ # get file destination
+ file_destination = dataset.get_file_name()
+
+ # save file locally
+ fn = os.path.basename(content.filename)
+ open(file_destination, 'wb').write(content.file.read())
+
+ # log
+ log.info ('The file "' + fn + '" was uploaded successfully.')
+
+ # replace separation with tabs
+ if space_to_tabs:
+ log.info ('Replacing spaces with tabs.')
+ sniff.convert_newlines_sep2tabs(file_destination)
+
+ # guess extension
+ if extension is None:
+ log.info ('Guessing extension.')
+ extension = sniff.guess_ext(file_destination)
+
+ # create hda
+ hda = trans.app.model.HistoryDatasetAssociation(dataset = dataset, name = content.filename,
+ extension = extension, dbkey = dbkey, history = history, sa_session = trans.sa_session)
+
+ # add status ok
+ hda.state = hda.states.OK
+
+ # add dataset to history
+ history.add_dataset(hda, genome_build = dbkey)
+ permissions = trans.app.security_agent.history_get_default_permissions( history )
+ trans.app.security_agent.set_all_dataset_permissions( hda.dataset, permissions )
+
+ # add to session
+ trans.sa_session.add(hda)
+ trans.sa_session.flush()
+
+ # get name
+ return hda.to_dict()
else:
- # TODO: implement other "upload" methods here.
+ # other options
trans.response.status = 501
- return "Not implemented."
+ return
@web.expose_api
def update( self, trans, history_id, id, payload, **kwd ):
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/galaxy.frame.js
--- a/static/scripts/galaxy.frame.js
+++ b/static/scripts/galaxy.frame.js
@@ -3,16 +3,13 @@
*/
// dependencies
-define(["utils/galaxy.css", "libs/backbone/backbone-relational"], function(css) {
+define(["utils/galaxy.css", "galaxy.master", "libs/backbone/backbone-relational"], function(css, mod_master) {
// frame manager
var GalaxyFrameManager = Backbone.View.extend(
{
// base element
- el: '#everything',
-
- // master head
- el_header : '#masthead',
+ el_main: '#everything',
// defaults inputs
options:
@@ -70,9 +67,41 @@
// frame active/disabled
active: false,
+ // button active
+ button_active: null,
+
+ // button load
+ button_load : null,
+
// initialize
initialize : function(options)
{
+ // add to master menu
+ var self = this;
+
+ // add activate icon
+ this.button_active = new mod_master.GalaxyMasterIcon (
+ {
+ icon : 'fa-icon-th',
+ tooltip : 'Enable/Disable Scratchbook',
+ on_click : function(e) { self.event_panel_active(e) }
+ });
+
+ // add to master
+ Galaxy.master.append(this.button_active);
+
+ // add load icon
+ this.button_load = new mod_master.GalaxyMasterIcon (
+ {
+ icon : 'fa-icon-eye-open',
+ tooltip : 'Show/Hide Scratchbook',
+ on_click : function(e) { self.event_panel_load(e) },
+ with_number : true
+ });
+
+ // add to master
+ Galaxy.master.append(this.button_load);
+
// load required css files
css.load_file("static/style/galaxy.frame.css");
@@ -89,8 +118,8 @@
// load menu buttons
$(this.el).append(this.frame_template_menu());
- // load load button
- $(this.el_header).append(this.frame_template_header());
+ // load to main frame
+ $(this.el_main).append($(this.el));
//
// define shadow frame
@@ -117,19 +146,13 @@
// initialize panel
this.panel_refresh();
-
- // link events
- this.event_initialize();
-
- // add
- $(".galaxy-frame-active").tooltip({title: "Enable/Disable Scratchbook"});
- $(".galaxy-frame-load").tooltip({title: "Show/Hide Scratchbook"});
-
+
// catch window resize event
var self = this;
$(window).resize(function ()
{
- self.panel_refresh();
+ if (self.visible)
+ self.panel_refresh();
});
// catch window close
@@ -140,12 +163,6 @@
};
},
- // check for mobile devices
- is_mobile: function()
- {
- return navigator.userAgent.match(/mobile|(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i);
- },
-
/*
EVENT HANDLING
*/
@@ -159,42 +176,22 @@
},
// events
- event_initialize: function()
+ events:
{
- /*if (!this.is_mobile())
- {*/
- this.events = {
- // global page events
- 'mousemove' : 'event_frame_mouse_move',
- 'mouseup' : 'event_frame_mouse_up',
- 'mouseleave' : 'event_frame_mouse_up',
- 'mousewheel' : 'event_panel_scroll',
- 'DOMMouseScroll' : 'event_panel_scroll',
+ // global frame events
+ 'mousemove' : 'event_frame_mouse_move',
+ 'mouseup' : 'event_frame_mouse_up',
+ 'mouseleave' : 'event_frame_mouse_up',
+ 'mousewheel' : 'event_panel_scroll',
+ 'DOMMouseScroll' : 'event_panel_scroll',
- // events fixed to elements
- 'mousedown .galaxy-frame' : 'event_frame_mouse_down',
- 'mousedown .galaxy-frame-active' : 'event_panel_active',
- 'mousedown .galaxy-frame-load' : 'event_panel_load',
- 'mousedown .galaxy-frame-background' : 'event_panel_load',
- 'mousedown .galaxy-frame-scroll-up' : 'event_panel_scroll_up',
- 'mousedown .galaxy-frame-scroll-down' : 'event_panel_scroll_down',
- 'mousedown .f-close' : 'event_frame_close',
- 'mousedown .f-pin' : 'event_frame_lock'
- };
- /*} else {
- this.events = {
- 'touchstart' : 'event_frame_mouse_down',
- 'touchstart .f-close' : 'event_frame_close',
- 'touchstart .f-pin' : 'event_frame_lock',
- 'touchmove' : 'event_frame_mouse_move',
- 'touchend' : 'event_frame_mouse_up',
- 'touchleave' : 'event_mouse_up',
- 'touchstart .galaxy-frame-load' : 'event_frame_load'
- };
- };*/
-
- // delegate
- this.delegateEvents(this.events);
+ // events fixed to elements
+ 'mousedown .galaxy-frame' : 'event_frame_mouse_down',
+ 'mousedown .galaxy-frame-background' : 'event_panel_load',
+ 'mousedown .galaxy-frame-scroll-up' : 'event_panel_scroll_up',
+ 'mousedown .galaxy-frame-scroll-down' : 'event_panel_scroll_down',
+ 'mousedown .f-close' : 'event_frame_close',
+ 'mousedown .f-pin' : 'event_frame_lock'
},
// drag start
@@ -390,7 +387,7 @@
frame.grid_lock = false;
// remove class
- $(frame.id).find('.f-pin').removeClass('f-toggle');
+ $(frame.id).find('.f-pin').removeClass('galaxy-toggle');
$(frame.id).find('.f-header').removeClass('f-not-allowed');
$(frame.id).find('.f-title').removeClass('f-not-allowed');
$(frame.id).find('.f-resize').show();
@@ -400,7 +397,7 @@
frame.grid_lock = true;
// add class
- $(frame.id).find('.f-pin').addClass('f-toggle');
+ $(frame.id).find('.f-pin').addClass('galaxy-toggle');
$(frame.id).find('.f-header').addClass('f-not-allowed');
$(frame.id).find('.f-title').addClass('f-not-allowed');
$(frame.id).find('.f-resize').hide();
@@ -414,9 +411,6 @@
// check
if (this.event.type !== null)
return;
-
- // prevent
- e.preventDefault();
// load panel
this.panel_show_hide();
@@ -428,9 +422,6 @@
// check
if (this.event.type !== null)
return;
-
- // prevent
- e.preventDefault();
// load panel
this.panel_active_disable();
@@ -640,13 +631,13 @@
menu_refresh: function()
{
// update on screen counter
- $(".galaxy-frame-load .number").text(this.frame_counter);
-
+ this.button_load.number(this.frame_counter);
+
// check
if(this.frame_counter == 0)
- $(".galaxy-frame-load").hide();
+ this.button_load.hide();
else
- $(".galaxy-frame-load").show();
+ this.button_load.show();
// scroll up possible?
if (this.top == this.options.top_min)
@@ -733,8 +724,8 @@
$(".galaxy-frame").fadeOut('fast');
// add class
- $(".galaxy-frame-load .icon").addClass("fa-icon-eye-close");
- $(".galaxy-frame-load .icon").removeClass("fa-icon-eye-open");
+ this.button_load.icon("fa-icon-eye-close");
+ this.button_load.untoggle();
// hide background
$(".galaxy-frame-background").hide();
@@ -749,8 +740,8 @@
$(".galaxy-frame").fadeIn('fast');
// add class
- $(".galaxy-frame-load .icon").addClass("fa-icon-eye-open");
- $(".galaxy-frame-load .icon").removeClass("fa-icon-eye-close");
+ this.button_load.icon("fa-icon-eye-open");
+ this.button_load.toggle();
// hide shadow
$(this.galaxy_frame_shadow.id).hide();
@@ -758,8 +749,8 @@
// show background
$(".galaxy-frame-background").show();
- // show menu
- this.menu_refresh();
+ // show panel
+ this.panel_refresh();
}
},
@@ -771,19 +762,19 @@
{
// disable
this.active = false;
-
- // untoggle
- $(".galaxy-frame-active .icon").removeClass("f-toggle");
+ // toggle
+ this.button_active.untoggle();
+
// hide panel
if (this.visible)
this.panel_show_hide();
} else {
// activate
this.active = true;
-
- // toggle
- $(".galaxy-frame-active .icon").addClass("f-toggle");
+
+ // untoggle
+ this.button_active.toggle();
}
},
@@ -1053,23 +1044,23 @@
content = '<iframe scrolling="auto" class="f-iframe" src="' + content + '"></iframe>';
// load template
- return '<div id="' + id + '" class="galaxy-frame f-corner">' +
- '<div class="f-header f-corner">' +
+ return '<div id="' + id + '" class="galaxy-frame galaxy-corner">' +
+ '<div class="f-header galaxy-corner">' +
'<span class="f-title">' + title + '</span>' +
'<span class="f-icon f-pin fa-icon-pushpin"></span>' +
'<span class="f-icon f-close fa-icon-trash"></span>' +
'</div>' +
- '<div class="f-content f-corner">' + content +
+ '<div class="f-content galaxy-corner">' + content +
'<div class="f-cover"></div>' +
'</div>' +
- '<span class="f-resize f-icon f-corner fa-icon-resize-full"></span>' +
+ '<span class="f-resize f-icon galaxy-corner fa-icon-resize-full"></span>' +
'</div>';
},
// fill shadow template
frame_template_shadow: function(id)
{
- return '<div id="' + id + '" class="galaxy-frame-shadow f-corner"></div>';
+ return '<div id="' + id + '" class="galaxy-frame-shadow galaxy-corner"></div>';
},
// fill background template in order to cover underlying iframes
@@ -1078,18 +1069,6 @@
return '<div class="galaxy-frame-background"></div>';
},
- // fill load button template
- frame_template_header: function()
- {
- return '<div class="galaxy-frame-load f-corner">' +
- '<div class="number f-corner">0</div>' +
- '<div class="icon fa-icon-2x"></div>' +
- '</div>' +
- '<div class="galaxy-frame-active f-corner" style="position: absolute; top: 8px;">' +
- '<div class="icon fa-icon-2x fa-icon-th"></div>' +
- '</div>';
- },
-
// fill menu button template
frame_template_menu: function()
{
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/galaxy.master.js
--- /dev/null
+++ b/static/scripts/galaxy.master.js
@@ -0,0 +1,151 @@
+/*
+ galaxy master v1.0
+*/
+
+// dependencies
+define(["utils/galaxy.css", "libs/backbone/backbone-relational"], function(css) {
+
+// master
+var GalaxyMaster = Backbone.View.extend(
+{
+ // base element
+ el_master: '.masthead-inner',
+
+ // initialize
+ initialize : function(options)
+ {
+ // load required css files
+ css.load_file("static/style/galaxy.master.css");
+
+ // define this element
+ this.setElement($(this.template()));
+
+ // append to master
+ $(this.el_master).append($(this.el));
+ },
+
+ // prevent default
+ events:
+ {
+ 'mousedown' : function(e) {e.preventDefault()}
+ },
+
+ // adds and displays a new frame/window
+ append : function(item)
+ {
+ $(this.el).append($(item.el));
+ },
+
+ // adds and displays a new frame/window
+ prepend : function(item)
+ {
+ $(this.el).prepend($(item.el));
+ },
+
+ /*
+ HTML TEMPLATES
+ */
+
+ // fill regular modal template
+ template: function()
+ {
+ return '<div id="galaxy-master" class="galaxy-master"></div>';
+ }
+});
+
+// frame manager
+var GalaxyMasterIcon = Backbone.View.extend(
+{
+ // icon options
+ options:
+ {
+ id : "galaxy-icon",
+ icon : "fa-icon-cog",
+ tooltip : "galaxy-icon",
+ with_number : false,
+ on_click : function() { alert ('clicked') },
+ visible : true
+ },
+
+ // initialize
+ initialize: function (options)
+ {
+ // read in defaults
+ if (options)
+ this.options = _.defaults(options, this.options);
+
+ // add template for icon
+ this.setElement($(this.template(this.options)));
+
+ // configure icon
+ var self = this;
+ $(this.el).find('.icon').tooltip({title: this.options.tooltip})
+ .on('click', self.options.on_click);
+
+ // visiblity
+ if (!this.options.visible)
+ this.hide();
+ },
+
+ // show
+ show: function()
+ {
+ $(this.el).css({visibility : 'visible'});
+ },
+
+ // show
+ hide: function()
+ {
+ $(this.el).css({visibility : 'hidden'});
+ },
+
+ // switch icon
+ icon: function (new_icon)
+ {
+ // update icon class
+ $(this.el).find('.icon').removeClass(this.options.icon)
+ .addClass(new_icon);
+
+ // update icon
+ this.options.icon = new_icon;
+ },
+
+ // toggle
+ toggle: function()
+ {
+ $(this.el).addClass('galaxy-toggle');
+ },
+
+ // untoggle
+ untoggle: function()
+ {
+ $(this.el).removeClass('galaxy-toggle');
+ },
+
+ // set/get number
+ number: function(new_number)
+ {
+ $(this.el).find('.number').text(new_number);
+ },
+
+ // fill template icon
+ template: function (options)
+ {
+ var tmpl = '<div id=' + options.id + ' class="galaxy-icon galaxy-corner">' +
+ '<div class="icon fa-icon-2x ' + options.icon + '"></div>';
+ if (options.with_number)
+ tmpl+= '<div class="number galaxy-corner"></div>';
+ tmpl += '</div>';
+
+ // return template
+ return tmpl;
+ }
+});
+
+// return
+return {
+ GalaxyMaster: GalaxyMaster,
+ GalaxyMasterIcon : GalaxyMasterIcon
+};
+
+});
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/galaxy.modal.js
--- /dev/null
+++ b/static/scripts/galaxy.modal.js
@@ -0,0 +1,122 @@
+/*
+ galaxy modal v1.0
+*/
+
+// dependencies
+define(["utils/galaxy.css", "libs/backbone/backbone-relational"], function(css) {
+
+// frame manager
+var GalaxyModal = Backbone.View.extend(
+{
+ // base element
+ el_main: '#everything',
+
+ // defaults inputs
+ options:
+ {
+ title : "galaxy-modal",
+ body : "No content available."
+ },
+
+ // initialize
+ initialize : function(options)
+ {
+ // load required css files
+ css.load_file("static/style/galaxy.modal.css");
+
+ // read in defaults
+ if (!options)
+ options = this.options;
+ else
+ options = _.defaults(options, this.options);
+
+ // create element
+ this.setElement(this.template(options.title, options.body));
+
+ // append template
+ $(this.el_main).append($(this.el));
+
+ // link elements
+ var footer = (this.$el).find('.footer');
+
+ // append buttons
+ var self = this;
+ if (options.buttons)
+ {
+ // link functions
+ $.each(options.buttons, function(name, value)
+ {
+ footer.append($('<button></button>').text(name).click(value)).append(" ");
+ });
+ } else
+ // default close button
+ footer.append($('<button></button>').text('Close').click(function() { self.hide() })).append(" ");
+
+ // hide
+ $(this.el).hide();
+ },
+
+ /*
+ EVENT HANDLING
+ */
+
+ // event
+ events:
+ {
+ 'mousedown .dialog' : 'event_default',
+ 'mousedown .background' : 'hide'
+ },
+
+ // drag
+ event_default: function (e)
+ {
+ e.preventDefault();
+ },
+
+ // adds and displays a new frame/window
+ show: function()
+ {
+ // fade out
+ this.$el.fadeIn('fast');
+ },
+
+ // hide modal
+ hide: function()
+ {
+ // fade out
+ this.$el.fadeOut('fast');
+ },
+
+ // destroy modal
+ destroy: function ()
+ {
+ // remove element
+ this.$el.remove();
+ },
+
+ /*
+ HTML TEMPLATES
+ */
+
+ // fill regular modal template
+ template: function(title, body)
+ {
+ return '<div class="galaxy-modal">' +
+ '<div class="background"></div>' +
+ '<div class="dialog galaxy-corner">' +
+ '<div class="header">' +
+ '<span><h3 class="title">' + title + '</h3></span>' +
+ '</div>' +
+ '<div class="body">' + body + '</div>' +
+ '<div class="footer"></div>' +
+ '</div>' +
+ '</div>';
+ }
+});
+
+// return
+return {
+ GalaxyModal: GalaxyModal
+};
+
+});
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/galaxy.upload.js
--- /dev/null
+++ b/static/scripts/galaxy.upload.js
@@ -0,0 +1,223 @@
+/*
+ galaxy upload v1.0
+*/
+
+// dependencies
+define(["utils/galaxy.css", "galaxy.modal", "galaxy.master", "utils/galaxy.uploadbox", "libs/backbone/backbone-relational"], function(css, mod_modal, mod_master) {
+
+// galaxy upload
+var GalaxyUpload = Backbone.View.extend(
+{
+ // own modal
+ modal : null,
+
+ // button
+ button_show : null,
+
+ // file counter
+ file_counter: 0,
+
+ // initialize
+ initialize : function()
+ {
+ // load required css files
+ css.load_file("static/style/galaxy.upload.css");
+
+ // add activate icon
+ var self = this;
+ this.button_show = new mod_master.GalaxyMasterIcon (
+ {
+ icon : 'fa-icon-upload',
+ tooltip : 'Upload Files',
+ on_click : function(e) { self.event_show(e) },
+ with_number : true
+ });
+
+ // add to master
+ Galaxy.master.prepend(this.button_show);
+ },
+
+ // events
+ events :
+ {
+ 'mouseover' : 'event_mouseover',
+ 'mouseleave' : 'event_mouseleave'
+ },
+
+ // mouse over
+ event_mouseover : function (e)
+ {
+ $('#galaxy-upload-box').addClass('galaxy-upload-highlight');
+ },
+
+ // mouse left
+ event_mouseleave : function (e)
+ {
+ $('#galaxy-upload-box').removeClass('galaxy-upload-highlight');
+ },
+
+ // start
+ event_start : function(index, file, message)
+ {
+ // make id
+ var id = '#galaxy-upload-file-' + index;
+
+ // add tag
+ $('#galaxy-upload-box').append(this.template_file(id));
+
+ // update title
+ $('#galaxy-upload-file-' + index).find('.title').html(file.name);
+
+ // initialize progress
+ this.event_progress(index, file, 0);
+
+ // update counter
+ this.file_counter++;
+ this.refresh();
+ },
+
+ // progress
+ event_progress : function(index, file, message)
+ {
+ // get progress bar
+ var el = $('#galaxy-upload-file-' + index);
+
+ // get value
+ var percentage = parseInt(message);
+
+ // update progress
+ el.find('.progress').css({ width : percentage + '%' });
+
+ // update info
+ el.find('.info').html(percentage + '% of ' + this.size_to_string (file.size));
+ },
+
+ // end
+ event_success : function(index, file, message)
+ {
+ // update galaxy history
+ Galaxy.currHistoryPanel.refresh();
+
+ // update counter
+ this.file_counter--;
+ this.refresh();
+ },
+
+ // end
+ event_error : function(index, file, message)
+ {
+ // get file box
+ var el = $('#galaxy-upload-file-' + index);
+
+ // update progress frame
+ el.find('.progress-frame').addClass("failed");
+
+ // update error message
+ el.find('.error').html("<strong>Failed:</strong> " + message);
+
+ // update progress
+ this.event_progress(index, file, 0);
+
+ // update counter
+ this.file_counter--;
+ this.refresh();
+ },
+
+ // show/hide upload frame
+ event_show : function (e)
+ {
+ // 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)
+ {
+ // make modal
+ this.modal = new mod_modal.GalaxyModal(
+ {
+ title : 'Upload files from your local drive',
+ body : this.template()
+ });
+
+ // get current history
+ var current_history = Galaxy.currHistoryPanel.model.get('id');
+
+ // file upload
+ var self = this;
+ $('#galaxy-upload-box').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) },
+ 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');
+ }
+
+ // show modal
+ this.modal.show();
+ },
+
+ // update counter
+ refresh: function ()
+ {
+ if (this.file_counter > 0)
+ this.button_show.number(this.file_counter);
+ else
+ this.button_show.number('');
+ },
+
+ // to string
+ size_to_string : function (size)
+ {
+ // identify unit
+ var unit = "";
+ if (size >= 100000000000) { size = size / 100000000000; unit = "TB"; } else
+ if (size >= 100000000) { size = size / 100000000; unit = "GB"; } else
+ if (size >= 100000) { size = size / 100000; unit = "MB"; } else
+ if (size >= 100) { size = size / 100; unit = "KB"; } else
+ { size = size * 10; unit = "b"; }
+ // return formatted string
+ return "<strong>" + (Math.round(size) / 10) + "</strong> " + unit;
+ },
+
+ // load html template
+ template: function()
+ {
+ return '<form id="galaxy-upload-box" class="galaxy-upload-box galaxy-corner"></form>';
+ },
+
+ // load html template
+ template_file: function(id)
+ {
+ return '<div id="' + id.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
+return {
+ GalaxyUpload: GalaxyUpload
+};
+
+});
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/mvc/data.js
--- a/static/scripts/mvc/data.js
+++ b/static/scripts/mvc/data.js
@@ -433,7 +433,7 @@
dataset_params.id = vis_id;
// add widget
- parent.frame_manager.frame_new(
+ parent.Galaxy.frame_manager.frame_new(
{
title : "Trackster",
type : "url",
@@ -450,7 +450,7 @@
var url = vis_url + "/trackster?" + $.param(dataset_params);
// add widget
- parent.frame_manager.frame_new(
+ parent.Galaxy.frame_manager.frame_new(
{
title : "Trackster",
type : "url",
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/mvc/dataset/hda-base.js
--- a/static/scripts/mvc/dataset/hda-base.js
+++ b/static/scripts/mvc/dataset/hda-base.js
@@ -246,7 +246,7 @@
// add frame manager option onclick event
var self = this;
displayBtnData.on_click = function(){
- parent.frame_manager.frame_new({
+ Galaxy.frame_manager.frame_new({
title : "Data Viewer",
type : "url",
location: "center",
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/mvc/dataset/hda-edit.js
--- a/static/scripts/mvc/dataset/hda-edit.js
+++ b/static/scripts/mvc/dataset/hda-edit.js
@@ -289,7 +289,7 @@
return create_scatterplot_action_fn( visualization_url, params );
default:
return function(){// add widget
- parent.frame_manager.frame_new(
+ Galaxy.frame_manager.frame_new(
{
title : "Visualization",
type : "url",
@@ -611,7 +611,7 @@
function create_scatterplot_action_fn( url, params ){
action = function() {
// add widget
- parent.frame_manager.frame_new(
+ Galaxy.frame_manager.frame_new(
{
title : "Scatterplot",
type : "url",
@@ -667,7 +667,7 @@
parent.hide_modal();
// add widget
- parent.frame_manager.frame_new(
+ Galaxy.frame_manager.frame_new(
{
title : "Trackster",
type : "url",
@@ -682,7 +682,7 @@
parent.hide_modal();
// add widget
- parent.frame_manager.frame_new(
+ Galaxy.frame_manager.frame_new(
{
title : "Trackster",
type : "url",
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/mvc/history/history-panel.js
--- a/static/scripts/mvc/history/history-panel.js
+++ b/static/scripts/mvc/history/history-panel.js
@@ -114,6 +114,13 @@
this.urls = {};
},
+ // refresh function
+ refresh : function() {
+ // refresh
+ // TODO: refresh content without reloading frame
+ window.location = window.location;
+ },
+
_setUpEventHandlers : function(){
// ---- model
// don't need to re-render entire model on all changes, just render disk size when it changes
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/packed/galaxy.frame.js
--- a/static/scripts/packed/galaxy.frame.js
+++ b/static/scripts/packed/galaxy.frame.js
@@ -1,1 +1,1 @@
-define(["utils/galaxy.css","libs/backbone/backbone-relational"],function(b){var a=Backbone.View.extend({el:"#everything",el_header:"#masthead",options:{frame:{cols:6,rows:3},rows:1000,cell:130,margin:5,scroll:5,top_min:40,frame_max:10},cols:0,top:0,top_max:0,frame_counter:0,frame_counter_id:0,frame_list:[],galaxy_frame_shadow:null,visible:false,active:false,initialize:function(d){b.load_file("static/style/galaxy.frame.css");if(d){this.options=_.defaults(d,this.options)}this.top=this.top_max=this.options.top_min;$(this.el).append(this.frame_template_background());$(this.el).append(this.frame_template_menu());$(this.el_header).append(this.frame_template_header());var e="#galaxy-frame-shadow";$(this.el).append(this.frame_template_shadow(e.substring(1)));this.galaxy_frame_shadow={id:e,screen_location:{},grid_location:{},grid_rank:null,grid_lock:false};this.frame_resize(this.galaxy_frame_shadow,{width:0,height:0});this.frame_list[e]=this.galaxy_frame_shadow;this.panel_refresh();this.event_initialize();$(".galaxy-frame-active").tooltip({title:"Enable/Disable Scratchbook"});$(".galaxy-frame-load").tooltip({title:"Show/Hide Scratchbook"});var c=this;$(window).resize(function(){c.panel_refresh()});window.onbeforeunload=function(){if(c.frame_counter>0){return"You opened "+c.frame_counter+" frame(s) which will be lost."}}},is_mobile:function(){return navigator.userAgent.match(/mobile|(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i)},event:{type:null,target:null,xy:null},event_initialize:function(){this.events={mousemove:"event_frame_mouse_move",mouseup:"event_frame_mouse_up",mouseleave:"event_frame_mouse_up",mousewheel:"event_panel_scroll",DOMMouseScroll:"event_panel_scroll","mousedown .galaxy-frame":"event_frame_mouse_down","mousedown .galaxy-frame-active":"event_panel_active","mousedown .galaxy-frame-load":"event_panel_load","mousedown .galaxy-frame-background":"event_panel_load","mousedown .galaxy-frame-scroll-up":"event_panel_scroll_up","mousedown .galaxy-frame-scroll-down":"event_panel_scroll_down","mousedown .f-close":"event_frame_close","mousedown .f-pin":"event_frame_lock"};this.delegateEvents(this.events)},event_frame_mouse_down:function(c){if(this.event.type!==null){return}if($(c.target).hasClass("f-header")||$(c.target).hasClass("f-title")){this.event.type="drag"}if($(c.target).hasClass("f-resize")){this.event.type="resize"}if(this.event.type===null){return}c.preventDefault();this.event.target=this.event_get_frame(c.target);if(this.event.target.grid_lock){this.event.type=null;return}this.event.xy={x:c.originalEvent.pageX,y:c.originalEvent.pageY};this.frame_drag_start(this.event.target)},event_frame_mouse_move:function(i){if(this.event.type!="drag"&&this.event.type!="resize"){return}var g={x:i.originalEvent.pageX,y:i.originalEvent.pageY};var d={x:g.x-this.event.xy.x,y:g.y-this.event.xy.y};this.event.xy=g;var h=this.frame_screen(this.event.target);if(this.event.type=="resize"){h.width+=d.x;h.height+=d.y;var f=this.options.cell-this.options.margin-1;h.width=Math.max(h.width,f);h.height=Math.max(h.height,f);this.frame_resize(this.event.target,h);h.width=this.to_grid_coord("width",h.width)+1;h.height=this.to_grid_coord("height",h.height)+1;h.width=this.to_pixel_coord("width",h.width);h.height=this.to_pixel_coord("height",h.height);this.frame_resize(this.galaxy_frame_shadow,h);this.frame_insert(this.galaxy_frame_shadow,{top:this.to_grid_coord("top",h.top),left:this.to_grid_coord("left",h.left)})}if(this.event.type=="drag"){h.left+=d.x;h.top+=d.y;this.frame_offset(this.event.target,h);var c={top:this.to_grid_coord("top",h.top),left:this.to_grid_coord("left",h.left)};if(c.left!==0){c.left++}this.frame_insert(this.galaxy_frame_shadow,c)}},event_frame_mouse_up:function(c){if(this.event.type!="drag"&&this.event.type!="resize"){return}this.frame_drag_stop(this.event.target);this.event.type=null},event_frame_close:function(d){if(this.event.type!==null){return}d.preventDefault();var f=this.event_get_frame(d.target);var c=this;$(f.id).fadeOut("fast",function(){$(f.id).remove();delete c.frame_list[f.id];c.frame_counter--;c.panel_refresh(true);c.panel_animation_complete();if(c.visible&&c.frame_counter==0){c.panel_show_hide()}})},event_frame_lock:function(c){if(this.event.type!==null){return}c.preventDefault();var d=this.event_get_frame(c.target);if(d.grid_lock){d.grid_lock=false;$(d.id).find(".f-pin").removeClass("f-toggle");$(d.id).find(".f-header").removeClass("f-not-allowed");$(d.id).find(".f-title").removeClass("f-not-allowed");$(d.id).find(".f-resize").show();$(d.id).find(".f-close").show()}else{d.grid_lock=true;$(d.id).find(".f-pin").addClass("f-toggle");$(d.id).find(".f-header").addClass("f-not-allowed");$(d.id).find(".f-title").addClass("f-not-allowed");$(d.id).find(".f-resize").hide();$(d.id).find(".f-close").hide()}},event_panel_load:function(c){if(this.event.type!==null){return}c.preventDefault();this.panel_show_hide()},event_panel_active:function(c){if(this.event.type!==null){return}c.preventDefault();this.panel_active_disable()},event_panel_scroll:function(c){if(this.event.type!==null||!this.visible){return}c.preventDefault();var d=c.originalEvent.detail?c.originalEvent.detail:c.originalEvent.wheelDelta/-3;this.panel_scroll(d)},event_panel_scroll_up:function(c){if(this.event.type!==null){return}c.preventDefault();this.panel_scroll(-this.options.scroll)},event_panel_scroll_down:function(c){if(this.event.type!==null){return}c.preventDefault();this.panel_scroll(this.options.scroll)},event_get_frame:function(c){return this.frame_list["#"+$(c).closest(".galaxy-frame").attr("id")]},frame_drag_start:function(d){this.frame_focus(d,true);var c=this.frame_screen(d);this.frame_resize(this.galaxy_frame_shadow,c);this.frame_grid(this.galaxy_frame_shadow,d.grid_location);d.grid_location=null;$(this.galaxy_frame_shadow.id).show();$(".f-cover").show()},frame_drag_stop:function(d){this.frame_focus(d,false);var c=this.frame_screen(this.galaxy_frame_shadow);this.frame_resize(d,c);this.frame_grid(d,this.galaxy_frame_shadow.grid_location,true);this.galaxy_frame_shadow.grid_location=null;$(this.galaxy_frame_shadow.id).hide();$(".f-cover").hide();this.panel_animation_complete()},to_grid_coord:function(e,d){var c=(e=="width"||e=="height")?1:-1;if(e=="top"){d-=this.top}return parseInt((d+c*this.options.margin)/this.options.cell,10)},to_pixel_coord:function(e,f){var c=(e=="width"||e=="height")?1:-1;var d=(f*this.options.cell)-c*this.options.margin;if(e=="top"){d+=this.top}return d},to_grid:function(c){return{top:this.to_grid_coord("top",c.top),left:this.to_grid_coord("left",c.left),width:this.to_grid_coord("width",c.width),height:this.to_grid_coord("height",c.height)}},to_pixel:function(c){return{top:this.to_pixel_coord("top",c.top),left:this.to_pixel_coord("left",c.left),width:this.to_pixel_coord("width",c.width),height:this.to_pixel_coord("height",c.height)}},is_collision:function(e){function c(h,g){return !(h.left>g.left+g.width-1||h.left+h.width-1<g.left||h.top>g.top+g.height-1||h.top+h.height-1<g.top)}for(var d in this.frame_list){var f=this.frame_list[d];if(f.grid_location===null){continue}if(c(e,f.grid_location)){return true}}return false},location_rank:function(c){return(c.top*this.cols)+c.left},menu_refresh:function(){$(".galaxy-frame-load .number").text(this.frame_counter);if(this.frame_counter==0){$(".galaxy-frame-load").hide()}else{$(".galaxy-frame-load").show()}if(this.top==this.options.top_min){$(".galaxy-frame-scroll-up").hide()}else{$(".galaxy-frame-scroll-up").show()}if(this.top==this.top_max){$(".galaxy-frame-scroll-down").hide()}else{$(".galaxy-frame-scroll-down").show()}},panel_animation_complete:function(){var c=this;$(".galaxy-frame").promise().done(function(){c.panel_scroll(0,true)})},panel_refresh:function(c){this.cols=parseInt($(window).width()/this.options.cell,10)+1;this.frame_insert(null,null,c)},panel_scroll:function(h,c){var e=this.top-this.options.scroll*h;e=Math.max(e,this.top_max);e=Math.min(e,this.options.top_min);if(this.top!=e){for(var d in this.frame_list){var g=this.frame_list[d];if(g.grid_location!==null){var f={top:g.screen_location.top-(this.top-e),left:g.screen_location.left};this.frame_offset(g,f,c)}}this.top=e}this.menu_refresh()},panel_show_hide:function(){if(this.visible){this.visible=false;$(".galaxy-frame").fadeOut("fast");$(".galaxy-frame-load .icon").addClass("fa-icon-eye-close");$(".galaxy-frame-load .icon").removeClass("fa-icon-eye-open");$(".galaxy-frame-background").hide();$(".galaxy-frame-menu").hide()}else{this.visible=true;$(".galaxy-frame").fadeIn("fast");$(".galaxy-frame-load .icon").addClass("fa-icon-eye-open");$(".galaxy-frame-load .icon").removeClass("fa-icon-eye-close");$(this.galaxy_frame_shadow.id).hide();$(".galaxy-frame-background").show();this.menu_refresh()}},panel_active_disable:function(){if(this.active){this.active=false;$(".galaxy-frame-active .icon").removeClass("f-toggle");if(this.visible){this.panel_show_hide()}}else{this.active=true;$(".galaxy-frame-active .icon").addClass("f-toggle")}},frame_new:function(d){if(!this.active){if(d.location=="center"){var c=$(window.parent.document).find("iframe#galaxy_main");c.attr("src",d.content)}else{window.location=d.content}return}if(this.frame_counter>this.options.frame_max){alert("You have reached the maximum number of allowed frames ("+this.options.frame_max+").");return}var e="#galaxy-frame-"+(this.frame_counter_id++);if($(e).length!==0){alert("This frame already exists. This page might contain multiple frame managers.");return}this.top=this.options.top_min;$(this.el).append(this.frame_template(e.substring(1),d.title,d.type,d.content));var f={id:e,screen_location:{},grid_location:{},grid_rank:null,grid_lock:false};d.width=this.to_pixel_coord("width",this.options.frame.cols);d.height=this.to_pixel_coord("height",this.options.frame.rows);this.frame_list[e]=f;this.frame_counter++;this.frame_resize(f,{width:d.width,height:d.height});this.frame_insert(f,{top:0,left:0},true);if(!this.visible){this.panel_show_hide()}},frame_insert:function(j,c,e){var d=[];if(j){j.grid_location=null;d.push([j,this.location_rank(c)])}var g=null;for(g in this.frame_list){var h=this.frame_list[g];if(h.grid_location!==null&&!h.grid_lock){h.grid_location=null;d.push([h,h.grid_rank])}}d.sort(function(k,f){var m=k[1];var l=f[1];return m<l?-1:(m>l?1:0)});for(g=0;g<d.length;g++){this.frame_place(d[g][0],e)}this.top_max=0;for(var g in this.frame_list){var j=this.frame_list[g];if(j.grid_location!==null){this.top_max=Math.max(this.top_max,j.grid_location.top+j.grid_location.height)}}this.top_max=$(window).height()-this.top_max*this.options.cell-2*this.options.margin;this.top_max=Math.min(this.top_max,this.options.top_min);this.menu_refresh()},frame_place:function(k,d){k.grid_location=null;var h=this.to_grid(this.frame_screen(k));var c=false;for(var f=0;f<this.options.rows;f++){for(var e=0;e<Math.max(1,this.cols-h.width);e++){h.top=f;h.left=e;if(!this.is_collision(h)){c=true;break}}if(c){break}}if(c){this.frame_grid(k,h,d)}else{console.log("Grid dimensions exceeded.")}},frame_focus:function(e,c){var d=parseInt(b.get_attribute("galaxy-frame","z-index"))+(c?1:0);$(e.id).css("z-index",d)},frame_offset:function(f,e,d){f.screen_location.left=e.left;f.screen_location.top=e.top;if(d){this.frame_focus(f,true);var c=this;$(f.id).animate({top:e.top,left:e.left},"fast",function(){c.frame_focus(f,false)})}else{$(f.id).css({top:e.top,left:e.left})}},frame_resize:function(d,c){$(d.id).css({width:c.width,height:c.height});d.screen_location.width=c.width;d.screen_location.height=c.height},frame_grid:function(e,c,d){e.grid_location=c;this.frame_offset(e,this.to_pixel(c),d);e.grid_rank=this.location_rank(c)},frame_screen:function(d){var c=d.screen_location;return{top:c.top,left:c.left,width:c.width,height:c.height}},frame_template:function(f,e,c,d){if(!e){e=""}if(c=="url"){d='<iframe scrolling="auto" class="f-iframe" src="'+d+'"></iframe>'}return'<div id="'+f+'" class="galaxy-frame f-corner"><div class="f-header f-corner"><span class="f-title">'+e+'</span><span class="f-icon f-pin fa-icon-pushpin"></span><span class="f-icon f-close fa-icon-trash"></span></div><div class="f-content f-corner">'+d+'<div class="f-cover"></div></div><span class="f-resize f-icon f-corner fa-icon-resize-full"></span></div>'},frame_template_shadow:function(c){return'<div id="'+c+'" class="galaxy-frame-shadow f-corner"></div>'},frame_template_background:function(){return'<div class="galaxy-frame-background"></div>'},frame_template_header:function(){return'<div class="galaxy-frame-load f-corner"><div class="number f-corner">0</div><div class="icon fa-icon-2x"></div></div><div class="galaxy-frame-active f-corner" style="position: absolute; top: 8px;"><div class="icon fa-icon-2x fa-icon-th"></div></div>'},frame_template_menu:function(){return'<div class="galaxy-frame-scroll-up galaxy-frame-menu fa-icon-chevron-up fa-icon-2x"></div><div class="galaxy-frame-scroll-down galaxy-frame-menu fa-icon-chevron-down fa-icon-2x"></div>'}});return{GalaxyFrameManager:a}});
\ No newline at end of file
+define(["utils/galaxy.css","galaxy.master","libs/backbone/backbone-relational"],function(b,c){var a=Backbone.View.extend({el_main:"#everything",options:{frame:{cols:6,rows:3},rows:1000,cell:130,margin:5,scroll:5,top_min:40,frame_max:10},cols:0,top:0,top_max:0,frame_counter:0,frame_counter_id:0,frame_list:[],galaxy_frame_shadow:null,visible:false,active:false,button_active:null,button_load:null,initialize:function(e){var d=this;this.button_active=new c.GalaxyMasterIcon({icon:"fa-icon-th",tooltip:"Enable/Disable Scratchbook",on_click:function(g){d.event_panel_active(g)}});Galaxy.master.append(this.button_active);this.button_load=new c.GalaxyMasterIcon({icon:"fa-icon-eye-open",tooltip:"Show/Hide Scratchbook",on_click:function(g){d.event_panel_load(g)},with_number:true});Galaxy.master.append(this.button_load);b.load_file("static/style/galaxy.frame.css");if(e){this.options=_.defaults(e,this.options)}this.top=this.top_max=this.options.top_min;$(this.el).append(this.frame_template_background());$(this.el).append(this.frame_template_menu());$(this.el_main).append($(this.el));var f="#galaxy-frame-shadow";$(this.el).append(this.frame_template_shadow(f.substring(1)));this.galaxy_frame_shadow={id:f,screen_location:{},grid_location:{},grid_rank:null,grid_lock:false};this.frame_resize(this.galaxy_frame_shadow,{width:0,height:0});this.frame_list[f]=this.galaxy_frame_shadow;this.panel_refresh();var d=this;$(window).resize(function(){if(d.visible){d.panel_refresh()}});window.onbeforeunload=function(){if(d.frame_counter>0){return"You opened "+d.frame_counter+" frame(s) which will be lost."}}},event:{type:null,target:null,xy:null},events:{mousemove:"event_frame_mouse_move",mouseup:"event_frame_mouse_up",mouseleave:"event_frame_mouse_up",mousewheel:"event_panel_scroll",DOMMouseScroll:"event_panel_scroll","mousedown .galaxy-frame":"event_frame_mouse_down","mousedown .galaxy-frame-background":"event_panel_load","mousedown .galaxy-frame-scroll-up":"event_panel_scroll_up","mousedown .galaxy-frame-scroll-down":"event_panel_scroll_down","mousedown .f-close":"event_frame_close","mousedown .f-pin":"event_frame_lock"},event_frame_mouse_down:function(d){if(this.event.type!==null){return}if($(d.target).hasClass("f-header")||$(d.target).hasClass("f-title")){this.event.type="drag"}if($(d.target).hasClass("f-resize")){this.event.type="resize"}if(this.event.type===null){return}d.preventDefault();this.event.target=this.event_get_frame(d.target);if(this.event.target.grid_lock){this.event.type=null;return}this.event.xy={x:d.originalEvent.pageX,y:d.originalEvent.pageY};this.frame_drag_start(this.event.target)},event_frame_mouse_move:function(j){if(this.event.type!="drag"&&this.event.type!="resize"){return}var h={x:j.originalEvent.pageX,y:j.originalEvent.pageY};var f={x:h.x-this.event.xy.x,y:h.y-this.event.xy.y};this.event.xy=h;var i=this.frame_screen(this.event.target);if(this.event.type=="resize"){i.width+=f.x;i.height+=f.y;var g=this.options.cell-this.options.margin-1;i.width=Math.max(i.width,g);i.height=Math.max(i.height,g);this.frame_resize(this.event.target,i);i.width=this.to_grid_coord("width",i.width)+1;i.height=this.to_grid_coord("height",i.height)+1;i.width=this.to_pixel_coord("width",i.width);i.height=this.to_pixel_coord("height",i.height);this.frame_resize(this.galaxy_frame_shadow,i);this.frame_insert(this.galaxy_frame_shadow,{top:this.to_grid_coord("top",i.top),left:this.to_grid_coord("left",i.left)})}if(this.event.type=="drag"){i.left+=f.x;i.top+=f.y;this.frame_offset(this.event.target,i);var d={top:this.to_grid_coord("top",i.top),left:this.to_grid_coord("left",i.left)};if(d.left!==0){d.left++}this.frame_insert(this.galaxy_frame_shadow,d)}},event_frame_mouse_up:function(d){if(this.event.type!="drag"&&this.event.type!="resize"){return}this.frame_drag_stop(this.event.target);this.event.type=null},event_frame_close:function(f){if(this.event.type!==null){return}f.preventDefault();var g=this.event_get_frame(f.target);var d=this;$(g.id).fadeOut("fast",function(){$(g.id).remove();delete d.frame_list[g.id];d.frame_counter--;d.panel_refresh(true);d.panel_animation_complete();if(d.visible&&d.frame_counter==0){d.panel_show_hide()}})},event_frame_lock:function(d){if(this.event.type!==null){return}d.preventDefault();var f=this.event_get_frame(d.target);if(f.grid_lock){f.grid_lock=false;$(f.id).find(".f-pin").removeClass("galaxy-toggle");$(f.id).find(".f-header").removeClass("f-not-allowed");$(f.id).find(".f-title").removeClass("f-not-allowed");$(f.id).find(".f-resize").show();$(f.id).find(".f-close").show()}else{f.grid_lock=true;$(f.id).find(".f-pin").addClass("galaxy-toggle");$(f.id).find(".f-header").addClass("f-not-allowed");$(f.id).find(".f-title").addClass("f-not-allowed");$(f.id).find(".f-resize").hide();$(f.id).find(".f-close").hide()}},event_panel_load:function(d){if(this.event.type!==null){return}this.panel_show_hide()},event_panel_active:function(d){if(this.event.type!==null){return}this.panel_active_disable()},event_panel_scroll:function(d){if(this.event.type!==null||!this.visible){return}d.preventDefault();var f=d.originalEvent.detail?d.originalEvent.detail:d.originalEvent.wheelDelta/-3;this.panel_scroll(f)},event_panel_scroll_up:function(d){if(this.event.type!==null){return}d.preventDefault();this.panel_scroll(-this.options.scroll)},event_panel_scroll_down:function(d){if(this.event.type!==null){return}d.preventDefault();this.panel_scroll(this.options.scroll)},event_get_frame:function(d){return this.frame_list["#"+$(d).closest(".galaxy-frame").attr("id")]},frame_drag_start:function(e){this.frame_focus(e,true);var d=this.frame_screen(e);this.frame_resize(this.galaxy_frame_shadow,d);this.frame_grid(this.galaxy_frame_shadow,e.grid_location);e.grid_location=null;$(this.galaxy_frame_shadow.id).show();$(".f-cover").show()},frame_drag_stop:function(e){this.frame_focus(e,false);var d=this.frame_screen(this.galaxy_frame_shadow);this.frame_resize(e,d);this.frame_grid(e,this.galaxy_frame_shadow.grid_location,true);this.galaxy_frame_shadow.grid_location=null;$(this.galaxy_frame_shadow.id).hide();$(".f-cover").hide();this.panel_animation_complete()},to_grid_coord:function(f,e){var d=(f=="width"||f=="height")?1:-1;if(f=="top"){e-=this.top}return parseInt((e+d*this.options.margin)/this.options.cell,10)},to_pixel_coord:function(f,h){var d=(f=="width"||f=="height")?1:-1;var e=(h*this.options.cell)-d*this.options.margin;if(f=="top"){e+=this.top}return e},to_grid:function(d){return{top:this.to_grid_coord("top",d.top),left:this.to_grid_coord("left",d.left),width:this.to_grid_coord("width",d.width),height:this.to_grid_coord("height",d.height)}},to_pixel:function(d){return{top:this.to_pixel_coord("top",d.top),left:this.to_pixel_coord("left",d.left),width:this.to_pixel_coord("width",d.width),height:this.to_pixel_coord("height",d.height)}},is_collision:function(f){function d(i,g){return !(i.left>g.left+g.width-1||i.left+i.width-1<g.left||i.top>g.top+g.height-1||i.top+i.height-1<g.top)}for(var e in this.frame_list){var h=this.frame_list[e];if(h.grid_location===null){continue}if(d(f,h.grid_location)){return true}}return false},location_rank:function(d){return(d.top*this.cols)+d.left},menu_refresh:function(){this.button_load.number(this.frame_counter);if(this.frame_counter==0){this.button_load.hide()}else{this.button_load.show()}if(this.top==this.options.top_min){$(".galaxy-frame-scroll-up").hide()}else{$(".galaxy-frame-scroll-up").show()}if(this.top==this.top_max){$(".galaxy-frame-scroll-down").hide()}else{$(".galaxy-frame-scroll-down").show()}},panel_animation_complete:function(){var d=this;$(".galaxy-frame").promise().done(function(){d.panel_scroll(0,true)})},panel_refresh:function(d){this.cols=parseInt($(window).width()/this.options.cell,10)+1;this.frame_insert(null,null,d)},panel_scroll:function(j,d){var f=this.top-this.options.scroll*j;f=Math.max(f,this.top_max);f=Math.min(f,this.options.top_min);if(this.top!=f){for(var e in this.frame_list){var h=this.frame_list[e];if(h.grid_location!==null){var g={top:h.screen_location.top-(this.top-f),left:h.screen_location.left};this.frame_offset(h,g,d)}}this.top=f}this.menu_refresh()},panel_show_hide:function(){if(this.visible){this.visible=false;$(".galaxy-frame").fadeOut("fast");this.button_load.icon("fa-icon-eye-close");this.button_load.untoggle();$(".galaxy-frame-background").hide();$(".galaxy-frame-menu").hide()}else{this.visible=true;$(".galaxy-frame").fadeIn("fast");this.button_load.icon("fa-icon-eye-open");this.button_load.toggle();$(this.galaxy_frame_shadow.id).hide();$(".galaxy-frame-background").show();this.panel_refresh()}},panel_active_disable:function(){if(this.active){this.active=false;this.button_active.untoggle();if(this.visible){this.panel_show_hide()}}else{this.active=true;this.button_active.toggle()}},frame_new:function(e){if(!this.active){if(e.location=="center"){var d=$(window.parent.document).find("iframe#galaxy_main");d.attr("src",e.content)}else{window.location=e.content}return}if(this.frame_counter>this.options.frame_max){alert("You have reached the maximum number of allowed frames ("+this.options.frame_max+").");return}var f="#galaxy-frame-"+(this.frame_counter_id++);if($(f).length!==0){alert("This frame already exists. This page might contain multiple frame managers.");return}this.top=this.options.top_min;$(this.el).append(this.frame_template(f.substring(1),e.title,e.type,e.content));var g={id:f,screen_location:{},grid_location:{},grid_rank:null,grid_lock:false};e.width=this.to_pixel_coord("width",this.options.frame.cols);e.height=this.to_pixel_coord("height",this.options.frame.rows);this.frame_list[f]=g;this.frame_counter++;this.frame_resize(g,{width:e.width,height:e.height});this.frame_insert(g,{top:0,left:0},true);if(!this.visible){this.panel_show_hide()}},frame_insert:function(k,d,g){var e=[];if(k){k.grid_location=null;e.push([k,this.location_rank(d)])}var h=null;for(h in this.frame_list){var j=this.frame_list[h];if(j.grid_location!==null&&!j.grid_lock){j.grid_location=null;e.push([j,j.grid_rank])}}e.sort(function(l,f){var n=l[1];var m=f[1];return n<m?-1:(n>m?1:0)});for(h=0;h<e.length;h++){this.frame_place(e[h][0],g)}this.top_max=0;for(var h in this.frame_list){var k=this.frame_list[h];if(k.grid_location!==null){this.top_max=Math.max(this.top_max,k.grid_location.top+k.grid_location.height)}}this.top_max=$(window).height()-this.top_max*this.options.cell-2*this.options.margin;this.top_max=Math.min(this.top_max,this.options.top_min);this.menu_refresh()},frame_place:function(l,e){l.grid_location=null;var k=this.to_grid(this.frame_screen(l));var d=false;for(var h=0;h<this.options.rows;h++){for(var f=0;f<Math.max(1,this.cols-k.width);f++){k.top=h;k.left=f;if(!this.is_collision(k)){d=true;break}}if(d){break}}if(d){this.frame_grid(l,k,e)}else{console.log("Grid dimensions exceeded.")}},frame_focus:function(f,d){var e=parseInt(b.get_attribute("galaxy-frame","z-index"))+(d?1:0);$(f.id).css("z-index",e)},frame_offset:function(g,f,e){g.screen_location.left=f.left;g.screen_location.top=f.top;if(e){this.frame_focus(g,true);var d=this;$(g.id).animate({top:f.top,left:f.left},"fast",function(){d.frame_focus(g,false)})}else{$(g.id).css({top:f.top,left:f.left})}},frame_resize:function(e,d){$(e.id).css({width:d.width,height:d.height});e.screen_location.width=d.width;e.screen_location.height=d.height},frame_grid:function(f,d,e){f.grid_location=d;this.frame_offset(f,this.to_pixel(d),e);f.grid_rank=this.location_rank(d)},frame_screen:function(e){var d=e.screen_location;return{top:d.top,left:d.left,width:d.width,height:d.height}},frame_template:function(g,f,d,e){if(!f){f=""}if(d=="url"){e='<iframe scrolling="auto" class="f-iframe" src="'+e+'"></iframe>'}return'<div id="'+g+'" class="galaxy-frame galaxy-corner"><div class="f-header galaxy-corner"><span class="f-title">'+f+'</span><span class="f-icon f-pin fa-icon-pushpin"></span><span class="f-icon f-close fa-icon-trash"></span></div><div class="f-content galaxy-corner">'+e+'<div class="f-cover"></div></div><span class="f-resize f-icon galaxy-corner fa-icon-resize-full"></span></div>'},frame_template_shadow:function(d){return'<div id="'+d+'" class="galaxy-frame-shadow galaxy-corner"></div>'},frame_template_background:function(){return'<div class="galaxy-frame-background"></div>'},frame_template_menu:function(){return'<div class="galaxy-frame-scroll-up galaxy-frame-menu fa-icon-chevron-up fa-icon-2x"></div><div class="galaxy-frame-scroll-down galaxy-frame-menu fa-icon-chevron-down fa-icon-2x"></div>'}});return{GalaxyFrameManager:a}});
\ No newline at end of file
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/packed/galaxy.master.js
--- /dev/null
+++ b/static/scripts/packed/galaxy.master.js
@@ -0,0 +1,1 @@
+define(["utils/galaxy.css","libs/backbone/backbone-relational"],function(b){var a=Backbone.View.extend({el_master:".masthead-inner",initialize:function(d){b.load_file("static/style/galaxy.master.css");this.setElement($(this.template()));$(this.el_master).append($(this.el))},events:{mousedown:function(d){d.preventDefault()}},append:function(d){$(this.el).append($(d.el))},prepend:function(d){$(this.el).prepend($(d.el))},template:function(){return'<div id="galaxy-master" class="galaxy-master"></div>'}});var c=Backbone.View.extend({options:{id:"galaxy-icon",icon:"fa-icon-cog",tooltip:"galaxy-icon",with_number:false,on_click:function(){alert("clicked")},visible:true},initialize:function(e){if(e){this.options=_.defaults(e,this.options)}this.setElement($(this.template(this.options)));var d=this;$(this.el).find(".icon").tooltip({title:this.options.tooltip}).on("click",d.options.on_click);if(!this.options.visible){this.hide()}},show:function(){$(this.el).css({visibility:"visible"})},hide:function(){$(this.el).css({visibility:"hidden"})},icon:function(d){$(this.el).find(".icon").removeClass(this.options.icon).addClass(d);this.options.icon=d},toggle:function(){$(this.el).addClass("galaxy-toggle")},untoggle:function(){$(this.el).removeClass("galaxy-toggle")},number:function(d){$(this.el).find(".number").text(d)},template:function(e){var d="<div id="+e.id+' class="galaxy-icon galaxy-corner"><div class="icon fa-icon-2x '+e.icon+'"></div>';if(e.with_number){d+='<div class="number galaxy-corner"></div>'}d+="</div>";return d}});return{GalaxyMaster:a,GalaxyMasterIcon:c}});
\ No newline at end of file
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/packed/galaxy.modal.js
--- /dev/null
+++ b/static/scripts/packed/galaxy.modal.js
@@ -0,0 +1,1 @@
+define(["utils/galaxy.css","libs/backbone/backbone-relational"],function(a){var b=Backbone.View.extend({el_main:"#everything",options:{title:"galaxy-modal",body:"No content available."},initialize:function(d){a.load_file("static/style/galaxy.modal.css");if(!d){d=this.options}else{d=_.defaults(d,this.options)}this.setElement(this.template(d.title,d.body));$(this.el_main).append($(this.el));var e=(this.$el).find(".footer");var c=this;if(d.buttons){$.each(d.buttons,function(f,g){e.append($("<button></button>").text(f).click(g)).append(" ")})}else{e.append($("<button></button>").text("Close").click(function(){c.hide()})).append(" ")}$(this.el).hide()},events:{"mousedown .dialog":"event_default","mousedown .background":"hide"},event_default:function(c){c.preventDefault()},show:function(){this.$el.fadeIn("fast")},hide:function(){this.$el.fadeOut("fast")},destroy:function(){this.$el.remove()},template:function(d,c){return'<div class="galaxy-modal"><div class="background"></div><div class="dialog galaxy-corner"><div class="header"><span><h3 class="title">'+d+'</h3></span></div><div class="body">'+c+'</div><div class="footer"></div></div></div>'}});return{GalaxyModal:b}});
\ No newline at end of file
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/packed/galaxy.upload.js
--- /dev/null
+++ b/static/scripts/packed/galaxy.upload.js
@@ -0,0 +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
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/packed/mvc/data.js
--- a/static/scripts/packed/mvc/data.js
+++ b/static/scripts/packed/mvc/data.js
@@ -1,1 +1,1 @@
-define(["libs/backbone/backbone-relational"],function(){var d=Backbone.RelationalModel.extend({});var e=Backbone.RelationalModel.extend({defaults:{id:"",type:"",name:"",hda_ldda:"hda",metadata:null},initialize:function(){this.on("change",this._set_metadata,this)},_set_metadata:function(){var i=new d();_.each(_.keys(this.attributes),function(j){if(j.indexOf("metadata_")===0){var l=j.split("metadata_")[1];i.set(l,this.attributes[j]);delete this.attributes[j]}},this);this.set("metadata",i,{silent:true})},get_metadata:function(i){return this.attributes.metadata.get(i)},urlRoot:galaxy_config.root+"api/datasets"});var c=e.extend({defaults:_.extend({},e.prototype.defaults,{chunk_url:null,first_data_chunk:null,chunk_index:-1,at_eof:false}),initialize:function(i){e.prototype.initialize.call(this);this.attributes.chunk_index=(this.attributes.first_data_chunk?1:0)},get_next_chunk:function(){if(this.attributes.at_eof){return null}var i=this,j=$.Deferred();$.getJSON(this.attributes.chunk_url,{chunk:i.attributes.chunk_index++}).success(function(k){var l;if(k.ck_data!==""){l=k}else{i.attributes.at_eof=true;l=null}j.resolve(l)});return j}});var g=Backbone.Collection.extend({model:e});var f=Backbone.View.extend({initialize:function(i){new b(i)},render:function(){var m=$("<table/>").attr({id:"content_table",cellpadding:0});this.$el.append(m);var i=this.model.get_metadata("column_names");if(i){m.append("<tr><th>"+i.join("</th><th>")+"</th></tr>")}var k=this.model.get("first_data_chunk");if(k){this._renderChunk(k)}var j=this,n=_.find(this.$el.parents(),function(o){return $(o).css("overflow")==="auto"}),l=false;if(!n){n=window}n=$(n);n.scroll(function(){if(!l&&(j.$el.height()-n.scrollTop()-n.height()<=0)){l=true;$.when(j.model.get_next_chunk()).then(function(o){if(o){j._renderChunk(o);l=false}})}});$("#loading_indicator").ajaxStart(function(){$(this).show()}).ajaxStop(function(){$(this).hide()})},_renderCell:function(k,i,l){var j=this.model.get_metadata("column_types");if(l!==undefined){return $("<td>").attr("colspan",l).addClass("stringalign").text(k)}else{if(j[i]==="str"||j==="list"){return $("<td>").addClass("stringalign").text(k)}else{return $("<td>").text(k)}}},_renderRow:function(i){var j=i.split("\t"),l=$("<tr>"),k=this.model.get_metadata("columns");if(j.length===k){_.each(j,function(n,m){l.append(this._renderCell(n,m))},this)}else{if(j.length>k){_.each(j.slice(0,k-1),function(n,m){l.append(this._renderCell(n,m))},this);l.append(this._renderCell(j.slice(k-1).join("\t"),k-1))}else{if(k>5&&j.length===k-1){_.each(j,function(n,m){l.append(this._renderCell(n,m))},this);l.append($("<td>"))}else{l.append(this._renderCell(i,0,k))}}}return l},_renderChunk:function(i){var j=this.$el.find("table");_.each(i.ck_data.split("\n"),function(k,l){j.append(this._renderRow(k))},this)}});var b=Backbone.View.extend({col:{chrom:null,start:null,end:null},url_viz:null,dataset_id:null,genome_build:null,data_type:null,initialize:function(k){var j=k.model.attributes;var m=k.model.attributes.metadata.attributes;if(typeof j.data_type!=="undefined"){this.data_type=j.data_type}else{console.log("TabularButtonTrackster : Data type missing.")}if(this.data_type=="bed"){if(typeof m.chromCol!=="undefined"||typeof m.startCol!=="undefined"||typeof m.endCol!=="undefined"){this.col.chrom=m.chromCol-1;this.col.start=m.startCol-1;this.col.end=m.endCol-1}else{console.log("TabularButtonTrackster : Bed-file metadata incomplete.")}}if(this.data_type=="vcf"){function l(o,p){for(var n=0;n<p.length;n++){if(p[n].match(o)){return n}}return -1}this.col.chrom=l("Chrom",m.column_names);this.col.start=l("Pos",m.column_names);this.col.end=null;if(this.col.chrom==-1||this.col.start==-1){console.log("TabularButtonTrackster : VCF-file metadata incomplete.")}}if(this.col.chrom===null){console.log("TabularButtonTrackster : Chromosome column undefined.");return}if(typeof k.model.attributes.id==="undefined"){console.log("TabularButtonTrackster : Dataset identification is missing.")}else{this.dataset_id=k.model.attributes.id}if(typeof k.model.attributes.url_viz==="undefined"){console.log("TabularButtonTrackster : Url for visualization controller is missing.")}else{this.url_viz=k.model.attributes.url_viz}if(typeof k.model.attributes.genome_build!=="undefined"){this.genome_build=k.model.attributes.genome_build}var i=new IconButtonView({model:new IconButton({title:"Visualize",icon_class:"chart_curve",id:"btn_viz"})});this.$el.append(i.render().$el);$("#btn_viz").hide()},events:{"mouseover tr":"btn_viz_show",mouseleave:"btn_viz_hide"},btn_viz_show:function(n){function m(s){return !isNaN(parseFloat(s))&&isFinite(s)}if(this.col.chrom===null){return}var r=$(n.target).parent();var o=r.children().eq(this.col.chrom).html();var i=r.children().eq(this.col.start).html();var k=this.col.end?r.children().eq(this.col.end).html():i;if(!o.match("^#")&&o!==""&&m(i)){var q={dataset_id:this.dataset_id,gene_region:o+":"+i+"-"+k};var l=r.offset();var j=l.left-10;var p=l.top-$(window).scrollTop();$("#btn_viz").css({position:"fixed",top:p+"px",left:j+"px"});$("#btn_viz").off("click");$("#btn_viz").click(this.create_trackster_action(this.url_viz,q,this.genome_build));$("#btn_viz").show()}else{$("#btn_viz").hide()}},btn_viz_hide:function(){$("#btn_viz").hide()},create_trackster_action:function(i,k,j){return function(){var l={};if(j){l["f-dbkey"]=j}$.ajax({url:i+"/list_tracks?"+$.param(l),dataType:"html",error:function(){alert(("Could not add this dataset to browser")+".")},success:function(m){var n=window.parent;n.show_modal(("View Data in a New or Saved Visualization"),"",{Cancel:function(){n.hide_modal()},"View in saved visualization":function(){n.show_modal(("Add Data to Saved Visualization"),m,{Cancel:function(){n.hide_modal()},"Add to visualization":function(){$(n.document).find("input[name=id]:checked").each(function(){var o=$(this).val();k.id=o;n.frame_manager.frame_new({title:"Trackster",type:"url",content:i+"/trackster?"+$.param(k)});n.hide_modal()})}})},"View in new visualization":function(){var o=i+"/trackster?"+$.param(k);n.frame_manager.frame_new({title:"Trackster",type:"url",content:o});n.hide_modal()}})}});return false}}});var a=function(l,j,m,i){var k=new j({model:new l(m)});k.render();if(i){i.append(k.$el)}return k};var h=function(k,i){var j=$("<div/>").appendTo(i);return new f({el:j,model:new c(k)}).render()};return{Dataset:e,TabularDataset:c,DatasetCollection:g,TabularDatasetChunkedView:f,createTabularDatasetChunkedView:h}});
\ No newline at end of file
+define(["libs/backbone/backbone-relational"],function(){var d=Backbone.RelationalModel.extend({});var e=Backbone.RelationalModel.extend({defaults:{id:"",type:"",name:"",hda_ldda:"hda",metadata:null},initialize:function(){this.on("change",this._set_metadata,this)},_set_metadata:function(){var i=new d();_.each(_.keys(this.attributes),function(j){if(j.indexOf("metadata_")===0){var l=j.split("metadata_")[1];i.set(l,this.attributes[j]);delete this.attributes[j]}},this);this.set("metadata",i,{silent:true})},get_metadata:function(i){return this.attributes.metadata.get(i)},urlRoot:galaxy_config.root+"api/datasets"});var c=e.extend({defaults:_.extend({},e.prototype.defaults,{chunk_url:null,first_data_chunk:null,chunk_index:-1,at_eof:false}),initialize:function(i){e.prototype.initialize.call(this);this.attributes.chunk_index=(this.attributes.first_data_chunk?1:0)},get_next_chunk:function(){if(this.attributes.at_eof){return null}var i=this,j=$.Deferred();$.getJSON(this.attributes.chunk_url,{chunk:i.attributes.chunk_index++}).success(function(k){var l;if(k.ck_data!==""){l=k}else{i.attributes.at_eof=true;l=null}j.resolve(l)});return j}});var g=Backbone.Collection.extend({model:e});var f=Backbone.View.extend({initialize:function(i){new b(i)},render:function(){var m=$("<table/>").attr({id:"content_table",cellpadding:0});this.$el.append(m);var i=this.model.get_metadata("column_names");if(i){m.append("<tr><th>"+i.join("</th><th>")+"</th></tr>")}var k=this.model.get("first_data_chunk");if(k){this._renderChunk(k)}var j=this,n=_.find(this.$el.parents(),function(o){return $(o).css("overflow")==="auto"}),l=false;if(!n){n=window}n=$(n);n.scroll(function(){if(!l&&(j.$el.height()-n.scrollTop()-n.height()<=0)){l=true;$.when(j.model.get_next_chunk()).then(function(o){if(o){j._renderChunk(o);l=false}})}});$("#loading_indicator").ajaxStart(function(){$(this).show()}).ajaxStop(function(){$(this).hide()})},_renderCell:function(k,i,l){var j=this.model.get_metadata("column_types");if(l!==undefined){return $("<td>").attr("colspan",l).addClass("stringalign").text(k)}else{if(j[i]==="str"||j==="list"){return $("<td>").addClass("stringalign").text(k)}else{return $("<td>").text(k)}}},_renderRow:function(i){var j=i.split("\t"),l=$("<tr>"),k=this.model.get_metadata("columns");if(j.length===k){_.each(j,function(n,m){l.append(this._renderCell(n,m))},this)}else{if(j.length>k){_.each(j.slice(0,k-1),function(n,m){l.append(this._renderCell(n,m))},this);l.append(this._renderCell(j.slice(k-1).join("\t"),k-1))}else{if(k>5&&j.length===k-1){_.each(j,function(n,m){l.append(this._renderCell(n,m))},this);l.append($("<td>"))}else{l.append(this._renderCell(i,0,k))}}}return l},_renderChunk:function(i){var j=this.$el.find("table");_.each(i.ck_data.split("\n"),function(k,l){j.append(this._renderRow(k))},this)}});var b=Backbone.View.extend({col:{chrom:null,start:null,end:null},url_viz:null,dataset_id:null,genome_build:null,data_type:null,initialize:function(k){var j=k.model.attributes;var m=k.model.attributes.metadata.attributes;if(typeof j.data_type!=="undefined"){this.data_type=j.data_type}else{console.log("TabularButtonTrackster : Data type missing.")}if(this.data_type=="bed"){if(typeof m.chromCol!=="undefined"||typeof m.startCol!=="undefined"||typeof m.endCol!=="undefined"){this.col.chrom=m.chromCol-1;this.col.start=m.startCol-1;this.col.end=m.endCol-1}else{console.log("TabularButtonTrackster : Bed-file metadata incomplete.")}}if(this.data_type=="vcf"){function l(o,p){for(var n=0;n<p.length;n++){if(p[n].match(o)){return n}}return -1}this.col.chrom=l("Chrom",m.column_names);this.col.start=l("Pos",m.column_names);this.col.end=null;if(this.col.chrom==-1||this.col.start==-1){console.log("TabularButtonTrackster : VCF-file metadata incomplete.")}}if(this.col.chrom===null){console.log("TabularButtonTrackster : Chromosome column undefined.");return}if(typeof k.model.attributes.id==="undefined"){console.log("TabularButtonTrackster : Dataset identification is missing.")}else{this.dataset_id=k.model.attributes.id}if(typeof k.model.attributes.url_viz==="undefined"){console.log("TabularButtonTrackster : Url for visualization controller is missing.")}else{this.url_viz=k.model.attributes.url_viz}if(typeof k.model.attributes.genome_build!=="undefined"){this.genome_build=k.model.attributes.genome_build}var i=new IconButtonView({model:new IconButton({title:"Visualize",icon_class:"chart_curve",id:"btn_viz"})});this.$el.append(i.render().$el);$("#btn_viz").hide()},events:{"mouseover tr":"btn_viz_show",mouseleave:"btn_viz_hide"},btn_viz_show:function(n){function m(s){return !isNaN(parseFloat(s))&&isFinite(s)}if(this.col.chrom===null){return}var r=$(n.target).parent();var o=r.children().eq(this.col.chrom).html();var i=r.children().eq(this.col.start).html();var k=this.col.end?r.children().eq(this.col.end).html():i;if(!o.match("^#")&&o!==""&&m(i)){var q={dataset_id:this.dataset_id,gene_region:o+":"+i+"-"+k};var l=r.offset();var j=l.left-10;var p=l.top-$(window).scrollTop();$("#btn_viz").css({position:"fixed",top:p+"px",left:j+"px"});$("#btn_viz").off("click");$("#btn_viz").click(this.create_trackster_action(this.url_viz,q,this.genome_build));$("#btn_viz").show()}else{$("#btn_viz").hide()}},btn_viz_hide:function(){$("#btn_viz").hide()},create_trackster_action:function(i,k,j){return function(){var l={};if(j){l["f-dbkey"]=j}$.ajax({url:i+"/list_tracks?"+$.param(l),dataType:"html",error:function(){alert(("Could not add this dataset to browser")+".")},success:function(m){var n=window.parent;n.show_modal(("View Data in a New or Saved Visualization"),"",{Cancel:function(){n.hide_modal()},"View in saved visualization":function(){n.show_modal(("Add Data to Saved Visualization"),m,{Cancel:function(){n.hide_modal()},"Add to visualization":function(){$(n.document).find("input[name=id]:checked").each(function(){var o=$(this).val();k.id=o;n.Galaxy.frame_manager.frame_new({title:"Trackster",type:"url",content:i+"/trackster?"+$.param(k)});n.hide_modal()})}})},"View in new visualization":function(){var o=i+"/trackster?"+$.param(k);n.Galaxy.frame_manager.frame_new({title:"Trackster",type:"url",content:o});n.hide_modal()}})}});return false}}});var a=function(l,j,m,i){var k=new j({model:new l(m)});k.render();if(i){i.append(k.$el)}return k};var h=function(k,i){var j=$("<div/>").appendTo(i);return new f({el:j,model:new c(k)}).render()};return{Dataset:e,TabularDataset:c,DatasetCollection:g,TabularDatasetChunkedView:f,createTabularDatasetChunkedView:h}});
\ No newline at end of file
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/packed/mvc/dataset/hda-base.js
--- a/static/scripts/packed/mvc/dataset/hda-base.js
+++ b/static/scripts/packed/mvc/dataset/hda-base.js
@@ -1,1 +1,1 @@
-var HDABaseView=Backbone.View.extend(LoggableMixin).extend({tagName:"div",className:"historyItemContainer",initialize:function(a){if(a.logger){this.logger=this.model.logger=a.logger}this.log(this+".initialize:",a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton];if(!a.urlTemplates){throw ("HDAView needs urlTemplates on initialize")}this.urlTemplates=a.urlTemplates;this.expanded=a.expanded||false;this.model.bind("change",function(d,c){var b=_.omit(this.model.changedAttributes(),"display_apps","display_types");if(_.keys(b).length){this.render()}else{if(this.expanded){this._render_displayApps()}}},this)},render:function(){var b=this,e=this.model.get("id"),c=this.model.get("state"),a=$("<div/>").attr("id","historyItem-"+e),d=(this.$el.children().size()===0);this.$el.attr("id","historyItemContainer-"+e);this.urls=this._renderUrls(this.urlTemplates,this.model.toJSON());a.addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+c);a.append(this._render_warnings());a.append(this._render_titleBar());this._setUpBehaviors(a);this.body=$(this._render_body());a.append(this.body);this.$el.fadeOut("fast",function(){b.$el.children().remove();b.$el.append(a).fadeIn("fast",function(){b.log(b+" rendered:",b.$el);var f="rendered";if(d){f+=":initial"}else{if(b.model.inReadyState()){f+=":ready"}}b.trigger(f)})});return this},_renderUrls:function(d,a){var b=this,c={};_.each(d,function(e,f){if(_.isObject(e)){c[f]=b._renderUrls(e,a)}else{if(f==="meta_download"){c[f]=b._renderMetaDownloadUrls(e,a)}else{try{c[f]=_.template(e,a)}catch(g){throw (b+"._renderUrls error: "+g+"\n rendering:"+e+"\n with "+JSON.stringify(a))}}}});return c},_renderMetaDownloadUrls:function(b,a){return _.map(a.meta_files,function(c){return{url:_.template(b,{id:a.id,file_type:c.file_type}),file_type:c.file_type}})},_setUpBehaviors:function(a){a=a||this.$el;make_popup_menus(a);a.find(".tooltip").tooltip({placement:"bottom"})},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());return a},_render_displayButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NEW)||(!this.model.get("accessible"))){this.displayButton=null;return null}var b={icon_class:"display",target:"galaxy_main"};if(this.model.get("purged")){b.enabled=false;b.title=_l("Cannot display datasets removed from disk")}else{if(this.model.get("state")===HistoryDatasetAssociation.STATES.UPLOAD){b.enabled=false;b.title=_l("This dataset must finish uploading before it can be viewed")}else{b.title=_l("View data");b.href=this.urls.display;var a=this;b.on_click=function(){parent.frame_manager.frame_new({title:"Data Viewer",type:"url",location:"center",content:a.urls.display})}}}this.displayButton=new IconButtonView({model:new IconButton(b)});return this.displayButton.render().$el},_render_titleLink:function(){return $(jQuery.trim(HDABaseView.templates.titleLink(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});return HDABaseView.templates.hdaSummary(a)},_render_primaryActionButtons:function(c){var a=this,b=$("<div/>").attr("id","primary-actions-"+this.model.get("id"));_.each(c,function(d){b.append(d.call(a))});return b},_render_downloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}var a=HDABaseView.templates.downloadLinks(_.extend(this.model.toJSON(),{urls:this.urls}));return $(a.trim())},_render_showParamsButton:function(){this.showParamsButton=new IconButtonView({model:new IconButton({title:_l("View details"),href:this.urls.show_params,target:"galaxy_main",icon_class:"information"})});return this.showParamsButton.render().$el},_render_displayAppArea:function(){return $("<div/>").addClass("display-apps")},_render_displayApps:function(c){c=c||this.$el;var d=c.find("div.display-apps"),a=this.model.get("display_types"),b=this.model.get("display_apps");if((!this.model.hasData())||(!c||!c.length)||(!d.length)){return}d.html(null);if(!_.isEmpty(a)){d.append(HDABaseView.templates.displayApps({displayApps:a}))}if(!_.isEmpty(b)){d.append(HDABaseView.templates.displayApps({displayApps:b}))}},_render_peek:function(){var a=this.model.get("peek");if(!a){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(a))},_render_body:function(){var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: none");if(this.expanded){this._render_body_html(a);a.css("display","block")}return a},_render_body_html:function(a){a.html("");switch(this.model.get("state")){case HistoryDatasetAssociation.STATES.NEW:this._render_body_new(a);break;case HistoryDatasetAssociation.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryDatasetAssociation.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryDatasetAssociation.STATES.PAUSED:this._render_body_paused(a);break;case HistoryDatasetAssociation.STATES.QUEUED:this._render_body_queued(a);break;case HistoryDatasetAssociation.STATES.RUNNING:this._render_body_running(a);break;case HistoryDatasetAssociation.STATES.ERROR:this._render_body_error(a);break;case HistoryDatasetAssociation.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryDatasetAssociation.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryDatasetAssociation.STATES.EMPTY:this._render_body_empty(a);break;case HistoryDatasetAssociation.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryDatasetAssociation.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+this.model.get("state")+'".</div>'))}a.append('<div style="clear: both"></div>');this._setUpBehaviors(a)},_render_body_new:function(b){var a=_l("This is a new dataset and not all of its data are available yet");b.append($("<div>"+_l(a)+"</div>"))},_render_body_not_viewable:function(a){a.append($("<div>"+_l("You do not have permission to view dataset")+"</div>"))},_render_body_uploading:function(a){a.append($("<div>"+_l("Dataset is uploading")+"</div>"))},_render_body_queued:function(a){a.append($("<div>"+_l("Job is waiting to run")+"</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_paused:function(a){a.append($("<div>"+_l("Job is paused. Use the history menu to resume")+"</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_running:function(a){a.append("<div>"+_l("Job is currently running")+"</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append((_l("An error occurred with this dataset")+": <i>"+$.trim(this.model.get("misc_info"))+"</i>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers.concat([this._render_downloadButton])))},_render_body_discarded:function(a){a.append("<div>"+_l("The job creating this dataset was cancelled before completion")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_setting_metadata:function(a){a.append($("<div>"+_l("Metadata is being auto-detected")+".</div>"))},_render_body_empty:function(a){a.append($("<div>"+_l("No data")+": <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_failed_metadata:function(a){a.append($(HDABaseView.templates.failedMetadata(_.extend(this.model.toJSON(),{urls:this.urls}))));this._render_body_ok(a)},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));a.append('<div class="clear"/>');a.append(this._render_displayAppArea());this._render_displayApps(a);a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility"},toggleBodyVisibility:function(c,a){var b=this;this.expanded=(a===undefined)?(!this.body.is(":visible")):(a);if(this.expanded){b._render_body_html(b.body);this.body.slideDown("fast",function(){b.trigger("body-expanded",b.model.get("id"))})}else{this.body.slideUp("fast",function(){b.trigger("body-collapsed",b.model.get("id"))})}},remove:function(b){var a=this;this.$el.fadeOut("fast",function(){a.$el.remove();a.off();if(b){b()}})},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDABaseView("+a+")"}});HDABaseView.templates={warningMsg:Handlebars.templates["template-warningmessagesmall"],messages:Handlebars.templates["template-hda-warning-messages"],titleLink:Handlebars.templates["template-hda-titleLink"],hdaSummary:Handlebars.templates["template-hda-hdaSummary"],downloadLinks:Handlebars.templates["template-hda-downloadLinks"],failedMetadata:Handlebars.templates["template-hda-failedMetadata"],displayApps:Handlebars.templates["template-hda-displayApps"]};
\ No newline at end of file
+var HDABaseView=Backbone.View.extend(LoggableMixin).extend({tagName:"div",className:"historyItemContainer",initialize:function(a){if(a.logger){this.logger=this.model.logger=a.logger}this.log(this+".initialize:",a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton];if(!a.urlTemplates){throw ("HDAView needs urlTemplates on initialize")}this.urlTemplates=a.urlTemplates;this.expanded=a.expanded||false;this.model.bind("change",function(d,c){var b=_.omit(this.model.changedAttributes(),"display_apps","display_types");if(_.keys(b).length){this.render()}else{if(this.expanded){this._render_displayApps()}}},this)},render:function(){var b=this,e=this.model.get("id"),c=this.model.get("state"),a=$("<div/>").attr("id","historyItem-"+e),d=(this.$el.children().size()===0);this.$el.attr("id","historyItemContainer-"+e);this.urls=this._renderUrls(this.urlTemplates,this.model.toJSON());a.addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+c);a.append(this._render_warnings());a.append(this._render_titleBar());this._setUpBehaviors(a);this.body=$(this._render_body());a.append(this.body);this.$el.fadeOut("fast",function(){b.$el.children().remove();b.$el.append(a).fadeIn("fast",function(){b.log(b+" rendered:",b.$el);var f="rendered";if(d){f+=":initial"}else{if(b.model.inReadyState()){f+=":ready"}}b.trigger(f)})});return this},_renderUrls:function(d,a){var b=this,c={};_.each(d,function(e,f){if(_.isObject(e)){c[f]=b._renderUrls(e,a)}else{if(f==="meta_download"){c[f]=b._renderMetaDownloadUrls(e,a)}else{try{c[f]=_.template(e,a)}catch(g){throw (b+"._renderUrls error: "+g+"\n rendering:"+e+"\n with "+JSON.stringify(a))}}}});return c},_renderMetaDownloadUrls:function(b,a){return _.map(a.meta_files,function(c){return{url:_.template(b,{id:a.id,file_type:c.file_type}),file_type:c.file_type}})},_setUpBehaviors:function(a){a=a||this.$el;make_popup_menus(a);a.find(".tooltip").tooltip({placement:"bottom"})},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());return a},_render_displayButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NEW)||(!this.model.get("accessible"))){this.displayButton=null;return null}var b={icon_class:"display",target:"galaxy_main"};if(this.model.get("purged")){b.enabled=false;b.title=_l("Cannot display datasets removed from disk")}else{if(this.model.get("state")===HistoryDatasetAssociation.STATES.UPLOAD){b.enabled=false;b.title=_l("This dataset must finish uploading before it can be viewed")}else{b.title=_l("View data");b.href=this.urls.display;var a=this;b.on_click=function(){Galaxy.frame_manager.frame_new({title:"Data Viewer",type:"url",location:"center",content:a.urls.display})}}}this.displayButton=new IconButtonView({model:new IconButton(b)});return this.displayButton.render().$el},_render_titleLink:function(){return $(jQuery.trim(HDABaseView.templates.titleLink(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});return HDABaseView.templates.hdaSummary(a)},_render_primaryActionButtons:function(c){var a=this,b=$("<div/>").attr("id","primary-actions-"+this.model.get("id"));_.each(c,function(d){b.append(d.call(a))});return b},_render_downloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}var a=HDABaseView.templates.downloadLinks(_.extend(this.model.toJSON(),{urls:this.urls}));return $(a.trim())},_render_showParamsButton:function(){this.showParamsButton=new IconButtonView({model:new IconButton({title:_l("View details"),href:this.urls.show_params,target:"galaxy_main",icon_class:"information"})});return this.showParamsButton.render().$el},_render_displayAppArea:function(){return $("<div/>").addClass("display-apps")},_render_displayApps:function(c){c=c||this.$el;var d=c.find("div.display-apps"),a=this.model.get("display_types"),b=this.model.get("display_apps");if((!this.model.hasData())||(!c||!c.length)||(!d.length)){return}d.html(null);if(!_.isEmpty(a)){d.append(HDABaseView.templates.displayApps({displayApps:a}))}if(!_.isEmpty(b)){d.append(HDABaseView.templates.displayApps({displayApps:b}))}},_render_peek:function(){var a=this.model.get("peek");if(!a){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(a))},_render_body:function(){var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: none");if(this.expanded){this._render_body_html(a);a.css("display","block")}return a},_render_body_html:function(a){a.html("");switch(this.model.get("state")){case HistoryDatasetAssociation.STATES.NEW:this._render_body_new(a);break;case HistoryDatasetAssociation.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryDatasetAssociation.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryDatasetAssociation.STATES.PAUSED:this._render_body_paused(a);break;case HistoryDatasetAssociation.STATES.QUEUED:this._render_body_queued(a);break;case HistoryDatasetAssociation.STATES.RUNNING:this._render_body_running(a);break;case HistoryDatasetAssociation.STATES.ERROR:this._render_body_error(a);break;case HistoryDatasetAssociation.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryDatasetAssociation.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryDatasetAssociation.STATES.EMPTY:this._render_body_empty(a);break;case HistoryDatasetAssociation.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryDatasetAssociation.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+this.model.get("state")+'".</div>'))}a.append('<div style="clear: both"></div>');this._setUpBehaviors(a)},_render_body_new:function(b){var a=_l("This is a new dataset and not all of its data are available yet");b.append($("<div>"+_l(a)+"</div>"))},_render_body_not_viewable:function(a){a.append($("<div>"+_l("You do not have permission to view dataset")+"</div>"))},_render_body_uploading:function(a){a.append($("<div>"+_l("Dataset is uploading")+"</div>"))},_render_body_queued:function(a){a.append($("<div>"+_l("Job is waiting to run")+"</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_paused:function(a){a.append($("<div>"+_l("Job is paused. Use the history menu to resume")+"</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_running:function(a){a.append("<div>"+_l("Job is currently running")+"</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append((_l("An error occurred with this dataset")+": <i>"+$.trim(this.model.get("misc_info"))+"</i>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers.concat([this._render_downloadButton])))},_render_body_discarded:function(a){a.append("<div>"+_l("The job creating this dataset was cancelled before completion")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_setting_metadata:function(a){a.append($("<div>"+_l("Metadata is being auto-detected")+".</div>"))},_render_body_empty:function(a){a.append($("<div>"+_l("No data")+": <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_failed_metadata:function(a){a.append($(HDABaseView.templates.failedMetadata(_.extend(this.model.toJSON(),{urls:this.urls}))));this._render_body_ok(a)},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));a.append('<div class="clear"/>');a.append(this._render_displayAppArea());this._render_displayApps(a);a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility"},toggleBodyVisibility:function(c,a){var b=this;this.expanded=(a===undefined)?(!this.body.is(":visible")):(a);if(this.expanded){b._render_body_html(b.body);this.body.slideDown("fast",function(){b.trigger("body-expanded",b.model.get("id"))})}else{this.body.slideUp("fast",function(){b.trigger("body-collapsed",b.model.get("id"))})}},remove:function(b){var a=this;this.$el.fadeOut("fast",function(){a.$el.remove();a.off();if(b){b()}})},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDABaseView("+a+")"}});HDABaseView.templates={warningMsg:Handlebars.templates["template-warningmessagesmall"],messages:Handlebars.templates["template-hda-warning-messages"],titleLink:Handlebars.templates["template-hda-titleLink"],hdaSummary:Handlebars.templates["template-hda-hdaSummary"],downloadLinks:Handlebars.templates["template-hda-downloadLinks"],failedMetadata:Handlebars.templates["template-hda-failedMetadata"],displayApps:Handlebars.templates["template-hda-displayApps"]};
\ No newline at end of file
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/packed/mvc/dataset/hda-edit.js
--- a/static/scripts/packed/mvc/dataset/hda-edit.js
+++ b/static/scripts/packed/mvc/dataset/hda-edit.js
@@ -1,1 +1,1 @@
-var HDAEditView=HDABaseView.extend(LoggableMixin).extend({initialize:function(a){HDABaseView.prototype.initialize.call(this,a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton,this._render_rerunButton]},_setUpBehaviors:function(c){HDABaseView.prototype._setUpBehaviors.call(this,c);var a=this,b=this.urls.purge,d=c.find("#historyItemPurger-"+this.model.get("id"));if(d){d.attr("href",["javascript","void(0)"].join(":"));d.click(function(e){var f=jQuery.ajax(b);f.success(function(i,g,h){a.model.set("purged",true);a.trigger("purged",a)});f.error(function(h,g,i){a.trigger("error",_l("Unable to purge this dataset"),h,g,i)})})}},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());a.append(this._render_editButton());a.append(this._render_deleteButton());return a},_render_editButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NEW)||(this.model.get("state")===HistoryDatasetAssociation.STATES.UPLOAD)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.editButton=null;return null}var c=this.model.get("purged"),a=this.model.get("deleted"),b={title:_l("Edit Attributes"),href:this.urls.edit,target:"galaxy_main",icon_class:"edit"};if(a||c){b.enabled=false;if(c){b.title=_l("Cannot edit attributes of datasets removed from disk")}else{if(a){b.title=_l("Undelete dataset to edit attributes")}}}this.editButton=new IconButtonView({model:new IconButton(b)});return this.editButton.render().$el},_render_deleteButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NEW)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.deleteButton=null;return null}var a=this,b=a.urls["delete"],c={title:_l("Delete"),href:b,id:"historyItemDeleter-"+this.model.get("id"),icon_class:"delete",on_click:function(){$.ajax({url:b,type:"POST",error:function(){a.$el.show()},success:function(){a.model.set({deleted:true})}})}};if(this.model.get("deleted")||this.model.get("purged")){c={title:_l("Dataset is already deleted"),icon_class:"delete",enabled:false}}this.deleteButton=new IconButtonView({model:new IconButton(c)});return this.deleteButton.render().$el},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){_.extend(a,{dbkey_unknown_and_editable:true})}return HDABaseView.templates.hdaSummary(a)},_render_errButton:function(){if(this.model.get("state")!==HistoryDatasetAssociation.STATES.ERROR){this.errButton=null;return null}this.errButton=new IconButtonView({model:new IconButton({title:_l("View or report this error"),href:this.urls.report_error,target:"galaxy_main",icon_class:"bug"})});return this.errButton.render().$el},_render_rerunButton:function(){this.rerunButton=new IconButtonView({model:new IconButton({title:_l("Run this job again"),href:this.urls.rerun,target:"galaxy_main",icon_class:"arrow-circle"})});return this.rerunButton.render().$el},_render_visualizationsButton:function(){var a=this.model.get("visualizations");if((!this.model.hasData())||(_.isEmpty(a))){this.visualizationsButton=null;return null}if(_.isObject(a[0])){return this._render_visualizationsFrameworkButton(a)}if(!this.urls.visualization){this.visualizationsButton=null;return null}var c=this.model.get("dbkey"),f=this.urls.visualization,d={},g={dataset_id:this.model.get("id"),hda_ldda:"hda"};if(c){g.dbkey=c}this.visualizationsButton=new IconButtonView({model:new IconButton({title:_l("Visualize"),href:this.urls.visualization,icon_class:"chart_curve"})});var b=this.visualizationsButton.render().$el;b.addClass("visualize-icon");function e(h){switch(h){case"trackster":return create_trackster_action_fn(f,g,c);case"scatterplot":return create_scatterplot_action_fn(f,g);default:return function(){parent.frame_manager.frame_new({title:"Visualization",type:"url",content:f+"/"+h+"?"+$.param(g)})}}}if(a.length===1){b.attr("title",a[0]);b.click(e(a[0]))}else{_.each(a,function(i){var h=i.charAt(0).toUpperCase()+i.slice(1);d[_l(h)]=e(i)});make_popupmenu(b,d)}return b},_render_visualizationsFrameworkButton:function(a){if(!(this.model.hasData())||!(a&&!_.isEmpty(a))){this.visualizationsButton=null;return null}this.visualizationsButton=new IconButtonView({model:new IconButton({title:_l("Visualize"),icon_class:"chart_curve"})});var c=this.visualizationsButton.render().$el;c.addClass("visualize-icon");if(_.keys(a).length===1){c.attr("title",_.keys(a)[0]);c.attr("href",_.values(a)[0])}else{var d=[];_.each(a,function(e){d.push(e)});var b=new PopupMenu(c,d)}return c},_render_secondaryActionButtons:function(b){var c=$("<div/>"),a=this;c.attr("style","float: right;").attr("id","secondary-actions-"+this.model.get("id"));_.each(b,function(d){c.append(d.call(a))});return c},_render_tagButton:function(){if(!(this.model.hasData())||(!this.urls.tags.get)){this.tagButton=null;return null}this.tagButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset tags"),target:"galaxy_main",href:this.urls.tags.get,icon_class:"tags"})});return this.tagButton.render().$el},_render_annotateButton:function(){if(!(this.model.hasData())||(!this.urls.annotation.get)){this.annotateButton=null;return null}this.annotateButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset annotation"),target:"galaxy_main",icon_class:"annotate"})});return this.annotateButton.render().$el},_render_tagArea:function(){if(!this.urls.tags.set){return null}return $(HDAEditView.templates.tagArea(_.extend(this.model.toJSON(),{urls:this.urls})).trim())},_render_annotationArea:function(){if(!this.urls.annotation.get){return null}return $(HDAEditView.templates.annotationArea(_.extend(this.model.toJSON(),{urls:this.urls})).trim())},_render_body_error:function(a){HDABaseView.prototype._render_body_error.call(this,a);var b=a.find("#primary-actions-"+this.model.get("id"));b.prepend(this._render_errButton())},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton,this._render_visualizationsButton]));a.append(this._render_secondaryActionButtons([this._render_tagButton,this._render_annotateButton]));a.append('<div class="clear"/>');a.append(this._render_tagArea());a.append(this._render_annotationArea());a.append(this._render_displayAppArea());this._render_displayApps(a);a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility","click a.icon-button.tags":"loadAndDisplayTags","click a.icon-button.annotate":"loadAndDisplayAnnotation"},loadAndDisplayTags:function(c){this.log(this+".loadAndDisplayTags",c);var a=this,d=this.$el.find(".tag-area"),b=d.find(".tag-elt");if(d.is(":hidden")){if(!jQuery.trim(b.html())){$.ajax({url:this.urls.tags.get,error:function(g,e,f){a.log("Tagging failed",g,e,f);a.trigger("error",_l("Tagging failed"),g,e,f)},success:function(e){b.html(e);b.find(".tooltip").tooltip();d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},loadAndDisplayAnnotation:function(b){this.log(this+".loadAndDisplayAnnotation",b);var d=this.$el.find(".annotation-area"),c=d.find(".annotation-elt"),a=this.urls.annotation.set;if(d.is(":hidden")){if(!jQuery.trim(c.html())){$.ajax({url:this.urls.annotation.get,error:function(){view.log("Annotation failed",xhr,status,error);view.trigger("error",_l("Annotation failed"),xhr,status,error)},success:function(e){if(e===""){e="<em>"+_l("Describe or add notes to dataset")+"</em>"}c.html(e);d.find(".tooltip").tooltip();async_save_text(c.attr("id"),c.attr("id"),a,"new_annotation",18,true,4);d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDAView("+a+")"}});HDAEditView.templates={tagArea:Handlebars.templates["template-hda-tagArea"],annotationArea:Handlebars.templates["template-hda-annotationArea"]};function create_scatterplot_action_fn(a,b){action=function(){parent.frame_manager.frame_new({title:"Scatterplot",type:"url",content:a+"/scatterplot?"+$.param(b),location:"center"});$("div.popmenu-wrapper").remove();return false};return action}function create_trackster_action_fn(a,c,b){return function(){var d={};if(b){d["f-dbkey"]=b}$.ajax({url:a+"/list_tracks?"+$.param(d),dataType:"html",error:function(){alert(_l("Could not add this dataset to browser")+".")},success:function(e){var f=window.parent;f.show_modal(_l("View Data in a New or Saved Visualization"),"",{Cancel:function(){f.hide_modal()},"View in saved visualization":function(){f.show_modal(_l("Add Data to Saved Visualization"),e,{Cancel:function(){f.hide_modal()},"Add to visualization":function(){$(f.document).find("input[name=id]:checked").each(function(){var g=$(this).val();c.id=g;f.hide_modal();f.frame_manager.frame_new({title:"Trackster",type:"url",content:a+"/trackster?"+$.param(c)})})}})},"View in new visualization":function(){f.hide_modal();f.frame_manager.frame_new({title:"Trackster",type:"url",content:a+"/trackster?"+$.param(c)})}})}});return false}};
\ No newline at end of file
+var HDAEditView=HDABaseView.extend(LoggableMixin).extend({initialize:function(a){HDABaseView.prototype.initialize.call(this,a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton,this._render_rerunButton]},_setUpBehaviors:function(c){HDABaseView.prototype._setUpBehaviors.call(this,c);var a=this,b=this.urls.purge,d=c.find("#historyItemPurger-"+this.model.get("id"));if(d){d.attr("href",["javascript","void(0)"].join(":"));d.click(function(e){var f=jQuery.ajax(b);f.success(function(i,g,h){a.model.set("purged",true);a.trigger("purged",a)});f.error(function(h,g,i){a.trigger("error",_l("Unable to purge this dataset"),h,g,i)})})}},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());a.append(this._render_editButton());a.append(this._render_deleteButton());return a},_render_editButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NEW)||(this.model.get("state")===HistoryDatasetAssociation.STATES.UPLOAD)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.editButton=null;return null}var c=this.model.get("purged"),a=this.model.get("deleted"),b={title:_l("Edit Attributes"),href:this.urls.edit,target:"galaxy_main",icon_class:"edit"};if(a||c){b.enabled=false;if(c){b.title=_l("Cannot edit attributes of datasets removed from disk")}else{if(a){b.title=_l("Undelete dataset to edit attributes")}}}this.editButton=new IconButtonView({model:new IconButton(b)});return this.editButton.render().$el},_render_deleteButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NEW)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.deleteButton=null;return null}var a=this,b=a.urls["delete"],c={title:_l("Delete"),href:b,id:"historyItemDeleter-"+this.model.get("id"),icon_class:"delete",on_click:function(){$.ajax({url:b,type:"POST",error:function(){a.$el.show()},success:function(){a.model.set({deleted:true})}})}};if(this.model.get("deleted")||this.model.get("purged")){c={title:_l("Dataset is already deleted"),icon_class:"delete",enabled:false}}this.deleteButton=new IconButtonView({model:new IconButton(c)});return this.deleteButton.render().$el},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){_.extend(a,{dbkey_unknown_and_editable:true})}return HDABaseView.templates.hdaSummary(a)},_render_errButton:function(){if(this.model.get("state")!==HistoryDatasetAssociation.STATES.ERROR){this.errButton=null;return null}this.errButton=new IconButtonView({model:new IconButton({title:_l("View or report this error"),href:this.urls.report_error,target:"galaxy_main",icon_class:"bug"})});return this.errButton.render().$el},_render_rerunButton:function(){this.rerunButton=new IconButtonView({model:new IconButton({title:_l("Run this job again"),href:this.urls.rerun,target:"galaxy_main",icon_class:"arrow-circle"})});return this.rerunButton.render().$el},_render_visualizationsButton:function(){var a=this.model.get("visualizations");if((!this.model.hasData())||(_.isEmpty(a))){this.visualizationsButton=null;return null}if(_.isObject(a[0])){return this._render_visualizationsFrameworkButton(a)}if(!this.urls.visualization){this.visualizationsButton=null;return null}var c=this.model.get("dbkey"),f=this.urls.visualization,d={},g={dataset_id:this.model.get("id"),hda_ldda:"hda"};if(c){g.dbkey=c}this.visualizationsButton=new IconButtonView({model:new IconButton({title:_l("Visualize"),href:this.urls.visualization,icon_class:"chart_curve"})});var b=this.visualizationsButton.render().$el;b.addClass("visualize-icon");function e(h){switch(h){case"trackster":return create_trackster_action_fn(f,g,c);case"scatterplot":return create_scatterplot_action_fn(f,g);default:return function(){Galaxy.frame_manager.frame_new({title:"Visualization",type:"url",content:f+"/"+h+"?"+$.param(g)})}}}if(a.length===1){b.attr("title",a[0]);b.click(e(a[0]))}else{_.each(a,function(i){var h=i.charAt(0).toUpperCase()+i.slice(1);d[_l(h)]=e(i)});make_popupmenu(b,d)}return b},_render_visualizationsFrameworkButton:function(a){if(!(this.model.hasData())||!(a&&!_.isEmpty(a))){this.visualizationsButton=null;return null}this.visualizationsButton=new IconButtonView({model:new IconButton({title:_l("Visualize"),icon_class:"chart_curve"})});var c=this.visualizationsButton.render().$el;c.addClass("visualize-icon");if(_.keys(a).length===1){c.attr("title",_.keys(a)[0]);c.attr("href",_.values(a)[0])}else{var d=[];_.each(a,function(e){d.push(e)});var b=new PopupMenu(c,d)}return c},_render_secondaryActionButtons:function(b){var c=$("<div/>"),a=this;c.attr("style","float: right;").attr("id","secondary-actions-"+this.model.get("id"));_.each(b,function(d){c.append(d.call(a))});return c},_render_tagButton:function(){if(!(this.model.hasData())||(!this.urls.tags.get)){this.tagButton=null;return null}this.tagButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset tags"),target:"galaxy_main",href:this.urls.tags.get,icon_class:"tags"})});return this.tagButton.render().$el},_render_annotateButton:function(){if(!(this.model.hasData())||(!this.urls.annotation.get)){this.annotateButton=null;return null}this.annotateButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset annotation"),target:"galaxy_main",icon_class:"annotate"})});return this.annotateButton.render().$el},_render_tagArea:function(){if(!this.urls.tags.set){return null}return $(HDAEditView.templates.tagArea(_.extend(this.model.toJSON(),{urls:this.urls})).trim())},_render_annotationArea:function(){if(!this.urls.annotation.get){return null}return $(HDAEditView.templates.annotationArea(_.extend(this.model.toJSON(),{urls:this.urls})).trim())},_render_body_error:function(a){HDABaseView.prototype._render_body_error.call(this,a);var b=a.find("#primary-actions-"+this.model.get("id"));b.prepend(this._render_errButton())},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton,this._render_visualizationsButton]));a.append(this._render_secondaryActionButtons([this._render_tagButton,this._render_annotateButton]));a.append('<div class="clear"/>');a.append(this._render_tagArea());a.append(this._render_annotationArea());a.append(this._render_displayAppArea());this._render_displayApps(a);a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility","click a.icon-button.tags":"loadAndDisplayTags","click a.icon-button.annotate":"loadAndDisplayAnnotation"},loadAndDisplayTags:function(c){this.log(this+".loadAndDisplayTags",c);var a=this,d=this.$el.find(".tag-area"),b=d.find(".tag-elt");if(d.is(":hidden")){if(!jQuery.trim(b.html())){$.ajax({url:this.urls.tags.get,error:function(g,e,f){a.log("Tagging failed",g,e,f);a.trigger("error",_l("Tagging failed"),g,e,f)},success:function(e){b.html(e);b.find(".tooltip").tooltip();d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},loadAndDisplayAnnotation:function(b){this.log(this+".loadAndDisplayAnnotation",b);var d=this.$el.find(".annotation-area"),c=d.find(".annotation-elt"),a=this.urls.annotation.set;if(d.is(":hidden")){if(!jQuery.trim(c.html())){$.ajax({url:this.urls.annotation.get,error:function(){view.log("Annotation failed",xhr,status,error);view.trigger("error",_l("Annotation failed"),xhr,status,error)},success:function(e){if(e===""){e="<em>"+_l("Describe or add notes to dataset")+"</em>"}c.html(e);d.find(".tooltip").tooltip();async_save_text(c.attr("id"),c.attr("id"),a,"new_annotation",18,true,4);d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDAView("+a+")"}});HDAEditView.templates={tagArea:Handlebars.templates["template-hda-tagArea"],annotationArea:Handlebars.templates["template-hda-annotationArea"]};function create_scatterplot_action_fn(a,b){action=function(){Galaxy.frame_manager.frame_new({title:"Scatterplot",type:"url",content:a+"/scatterplot?"+$.param(b),location:"center"});$("div.popmenu-wrapper").remove();return false};return action}function create_trackster_action_fn(a,c,b){return function(){var d={};if(b){d["f-dbkey"]=b}$.ajax({url:a+"/list_tracks?"+$.param(d),dataType:"html",error:function(){alert(_l("Could not add this dataset to browser")+".")},success:function(e){var f=window.parent;f.show_modal(_l("View Data in a New or Saved Visualization"),"",{Cancel:function(){f.hide_modal()},"View in saved visualization":function(){f.show_modal(_l("Add Data to Saved Visualization"),e,{Cancel:function(){f.hide_modal()},"Add to visualization":function(){$(f.document).find("input[name=id]:checked").each(function(){var g=$(this).val();c.id=g;f.hide_modal();Galaxy.frame_manager.frame_new({title:"Trackster",type:"url",content:a+"/trackster?"+$.param(c)})})}})},"View in new visualization":function(){f.hide_modal();Galaxy.frame_manager.frame_new({title:"Trackster",type:"url",content:a+"/trackster?"+$.param(c)})}})}});return false}};
\ No newline at end of file
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/packed/mvc/history/history-panel.js
--- a/static/scripts/packed/mvc/history/history-panel.js
+++ b/static/scripts/packed/mvc/history/history-panel.js
@@ -1,1 +1,1 @@
-var HistoryPanel=Backbone.View.extend(LoggableMixin).extend({el:"body.historyPage",HDAView:HDAEditView,events:{"click #history-tag":"loadAndDisplayTags","click #message-container":"removeMessage"},initialize:function(a){if(a.logger){this.logger=this.model.logger=a.logger}this.log(this+".initialize:",a);if(!a.urlTemplates){throw (this+" needs urlTemplates on initialize")}if(!a.urlTemplates.history){throw (this+" needs urlTemplates.history on initialize")}if(!a.urlTemplates.hda){throw (this+" needs urlTemplates.hda on initialize")}this.urlTemplates=a.urlTemplates.history;this.hdaUrlTemplates=a.urlTemplates.hda;this._setUpWebStorage(a.initiallyExpanded,a.show_deleted,a.show_hidden);this._setUpEventHandlers();this.hdaViews={};this.urls={}},_setUpEventHandlers:function(){this.model.bind("change:nice_size",this.updateHistoryDiskSize,this);this.model.bind("error",function(d,c,b,a){this.displayMessage("error",d);this.model.attributes.error=undefined},this);this.model.hdas.bind("add",this.add,this);this.model.hdas.bind("reset",this.addAll,this);this.model.hdas.bind("change:deleted",this.handleHdaDeletionChange,this);this.model.hdas.bind("change:purged",function(a){this.model.fetch()},this);this.model.hdas.bind("state:ready",function(b,c,a){if((!b.get("visible"))&&(!this.storage.get("show_hidden"))){this.removeHdaView(b.get("id"))}},this);this.bind("error",function(d,c,b,a){this.displayMessage("error",d)});if(this.logger){this.bind("all",function(a){this.log(this+"",arguments)},this)}},_setUpWebStorage:function(b,a,c){this.storage=new PersistantStorage("HistoryView."+this.model.get("id"),{expandedHdas:{},show_deleted:false,show_hidden:false});this.log(this+" (prev) storage:",JSON.stringify(this.storage.get(),null,2));if(b){this.storage.set("exandedHdas",b)}if((a===true)||(a===false)){this.storage.set("show_deleted",a)}if((c===true)||(c===false)){this.storage.set("show_hidden",c)}this.show_deleted=this.storage.get("show_deleted");this.show_hidden=this.storage.get("show_hidden");this.log(this+" (init'd) storage:",this.storage.get())},add:function(a){this.render()},addAll:function(){this.render()},handleHdaDeletionChange:function(a){if(a.get("deleted")&&!this.storage.get("show_deleted")){this.removeHdaView(a.get("id"))}},removeHdaView:function(c,b){var a=this.hdaViews[c];if(!a){return}a.remove(b);delete this.hdaViews[c];if(_.isEmpty(this.hdaViews)){this.render()}},render:function(){var b=this,d=b.toString()+".set-up",c=$("<div/>"),a=this.model.toJSON(),e=(this.$el.children().size()===0);a.urls=this._renderUrls(a);c.append(HistoryPanel.templates.historyPanel(a));c.find(".tooltip").tooltip({placement:"bottom"});if(!this.model.hdas.length||!this.renderItems(c.find("#"+this.model.get("id")+"-datasets"))){c.find("#emptyHistoryMessage").show()}$(b).queue(d,function(f){b.$el.fadeOut("fast",function(){f()})});$(b).queue(d,function(f){b.$el.html("");b.$el.append(c.children());b.$el.fadeIn("fast",function(){f()})});$(b).queue(d,function(f){this.log(b+" rendered:",b.$el);b._setUpBehaviours();if(e){b.trigger("rendered:initial")}else{b.trigger("rendered")}f()});$(b).dequeue(d);return this},_renderUrls:function(a){var b=this;b.urls={};_.each(this.urlTemplates,function(d,c){b.urls[c]=_.template(d,a)});return b.urls},renderItems:function(b){this.hdaViews={};var a=this,c=this.model.hdas.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"));_.each(c,function(f){var e=f.get("id"),d=a.storage.get("expandedHdas").get(e);a.hdaViews[e]=new a.HDAView({model:f,expanded:d,urlTemplates:a.hdaUrlTemplates,logger:a.logger});a._setUpHdaListeners(a.hdaViews[e]);b.prepend(a.hdaViews[e].render().$el)});return c.length},_setUpHdaListeners:function(b){var a=this;b.bind("body-expanded",function(c){a.storage.get("expandedHdas").set(c,true)});b.bind("body-collapsed",function(c){a.storage.get("expandedHdas").deleteKey(c)});b.bind("error",function(f,e,c,d){a.displayMessage("error",f)})},_setUpBehaviours:function(){if(!(this.model.get("user")&&this.model.get("user").email)){return}var a=this.$("#history-annotation-area");this.$("#history-annotate").click(function(){if(a.is(":hidden")){a.slideDown("fast")}else{a.slideUp("fast")}return false});async_save_text("history-name-container","history-name",this.urls.rename,"new_name",18);async_save_text("history-annotation-container","history-annotation",this.urls.annotate,"new_annotation",18,true,4)},updateHistoryDiskSize:function(){this.$el.find("#history-size").text(this.model.get("nice_size"))},showQuotaMessage:function(){var a=this.$el.find("#quota-message-container");if(a.is(":hidden")){a.slideDown("fast")}},hideQuotaMessage:function(){var a=this.$el.find("#quota-message-container");if(!a.is(":hidden")){a.slideUp("fast")}},toggleShowDeleted:function(){this.storage.set("show_deleted",!this.storage.get("show_deleted"));this.render();return this.storage.get("show_deleted")},toggleShowHidden:function(){this.storage.set("show_hidden",!this.storage.get("show_hidden"));this.render();return this.storage.get("show_hidden")},collapseAllHdaBodies:function(){_.each(this.hdaViews,function(a){a.toggleBodyVisibility(null,false)});this.storage.set("expandedHdas",{})},loadAndDisplayTags:function(d){this.log(this+".loadAndDisplayTags",d);var b=this,e=this.$el.find("#history-tag-area"),c=e.find(".tag-elt");this.log("\t tagArea",e," tagElt",c);if(e.is(":hidden")){if(!jQuery.trim(c.html())){var a=this;$.ajax({url:a.urls.tag,error:function(h,g,f){b.log("Error loading tag area html",h,g,f);b.trigger("error",_l("Tagging failed"),h,g,f)},success:function(f){c.html(f);c.find(".tooltip").tooltip();e.slideDown("fast")}})}else{e.slideDown("fast")}}else{e.slideUp("fast")}return false},displayMessage:function(c,d){var b=this.$el.find("#message-container"),a=$("<div/>").addClass(c+"message").text(d);b.html(a)},removeMessage:function(){var a=this.$el.find("#message-container");a.html(null)},scrollToTop:function(){$(document).scrollTop(0);return this},scrollIntoView:function(b,c){if(!c){$(document).scrollTop(b);return this}var a=window,d=this.$el.parent(),f=$(a).innerHeight(),e=(f/2)-(c/2);$(d).scrollTop(b-e);return this},scrollToId:function(b){if((!b)||(!this.hdaViews[b])){return this}var a=this.hdaViews[b].$el;this.scrollIntoView(a.offset().top,a.outerHeight());return this},scrollToHid:function(a){var b=this.model.hdas.getByHid(a);if(!b){return this}return this.scrollToId(b.id)},toString:function(){var a=this.model.get("name")||"";return"HistoryPanel("+a+")"}});HistoryPanel.templates={historyPanel:Handlebars.templates["template-history-historyPanel"]};
\ No newline at end of file
+var HistoryPanel=Backbone.View.extend(LoggableMixin).extend({el:"body.historyPage",HDAView:HDAEditView,events:{"click #history-tag":"loadAndDisplayTags","click #message-container":"removeMessage"},initialize:function(a){if(a.logger){this.logger=this.model.logger=a.logger}this.log(this+".initialize:",a);if(!a.urlTemplates){throw (this+" needs urlTemplates on initialize")}if(!a.urlTemplates.history){throw (this+" needs urlTemplates.history on initialize")}if(!a.urlTemplates.hda){throw (this+" needs urlTemplates.hda on initialize")}this.urlTemplates=a.urlTemplates.history;this.hdaUrlTemplates=a.urlTemplates.hda;this._setUpWebStorage(a.initiallyExpanded,a.show_deleted,a.show_hidden);this._setUpEventHandlers();this.hdaViews={};this.urls={}},refresh:function(){window.location=window.location},_setUpEventHandlers:function(){this.model.bind("change:nice_size",this.updateHistoryDiskSize,this);this.model.bind("error",function(d,c,b,a){this.displayMessage("error",d);this.model.attributes.error=undefined},this);this.model.hdas.bind("add",this.add,this);this.model.hdas.bind("reset",this.addAll,this);this.model.hdas.bind("change:deleted",this.handleHdaDeletionChange,this);this.model.hdas.bind("change:purged",function(a){this.model.fetch()},this);this.model.hdas.bind("state:ready",function(b,c,a){if((!b.get("visible"))&&(!this.storage.get("show_hidden"))){this.removeHdaView(b.get("id"))}},this);this.bind("error",function(d,c,b,a){this.displayMessage("error",d)});if(this.logger){this.bind("all",function(a){this.log(this+"",arguments)},this)}},_setUpWebStorage:function(b,a,c){this.storage=new PersistantStorage("HistoryView."+this.model.get("id"),{expandedHdas:{},show_deleted:false,show_hidden:false});this.log(this+" (prev) storage:",JSON.stringify(this.storage.get(),null,2));if(b){this.storage.set("exandedHdas",b)}if((a===true)||(a===false)){this.storage.set("show_deleted",a)}if((c===true)||(c===false)){this.storage.set("show_hidden",c)}this.show_deleted=this.storage.get("show_deleted");this.show_hidden=this.storage.get("show_hidden");this.log(this+" (init'd) storage:",this.storage.get())},add:function(a){this.render()},addAll:function(){this.render()},handleHdaDeletionChange:function(a){if(a.get("deleted")&&!this.storage.get("show_deleted")){this.removeHdaView(a.get("id"))}},removeHdaView:function(c,b){var a=this.hdaViews[c];if(!a){return}a.remove(b);delete this.hdaViews[c];if(_.isEmpty(this.hdaViews)){this.render()}},render:function(){var b=this,d=b.toString()+".set-up",c=$("<div/>"),a=this.model.toJSON(),e=(this.$el.children().size()===0);a.urls=this._renderUrls(a);c.append(HistoryPanel.templates.historyPanel(a));c.find(".tooltip").tooltip({placement:"bottom"});if(!this.model.hdas.length||!this.renderItems(c.find("#"+this.model.get("id")+"-datasets"))){c.find("#emptyHistoryMessage").show()}$(b).queue(d,function(f){b.$el.fadeOut("fast",function(){f()})});$(b).queue(d,function(f){b.$el.html("");b.$el.append(c.children());b.$el.fadeIn("fast",function(){f()})});$(b).queue(d,function(f){this.log(b+" rendered:",b.$el);b._setUpBehaviours();if(e){b.trigger("rendered:initial")}else{b.trigger("rendered")}f()});$(b).dequeue(d);return this},_renderUrls:function(a){var b=this;b.urls={};_.each(this.urlTemplates,function(d,c){b.urls[c]=_.template(d,a)});return b.urls},renderItems:function(b){this.hdaViews={};var a=this,c=this.model.hdas.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"));_.each(c,function(f){var e=f.get("id"),d=a.storage.get("expandedHdas").get(e);a.hdaViews[e]=new a.HDAView({model:f,expanded:d,urlTemplates:a.hdaUrlTemplates,logger:a.logger});a._setUpHdaListeners(a.hdaViews[e]);b.prepend(a.hdaViews[e].render().$el)});return c.length},_setUpHdaListeners:function(b){var a=this;b.bind("body-expanded",function(c){a.storage.get("expandedHdas").set(c,true)});b.bind("body-collapsed",function(c){a.storage.get("expandedHdas").deleteKey(c)});b.bind("error",function(f,e,c,d){a.displayMessage("error",f)})},_setUpBehaviours:function(){if(!(this.model.get("user")&&this.model.get("user").email)){return}var a=this.$("#history-annotation-area");this.$("#history-annotate").click(function(){if(a.is(":hidden")){a.slideDown("fast")}else{a.slideUp("fast")}return false});async_save_text("history-name-container","history-name",this.urls.rename,"new_name",18);async_save_text("history-annotation-container","history-annotation",this.urls.annotate,"new_annotation",18,true,4)},updateHistoryDiskSize:function(){this.$el.find("#history-size").text(this.model.get("nice_size"))},showQuotaMessage:function(){var a=this.$el.find("#quota-message-container");if(a.is(":hidden")){a.slideDown("fast")}},hideQuotaMessage:function(){var a=this.$el.find("#quota-message-container");if(!a.is(":hidden")){a.slideUp("fast")}},toggleShowDeleted:function(){this.storage.set("show_deleted",!this.storage.get("show_deleted"));this.render();return this.storage.get("show_deleted")},toggleShowHidden:function(){this.storage.set("show_hidden",!this.storage.get("show_hidden"));this.render();return this.storage.get("show_hidden")},collapseAllHdaBodies:function(){_.each(this.hdaViews,function(a){a.toggleBodyVisibility(null,false)});this.storage.set("expandedHdas",{})},loadAndDisplayTags:function(d){this.log(this+".loadAndDisplayTags",d);var b=this,e=this.$el.find("#history-tag-area"),c=e.find(".tag-elt");this.log("\t tagArea",e," tagElt",c);if(e.is(":hidden")){if(!jQuery.trim(c.html())){var a=this;$.ajax({url:a.urls.tag,error:function(h,g,f){b.log("Error loading tag area html",h,g,f);b.trigger("error",_l("Tagging failed"),h,g,f)},success:function(f){c.html(f);c.find(".tooltip").tooltip();e.slideDown("fast")}})}else{e.slideDown("fast")}}else{e.slideUp("fast")}return false},displayMessage:function(c,d){var b=this.$el.find("#message-container"),a=$("<div/>").addClass(c+"message").text(d);b.html(a)},removeMessage:function(){var a=this.$el.find("#message-container");a.html(null)},scrollToTop:function(){$(document).scrollTop(0);return this},scrollIntoView:function(b,c){if(!c){$(document).scrollTop(b);return this}var a=window,d=this.$el.parent(),f=$(a).innerHeight(),e=(f/2)-(c/2);$(d).scrollTop(b-e);return this},scrollToId:function(b){if((!b)||(!this.hdaViews[b])){return this}var a=this.hdaViews[b].$el;this.scrollIntoView(a.offset().top,a.outerHeight());return this},scrollToHid:function(a){var b=this.model.hdas.getByHid(a);if(!b){return this}return this.scrollToId(b.id)},toString:function(){var a=this.model.get("name")||"";return"HistoryPanel("+a+")"}});HistoryPanel.templates={historyPanel:Handlebars.templates["template-history-historyPanel"]};
\ No newline at end of file
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/packed/utils/galaxy.uploadbox.js
--- /dev/null
+++ b/static/scripts/packed/utils/galaxy.uploadbox.js
@@ -0,0 +1,1 @@
+(function(d){jQuery.event.props.push("dataTransfer");var c={url:"",paramname:"content",maxfilesize:2048,data:{},dragover:function(){},dragleave:function(){},initialize:function(){},start:function(){},progress:function(){},success:function(){},error:function(f,g,h){alert(h)},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+."};var a=[];var b=-1;var e=false;d.fn.uploadbox=function(n){var f=d.extend({},c,n);var l=window.File&&window.FileReader&&window.FormData&&window.XMLHttpRequest;this.append('<input id="uploadbox_input" type="file" style="display: none" multiple>');this.append('<div id="uploadbox_info"></div>');if(l){this.find("#uploadbox_info").html(f.text_default)}else{this.find("#uploadbox_info").html(f.text_degrade)}this.on("drop",i);this.on("dragover",j);this.on("dragleave",m);this.on("click",function(p){p.stopPropagation();d("#uploadbox_input").trigger(p)});d("#uploadbox_input").change(function(q){var p=q.target.files;o(p)});function i(q){if(!q.dataTransfer){return}var p=q.dataTransfer.files;o(p);q.preventDefault();return false}function j(p){p.preventDefault();f.dragover.call(this,p)}function m(p){p.stopPropagation();f.dragleave.call(this,p)}function g(p){if(p.lengthComputable){f.progress(this.index,this.file,Math.round((p.loaded*100)/p.total))}}function o(r){var q=a.length;for(var p=0;p<r.length;p++){a.push(r[p])}for(var p=q;p<a.length;p++){f.start(p,a[p],"")}if(!e){h()}}function h(){if(b+1==a.length){e=false;return}e=true;var s=++b;try{var q=new FileReader();var t=a[s];var r=t.size;var p=1048576*f.maxfilesize;q.index=s;if(r<p){q.onloadend=function(v){k(s,t)};q.onerror=function(v){f.error(s,t,f.error_default);e=false};q.readAsDataURL(t)}else{f.error(s,t,f.error_filesize);h()}}catch(u){f.error(s,t,u)}}function k(p,r){var s=new FormData();for(var q in f.data){s.append(q,f.data[q])}s.append(f.paramname,r,r.name);var t=new XMLHttpRequest();t.upload.index=p;t.upload.file=r;t.upload.addEventListener("progress",g,false);t.open("POST",f.url,true);t.setRequestHeader("Accept","application/json");t.setRequestHeader("Cache-Control","no-cache");t.setRequestHeader("X-Requested-With","XMLHttpRequest");t.send(s);t.onloadend=function(){var u=null;if(t.responseText){try{u=jQuery.parseJSON(t.responseText)}catch(v){u=t.responseText}}if(t.status<200||t.status>299){f.error(p,r,t.statusText+" (Server Code "+t.status+")");e=false}else{f.success(p,r,u);h()}}}return this}})(jQuery);
\ No newline at end of file
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/scripts/utils/galaxy.uploadbox.js
--- /dev/null
+++ b/static/scripts/utils/galaxy.uploadbox.js
@@ -0,0 +1,258 @@
+/*
+ galaxy upload lib v1.0 - uses FileReader, FormData and XMLHttpRequest
+*/
+;(function($)
+{
+ // add event properties
+ jQuery.event.props.push("dataTransfer");
+
+ // default options
+ var default_opts =
+ {
+ url : '',
+ paramname : 'content',
+ maxfilesize : 2048,
+ data : {},
+ dragover : function() {},
+ dragleave : 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+."
+ }
+
+ // global file queue
+ var queue = [];
+
+ // global counter for file being currently processed
+ var queue_index = -1;
+
+ // global queue status
+ var queue_status = false;
+
+ // attach to element
+ $.fn.uploadbox = function(options)
+ {
+ // parse options
+ var opts = $.extend({}, default_opts, options);
+
+ // compatibility
+ var mode = window.File && window.FileReader && window.FormData && window.XMLHttpRequest;
+
+ // append upload button
+ this.append('<input id="uploadbox_input" type="file" style="display: none" multiple>');
+ this.append('<div id="uploadbox_info"></div>');
+
+ // set info text
+ if (mode)
+ this.find('#uploadbox_info').html(opts.text_default);
+ else
+ this.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);
+ });
+
+ // attach change event
+ $('#uploadbox_input').change(function(e)
+ {
+ var files = e.target.files;
+ upload(files);
+ });
+
+ // drop event
+ function drop(e)
+ {
+ // check if its a file transfer
+ if(!e.dataTransfer)
+ return;
+
+ // get files from event
+ var files = e.dataTransfer.files;
+
+ // start upload
+ upload(files);
+
+ // prevent default
+ e.preventDefault();
+
+ // return
+ return false;
+ }
+
+ // drag over
+ function dragover(e)
+ {
+ e.preventDefault();
+ opts.dragover.call(this, e);
+ }
+
+ // drag leave
+ function dragleave(e)
+ {
+ e.stopPropagation();
+ opts.dragleave.call(this, e);
+ }
+
+ // progress
+ function progress(e)
+ {
+ // get percentage
+ if (e.lengthComputable)
+ opts.progress(this.index, this.file, Math.round((e.loaded * 100) / e.total));
+ }
+
+ // respond to an upload request
+ function upload(files)
+ {
+ // get current queue size
+ var queue_sofar = queue.length;
+
+ // add new files to queue
+ for (var index = 0; index < files.length; index++)
+ queue.push(files[index]);
+
+ // tell client about new uploads
+ for (var index = queue_sofar; index < queue.length; index++)
+ opts.start(index, queue[index], "");
+
+ // initiate processing loop if process loop is not running already
+ if (!queue_status)
+ process();
+ }
+
+ // process an upload, recursive
+ function process()
+ {
+ // check if for files
+ if (queue_index + 1 == queue.length)
+ {
+ queue_status = false;
+ return;
+ }
+
+ // set status
+ queue_status = true;
+
+ // identify current index
+ var index = ++queue_index;
+
+ // add file to queue
+ try
+ {
+ // load file read
+ 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)
+ {
+ send(index, file)
+ };
+
+ // link error
+ reader.onerror = function(e)
+ {
+ opts.error(index, file, opts.error_default);
+ queue_status = false;
+ };
+
+ // read data
+ reader.readAsDataURL(file);
+ } else {
+ // skip file
+ opts.error(index, file, opts.error_filesize);
+
+ // restart process
+ process();
+ }
+ } catch (err)
+ {
+ // parse error
+ opts.error(index, file, err);
+ }
+ }
+
+ // send file
+ function send (index, file)
+ {
+ // construct form data
+ var formData = new FormData();
+ for (var key in opts.data)
+ formData.append(key, opts.data[key]);
+ formData.append(opts.paramname, file, file.name);
+
+ // prepare request
+ var xhr = new XMLHttpRequest();
+
+ // prepare upload progress
+ xhr.upload.index = index;
+ xhr.upload.file = file;
+ xhr.upload.addEventListener('progress', progress, false);
+
+ // open request
+ xhr.open('POST', opts.url, true);
+ xhr.setRequestHeader('Accept', 'application/json');
+ xhr.setRequestHeader('Cache-Control', 'no-cache');
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+ xhr.send(formData);
+
+ // onloadend
+ xhr.onloadend = function()
+ {
+ // retrieve response
+ var response = null;
+ if (xhr.responseText)
+ {
+ try
+ {
+ response = jQuery.parseJSON(xhr.responseText);
+ } catch (e) {
+ response = xhr.responseText;
+ }
+ }
+
+ // pass any error to the error option
+ if (xhr.status < 200 || xhr.status > 299)
+ {
+ // request error
+ opts.error(index, file, xhr.statusText + " (Server Code " + xhr.status + ")");
+
+ // reset status
+ queue_status = false;
+ } else {
+ // parse response
+ opts.success(index, file, response);
+
+ // upload next file
+ process();
+ }
+ }
+ }
+
+ // return
+ return this;
+ }
+})(jQuery);
\ No newline at end of file
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/style/blue/galaxy.frame.css
--- a/static/style/blue/galaxy.frame.css
+++ b/static/style/blue/galaxy.frame.css
@@ -1,21 +1,33 @@
/*
- galaxy-frames generic styles
+ galaxy generic styles
*/
-.f-corner
+.bs-tooltip
+{
+ z-index: 34010;
+}
+
+.galaxy-corner
{
-moz-border-radius: 4px;
border-radius: 4px;
}
-.f-toggle
+.galaxy-corner-soft
+{
+ -moz-border-radius: 2px;
+ border-radius: 2px;
+}
+
+.galaxy-toggle
{
color: #BCC800;
}
-.bs-tooltip
+.galaxy-shadow
{
- z-index: 34010;
+ -webkit-box-shadow: 1px 1px 4px rgba(0,0,0,0.16);
+ box-shadow: 1px 1px 4px rgba(0,0,0,0.16);
}
/*
@@ -80,42 +92,6 @@
}
/*
- panel active button
-*/
-.galaxy-frame-active
-{
- z-index : 34010;
- position : absolute;
- top : 8px;
- right : 120px;
- cursor : pointer;
- color : #D0D0D0;
-}
-
-/*
- panel load button
-*/
-.galaxy-frame-load
-{
- z-index : 34010;
- position : absolute;
- top : 6px;
- right : 170px;
- cursor : pointer;
- color : #BCC800;
-}
-
-.galaxy-frame-load .number
-{
- position : absolute;
- font-weight : bold;
- font-size : 12px;
- font-family : Verdana, Arial;
- top : 8px;
- left : 26px;
-}
-
-/*
frame components
*/
.galaxy-frame .f-content
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/style/blue/galaxy.master.css
--- /dev/null
+++ b/static/style/blue/galaxy.master.css
@@ -0,0 +1,30 @@
+/*
+ galaxy master
+*/
+.galaxy-master
+{
+ position : absolute;
+ top : 0px;
+ right : 100px;
+ cursor : pointer;
+ color : #D0D0D0;
+ overflow : hidden;
+ z-index : 34010;
+ padding : 8px;
+}
+
+.galaxy-icon
+{
+ float : left;
+ margin : 0px 10px;
+}
+
+.galaxy-icon .number
+{
+ font-weight : bold;
+ font-size : 12px;
+ font-family : Verdana, Arial;
+ position : relative;
+ left : 23px;
+ top : -9px;
+}
\ No newline at end of file
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/style/blue/galaxy.modal.css
--- /dev/null
+++ b/static/style/blue/galaxy.modal.css
@@ -0,0 +1,70 @@
+/*
+ galaxy-modal
+*/
+
+.galaxy-modal
+{
+ z-index : 15000;
+ width : 100%;
+ height : 100%;
+ position : absolute;
+}
+
+.galaxy-modal .background
+{
+ width : 100%;
+ height : 100%;
+ position : absolute;
+ opacity : 0.6;
+ background : #11131A;
+ overflow : auto;
+}
+
+.galaxy-modal .dialog
+{
+ overflow : hidden;
+ position : absolute;
+ background : #FFFFFF;
+ border : 1px solid #D0D0D0;
+ top : 20%;
+ left : 50%;
+ width : 560px;
+ margin-left : -280px;
+ -moz-box-shadow : 0 3px 7px rgba(0, 0, 0, 0.3);
+ box-shadow : 0 3px 7px rgba(0, 0, 0, 0.3);
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+}
+
+.galaxy-modal .header h3
+{
+ margin : 0;
+ line-height : 30px;
+}
+
+.galaxy-modal .header
+{
+ padding : 9px 15px;
+ border-bottom : 1px solid #eee;
+}
+
+.galaxy-modal .body
+{
+ position : relative;
+ overflow-y : auto;
+ max-height : 400px;
+ padding : 15px;
+}
+
+.galaxy-modal .footer
+{
+ text-align : right;
+ border-top : 1px solid #ddd;
+ background-color : #f5f5f5;
+ -webkit-box-shadow : inset 0 1px 0 #ffffff;
+ -moz-box-shadow : inset 0 1px 0 #ffffff;
+ box-shadow : inset 0 1px 0 #ffffff;
+ float : right;
+ padding : 12px;
+ width : 100%;
+ height : 100%;
+}
\ No newline at end of file
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 static/style/blue/galaxy.upload.css
--- /dev/null
+++ b/static/style/blue/galaxy.upload.css
@@ -0,0 +1,97 @@
+/*
+ upload box
+*/
+
+.galaxy-upload-button
+{
+ z-index : 34010;
+ position : absolute;
+ top : 8px;
+ right : 210px;
+ cursor : pointer;
+ color : #D0D0D0;
+}
+
+.galaxy-upload-box
+{
+ margin : -5px;
+ width : 100%;
+ height : 200px;
+ max-height : 200px;
+ border : 1px dashed #D0D0D0;
+ font-weight : bold;
+ line-height : 16px;
+ color : #5C5858;
+ padding : 10px 0px 0px 0px;
+ text-align : center;
+ font-size : 12px;
+ cursor : pointer;
+ overflow : scroll;
+}
+
+.galaxy-upload-highlight
+{
+ border : 1px dashed #5C5858;
+ color : #5C5858;
+}
+
+.galaxy-upload-file
+{
+ position : relative;
+ margin : 5px 20px 5px 20px;
+ border : 1px solid #D0D0D0;
+}
+
+.galaxy-upload-file .title
+{
+ font-weight : normal;
+ font-size : 12px;
+ color : #5C5858;
+ margin : 3px 130px 0px 5px;
+ text-align : left;
+ overflow : hidden;
+}
+
+.galaxy-upload-file .progress-frame
+{
+ border : 0px;
+ margin : 0px 5px 3px 5px;
+ height : 7px;
+ background : #D0D0D0;
+}
+
+.galaxy-upload-file .progress
+{
+ background : #CCFFCC;
+ height : 100%;
+ width : 0%;
+}
+
+.galaxy-upload-file .failed
+{
+ background : #FFCCCC;
+}
+
+.galaxy-upload-file .error
+{
+ font-weight : normal;
+ font-size : 10px;
+ color : #5C5858;
+ text-align : left;
+ overflow : hidden;
+ margin : 0px 5px 0px 5px;
+}
+
+.galaxy-upload-file .info
+{
+ position : absolute;
+ top : 4px;
+ right : 5px;
+ font-weight : normal;
+ font-size : 10px;
+ color : #5C5858;
+ text-align : right;
+ overflow : hidden;
+ max-width : 100px;
+ max-height : 12px;
+}
\ No newline at end of file
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 templates/base/base_panels.mako
--- a/templates/base/base_panels.mako
+++ b/templates/base/base_panels.mako
@@ -101,9 +101,13 @@
}
});
- ## frame manager
- var frame_manager = null;
- require(['galaxy.frame'], function(frame) { this.frame_manager = new frame.GalaxyFrameManager(galaxy_config); });
+ ## load galaxy js-modules
+ require(['galaxy.master', 'galaxy.frame', 'galaxy.upload'], function(master, frame, upload)
+ {
+ Galaxy.master = new master.GalaxyMaster();
+ Galaxy.frame_manager = new frame.GalaxyFrameManager();
+ ##Galaxy.upload = new upload.GalaxyUpload();
+ });
</script></%def>
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 templates/webapps/galaxy/base_panels.mako
--- a/templates/webapps/galaxy/base_panels.mako
+++ b/templates/webapps/galaxy/base_panels.mako
@@ -117,7 +117,7 @@
${tab( "analysis", _("Analyze Data"), h.url_for( controller='/root', action='index' ) )}
## Workflow tab.
- ${tab( "workflow", _("Workflow"), "javascript:frame_manager.frame_new({title: 'Workflow', type: 'url', content: '" + h.url_for( controller='/workflow', action='index' ) + "'});")}
+ ${tab( "workflow", _("Workflow"), "javascript:Galaxy.frame_manager.frame_new({title: 'Workflow', type: 'url', content: '" + h.url_for( controller='/workflow', action='index' ) + "'});")}
## 'Shared Items' or Libraries tab.
<%
@@ -147,10 +147,10 @@
## Visualization menu.
<%
menu_options = [
- [_('New Track Browser'), "javascript:frame_manager.frame_new({title: 'Trackster', type: 'url', content: '" + h.url_for( controller='/visualization', action='trackster' ) + "'});"],
- [_('Saved Visualizations'), "javascript:frame_manager.frame_new({ type: 'url', content : '" + h.url_for( controller='/visualization', action='list' ) + "'});" ]
+ [_('New Track Browser'), "javascript:Galaxy.frame_manager.frame_new({title: 'Trackster', type: 'url', content: '" + h.url_for( controller='/visualization', action='trackster' ) + "'});"],
+ [_('Saved Visualizations'), "javascript:Galaxy.frame_manager.frame_new({ type: 'url', content : '" + h.url_for( controller='/visualization', action='list' ) + "'});" ]
]
- tab( "visualization", _("Visualization"), "javascript:frame_manager.frame_new({title: 'Trackster', type: 'url', content: '" + h.url_for( controller='/visualization', action='list' ) + "'});", menu_options=menu_options )
+ tab( "visualization", _("Visualization"), "javascript:Galaxy.frame_manager.frame_new({title: 'Trackster', type: 'url', content: '" + h.url_for( controller='/visualization', action='list' ) + "'});", menu_options=menu_options )
%>
## Cloud menu.
diff -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 -r 99cc1ee095c39f800ffc8a6bf36912fcd6cd06e9 templates/webapps/galaxy/galaxy.masthead.mako
--- a/templates/webapps/galaxy/galaxy.masthead.mako
+++ b/templates/webapps/galaxy/galaxy.masthead.mako
@@ -33,9 +33,12 @@
if (window != window.top)
$('<link href="' + galaxy_config.root + 'static/style/galaxy.frame.masthead.css" rel="stylesheet">').appendTo('head');
- ## frame manager
- var frame_manager = null;
- require(['galaxy.frame'], function(frame) { this.frame_manager = new frame.GalaxyFrameManager(galaxy_config); });
+ ## load galaxy js-modules
+ require(['galaxy.master', 'galaxy.frame'], function(master, frame)
+ {
+ Galaxy.master = new master.GalaxyMaster();
+ Galaxy.frame_manager = new frame.GalaxyFrameManager();
+ });
</script>
## start main tag
@@ -102,7 +105,7 @@
${tab( "analysis", _("Analyze Data"), h.url_for( controller='/root', action='index' ) )}
## Workflow tab.
- ${tab( "workflow", _("Workflow"), "javascript:frame_manager.frame_new({title: 'Workflow', type: 'url', content: '" + h.url_for( controller='/workflow', action='index' ) + "'});")}
+ ${tab( "workflow", _("Workflow"), "javascript:Galaxy.frame_manager.frame_new({title: 'Workflow', type: 'url', content: '" + h.url_for( controller='/workflow', action='index' ) + "'});")}
## 'Shared Items' or Libraries tab.
<%
@@ -132,10 +135,10 @@
## Visualization menu.
<%
menu_options = [
- [_('New Track Browser'), "javascript:frame_manager.frame_new({title: 'Trackster', type: 'url', content: '" + h.url_for( controller='/visualization', action='trackster' ) + "'});"],
- [_('Saved Visualizations'), "javascript:frame_manager.frame_new({ type: 'url', content : '" + h.url_for( controller='/visualization', action='list' ) + "'});" ]
+ [_('New Track Browser'), "javascript:Galaxy.frame_manager.frame_new({title: 'Trackster', type: 'url', content: '" + h.url_for( controller='/visualization', action='trackster' ) + "'});"],
+ [_('Saved Visualizations'), "javascript:Galaxy.frame_manager.frame_new({ type: 'url', content : '" + h.url_for( controller='/visualization', action='list' ) + "'});" ]
]
- tab( "visualization", _("Visualization"), "javascript:frame_manager.frame_new({title: 'Trackster', type: 'url', content: '" + h.url_for( controller='/visualization', action='list' ) + "'});", menu_options=menu_options )
+ tab( "visualization", _("Visualization"), "javascript:Galaxy.frame_manager.frame_new({title: 'Trackster', type: 'url', content: '" + h.url_for( controller='/visualization', action='list' ) + "'});", menu_options=menu_options )
%>
## Cloud menu.
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: jmchilton: Add ucsc_tools requirement for extract_genomic_dna.xml tool.
by commits-noreply@bitbucket.org 11 Sep '13
by commits-noreply@bitbucket.org 11 Sep '13
11 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/598d633c9caa/
Changeset: 598d633c9caa
User: jmchilton
Date: 2013-09-03 19:32:02
Summary: Add ucsc_tools requirement for extract_genomic_dna.xml tool.
Affected #: 1 file
diff -r fd380581d0073c6a08cca74e34434f058804de3d -r 598d633c9caa9cccbd28e8fc57f650c1b8564371 tools/extract/extract_genomic_dna.xml
--- a/tools/extract/extract_genomic_dna.xml
+++ b/tools/extract/extract_genomic_dna.xml
@@ -53,6 +53,7 @@
</outputs><requirements><requirement type="binary">faToTwoBit</requirement>
+ <requirement type="package">ucsc_tools</requirement></requirements><tests><test>
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: Dave Bouvier: Fix for displaying repository dependencies that are not filtered out.
by commits-noreply@bitbucket.org 10 Sep '13
by commits-noreply@bitbucket.org 10 Sep '13
10 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/fd380581d007/
Changeset: fd380581d007
User: Dave Bouvier
Date: 2013-09-10 22:35:48
Summary: Fix for displaying repository dependencies that are not filtered out.
Affected #: 1 file
diff -r cd91ec8f14059167cdfda2ab606035c97ead5469 -r fd380581d0073c6a08cca74e34434f058804de3d 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
@@ -625,10 +625,7 @@
tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
common_util.parse_repository_dependency_tuple( required_rd_tup )
if not asbool( only_if_compiling_contained_td ):
- if rd_key in filtered_key_rd_dict:
- filtered_key_rd_dict[ rd_key ].append( required_rd_tup )
- else:
- filtered_key_rd_dict[ rd_key ] = [ required_rd_tup ]
+ filtered_key_rd_dict[ rd_key ] = required_rd_tup
return filtered_key_rd_dict
def merge_missing_repository_dependencies_to_installed_container( containers_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
commit/galaxy-central: Dave Bouvier: Fix for filtering out repository dependencies that are only required when compiling a tool dependency because the precompiled binary was not found or failed to install.
by commits-noreply@bitbucket.org 10 Sep '13
by commits-noreply@bitbucket.org 10 Sep '13
10 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/cd91ec8f1405/
Changeset: cd91ec8f1405
User: Dave Bouvier
Date: 2013-09-10 20:35:06
Summary: Fix for filtering out repository dependencies that are only required when compiling a tool dependency because the precompiled binary was not found or failed to install.
Affected #: 1 file
diff -r 595c30bc8df5dfd626d78cc4e030ac1910b54f4e -r cd91ec8f14059167cdfda2ab606035c97ead5469 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
@@ -678,7 +678,7 @@
current_repository_key_rd_dicts = get_updated_changeset_revisions_for_repository_dependencies( trans, current_repository_key_rd_dicts )
for key_rd_dict in current_repository_key_rd_dicts:
# Filter out repository dependencies that are required only if compiling the dependent repository's tool dependency.
- all_repository_dependencieskey_rd_dict = filter_only_if_compiling_contained_td( key_rd_dict )
+ key_rd_dict = filter_only_if_compiling_contained_td( key_rd_dict )
if key_rd_dict:
is_circular = False
if not in_key_rd_dicts( key_rd_dict, handled_key_rd_dicts ) and not in_key_rd_dicts( key_rd_dict, key_rd_dicts_to_be_processed ):
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: Slight refactoring of message generation in the tool shed.
by commits-noreply@bitbucket.org 10 Sep '13
by commits-noreply@bitbucket.org 10 Sep '13
10 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/595c30bc8df5/
Changeset: 595c30bc8df5
User: greg
Date: 2013-09-10 20:19:46
Summary: Slight refactoring of message generation in the tool shed.
Affected #: 5 files
diff -r 04a3137539d245fa294f73f8b6467a5b13e6d028 -r 595c30bc8df5dfd626d78cc4e030ac1910b54f4e 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
@@ -2159,11 +2159,17 @@
all_repository_dependencies=None,
handled_key_rd_dicts=None )
if str( repository.type ) != rt_util.TOOL_DEPENDENCY_DEFINITION:
- # Handle messaging for orphan tool dependencies.
- orphan_message = tool_dependency_util.generate_message_for_orphan_tool_dependencies( trans, repository, metadata )
- if orphan_message:
- message += orphan_message
+ # Handle messaging for resetting repository type to the optimal value.
+ change_repository_type_message = tool_dependency_util.generate_message_for_repository_type_change( trans, repository )
+ if change_repository_type_message:
+ message += change_repository_type_message
status = 'warning'
+ else:
+ # Handle messaging for orphan tool dependency definitions.
+ orphan_message = tool_dependency_util.generate_message_for_orphan_tool_dependencies( trans, repository, metadata )
+ if orphan_message:
+ message += orphan_message
+ status = 'warning'
if is_malicious:
if trans.app.security_agent.can_push( trans.app, trans.user, repository ):
message += malicious_error_can_push
diff -r 04a3137539d245fa294f73f8b6467a5b13e6d028 -r 595c30bc8df5dfd626d78cc4e030ac1910b54f4e lib/galaxy/webapps/tool_shed/controllers/upload.py
--- a/lib/galaxy/webapps/tool_shed/controllers/upload.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/upload.py
@@ -207,15 +207,20 @@
else:
metadata_dict = {}
if str( repository.type ) != rt_util.TOOL_DEPENDENCY_DEFINITION:
- # Provide a warning message if a tool_dependencies.xml file is provided, but tool dependencies weren't loaded due to a requirement tag mismatch
- # or some other problem. Tool dependency definitions can define orphan tool dependencies (no relationship to any tools contained in the repository),
- # so warning messages are important because orphans are always valid. The repository owner must be warned in case they did not intend to define an
- # orphan dependency, but simply provided incorrect information (tool shed, name owner, changeset_revision) for the definition.
- # Handle messaging for orphan tool dependencies.
- orphan_message = tool_dependency_util.generate_message_for_orphan_tool_dependencies( trans, repository, metadata_dict )
- if orphan_message:
- message += orphan_message
+ change_repository_type_message = tool_dependency_util.generate_message_for_repository_type_change( trans, repository )
+ if change_repository_type_message:
+ message += change_repository_type_message
status = 'warning'
+ else:
+ # Provide a warning message if a tool_dependencies.xml file is provided, but tool dependencies weren't loaded due to a requirement tag mismatch
+ # or some other problem. Tool dependency definitions can define orphan tool dependencies (no relationship to any tools contained in the repository),
+ # so warning messages are important because orphans are always valid. The repository owner must be warned in case they did not intend to define an
+ # orphan dependency, but simply provided incorrect information (tool shed, name owner, changeset_revision) for the definition.
+ # Handle messaging for orphan tool dependencies.
+ orphan_message = tool_dependency_util.generate_message_for_orphan_tool_dependencies( trans, repository, metadata_dict )
+ if orphan_message:
+ message += orphan_message
+ status = 'warning'
# Handle messaging for invalid tool dependencies.
invalid_tool_dependencies_message = tool_dependency_util.generate_message_for_invalid_tool_dependencies( metadata_dict )
if invalid_tool_dependencies_message:
diff -r 04a3137539d245fa294f73f8b6467a5b13e6d028 -r 595c30bc8df5dfd626d78cc4e030ac1910b54f4e lib/tool_shed/util/metadata_util.py
--- a/lib/tool_shed/util/metadata_util.py
+++ b/lib/tool_shed/util/metadata_util.py
@@ -906,13 +906,13 @@
repository_dependency_tups=invalid_repository_dependency_tups,
is_valid=False,
description=description )
- # We need to continue to restrict the behavior of orphan tool dependencies, possibly eliminating them altoghether at some point.
+ # We need to continue to restrict the behavior for defining orphan tool dependencies, possibly eliminating them altoghether at some point.
check_for_orphan_tool_dependencies = False
if app.name == 'tool_shed':
- if repository.type == rt_util.UNRESTRICTED and 'tools' not in metadata_dict:
+ if repository.type != rt_util.TOOL_DEPENDENCY_DEFINITION and not repository.can_change_type_to( app, rt_util.TOOL_DEPENDENCY_DEFINITION ):
check_for_orphan_tool_dependencies = True
- elif 'tools' in metadata_dict:
- check_for_orphan_tool_dependencies = True
+ elif 'tools' in metadata_dict:
+ check_for_orphan_tool_dependencies = True
if check_for_orphan_tool_dependencies:
# Determine and store orphan tool dependencies.
orphan_tool_dependencies = get_orphan_tool_dependencies( metadata_dict )
diff -r 04a3137539d245fa294f73f8b6467a5b13e6d028 -r 595c30bc8df5dfd626d78cc4e030ac1910b54f4e 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
@@ -150,14 +150,17 @@
version = requirements_dict[ 'version' ]
message += "<b>* name:</b> %s, <b>type:</b> %s, <b>version:</b> %s<br/>" % ( str( name ), str( type ), str( version ) )
message += "<br/>"
- elif repository.can_change_type_to( trans.app, rt_util.TOOL_DEPENDENCY_DEFINITION ):
- tool_dependency_definition_type_class = trans.app.repository_types_registry.get_class_by_label( rt_util.TOOL_DEPENDENCY_DEFINITION )
- message += "This repository currently contains a single file named <b>%s</b>. If additional files will " % suc.TOOL_DEPENDENCY_DEFINITION_FILENAME
- message += "not be added to this repository, then it's type should be set to <b>%s</b>.<br/>" % tool_dependency_definition_type_class.label
- else:
- message += "This repository contains no tools, so it's defined tool dependencies are considered orphans within this repository.<br/>"
return message
+def generate_message_for_repository_type_change( trans, repository ):
+ message = ''
+ if repository.can_change_type_to( trans.app, rt_util.TOOL_DEPENDENCY_DEFINITION ):
+ tool_dependency_definition_type_class = trans.app.repository_types_registry.get_class_by_label( rt_util.TOOL_DEPENDENCY_DEFINITION )
+ message += "This repository currently contains a single file named <b>%s</b>. If additional files will " % suc.TOOL_DEPENDENCY_DEFINITION_FILENAME
+ message += "not be added to this repository, then it's type should be set to <b>%s</b>.<br/>" % tool_dependency_definition_type_class.label
+ return message
+
+
def get_download_url_for_platform( url_templates, platform_info_dict ):
'''
Compare the dict returned by get_platform_info() with the values specified in the url_template element. Return
diff -r 04a3137539d245fa294f73f8b6467a5b13e6d028 -r 595c30bc8df5dfd626d78cc4e030ac1910b54f4e test/tool_shed/functional/test_0100_complex_repository_dependencies.py
--- a/test/tool_shed/functional/test_0100_complex_repository_dependencies.py
+++ b/test/tool_shed/functional/test_0100_complex_repository_dependencies.py
@@ -54,7 +54,7 @@
strings_displayed=[ 'This repository currently contains a single file named <b>tool_dependencies.xml</b>' ],
strings_not_displayed=[] )
# Visit the manage repository page for package_bwa_0_5_9_0100.
- self.display_manage_repository_page( repository, strings_displayed=[ 'Tool dependencies', 'may not be', 'in this repository' ] )
+ self.display_manage_repository_page( repository, strings_displayed=[ 'Tool dependencies', 'will not be', 'to this repository' ] )
def test_0010_create_bwa_base_repository( self ):
'''Create and populate bwa_base_0100.'''
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: Don't generate error messages when resetting metadata on installed tool shed repositories that have repository dependencies that are not installed because they were not needed for compiling the dependent repository's tool dependency.
by commits-noreply@bitbucket.org 10 Sep '13
by commits-noreply@bitbucket.org 10 Sep '13
10 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/04a3137539d2/
Changeset: 04a3137539d2
User: greg
Date: 2013-09-10 19:29:18
Summary: Don't generate error messages when resetting metadata on installed tool shed repositories that have repository dependencies that are not installed because they were not needed for compiling the dependent repository's tool dependency.
Affected #: 1 file
diff -r 1e30cdb6d3b82a68da8daddc86411eecc33be444 -r 04a3137539d245fa294f73f8b6467a5b13e6d028 lib/tool_shed/util/metadata_util.py
--- a/lib/tool_shed/util/metadata_util.py
+++ b/lib/tool_shed/util/metadata_util.py
@@ -1195,14 +1195,17 @@
repository = suc.get_repository_for_dependency_relationship( app, cleaned_toolshed, name, owner, updated_changeset_revision )
if repository:
return repository_dependency_tup, is_valid, error_message
- # We'll currently default to setting the repository dependency definition as invalid if an installed repository cannot be found.
- # This may not be ideal because the tool shed may have simply been inaccessible when metadata was being generated for the installed
- # tool shed repository.
- error_message = "Ignoring invalid repository dependency definition for tool shed %s, name %s, owner %s, changeset revision %s "% \
- ( toolshed, name, owner, changeset_revision )
- log.debug( error_message )
- is_valid = False
- return repository_dependency_tup, is_valid, error_message
+ # Don't generate an error message for missing repository dependencies that are required only if compiling the dependent repository's
+ # tool dependency.
+ if not only_if_compiling_contained_td:
+ # We'll currently default to setting the repository dependency definition as invalid if an installed repository cannot be found.
+ # This may not be ideal because the tool shed may have simply been inaccessible when metadata was being generated for the installed
+ # tool shed repository.
+ error_message = "Ignoring invalid repository dependency definition for tool shed %s, name %s, owner %s, changeset revision %s "% \
+ ( toolshed, name, owner, changeset_revision )
+ log.debug( error_message )
+ is_valid = False
+ return repository_dependency_tup, is_valid, error_message
else:
# We're in the tool shed.
if suc.tool_shed_is_this_tool_shed( toolshed ):
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/0bc38956530a/
Changeset: 0bc38956530a
Branch: dataset-cleanup
User: lance_parsons
Date: 2013-04-18 17:24:09
Summary: Basic administrative dataset cleanup script
Affected #: 3 files
diff -r 18b23ed8de5b384f142db349e7379c03567758df -r 0bc38956530a382faea4b42e771037672c2a6b0c scripts/cleanup_datasets/admin_cleanup_datasets.py
--- /dev/null
+++ b/scripts/cleanup_datasets/admin_cleanup_datasets.py
@@ -0,0 +1,256 @@
+#!/usr/bin/env python
+"""
+Mark datasets as deleted that are older than specified cutoff
+and (optionaly) with a tool_id that matches the specified search
+string.
+
+This script is useful for administrators to cleanup after users who
+leave many old datasets around. It was modeled after the cleanup_datasets.py
+script originally distributed with Galaxy.
+
+Basic Usage:
+ admin_cleanup_datasets.py universe_wsgi.ini -d 60 \
+ --template=email_template.txt
+
+Required Arguments:
+ config_file - the Galaxy configuration file (universe_wsgi.ini)
+
+Optional Arguments:
+ -d --days - number of days old the dataset must be (default: 60)
+ --tool_id - string to search for in dataset tool_id
+ --template - Mako template file to use for email notification
+ -i --info_only - Print results, but don't email or delete anything
+ -e --email_only - Email notifications, but don't delete anything
+ Useful for notifying users of pending deletion
+
+ --smtp - Specify smtp server
+ If not specified, use smtp settings specified in config file
+ --fromaddr - Specify from address
+ If not specified, use error_email_to specified in config file
+
+Email Template Variables:
+ cutoff - the cutoff in days
+ email - the users email address
+ datasets - a list of tuples containing 'dataset' and 'history' names
+
+
+Author: Lance Parsons (lparsons(a)princeton.edu)
+"""
+import os
+import sys
+import shutil
+import logging
+from collections import defaultdict
+
+log = logging.getLogger()
+log.setLevel(10)
+log.addHandler(logging.StreamHandler(sys.stdout))
+
+from cleanup_datasets import CleanupDatasetsApplication
+import pkg_resources
+pkg_resources.require("SQLAlchemy >= 0.4")
+
+#pkg_resources.require("Mako")
+from mako.template import Template
+
+import time
+import ConfigParser
+from datetime import datetime, timedelta
+from time import strftime
+from optparse import OptionParser
+
+import galaxy.config
+import galaxy.model.mapping
+import sqlalchemy as sa
+from galaxy.model.orm import and_
+import galaxy.util
+
+assert sys.version_info[:2] >= (2, 4)
+
+
+def main():
+ """
+ Datasets that are older than the specified cutoff and for which the tool_id
+ contains the specified text will be marked as deleted in user's history and
+ the user will be notified by email using the specified template file.
+ """
+ parser = OptionParser()
+ parser.add_option("-d", "--days", dest="days", action="store",
+ type="int", help="number of days (60)", default=60)
+ parser.add_option("--tool_id", default="",
+ help="Text to match against tool_id")
+ parser.add_option("--template", default=None,
+ help="Mako Template file to use as email "
+ "Variables are 'cutoff' for the cutoff in days, "
+ "'email' for users email and "
+ "'datasets' which is a list of tuples "
+ "containing 'dataset' and 'history' names. "
+ "Default: admin_cleanup_deletion_template.txt")
+ parser.add_option("-i", "--info_only", action="store_true",
+ dest="info_only", help="info about the requested action",
+ default=False)
+ parser.add_option("-e", "--email_only", action="store_true",
+ dest="email_only", help="Send emails only, don't delete",
+ default=False)
+ parser.add_option("--smtp", default=None,
+ help="SMTP Server to use to send email. "
+ "Default: [read from galaxy ini file]")
+ parser.add_option("--fromaddr", default=None,
+ help="From address to use to send email. "
+ "Default: [read from galaxy ini file]")
+ (options, args) = parser.parse_args()
+ ini_file = args[0]
+
+ config_parser = ConfigParser.ConfigParser({'here': os.getcwd()})
+ config_parser.read(ini_file)
+ config_dict = {}
+ for key, value in config_parser.items("app:main"):
+ config_dict[key] = value
+
+ if options.smtp is not None:
+ config_dict['smtp_server'] = options.smtp
+ if config_dict.get('smtp_server') is None:
+ parser.error("SMTP Server must be specified as an option (--smtp) "
+ "or in the config file (smtp_server)")
+
+ if options.fromaddr is not None:
+ config_dict['error_email_to'] = options.fromaddr
+ if config_dict.get('error_email_to') is None:
+ parser.error("From address must be specified as an option "
+ "(--fromaddr) or in the config file "
+ "(error_email_to)")
+
+ scriptdir = os.path.dirname(os.path.abspath(__file__))
+ template_file = options.template
+ if template_file is None:
+ default_template = os.path.join(scriptdir,
+ 'admin_cleanup_deletion_template.txt')
+ sample_template_file = "%s.sample" % default_template
+ if os.path.exists(default_template):
+ template_file = default_template
+ elif os.path.exists(sample_template_file):
+ print "Copying %s to %s" % (sample_template_file, default_template)
+ shutil.copyfile(sample_template_file, default_template)
+ template_file = default_template
+ else:
+ parser.error("Default template (%s) or sample template (%s) not "
+ "found, please specify template as an option "
+ "(--template)." % default_template,
+ sample_template_file)
+ elif not os.path.exists(template_file):
+ parser.error("Specified template file (%s) not found." % template_file)
+
+ config = galaxy.config.Configuration(**config_dict)
+
+ app = CleanupDatasetsApplication(config)
+ cutoff_time = datetime.utcnow() - timedelta(days=options.days)
+ now = strftime("%Y-%m-%d %H:%M:%S")
+
+ print "##########################################"
+ print "\n# %s - Handling stuff older than %i days" % (now, options.days)
+
+ if options.info_only:
+ print "# Displaying info only ( --info_only )\n"
+ elif options.email_only:
+ print "# Sending emails only, not deleting ( --email_only )\n"
+
+ administrative_delete_datasets(
+ app, cutoff_time, options.days, tool_id=options.tool_id,
+ template_file=template_file, config=config,
+ email_only=options.email_only, info_only=options.info_only)
+ app.shutdown()
+ sys.exit(0)
+
+
+def administrative_delete_datasets(app, cutoff_time, cutoff_days,
+ tool_id, template_file,
+ config, email_only=False,
+ info_only=False):
+ # Marks dataset history association deleted and email users
+ start = time.time()
+ # We really only need the id column here, but sqlalchemy barfs when
+ # trying to select only 1 column
+ hda_ids_query = sa.select(
+ (app.model.HistoryDatasetAssociation.table.c.id,
+ app.model.HistoryDatasetAssociation.table.c.deleted),
+ whereclause=and_(
+ app.model.Dataset.table.c.deleted == False,
+ app.model.HistoryDatasetAssociation.table.c.update_time
+ < cutoff_time,
+ app.model.Job.table.c.tool_id.like("%%%s%%" % tool_id),
+ app.model.HistoryDatasetAssociation.table.c.deleted == False),
+ from_obj=[sa.outerjoin(
+ app.model.Dataset.table,
+ app.model.HistoryDatasetAssociation.table)
+ .outerjoin(app.model.JobToOutputDatasetAssociation.table)
+ .outerjoin(app.model.Job.table)])
+ deleted_instance_count = 0
+ # skip = []
+ user_notifications = defaultdict(list)
+ # Add all datasets associated with Histories to our list
+ hda_ids = []
+ hda_ids.extend(
+ [row.id for row in hda_ids_query.execute()])
+ # Process each of the Dataset objects
+ for hda_id in hda_ids:
+ user_query = sa.select(
+ [app.model.HistoryDatasetAssociation.table,
+ app.model.History.table,
+ app.model.User.table],
+ whereclause=and_(
+ app.model.HistoryDatasetAssociation.table.c.id == hda_id),
+ from_obj=[sa.join(app.model.User.table,
+ app.model.History.table)
+ .join(app.model.HistoryDatasetAssociation.table)],
+ use_labels=True)
+ for result in user_query.execute():
+ user_notifications[result[app.model.User.table.c.email]].append(
+ (result[app.model.HistoryDatasetAssociation.table.c.name],
+ result[app.model.History.table.c.name]))
+ deleted_instance_count += 1
+ if not info_only and not email_only:
+ # Get the HistoryDatasetAssociation objects
+ hda = app.sa_session.query(
+ app.model.HistoryDatasetAssociation).get(hda_id)
+ if not hda.deleted:
+ # Mark the HistoryDatasetAssociation as deleted
+ hda.deleted = True
+ app.sa_session.add(hda)
+ print ("Marked HistoryDatasetAssociation id %d as "
+ "deleted" % hda.id)
+ app.sa_session.flush()
+
+ emailtemplate = Template(filename=template_file)
+ for (email, dataset_list) in user_notifications.iteritems():
+ msgtext = emailtemplate.render(email=email,
+ datasets=dataset_list,
+ cutoff=cutoff_days)
+ subject = "Galaxy Server Cleanup " \
+ "- %d datasets DELETED" % len(dataset_list)
+ fromaddr = config.error_email_to
+ print ""
+ print "From: %s" % fromaddr
+ print "To: %s" % email
+ print "Subject: %s" % subject
+ print "----------"
+ print msgtext
+ if not info_only:
+ #msg = MIMEText(msgtext)
+ #msg['Subject'] = subject
+ #msg['From'] = 'noone(a)nowhere.com'
+ #msg['To'] = email
+ galaxy.util.send_mail(fromaddr, email, subject,
+ msgtext, config)
+ #s = smtplib.SMTP(smtp_server)
+ #s.sendmail(['lparsons(a)princeton.edu'], email, msg.as_string())
+ #s.quit()
+
+ stop = time.time()
+ print ""
+ print "Marked %d dataset instances as deleted" % deleted_instance_count
+ print "Total elapsed time: ", stop - start
+ print "##########################################"
+
+
+if __name__ == "__main__":
+ main()
diff -r 18b23ed8de5b384f142db349e7379c03567758df -r 0bc38956530a382faea4b42e771037672c2a6b0c scripts/cleanup_datasets/admin_cleanup_deletion_template.txt.sample
--- /dev/null
+++ b/scripts/cleanup_datasets/admin_cleanup_deletion_template.txt.sample
@@ -0,0 +1,11 @@
+Galaxy Server Cleanup
+---------------------
+The following datasets you own on Galaxy are older than ${cutoff} days and have been DELETED:
+
+% for dataset, history in datasets:
+ "${dataset}" in history "${history}"
+% endfor
+
+You may be able to undelete them by logging into Galaxy, navigating to the appropriate history, selecting "Include Deleted Datasets" from the history options menu, and clicking on the link to undelete each dataset that you want to keep. You can then download the datasets. Thank you for your understanding and cooporation in this necessary cleanup in order to keep the Galaxy resource available. Please don't hesitate to contact us if you have any questions.
+
+ -- Galaxy Administrators
diff -r 18b23ed8de5b384f142db349e7379c03567758df -r 0bc38956530a382faea4b42e771037672c2a6b0c scripts/cleanup_datasets/admin_cleanup_warning_template.txt.sample
--- /dev/null
+++ b/scripts/cleanup_datasets/admin_cleanup_warning_template.txt.sample
@@ -0,0 +1,11 @@
+Galaxy Server Cleanup
+---------------------
+The following datasets you own on Galaxy are older than ${cutoff} days and will be deleted soon. Be sure to download any datasets you need to keep.
+
+% for dataset, history in datasets:
+ "${dataset}" in history "${history}"
+% endfor
+
+Please contact us if you have any questions.
+
+ -- Galaxy Administrators
https://bitbucket.org/galaxy/galaxy-central/commits/e4734c99812a/
Changeset: e4734c99812a
Branch: dataset-cleanup
User: lance_parsons
Date: 2013-04-18 21:43:00
Summary: Fix admin_cleanup_datasets.py for copied datasets
Affected #: 1 file
diff -r 0bc38956530a382faea4b42e771037672c2a6b0c -r e4734c99812ad2f240b2fa963ea9af3fa710bd74 scripts/cleanup_datasets/admin_cleanup_datasets.py
--- a/scripts/cleanup_datasets/admin_cleanup_datasets.py
+++ b/scripts/cleanup_datasets/admin_cleanup_datasets.py
@@ -17,7 +17,7 @@
Optional Arguments:
-d --days - number of days old the dataset must be (default: 60)
- --tool_id - string to search for in dataset tool_id
+ --tool_id - string to search for in dataset tool_id (default: all)
--template - Mako template file to use for email notification
-i --info_only - Print results, but don't email or delete anything
-e --email_only - Email notifications, but don't delete anything
@@ -47,8 +47,8 @@
log.addHandler(logging.StreamHandler(sys.stdout))
from cleanup_datasets import CleanupDatasetsApplication
-import pkg_resources
-pkg_resources.require("SQLAlchemy >= 0.4")
+#import pkg_resources
+#pkg_resources.require("SQLAlchemy >= 0.4")
#pkg_resources.require("Mako")
from mako.template import Template
@@ -77,8 +77,9 @@
parser = OptionParser()
parser.add_option("-d", "--days", dest="days", action="store",
type="int", help="number of days (60)", default=60)
- parser.add_option("--tool_id", default="",
- help="Text to match against tool_id")
+ parser.add_option("--tool_id", default=None,
+ help="Text to match against tool_id"
+ "Default: match all")
parser.add_option("--template", default=None,
help="Mako Template file to use as email "
"Variables are 'cutoff' for the cutoff in days, "
@@ -168,6 +169,7 @@
info_only=False):
# Marks dataset history association deleted and email users
start = time.time()
+ # Get HDAs older than cutoff time (ignore tool_id at this point)
# We really only need the id column here, but sqlalchemy barfs when
# trying to select only 1 column
hda_ids_query = sa.select(
@@ -177,20 +179,28 @@
app.model.Dataset.table.c.deleted == False,
app.model.HistoryDatasetAssociation.table.c.update_time
< cutoff_time,
- app.model.Job.table.c.tool_id.like("%%%s%%" % tool_id),
app.model.HistoryDatasetAssociation.table.c.deleted == False),
from_obj=[sa.outerjoin(
app.model.Dataset.table,
- app.model.HistoryDatasetAssociation.table)
- .outerjoin(app.model.JobToOutputDatasetAssociation.table)
- .outerjoin(app.model.Job.table)])
- deleted_instance_count = 0
- # skip = []
- user_notifications = defaultdict(list)
- # Add all datasets associated with Histories to our list
+ app.model.HistoryDatasetAssociation.table)])
+
+ # Add all datasets associated with Histories to our list
hda_ids = []
hda_ids.extend(
[row.id for row in hda_ids_query.execute()])
+
+ # Now find the tool_id that generated the dataset (even if it was copied)
+ tool_matched_ids = []
+ if tool_id is not None:
+ for hda_id in hda_ids:
+ this_tool_id = _get_tool_id_for_hda(app, hda_id)
+ if this_tool_id is not None and tool_id in this_tool_id:
+ tool_matched_ids.append(hda_id)
+ hda_ids = tool_matched_ids
+
+ deleted_instance_count = 0
+ user_notifications = defaultdict(list)
+
# Process each of the Dataset objects
for hda_id in hda_ids:
user_query = sa.select(
@@ -252,5 +262,22 @@
print "##########################################"
+def _get_tool_id_for_hda(app, hda_id):
+ # TODO Some datasets don't seem to have an entry in jtod or a copied_from
+ if hda_id is None:
+ return None
+ job = app.sa_session.query(app.model.Job).\
+ join(app.model.JobToOutputDatasetAssociation).\
+ filter(app.model.JobToOutputDatasetAssociation.table.c.dataset_id ==
+ hda_id).first()
+ if job is not None:
+ return job.tool_id
+ else:
+ hda = app.sa_session.query(app.model.HistoryDatasetAssociation).\
+ get(hda_id)
+ return _get_tool_id_for_hda(app, hda.
+ copied_from_history_dataset_association_id)
+
+
if __name__ == "__main__":
main()
https://bitbucket.org/galaxy/galaxy-central/commits/1e30cdb6d3b8/
Changeset: 1e30cdb6d3b8
User: dannon
Date: 2013-09-10 19:14:10
Summary: Merged in lance_parsons/galaxy-central-pull-requests/dataset-cleanup (pull request #158)
Basic administrative dataset cleanup script
Affected #: 3 files
diff -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 -r 1e30cdb6d3b82a68da8daddc86411eecc33be444 scripts/cleanup_datasets/admin_cleanup_datasets.py
--- /dev/null
+++ b/scripts/cleanup_datasets/admin_cleanup_datasets.py
@@ -0,0 +1,283 @@
+#!/usr/bin/env python
+"""
+Mark datasets as deleted that are older than specified cutoff
+and (optionaly) with a tool_id that matches the specified search
+string.
+
+This script is useful for administrators to cleanup after users who
+leave many old datasets around. It was modeled after the cleanup_datasets.py
+script originally distributed with Galaxy.
+
+Basic Usage:
+ admin_cleanup_datasets.py universe_wsgi.ini -d 60 \
+ --template=email_template.txt
+
+Required Arguments:
+ config_file - the Galaxy configuration file (universe_wsgi.ini)
+
+Optional Arguments:
+ -d --days - number of days old the dataset must be (default: 60)
+ --tool_id - string to search for in dataset tool_id (default: all)
+ --template - Mako template file to use for email notification
+ -i --info_only - Print results, but don't email or delete anything
+ -e --email_only - Email notifications, but don't delete anything
+ Useful for notifying users of pending deletion
+
+ --smtp - Specify smtp server
+ If not specified, use smtp settings specified in config file
+ --fromaddr - Specify from address
+ If not specified, use error_email_to specified in config file
+
+Email Template Variables:
+ cutoff - the cutoff in days
+ email - the users email address
+ datasets - a list of tuples containing 'dataset' and 'history' names
+
+
+Author: Lance Parsons (lparsons(a)princeton.edu)
+"""
+import os
+import sys
+import shutil
+import logging
+from collections import defaultdict
+
+log = logging.getLogger()
+log.setLevel(10)
+log.addHandler(logging.StreamHandler(sys.stdout))
+
+from cleanup_datasets import CleanupDatasetsApplication
+#import pkg_resources
+#pkg_resources.require("SQLAlchemy >= 0.4")
+
+#pkg_resources.require("Mako")
+from mako.template import Template
+
+import time
+import ConfigParser
+from datetime import datetime, timedelta
+from time import strftime
+from optparse import OptionParser
+
+import galaxy.config
+import galaxy.model.mapping
+import sqlalchemy as sa
+from galaxy.model.orm import and_
+import galaxy.util
+
+assert sys.version_info[:2] >= (2, 4)
+
+
+def main():
+ """
+ Datasets that are older than the specified cutoff and for which the tool_id
+ contains the specified text will be marked as deleted in user's history and
+ the user will be notified by email using the specified template file.
+ """
+ parser = OptionParser()
+ parser.add_option("-d", "--days", dest="days", action="store",
+ type="int", help="number of days (60)", default=60)
+ parser.add_option("--tool_id", default=None,
+ help="Text to match against tool_id"
+ "Default: match all")
+ parser.add_option("--template", default=None,
+ help="Mako Template file to use as email "
+ "Variables are 'cutoff' for the cutoff in days, "
+ "'email' for users email and "
+ "'datasets' which is a list of tuples "
+ "containing 'dataset' and 'history' names. "
+ "Default: admin_cleanup_deletion_template.txt")
+ parser.add_option("-i", "--info_only", action="store_true",
+ dest="info_only", help="info about the requested action",
+ default=False)
+ parser.add_option("-e", "--email_only", action="store_true",
+ dest="email_only", help="Send emails only, don't delete",
+ default=False)
+ parser.add_option("--smtp", default=None,
+ help="SMTP Server to use to send email. "
+ "Default: [read from galaxy ini file]")
+ parser.add_option("--fromaddr", default=None,
+ help="From address to use to send email. "
+ "Default: [read from galaxy ini file]")
+ (options, args) = parser.parse_args()
+ ini_file = args[0]
+
+ config_parser = ConfigParser.ConfigParser({'here': os.getcwd()})
+ config_parser.read(ini_file)
+ config_dict = {}
+ for key, value in config_parser.items("app:main"):
+ config_dict[key] = value
+
+ if options.smtp is not None:
+ config_dict['smtp_server'] = options.smtp
+ if config_dict.get('smtp_server') is None:
+ parser.error("SMTP Server must be specified as an option (--smtp) "
+ "or in the config file (smtp_server)")
+
+ if options.fromaddr is not None:
+ config_dict['error_email_to'] = options.fromaddr
+ if config_dict.get('error_email_to') is None:
+ parser.error("From address must be specified as an option "
+ "(--fromaddr) or in the config file "
+ "(error_email_to)")
+
+ scriptdir = os.path.dirname(os.path.abspath(__file__))
+ template_file = options.template
+ if template_file is None:
+ default_template = os.path.join(scriptdir,
+ 'admin_cleanup_deletion_template.txt')
+ sample_template_file = "%s.sample" % default_template
+ if os.path.exists(default_template):
+ template_file = default_template
+ elif os.path.exists(sample_template_file):
+ print "Copying %s to %s" % (sample_template_file, default_template)
+ shutil.copyfile(sample_template_file, default_template)
+ template_file = default_template
+ else:
+ parser.error("Default template (%s) or sample template (%s) not "
+ "found, please specify template as an option "
+ "(--template)." % default_template,
+ sample_template_file)
+ elif not os.path.exists(template_file):
+ parser.error("Specified template file (%s) not found." % template_file)
+
+ config = galaxy.config.Configuration(**config_dict)
+
+ app = CleanupDatasetsApplication(config)
+ cutoff_time = datetime.utcnow() - timedelta(days=options.days)
+ now = strftime("%Y-%m-%d %H:%M:%S")
+
+ print "##########################################"
+ print "\n# %s - Handling stuff older than %i days" % (now, options.days)
+
+ if options.info_only:
+ print "# Displaying info only ( --info_only )\n"
+ elif options.email_only:
+ print "# Sending emails only, not deleting ( --email_only )\n"
+
+ administrative_delete_datasets(
+ app, cutoff_time, options.days, tool_id=options.tool_id,
+ template_file=template_file, config=config,
+ email_only=options.email_only, info_only=options.info_only)
+ app.shutdown()
+ sys.exit(0)
+
+
+def administrative_delete_datasets(app, cutoff_time, cutoff_days,
+ tool_id, template_file,
+ config, email_only=False,
+ info_only=False):
+ # Marks dataset history association deleted and email users
+ start = time.time()
+ # Get HDAs older than cutoff time (ignore tool_id at this point)
+ # We really only need the id column here, but sqlalchemy barfs when
+ # trying to select only 1 column
+ hda_ids_query = sa.select(
+ (app.model.HistoryDatasetAssociation.table.c.id,
+ app.model.HistoryDatasetAssociation.table.c.deleted),
+ whereclause=and_(
+ app.model.Dataset.table.c.deleted == False,
+ app.model.HistoryDatasetAssociation.table.c.update_time
+ < cutoff_time,
+ app.model.HistoryDatasetAssociation.table.c.deleted == False),
+ from_obj=[sa.outerjoin(
+ app.model.Dataset.table,
+ app.model.HistoryDatasetAssociation.table)])
+
+ # Add all datasets associated with Histories to our list
+ hda_ids = []
+ hda_ids.extend(
+ [row.id for row in hda_ids_query.execute()])
+
+ # Now find the tool_id that generated the dataset (even if it was copied)
+ tool_matched_ids = []
+ if tool_id is not None:
+ for hda_id in hda_ids:
+ this_tool_id = _get_tool_id_for_hda(app, hda_id)
+ if this_tool_id is not None and tool_id in this_tool_id:
+ tool_matched_ids.append(hda_id)
+ hda_ids = tool_matched_ids
+
+ deleted_instance_count = 0
+ user_notifications = defaultdict(list)
+
+ # Process each of the Dataset objects
+ for hda_id in hda_ids:
+ user_query = sa.select(
+ [app.model.HistoryDatasetAssociation.table,
+ app.model.History.table,
+ app.model.User.table],
+ whereclause=and_(
+ app.model.HistoryDatasetAssociation.table.c.id == hda_id),
+ from_obj=[sa.join(app.model.User.table,
+ app.model.History.table)
+ .join(app.model.HistoryDatasetAssociation.table)],
+ use_labels=True)
+ for result in user_query.execute():
+ user_notifications[result[app.model.User.table.c.email]].append(
+ (result[app.model.HistoryDatasetAssociation.table.c.name],
+ result[app.model.History.table.c.name]))
+ deleted_instance_count += 1
+ if not info_only and not email_only:
+ # Get the HistoryDatasetAssociation objects
+ hda = app.sa_session.query(
+ app.model.HistoryDatasetAssociation).get(hda_id)
+ if not hda.deleted:
+ # Mark the HistoryDatasetAssociation as deleted
+ hda.deleted = True
+ app.sa_session.add(hda)
+ print ("Marked HistoryDatasetAssociation id %d as "
+ "deleted" % hda.id)
+ app.sa_session.flush()
+
+ emailtemplate = Template(filename=template_file)
+ for (email, dataset_list) in user_notifications.iteritems():
+ msgtext = emailtemplate.render(email=email,
+ datasets=dataset_list,
+ cutoff=cutoff_days)
+ subject = "Galaxy Server Cleanup " \
+ "- %d datasets DELETED" % len(dataset_list)
+ fromaddr = config.error_email_to
+ print ""
+ print "From: %s" % fromaddr
+ print "To: %s" % email
+ print "Subject: %s" % subject
+ print "----------"
+ print msgtext
+ if not info_only:
+ #msg = MIMEText(msgtext)
+ #msg['Subject'] = subject
+ #msg['From'] = 'noone(a)nowhere.com'
+ #msg['To'] = email
+ galaxy.util.send_mail(fromaddr, email, subject,
+ msgtext, config)
+ #s = smtplib.SMTP(smtp_server)
+ #s.sendmail(['lparsons(a)princeton.edu'], email, msg.as_string())
+ #s.quit()
+
+ stop = time.time()
+ print ""
+ print "Marked %d dataset instances as deleted" % deleted_instance_count
+ print "Total elapsed time: ", stop - start
+ print "##########################################"
+
+
+def _get_tool_id_for_hda(app, hda_id):
+ # TODO Some datasets don't seem to have an entry in jtod or a copied_from
+ if hda_id is None:
+ return None
+ job = app.sa_session.query(app.model.Job).\
+ join(app.model.JobToOutputDatasetAssociation).\
+ filter(app.model.JobToOutputDatasetAssociation.table.c.dataset_id ==
+ hda_id).first()
+ if job is not None:
+ return job.tool_id
+ else:
+ hda = app.sa_session.query(app.model.HistoryDatasetAssociation).\
+ get(hda_id)
+ return _get_tool_id_for_hda(app, hda.
+ copied_from_history_dataset_association_id)
+
+
+if __name__ == "__main__":
+ main()
diff -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 -r 1e30cdb6d3b82a68da8daddc86411eecc33be444 scripts/cleanup_datasets/admin_cleanup_deletion_template.txt.sample
--- /dev/null
+++ b/scripts/cleanup_datasets/admin_cleanup_deletion_template.txt.sample
@@ -0,0 +1,11 @@
+Galaxy Server Cleanup
+---------------------
+The following datasets you own on Galaxy are older than ${cutoff} days and have been DELETED:
+
+% for dataset, history in datasets:
+ "${dataset}" in history "${history}"
+% endfor
+
+You may be able to undelete them by logging into Galaxy, navigating to the appropriate history, selecting "Include Deleted Datasets" from the history options menu, and clicking on the link to undelete each dataset that you want to keep. You can then download the datasets. Thank you for your understanding and cooporation in this necessary cleanup in order to keep the Galaxy resource available. Please don't hesitate to contact us if you have any questions.
+
+ -- Galaxy Administrators
diff -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 -r 1e30cdb6d3b82a68da8daddc86411eecc33be444 scripts/cleanup_datasets/admin_cleanup_warning_template.txt.sample
--- /dev/null
+++ b/scripts/cleanup_datasets/admin_cleanup_warning_template.txt.sample
@@ -0,0 +1,11 @@
+Galaxy Server Cleanup
+---------------------
+The following datasets you own on Galaxy are older than ${cutoff} days and will be deleted soon. Be sure to download any datasets you need to keep.
+
+% for dataset, history in datasets:
+ "${dataset}" in history "${history}"
+% endfor
+
+Please contact us if you have any questions.
+
+ -- Galaxy Administrators
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: Framework enhancements for handling installation of repositories into Galaxy that have repository dependencies that are needed only for compiling a tool dependency.
by commits-noreply@bitbucket.org 10 Sep '13
by commits-noreply@bitbucket.org 10 Sep '13
10 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/69bec229bdf8/
Changeset: 69bec229bdf8
User: greg
Date: 2013-09-10 17:59:22
Summary: Framework enhancements for handling installation of repositories into Galaxy that have repository dependencies that are needed only for compiling a tool dependency.
Affected #: 7 files
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 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
@@ -2280,8 +2280,20 @@
handled_key_rd_dicts=None )
if metadata:
if 'repository_dependencies' in metadata and not repository_dependencies:
- message += 'The repository dependency definitions for this repository are invalid and will be ignored.'
- status = 'error'
+ # See if we have an invalid repository dependency definition or if the repository dependency is required only for compiling the
+ # repository's tool dependency.
+ invalid = False
+ repository_dependencies_dict = metadata[ 'repository_dependencies' ]
+ rd_tups = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ for rd_tup in rd_tups:
+ rdtool_shed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required, rd_only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
+ if not util.asbool( rd_only_if_compiling_contained_td ):
+ invalid = True
+ break
+ if invalid:
+ message += 'The repository dependency definitions for this repository are invalid and will be ignored.'
+ status = 'error'
else:
repository_metadata_id = None
metadata = None
@@ -2718,20 +2730,8 @@
name = kwd.get( 'name', None )
owner = kwd.get( 'owner', None )
changeset_revision = kwd.get( 'changeset_revision', None )
- repository = suc.get_repository_by_name_and_owner( trans.app, name, owner )
- repo_dir = repository.repo_path( trans.app )
- repo = hg.repository( suc.get_configured_ui(), repo_dir )
- # Get the upper bound changeset revision.
- upper_bound_changeset_revision = suc.get_next_downloadable_changeset_revision( repository, repo, changeset_revision )
- # Build the list of changeset revision hashes defining each available update up to, but excluding, upper_bound_changeset_revision.
- changeset_hashes = []
- for changeset in suc.reversed_lower_upper_bounded_changelog( repo, changeset_revision, upper_bound_changeset_revision ):
- # Make sure to exclude upper_bound_changeset_revision.
- if changeset != upper_bound_changeset_revision:
- changeset_hashes.append( str( repo.changectx( changeset ) ) )
- if changeset_hashes:
- changeset_hashes_str = ','.join( changeset_hashes )
- return changeset_hashes_str
+ if name and owner and changeset_revision:
+ return suc.get_updated_changeset_revisions( trans, name, owner, changeset_revision )
return ''
@web.expose
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 lib/tool_shed/galaxy_install/install_manager.py
--- a/lib/tool_shed/galaxy_install/install_manager.py
+++ b/lib/tool_shed/galaxy_install/install_manager.py
@@ -270,7 +270,8 @@
continue
for rd_tup in rd_tups:
prior_install_ids = []
- tool_shed, name, owner, changeset_revision, prior_installation_required = common_util.parse_repository_dependency_tuple( rd_tup )
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
if util.asbool( prior_installation_required ):
for tsr in tool_shed_repositories:
if tsr.name == name and tsr.owner == owner and tsr.changeset_revision == changeset_revision:
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 lib/tool_shed/util/common_util.py
--- a/lib/tool_shed/util/common_util.py
+++ b/lib/tool_shed/util/common_util.py
@@ -46,8 +46,8 @@
if rd_key in [ 'root_key', 'description' ]:
continue
for rd_tup in rd_tups:
- tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td \
- = parse_repository_dependency_tuple( rd_tup )
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ parse_repository_dependency_tuple( rd_tup )
tool_shed_accessible, tool_dependencies = get_tool_dependencies( app,
tool_shed,
name,
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 lib/tool_shed/util/container_util.py
--- a/lib/tool_shed/util/container_util.py
+++ b/lib/tool_shed/util/container_util.py
@@ -984,7 +984,7 @@
tool_dependency_id=None,
is_orphan='Orphan' )
folder.tool_dependencies.append( tool_dependency )
- is_orphan_description = "these dependencies may not be required by tools in this repository"
+ not_used_by_local_tools_description = "these dependencies may not be required by tools in this repository"
for dependency_key, requirements_dict in tool_dependencies.items():
tool_dependency_id += 1
if dependency_key in [ 'set_environment' ]:
@@ -995,7 +995,7 @@
# TODO: handle this is Galaxy
is_orphan = False
if is_orphan:
- folder.description = is_orphan_description
+ folder.description = not_used_by_local_tools_description
name = set_environment_dict.get( 'name', None )
type = set_environment_dict[ 'type' ]
repository_id = set_environment_dict.get( 'repository_id', None )
@@ -1018,10 +1018,9 @@
if trans.webapp.name == 'tool_shed':
is_orphan = requirements_dict.get( 'is_orphan', False )
else:
- # TODO: handle this is Galaxy
is_orphan = False
if is_orphan:
- folder.description = is_orphan_description
+ folder.description = not_used_by_local_tools_description
name = requirements_dict[ 'name' ]
version = requirements_dict[ 'version' ]
type = requirements_dict[ 'type' ]
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 lib/tool_shed/util/metadata_util.py
--- a/lib/tool_shed/util/metadata_util.py
+++ b/lib/tool_shed/util/metadata_util.py
@@ -19,7 +19,9 @@
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 import install_util
from tool_shed.galaxy_install.tool_dependencies import td_common_util
+import tool_shed.repository_types.util as rt_util
import pkg_resources
@@ -904,10 +906,18 @@
repository_dependency_tups=invalid_repository_dependency_tups,
is_valid=False,
description=description )
- # Determine and store orphan tool dependencies.
- orphan_tool_dependencies = get_orphan_tool_dependencies( metadata_dict )
- if orphan_tool_dependencies:
- metadata_dict[ 'orphan_tool_dependencies' ] = orphan_tool_dependencies
+ # We need to continue to restrict the behavior of orphan tool dependencies, possibly eliminating them altoghether at some point.
+ check_for_orphan_tool_dependencies = False
+ if app.name == 'tool_shed':
+ if repository.type == rt_util.UNRESTRICTED and 'tools' not in metadata_dict:
+ check_for_orphan_tool_dependencies = True
+ elif 'tools' in metadata_dict:
+ check_for_orphan_tool_dependencies = True
+ if check_for_orphan_tool_dependencies:
+ # Determine and store orphan tool dependencies.
+ orphan_tool_dependencies = get_orphan_tool_dependencies( metadata_dict )
+ if orphan_tool_dependencies:
+ metadata_dict[ 'orphan_tool_dependencies' ] = orphan_tool_dependencies
return metadata_dict, error_message
def generate_tool_metadata( tool_config, tool, repository_clone_url, metadata_dict ):
@@ -1128,16 +1138,6 @@
sample_file_metadata_paths.append( relative_path_to_sample_file )
return sample_file_metadata_paths, sample_file_copy_paths
-def get_updated_changeset_revisions_from_tool_shed( app, tool_shed_url, name, owner, changeset_revision ):
- """
- Get all appropriate newer changeset revisions for the repository defined by the received tool_shed_url / name / owner combination.
- """
- url = suc.url_join( tool_shed_url,
- 'repository/updated_changeset_revisions?name=%s&owner=%s&changeset_revision=%s' %
- ( name, owner, changeset_revision ) )
- text = common_util.tool_shed_get( app, tool_shed_url, url )
- return text
-
def handle_existing_tool_dependencies_that_changed_in_update( app, repository, original_dependency_dict, new_dependency_dict ):
"""
This method is called when a Galaxy admin is getting updates for an installed tool shed repository in order to cover the case where an
@@ -1188,7 +1188,7 @@
return repository_dependency_tup, is_valid, error_message
else:
# Send a request to the tool shed to retrieve appropriate additional changeset revisions with which the repository may have been installed.
- text = get_updated_changeset_revisions_from_tool_shed( app, toolshed, name, owner, changeset_revision )
+ text = install_util.get_updated_changeset_revisions_from_tool_shed( app, toolshed, name, owner, changeset_revision )
if text:
updated_changeset_revisions = util.listify( text )
for updated_changeset_revision in updated_changeset_revisions:
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 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
@@ -1,7 +1,9 @@
import logging
import os
from galaxy import eggs
+from galaxy.util import asbool
from galaxy.util import json
+from galaxy.util import listify
import tool_shed.util.shed_util_common as suc
from tool_shed.util import common_util
from tool_shed.util import common_install_util
@@ -263,9 +265,9 @@
message = '%s ' % str( error )
return message
-def get_key_for_repository_changeset_revision( toolshed_base_url, repository, repository_metadata, all_repository_dependencies ):
+def get_key_for_repository_changeset_revision( trans, toolshed_base_url, repository, repository_metadata, all_repository_dependencies ):
prior_installation_required, only_if_compiling_contained_td = \
- get_prior_installation_required_and_only_if_compiling_contained_td( toolshed_base_url, repository, repository_metadata, all_repository_dependencies )
+ get_prior_installation_required_and_only_if_compiling_contained_td( trans, toolshed_base_url, repository, repository_metadata, all_repository_dependencies )
# Create a key with the value of prior_installation_required defaulted to False.
key = container_util.generate_repository_dependencies_key_for_repository( toolshed_base_url=toolshed_base_url,
repository_name=repository.name,
@@ -275,21 +277,47 @@
only_if_compiling_contained_td=only_if_compiling_contained_td )
return key
-def get_prior_installation_required_and_only_if_compiling_contained_td( toolshed_base_url, repository, repository_metadata, all_repository_dependencies ):
+def get_prior_installation_required_and_only_if_compiling_contained_td( trans, toolshed_base_url, repository, repository_metadata, all_repository_dependencies ):
"""
- If all_repository_dependencies contains a repository dependency tuple that is associated with the received repository, return the
- value of the tuple's prior_installation_required component.
+ This method is called from the tool shed and never Galaxy. If all_repository_dependencies contains a repository dependency tuple that is associated with
+ the received repository, return the value of the tuple's prior_installation_required component.
"""
- for rd_key, rd_tups in all_repository_dependencies.items():
- if rd_key in [ 'root_key', 'description' ]:
- continue
+ if all_repository_dependencies:
+ for rd_key, rd_tups in all_repository_dependencies.items():
+ if rd_key in [ 'root_key', 'description' ]:
+ continue
+ for rd_tup in rd_tups:
+ rd_toolshed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required, rd_only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
+ if rd_toolshed == toolshed_base_url and \
+ rd_name == repository.name and \
+ rd_owner == repository.user.username and \
+ rd_changeset_revision == repository_metadata.changeset_revision:
+ return rd_prior_installation_required, rd_only_if_compiling_contained_td
+ elif repository_metadata:
+ # Get the list of changeset revisions from the tool shed to which the repository may be updated.
+ metadata = repository_metadata.metadata
+ current_changeset_revision = str( repository_metadata.changeset_revision )
+ # Get the changeset revision to which the current value of required_repository_changeset_revision should be updated if it's not current.
+ text = suc.get_updated_changeset_revisions( trans,
+ name=str( repository.name ),
+ owner=str( repository.user.username ),
+ changeset_revision=current_changeset_revision )
+ if text:
+ valid_changeset_revisions = listify( text )
+ if current_changeset_revision not in valid_changeset_revisions:
+ valid_changeset_revisions.append( current_changeset_revision )
+ else:
+ valid_changeset_revisions = [ current_changeset_revision ]
+ repository_dependencies_dict = metadata[ 'repository_dependencies' ]
+ rd_tups = repository_dependencies_dict.get( 'repository_dependencies', [] )
for rd_tup in rd_tups:
rd_toolshed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required, rd_only_if_compiling_contained_td = \
common_util.parse_repository_dependency_tuple( rd_tup )
if rd_toolshed == toolshed_base_url and \
rd_name == repository.name and \
rd_owner == repository.user.username and \
- rd_changeset_revision == repository_metadata.changeset_revision:
+ rd_changeset_revision in valid_changeset_revisions:
return rd_prior_installation_required, rd_only_if_compiling_contained_td
# Default both prior_installation_required and only_if_compiling_contained_td to False.
return 'False', 'False'
@@ -333,7 +361,11 @@
metadata = repository_metadata.metadata
if metadata:
if 'repository_dependencies' in metadata:
- current_repository_key = get_key_for_repository_changeset_revision( toolshed_base_url, repository, repository_metadata, all_repository_dependencies )
+ current_repository_key = get_key_for_repository_changeset_revision( trans,
+ toolshed_base_url,
+ repository,
+ repository_metadata,
+ all_repository_dependencies )
repository_dependencies_dict = metadata[ 'repository_dependencies' ]
if not all_repository_dependencies:
all_repository_dependencies = initialize_all_repository_dependencies( current_repository_key,
@@ -583,6 +615,22 @@
return True
return False
+def filter_only_if_compiling_contained_td( key_rd_dict ):
+ """
+ Return a copy of the received key_rd_dict with repository dependencies that are needed only_if_compiling_contained_td filtered out
+ of the list of repository dependencies for each rd_key.
+ """
+ filtered_key_rd_dict = {}
+ for rd_key, required_rd_tup in key_rd_dict.items():
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( required_rd_tup )
+ if not asbool( only_if_compiling_contained_td ):
+ if rd_key in filtered_key_rd_dict:
+ filtered_key_rd_dict[ rd_key ].append( required_rd_tup )
+ else:
+ filtered_key_rd_dict[ rd_key ] = [ required_rd_tup ]
+ return filtered_key_rd_dict
+
def merge_missing_repository_dependencies_to_installed_container( containers_dict ):
"""Merge the list of missing repository dependencies into the list of installed repository dependencies."""
missing_rd_container_root = containers_dict.get( 'missing_repository_dependencies', None )
@@ -629,32 +677,35 @@
current_repository_key_rd_dicts = remove_ropository_dependency_reference_to_self( current_repository_key_rd_dicts )
current_repository_key_rd_dicts = get_updated_changeset_revisions_for_repository_dependencies( trans, current_repository_key_rd_dicts )
for key_rd_dict in current_repository_key_rd_dicts:
- is_circular = False
- if not in_key_rd_dicts( key_rd_dict, handled_key_rd_dicts ) and not in_key_rd_dicts( key_rd_dict, key_rd_dicts_to_be_processed ):
- filtered_current_repository_key_rd_dicts.append( key_rd_dict )
- repository_dependency = key_rd_dict[ current_repository_key ]
- if current_repository_key in all_repository_dependencies:
- # Add all repository dependencies for the current repository into it's entry in all_repository_dependencies.
- all_repository_dependencies_val = all_repository_dependencies[ current_repository_key ]
- if repository_dependency not in all_repository_dependencies_val:
- all_repository_dependencies_val.append( repository_dependency )
- all_repository_dependencies[ current_repository_key ] = all_repository_dependencies_val
- elif not in_all_repository_dependencies( current_repository_key, repository_dependency, all_repository_dependencies ):
- # Handle circular repository dependencies.
- if is_circular_repository_dependency( current_repository_key, repository_dependency, all_repository_dependencies ):
- is_circular = True
- circular_repository_dependencies, handled_key_rd_dicts, all_repository_dependencies = \
- handle_circular_repository_dependency( current_repository_key,
- repository_dependency,
- circular_repository_dependencies,
- handled_key_rd_dicts,
- all_repository_dependencies )
- else:
- all_repository_dependencies[ current_repository_key ] = [ repository_dependency ]
- if not is_circular and can_add_to_key_rd_dicts( key_rd_dict, key_rd_dicts_to_be_processed ):
- new_key_rd_dict = {}
- new_key_rd_dict[ current_repository_key ] = repository_dependency
- key_rd_dicts_to_be_processed.append( new_key_rd_dict )
+ # Filter out repository dependencies that are required only if compiling the dependent repository's tool dependency.
+ all_repository_dependencieskey_rd_dict = filter_only_if_compiling_contained_td( key_rd_dict )
+ if key_rd_dict:
+ is_circular = False
+ if not in_key_rd_dicts( key_rd_dict, handled_key_rd_dicts ) and not in_key_rd_dicts( key_rd_dict, key_rd_dicts_to_be_processed ):
+ filtered_current_repository_key_rd_dicts.append( key_rd_dict )
+ repository_dependency = key_rd_dict[ current_repository_key ]
+ if current_repository_key in all_repository_dependencies:
+ # Add all repository dependencies for the current repository into it's entry in all_repository_dependencies.
+ all_repository_dependencies_val = all_repository_dependencies[ current_repository_key ]
+ if repository_dependency not in all_repository_dependencies_val:
+ all_repository_dependencies_val.append( repository_dependency )
+ all_repository_dependencies[ current_repository_key ] = all_repository_dependencies_val
+ elif not in_all_repository_dependencies( current_repository_key, repository_dependency, all_repository_dependencies ):
+ # Handle circular repository dependencies.
+ if is_circular_repository_dependency( current_repository_key, repository_dependency, all_repository_dependencies ):
+ is_circular = True
+ circular_repository_dependencies, handled_key_rd_dicts, all_repository_dependencies = \
+ handle_circular_repository_dependency( current_repository_key,
+ repository_dependency,
+ circular_repository_dependencies,
+ handled_key_rd_dicts,
+ all_repository_dependencies )
+ else:
+ all_repository_dependencies[ current_repository_key ] = [ repository_dependency ]
+ if not is_circular and can_add_to_key_rd_dicts( key_rd_dict, key_rd_dicts_to_be_processed ):
+ new_key_rd_dict = {}
+ new_key_rd_dict[ current_repository_key ] = repository_dependency
+ key_rd_dicts_to_be_processed.append( new_key_rd_dict )
return filtered_current_repository_key_rd_dicts, key_rd_dicts_to_be_processed, handled_key_rd_dicts, all_repository_dependencies
def prune_invalid_repository_dependencies( repository_dependencies ):
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 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
@@ -1190,6 +1190,27 @@
return {}
return tool_shed_status_dict
+def get_updated_changeset_revisions( trans, name, owner, changeset_revision ):
+ """
+ Return a string of comma-separated changeset revision hashes for all available updates to the received changeset revision for the repository
+ defined by the received name and owner.
+ """
+ repository = get_repository_by_name_and_owner( trans.app, name, owner )
+ repo_dir = repository.repo_path( trans.app )
+ repo = hg.repository( get_configured_ui(), repo_dir )
+ # Get the upper bound changeset revision.
+ upper_bound_changeset_revision = get_next_downloadable_changeset_revision( repository, repo, changeset_revision )
+ # Build the list of changeset revision hashes defining each available update up to, but excluding, upper_bound_changeset_revision.
+ changeset_hashes = []
+ for changeset in reversed_lower_upper_bounded_changelog( repo, changeset_revision, upper_bound_changeset_revision ):
+ # Make sure to exclude upper_bound_changeset_revision.
+ if changeset != upper_bound_changeset_revision:
+ changeset_hashes.append( str( repo.changectx( changeset ) ) )
+ if changeset_hashes:
+ changeset_hashes_str = ','.join( changeset_hashes )
+ return changeset_hashes_str
+ return ''
+
def get_url_from_tool_shed( app, tool_shed ):
"""
The value of tool_shed is something like: toolshed.g2.bx.psu.edu. We need the URL to this tool shed, which is something like:
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: Dave Bouvier: Make the "keep tool dependencies" feature for the install and test framework optional.
by commits-noreply@bitbucket.org 09 Sep '13
by commits-noreply@bitbucket.org 09 Sep '13
09 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/82833b9b6f4f/
Changeset: 82833b9b6f4f
User: Dave Bouvier
Date: 2013-09-09 20:48:35
Summary: Make the "keep tool dependencies" feature for the install and test framework optional.
Affected #: 3 files
diff -r ed3c786622741814a07589a1e642cca75c51c822 -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 test/install_and_test_tool_shed_repositories/base/twilltestcase.py
--- a/test/install_and_test_tool_shed_repositories/base/twilltestcase.py
+++ b/test/install_and_test_tool_shed_repositories/base/twilltestcase.py
@@ -136,11 +136,17 @@
break
time.sleep( 1 )
- def uninstall_repository( self, installed_repository ):
+ def uninstall_repository( self, installed_repository, deactivate_only=False ):
url = '/admin_toolshed/deactivate_or_uninstall_repository?id=%s' % self.security.encode_id( installed_repository.id )
self.visit_url( url )
- tc.fv ( 1, "remove_from_disk", 'false' )
+ if deactivate_only:
+ tc.fv ( 1, "remove_from_disk", 'false' )
+ else:
+ tc.fv ( 1, "remove_from_disk", 'true' )
tc.submit( 'deactivate_or_uninstall_repository_button' )
strings_displayed = [ 'The repository named' ]
- strings_displayed.append( 'has been deactivated' )
- self.check_for_strings( strings_displayed, strings_not_displayed=[] )
+ if deactivate_only:
+ strings_displayed.append( 'has been deactivated' )
+ else:
+ strings_displayed.append( 'has been uninstalled' )
+ self.check_for_strings( strings_displayed, strings_not_displayed=[] )
\ No newline at end of file
diff -r ed3c786622741814a07589a1e642cca75c51c822 -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 test/install_and_test_tool_shed_repositories/functional/test_install_repositories.py
--- a/test/install_and_test_tool_shed_repositories/functional/test_install_repositories.py
+++ b/test/install_and_test_tool_shed_repositories/functional/test_install_repositories.py
@@ -16,7 +16,7 @@
# Install the repository through the web interface using twill.
self.install_repository( repository_info_dict )
- def do_uninstallation( self, repository_info_dict ):
+ def do_uninstallation( self, repository_info_dict, deactivate_only=False ):
self.logout()
self.login( email='test(a)bx.psu.edu', username='test' )
admin_user = test_db_util.get_user( 'test(a)bx.psu.edu' )
@@ -27,7 +27,7 @@
repository_info_dict[ 'changeset_revision' ] )
admin_user_private_role = test_db_util.get_private_role( admin_user )
# Uninstall the repository through the web interface using twill.
- self.uninstall_repository( repository )
+ self.uninstall_repository( repository, deactivate_only )
def generate_install_method( repository_dict=None ):
"""Generate abstract test cases for the defined list of repositories."""
@@ -55,7 +55,7 @@
new_class_obj = new.classobj( name, baseclasses, namespace )
G[ name ] = new_class_obj
-def generate_uninstall_method( repository_dict=None ):
+def generate_uninstall_method( repository_dict=None, deactivate_only=False ):
"""Generate abstract test cases for the defined list of repositories."""
if repository_dict is None:
return
@@ -63,20 +63,20 @@
G = globals()
# Eliminate all previous tests from G.
for key, val in G.items():
- if key.startswith( 'TestInstallRepository_' ) or key.startswith( 'TestUninstallRepository_' ) or key.startswith( 'TestForTool_' ):
+ if key.startswith( 'TestInstallRepository_' ) or key.startswith( 'TestForTool_' ):
del G[ key ]
# Create a new subclass with a method named install_repository_XXX that installs the repository specified by the provided dict.
- name = "TestUninstallRepository_" + repository_dict[ 'name' ]
+ name = "TestUninstallRepository_%s_%s" % ( repository_dict[ 'name' ], repository_dict[ 'changeset_revision' ] )
baseclasses = ( InstallTestRepositories, )
namespace = dict()
def make_uninstall_method( repository_dict ):
def test_install_repository( self ):
- self.do_uninstallation( repository_dict )
+ self.do_uninstallation( repository_dict, deactivate_only )
return test_install_repository
test_method = make_uninstall_method( repository_dict )
test_method.__doc__ = "Uninstall the repository %s." % repository_dict[ 'name' ]
- namespace[ 'uninstall_repository_%s' % repository_dict[ 'name' ] ] = test_method
+ namespace[ 'uninstall_repository_%s_%s' % ( repository_dict[ 'name' ], repository_dict[ 'changeset_revision' ] ) ] = test_method
# The new.classobj function returns a new class object, with name name, derived
# from baseclasses (which should be a tuple of classes) and with namespace dict.
new_class_obj = new.classobj( name, baseclasses, namespace )
- G[ name ] = new_class_obj
+ G[ name ] = new_class_obj
\ No newline at end of file
diff -r ed3c786622741814a07589a1e642cca75c51c822 -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 test/install_and_test_tool_shed_repositories/functional_tests.py
--- a/test/install_and_test_tool_shed_repositories/functional_tests.py
+++ b/test/install_and_test_tool_shed_repositories/functional_tests.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-# NOTE: This script cannot be run directly, because it needs to have test/functional/test_toolbox.py in sys.argv in
+# NOTE: This script cannot be run directly, because it needs to have test/functional/test_toolbox.py in sys.argv in
# order to run functional tests on repository tools after installation. The install_and_test_tool_shed_repositories.sh
# will execute this script with the appropriate parameters.
@@ -157,7 +157,7 @@
<tables></tables>
'''
-
+
# The tool shed url and api key must be set for this script to work correctly. Additionally, if the tool shed url does not
# point to one of the defaults, the GALAXY_INSTALL_TEST_TOOL_SHEDS_CONF needs to point to a tool sheds configuration file
# that contains a definition for that tool shed.
@@ -169,7 +169,7 @@
if tool_shed_api_key is None:
print "This script requires the GALAXY_INSTALL_TEST_TOOL_SHED_API_KEY environment variable to be set and non-empty."
exit( 1 )
-
+
if galaxy_tool_shed_url is None:
print "This script requires the GALAXY_INSTALL_TEST_TOOL_SHED_URL environment variable to be set and non-empty."
exit( 1 )
@@ -188,12 +188,12 @@
testing_single_repository[ 'changeset_revision' ] = os.environ[ 'repository_revision' ]
else:
testing_single_repository[ 'changeset_revision' ] = None
-
+
class ReportResults( Plugin ):
'''Simple Nose plugin to record the IDs of all tests run, regardless of success.'''
name = "reportresults"
passed = dict()
-
+
def options( self, parser, env=os.environ ):
super( ReportResults, self ).options( parser, env=env )
@@ -224,7 +224,7 @@
return passed_tests
return []
-def execute_uninstall_method( app ):
+def execute_uninstall_method( app, deactivate_only=False ):
# Clean out any generated tests.
remove_generated_tests( app )
sa_session = app.model.context.current
@@ -244,11 +244,11 @@
log.debug( 'Changeset revision %s of repository %s queued for uninstallation.', changeset_revision, name )
repository_dict = dict( name=name, owner=owner, changeset_revision=changeset_revision )
# Generate a test method to uninstall this repository through the embedded Galaxy application's web interface.
- test_install_repositories.generate_uninstall_method( repository_dict )
+ test_install_repositories.generate_uninstall_method( repository_dict, deactivate_only )
# Set up nose to run the generated uninstall method as a functional test.
test_config = nose.config.Config( env=os.environ, plugins=nose.plugins.manager.DefaultPluginManager() )
test_config.configure( sys.argv )
- # Run the uninstall method. This method uses the Galaxy web interface to uninstall the previously installed
+ # Run the uninstall method. This method uses the Galaxy web interface to uninstall the previously installed
# repository and delete it from disk.
result, _ = run_tests( test_config )
success = result.wasSuccessful()
@@ -258,7 +258,7 @@
if 'api' in parts and parts.index( 'api' ) != 0:
parts.pop( parts.index( 'api' ) )
parts.insert( 0, 'api' )
- elif 'api' not in parts:
+ elif 'api' not in parts:
parts.insert( 0, 'api' )
url = url_join( base, *parts )
if key:
@@ -318,8 +318,8 @@
NOTE: If the tool shed URL specified in any dict is not present in the tool_sheds_conf.xml, the installation will fail.
'''
assert tool_shed_api_key is not None, 'Cannot proceed without tool shed API key.'
- params = urllib.urlencode( dict( do_not_test='false',
- downloadable='true',
+ params = urllib.urlencode( dict( do_not_test='false',
+ downloadable='true',
malicious='false',
includes_tools='true',
skip_tool_test='false' ) )
@@ -334,7 +334,7 @@
repository_info_dict = get_repository_info_from_api( galaxy_tool_shed_url, repository_to_install_dict )
if repository_info_dict[ 'latest_revision' ] == '000000000000':
continue
- owner = repository_info_dict[ 'owner' ]
+ owner = repository_info_dict[ 'owner' ]
name = repository_info_dict[ 'name' ]
changeset_revision = repository_to_install_dict[ 'changeset_revision' ]
repository_id = repository_to_install_dict[ 'repository_id' ]
@@ -343,9 +343,9 @@
# and therefore do not need to be checked. If they are undeleted, this script will then test them the next time it runs.
if repository_info_dict[ 'deleted' ]:
log.info( "Skipping revision %s of repository id %s (%s/%s) since the repository is deleted...",
- changeset_revision,
- repository_id,
- name,
+ changeset_revision,
+ repository_id,
+ name,
owner )
continue
# Now merge the dict returned from /api/repository_revisions with the detailed dict we just retrieved.
@@ -360,8 +360,8 @@
else:
skipped_previous = ''
if testing_single_repository:
- log.info( 'Testing single repository with name %s and owner %s.',
- testing_single_repository[ 'name' ],
+ log.info( 'Testing single repository with name %s and owner %s.',
+ testing_single_repository[ 'name' ],
testing_single_repository[ 'owner' ])
for repository_to_install in detailed_repository_list:
if repository_to_install[ 'name' ] == testing_single_repository[ 'name' ] \
@@ -415,7 +415,7 @@
[
{
'reason': The default reason or the reason specified in this section,
- 'repositories':
+ 'repositories':
[
( name, owner, changeset revision if changeset revision else None ),
( name, owner, changeset revision if changeset revision else None )
@@ -423,7 +423,7 @@
},
{
'reason': The default reason or the reason specified in this section,
- 'repositories':
+ 'repositories':
[
( name, owner, changeset revision if changeset revision else None ),
( name, owner, changeset revision if changeset revision else None )
@@ -473,8 +473,8 @@
return update( tool_shed_api_key, '%s' % ( url_join( galaxy_tool_shed_url, 'api', 'repository_revisions', metadata_id ) ), params, return_formatted=False )
def remove_generated_tests( app ):
- # Delete any configured tool functional tests from the test_toolbox.__dict__, otherwise nose will find them
- # and try to re-run the tests after uninstalling the repository, which will cause false failure reports,
+ # Delete any configured tool functional tests from the test_toolbox.__dict__, otherwise nose will find them
+ # and try to re-run the tests after uninstalling the repository, which will cause false failure reports,
# since the test data has been deleted from disk by now.
tests_to_delete = []
tools_to_delete = []
@@ -525,7 +525,7 @@
# ---- Configuration ------------------------------------------------------
galaxy_test_host = os.environ.get( 'GALAXY_INSTALL_TEST_HOST', default_galaxy_test_host )
galaxy_test_port = os.environ.get( 'GALAXY_INSTALL_TEST_PORT', str( default_galaxy_test_port_max ) )
-
+
tool_path = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_PATH', 'tools' )
if 'HTTP_ACCEPT_LANGUAGE' not in os.environ:
os.environ[ 'HTTP_ACCEPT_LANGUAGE' ] = default_galaxy_locales
@@ -536,6 +536,11 @@
if not os.path.isdir( galaxy_test_tmp_dir ):
os.mkdir( galaxy_test_tmp_dir )
galaxy_test_proxy_port = None
+ # Allow the option to keep or delete tool dependencies when a repository has been tested.
+ if 'GALAXY_INSTALL_TEST_KEEP_TOOL_DEPENDENCIES' in os.environ:
+ deactivate_only = True
+ else:
+ deactivate_only = False
# Set up the configuration files for the Galaxy instance.
shed_tool_data_table_conf_file = os.environ.get( 'GALAXY_INSTALL_TEST_SHED_TOOL_DATA_TABLE_CONF', os.path.join( galaxy_test_tmp_dir, 'test_shed_tool_data_table_conf.xml' ) )
galaxy_tool_data_table_conf_file = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_DATA_TABLE_CONF', tool_data_table_conf )
@@ -553,19 +558,19 @@
# Configure the database connection and path.
if 'GALAXY_INSTALL_TEST_DBPATH' in os.environ:
galaxy_db_path = os.environ[ 'GALAXY_INSTALL_TEST_DBPATH' ]
- else:
+ else:
tempdir = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
galaxy_db_path = os.path.join( tempdir, 'database' )
# Configure the paths Galaxy needs to install and test tools.
galaxy_file_path = os.path.join( galaxy_db_path, 'files' )
new_repos_path = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
galaxy_tempfiles = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
- galaxy_shed_tool_path = tempfile.mkdtemp( dir=galaxy_test_tmp_dir, prefix='shed_tools' )
+ galaxy_shed_tool_path = tempfile.mkdtemp( dir=galaxy_test_tmp_dir, prefix='shed_tools' )
galaxy_migrated_tool_path = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
# Set up the tool dependency path for the Galaxy instance.
tool_dependency_dir = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_DEPENDENCY_DIR', None )
if tool_dependency_dir is None:
- tool_dependency_dir = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
+ tool_dependency_dir = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
os.environ[ 'GALAXY_INSTALL_TEST_TOOL_DEPENDENCY_DIR' ] = tool_dependency_dir
os.environ[ 'GALAXY_TOOL_DEPENDENCY_DIR' ] = tool_dependency_dir
if 'GALAXY_INSTALL_TEST_DBURI' in os.environ:
@@ -639,13 +644,13 @@
# Set the global_conf[ '__file__' ] option to the location of the temporary .ini file, which gets passed to set_metadata.sh.
kwargs[ 'global_conf' ] = get_webapp_global_conf()
kwargs[ 'global_conf' ][ '__file__' ] = galaxy_config_file
- # ---- Build Galaxy Application --------------------------------------------------
+ # ---- Build Galaxy Application --------------------------------------------------
if not database_connection.startswith( 'sqlite://' ):
kwargs[ 'database_engine_option_max_overflow' ] = '20'
kwargs[ 'database_engine_option_pool_size' ] = '10'
kwargs[ 'config_file' ] = galaxy_config_file
app = UniverseApplication( **kwargs )
-
+
log.info( "Embedded Galaxy application started" )
# ---- Run galaxy webserver ------------------------------------------------------
@@ -703,7 +708,7 @@
if additional_tool_data_tables:
app.tool_data_tables.add_new_entries_from_config_file( config_filename=additional_tool_data_tables,
tool_data_path=additional_tool_data_path,
- shed_tool_data_table_config=None,
+ shed_tool_data_table_config=None,
persist=False )
# Initialize some variables for the summary that will be printed to stdout.
repositories_passed = []
@@ -784,14 +789,14 @@
# Iterate through the list of repositories defined not to be installed. This should be a list of dicts in the following format:
# {
# 'reason': The default reason or the reason specified in this section,
- # 'repositories':
+ # 'repositories':
# [
# ( name, owner, changeset revision if changeset revision else None ),
# ( name, owner, changeset revision if changeset revision else None )
# ]
# },
# If changeset revision is None, that means the entire repository is excluded from testing, otherwise only the specified
- # revision should be skipped.
+ # revision should be skipped.
# TODO: When a repository is selected to be skipped, use the API to update the tool shed with the defined skip reason.
skip_this_repository = False
skip_because = None
@@ -831,11 +836,11 @@
log.exception( 'Error getting installed repository.' )
success = False
pass
- # If the installation succeeds, configure and run functional tests for this repository. This is equivalent to
+ # If the installation succeeds, configure and run functional tests for this repository. This is equivalent to
# sh run_functional_tests.sh -installed
if success:
log.debug( 'Installation of %s succeeded, running all defined functional tests.', name )
- # Generate the shed_tools_dict that specifies the location of test data contained within this repository. If the repository
+ # Generate the shed_tools_dict that specifies the location of test data contained within this repository. If the repository
# does not have a test-data directory, this will return has_test_data = False, and we will set the do_not_test flag to True,
# and the tools_functionally_correct flag to False, as well as updating tool_test_results.
file( galaxy_shed_tools_dict, 'w' ).write( to_json_string( dict() ) )
@@ -876,8 +881,8 @@
# 'tool_dependencies':
# [
# {
- # 'type': 'Type of tool dependency, e.g. package, set_environment, etc.',
- # 'name': 'Name of the tool dependency.',
+ # 'type': 'Type of tool dependency, e.g. package, set_environment, etc.',
+ # 'name': 'Name of the tool dependency.',
# 'version': 'Version if this is a package, otherwise blank.',
# 'error_message': 'The error message returned when installation was attempted.',
# },
@@ -885,8 +890,8 @@
# 'repository_dependencies':
# [
# {
- # 'tool_shed': 'The tool shed that this repository was installed from.',
- # 'name': 'The name of the repository that failed to install.',
+ # 'tool_shed': 'The tool shed that this repository was installed from.',
+ # 'name': 'The name of the repository that failed to install.',
# 'owner': 'Owner of the failed repository.',
# 'changeset_revision': 'Changeset revision of the failed repository.',
# 'error_message': 'The error message that was returned when the repository failed to install.',
@@ -895,8 +900,8 @@
# 'current_repository':
# [
# {
- # 'tool_shed': 'The tool shed that this repository was installed from.',
- # 'name': 'The name of the repository that failed to install.',
+ # 'tool_shed': 'The tool shed that this repository was installed from.',
+ # 'name': 'The name of the repository that failed to install.',
# 'owner': 'Owner of the failed repository.',
# 'changeset_revision': 'Changeset revision of the failed repository.',
# 'error_message': 'The error message that was returned when the repository failed to install.',
@@ -919,7 +924,7 @@
# },
# ]
# "not_tested":
- # {
+ # {
# "reason": "The Galaxy development team has determined that this repository should not be installed and tested by the automated framework."
# }
# }
@@ -949,14 +954,14 @@
params[ 'tools_functionally_correct' ] = False
params[ 'missing_test_components' ] = True
params[ 'do_not_test' ] = str( set_do_not_test )
- register_test_result( galaxy_tool_shed_url,
- metadata_revision_id,
- repository_status,
- repository_info_dict,
+ register_test_result( galaxy_tool_shed_url,
+ metadata_revision_id,
+ repository_status,
+ repository_info_dict,
params )
# Run the cleanup method. This removes tool functional test methods from the test_toolbox module and uninstalls the
# repository using Twill.
- execute_uninstall_method( app )
+ execute_uninstall_method( app, deactivate_only )
# Set the test_toolbox.toolbox module-level variable to the new app.toolbox.
test_toolbox.toolbox = app.toolbox
repositories_failed.append( dict( name=name, owner=owner, changeset_revision=changeset_revision ) )
@@ -968,15 +973,15 @@
log.error( 'Updating repository and skipping functional tests.' )
# In keeping with the standard display layout, add the error message to the dict for each tool individually.
for dependency in failed_tool_dependencies:
- test_result = dict( type=dependency.type,
- name=dependency.name,
+ test_result = dict( type=dependency.type,
+ name=dependency.name,
version=dependency.version,
error_message=dependency.error_message )
repository_status[ 'installation_errors' ][ 'tool_dependencies' ].append( test_result )
for dependency in repository.repository_dependencies_with_installation_errors:
- test_result = dict( tool_shed=dependency.tool_shed,
- name=dependency.name,
- owner=dependency.owner,
+ test_result = dict( tool_shed=dependency.tool_shed,
+ name=dependency.name,
+ owner=dependency.owner,
changeset_revision=dependency.changeset_revision,
error_message=dependency.error_message )
repository_status[ 'installation_errors' ][ 'repository_dependencies' ].append( test_result )
@@ -984,14 +989,19 @@
params[ 'tools_functionally_correct' ] = False
params[ 'do_not_test' ] = False
params[ 'test_install_error' ] = True
- register_test_result( galaxy_tool_shed_url,
- metadata_revision_id,
- repository_status,
- repository_info_dict,
+ register_test_result( galaxy_tool_shed_url,
+ metadata_revision_id,
+ repository_status,
+ repository_info_dict,
params )
# Run the cleanup method. This removes tool functional test methods from the test_toolbox module and uninstalls the
- # repository using Twill.
- execute_uninstall_method( app )
+ # repository using Twill. If tool dependencies failed installation, select to uninstall instead of deavctivate,
+ # to make way for the next attempt. Otherwise, default to the value determined by the environment variable
+ # GALAXY_INSTALL_TEST_KEEP_TOOL_DEPENDENCIES.
+ if failed_tool_dependencies:
+ execute_uninstall_method( app, deactivate_only=False )
+ else:
+ execute_uninstall_method( app, deactivate_only=deactivate_only )
# Set the test_toolbox.toolbox module-level variable to the new app.toolbox.
test_toolbox.toolbox = app.toolbox
repositories_failed_install.append( dict( name=name, owner=owner, changeset_revision=changeset_revision ) )
@@ -1007,7 +1017,7 @@
os.environ[ 'GALAXY_TEST_PORT' ] = galaxy_test_port
# Set the module-level variable 'toolbox', so that test.functional.test_toolbox will generate the appropriate test methods.
test_toolbox.toolbox = app.toolbox
- # Generate the test methods for this installed repository. We need to pass in True here, or it will look
+ # Generate the test methods for this installed repository. We need to pass in True here, or it will look
# in $GALAXY_HOME/test-data for test data, which may result in missing or invalid test files.
test_toolbox.build_tests( testing_shed_tools=True )
# Set up nose to run the generated functional tests.
@@ -1037,10 +1047,10 @@
params[ 'tools_functionally_correct' ] = True
params[ 'do_not_test' ] = False
params[ 'test_install_error' ] = False
- register_test_result( galaxy_tool_shed_url,
- metadata_revision_id,
- repository_status,
- repository_info_dict,
+ register_test_result( galaxy_tool_shed_url,
+ metadata_revision_id,
+ repository_status,
+ repository_info_dict,
params )
log.debug( 'Revision %s of repository %s installed and passed functional tests.', changeset_revision, name )
else:
@@ -1081,7 +1091,7 @@
if output_type in tmp_output:
test_status[ output_type ] = '\n'.join( tmp_output[ output_type ] )
repository_status[ 'failed_tests' ].append( test_status )
- # Call the register_test_result method, which executes a PUT request to the repository_revisions API controller with the outcome
+ # Call the register_test_result method, which executes a PUT request to the repository_revisions API controller with the outcome
# of the tests, and updates tool_test_results with the relevant log data.
# This also sets the do_not_test and tools_functionally correct flags to the appropriate values, and updates the time_last_tested
# field to today's date.
@@ -1090,19 +1100,19 @@
params[ 'tools_functionally_correct' ] = False
params[ 'test_install_error' ] = False
params[ 'do_not_test' ] = str( set_do_not_test )
- register_test_result( galaxy_tool_shed_url,
- metadata_revision_id,
- repository_status,
- repository_info_dict,
+ register_test_result( galaxy_tool_shed_url,
+ metadata_revision_id,
+ repository_status,
+ repository_info_dict,
params )
log.debug( 'Revision %s of repository %s installed successfully, but did not pass functional tests.',
- changeset_revision, name )
+ changeset_revision, name )
# Run the uninstall method. This removes tool functional test methods from the test_toolbox module and uninstalls the
# repository using Twill.
log.debug( 'Uninstalling changeset revision %s of repository %s',
- repository_info_dict[ 'changeset_revision' ],
+ repository_info_dict[ 'changeset_revision' ],
repository_info_dict[ 'name' ] )
- success = execute_uninstall_method( app )
+ success = execute_uninstall_method( app, deactivate_only )
if not success:
log.error( 'Repository %s failed to uninstall.', repository_info_dict[ 'name' ] )
# Set the test_toolbox.toolbox module-level variable to the new app.toolbox.
@@ -1115,28 +1125,28 @@
except:
log.exception( 'Unable to uninstall, no installed repository found.' )
continue
- test_result = dict( tool_shed=repository.tool_shed,
- name=repository.name,
- owner=repository.owner,
+ test_result = dict( tool_shed=repository.tool_shed,
+ name=repository.name,
+ owner=repository.owner,
changeset_revision=repository.changeset_revision,
error_message=repository.error_message )
repository_status[ 'installation_errors' ][ 'repository_dependencies' ].append( test_result )
params[ 'tools_functionally_correct' ] = False
params[ 'test_install_error' ] = True
params[ 'do_not_test' ] = False
- register_test_result( galaxy_tool_shed_url,
- metadata_revision_id,
- repository_status,
- repository_info_dict,
+ register_test_result( galaxy_tool_shed_url,
+ metadata_revision_id,
+ repository_status,
+ repository_info_dict,
params )
- success = execute_uninstall_method( app )
+ success = execute_uninstall_method( app, deactivate_only )
if not success:
log.error( 'Repository %s failed to uninstall.', repository_info_dict[ 'name' ] )
repositories_failed_install.append( dict( name=name, owner=owner, changeset_revision=changeset_revision ) )
log.debug( 'Repository %s failed to install correctly.', repository_info_dict[ 'name' ] )
except:
log.exception( "Failure running tests" )
-
+
log.info( "Shutting down" )
# ---- Tear down -----------------------------------------------------------
# Gracefully shut down the embedded web server and UniverseApplication.
@@ -1191,7 +1201,7 @@
# Normally, the value of 'success' would determine whether this test suite is marked as passed or failed
# in the automated buildbot framework. However, due to the procedure used here, we only want to report
# failure if a repository fails to install correctly. Therefore, we have overriden the value of 'success'
- # here based on what actions the script has executed.
+ # here based on what actions the script has executed.
if success:
return 0
else:
@@ -1202,4 +1212,4 @@
print "####################################################################################"
print "# %s - running repository installation and testing script." % now
print "####################################################################################"
- sys.exit( main() )
+ sys.exit( main() )
\ 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