galaxy-commits
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
commit/galaxy-central: guerler: Grids: Fix forms grid sorting
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4501db4f8ac2/
Changeset: 4501db4f8ac2
User: guerler
Date: 2013-12-12 00:41:26
Summary: Grids: Fix forms grid sorting
Affected #: 1 file
diff -r 5ab8b88ae58e99be83e6a2488a7855a02b260c18 -r 4501db4f8ac29c0c351a861611217d23159272c5 lib/galaxy/webapps/galaxy/controllers/forms.py
--- a/lib/galaxy/webapps/galaxy/controllers/forms.py
+++ b/lib/galaxy/webapps/galaxy/controllers/forms.py
@@ -65,6 +65,9 @@
global_actions = [
grids.GridAction( "Create new form", dict( controller='forms', action='create_form_definition' ) )
]
+
+ def build_initial_query( self, trans, **kwargs ):
+ return trans.sa_session.query( self.model_class ).join (model.FormDefinition, self.model_class.latest_form_id == model.FormDefinition.id)
class Forms( BaseUIController ):
# Empty TextField
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: Add modebutton jq plugin: creates an element that switches between N 'modes' of displayed contents/click functions
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5ab8b88ae58e/
Changeset: 5ab8b88ae58e
User: carlfeberhard
Date: 2013-12-11 23:47:17
Summary: Add modebutton jq plugin: creates an element that switches between N 'modes' of displayed contents/click functions
Affected #: 2 files
diff -r a0e7daee0399f71ef7203d949796cbfa0dec5ec2 -r 5ab8b88ae58e99be83e6a2488a7855a02b260c18 static/scripts/mvc/ui.js
--- a/static/scripts/mvc/ui.js
+++ b/static/scripts/mvc/ui.js
@@ -655,6 +655,147 @@
//==============================================================================
+(function(){
+ /** Multi 'mode' button (or any element really) that changes the html
+ * contents of itself when clicked. Pass in an ordered list of
+ * objects with 'html' and (optional) onclick functions.
+ *
+ * When clicked in a particular node, the onclick function will
+ * be called (with the element as this) and the element will
+ * switch to the next mode, replacing it's html content with
+ * that mode's html.
+ *
+ * If there is no next mode, the element will switch back to
+ * the first mode.
+ * @example:
+ * $( '.myElement' ).modeButton({
+ * modes : [
+ * {
+ * mode: 'bler',
+ * html: '<h5>Bler</h5>',
+ * onclick : function(){
+ * $( 'body' ).css( 'background-color', 'red' );
+ * }
+ * },
+ * {
+ * mode: 'bloo',
+ * html: '<h4>Bloo</h4>',
+ * onclick : function(){
+ * $( 'body' ).css( 'background-color', 'blue' );
+ * }
+ * },
+ * {
+ * mode: 'blah',
+ * html: '<h3>Blah</h3>',
+ * onclick : function(){
+ * $( 'body' ).css( 'background-color', 'grey' );
+ * }
+ * },
+ * ]
+ * });
+ * $( '.myElement' ).modeButton( 'callModeFn', 'bler' );
+ */
+ function ModeButton( element, options ){
+ this.currModeIndex = 0;
+ return this.init( element, options );
+ }
+
+ ModeButton.prototype.DATA_KEY = 'mode-button';
+ ModeButton.prototype.defaults = {
+ modes : [
+ { mode: 'default' }
+ ]
+ };
+
+ ModeButton.prototype.init = function _init( element, options ){
+ options = options || {};
+ this.$element = $( element );
+ this.options = jQuery.extend( true, this.defaults, options );
+
+ var modeButton = this;
+ this.$element.click( function _ModeButtonClick( event ){
+
+ // call the curr mode fn
+ modeButton.callModeFn();
+ // inc the curr mode index
+ modeButton._incModeIndex();
+ // set the element html
+ $( this ).html( modeButton.options.modes[ modeButton.currModeIndex ].html );
+ });
+
+ this.currModeIndex = 0;
+ if( this.options.initialMode ){
+ this.currModeIndex = this._getModeIndex( this.options.initialMode );
+ }
+ return this;
+ };
+
+
+ ModeButton.prototype._getModeIndex = function __getModeIndex( modeKey ){
+ for( var i=0; i<this.options.modes.length; i+=1 ){
+ if( this.options.modes[ i ].mode === modeKey ){ return i; }
+ }
+ throw new Error( 'mode not found: ' + modeKey );
+ };
+ ModeButton.prototype.getCurrMode = function _getCurrMode(){
+ return this.options.modes[ this.currModeIndex ];
+ };
+ ModeButton.prototype.getMode = function _getMode( modeKey ){
+ if( !modeKey ){ return this.getCurrMode(); }
+ return this.options.modes[( this._getModeIndex( modeKey ) )];
+ };
+ ModeButton.prototype.hasMode = function _hasMode( modeKey ){
+ return !!this.getMode( modeKey );
+ };
+ ModeButton.prototype.currentMode = function _currentMode(){
+ return this.options.modes[ this.currModeIndex ];
+ };
+ ModeButton.prototype.setMode = function _setMode( newModeKey ){
+ var newMode = this.getMode( newModeKey );
+ this.$element.html( newMode.html || null );
+ return this;
+ };
+ ModeButton.prototype._incModeIndex = function __incModeIndex(){
+ this.currModeIndex += 1;
+ if( this.currModeIndex >= this.options.modes.length ){
+ this.currModeIndex = 0;
+ }
+ return this;
+ };
+ ModeButton.prototype.callModeFn = function _callModeFn( modeKey ){
+ var modeFn = this.getMode( modeKey ).onclick;
+ if( modeFn && jQuery.type( modeFn === 'function' ) ){
+ return modeFn.call( this );
+ }
+ return undefined;
+ };
+
+ // as jq plugin
+ jQuery.fn.extend({
+ modeButton : function $modeButton( options ){
+ var nonOptionsArgs = jQuery.makeArray( arguments ).slice( 1 );
+ return this.each( function(){
+ var $this = $( this ),
+ data = $this.data( 'mode-button' );
+
+ if( jQuery.type( options ) === 'object' ){
+ data = new ModeButton( $this, options );
+ $this.data( 'mode-button', data );
+ }
+ if( data && jQuery.type( options ) === 'string' ){
+ var fn = data[ options ];
+ if( jQuery.type( fn ) === 'function' ){
+ return fn.apply( data, nonOptionsArgs );
+ }
+ }
+ return this;
+ });
+ }
+ });
+}());
+
+
+//==============================================================================
function LoadingIndicator( $where, options ){
//TODO: move out of global
//TODO: too specific to history panel
diff -r a0e7daee0399f71ef7203d949796cbfa0dec5ec2 -r 5ab8b88ae58e99be83e6a2488a7855a02b260c18 static/scripts/packed/mvc/ui.js
--- a/static/scripts/packed/mvc/ui.js
+++ b/static/scripts/packed/mvc/ui.js
@@ -1,1 +1,1 @@
-var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,is_menu_button:true,id:null,href:null,target:null,enabled:true,visible:true,tooltip_config:{}}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=this.template(this.model.toJSON());a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(_.isFunction(this.model.get("on_click"))){this.model.get("on_click")(a);return false}return true},template:function(b){var a='title="'+b.title+'" class="icon-button';if(b.is_menu_button){a+=" menu-button"}a+=" "+b.icon_class;if(!b.enabled){a+="_disabled"}a+='"';if(b.id){a+=' id="'+b.id+'"'}a+=' href="'+b.href+'"';if(b.target){a+=' target="'+b.target+'"'}if(!b.visible){a+=' style="display: none;"'}if(b.enabled){a="<a "+a+"/>"}else{a="<span "+a+"/>"}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b;if(!this.$button.size()){this.$button=$("<div/>")}this.options=a||[];var c=this;this.$button.click(function(d){$(".popmenu-wrapper").remove();c._renderAndShow(d);return false})},_renderAndShow:function(a){this.render();this.$el.appendTo("body").css(this._getShownPosition(a)).show();this._setUpCloseBehavior()},render:function(){this.$el.addClass("popmenu-wrapper").hide().css({position:"absolute"}).html(this.template(this.$button.attr("id"),this.options));if(this.options.length){var a=this;this.$el.find("li").each(function(c,b){var d=a.options[c];if(d.func){$(this).children("a.popupmenu-option").click(function(e){d.func.call(a,e,d)})}})}return this},template:function(b,a){return['<ul id="',b,'-menu" class="dropdown-menu">',this._templateOptions(a),"</ul>"].join("")},_templateOptions:function(a){if(!a.length){return"<li>(no options)</li>"}return _.map(a,function(d){if(d.divider){return'<li class="divider"></li>'}else{if(d.header){return['<li class="head"><a href="javascript:void(0);">',d.html,"</a></li>"].join("")}}var c=d.href||"javascript:void(0);",e=(d.target)?(' target="'+d.target+'"'):(""),b=(d.checked)?('<span class="fa fa-check"></span>'):("");return['<li><a class="popupmenu-option" href="',c,'"',e,">",b,d.html,"</a></li>"].join("")}).join("")},_getShownPosition:function(b){var c=this.$el.width();var a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_setUpCloseBehavior:function(){var c=this;function a(e){$(document).off("click.close_popup");if(window.parent!==window){try{$(window.parent.document).off("click.close_popup")}catch(d){}}else{try{$("iframe#galaxy_main").contents().off("click.close_popup")}catch(d){}}c.remove()}$("html").one("click.close_popup",a);if(window.parent!==window){try{$(window.parent.document).find("html").one("click.close_popup",a)}catch(b){}}else{try{$("iframe#galaxy_main").contents().one("click.close_popup",a)}catch(b){}}},addItem:function(b,a){a=(a>=0)?a:this.options.length;this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a<this.options.length;a++){if(_.has(this.options[a],"html")&&(this.options[a].html===b)){return a}}return null},findItemByHtml:function(a){return this.options[(this.findIndexByHtml(a))]},toString:function(){return"PopupMenu"}});PopupMenu.make_popupmenu=function(b,c){var a=[];_.each(c,function(f,d){var e={html:d};if(f===null){e.header=true}else{if(jQuery.type(f)==="function"){e.func=f}}a.push(e)});return new PopupMenu($(b),a)};PopupMenu.convertLinksToOptions=function(c,a){c=$(c);a=a||"a";var b=[];c.find(a).each(function(g,e){var f={},d=$(g);f.html=d.text();if(d.attr("href")){var j=d.attr("href"),k=d.attr("target"),h=d.attr("confirm");f.func=function(){if((h)&&(!confirm(h))){return}switch(k){case"_parent":window.parent.location=j;break;case"_top":window.top.location=j;break;default:window.location=j}}}b.push(f)});return b};PopupMenu.fromExistingDom=function(d,c,a){d=$(d);c=$(c);var b=PopupMenu.convertLinksToOptions(c,a);c.remove();return new PopupMenu(d,b)};PopupMenu.make_popup_menus=function(c,b,d){c=c||document;b=b||"div[popupmenu]";d=d||function(e,f){return"#"+e.attr("popupmenu")};var a=[];$(c).find(b).each(function(){var e=$(this),f=$(c).find(d(e,c));a.push(PopupMenu.fromDom(f,e));f.addClass("popup")});return a};var faIconButton=function(a){a=a||{};a.tooltipConfig=a.tooltipConfig||{placement:"bottom"};a.classes=["icon-btn"].concat(a.classes||[]);if(a.disabled){a.classes.push("disabled")}var b=['<a class="',a.classes.join(" "),'"',((a.title)?(' title="'+a.title+'"'):("")),((!a.disabled&&a.target)?(' target="'+a.target+'"'):("")),' href="',((!a.disabled&&a.href)?(a.href):("javascript:void(0);")),'">','<span class="fa ',a.faIcon,'"></span>',"</a>"].join("");var c=$(b).tooltip(a.tooltipConfig);if(_.isFunction(a.onclick)){c.click(a.onclick)}return c};(function(){function a(j,p){var d=27,m=13,c=$(j),e=true,g={initialVal:"",name:"search",placeholder:"search",classes:"",onclear:function(){},onfirstsearch:null,onsearch:function(q){},minSearchLen:0,escWillClear:true,oninit:function(){}};function i(q){var r=$(this).parent().children("input");r.val("");r.trigger("clear:searchInput");p.onclear()}function o(r,q){$(this).trigger("search:searchInput",q);if(typeof p.onfirstsearch==="function"&&e){e=false;p.onfirstsearch(q)}else{p.onsearch(q)}}function f(){return['<input type="text" name="',p.name,'" placeholder="',p.placeholder,'" ','class="search-query ',p.classes,'" ',"/>"].join("")}function l(){return $(f()).focus(function(q){$(this).select()}).keyup(function(r){if(r.which===d&&p.escWillClear){i.call(this,r)}else{var q=$(this).val();if((r.which===m)||(p.minSearchLen&&q.length>=p.minSearchLen)){o.call(this,r,q)}else{if(!q.length){i.call(this,r)}}}}).val(p.initialVal)}function k(){return $(['<span class="search-clear fa fa-times-circle" ','title="',_l("clear search (esc)"),'"></span>'].join("")).tooltip({placement:"bottom"}).click(function(q){i.call(this,q)})}function n(){return $(['<span class="search-loading fa fa-spinner fa-spin" ','title="',_l("loading..."),'"></span>'].join("")).hide().tooltip({placement:"bottom"})}function h(){c.find(".search-loading").toggle();c.find(".search-clear").toggle()}if(jQuery.type(p)==="string"){if(p==="toggle-loading"){h()}return c}if(jQuery.type(p)==="object"){p=jQuery.extend(true,g,p)}return c.addClass("search-input").prepend([l(),k(),n()])}jQuery.fn.extend({searchInput:function b(c){return this.each(function(){return a(this,c)})}})}());function LoadingIndicator(a,c){var b=this;c=jQuery.extend({cover:false},c||{});function d(){var e=['<div class="loading-indicator">','<div class="loading-indicator-text">','<span class="fa fa-spinner fa-spin fa-lg"></span>','<span class="loading-indicator-message">loading...</span>',"</div>","</div>"].join("\n");var g=$(e).hide().css(c.css||{position:"fixed"}),f=g.children(".loading-indicator-text");if(c.cover){g.css({"z-index":2,top:a.css("top"),bottom:a.css("bottom"),left:a.css("left"),right:a.css("right"),opacity:0.5,"background-color":"white","text-align":"center"});f=g.children(".loading-indicator-text").css({"margin-top":"20px"})}else{f=g.children(".loading-indicator-text").css({margin:"12px 0px 0px 10px",opacity:"0.85",color:"grey"});f.children(".loading-indicator-message").css({margin:"0px 8px 0px 0px","font-style":"italic"})}return g}b.show=function(f,e,g){f=f||"loading...";e=e||"fast";b.$indicator=d().insertBefore(a);b.message(f);b.$indicator.fadeIn(e,g);return b};b.message=function(e){b.$indicator.find("i").text(e)};b.hide=function(e,f){e=e||"fast";if(b.$indicator&&b.$indicator.size()){b.$indicator.fadeOut(e,function(){b.$indicator.remove();if(f){f()}})}else{if(f){f()}}return b};return b};
\ No newline at end of file
+var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,is_menu_button:true,id:null,href:null,target:null,enabled:true,visible:true,tooltip_config:{}}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=this.template(this.model.toJSON());a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(_.isFunction(this.model.get("on_click"))){this.model.get("on_click")(a);return false}return true},template:function(b){var a='title="'+b.title+'" class="icon-button';if(b.is_menu_button){a+=" menu-button"}a+=" "+b.icon_class;if(!b.enabled){a+="_disabled"}a+='"';if(b.id){a+=' id="'+b.id+'"'}a+=' href="'+b.href+'"';if(b.target){a+=' target="'+b.target+'"'}if(!b.visible){a+=' style="display: none;"'}if(b.enabled){a="<a "+a+"/>"}else{a="<span "+a+"/>"}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b;if(!this.$button.size()){this.$button=$("<div/>")}this.options=a||[];var c=this;this.$button.click(function(d){$(".popmenu-wrapper").remove();c._renderAndShow(d);return false})},_renderAndShow:function(a){this.render();this.$el.appendTo("body").css(this._getShownPosition(a)).show();this._setUpCloseBehavior()},render:function(){this.$el.addClass("popmenu-wrapper").hide().css({position:"absolute"}).html(this.template(this.$button.attr("id"),this.options));if(this.options.length){var a=this;this.$el.find("li").each(function(c,b){var d=a.options[c];if(d.func){$(this).children("a.popupmenu-option").click(function(e){d.func.call(a,e,d)})}})}return this},template:function(b,a){return['<ul id="',b,'-menu" class="dropdown-menu">',this._templateOptions(a),"</ul>"].join("")},_templateOptions:function(a){if(!a.length){return"<li>(no options)</li>"}return _.map(a,function(d){if(d.divider){return'<li class="divider"></li>'}else{if(d.header){return['<li class="head"><a href="javascript:void(0);">',d.html,"</a></li>"].join("")}}var c=d.href||"javascript:void(0);",e=(d.target)?(' target="'+d.target+'"'):(""),b=(d.checked)?('<span class="fa fa-check"></span>'):("");return['<li><a class="popupmenu-option" href="',c,'"',e,">",b,d.html,"</a></li>"].join("")}).join("")},_getShownPosition:function(b){var c=this.$el.width();var a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_setUpCloseBehavior:function(){var c=this;function a(e){$(document).off("click.close_popup");if(window.parent!==window){try{$(window.parent.document).off("click.close_popup")}catch(d){}}else{try{$("iframe#galaxy_main").contents().off("click.close_popup")}catch(d){}}c.remove()}$("html").one("click.close_popup",a);if(window.parent!==window){try{$(window.parent.document).find("html").one("click.close_popup",a)}catch(b){}}else{try{$("iframe#galaxy_main").contents().one("click.close_popup",a)}catch(b){}}},addItem:function(b,a){a=(a>=0)?a:this.options.length;this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a<this.options.length;a++){if(_.has(this.options[a],"html")&&(this.options[a].html===b)){return a}}return null},findItemByHtml:function(a){return this.options[(this.findIndexByHtml(a))]},toString:function(){return"PopupMenu"}});PopupMenu.make_popupmenu=function(b,c){var a=[];_.each(c,function(f,d){var e={html:d};if(f===null){e.header=true}else{if(jQuery.type(f)==="function"){e.func=f}}a.push(e)});return new PopupMenu($(b),a)};PopupMenu.convertLinksToOptions=function(c,a){c=$(c);a=a||"a";var b=[];c.find(a).each(function(g,e){var f={},d=$(g);f.html=d.text();if(d.attr("href")){var j=d.attr("href"),k=d.attr("target"),h=d.attr("confirm");f.func=function(){if((h)&&(!confirm(h))){return}switch(k){case"_parent":window.parent.location=j;break;case"_top":window.top.location=j;break;default:window.location=j}}}b.push(f)});return b};PopupMenu.fromExistingDom=function(d,c,a){d=$(d);c=$(c);var b=PopupMenu.convertLinksToOptions(c,a);c.remove();return new PopupMenu(d,b)};PopupMenu.make_popup_menus=function(c,b,d){c=c||document;b=b||"div[popupmenu]";d=d||function(e,f){return"#"+e.attr("popupmenu")};var a=[];$(c).find(b).each(function(){var e=$(this),f=$(c).find(d(e,c));a.push(PopupMenu.fromDom(f,e));f.addClass("popup")});return a};var faIconButton=function(a){a=a||{};a.tooltipConfig=a.tooltipConfig||{placement:"bottom"};a.classes=["icon-btn"].concat(a.classes||[]);if(a.disabled){a.classes.push("disabled")}var b=['<a class="',a.classes.join(" "),'"',((a.title)?(' title="'+a.title+'"'):("")),((!a.disabled&&a.target)?(' target="'+a.target+'"'):("")),' href="',((!a.disabled&&a.href)?(a.href):("javascript:void(0);")),'">','<span class="fa ',a.faIcon,'"></span>',"</a>"].join("");var c=$(b).tooltip(a.tooltipConfig);if(_.isFunction(a.onclick)){c.click(a.onclick)}return c};(function(){function a(j,p){var d=27,m=13,c=$(j),e=true,g={initialVal:"",name:"search",placeholder:"search",classes:"",onclear:function(){},onfirstsearch:null,onsearch:function(q){},minSearchLen:0,escWillClear:true,oninit:function(){}};function i(q){var r=$(this).parent().children("input");r.val("");r.trigger("clear:searchInput");p.onclear()}function o(r,q){$(this).trigger("search:searchInput",q);if(typeof p.onfirstsearch==="function"&&e){e=false;p.onfirstsearch(q)}else{p.onsearch(q)}}function f(){return['<input type="text" name="',p.name,'" placeholder="',p.placeholder,'" ','class="search-query ',p.classes,'" ',"/>"].join("")}function l(){return $(f()).focus(function(q){$(this).select()}).keyup(function(r){if(r.which===d&&p.escWillClear){i.call(this,r)}else{var q=$(this).val();if((r.which===m)||(p.minSearchLen&&q.length>=p.minSearchLen)){o.call(this,r,q)}else{if(!q.length){i.call(this,r)}}}}).val(p.initialVal)}function k(){return $(['<span class="search-clear fa fa-times-circle" ','title="',_l("clear search (esc)"),'"></span>'].join("")).tooltip({placement:"bottom"}).click(function(q){i.call(this,q)})}function n(){return $(['<span class="search-loading fa fa-spinner fa-spin" ','title="',_l("loading..."),'"></span>'].join("")).hide().tooltip({placement:"bottom"})}function h(){c.find(".search-loading").toggle();c.find(".search-clear").toggle()}if(jQuery.type(p)==="string"){if(p==="toggle-loading"){h()}return c}if(jQuery.type(p)==="object"){p=jQuery.extend(true,g,p)}return c.addClass("search-input").prepend([l(),k(),n()])}jQuery.fn.extend({searchInput:function b(c){return this.each(function(){return a(this,c)})}})}());(function(){function b(m,l){this.currModeIndex=0;return this.init(m,l)}b.prototype.DATA_KEY="mode-button";b.prototype.defaults={modes:[{mode:"default"}]};b.prototype.init=function f(m,l){l=l||{};this.$element=$(m);this.options=jQuery.extend(true,this.defaults,l);var o=this;this.$element.click(function n(p){o.callModeFn();o._incModeIndex();$(this).html(o.options.modes[o.currModeIndex].html)});this.currModeIndex=0;if(this.options.initialMode){this.currModeIndex=this._getModeIndex(this.options.initialMode)}return this};b.prototype._getModeIndex=function j(l){for(var m=0;m<this.options.modes.length;m+=1){if(this.options.modes[m].mode===l){return m}}throw new Error("mode not found: "+l)};b.prototype.getCurrMode=function a(){return this.options.modes[this.currModeIndex]};b.prototype.getMode=function g(l){if(!l){return this.getCurrMode()}return this.options.modes[(this._getModeIndex(l))]};b.prototype.hasMode=function k(l){return !!this.getMode(l)};b.prototype.currentMode=function e(){return this.options.modes[this.currModeIndex]};b.prototype.setMode=function c(m){var l=this.getMode(m);this.$element.html(l.html||null);return this};b.prototype._incModeIndex=function d(){this.currModeIndex+=1;if(this.currModeIndex>=this.options.modes.length){this.currModeIndex=0}return this};b.prototype.callModeFn=function h(l){var m=this.getMode(l).onclick;if(m&&jQuery.type(m==="function")){return m.call(this)}return undefined};jQuery.fn.extend({modeButton:function i(m){var l=jQuery.makeArray(arguments).slice(1);return this.each(function(){var p=$(this),o=p.data("mode-button");if(jQuery.type(m)==="object"){o=new b(p,m);p.data("mode-button",o)}if(o&&jQuery.type(m)==="string"){var n=o[m];if(jQuery.type(n)==="function"){return n.apply(o,l)}}return this})}})}());function LoadingIndicator(a,c){var b=this;c=jQuery.extend({cover:false},c||{});function d(){var e=['<div class="loading-indicator">','<div class="loading-indicator-text">','<span class="fa fa-spinner fa-spin fa-lg"></span>','<span class="loading-indicator-message">loading...</span>',"</div>","</div>"].join("\n");var g=$(e).hide().css(c.css||{position:"fixed"}),f=g.children(".loading-indicator-text");if(c.cover){g.css({"z-index":2,top:a.css("top"),bottom:a.css("bottom"),left:a.css("left"),right:a.css("right"),opacity:0.5,"background-color":"white","text-align":"center"});f=g.children(".loading-indicator-text").css({"margin-top":"20px"})}else{f=g.children(".loading-indicator-text").css({margin:"12px 0px 0px 10px",opacity:"0.85",color:"grey"});f.children(".loading-indicator-message").css({margin:"0px 8px 0px 0px","font-style":"italic"})}return g}b.show=function(f,e,g){f=f||"loading...";e=e||"fast";b.$indicator=d().insertBefore(a);b.message(f);b.$indicator.fadeIn(e,g);return b};b.message=function(e){b.$indicator.find("i").text(e)};b.hide=function(e,f){e=e||"fast";if(b.$indicator&&b.$indicator.size()){b.$indicator.fadeOut(e,function(){b.$indicator.remove();if(f){f()}})}else{if(f){f()}}return b};return b};
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: History view: allow switching when viewing own
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a0e7daee0399/
Changeset: a0e7daee0399
User: carlfeberhard
Date: 2013-12-11 23:29:22
Summary: History view: allow switching when viewing own
Affected #: 1 file
diff -r d19e22bce1b880b86b6245760bdf0d8c7d13366e -r a0e7daee0399f71ef7203d949796cbfa0dec5ec2 templates/webapps/galaxy/history/view.mako
--- a/templates/webapps/galaxy/history/view.mako
+++ b/templates/webapps/galaxy/history/view.mako
@@ -17,6 +17,13 @@
<script type="text/javascript">
$(function() {
init_history_items( $("div.historyItemWrapper"), false, "nochanges" );
+ $( '#switch-to-link' ).click( function( event ){
+ var galaxy = window.Galaxy || window.parent.Galaxy;
+ if( galaxy ){
+ galaxy.currHistoryPanel.switchToHistory( '${ trans.security.encode_id( history.id ) }' );
+ }
+ });
+ $( '#refresh' ).click( function( event ){ window.location.reload( true ); })
});
</script></%def>
@@ -119,9 +126,15 @@
</div><div id="top-links" class="historyLinks" style="padding: 0px 0px 5px 0px">
- %if not history.purged:
- <a href="${h.url_for(controller='history', action='imp', id=trans.security.encode_id(history.id) )}">import and start using history</a> |
- <a href="${get_history_link( history )}">${_('refresh')}</a> |
+ %if not history.purged and history.user != trans.user:
+ ##TODO: need to remove _top
+ <a href="${h.url_for(controller='history', action='imp', id=trans.security.encode_id(history.id) )}"
+ >import and start using history</a> |
+ <a id="refresh" href="javascript:void(0)" >${_('refresh')}</a> |
+ %endif
+ %if not history.purged and history.user == trans.user:
+ <a id="switch-to-link" href="javascript:void(0)">${_('switch to this history')}</a> |
+ <a id="refresh" href="javascript:void(0)" >${_('refresh')}</a> |
%endif
%if show_deleted:
<a href="${h.url_for(controller='history', action='view', id=trans.security.encode_id(history.id), show_deleted=False, use_panels=use_panels )}">${_('hide deleted')}</a> |
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: UI: Fix nested history bug
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d19e22bce1b8/
Changeset: d19e22bce1b8
User: guerler
Date: 2013-12-11 22:39:20
Summary: UI: Fix nested history bug
Affected #: 1 file
diff -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc -r d19e22bce1b880b86b6245760bdf0d8c7d13366e lib/galaxy/webapps/galaxy/controllers/history.py
--- a/lib/galaxy/webapps/galaxy/controllers/history.py
+++ b/lib/galaxy/webapps/galaxy/controllers/history.py
@@ -838,8 +838,8 @@
# Set imported history to be user's current history.
trans.set_history( new_history )
return trans.show_ok_message(
- message="""History "%s" has been imported. <br>You can <a href="%s">start using this history</a> or %s."""
- % ( new_history.name, web.url_for( '/' ), referer_message ), use_panels=True )
+ message="""History "%s" has been imported. <br>You can <a href="%s" onclick="parent.window.location='%s';">start using this history</a> or %s."""
+ % ( new_history.name, web.url_for( '/' ), web.url_for( '/' ), referer_message ), use_panels=True )
elif not user_history or not user_history.datasets or confirm:
new_history = import_history.copy()
new_history.name = "imported: " + new_history.name
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Allow a tool dependency to be uninstalled from Galaxy only if it is in an error state. Allow an installed repository to be uninstalled from Galaxy only if it has no dependent repositories and none of its contents are dependencies of other repository contents.
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/b56f6e027d2c/
Changeset: b56f6e027d2c
User: greg
Date: 2013-12-11 22:36:32
Summary: Allow a tool dependency to be uninstalled from Galaxy only if it is in an error state. Allow an installed repository to be uninstalled from Galaxy only if it has no dependent repositories and none of its contents are dependencies of other repository contents.
Affected #: 13 files
diff -r 392469f092a67318ed25a4c675e72850e0a8f4b4 -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -87,7 +87,8 @@
self.install_model = install_mapping.init( install_db_url,
install_db_engine_options )
# Manage installed tool shed repositories.
- self.installed_repository_manager = tool_shed.galaxy_install.InstalledRepositoryManager( self )
+ from tool_shed.galaxy_install import installed_repository_manager
+ self.installed_repository_manager = installed_repository_manager.InstalledRepositoryManager( self )
# Create an empty datatypes registry.
self.datatypes_registry = galaxy.datatypes.registry.Registry()
# Load proprietary datatypes defined in datatypes_conf.xml files in all installed tool shed repositories. We
diff -r 392469f092a67318ed25a4c675e72850e0a8f4b4 -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc lib/galaxy/model/tool_shed_install/__init__.py
--- a/lib/galaxy/model/tool_shed_install/__init__.py
+++ b/lib/galaxy/model/tool_shed_install/__init__.py
@@ -1,10 +1,7 @@
import os
-
from galaxy.model.item_attrs import Dictifiable
-
from galaxy.util.bunch import Bunch
from galaxy.util import asbool
-
from tool_shed.util import common_util
@@ -61,9 +58,38 @@
def can_reset_metadata( self ):
return self.status == self.installation_status.INSTALLED
- @property
- def can_uninstall( self ):
- return self.status != self.installation_status.UNINSTALLED
+ def can_uninstall( self, app ):
+ # An installed repository cannot be uninstalled if other installed repositories or installed repository
+ # contents (i.e., tool dependencies) require it.
+ if self.status == self.installation_status.UNINSTALLED:
+ return False
+ irm = app.installed_repository_manager
+ # Find other installed repositories that require this repository.
+ for repository in irm.repository_dependencies_of_installed_repositories:
+ if repository.id == self.id:
+ installed_repository_dependencies = \
+ irm.installed_repository_dependencies_of_installed_repositories[ repository ]
+ if installed_repository_dependencies:
+ # This repository cannot be uninstalled because other installed repositories require it.
+ return False
+ # Find installed tool dependencies that require this repository's installed tool dependencies.
+ installed_tool_dependencies = []
+ for repository in irm.installed_tool_dependencies_of_installed_repositories:
+ if repository.id == self.id:
+ installed_tool_dependencies = \
+ irm.installed_tool_dependencies_of_installed_repositories[ repository ]
+ break
+ for td in installed_tool_dependencies:
+ if td.id in irm.ids_of_installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies_keys:
+ for installed_td in irm.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies:
+ if installed_td.id == td.id:
+ installed_dependent_tds = \
+ irm.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies[ installed_td ]
+ if installed_dependent_tds:
+ # This repository cannot be uninstalled because it contains installed tool dependencies that
+ # are required at run time by other installed tool dependencies.
+ return False
+ return True
@property
def can_deactivate( self ):
@@ -218,7 +244,7 @@
@property
def installed_tool_dependencies( self ):
- """Return the repository's tool dependencies that are currently installed."""
+ """Return the repository's tool dependencies that are currently installed, but possibly in an error state."""
installed_dependencies = []
for tool_dependency in self.tool_dependencies:
if tool_dependency.status in [ ToolDependency.installation_status.INSTALLED,
@@ -313,9 +339,9 @@
required_repositories_missing_or_being_installed = []
for required_repository in self.repository_dependencies:
if required_repository.status in [ self.installation_status.ERROR,
- self.installation_status.INSTALLING,
- self.installation_status.NEVER_INSTALLED,
- self.installation_status.UNINSTALLED ]:
+ self.installation_status.INSTALLING,
+ self.installation_status.NEVER_INSTALLED,
+ self.installation_status.UNINSTALLED ]:
required_repositories_missing_or_being_installed.append( required_repository )
return required_repositories_missing_or_being_installed
@@ -507,7 +533,9 @@
@property
def can_uninstall( self ):
- return self.status in [ self.installation_status.ERROR, self.installation_status.INSTALLED ]
+ # A tool dependency can be uninstalled only if it is currently in an error state. Only the containing
+ # repository can be uninstalled if a tool dependency is properly installed.
+ return self.status in [ self.installation_status.ERROR ]
@property
def can_update( self ):
@@ -516,6 +544,13 @@
self.installation_status.ERROR,
self.installation_status.UNINSTALLED ]
+ def get_env_shell_file_path( self, app ):
+ installation_directory = self.installation_directory( app )
+ file_path = os.path.join( installation_directory, 'env.sh' )
+ if os.path.exists( file_path ):
+ return file_path
+ return None
+
@property
def in_error_state( self ):
return self.status == self.installation_status.ERROR
@@ -536,6 +571,10 @@
self.tool_shed_repository.name,
self.tool_shed_repository.installed_changeset_revision )
+ @property
+ def is_installed( self ):
+ return self.status == self.installation_status.INSTALLED
+
class ToolVersion( object, Dictifiable ):
dict_element_visible_keys = ( 'id', 'tool_shed_repository' )
@@ -549,23 +588,23 @@
def get_previous_version( self, app ):
context = app.install_model.context
tva = context.query( app.install_model.ToolVersionAssociation ) \
- .filter( app.install_model.ToolVersionAssociation.table.c.tool_id == self.id ) \
- .first()
+ .filter( app.install_model.ToolVersionAssociation.table.c.tool_id == self.id ) \
+ .first()
if tva:
return context.query( app.install_model.ToolVersion ) \
- .filter( app.install_model.ToolVersion.table.c.id == tva.parent_id ) \
- .first()
+ .filter( app.install_model.ToolVersion.table.c.id == tva.parent_id ) \
+ .first()
return None
def get_next_version( self, app ):
context = app.install_model.context
tva = context.query( app.install_model.ToolVersionAssociation ) \
- .filter( app.install_model.ToolVersionAssociation.table.c.parent_id == self.id ) \
- .first()
+ .filter( app.install_model.ToolVersionAssociation.table.c.parent_id == self.id ) \
+ .first()
if tva:
return context.query( app.install_model.ToolVersion ) \
- .filter( app.install_model.ToolVersion.table.c.id == tva.tool_id ) \
- .first()
+ .filter( app.install_model.ToolVersion.table.c.id == tva.tool_id ) \
+ .first()
return None
def get_versions( self, app ):
diff -r 392469f092a67318ed25a4c675e72850e0a8f4b4 -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc lib/galaxy/model/tool_shed_install/mapping.py
--- a/lib/galaxy/model/tool_shed_install/mapping.py
+++ b/lib/galaxy/model/tool_shed_install/mapping.py
@@ -7,10 +7,8 @@
from galaxy.model.base import ModelMapping
from galaxy.model.orm.engine_factory import build_engine
-
metadata = MetaData()
-
install_model.ToolShedRepository.table = Table( "tool_shed_repository", metadata,
Column( "id", Integer, primary_key=True ),
Column( "create_time", DateTime, default=now ),
@@ -72,7 +70,6 @@
Column( "repository_path", TEXT ),
Column( "version", Integer ) )
-
mapper( install_model.ToolShedRepository, install_model.ToolShedRepository.table,
properties=dict( tool_versions=relation( install_model.ToolVersion,
primaryjoin=( install_model.ToolShedRepository.table.c.id == install_model.ToolVersion.table.c.tool_shed_repository_id ),
@@ -112,17 +109,13 @@
"""Connect mappings to the database"""
# Load the appropriate db module
engine = build_engine( url, engine_options )
-
# Connect the metadata to the database.
metadata.bind = engine
-
- result = ModelMapping([install_model], engine=engine)
-
+ result = ModelMapping( [ install_model ], engine=engine )
# Create tables if needed
if create_tables:
metadata.create_all()
# metadata.engine.commit()
-
result.create_tables = create_tables
#load local galaxy security policy
return result
diff -r 392469f092a67318ed25a4c675e72850e0a8f4b4 -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -265,6 +265,9 @@
if remove_from_disk_checked:
tool_shed_repository.status = trans.install_model.ToolShedRepository.installation_status.UNINSTALLED
tool_shed_repository.error_message = None
+ # Remove the uninstalled repository and any tool dependencies from the in-memory dictionaries in the
+ # installed_repository_manager.
+ trans.app.installed_repository_manager.handle_uninstall( tool_shed_repository )
else:
tool_shed_repository.status = trans.install_model.ToolShedRepository.installation_status.DEACTIVATED
trans.install_model.context.add( tool_shed_repository )
@@ -1564,7 +1567,7 @@
tool_shed_repository = tool_dependencies[ 0 ].tool_shed_repository
if kwd.get( 'uninstall_tool_dependencies_button', False ):
errors = False
- # Filter tool dependencies to only those that are installed.
+ # Filter tool dependencies to only those that are installed but in an error state.
tool_dependencies_for_uninstallation = []
for tool_dependency in tool_dependencies:
if tool_dependency.can_uninstall:
diff -r 392469f092a67318ed25a4c675e72850e0a8f4b4 -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc lib/tool_shed/galaxy_install/__init__.py
--- a/lib/tool_shed/galaxy_install/__init__.py
+++ b/lib/tool_shed/galaxy_install/__init__.py
@@ -1,54 +0,0 @@
-"""
-Classes encapsulating the management of repositories installed from Galaxy tool sheds.
-"""
-import os, logging
-import tool_shed.util.shed_util_common
-import tool_shed.util.datatype_util
-from galaxy.model.orm import and_
-from tool_shed.util import xml_util
-
-log = logging.getLogger( __name__ )
-
-class InstalledRepositoryManager( object ):
- def __init__( self, app ):
- self.app = app
- self.install_model = self.app.install_model
- self.context = self.install_model.context
- self.tool_configs = self.app.config.tool_configs
- if self.app.config.migrated_tools_config not in self.tool_configs:
- self.tool_configs.append( self.app.config.migrated_tools_config )
- self.installed_repository_dicts = []
- def get_repository_install_dir( self, tool_shed_repository ):
- for tool_config in self.tool_configs:
- tree, error_message = xml_util.parse_xml( tool_config )
- if tree is None:
- return None
- root = tree.getroot()
- tool_path = root.get( 'tool_path', None )
- if tool_path:
- ts = tool_shed.util.shed_util_common.clean_tool_shed_url( tool_shed_repository.tool_shed )
- relative_path = os.path.join( tool_path,
- ts,
- 'repos',
- tool_shed_repository.owner,
- tool_shed_repository.name,
- tool_shed_repository.installed_changeset_revision )
- if os.path.exists( relative_path ):
- return relative_path
- return None
- def load_proprietary_datatypes( self ):
- for tool_shed_repository in self.context.query( self.install_model.ToolShedRepository ) \
- .filter( and_( self.install_model.ToolShedRepository.table.c.includes_datatypes==True,
- self.install_model.ToolShedRepository.table.c.deleted==False ) ) \
- .order_by( self.install_model.ToolShedRepository.table.c.id ):
- relative_install_dir = self.get_repository_install_dir( tool_shed_repository )
- if relative_install_dir:
- installed_repository_dict = tool_shed.util.datatype_util.load_installed_datatypes( self.app, tool_shed_repository, relative_install_dir )
- if installed_repository_dict:
- self.installed_repository_dicts.append( installed_repository_dict )
- def load_proprietary_converters_and_display_applications( self, deactivate=False ):
- for installed_repository_dict in self.installed_repository_dicts:
- if installed_repository_dict[ 'converter_path' ]:
- tool_shed.util.datatype_util.load_installed_datatype_converters( self.app, installed_repository_dict, deactivate=deactivate )
- if installed_repository_dict[ 'display_path' ]:
- tool_shed.util.datatype_util.load_installed_display_applications( self.app, installed_repository_dict, deactivate=deactivate )
diff -r 392469f092a67318ed25a4c675e72850e0a8f4b4 -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc lib/tool_shed/galaxy_install/installed_repository_manager.py
--- /dev/null
+++ b/lib/tool_shed/galaxy_install/installed_repository_manager.py
@@ -0,0 +1,340 @@
+"""
+Class encapsulating the management of repositories installed from Galaxy tool sheds.
+"""
+import logging
+import os
+import tool_shed.util.shed_util_common as suc
+from tool_shed.util import datatype_util
+from tool_shed.util import repository_dependency_util
+from tool_shed.util import tool_dependency_util
+from tool_shed.util import xml_util
+from galaxy.model.orm import and_
+
+log = logging.getLogger( __name__ )
+
+
+class InstalledRepositoryManager( object ):
+
+ def __init__( self, app ):
+ """
+ Among other things, eep in in-memory set of installed repositories and tool dependencies along with the relationships
+ between each of them. This will allow for quick discovery of those repositories or components that can be uninstalled.
+ The feature allowing a Galaxy administrator to uninstall a repository should not be available to repositories or tool
+ dependency packages that are required by other repositories or their contents (packages). The uninstall feature should
+ be available only at the repository hierarchy level where every dependency will be uninstalled. The exception for this
+ is if an item (repository or tool dependency package) is not in an INSTALLED state - in these cases, the specific item
+ can be uninstalled in order to attempt re-installation.
+ """
+ self.app = app
+ self.install_model = self.app.install_model
+ self.context = self.install_model.context
+ self.tool_configs = self.app.config.tool_configs
+ if self.app.config.migrated_tools_config not in self.tool_configs:
+ self.tool_configs.append( self.app.config.migrated_tools_config )
+ self.installed_repository_dicts = []
+ # Keep an in-memory dictionary whose keys are tool_shed_repository objects (whose status is 'Installed') and whose values
+ # are a list of tool_shed_repository objects (whose status can be anything) required by the key. The value defines the
+ # entire repository dependency tree.
+ self.repository_dependencies_of_installed_repositories = {}
+ # Keep an in-memory dictionary whose keys are tool_shed_repository objects (whose status is 'Installed') and whose values
+ # are a list of tool_shed_repository objects (whose status is 'Installed') required by the key. The value defines the
+ # entire repository dependency tree.
+ self.installed_repository_dependencies_of_installed_repositories = {}
+ # Keep an in-memory dictionary whose keys are tool_shed_repository objects (whose status is 'Installed') and whose values
+ # are a list of its immediate tool_dependency objects (whose status can be anything). The value defines only the immediate
+ # tool dependencies of the repository and does not include any dependencies of the tool dependencies.
+ self.tool_dependencies_of_installed_repositories = {}
+ # Keep an in-memory dictionary whose keys are tool_shed_repository objects (whose status is 'Installed') and whose values
+ # are a list of its immediate tool_dependency objects (whose status is 'Installed'). The value defines only the immediate
+ # tool dependencies of the repository and does not include any dependencies of the tool dependencies.
+ self.installed_tool_dependencies_of_installed_repositories = {}
+ # Keep an in-memory dictionary whose keys are tool_dependency objects (whose status is 'Installed') and whose values are
+ # a list of tool_dependency objects (whose status can be anything) required by the installed tool dependency at runtime.
+ # The value defines the entire tool dependency tree.
+ self.runtime_tool_dependencies_of_installed_tool_dependencies = {}
+ # Keep an in-memory dictionary whose keys are tool_dependency objects (whose status is 'Installed') and whose values are
+ # a list of tool_dependency objects (whose status is 'Installed') that require the key at runtime. The value defines the
+ # entire tool dependency tree.
+ self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies = {}
+ # Load defined dependency relationships for installed tool shed repositories and their contents.
+ self.load_dependency_relationships()
+
+ def add_entry_to_installed_repository_dependencies_of_installed_repositories( self, repository ):
+ """Add an entry to self.installed_repository_dependencies_of_installed_repositories."""
+ if repository.id not in self.ids_of_installed_repository_dependencies_of_installed_repositories_keys:
+ debug_msg = "Adding an entry for revision %s of repository %s owned by %s " % \
+ ( str( repository.changeset_revision ), str( repository.name ), str( repository.owner ) )
+ debug_msg += "to installed_repository_dependencies_of_installed_repositories."
+ log.debug( debug_msg )
+ status = self.install_model.ToolShedRepository.installation_status.INSTALLED
+ repository_dependency_tree = \
+ repository_dependency_util.get_repository_dependency_tree_for_repository( self.app,
+ repository,
+ status=status )
+ self.installed_repository_dependencies_of_installed_repositories[ repository ] = \
+ repository_dependency_tree
+
+ def add_entry_to_installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies( self, tool_dependency ):
+ """Add an entry to self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies."""
+ if tool_dependency.id not in self.ids_of_installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies_keys:
+ debug_msg = "Adding an entry for version %s of %s %s " % \
+ ( str( tool_dependency.version ), str( tool_dependency.type ), str( tool_dependency.name ) )
+ debug_msg += "to installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies."
+ log.debug( debug_msg )
+ status = self.install_model.ToolDependency.installation_status.INSTALLED
+ installed_runtime_dependent_tool_dependencies = \
+ tool_dependency_util.get_runtime_dependent_tool_dependencies( self.app, tool_dependency, status=status )
+ self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies[ tool_dependency ] = \
+ installed_runtime_dependent_tool_dependencies
+
+ def add_entry_to_installed_tool_dependencies_of_installed_repositories( self, repository ):
+ """Add an entry to self.installed_tool_dependencies_of_installed_repositories."""
+ if repository.id not in self.ids_of_installed_tool_dependencies_of_installed_repositories_keys:
+ debug_msg = "Adding an entry for revision %s of repository %s owned by %s " % \
+ ( str( repository.changeset_revision ), str( repository.name ), str( repository.owner ) )
+ debug_msg += "to installed_tool_dependencies_of_installed_repositories."
+ log.debug( debug_msg )
+ installed_tool_dependencies = []
+ for td in repository.tool_dependencies:
+ if td.status == self.app.install_model.ToolDependency.installation_status.INSTALLED:
+ installed_tool_dependencies.append( td )
+ self.installed_tool_dependencies_of_installed_repositories[ repository ] = installed_tool_dependencies
+
+ def add_entry_to_repository_dependencies_of_installed_repositories( self, repository ):
+ """Add an entry to self.repository_dependencies_of_installed_repositories."""
+ if repository.id not in self.ids_of_repository_dependencies_of_installed_repositories_keys:
+ debug_msg = "Adding an entry for revision %s of repository %s owned by %s " % \
+ ( str( repository.changeset_revision ), str( repository.name ), str( repository.owner ) )
+ debug_msg += "to repository_dependencies_of_installed_repositories."
+ log.debug( debug_msg )
+ repository_dependency_tree = \
+ repository_dependency_util.get_repository_dependency_tree_for_repository( self.app,
+ repository,
+ status=None )
+ self.repository_dependencies_of_installed_repositories[ repository ] = repository_dependency_tree
+
+ def add_entry_to_runtime_tool_dependencies_of_installed_tool_dependencies( self, tool_dependency ):
+ """Add an entry to self.runtime_tool_dependencies_of_installed_tool_dependencies."""
+ if tool_dependency.id not in self.ids_of_runtime_tool_dependencies_of_installed_tool_dependencies_keys:
+ debug_msg = "Adding an entry for version %s of %s %s " % \
+ ( str( tool_dependency.version ), str( tool_dependency.type ), str( tool_dependency.name ) )
+ debug_msg += "to runtime_tool_dependencies_of_installed_tool_dependencies."
+ log.debug( debug_msg )
+ runtime_dependent_tool_dependencies = \
+ tool_dependency_util.get_runtime_dependent_tool_dependencies( self.app, tool_dependency, status=None )
+ self.runtime_tool_dependencies_of_installed_tool_dependencies[ tool_dependency ] = \
+ runtime_dependent_tool_dependencies
+
+ def add_entry_to_tool_dependencies_of_installed_repositories( self, repository ):
+ """Add an entry to self.tool_dependencies_of_installed_repositories."""
+ if repository.id not in self.ids_of_tool_dependencies_of_installed_repositories_keys:
+ debug_msg = "Adding an entry for revision %s of repository %s owned by %s " % \
+ ( str( repository.changeset_revision ), str( repository.name ), str( repository.owner ) )
+ debug_msg += "to tool_dependencies_of_installed_repositories."
+ log.debug( debug_msg )
+ self.tool_dependencies_of_installed_repositories[ repository ] = repository.tool_dependencies
+
+ def get_containing_repository_for_tool_dependency( self, tool_dependency ):
+ for installed_repository, tool_dependencies in self.tool_dependencies_of_installed_repositories.items():
+ td_ids = [ td.id for td in tool_dependencies ]
+ if tool_dependency.id in td_ids:
+ return installed_repository
+ return None
+
+ def get_repository_install_dir( self, tool_shed_repository ):
+ for tool_config in self.tool_configs:
+ tree, error_message = xml_util.parse_xml( tool_config )
+ if tree is None:
+ return None
+ root = tree.getroot()
+ tool_path = root.get( 'tool_path', None )
+ if tool_path:
+ ts = suc.clean_tool_shed_url( tool_shed_repository.tool_shed )
+ relative_path = os.path.join( tool_path,
+ ts,
+ 'repos',
+ tool_shed_repository.owner,
+ tool_shed_repository.name,
+ tool_shed_repository.installed_changeset_revision )
+ if os.path.exists( relative_path ):
+ return relative_path
+ return None
+
+ def handle_install( self, repository ):
+ """Load the dependency relationships for a repository that was just installed or reinstalled."""
+ # Populate self.repository_dependencies_of_installed_repositories.
+ self.add_entry_to_repository_dependencies_of_installed_repositories( repository )
+ # Populate self.installed_repository_dependencies_of_installed_repositories.
+ self.add_entry_to_installed_repository_dependencies_of_installed_repositories( repository )
+ # Populate self.tool_dependencies_of_installed_repositories.
+ self.add_entry_to_tool_dependencies_of_installed_repositories( repository )
+ # Populate self.installed_tool_dependencies_of_installed_repositories.
+ self.add_entry_to_installed_tool_dependencies_of_installed_repositories( repository )
+ for tool_dependency in repository.tool_dependencies:
+ # Populate self.runtime_tool_dependencies_of_installed_tool_dependencies.
+ self.add_entry_to_runtime_tool_dependencies_of_installed_tool_dependencies( tool_dependency )
+ # Populate self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies.
+ self.add_entry_to_installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies( tool_dependency )
+
+ def handle_uninstall( self, repository ):
+ """Remove the dependency relationships for a repository that was just uninstalled."""
+ for tool_dependency in repository.tool_dependencies:
+ # Remove all this tool_dependency from all values in
+ # self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies
+ altered_installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies = {}
+ for td, installed_runtime_dependent_tool_dependencies in \
+ self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies.items():
+ irdtd_ids = [ irdtd.id for irdtd in installed_runtime_dependent_tool_dependencies ]
+ if td.id in irdtd_ids:
+ index = irdtd_ids[ td.id ]
+ # Remove the tool_dependency from the list.
+ del installed_runtime_dependent_tool_dependencies[ index ]
+ # Add the possibly altered list to the altered dictionary.
+ altered_installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies[ td ] = \
+ installed_runtime_dependent_tool_dependencies
+ self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies = \
+ altered_installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies
+ # Remove the entry for this tool_dependency from self.runtime_tool_dependencies_of_installed_tool_dependencies.
+ self.remove_entry_from_runtime_tool_dependencies_of_installed_tool_dependencies( tool_dependency )
+ # Remove the entry for this tool_dependency from
+ # self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies.
+ self.remove_entry_from_installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies( tool_dependency )
+ # Remove this repository's entry from self.installed_tool_dependencies_of_installed_repositories.
+ self.remove_entry_from_installed_tool_dependencies_of_installed_repositories( repository )
+ # Remove this repository's entry from self.tool_dependencies_of_installed_repositories
+ self.remove_entry_from_tool_dependencies_of_installed_repositories( repository )
+ # Remove this repository's entry from self.installed_repository_dependencies_of_installed_repositories.
+ self.remove_entry_from_installed_repository_dependencies_of_installed_repositories( repository )
+ # Remove this repository's entry from self.repository_dependencies_of_installed_repositories.
+ self.remove_entry_from_repository_dependencies_of_installed_repositories( repository )
+
+ @property
+ def ids_of_installed_repository_dependencies_of_installed_repositories_keys( self ):
+ return [ r.id for r in self.installed_repository_dependencies_of_installed_repositories.keys() ]
+
+ @property
+ def ids_of_installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies_keys( self ):
+ return [ td.id for td in self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies.keys() ]
+
+ @property
+ def ids_of_installed_tool_dependencies_of_installed_repositories_keys( self ):
+ return [ r.id for r in self.installed_tool_dependencies_of_installed_repositories.keys() ]
+
+ @property
+ def ids_of_repository_dependencies_of_installed_repositories_keys( self ):
+ return [ r.id for r in self.repository_dependencies_of_installed_repositories.keys() ]
+
+ @property
+ def ids_of_runtime_tool_dependencies_of_installed_tool_dependencies_keys( self ):
+ return [ td.id for td in self.runtime_tool_dependencies_of_installed_tool_dependencies.keys() ]
+
+ @property
+ def ids_of_tool_dependencies_of_installed_repositories_keys( self ):
+ return [ r.id for r in self.tool_dependencies_of_installed_repositories.keys() ]
+
+ def load_dependency_relationships( self ):
+ """Load relationships for all installed repositories and tool dependencies into in-memnory dictionaries."""
+ # Get the list of installed tool shed repositories.
+ for repository in self.context.query( self.app.install_model.ToolShedRepository ) \
+ .filter( self.app.install_model.ToolShedRepository.table.c.status ==
+ self.app.install_model.ToolShedRepository.installation_status.INSTALLED ):
+ # Populate self.repository_dependencies_of_installed_repositories.
+ self.add_entry_to_repository_dependencies_of_installed_repositories( repository )
+ # Populate self.installed_repository_dependencies_of_installed_repositories.
+ self.add_entry_to_installed_repository_dependencies_of_installed_repositories( repository )
+ # Populate self.tool_dependencies_of_installed_repositories.
+ self.add_entry_to_tool_dependencies_of_installed_repositories( repository )
+ # Populate self.installed_tool_dependencies_of_installed_repositories.
+ self.add_entry_to_installed_tool_dependencies_of_installed_repositories( repository )
+ # Get the list of installed tool dependencies.
+ for tool_dependency in self.context.query( self.app.install_model.ToolDependency ) \
+ .filter( self.app.install_model.ToolDependency.table.c.status ==
+ self.app.install_model.ToolDependency.installation_status.INSTALLED ):
+ # Populate self.runtime_tool_dependencies_of_installed_tool_dependencies.
+ self.add_entry_to_runtime_tool_dependencies_of_installed_tool_dependencies( tool_dependency )
+ # Populate self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies.
+ self.add_entry_to_installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies( tool_dependency )
+
+ def load_proprietary_datatypes( self ):
+ for tool_shed_repository in self.context.query( self.install_model.ToolShedRepository ) \
+ .filter( and_( self.install_model.ToolShedRepository.table.c.includes_datatypes==True,
+ self.install_model.ToolShedRepository.table.c.deleted==False ) ) \
+ .order_by( self.install_model.ToolShedRepository.table.c.id ):
+ relative_install_dir = self.get_repository_install_dir( tool_shed_repository )
+ if relative_install_dir:
+ installed_repository_dict = datatype_util.load_installed_datatypes( self.app, tool_shed_repository, relative_install_dir )
+ if installed_repository_dict:
+ self.installed_repository_dicts.append( installed_repository_dict )
+
+ def load_proprietary_converters_and_display_applications( self, deactivate=False ):
+ for installed_repository_dict in self.installed_repository_dicts:
+ if installed_repository_dict[ 'converter_path' ]:
+ datatype_util.load_installed_datatype_converters( self.app, installed_repository_dict, deactivate=deactivate )
+ if installed_repository_dict[ 'display_path' ]:
+ datatype_util.load_installed_display_applications( self.app, installed_repository_dict, deactivate=deactivate )
+
+ def remove_entry_from_installed_repository_dependencies_of_installed_repositories( self, repository ):
+ """Remove an entry from self.installed_repository_dependencies_of_installed_repositories"""
+ for r in self.installed_repository_dependencies_of_installed_repositories:
+ if r.id == repository.id:
+ debug_msg = "Removing entry for revision %s of repository %s owned by %s " % \
+ ( str( repository.changeset_revision ), str( repository.name ), str( repository.owner ) )
+ debug_msg += "from installed_repository_dependencies_of_installed_repositories."
+ log.debug( debug_msg )
+ del self.installed_repository_dependencies_of_installed_repositories[ r ]
+ break
+
+ def remove_entry_from_installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies( self, tool_dependency ):
+ """Remove an entry from self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies."""
+ for td in self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies:
+ if td.id == tool_dependency.id:
+ debug_msg = "Removing entry for version %s of %s %s " % \
+ ( str( tool_dependency.version ), str( tool_dependency.type ), str( tool_dependency.name ) )
+ debug_msg += "from installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies."
+ log.debug( debug_msg )
+ del self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies[ td ]
+ break
+
+ def remove_entry_from_installed_tool_dependencies_of_installed_repositories( self, repository ):
+ """Remove an entry from self.installed_tool_dependencies_of_installed_repositories"""
+ for r in self.installed_tool_dependencies_of_installed_repositories:
+ if r.id == repository.id:
+ debug_msg = "Removing entry for revision %s of repository %s owned by %s " % \
+ ( str( repository.changeset_revision ), str( repository.name ), str( repository.owner ) )
+ debug_msg += "from installed_tool_dependencies_of_installed_repositories."
+ log.debug( debug_msg )
+ del self.installed_tool_dependencies_of_installed_repositories[ r ]
+ break
+
+ def remove_entry_from_repository_dependencies_of_installed_repositories( self, repository ):
+ """Remove an entry from self.repository_dependencies_of_installed_repositories."""
+ for r in self.repository_dependencies_of_installed_repositories:
+ if r.id == repository.id:
+ debug_msg = "Removing entry for revision %s of repository %s owned by %s " % \
+ ( str( repository.changeset_revision ), str( repository.name ), str( repository.owner ) )
+ debug_msg += "from repository_dependencies_of_installed_repositories."
+ log.debug( debug_msg )
+ del self.repository_dependencies_of_installed_repositories[ r ]
+ break
+
+ def remove_entry_from_runtime_tool_dependencies_of_installed_tool_dependencies( self, tool_dependency ):
+ """Remove an entry from self.runtime_tool_dependencies_of_installed_tool_dependencies."""
+ for td in self.runtime_tool_dependencies_of_installed_tool_dependencies:
+ if td.id == tool_dependency.id:
+ debug_msg = "Removing entry for version %s of %s %s " % \
+ ( str( tool_dependency.version ), str( tool_dependency.type ), str( tool_dependency.name ) )
+ debug_msg += "from runtime_tool_dependencies_of_installed_tool_dependencies."
+ log.debug( debug_msg )
+ del self.runtime_tool_dependencies_of_installed_tool_dependencies[ td ]
+ break
+
+ def remove_entry_from_tool_dependencies_of_installed_repositories( self, repository ):
+ """Remove an entry from self.tool_dependencies_of_installed_repositories."""
+ for r in self.tool_dependencies_of_installed_repositories:
+ if r.id == repository.id:
+ debug_msg = "Removing entry for revision %s of repository %s owned by %s " % \
+ ( str( repository.changeset_revision ), str( repository.name ), str( repository.owner ) )
+ debug_msg += "from tool_dependencies_of_installed_repositories."
+ log.debug( debug_msg )
+ del self.tool_dependencies_of_installed_repositories[ r ]
+ break
diff -r 392469f092a67318ed25a4c675e72850e0a8f4b4 -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc lib/tool_shed/galaxy_install/repository_util.py
--- a/lib/tool_shed/galaxy_install/repository_util.py
+++ b/lib/tool_shed/galaxy_install/repository_util.py
@@ -504,8 +504,8 @@
query = trans.install_model.context.query( trans.install_model.ToolShedRepository ).filter( or_( *clause_list ) )
return encoded_kwd, query, tool_shed_repositories, encoded_repository_ids
-def install_tool_shed_repository( trans, tool_shed_repository, repo_info_dict, tool_panel_section_key, shed_tool_conf, tool_path, install_tool_dependencies,
- reinstalling=False ):
+def install_tool_shed_repository( trans, tool_shed_repository, repo_info_dict, tool_panel_section_key, shed_tool_conf, tool_path,
+ install_tool_dependencies, reinstalling=False ):
if tool_panel_section_key:
try:
tool_section = trans.app.toolbox.tool_panel[ tool_panel_section_key ]
@@ -579,7 +579,11 @@
tool_dependencies_config=tool_dependencies_config,
tool_dependencies=tool_shed_repository.tool_dependencies )
suc.remove_dir( work_dir )
- suc.update_tool_shed_repository_status( trans.app, tool_shed_repository, trans.install_model.ToolShedRepository.installation_status.INSTALLED )
+ suc.update_tool_shed_repository_status( trans.app,
+ tool_shed_repository,
+ trans.install_model.ToolShedRepository.installation_status.INSTALLED )
+ # Add the installed repository and any tool dependencies to the in-memory dictionaries in the installed_repository_manager.
+ trans.app.installed_repository_manager.handle_install( tool_shed_repository )
else:
# An error occurred while cloning the repository, so reset everything necessary to enable another attempt.
set_repository_attributes( trans,
diff -r 392469f092a67318ed25a4c675e72850e0a8f4b4 -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc lib/tool_shed/galaxy_install/update_manager.py
--- a/lib/tool_shed/galaxy_install/update_manager.py
+++ b/lib/tool_shed/galaxy_install/update_manager.py
@@ -30,7 +30,7 @@
# repository. This information includes items like newer installable repository revisions, current revision updates, whether
# the repository revision is the latest installable revision, and whether the repository has been deprecated in the tool shed.
for repository in self.context.query( self.app.install_model.ToolShedRepository ) \
- .filter( self.app.install_model.ToolShedRepository.table.c.deleted == False ):
+ .filter( self.app.install_model.ToolShedRepository.table.c.deleted == False ):
tool_shed_status_dict = suc.get_tool_shed_status_for_installed_repository( self.app, repository )
if tool_shed_status_dict:
if tool_shed_status_dict != repository.tool_shed_status:
diff -r 392469f092a67318ed25a4c675e72850e0a8f4b4 -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc 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
@@ -355,14 +355,43 @@
handled_key_rd_dicts,
circular_repository_dependencies )
elif key_rd_dicts_to_be_processed:
- handle_next_repository_dependency( trans, key_rd_dicts_to_be_processed, all_repository_dependencies, handled_key_rd_dicts, circular_repository_dependencies )
+ handle_next_repository_dependency( trans,
+ key_rd_dicts_to_be_processed,
+ all_repository_dependencies,
+ handled_key_rd_dicts,
+ circular_repository_dependencies )
elif key_rd_dicts_to_be_processed:
- handle_next_repository_dependency( trans, key_rd_dicts_to_be_processed, all_repository_dependencies, handled_key_rd_dicts, circular_repository_dependencies )
+ handle_next_repository_dependency( trans,
+ key_rd_dicts_to_be_processed,
+ all_repository_dependencies,
+ handled_key_rd_dicts,
+ circular_repository_dependencies )
elif key_rd_dicts_to_be_processed:
- handle_next_repository_dependency( trans, key_rd_dicts_to_be_processed, all_repository_dependencies, handled_key_rd_dicts, circular_repository_dependencies )
+ handle_next_repository_dependency( trans,
+ key_rd_dicts_to_be_processed,
+ all_repository_dependencies,
+ handled_key_rd_dicts,
+ circular_repository_dependencies )
all_repository_dependencies = prune_invalid_repository_dependencies( all_repository_dependencies )
return all_repository_dependencies
+def get_repository_dependency_tree_for_repository( app, repository, dependency_tree=None, status=None ):
+ """
+ Return a list of of tool_shed_repository ids (whose status can be anything) required by the received repository. The
+ returned list defines the entire repository dependency tree.
+ """
+ if dependency_tree is None:
+ dependency_tree = []
+ tree_object_ids = [ r.id for r in dependency_tree ]
+ for rrda in repository.required_repositories:
+ repository_dependency = rrda.repository_dependency
+ required_repository = repository_dependency.repository
+ if status is None or required_repository.status == status:
+ if required_repository.id not in tree_object_ids:
+ dependency_tree.append( required_repository )
+ return get_repository_dependency_tree_for_repository( app, required_repository, dependency_tree=dependency_tree )
+ return dependency_tree
+
def get_updated_changeset_revisions_for_repository_dependencies( trans, key_rd_dicts ):
updated_key_rd_dicts = []
for key_rd_dict in key_rd_dicts:
diff -r 392469f092a67318ed25a4c675e72850e0a8f4b4 -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc 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
@@ -4,6 +4,7 @@
from galaxy import eggs
from galaxy import util
from galaxy.model.orm import and_
+from galaxy.model.orm import or_
import tool_shed.util.shed_util_common as suc
import tool_shed.repository_types.util as rt_util
from tool_shed.util import xml_util
@@ -13,9 +14,10 @@
def add_installation_directories_to_tool_dependencies( trans, tool_dependencies ):
"""
- Determine the path to the installation directory for each of the received tool dependencies. This path will be displayed within the tool dependencies
- container on the select_tool_panel_section or reselect_tool_panel_section pages when installing or reinstalling repositories that contain tools with the
- defined tool dependencies. The list of tool dependencies may be associated with more than a single repository.
+ Determine the path to the installation directory for each of the received tool dependencies. This path will be
+ displayed within the tool dependencies container on the select_tool_panel_section or reselect_tool_panel_section
+ pages when installing or reinstalling repositories that contain tools with the defined tool dependencies. The
+ list of tool dependencies may be associated with more than a single repository.
"""
for dependency_key, requirements_dict in tool_dependencies.items():
if dependency_key in [ 'set_environment' ]:
@@ -64,7 +66,10 @@
return tool_dependency
def create_tool_dependency_objects( app, tool_shed_repository, relative_install_dir, set_status=True ):
- """Create or update a ToolDependency for each entry in tool_dependencies_config. This method is called when installing a new tool_shed_repository."""
+ """
+ Create or update a ToolDependency for each entry in tool_dependencies_config. This method is called when
+ installing a new tool_shed_repository.
+ """
tool_dependency_objects = []
shed_config_dict = tool_shed_repository.get_shed_config_dict( app )
if shed_config_dict.get( 'tool_path' ):
@@ -82,12 +87,13 @@
name = elem.get( 'name', None )
version = elem.get( 'version', None )
if name and version:
+ status = app.install_model.ToolDependency.installation_status.NEVER_INSTALLED
tool_dependency = create_or_update_tool_dependency( app,
tool_shed_repository,
name=name,
version=version,
type=tool_dependency_type,
- status=app.install_model.ToolDependency.installation_status.NEVER_INSTALLED,
+ status=status,
set_status=set_status )
tool_dependency_objects.append( tool_dependency )
elif tool_dependency_type == 'set_environment':
@@ -96,12 +102,13 @@
name = env_elem.get( 'name', None )
action = env_elem.get( 'action', None )
if name and action:
+ status = app.install_model.ToolDependency.installation_status.NEVER_INSTALLED
tool_dependency = create_or_update_tool_dependency( app,
tool_shed_repository,
name=name,
version=None,
type=tool_dependency_type,
- status=app.install_model.ToolDependency.installation_status.NEVER_INSTALLED,
+ status=status,
set_status=set_status )
tool_dependency_objects.append( tool_dependency )
return tool_dependency_objects
@@ -185,12 +192,38 @@
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
+ 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_runtime_dependent_tool_dependencies( app, tool_dependency, status=None ):
+ """
+ Return the list of tool dependency objects that require the received tool dependency at run time. The returned
+ list will be filtered by the received status if it is not None. This method is called only from Galaxy.
+ """
+ runtime_dependent_tool_dependencies = []
+ required_env_shell_file_path = tool_dependency.get_env_shell_file_path( app )
+ if required_env_shell_file_path:
+ required_env_shell_file_path = os.path.abspath( required_env_shell_file_path )
+ if required_env_shell_file_path is not None:
+ for td in app.install_model.context.query( app.install_model.ToolDependency ):
+ if status is None or td.status == status:
+ env_shell_file_path = td.get_env_shell_file_path( app )
+ if env_shell_file_path is not None:
+ try:
+ contents = open( env_shell_file_path, 'r' ).read()
+ except Exception, e:
+ contents = None
+ log.debug( 'Error reading file %s, so cannot determine if package %s requires package %s at run time: %s' % \
+ ( str( env_shell_file_path ), str( td.name ), str( tool_dependency.name ), str( e ) ) )
+ if contents is not None and contents.find( required_env_shell_file_path ) >= 0:
+ runtime_dependent_tool_dependencies.append( td )
+ return runtime_dependent_tool_dependencies
+
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 392469f092a67318ed25a4c675e72850e0a8f4b4 -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc templates/admin/tool_shed_repository/deactivate_or_uninstall_repository.mako
--- a/templates/admin/tool_shed_repository/deactivate_or_uninstall_repository.mako
+++ b/templates/admin/tool_shed_repository/deactivate_or_uninstall_repository.mako
@@ -36,12 +36,100 @@
${repository.deleted}
</div><div class="form-row">
- %if repository.can_deactivate:
+ <%
+ can_deactivate_repository = repository.can_deactivate
+ can_uninstall_repository = repository.can_uninstall( trans.app )
+ %>
+ %if can_deactivate_repository and can_uninstall_repository:
<% deactivate_uninstall_button_text = "Deactivate or Uninstall" %>
${remove_from_disk_check_box.get_html()}
<label for="repository" style="display: inline;font-weight:normal;">Check to uninstall or leave blank to deactivate</label><br/><br/>
- <label>Deactivating this repository will result in the following:</label>
+ %elif can_deactivate_repository:
+ <% deactivate_uninstall_button_text = "Deactivate" %>
+ %else:
+ <% deactivate_uninstall_button_text = "Uninstall" %>
+ ##hack to mimic check box
+ <input type="hidden" name="remove_from_disk" value="true"/><input type="hidden" name="remove_from_disk" value="true"/>
+ %endif
+ %if not can_uninstall_repository:
+ <%
+ irm = trans.app.installed_repository_manager
+
+ # Get installed repositories that require this repository.
+ installed_repository_dependencies = []
+ installed_runtime_dependent_tool_dependencies = []
+ for r in irm.installed_repository_dependencies_of_installed_repositories:
+ if r.id == repository.id:
+ installed_repository_dependencies = irm.installed_repository_dependencies_of_installed_repositories[ r ]
+ break
+
+ # Get this repository's installed tool dependencies.
+ installed_tool_dependencies = []
+ for r in irm.installed_tool_dependencies_of_installed_repositories:
+ if r.id == repository.id:
+ installed_tool_dependencies = irm.installed_tool_dependencies_of_installed_repositories[ r ]
+ break
+
+ # Get installed runtime dependent tool dependencies of this repository's installed tool dependencies.
+ installed_runtime_dependent_tool_dependencies = []
+ for itd in installed_tool_dependencies:
+ for td in irm.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies:
+ if td.id == itd.id:
+ installed_dependent_tds = \
+ irm.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies[ td ]
+ if installed_dependent_tds:
+ installed_runtime_dependent_tool_dependencies.extend( installed_dependent_tds )
+ %>
+ %if installed_repository_dependencies or installed_runtime_dependent_tool_dependencies:
+ <table width="100%" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td bgcolor="#D8D8D8">
+ <label>This repository cannot be uninstalled because it is required by the following installed items:</label>
+ </td>
+ </tr>
+ </table>
+ %if installed_repository_dependencies:
+ <label>Dependent repositories:</label>
+ <ul>
+ %for installed_repository_dependency in installed_repository_dependencies:
+ <%
+ changeset_revision = installed_repository_dependency.changeset_revision
+ name = installed_repository_dependency.name
+ owner = installed_repository_dependency.owner
+ %>
+ <li>Revision <b>${ changeset_revision | h}</b> of repository <b>${name | h}</b> owned by <b>${owner | h}</b></li>
+ %endfor
+ </ul>
+ %endif
+ %if installed_runtime_dependent_tool_dependencies:
+ <label>Runtime dependent tool dependencies of this repository's tool dependencies:</label>
+ <ul>
+ %for td in installed_runtime_dependent_tool_dependencies:
+ <%
+ containing_repository = irm.get_containing_repository_for_tool_dependency( td )
+ repository_name = containing_repository.name
+ changeset_revision = containing_repository.changeset_revision
+ owner = containing_repository.owner
+ %>
+ <li>
+ Version <b>${td.version}</b> of ${td.type} <b>${td.name}</b> contained in revision
+ <b>${changeset_revision | h}</b> of repository <b>${repository_name | h}</b> owned by <b>${owner}</b>
+ </li>
+ %endfor
+ </ul>
+ %endif
+ <br/>
+ %endif
+ %endif
+ %if can_deactivate_repository:
+ <table width="100%" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td bgcolor="#D8D8D8">
+ <label>Deactivating this repository will result in the following:</label>
+ </td>
+ </tr>
+ </table><div class="toolParamHelp" style="clear: both;">
* The repository and all of it's contents will remain on disk.
</div>
@@ -64,40 +152,45 @@
* The repository record's deleted column in the tool_shed_repository database table will be set to True.
</div><br/>
- %else:
- <% deactivate_uninstall_button_text = "Uninstall" %>
- ##hack to mimic check box
- <input type="hidden" name="remove_from_disk" value="true"/><input type="hidden" name="remove_from_disk" value="true"/>
%endif
- <label>Uninstalling this repository will result in the following:</label>
- <div class="toolParamHelp" style="clear: both;">
- * The repository and all of it's contents will be removed from disk.
- </div>
- %if repository.includes_tools_for_display_in_tool_panel:
+ %if can_uninstall_repository:
+ <table width="100%" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td bgcolor="#D8D8D8">
+ <label>Uninstalling this repository will result in the following:</label>
+ </td>
+ </tr>
+ </table><div class="toolParamHelp" style="clear: both;">
- * The repository's tool tag sets will be removed from the tool config file in which they are defined.
+ * The repository and all of it's contents will be removed from disk.
</div>
- %endif
- %if repository.includes_tool_dependencies:
+ %if repository.includes_tools_for_display_in_tool_panel:
+ <div class="toolParamHelp" style="clear: both;">
+ * The repository's tool tag sets will be removed from the tool config file in which they are defined.
+ </div>
+ %endif
+ %if repository.includes_tool_dependencies:
+ <div class="toolParamHelp" style="clear: both;">
+ * The repository's installed tool dependencies will be removed from disk.
+ </div>
+ <div class="toolParamHelp" style="clear: both;">
+ * Each associated tool dependency record's status column in the tool_dependency database table will be set to 'Uninstalled'.
+ </div>
+ %endif
+ %if repository.includes_datatypes:
+ <div class="toolParamHelp" style="clear: both;">
+ * The repository's datatypes, datatype converters and display applications will be eliminated from the datatypes registry.
+ </div>
+ %endif
<div class="toolParamHelp" style="clear: both;">
- * The repository's installed tool dependencies will be removed from disk.
+ * The repository record's deleted column in the tool_shed_repository database table will be set to True.
</div><div class="toolParamHelp" style="clear: both;">
- * Each associated tool dependency record's status column in the tool_dependency database table will be set to 'Uninstalled'.
+ * The repository record's uninstalled column in the tool_shed_repository database table will be set to True.
</div>
+ <div style="clear: both"></div>
+ <br/>
%endif
- %if repository.includes_datatypes:
- <div class="toolParamHelp" style="clear: both;">
- * The repository's datatypes, datatype converters and display applications will be eliminated from the datatypes registry.
- </div>
- %endif
- <div class="toolParamHelp" style="clear: both;">
- * The repository record's deleted column in the tool_shed_repository database table will be set to True.
- </div>
- <div class="toolParamHelp" style="clear: both;">
- * The repository record's uninstalled column in the tool_shed_repository database table will be set to True.
- </div>
- <div style="clear: both"></div></div><div class="form-row"><input type="submit" name="deactivate_or_uninstall_repository_button" value="${deactivate_uninstall_button_text}"/>
diff -r 392469f092a67318ed25a4c675e72850e0a8f4b4 -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc templates/admin/tool_shed_repository/manage_repository_tool_dependencies.mako
--- a/templates/admin/tool_shed_repository/manage_repository_tool_dependencies.mako
+++ b/templates/admin/tool_shed_repository/manage_repository_tool_dependencies.mako
@@ -30,6 +30,8 @@
<tr><th bgcolor="#D8D8D8">Name</th><th bgcolor="#D8D8D8">Version</th><th bgcolor="#D8D8D8">Type</th><th bgcolor="#D8D8D8">Status</th><th bgcolor="#D8D8D8">Error</th></tr>
%for tool_dependency in repository.tool_dependencies:
<%
+ # Tool dependencies cannot be uninstalled if they have a status of 'Installed'. Only the containing repository
+ # can be uninstalled (only if it has no dependent repositories) if a tool dependency has been successfully installed.
if tool_dependency.error_message:
error_message = tool_dependency.error_message
else:
@@ -39,7 +41,8 @@
trans.install_model.ToolDependency.installation_status.UNINSTALLED ]:
can_install = True
if not can_uninstall:
- if tool_dependency.status not in [ trans.install_model.ToolDependency.installation_status.NEVER_INSTALLED,
+ if tool_dependency.status not in [ trans.install_model.ToolDependency.installation_status.INSTALLED,
+ trans.install_model.ToolDependency.installation_status.NEVER_INSTALLED,
trans.install_model.ToolDependency.installation_status.UNINSTALLED ]:
can_uninstall = True
%>
diff -r 392469f092a67318ed25a4c675e72850e0a8f4b4 -r b56f6e027d2ca3e8cb5ef6f6514e085107ac5dfc templates/admin/tool_shed_repository/repository_actions_menu.mako
--- a/templates/admin/tool_shed_repository/repository_actions_menu.mako
+++ b/templates/admin/tool_shed_repository/repository_actions_menu.mako
@@ -5,6 +5,12 @@
from tool_shed.util.encoding_util import tool_shed_encode
in_error_state = repository.in_error_state
tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in repository.tool_dependencies ]
+ if repository.status in [ trans.install_model.ToolShedRepository.installation_status.DEACTIVATED,
+ trans.install_model.ToolShedRepository.installation_status.ERROR,
+ trans.install_model.ToolShedRepository.installation_status.INSTALLED ]:
+ can_administer = True
+ else:
+ can_administer = False
%><br/><br/><ul class="manage-table-actions">
@@ -20,7 +26,7 @@
<a class="action-button" target="galaxy_main" href="${h.url_for( controller='admin_toolshed', action='reset_to_install', id=trans.security.encode_id( repository.id ), reset_repository=True )}">Reset to install</a>
%elif repository.can_install:
<a class="action-button" target="galaxy_main" href="${h.url_for( controller='admin_toolshed', action='manage_repository', id=trans.security.encode_id( repository.id ), operation='install' )}">Install</a>
- %elif repository.can_uninstall:
+ %elif can_administer:
<a class="action-button" target="galaxy_main" href="${h.url_for( controller='admin_toolshed', action='manage_repository', id=trans.security.encode_id( repository.id ) )}">Manage repository</a><a class="action-button" target="galaxy_main" href="${h.url_for( controller='admin_toolshed', action='browse_repository', id=trans.security.encode_id( repository.id ) )}">Browse repository files</a><a class="action-button" target="galaxy_main" href="${h.url_for( controller='admin_toolshed', action='check_for_updates', id=trans.security.encode_id( repository.id ) )}">Get repository updates</a>
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: Grids: Fix for toolshed grids
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/392469f092a6/
Changeset: 392469f092a6
User: guerler
Date: 2013-12-11 20:58:35
Summary: Grids: Fix for toolshed grids
Affected #: 2 files
diff -r 87101044e7d4bc1d7495c0dfdaf3663339618047 -r 392469f092a67318ed25a4c675e72850e0a8f4b4 templates/webapps/tool_shed/category/grid.mako
--- a/templates/webapps/tool_shed/category/grid.mako
+++ b/templates/webapps/tool_shed/category/grid.mako
@@ -1,3 +1,4 @@
+<%inherit file="/base.mako"/><%namespace name="grid_base" file="/grid_base.mako" import="*" /><%namespace name="grid_common" file="../common/grid_common.mako" import="*" />
@@ -9,5 +10,4 @@
%></%def>
-<!DOCTYPE HTML>
${grid_base.load(False, capture(self.insert))}
\ No newline at end of file
diff -r 87101044e7d4bc1d7495c0dfdaf3663339618047 -r 392469f092a67318ed25a4c675e72850e0a8f4b4 templates/webapps/tool_shed/category/valid_grid.mako
--- a/templates/webapps/tool_shed/category/valid_grid.mako
+++ b/templates/webapps/tool_shed/category/valid_grid.mako
@@ -1,3 +1,4 @@
+<%inherit file="/base.mako"/><%namespace name="grid_base" file="/grid_base.mako" import="*" /><%namespace name="grid_common" file="../common/grid_common.mako" import="*" />
@@ -9,5 +10,4 @@
%></%def>
-<!DOCTYPE HTML>
${grid_base.load(False, capture(self.insert))}
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Remove duplicate JS scripts from grids.
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/87101044e7d4/
Changeset: 87101044e7d4
User: jgoecks
Date: 2013-12-11 20:23:57
Summary: Remove duplicate JS scripts from grids.
Affected #: 1 file
diff -r 42a88bd063ee84f0d1ddb38ddcff564421ed8140 -r 87101044e7d4bc1d7495c0dfdaf3663339618047 templates/grid_base.mako
--- a/templates/grid_base.mako
+++ b/templates/grid_base.mako
@@ -21,7 +21,6 @@
<%
self.init(insert)
self.stylesheets()
- self.javascripts()
self.grid_javascripts()
if embedded:
self.render_grid_header( grid, False )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: inithello: When creating a repository, make sure there are no repositories with the same name, deleted or active.
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/77b5d4888d6d/
Changeset: 77b5d4888d6d
Branch: stable
User: inithello
Date: 2013-12-11 18:43:36
Summary: When creating a repository, make sure there are no repositories with the same name, deleted or active.
Affected #: 2 files
diff -r 9d4cbf2a1c13dd481c10d28a28afb41d23553d18 -r 77b5d4888d6d957d24caccdcd5154bb8cb7574e4 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
@@ -933,7 +933,7 @@
repository_type = kwd.get( 'repository_type', rt_util.UNRESTRICTED )
if kwd.get( 'create_repository_button', False ):
error = False
- message = repository_maintenance_util.validate_repository_name( name, trans.user )
+ message = repository_maintenance_util.validate_repository_name( trans.app, name, trans.user )
if message:
error = True
if not description:
@@ -2070,7 +2070,7 @@
repository.long_description = long_description
flush_needed = True
if repository.times_downloaded == 0 and repo_name != repository.name:
- message = repository_maintenance_util.validate_repository_name( repo_name, user )
+ message = repository_maintenance_util.validate_repository_name( trans.app, repo_name, user )
if message:
error = True
else:
diff -r 9d4cbf2a1c13dd481c10d28a28afb41d23553d18 -r 77b5d4888d6d957d24caccdcd5154bb8cb7574e4 lib/tool_shed/util/repository_maintenance_util.py
--- a/lib/tool_shed/util/repository_maintenance_util.py
+++ b/lib/tool_shed/util/repository_maintenance_util.py
@@ -56,15 +56,18 @@
fp.write( 'hgext.purge=' )
fp.close()
-def validate_repository_name( name, user ):
+def validate_repository_name( app, name, user ):
# Repository names must be unique for each user, must be at least four characters
# in length and must contain only lower-case letters, numbers, and the '_' character.
if name in [ 'None', None, '' ]:
return 'Enter the required repository name.'
if name in [ 'repos' ]:
return "The term <b>%s</b> is a reserved word in the tool shed, so it cannot be used as a repository name." % name
- for repository in user.active_repositories:
- if repository.name == name:
+ check_existing = suc.get_repository_by_name_and_owner( app, name, user.username )
+ if check_existing is not None:
+ if check_existing.deleted:
+ return 'You have a deleted repository named <b>%s</b>, so choose a different name.' % name
+ else:
return "You already have a repository named <b>%s</b>, so choose a different name." % name
if len( name ) < 4:
return "Repository names must be at least 4 characters in length."
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/9c5a2c5f560d/
Changeset: 9c5a2c5f560d
User: inithello
Date: 2013-12-11 18:43:36
Summary: When creating a repository, make sure there are no repositories with the same name, deleted or active.
Affected #: 2 files
diff -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 -r 9c5a2c5f560dbd769b44d684f657625563d52022 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
@@ -932,7 +932,7 @@
repository_type = kwd.get( 'repository_type', rt_util.UNRESTRICTED )
if kwd.get( 'create_repository_button', False ):
error = False
- message = repository_maintenance_util.validate_repository_name( name, trans.user )
+ message = repository_maintenance_util.validate_repository_name( trans.app, name, trans.user )
if message:
error = True
if not description:
@@ -2085,7 +2085,7 @@
repository.long_description = long_description
flush_needed = True
if repository.times_downloaded == 0 and repo_name != repository.name:
- message = repository_maintenance_util.validate_repository_name( repo_name, user )
+ message = repository_maintenance_util.validate_repository_name( trans.app, repo_name, user )
if message:
error = True
else:
diff -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 -r 9c5a2c5f560dbd769b44d684f657625563d52022 lib/tool_shed/util/repository_maintenance_util.py
--- a/lib/tool_shed/util/repository_maintenance_util.py
+++ b/lib/tool_shed/util/repository_maintenance_util.py
@@ -137,7 +137,7 @@
results_message += 'This Tool Shed does not have the category <b>%s</b> so it will not be associated with this repository.' % \
str( category_name )
else:
- category_ids.append( trans.security.encode_id( category.id ) )
+ category_ids.append( trans.security.encode_id( category.id ) )
# Create the repository record in the database.
repository, create_message = create_repository( trans,
name,
@@ -157,15 +157,18 @@
import_results_tups.append( ( ( str( name ), str( username ) ), results_message ) )
return import_results_tups
-def validate_repository_name( name, user ):
+def validate_repository_name( app, name, user ):
# Repository names must be unique for each user, must be at least four characters
# in length and must contain only lower-case letters, numbers, and the '_' character.
if name in [ 'None', None, '' ]:
return 'Enter the required repository name.'
if name in [ 'repos' ]:
return "The term <b>%s</b> is a reserved word in the tool shed, so it cannot be used as a repository name." % name
- for repository in user.active_repositories:
- if repository.name == name:
+ check_existing = suc.get_repository_by_name_and_owner( app, name, user.username )
+ if check_existing is not None:
+ if check_existing.deleted:
+ return 'You have a deleted repository named <b>%s</b>, so choose a different name.' % name
+ else:
return "You already have a repository named <b>%s</b>, so choose a different name." % name
if len( name ) < 4:
return "Repository names must be at least 4 characters in length."
https://bitbucket.org/galaxy/galaxy-central/commits/b128bbaf91fc/
Changeset: b128bbaf91fc
Branch: search
User: inithello
Date: 2013-12-11 19:11:43
Summary: Close branch search
Affected #: 0 files
https://bitbucket.org/galaxy/galaxy-central/commits/42a88bd063ee/
Changeset: 42a88bd063ee
User: inithello
Date: 2013-12-11 19:15:36
Summary: Merge in 11692:9c5a2c5f560d
Affected #: 2 files
diff -r 9c5a2c5f560dbd769b44d684f657625563d52022 -r 42a88bd063ee84f0d1ddb38ddcff564421ed8140 lib/galaxy/tools/deps/__init__.py
--- a/lib/galaxy/tools/deps/__init__.py
+++ b/lib/galaxy/tools/deps/__init__.py
@@ -76,6 +76,7 @@
return [
ToolShedPackageDependencyResolver(self),
GalaxyPackageDependencyResolver(self),
+ GalaxyPackageDependencyResolver(self, versionless=True),
]
def __parse_resolver_conf_xml(self, root):
diff -r 9c5a2c5f560dbd769b44d684f657625563d52022 -r 42a88bd063ee84f0d1ddb38ddcff564421ed8140 test/unit/test_tool_deps.py
--- a/test/unit/test_tool_deps.py
+++ b/test/unit/test_tool_deps.py
@@ -42,9 +42,10 @@
dependency = dm.find_dep( "dep1", None )
assert dependency.version == "2.0"
- ## Test default will not be fallen back upon by default
+ ## Test default resolve will be fall back on default package dependency
+ ## when using the default resolver.
dependency = dm.find_dep( "dep1", "2.1" )
- assert dependency == INDETERMINATE_DEPENDENCY
+ assert dependency.version == "2.0" # 2.0 is defined as default_version
TEST_REPO_USER = "devteam"
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/98a91b2610ab/
Changeset: 98a91b2610ab
User: jmchilton
Date: 2013-12-10 16:43:07
Summary: Resolve default package definitions if extact version is unavailable.
Old behavior can be reverted by setting up a dependency_resolvers_conf.xml with the following contents
```
<dependency_resolvers><tool_shed_packages /><galaxy_packages /></dependency_resolvers>
```
The new behavior corresponds to the following dependency_resolvers_conf.xml contents:
```
<dependency_resolvers><tool_shed_packages /><galaxy_packages /><galaxy_packages versionless="true" /></dependency_resolvers>
```
Still think galaxy_packages should come before tool_shed_packages in resolution order so that deployers can fix broken tool shed installs with manual installs or deploy optimized versions of packages without having to mess with a dependency_resolvers_conf.xml file.
Affected #: 2 files
diff -r 3bf805dfa14eb150e90c1aab565eb22b8ab3d9b8 -r 98a91b2610abbffd0a299c6ae9bae075ca5561f4 lib/galaxy/tools/deps/__init__.py
--- a/lib/galaxy/tools/deps/__init__.py
+++ b/lib/galaxy/tools/deps/__init__.py
@@ -76,6 +76,7 @@
return [
ToolShedPackageDependencyResolver(self),
GalaxyPackageDependencyResolver(self),
+ GalaxyPackageDependencyResolver(self, versionless=True),
]
def __parse_resolver_conf_xml(self, tree):
diff -r 3bf805dfa14eb150e90c1aab565eb22b8ab3d9b8 -r 98a91b2610abbffd0a299c6ae9bae075ca5561f4 test/unit/test_tool_deps.py
--- a/test/unit/test_tool_deps.py
+++ b/test/unit/test_tool_deps.py
@@ -42,9 +42,10 @@
dependency = dm.find_dep( "dep1", None )
assert dependency.version == "2.0"
- ## Test default will not be fallen back upon by default
+ ## Test default resolve will be fall back on default package dependency
+ ## when using the default resolver.
dependency = dm.find_dep( "dep1", "2.1" )
- assert dependency == INDETERMINATE_DEPENDENCY
+ assert dependency.version == "2.0" # 2.0 is defined as default_version
TEST_REPO_USER = "devteam"
https://bitbucket.org/galaxy/galaxy-central/commits/7200976bcad7/
Changeset: 7200976bcad7
User: dannon
Date: 2013-12-11 19:11:06
Summary: Merged in jmchilton/galaxy-central-fork-1 (pull request #272)
Resolve default package definitions if exact version is unavailable.
Affected #: 2 files
diff -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 -r 7200976bcad7741fe663f86492824dc5b3e24f50 lib/galaxy/tools/deps/__init__.py
--- a/lib/galaxy/tools/deps/__init__.py
+++ b/lib/galaxy/tools/deps/__init__.py
@@ -76,6 +76,7 @@
return [
ToolShedPackageDependencyResolver(self),
GalaxyPackageDependencyResolver(self),
+ GalaxyPackageDependencyResolver(self, versionless=True),
]
def __parse_resolver_conf_xml(self, root):
diff -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 -r 7200976bcad7741fe663f86492824dc5b3e24f50 test/unit/test_tool_deps.py
--- a/test/unit/test_tool_deps.py
+++ b/test/unit/test_tool_deps.py
@@ -42,9 +42,10 @@
dependency = dm.find_dep( "dep1", None )
assert dependency.version == "2.0"
- ## Test default will not be fallen back upon by default
+ ## Test default resolve will be fall back on default package dependency
+ ## when using the default resolver.
dependency = dm.find_dep( "dep1", "2.1" )
- assert dependency == INDETERMINATE_DEPENDENCY
+ assert dependency.version == "2.0" # 2.0 is defined as default_version
TEST_REPO_USER = "devteam"
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: History panel: small improvements
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/7e45d419c54d/
Changeset: 7e45d419c54d
User: carlfeberhard
Date: 2013-12-11 18:59:40
Summary: History panel: small improvements
Affected #: 17 files
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/scripts/mvc/dataset/hda-model.js
--- a/static/scripts/mvc/dataset/hda-model.js
+++ b/static/scripts/mvc/dataset/hda-model.js
@@ -503,6 +503,11 @@
return filteredHdas;
},
+ /** return true if any hdas don't have details */
+ haveDetails : function(){
+ return this.all( function( hda ){ return hda.hasDetails(); });
+ },
+
// ........................................................................ ajax
/** fetch detailed model data for all HDAs in this collection */
fetchAllDetails : function( options ){
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/scripts/mvc/history/history-model.js
--- a/static/scripts/mvc/history/history-model.js
+++ b/static/scripts/mvc/history/history-model.js
@@ -121,6 +121,10 @@
return !!( user && user.id );
},
+ hdaCount : function(){
+ return _.reduce( _.values( this.get( 'state_details' ) ), function( memo, num ){ return memo + num; }, 0 );
+ },
+
// ........................................................................ ajax
/** does the HDA collection indicate they're still running and need to be updated later? delay + update if needed
* @param {Function} onReadyCallback function to run when all HDAs are in the ready state
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/scripts/mvc/history/history-panel.js
--- a/static/scripts/mvc/history/history-panel.js
+++ b/static/scripts/mvc/history/history-panel.js
@@ -79,8 +79,8 @@
//logger : console,
/** which class to use for constructing the HDA views */
- //HDAView : hdaBase.HDABaseView,
- HDAView : hdaEdit.HDAEditView,
+ //defaultHDAViewClass : hdaBase.HDABaseView,
+ defaultHDAViewClass : hdaEdit.HDAEditView,
tagName : 'div',
className : 'history-panel',
@@ -107,15 +107,12 @@
this.logger = attributes.logger;
}
this.log( this + '.initialize:', attributes );
-//TODO: pass show_del'd/hidden through
+ // ---- set up instance vars
+ this.HDAViewClass = attributes.HDAViewClass || this.defaultHDAViewClass;
/** where should pages from links be displayed? (default to new tab/window) */
this.linkTarget = attributes.linkTarget || '_blank';
- // set up (non-model related) event handlers
- this._setUpListeners();
-
- // ---- set up instance vars
/** map of hda model ids to hda views */
this.hdaViews = {};
/** loading indicator */
@@ -130,6 +127,8 @@
/** is the panel currently showing the dataset selection controls? */
this.selecting = attributes.selecting || false;
+ this._setUpListeners();
+
// ---- handle models passed on init
if( this.model ){
this._setUpWebStorage( attributes.initiallyExpanded, attributes.show_deleted, attributes.show_hidden );
@@ -559,8 +558,10 @@
} else {
$newRender.append( HistoryPanel.templates.historyPanel( this.model.toJSON() ) );
- this._renderTags( $newRender );
- this._renderAnnotation( $newRender );
+ if( Galaxy.currUser.id && Galaxy.currUser.id === this.model.get( 'user_id' ) ){
+ this._renderTags( $newRender );
+ this._renderAnnotation( $newRender );
+ }
}
// search and select available to both anon/logged-in users
//$newRender.find( '.history-secondary-actions' ).prepend( this._renderSelectButton() );
@@ -622,18 +623,24 @@
$where.find( '[title]' ).tooltip({ placement: 'bottom' });
// anon users shouldn't have access to any of the following
- if( !this.model || !Galaxy.currUser || Galaxy.currUser.isAnonymous() ){ return; }
+ if( ( !this.model )
+ || ( !Galaxy.currUser || Galaxy.currUser.isAnonymous() )
+ || ( Galaxy.currUser.id !== this.model.get( 'user_id' ) ) ){
+ return;
+ }
- var panel = this;//,
- $where.find( '.history-name' ).make_text_editable({
- on_finish: function( newName ){
- $where.find( '.history-name' ).text( newName );
- panel.model.save({ name: newName })
- .fail( function(){
- $where.find( '.history-name' ).text( panel.model.previous( 'name' ) );
- });
- }
- });
+ var panel = this;
+ $where.find( '.history-name' )
+ .attr( 'title', _l( 'Click to rename history' ) ).tooltip({ placement: 'bottom' })
+ .make_text_editable({
+ on_finish: function( newName ){
+ $where.find( '.history-name' ).text( newName );
+ panel.model.save({ name: newName })
+ .fail( function(){
+ $where.find( '.history-name' ).text( panel.model.previous( 'name' ) );
+ });
+ }
+ });
this._setUpDatasetActionsPopup( $where );
},
@@ -721,10 +728,11 @@
createHdaView : function( hda ){
var hdaId = hda.get( 'id' ),
expanded = this.storage.get( 'expandedHdas' )[ hdaId ],
- hdaView = new this.HDAView({
+ hdaView = new this.HDAViewClass({
model : hda,
linkTarget : this.linkTarget,
expanded : expanded,
+ //draggable : true,
selectable : this.selecting,
hasUser : this.model.hasUser(),
logger : this.logger
@@ -830,8 +838,9 @@
// allow (error) messages to be clicked away
//TODO: switch to common close (X) idiom
'click .message-container' : 'clearMessages',
+
'click .history-search-btn' : 'toggleSearchControls',
- 'click .history-select-btn' : function( e ){ this.toggleSelect( this.fxSpeed ); },
+ 'click .history-select-btn' : function( e ){ this.toggleSelectors( this.fxSpeed ); },
'click .history-select-all-datasets-btn' : 'selectAllDatasets'
},
@@ -892,6 +901,10 @@
}
function onFirstSearch( searchFor ){
//console.debug( 'onSearch', searchFor, panel );
+ if( panel.model.hdas.haveDetails() ){
+ onSearch( searchFor );
+ return;
+ }
panel.$el.find( '.history-search-controls' ).searchInput( 'toggle-loading' );
panel.model.hdas.fetchAllDetails({ silent: true })
.always( function(){
@@ -952,7 +965,7 @@
});
},
- toggleSelect : function( speed ){
+ toggleSelectors : function( speed ){
if( !this.selecting ){
this.showSelectors( speed );
} else {
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/scripts/packed/mvc/dataset/hda-model.js
--- a/static/scripts/packed/mvc/dataset/hda-model.js
+++ b/static/scripts/packed/mvc/dataset/hda-model.js
@@ -1,1 +1,1 @@
-define([],function(){var d=Backbone.Model.extend(LoggableMixin).extend({defaults:{history_id:null,model_class:"HistoryDatasetAssociation",hid:0,id:null,name:"(unnamed dataset)",state:"new",deleted:false,visible:true,accessible:true,purged:false,data_type:null,file_size:0,file_ext:"",meta_files:[],misc_blurb:"",misc_info:"",tags:null},urlRoot:galaxy_config.root+"api/histories/",url:function(){return this.urlRoot+this.get("history_id")+"/contents/"+this.get("id")},urls:function(){var i=this.get("id");if(!i){return{}}var h={purge:galaxy_config.root+"datasets/"+i+"/purge_async",display:galaxy_config.root+"datasets/"+i+"/display/?preview=True",edit:galaxy_config.root+"datasets/"+i+"/edit",download:galaxy_config.root+"datasets/"+i+"/display?to_ext="+this.get("file_ext"),report_error:galaxy_config.root+"dataset/errors?id="+i,rerun:galaxy_config.root+"tool_runner/rerun?id="+i,show_params:galaxy_config.root+"datasets/"+i+"/show_params",visualization:galaxy_config.root+"visualization",annotation:{get:galaxy_config.root+"dataset/get_annotation_async?id="+i,set:galaxy_config.root+"dataset/annotate_async?id="+i},meta_download:galaxy_config.root+"dataset/get_metadata_file?hda_id="+i+"&metadata_name="};return h},initialize:function(h){this.log(this+".initialize",this.attributes);this.log("\tparent history_id: "+this.get("history_id"));if(!this.get("accessible")){this.set("state",d.STATES.NOT_VIEWABLE)}this._setUpListeners()},_setUpListeners:function(){this.on("change:state",function(i,h){this.log(this+" has changed state:",i,h);if(this.inReadyState()){this.trigger("state:ready",i,h,this.previous("state"))}})},toJSON:function(){var h=Backbone.Model.prototype.toJSON.call(this);h.misc_info=jQuery.trim(h.misc_info);return h},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},isVisible:function(i,j){var h=true;if((!i)&&(this.get("deleted")||this.get("purged"))){h=false}if((!j)&&(!this.get("visible"))){h=false}return h},hidden:function(){return !this.get("visible")},inReadyState:function(){var h=_.contains(d.READY_STATES,this.get("state"));return(this.isDeletedOrPurged()||h)},hasDetails:function(){return _.has(this.attributes,"genome_build")},hasData:function(){return(this.get("file_size")>0)},"delete":function c(h){if(this.get("deleted")){return jQuery.when()}return this.save({deleted:true},h)},undelete:function a(h){if(!this.get("deleted")||this.get("purged")){return jQuery.when()}return this.save({deleted:false},h)},hide:function b(h){if(!this.get("visible")){return jQuery.when()}return this.save({visible:false},h)},unhide:function g(h){if(this.get("visible")){return jQuery.when()}return this.save({visible:true},h)},purge:function f(h){if(this.get("purged")){return jQuery.when()}h=h||{};h.url=galaxy_config.root+"datasets/"+this.get("id")+"/purge_async";var i=this,j=jQuery.ajax(h);j.done(function(m,k,l){i.set({deleted:true,purged:true})});j.fail(function(o,k,n){var l=_l("Unable to purge dataset");var m=("Removal of datasets by users is not allowed in this Galaxy instance");if(o.responseJSON&&o.responseJSON.error){l=o.responseJSON.error}else{if(o.responseText.indexOf(m)!==-1){l=m}}o.responseText=l;i.trigger("error",i,o,h,_l(l),{error:l})});return j},searchAttributes:["name","file_ext","genome_build","misc_blurb","misc_info","annotation","tags"],searchAliases:{title:"name",format:"file_ext",database:"genome_build",blurb:"misc_blurb",description:"misc_blurb",info:"misc_info",tag:"tags"},searchAttribute:function(j,h){var i=this.get(j);if(!h||(i===undefined||i===null)){return false}if(_.isArray(i)){return this._searchArrayAttribute(i,h)}return(i.toString().toLowerCase().indexOf(h.toLowerCase())!==-1)},_searchArrayAttribute:function(i,h){h=h.toLowerCase();return _.any(i,function(j){return(j.toString().toLowerCase().indexOf(h.toLowerCase())!==-1)})},search:function(h){var i=this;return _.filter(this.searchAttributes,function(j){return i.searchAttribute(j,h)})},matches:function(i){var k="=",h=i.split(k);if(h.length>=2){var j=h[0];j=this.searchAliases[j]||j;return this.searchAttribute(j,h[1])}return !!this.search(i).length},matchesAll:function(i){var h=this;i=i.match(/(".*"|\w*=".*"|\S*)/g).filter(function(j){return !!j});return _.all(i,function(j){j=j.replace(/"/g,"");return h.matches(j)})},toString:function(){var h=this.get("id")||"";if(this.get("name")){h=this.get("hid")+' :"'+this.get("name")+'",'+h}return"HDA("+h+")"}});d.STATES={UPLOAD:"upload",QUEUED:"queued",RUNNING:"running",SETTING_METADATA:"setting_metadata",NEW:"new",EMPTY:"empty",OK:"ok",PAUSED:"paused",FAILED_METADATA:"failed_metadata",NOT_VIEWABLE:"noPermission",DISCARDED:"discarded",ERROR:"error"};d.READY_STATES=[d.STATES.NEW,d.STATES.OK,d.STATES.EMPTY,d.STATES.PAUSED,d.STATES.FAILED_METADATA,d.STATES.NOT_VIEWABLE,d.STATES.DISCARDED,d.STATES.ERROR];d.NOT_READY_STATES=[d.STATES.UPLOAD,d.STATES.QUEUED,d.STATES.RUNNING,d.STATES.SETTING_METADATA];var e=Backbone.Collection.extend(LoggableMixin).extend({model:d,urlRoot:galaxy_config.root+"api/histories",url:function(){return this.urlRoot+"/"+this.historyId+"/contents"},initialize:function(i,h){h=h||{};this.historyId=h.historyId},ids:function(){return this.map(function(h){return h.id})},notReady:function(){return this.filter(function(h){return !h.inReadyState()})},running:function(){var h=[];this.each(function(i){if(!i.inReadyState()){h.push(i.get("id"))}});return h},getByHid:function(h){return _.first(this.filter(function(i){return i.get("hid")===h}))},getVisible:function(h,k,j){j=j||[];var i=new e(this.filter(function(l){return l.isVisible(h,k)}));_.each(j,function(l){if(!_.isFunction(l)){return}i=new e(i.filter(l))});return i},fetchAllDetails:function(i){i=i||{};var h={details:"all"};i.data=(i.data)?(_.extend(i.data,h)):(h);return this.fetch(i)},ajaxQueue:function(k,j){var i=jQuery.Deferred(),h=this.length,m=[];if(!h){i.resolve([]);return i}var l=this.chain().reverse().map(function(o,n){return function(){var p=k.call(o,j);p.done(function(q){i.notify({curr:n,total:h,response:q,model:o})});p.always(function(q){m.push(q);if(l.length){l.shift()()}else{i.resolve(m)}})}}).value();l.shift()();return i},matches:function(h){return this.filter(function(i){return i.matches(h)})},set:function(j,h){var i=this;j=_.map(j,function(l){var m=i.get(l.id);if(!m){return l}var k=m.toJSON();_.extend(k,l);return k});Backbone.Collection.prototype.set.call(this,j,h)},toString:function(){return(["HDACollection(",[this.historyId,this.length].join(),")"].join(""))}});return{HistoryDatasetAssociation:d,HDACollection:e}});
\ No newline at end of file
+define([],function(){var d=Backbone.Model.extend(LoggableMixin).extend({defaults:{history_id:null,model_class:"HistoryDatasetAssociation",hid:0,id:null,name:"(unnamed dataset)",state:"new",deleted:false,visible:true,accessible:true,purged:false,data_type:null,file_size:0,file_ext:"",meta_files:[],misc_blurb:"",misc_info:"",tags:null},urlRoot:galaxy_config.root+"api/histories/",url:function(){return this.urlRoot+this.get("history_id")+"/contents/"+this.get("id")},urls:function(){var i=this.get("id");if(!i){return{}}var h={purge:galaxy_config.root+"datasets/"+i+"/purge_async",display:galaxy_config.root+"datasets/"+i+"/display/?preview=True",edit:galaxy_config.root+"datasets/"+i+"/edit",download:galaxy_config.root+"datasets/"+i+"/display?to_ext="+this.get("file_ext"),report_error:galaxy_config.root+"dataset/errors?id="+i,rerun:galaxy_config.root+"tool_runner/rerun?id="+i,show_params:galaxy_config.root+"datasets/"+i+"/show_params",visualization:galaxy_config.root+"visualization",annotation:{get:galaxy_config.root+"dataset/get_annotation_async?id="+i,set:galaxy_config.root+"dataset/annotate_async?id="+i},meta_download:galaxy_config.root+"dataset/get_metadata_file?hda_id="+i+"&metadata_name="};return h},initialize:function(h){this.log(this+".initialize",this.attributes);this.log("\tparent history_id: "+this.get("history_id"));if(!this.get("accessible")){this.set("state",d.STATES.NOT_VIEWABLE)}this._setUpListeners()},_setUpListeners:function(){this.on("change:state",function(i,h){this.log(this+" has changed state:",i,h);if(this.inReadyState()){this.trigger("state:ready",i,h,this.previous("state"))}})},toJSON:function(){var h=Backbone.Model.prototype.toJSON.call(this);h.misc_info=jQuery.trim(h.misc_info);return h},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},isVisible:function(i,j){var h=true;if((!i)&&(this.get("deleted")||this.get("purged"))){h=false}if((!j)&&(!this.get("visible"))){h=false}return h},hidden:function(){return !this.get("visible")},inReadyState:function(){var h=_.contains(d.READY_STATES,this.get("state"));return(this.isDeletedOrPurged()||h)},hasDetails:function(){return _.has(this.attributes,"genome_build")},hasData:function(){return(this.get("file_size")>0)},"delete":function c(h){if(this.get("deleted")){return jQuery.when()}return this.save({deleted:true},h)},undelete:function a(h){if(!this.get("deleted")||this.get("purged")){return jQuery.when()}return this.save({deleted:false},h)},hide:function b(h){if(!this.get("visible")){return jQuery.when()}return this.save({visible:false},h)},unhide:function g(h){if(this.get("visible")){return jQuery.when()}return this.save({visible:true},h)},purge:function f(h){if(this.get("purged")){return jQuery.when()}h=h||{};h.url=galaxy_config.root+"datasets/"+this.get("id")+"/purge_async";var i=this,j=jQuery.ajax(h);j.done(function(m,k,l){i.set({deleted:true,purged:true})});j.fail(function(o,k,n){var l=_l("Unable to purge dataset");var m=("Removal of datasets by users is not allowed in this Galaxy instance");if(o.responseJSON&&o.responseJSON.error){l=o.responseJSON.error}else{if(o.responseText.indexOf(m)!==-1){l=m}}o.responseText=l;i.trigger("error",i,o,h,_l(l),{error:l})});return j},searchAttributes:["name","file_ext","genome_build","misc_blurb","misc_info","annotation","tags"],searchAliases:{title:"name",format:"file_ext",database:"genome_build",blurb:"misc_blurb",description:"misc_blurb",info:"misc_info",tag:"tags"},searchAttribute:function(j,h){var i=this.get(j);if(!h||(i===undefined||i===null)){return false}if(_.isArray(i)){return this._searchArrayAttribute(i,h)}return(i.toString().toLowerCase().indexOf(h.toLowerCase())!==-1)},_searchArrayAttribute:function(i,h){h=h.toLowerCase();return _.any(i,function(j){return(j.toString().toLowerCase().indexOf(h.toLowerCase())!==-1)})},search:function(h){var i=this;return _.filter(this.searchAttributes,function(j){return i.searchAttribute(j,h)})},matches:function(i){var k="=",h=i.split(k);if(h.length>=2){var j=h[0];j=this.searchAliases[j]||j;return this.searchAttribute(j,h[1])}return !!this.search(i).length},matchesAll:function(i){var h=this;i=i.match(/(".*"|\w*=".*"|\S*)/g).filter(function(j){return !!j});return _.all(i,function(j){j=j.replace(/"/g,"");return h.matches(j)})},toString:function(){var h=this.get("id")||"";if(this.get("name")){h=this.get("hid")+' :"'+this.get("name")+'",'+h}return"HDA("+h+")"}});d.STATES={UPLOAD:"upload",QUEUED:"queued",RUNNING:"running",SETTING_METADATA:"setting_metadata",NEW:"new",EMPTY:"empty",OK:"ok",PAUSED:"paused",FAILED_METADATA:"failed_metadata",NOT_VIEWABLE:"noPermission",DISCARDED:"discarded",ERROR:"error"};d.READY_STATES=[d.STATES.NEW,d.STATES.OK,d.STATES.EMPTY,d.STATES.PAUSED,d.STATES.FAILED_METADATA,d.STATES.NOT_VIEWABLE,d.STATES.DISCARDED,d.STATES.ERROR];d.NOT_READY_STATES=[d.STATES.UPLOAD,d.STATES.QUEUED,d.STATES.RUNNING,d.STATES.SETTING_METADATA];var e=Backbone.Collection.extend(LoggableMixin).extend({model:d,urlRoot:galaxy_config.root+"api/histories",url:function(){return this.urlRoot+"/"+this.historyId+"/contents"},initialize:function(i,h){h=h||{};this.historyId=h.historyId},ids:function(){return this.map(function(h){return h.id})},notReady:function(){return this.filter(function(h){return !h.inReadyState()})},running:function(){var h=[];this.each(function(i){if(!i.inReadyState()){h.push(i.get("id"))}});return h},getByHid:function(h){return _.first(this.filter(function(i){return i.get("hid")===h}))},getVisible:function(h,k,j){j=j||[];var i=new e(this.filter(function(l){return l.isVisible(h,k)}));_.each(j,function(l){if(!_.isFunction(l)){return}i=new e(i.filter(l))});return i},haveDetails:function(){return this.all(function(h){return h.hasDetails()})},fetchAllDetails:function(i){i=i||{};var h={details:"all"};i.data=(i.data)?(_.extend(i.data,h)):(h);return this.fetch(i)},ajaxQueue:function(k,j){var i=jQuery.Deferred(),h=this.length,m=[];if(!h){i.resolve([]);return i}var l=this.chain().reverse().map(function(o,n){return function(){var p=k.call(o,j);p.done(function(q){i.notify({curr:n,total:h,response:q,model:o})});p.always(function(q){m.push(q);if(l.length){l.shift()()}else{i.resolve(m)}})}}).value();l.shift()();return i},matches:function(h){return this.filter(function(i){return i.matches(h)})},set:function(j,h){var i=this;j=_.map(j,function(l){var m=i.get(l.id);if(!m){return l}var k=m.toJSON();_.extend(k,l);return k});Backbone.Collection.prototype.set.call(this,j,h)},toString:function(){return(["HDACollection(",[this.historyId,this.length].join(),")"].join(""))}});return{HistoryDatasetAssociation:d,HDACollection:e}});
\ No newline at end of file
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/scripts/packed/mvc/history/history-model.js
--- a/static/scripts/packed/mvc/history/history-model.js
+++ b/static/scripts/packed/mvc/history/history-model.js
@@ -1,1 +1,1 @@
-define(["mvc/dataset/hda-model"],function(a){var c=Backbone.Model.extend(LoggableMixin).extend({defaults:{model_class:"History",id:null,name:"Unnamed History",state:"new",diskSize:0,deleted:false},urlRoot:galaxy_config.root+"api/histories",renameUrl:function(){var e=this.get("id");if(!e){return undefined}return galaxy_config.root+"history/rename_async?id="+this.get("id")},annotateUrl:function(){var e=this.get("id");if(!e){return undefined}return galaxy_config.root+"history/annotate_async?id="+this.get("id")},tagUrl:function(){var e=this.get("id");if(!e){return undefined}return galaxy_config.root+"tag/get_tagging_elt_async?item_id="+this.get("id")+"&item_class=History"},initialize:function(f,g,e){e=e||{};this.logger=e.logger||null;this.log(this+".initialize:",f,g,e);this.hdas=new a.HDACollection(g||[],{historyId:this.get("id")});if(g&&_.isArray(g)){this.hdas.reset(g)}this._setUpListeners();this.updateTimeoutId=null;this.checkForUpdates()},_setUpListeners:function(){this.on("error",function(f,i,e,h,g){this.errorHandler(f,i,e,h,g)});if(this.hdas){this.listenTo(this.hdas,"error",function(){this.trigger.apply(this,["error:hdas"].concat(jQuery.makeArray(arguments)))})}this.on("change:id",function(f,e){if(this.hdas){this.hdas.historyId=e}},this)},errorHandler:function(f,i,e,h,g){this.clearUpdateTimeout()},hasUser:function(){var e=this.get("user");return !!(e&&e.id)},checkForUpdates:function(e){if(this.hdas.running().length){this.setUpdateTimeout()}else{this.trigger("ready");if(_.isFunction(e)){e.call(this)}}return this},setUpdateTimeout:function(e){e=e||c.UPDATE_DELAY;var f=this;this.clearUpdateTimeout();this.updateTimeoutId=setTimeout(function(){f.refresh()},e);return this.updateTimeoutId},clearUpdateTimeout:function(){if(this.updateTimeoutId){clearTimeout(this.updateTimeoutId);this.updateTimeoutId=null}},refresh:function(f,e){f=f||[];e=e||{};var g=this;e.data=e.data||{};if(f.length){e.data.details=f.join(",")}var h=this.hdas.fetch(e);h.done(function(i){g.checkForUpdates(function(){this.fetch()})});return h},toString:function(){return"History("+this.get("id")+","+this.get("name")+")"}});c.UPDATE_DELAY=4000;c.getHistoryData=function d(f,p){p=p||{};var j=p.hdaDetailIds||[];var l=jQuery.Deferred(),k=null;function g(q){return jQuery.ajax(galaxy_config.root+"api/histories/"+f)}function e(q){if(!q||!q.state_ids){return 0}return _.reduce(q.state_ids,function(r,t,s){return r+t.length},0)}function o(r){if(!e(r)){return[]}if(_.isFunction(j)){j=j(r)}var q=(j.length)?({details:j.join(",")}):({});return jQuery.ajax(galaxy_config.root+"api/histories/"+r.id+"/contents",{data:q})}var n=p.historyFn||g,m=p.hdaFn||o;var i=n(f);i.done(function(q){k=q;l.notify({status:"history data retrieved",historyJSON:k})});i.fail(function(s,q,r){l.reject(s,"loading the history")});var h=i.then(m);h.then(function(q){l.notify({status:"dataset data retrieved",historyJSON:k,hdaJSON:q});l.resolve(k,q)});h.fail(function(s,q,r){l.reject(s,"loading the datasets",{history:k})});return l};var b=Backbone.Collection.extend(LoggableMixin).extend({model:c,urlRoot:galaxy_config.root+"api/histories"});return{History:c,HistoryCollection:b}});
\ No newline at end of file
+define(["mvc/dataset/hda-model"],function(a){var c=Backbone.Model.extend(LoggableMixin).extend({defaults:{model_class:"History",id:null,name:"Unnamed History",state:"new",diskSize:0,deleted:false},urlRoot:galaxy_config.root+"api/histories",renameUrl:function(){var e=this.get("id");if(!e){return undefined}return galaxy_config.root+"history/rename_async?id="+this.get("id")},annotateUrl:function(){var e=this.get("id");if(!e){return undefined}return galaxy_config.root+"history/annotate_async?id="+this.get("id")},tagUrl:function(){var e=this.get("id");if(!e){return undefined}return galaxy_config.root+"tag/get_tagging_elt_async?item_id="+this.get("id")+"&item_class=History"},initialize:function(f,g,e){e=e||{};this.logger=e.logger||null;this.log(this+".initialize:",f,g,e);this.hdas=new a.HDACollection(g||[],{historyId:this.get("id")});if(g&&_.isArray(g)){this.hdas.reset(g)}this._setUpListeners();this.updateTimeoutId=null;this.checkForUpdates()},_setUpListeners:function(){this.on("error",function(f,i,e,h,g){this.errorHandler(f,i,e,h,g)});if(this.hdas){this.listenTo(this.hdas,"error",function(){this.trigger.apply(this,["error:hdas"].concat(jQuery.makeArray(arguments)))})}this.on("change:id",function(f,e){if(this.hdas){this.hdas.historyId=e}},this)},errorHandler:function(f,i,e,h,g){this.clearUpdateTimeout()},hasUser:function(){var e=this.get("user");return !!(e&&e.id)},hdaCount:function(){return _.reduce(_.values(this.get("state_details")),function(e,f){return e+f},0)},checkForUpdates:function(e){if(this.hdas.running().length){this.setUpdateTimeout()}else{this.trigger("ready");if(_.isFunction(e)){e.call(this)}}return this},setUpdateTimeout:function(e){e=e||c.UPDATE_DELAY;var f=this;this.clearUpdateTimeout();this.updateTimeoutId=setTimeout(function(){f.refresh()},e);return this.updateTimeoutId},clearUpdateTimeout:function(){if(this.updateTimeoutId){clearTimeout(this.updateTimeoutId);this.updateTimeoutId=null}},refresh:function(f,e){f=f||[];e=e||{};var g=this;e.data=e.data||{};if(f.length){e.data.details=f.join(",")}var h=this.hdas.fetch(e);h.done(function(i){g.checkForUpdates(function(){this.fetch()})});return h},toString:function(){return"History("+this.get("id")+","+this.get("name")+")"}});c.UPDATE_DELAY=4000;c.getHistoryData=function d(f,p){p=p||{};var j=p.hdaDetailIds||[];var l=jQuery.Deferred(),k=null;function g(q){return jQuery.ajax(galaxy_config.root+"api/histories/"+f)}function e(q){if(!q||!q.state_ids){return 0}return _.reduce(q.state_ids,function(r,t,s){return r+t.length},0)}function o(r){if(!e(r)){return[]}if(_.isFunction(j)){j=j(r)}var q=(j.length)?({details:j.join(",")}):({});return jQuery.ajax(galaxy_config.root+"api/histories/"+r.id+"/contents",{data:q})}var n=p.historyFn||g,m=p.hdaFn||o;var i=n(f);i.done(function(q){k=q;l.notify({status:"history data retrieved",historyJSON:k})});i.fail(function(s,q,r){l.reject(s,"loading the history")});var h=i.then(m);h.then(function(q){l.notify({status:"dataset data retrieved",historyJSON:k,hdaJSON:q});l.resolve(k,q)});h.fail(function(s,q,r){l.reject(s,"loading the datasets",{history:k})});return l};var b=Backbone.Collection.extend(LoggableMixin).extend({model:c,urlRoot:galaxy_config.root+"api/histories"});return{History:c,HistoryCollection:b}});
\ No newline at end of file
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 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 @@
-define(["mvc/history/history-model","mvc/dataset/hda-model","mvc/dataset/hda-base","mvc/dataset/hda-edit"],function(g,d,b,a){var c=SessionStorageModel.extend({defaults:{expandedHdas:{},show_deleted:false,show_hidden:false},addExpandedHda:function(h){this.save("expandedHdas",_.extend(this.get("expandedHdas"),_.object([h],[true])))},removeExpandedHda:function(h){this.save("expandedHdas",_.omit(this.get("expandedHdas"),h))},toString:function(){return"HistoryPanelPrefs("+this.id+")"}});c.historyStorageKey=function f(h){if(!h){throw new Error("HistoryPanelPrefs.historyStorageKey needs valid id: "+h)}return("history:"+h)};var e=Backbone.View.extend(LoggableMixin).extend({HDAView:a.HDAEditView,tagName:"div",className:"history-panel",fxSpeed:"fast",datasetsSelector:".datasets-list",emptyMsgSelector:".empty-history-message",msgsSelector:".message-container",initialize:function(h){h=h||{};if(h.logger){this.logger=h.logger}this.log(this+".initialize:",h);this.linkTarget=h.linkTarget||"_blank";this._setUpListeners();this.hdaViews={};this.indicator=new LoadingIndicator(this.$el);this.filters=[];this.searching=h.searching||false;this.selecting=h.selecting||false;if(this.model){this._setUpWebStorage(h.initiallyExpanded,h.show_deleted,h.show_hidden);this._setUpModelEventHandlers()}if(h.onready){h.onready.call(this)}},_setUpListeners:function(){this.on("error",function(i,l,h,k,j){this.errorHandler(i,l,h,k,j)});this.on("loading-history",function(){this.showLoadingIndicator("loading history...")});this.on("loading-done",function(){this.hideLoadingIndicator()});this.once("rendered",function(){this.trigger("rendered:initial",this);return false});this.on("switched-history current-history new-history",function(){if(_.isEmpty(this.hdaViews)){this.trigger("empty-history",this)}});if(this.logger){this.on("all",function(h){this.log(this+"",arguments)},this)}},errorHandler:function(j,m,i,l,k){var h=this._parseErrorMessage(j,m,i,l,k);if(m&&m.status===0&&m.readyState===0){}else{if(m&&m.status===502){}else{if(!this.$el.find(this.msgsSelector).is(":visible")){this.once("rendered",function(){this.displayMessage("error",h.message,h.details)})}else{this.displayMessage("error",h.message,h.details)}}}},_parseErrorMessage:function(k,o,j,n,m){var i=Galaxy.currUser,h={message:this._bePolite(n),details:{user:(i instanceof User)?(i.toJSON()):(i+""),source:(k instanceof Backbone.Model)?(k.toJSON()):(k+""),xhr:o,options:(o)?(_.omit(j,"xhr")):(j)}};_.extend(h.details,m||{});if(o&&_.isFunction(o.getAllResponseHeaders)){var l=o.getAllResponseHeaders();l=_.compact(l.split("\n"));l=_.map(l,function(p){return p.split(": ")});h.details.xhr.responseHeaders=_.object(l)}return h},_bePolite:function(h){h=h||_l("An error occurred while getting updates from the server");return h+". "+_l("Please contact a Galaxy administrator if the problem persists.")},loadCurrentHistory:function(i){var h=this;return this.loadHistoryWithHDADetails("current",i).then(function(k,j){h.trigger("current-history",h)})},switchToHistory:function(k,j){var h=this,i=function(){return jQuery.post(galaxy_config.root+"api/histories/"+k+"/set_as_current")};return this.loadHistoryWithHDADetails(k,j,i).then(function(m,l){h.trigger("switched-history",h)})},createNewHistory:function(j){if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){this.displayMessage("error",_l("You must be logged in to create histories"));return $.when()}var h=this,i=function(){return jQuery.post(galaxy_config.root+"api/histories",{current:true})};return this.loadHistory(undefined,j,i).then(function(l,k){h.trigger("new-history",h)})},loadHistoryWithHDADetails:function(k,j,i,m){var h=this,l=function(n){return h.getExpandedHdaIds(n.id)};return this.loadHistory(k,j,i,m,l)},loadHistory:function(k,j,i,n,l){this.trigger("loading-history",this);j=j||{};var h=this;var m=g.History.getHistoryData(k,{historyFn:i,hdaFn:n,hdaDetailIds:j.initiallyExpanded||l});return this._loadHistoryFromXHR(m,j).fail(function(q,o,p){h.trigger("error",h,q,j,_l("An error was encountered while "+o),{historyId:k,history:p||{}})}).always(function(){h.trigger("loading-done",h)})},_loadHistoryFromXHR:function(j,i){var h=this;j.then(function(k,l){h.setModel(k,l,i)});j.fail(function(l,k){h.render()});return j},setModel:function(j,h,i){i=i||{};if(this.model){this.model.clearUpdateTimeout();this.stopListening(this.model);this.stopListening(this.model.hdas)}this.hdaViews={};if(Galaxy&&Galaxy.currUser){j.user=Galaxy.currUser.toJSON()}this.model=new g.History(j,h,i);this._setUpWebStorage(i.initiallyExpanded,i.show_deleted,i.show_hidden);this._setUpModelEventHandlers();this.trigger("new-model",this);this.render();return this},_setUpWebStorage:function(i,h,j){this.storage=new c({id:c.historyStorageKey(this.model.get("id"))});if(_.isObject(i)){this.storage.set("exandedHdas",i)}if(_.isBoolean(h)){this.storage.set("show_deleted",h)}if(_.isBoolean(j)){this.storage.set("show_hidden",j)}this.trigger("new-storage",this.storage,this);this.log(this+" (init'd) storage:",this.storage.get())},clearWebStorage:function(){for(var h in sessionStorage){if(h.indexOf("history:")===0){sessionStorage.removeItem(h)}}},getStoredOptions:function(i){if(!i||i==="current"){return(this.storage)?(this.storage.get()):({})}var h=sessionStorage.getItem(c.historyStorageKey(i));return(h===null)?({}):(JSON.parse(h))},getExpandedHdaIds:function(h){var i=this.getStoredOptions(h).expandedHdas;return((_.isEmpty(i))?([]):(_.keys(i)))},_setUpModelEventHandlers:function(){this.model.on("error error:hdas",function(i,k,h,j){this.errorHandler(i,k,h,j)},this);this.model.on("change:nice_size",this.updateHistoryDiskSize,this);if(Galaxy&&Galaxy.quotaMeter){this.listenTo(this.model,"change:nice_size",function(){Galaxy.quotaMeter.update()})}this.model.hdas.on("add",this.addHdaView,this);this.model.hdas.on("change:deleted",this.handleHdaDeletionChange,this);this.model.hdas.on("change:visible",this.handleHdaVisibleChange,this);this.model.hdas.on("change:purged",function(h){this.model.fetch()},this);this.model.hdas.on("state:ready",function(i,j,h){if((!i.get("visible"))&&(!this.storage.get("show_hidden"))){this.removeHdaView(this.hdaViews[i.id])}},this)},render:function(j,k){j=(j===undefined)?(this.fxSpeed):(j);var h=this,i;if(this.model){i=this.renderModel()}else{i=this.renderWithoutModel()}$(h).queue("fx",[function(l){if(j&&h.$el.is(":visible")){h.$el.fadeOut(j,l)}else{l()}},function(l){h.$el.empty();if(i){h.$el.append(i.children())}l()},function(l){if(j&&!h.$el.is(":visible")){h.$el.fadeIn(j,l)}else{l()}},function(l){if(k){k.call(this)}h.trigger("rendered",this);l()}]);return this},renderWithoutModel:function(){var h=$("<div/>"),i=$("<div/>").addClass("message-container").css({"margin-left":"4px","margin-right":"4px"});return h.append(i)},renderModel:function(){var h=$("<div/>");if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){h.append(e.templates.anonHistoryPanel(this.model.toJSON()))}else{h.append(e.templates.historyPanel(this.model.toJSON()));this._renderTags(h);this._renderAnnotation(h)}h.find(".history-secondary-actions").prepend(this._renderSearchButton());this._setUpBehaviours(h);this.renderHdas(h);return h},_renderTags:function(h){this.tagsEditor=new TagsEditor({model:this.model,el:h.find(".history-controls .tags-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit history tags"),classes:"history-tag-btn",faIcon:"fa-tags"}).appendTo(h.find(".history-secondary-actions"))})},_renderAnnotation:function(h){this.annotationEditor=new AnnotationEditor({model:this.model,el:h.find(".history-controls .annotation-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit history tags"),classes:"history-annotate-btn",faIcon:"fa-comment"}).appendTo(h.find(".history-secondary-actions"))})},_renderSearchButton:function(h){return faIconButton({title:_l("Search datasets"),classes:"history-search-btn",faIcon:"fa-search"})},_renderSelectButton:function(h){return faIconButton({title:_l("Operations on multiple datasets"),classes:"history-select-btn",faIcon:"fa-check-square-o"})},_setUpBehaviours:function(h){h=h||this.$el;h.find("[title]").tooltip({placement:"bottom"});if(!this.model||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){return}var i=this;h.find(".history-name").make_text_editable({on_finish:function(j){h.find(".history-name").text(j);i.model.save({name:j}).fail(function(){h.find(".history-name").text(i.model.previous("name"))})}});this._setUpDatasetActionsPopup(h)},_setUpDatasetActionsPopup:function(h){var i=this;(new PopupMenu(h.find(".history-dataset-action-popup-btn"),[{html:_l("Hide datasets"),func:function(){var j=d.HistoryDatasetAssociation.prototype.hide;i.getSelectedHdaCollection().ajaxQueue(j)}},{html:_l("Unhide datasets"),func:function(){var j=d.HistoryDatasetAssociation.prototype.unhide;i.getSelectedHdaCollection().ajaxQueue(j)}},{html:_l("Delete datasets"),func:function(){var j=d.HistoryDatasetAssociation.prototype["delete"];i.getSelectedHdaCollection().ajaxQueue(j)}},{html:_l("Undelete datasets"),func:function(){var j=d.HistoryDatasetAssociation.prototype.undelete;i.getSelectedHdaCollection().ajaxQueue(j)}},{html:_l("Permanently delete datasets"),func:function(){if(confirm(_l("This will permanently remove the data in your datasets. Are you sure?"))){var j=d.HistoryDatasetAssociation.prototype.purge;i.getSelectedHdaCollection().ajaxQueue(j)}}}]))},refreshHdas:function(i,h){if(this.model){return this.model.refresh(i,h)}return $.when()},addHdaView:function(k){this.log("add."+this,k);var i=this;if(!k.isVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"))){return}$({}).queue([function j(m){var l=i.$el.find(i.emptyMsgSelector);if(l.is(":visible")){l.fadeOut(i.fxSpeed,m)}else{m()}},function h(m){i.scrollToTop();var l=i.$el.find(i.datasetsSelector);i.createHdaView(k).$el.hide().prependTo(l).slideDown(i.fxSpeed)}])},createHdaView:function(j){var i=j.get("id"),h=this.storage.get("expandedHdas")[i],k=new this.HDAView({model:j,linkTarget:this.linkTarget,expanded:h,selectable:this.selecting,hasUser:this.model.hasUser(),logger:this.logger});this._setUpHdaListeners(k);this.hdaViews[i]=k;return k.render()},_setUpHdaListeners:function(i){var h=this;i.on("body-expanded",function(j){h.storage.addExpandedHda(j)});i.on("body-collapsed",function(j){h.storage.removeExpandedHda(j)});i.on("error",function(k,m,j,l){h.errorHandler(k,m,j,l)})},handleHdaDeletionChange:function(h){if(h.get("deleted")&&!this.storage.get("show_deleted")){this.removeHdaView(this.hdaViews[h.id])}},handleHdaVisibleChange:function(h){if(h.hidden()&&!this.storage.get("show_hidden")){this.removeHdaView(this.hdaViews[h.id])}},removeHdaView:function(i){if(!i){return}var h=this;i.$el.fadeOut(h.fxSpeed,function(){i.off();i.remove();delete h.hdaViews[i.model.id];if(_.isEmpty(h.hdaViews)){h.$el.find(h.emptyMsgSelector).fadeIn(h.fxSpeed,function(){h.trigger("empty-history",h)})}})},renderHdas:function(j){j=j||this.$el;this.hdaViews={};var i=this,h=j.find(this.datasetsSelector),k=this.model.hdas.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"),this.filters);h.empty();if(k.length){k.each(function(l){h.prepend(i.createHdaView(l).$el)});j.find(this.emptyMsgSelector).hide()}else{j.find(this.emptyMsgSelector).show()}return this.hdaViews},events:{"click .message-container":"clearMessages","click .history-search-btn":"toggleSearchControls","click .history-select-btn":function(h){this.toggleSelect(this.fxSpeed)},"click .history-select-all-datasets-btn":"selectAllDatasets"},updateHistoryDiskSize:function(){this.$el.find(".history-size").text(this.model.get("nice_size"))},collapseAllHdaBodies:function(){_.each(this.hdaViews,function(h){h.toggleBodyVisibility(null,false)});this.storage.set("expandedHdas",{})},toggleShowDeleted:function(){this.storage.set("show_deleted",!this.storage.get("show_deleted"));this.renderHdas();return this.storage.get("show_deleted")},toggleShowHidden:function(){this.storage.set("show_hidden",!this.storage.get("show_hidden"));this.renderHdas();return this.storage.get("show_hidden")},renderSearchControls:function(i){var j=this;function l(m){j.searchFor=m;j.filters=[function(n){return n.matchesAll(j.searchFor)}];j.trigger("search:searching",m,j);j.renderHdas()}function h(m){j.$el.find(".history-search-controls").searchInput("toggle-loading");j.model.hdas.fetchAllDetails({silent:true}).always(function(){j.$el.find(".history-search-controls").searchInput("toggle-loading")}).done(function(){l(m)})}function k(){j.searchFor="";j.filters=[];j.trigger("search:clear",j);j.renderHdas()}return i.searchInput({initialVal:j.searchFor,name:"history-search",placeholder:"search datasets",classes:"history-search",onfirstsearch:h,onsearch:l,onclear:k})},toggleSearchControls:function(){var h=this.$el.find(".history-search-controls");if(!h.children().size()){h=this.renderSearchControls(h).hide()}h.slideToggle(this.fxSpeed,function(){if($(this).is(":visible")){this.searching=true;$(this).find("input").focus()}else{this.searching=false}})},showSelectors:function(h){this.selecting=true;this.$el.find(".history-dataset-actions").slideDown(h);_.each(this.hdaViews,function(i){i.showSelector(h)})},hideSelectors:function(h){this.selecting=false;this.$el.find(".history-dataset-actions").slideUp(h);_.each(this.hdaViews,function(i){i.hideSelector(h)})},toggleSelect:function(h){if(!this.selecting){this.showSelectors(h)}else{this.hideSelectors(h)}},selectAllDatasets:function(i){var h=this.$el.find(".history-select-all-datasets-btn");currMode=h.data("mode");if(currMode==="select"){_.each(this.hdaViews,function(j){j.select(i)});h.data("mode","deselect");h.text(_l("De-select all"))}else{if(currMode==="deselect"){_.each(this.hdaViews,function(j){j.deselect(i)});h.data("mode","select");h.text(_l("Select all"))}}},getSelectedHdaViews:function(){return _.filter(this.hdaViews,function(h){return h.selected})},getSelectedHdaCollection:function(){return new d.HDACollection(_.map(this.getSelectedHdaViews(),function(h){return h.model}),{historyId:this.model.id})},showLoadingIndicator:function(i,h,j){h=(h!==undefined)?(h):(this.fxSpeed);if(!this.indicator){this.indicator=new LoadingIndicator(this.$el,this.$el.parent())}if(!this.$el.is(":visible")){this.indicator.show(0,j)}else{this.$el.fadeOut(h);this.indicator.show(i,h,j)}},hideLoadingIndicator:function(h,i){h=(h!==undefined)?(h):(this.fxSpeed);if(this.indicator){this.indicator.hide(h,i)}},displayMessage:function(m,n,l){var j=this;this.scrollToTop();var k=this.$el.find(this.msgsSelector),h=$("<div/>").addClass(m+"message").html(n);if(!_.isEmpty(l)){var i=$('<a href="javascript:void(0)">Details</a>').click(function(){Galaxy.modal.show(j.messageToModalOptions(m,n,l));return false});h.append(" ",i)}return k.html(h)},messageToModalOptions:function(l,n,k){var h=this,m=$("<div/>"),j={title:"Details"};function i(o){o=_.omit(o,_.functions(o));return["<table>",_.map(o,function(q,p){q=(_.isObject(q))?(i(q)):(q);return'<tr><td style="vertical-align: top; color: grey">'+p+'</td><td style="padding-left: 8px">'+q+"</td></tr>"}).join(""),"</table>"].join("")}if(_.isObject(k)){j.body=m.append(i(k))}else{j.body=m.html(k)}j.buttons={Ok:function(){Galaxy.modal.hide();h.clearMessages()}};return j},clearMessages:function(){var h=this.$el.find(this.msgsSelector);h.empty()},scrollPosition:function(){return this.$el.parent().scrollTop()},scrollTo:function(h){this.$el.parent().scrollTop(h)},scrollToTop:function(){this.$el.parent().scrollTop(0);return this},scrollIntoView:function(i,j){if(!j){this.$el.parent().parent().scrollTop(i);return this}var h=window,k=this.$el.parent().parent(),m=$(h).innerHeight(),l=(m/2)-(j/2);$(k).scrollTop(i-l);return this},scrollToId:function(i){if((!i)||(!this.hdaViews[i])){return this}var h=this.hdaViews[i].$el;this.scrollIntoView(h.offset().top,h.outerHeight());return this},scrollToHid:function(h){var i=this.model.hdas.getByHid(h);if(!i){return this}return this.scrollToId(i.id)},connectToQuotaMeter:function(h){if(!h){return this}this.listenTo(h,"quota:over",this.showQuotaMessage);this.listenTo(h,"quota:under",this.hideQuotaMessage);this.on("rendered rendered:initial",function(){if(h&&h.isOverQuota()){this.showQuotaMessage()}});return this},showQuotaMessage:function(){var h=this.$el.find(".quota-message");if(h.is(":hidden")){h.slideDown(this.fxSpeed)}},hideQuotaMessage:function(){var h=this.$el.find(".quota-message");if(!h.is(":hidden")){h.slideUp(this.fxSpeed)}},connectToOptionsMenu:function(h){if(!h){return this}this.on("new-storage",function(j,i){if(h&&j){h.findItemByHtml(_l("Include Deleted Datasets")).checked=j.get("show_deleted");h.findItemByHtml(_l("Include Hidden Datasets")).checked=j.get("show_hidden")}});return this},toString:function(){return"HistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});e.templates={historyPanel:Handlebars.templates["template-history-historyPanel"],anonHistoryPanel:Handlebars.templates["template-history-historyPanel-anon"]};return{HistoryPanel:e}});
\ No newline at end of file
+define(["mvc/history/history-model","mvc/dataset/hda-model","mvc/dataset/hda-base","mvc/dataset/hda-edit"],function(g,d,b,a){var c=SessionStorageModel.extend({defaults:{expandedHdas:{},show_deleted:false,show_hidden:false},addExpandedHda:function(h){this.save("expandedHdas",_.extend(this.get("expandedHdas"),_.object([h],[true])))},removeExpandedHda:function(h){this.save("expandedHdas",_.omit(this.get("expandedHdas"),h))},toString:function(){return"HistoryPanelPrefs("+this.id+")"}});c.historyStorageKey=function f(h){if(!h){throw new Error("HistoryPanelPrefs.historyStorageKey needs valid id: "+h)}return("history:"+h)};var e=Backbone.View.extend(LoggableMixin).extend({defaultHDAViewClass:a.HDAEditView,tagName:"div",className:"history-panel",fxSpeed:"fast",datasetsSelector:".datasets-list",emptyMsgSelector:".empty-history-message",msgsSelector:".message-container",initialize:function(h){h=h||{};if(h.logger){this.logger=h.logger}this.log(this+".initialize:",h);this.HDAViewClass=h.HDAViewClass||this.defaultHDAViewClass;this.linkTarget=h.linkTarget||"_blank";this.hdaViews={};this.indicator=new LoadingIndicator(this.$el);this.filters=[];this.searching=h.searching||false;this.selecting=h.selecting||false;this._setUpListeners();if(this.model){this._setUpWebStorage(h.initiallyExpanded,h.show_deleted,h.show_hidden);this._setUpModelEventHandlers()}if(h.onready){h.onready.call(this)}},_setUpListeners:function(){this.on("error",function(i,l,h,k,j){this.errorHandler(i,l,h,k,j)});this.on("loading-history",function(){this.showLoadingIndicator("loading history...")});this.on("loading-done",function(){this.hideLoadingIndicator()});this.once("rendered",function(){this.trigger("rendered:initial",this);return false});this.on("switched-history current-history new-history",function(){if(_.isEmpty(this.hdaViews)){this.trigger("empty-history",this)}});if(this.logger){this.on("all",function(h){this.log(this+"",arguments)},this)}},errorHandler:function(j,m,i,l,k){var h=this._parseErrorMessage(j,m,i,l,k);if(m&&m.status===0&&m.readyState===0){}else{if(m&&m.status===502){}else{if(!this.$el.find(this.msgsSelector).is(":visible")){this.once("rendered",function(){this.displayMessage("error",h.message,h.details)})}else{this.displayMessage("error",h.message,h.details)}}}},_parseErrorMessage:function(k,o,j,n,m){var i=Galaxy.currUser,h={message:this._bePolite(n),details:{user:(i instanceof User)?(i.toJSON()):(i+""),source:(k instanceof Backbone.Model)?(k.toJSON()):(k+""),xhr:o,options:(o)?(_.omit(j,"xhr")):(j)}};_.extend(h.details,m||{});if(o&&_.isFunction(o.getAllResponseHeaders)){var l=o.getAllResponseHeaders();l=_.compact(l.split("\n"));l=_.map(l,function(p){return p.split(": ")});h.details.xhr.responseHeaders=_.object(l)}return h},_bePolite:function(h){h=h||_l("An error occurred while getting updates from the server");return h+". "+_l("Please contact a Galaxy administrator if the problem persists.")},loadCurrentHistory:function(i){var h=this;return this.loadHistoryWithHDADetails("current",i).then(function(k,j){h.trigger("current-history",h)})},switchToHistory:function(k,j){var h=this,i=function(){return jQuery.post(galaxy_config.root+"api/histories/"+k+"/set_as_current")};return this.loadHistoryWithHDADetails(k,j,i).then(function(m,l){h.trigger("switched-history",h)})},createNewHistory:function(j){if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){this.displayMessage("error",_l("You must be logged in to create histories"));return $.when()}var h=this,i=function(){return jQuery.post(galaxy_config.root+"api/histories",{current:true})};return this.loadHistory(undefined,j,i).then(function(l,k){h.trigger("new-history",h)})},loadHistoryWithHDADetails:function(k,j,i,m){var h=this,l=function(n){return h.getExpandedHdaIds(n.id)};return this.loadHistory(k,j,i,m,l)},loadHistory:function(k,j,i,n,l){this.trigger("loading-history",this);j=j||{};var h=this;var m=g.History.getHistoryData(k,{historyFn:i,hdaFn:n,hdaDetailIds:j.initiallyExpanded||l});return this._loadHistoryFromXHR(m,j).fail(function(q,o,p){h.trigger("error",h,q,j,_l("An error was encountered while "+o),{historyId:k,history:p||{}})}).always(function(){h.trigger("loading-done",h)})},_loadHistoryFromXHR:function(j,i){var h=this;j.then(function(k,l){h.setModel(k,l,i)});j.fail(function(l,k){h.render()});return j},setModel:function(j,h,i){i=i||{};if(this.model){this.model.clearUpdateTimeout();this.stopListening(this.model);this.stopListening(this.model.hdas)}this.hdaViews={};if(Galaxy&&Galaxy.currUser){j.user=Galaxy.currUser.toJSON()}this.model=new g.History(j,h,i);this._setUpWebStorage(i.initiallyExpanded,i.show_deleted,i.show_hidden);this._setUpModelEventHandlers();this.trigger("new-model",this);this.render();return this},_setUpWebStorage:function(i,h,j){this.storage=new c({id:c.historyStorageKey(this.model.get("id"))});if(_.isObject(i)){this.storage.set("exandedHdas",i)}if(_.isBoolean(h)){this.storage.set("show_deleted",h)}if(_.isBoolean(j)){this.storage.set("show_hidden",j)}this.trigger("new-storage",this.storage,this);this.log(this+" (init'd) storage:",this.storage.get())},clearWebStorage:function(){for(var h in sessionStorage){if(h.indexOf("history:")===0){sessionStorage.removeItem(h)}}},getStoredOptions:function(i){if(!i||i==="current"){return(this.storage)?(this.storage.get()):({})}var h=sessionStorage.getItem(c.historyStorageKey(i));return(h===null)?({}):(JSON.parse(h))},getExpandedHdaIds:function(h){var i=this.getStoredOptions(h).expandedHdas;return((_.isEmpty(i))?([]):(_.keys(i)))},_setUpModelEventHandlers:function(){this.model.on("error error:hdas",function(i,k,h,j){this.errorHandler(i,k,h,j)},this);this.model.on("change:nice_size",this.updateHistoryDiskSize,this);if(Galaxy&&Galaxy.quotaMeter){this.listenTo(this.model,"change:nice_size",function(){Galaxy.quotaMeter.update()})}this.model.hdas.on("add",this.addHdaView,this);this.model.hdas.on("change:deleted",this.handleHdaDeletionChange,this);this.model.hdas.on("change:visible",this.handleHdaVisibleChange,this);this.model.hdas.on("change:purged",function(h){this.model.fetch()},this);this.model.hdas.on("state:ready",function(i,j,h){if((!i.get("visible"))&&(!this.storage.get("show_hidden"))){this.removeHdaView(this.hdaViews[i.id])}},this)},render:function(j,k){j=(j===undefined)?(this.fxSpeed):(j);var h=this,i;if(this.model){i=this.renderModel()}else{i=this.renderWithoutModel()}$(h).queue("fx",[function(l){if(j&&h.$el.is(":visible")){h.$el.fadeOut(j,l)}else{l()}},function(l){h.$el.empty();if(i){h.$el.append(i.children())}l()},function(l){if(j&&!h.$el.is(":visible")){h.$el.fadeIn(j,l)}else{l()}},function(l){if(k){k.call(this)}h.trigger("rendered",this);l()}]);return this},renderWithoutModel:function(){var h=$("<div/>"),i=$("<div/>").addClass("message-container").css({"margin-left":"4px","margin-right":"4px"});return h.append(i)},renderModel:function(){var h=$("<div/>");if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){h.append(e.templates.anonHistoryPanel(this.model.toJSON()))}else{h.append(e.templates.historyPanel(this.model.toJSON()));if(Galaxy.currUser.id&&Galaxy.currUser.id===this.model.get("user_id")){this._renderTags(h);this._renderAnnotation(h)}}h.find(".history-secondary-actions").prepend(this._renderSearchButton());this._setUpBehaviours(h);this.renderHdas(h);return h},_renderTags:function(h){this.tagsEditor=new TagsEditor({model:this.model,el:h.find(".history-controls .tags-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit history tags"),classes:"history-tag-btn",faIcon:"fa-tags"}).appendTo(h.find(".history-secondary-actions"))})},_renderAnnotation:function(h){this.annotationEditor=new AnnotationEditor({model:this.model,el:h.find(".history-controls .annotation-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit history tags"),classes:"history-annotate-btn",faIcon:"fa-comment"}).appendTo(h.find(".history-secondary-actions"))})},_renderSearchButton:function(h){return faIconButton({title:_l("Search datasets"),classes:"history-search-btn",faIcon:"fa-search"})},_renderSelectButton:function(h){return faIconButton({title:_l("Operations on multiple datasets"),classes:"history-select-btn",faIcon:"fa-check-square-o"})},_setUpBehaviours:function(h){h=h||this.$el;h.find("[title]").tooltip({placement:"bottom"});if((!this.model)||(!Galaxy.currUser||Galaxy.currUser.isAnonymous())||(Galaxy.currUser.id!==this.model.get("user_id"))){return}var i=this;h.find(".history-name").attr("title",_l("Click to rename history")).tooltip({placement:"bottom"}).make_text_editable({on_finish:function(j){h.find(".history-name").text(j);i.model.save({name:j}).fail(function(){h.find(".history-name").text(i.model.previous("name"))})}});this._setUpDatasetActionsPopup(h)},_setUpDatasetActionsPopup:function(h){var i=this;(new PopupMenu(h.find(".history-dataset-action-popup-btn"),[{html:_l("Hide datasets"),func:function(){var j=d.HistoryDatasetAssociation.prototype.hide;i.getSelectedHdaCollection().ajaxQueue(j)}},{html:_l("Unhide datasets"),func:function(){var j=d.HistoryDatasetAssociation.prototype.unhide;i.getSelectedHdaCollection().ajaxQueue(j)}},{html:_l("Delete datasets"),func:function(){var j=d.HistoryDatasetAssociation.prototype["delete"];i.getSelectedHdaCollection().ajaxQueue(j)}},{html:_l("Undelete datasets"),func:function(){var j=d.HistoryDatasetAssociation.prototype.undelete;i.getSelectedHdaCollection().ajaxQueue(j)}},{html:_l("Permanently delete datasets"),func:function(){if(confirm(_l("This will permanently remove the data in your datasets. Are you sure?"))){var j=d.HistoryDatasetAssociation.prototype.purge;i.getSelectedHdaCollection().ajaxQueue(j)}}}]))},refreshHdas:function(i,h){if(this.model){return this.model.refresh(i,h)}return $.when()},addHdaView:function(k){this.log("add."+this,k);var i=this;if(!k.isVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"))){return}$({}).queue([function j(m){var l=i.$el.find(i.emptyMsgSelector);if(l.is(":visible")){l.fadeOut(i.fxSpeed,m)}else{m()}},function h(m){i.scrollToTop();var l=i.$el.find(i.datasetsSelector);i.createHdaView(k).$el.hide().prependTo(l).slideDown(i.fxSpeed)}])},createHdaView:function(j){var i=j.get("id"),h=this.storage.get("expandedHdas")[i],k=new this.HDAViewClass({model:j,linkTarget:this.linkTarget,expanded:h,selectable:this.selecting,hasUser:this.model.hasUser(),logger:this.logger});this._setUpHdaListeners(k);this.hdaViews[i]=k;return k.render()},_setUpHdaListeners:function(i){var h=this;i.on("body-expanded",function(j){h.storage.addExpandedHda(j)});i.on("body-collapsed",function(j){h.storage.removeExpandedHda(j)});i.on("error",function(k,m,j,l){h.errorHandler(k,m,j,l)})},handleHdaDeletionChange:function(h){if(h.get("deleted")&&!this.storage.get("show_deleted")){this.removeHdaView(this.hdaViews[h.id])}},handleHdaVisibleChange:function(h){if(h.hidden()&&!this.storage.get("show_hidden")){this.removeHdaView(this.hdaViews[h.id])}},removeHdaView:function(i){if(!i){return}var h=this;i.$el.fadeOut(h.fxSpeed,function(){i.off();i.remove();delete h.hdaViews[i.model.id];if(_.isEmpty(h.hdaViews)){h.$el.find(h.emptyMsgSelector).fadeIn(h.fxSpeed,function(){h.trigger("empty-history",h)})}})},renderHdas:function(j){j=j||this.$el;this.hdaViews={};var i=this,h=j.find(this.datasetsSelector),k=this.model.hdas.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"),this.filters);h.empty();if(k.length){k.each(function(l){h.prepend(i.createHdaView(l).$el)});j.find(this.emptyMsgSelector).hide()}else{j.find(this.emptyMsgSelector).show()}return this.hdaViews},events:{"click .message-container":"clearMessages","click .history-search-btn":"toggleSearchControls","click .history-select-btn":function(h){this.toggleSelectors(this.fxSpeed)},"click .history-select-all-datasets-btn":"selectAllDatasets"},updateHistoryDiskSize:function(){this.$el.find(".history-size").text(this.model.get("nice_size"))},collapseAllHdaBodies:function(){_.each(this.hdaViews,function(h){h.toggleBodyVisibility(null,false)});this.storage.set("expandedHdas",{})},toggleShowDeleted:function(){this.storage.set("show_deleted",!this.storage.get("show_deleted"));this.renderHdas();return this.storage.get("show_deleted")},toggleShowHidden:function(){this.storage.set("show_hidden",!this.storage.get("show_hidden"));this.renderHdas();return this.storage.get("show_hidden")},renderSearchControls:function(i){var j=this;function l(m){j.searchFor=m;j.filters=[function(n){return n.matchesAll(j.searchFor)}];j.trigger("search:searching",m,j);j.renderHdas()}function h(m){if(j.model.hdas.haveDetails()){l(m);return}j.$el.find(".history-search-controls").searchInput("toggle-loading");j.model.hdas.fetchAllDetails({silent:true}).always(function(){j.$el.find(".history-search-controls").searchInput("toggle-loading")}).done(function(){l(m)})}function k(){j.searchFor="";j.filters=[];j.trigger("search:clear",j);j.renderHdas()}return i.searchInput({initialVal:j.searchFor,name:"history-search",placeholder:"search datasets",classes:"history-search",onfirstsearch:h,onsearch:l,onclear:k})},toggleSearchControls:function(){var h=this.$el.find(".history-search-controls");if(!h.children().size()){h=this.renderSearchControls(h).hide()}h.slideToggle(this.fxSpeed,function(){if($(this).is(":visible")){this.searching=true;$(this).find("input").focus()}else{this.searching=false}})},showSelectors:function(h){this.selecting=true;this.$el.find(".history-dataset-actions").slideDown(h);_.each(this.hdaViews,function(i){i.showSelector(h)})},hideSelectors:function(h){this.selecting=false;this.$el.find(".history-dataset-actions").slideUp(h);_.each(this.hdaViews,function(i){i.hideSelector(h)})},toggleSelectors:function(h){if(!this.selecting){this.showSelectors(h)}else{this.hideSelectors(h)}},selectAllDatasets:function(i){var h=this.$el.find(".history-select-all-datasets-btn");currMode=h.data("mode");if(currMode==="select"){_.each(this.hdaViews,function(j){j.select(i)});h.data("mode","deselect");h.text(_l("De-select all"))}else{if(currMode==="deselect"){_.each(this.hdaViews,function(j){j.deselect(i)});h.data("mode","select");h.text(_l("Select all"))}}},getSelectedHdaViews:function(){return _.filter(this.hdaViews,function(h){return h.selected})},getSelectedHdaCollection:function(){return new d.HDACollection(_.map(this.getSelectedHdaViews(),function(h){return h.model}),{historyId:this.model.id})},showLoadingIndicator:function(i,h,j){h=(h!==undefined)?(h):(this.fxSpeed);if(!this.indicator){this.indicator=new LoadingIndicator(this.$el,this.$el.parent())}if(!this.$el.is(":visible")){this.indicator.show(0,j)}else{this.$el.fadeOut(h);this.indicator.show(i,h,j)}},hideLoadingIndicator:function(h,i){h=(h!==undefined)?(h):(this.fxSpeed);if(this.indicator){this.indicator.hide(h,i)}},displayMessage:function(m,n,l){var j=this;this.scrollToTop();var k=this.$el.find(this.msgsSelector),h=$("<div/>").addClass(m+"message").html(n);if(!_.isEmpty(l)){var i=$('<a href="javascript:void(0)">Details</a>').click(function(){Galaxy.modal.show(j.messageToModalOptions(m,n,l));return false});h.append(" ",i)}return k.html(h)},messageToModalOptions:function(l,n,k){var h=this,m=$("<div/>"),j={title:"Details"};function i(o){o=_.omit(o,_.functions(o));return["<table>",_.map(o,function(q,p){q=(_.isObject(q))?(i(q)):(q);return'<tr><td style="vertical-align: top; color: grey">'+p+'</td><td style="padding-left: 8px">'+q+"</td></tr>"}).join(""),"</table>"].join("")}if(_.isObject(k)){j.body=m.append(i(k))}else{j.body=m.html(k)}j.buttons={Ok:function(){Galaxy.modal.hide();h.clearMessages()}};return j},clearMessages:function(){var h=this.$el.find(this.msgsSelector);h.empty()},scrollPosition:function(){return this.$el.parent().scrollTop()},scrollTo:function(h){this.$el.parent().scrollTop(h)},scrollToTop:function(){this.$el.parent().scrollTop(0);return this},scrollIntoView:function(i,j){if(!j){this.$el.parent().parent().scrollTop(i);return this}var h=window,k=this.$el.parent().parent(),m=$(h).innerHeight(),l=(m/2)-(j/2);$(k).scrollTop(i-l);return this},scrollToId:function(i){if((!i)||(!this.hdaViews[i])){return this}var h=this.hdaViews[i].$el;this.scrollIntoView(h.offset().top,h.outerHeight());return this},scrollToHid:function(h){var i=this.model.hdas.getByHid(h);if(!i){return this}return this.scrollToId(i.id)},connectToQuotaMeter:function(h){if(!h){return this}this.listenTo(h,"quota:over",this.showQuotaMessage);this.listenTo(h,"quota:under",this.hideQuotaMessage);this.on("rendered rendered:initial",function(){if(h&&h.isOverQuota()){this.showQuotaMessage()}});return this},showQuotaMessage:function(){var h=this.$el.find(".quota-message");if(h.is(":hidden")){h.slideDown(this.fxSpeed)}},hideQuotaMessage:function(){var h=this.$el.find(".quota-message");if(!h.is(":hidden")){h.slideUp(this.fxSpeed)}},connectToOptionsMenu:function(h){if(!h){return this}this.on("new-storage",function(j,i){if(h&&j){h.findItemByHtml(_l("Include Deleted Datasets")).checked=j.get("show_deleted");h.findItemByHtml(_l("Include Hidden Datasets")).checked=j.get("show_hidden")}});return this},toString:function(){return"HistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});e.templates={historyPanel:Handlebars.templates["template-history-historyPanel"],anonHistoryPanel:Handlebars.templates["template-history-historyPanel-anon"]};return{HistoryPanel:e}});
\ No newline at end of file
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/scripts/packed/templates/compiled/history-templates.js
--- a/static/scripts/packed/templates/compiled/history-templates.js
+++ b/static/scripts/packed/templates/compiled/history-templates.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-body"]=b(function(g,r,p,k,z){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);z=z||{};var q="",h,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(D,C){var A="",B;A+='\n <div class="dataset-summary">\n ';if(B=p.body){B=B.call(D,{hash:{},data:C})}else{B=D.body;B=typeof B===e?B.apply(D):B}if(B||B===0){A+=B}A+='\n </div>\n <div class="dataset-actions clear">\n <div class="left"></div>\n <div class="right"></div>\n </div>\n\n ';return A}function m(D,C){var A="",B;A+='\n <div class="dataset-summary">\n ';B=p["if"].call(D,D.misc_blurb,{hash:{},inverse:o.noop,fn:o.program(4,l,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.data_type,{hash:{},inverse:o.noop,fn:o.program(6,j,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.metadata_dbkey,{hash:{},inverse:o.noop,fn:o.program(9,f,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.misc_info,{hash:{},inverse:o.noop,fn:o.program(12,x,C),data:C});if(B||B===0){A+=B}A+='\n </div>\n\n <div class="dataset-actions clear">\n <div class="left"></div>\n <div class="right"></div>\n </div>\n\n ';B=p.unless.call(D,D.deleted,{hash:{},inverse:o.noop,fn:o.program(14,w,C),data:C});if(B||B===0){A+=B}A+="\n\n ";return A}function l(D,C){var A="",B;A+='\n <div class="dataset-blurb">\n <span class="value">';if(B=p.misc_blurb){B=B.call(D,{hash:{},data:C})}else{B=D.misc_blurb;B=typeof B===e?B.apply(D):B}A+=d(B)+"</span>\n </div>\n ";return A}function j(E,D){var A="",C,B;A+='\n <div class="dataset-datatype">\n <label class="prompt">';B={hash:{},inverse:o.noop,fn:o.program(7,i,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+='</label>\n <span class="value">';if(C=p.data_type){C=C.call(E,{hash:{},data:D})}else{C=E.data_type;C=typeof C===e?C.apply(E):C}A+=d(C)+"</span>\n </div>\n ";return A}function i(B,A){return"format"}function f(E,D){var A="",C,B;A+='\n <div class="dataset-dbkey">\n <label class="prompt">';B={hash:{},inverse:o.noop,fn:o.program(10,y,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+='</label>\n <span class="value">\n ';if(C=p.metadata_dbkey){C=C.call(E,{hash:{},data:D})}else{C=E.metadata_dbkey;C=typeof C===e?C.apply(E):C}A+=d(C)+"\n </span>\n </div>\n ";return A}function y(B,A){return"database"}function x(D,C){var A="",B;A+='\n <div class="dataset-info">\n <span class="value">';if(B=p.misc_info){B=B.call(D,{hash:{},data:C})}else{B=D.misc_info;B=typeof B===e?B.apply(D):B}A+=d(B)+"</span>\n </div>\n ";return A}function w(D,C){var A="",B;A+='\n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n <div class="dataset-display-applications">\n ';B=p.each.call(D,D.display_apps,{hash:{},inverse:o.noop,fn:o.program(15,v,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p.each.call(D,D.display_types,{hash:{},inverse:o.noop,fn:o.program(15,v,C),data:C});if(B||B===0){A+=B}A+='\n </div>\n\n <div class="dataset-peek">\n ';B=p["if"].call(D,D.peek,{hash:{},inverse:o.noop,fn:o.program(19,s,C),data:C});if(B||B===0){A+=B}A+="\n </div>\n\n ";return A}function v(D,C){var A="",B;A+='\n <div class="display-application">\n <span class="display-application-location">';if(B=p.label){B=B.call(D,{hash:{},data:C})}else{B=D.label;B=typeof B===e?B.apply(D):B}A+=d(B)+'</span>\n <span class="display-application-links">\n ';B=p.each.call(D,D.links,{hash:{},inverse:o.noop,fn:o.program(16,u,C),data:C});if(B||B===0){A+=B}A+="\n </span>\n </div>\n ";return A}function u(E,D){var A="",C,B;A+='\n <a target="';if(C=p.target){C=C.call(E,{hash:{},data:D})}else{C=E.target;C=typeof C===e?C.apply(E):C}A+=d(C)+'" href="';if(C=p.href){C=C.call(E,{hash:{},data:D})}else{C=E.href;C=typeof C===e?C.apply(E):C}A+=d(C)+'">';B={hash:{},inverse:o.noop,fn:o.program(17,t,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+="</a>\n ";return A}function t(C,B){var A;if(A=p.text){A=A.call(C,{hash:{},data:B})}else{A=C.text;A=typeof A===e?A.apply(C):A}return d(A)}function s(D,C){var A="",B;A+='\n <pre class="peek">';if(B=p.peek){B=B.call(D,{hash:{},data:C})}else{B=D.peek;B=typeof B===e?B.apply(D):B}if(B||B===0){A+=B}A+="</pre>\n ";return A}q+='<div class="dataset-body">\n ';h=p["if"].call(r,r.body,{hash:{},inverse:o.program(3,m,z),fn:o.program(1,n,z),data:z});if(h||h===0){q+=h}q+="\n</div>";return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-skeleton"]=b(function(f,r,p,k,w){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,f.helpers);w=w||{};var q="",h,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(B,A){var x="",z,y;x+='\n <div class="errormessagesmall">\n ';y={hash:{},inverse:o.noop,fn:o.program(2,m,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+=":\n ";y={hash:{},inverse:o.noop,fn:o.program(4,l,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </div>\n ";return x}function m(y,x){return"There was an error getting the data for this dataset"}function l(z,y){var x;if(x=p.error){x=x.call(z,{hash:{},data:y})}else{x=z.error;x=typeof x===e?x.apply(z):x}return d(x)}function j(A,z){var x="",y;x+="\n ";y=p["if"].call(A,A.purged,{hash:{},inverse:o.program(10,v,z),fn:o.program(7,i,z),data:z});if(y||y===0){x+=y}x+="\n ";return x}function i(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(8,g,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </strong></div>\n\n ";return x}function g(y,x){return"This dataset has been deleted and removed from disk."}function v(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(11,u,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n \n Click <a href="javascript:void(0);" class="dataset-undelete">here</a> to undelete it\n or <a href="javascript:void(0);" class="dataset-purge">here</a> to immediately remove it from disk\n </strong></div>\n ';return x}function u(y,x){return"This dataset has been deleted."}function t(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(14,s,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n Click <a href="javascript:void(0);" class="dataset-unhide">here</a> to unhide it\n </strong></div>\n ';return x}function s(y,x){return"This dataset has been hidden."}q+='<div class="dataset hda">\n <div class="dataset-warnings">\n ';h=p["if"].call(r,r.error,{hash:{},inverse:o.noop,fn:o.program(1,n,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p["if"].call(r,r.deleted,{hash:{},inverse:o.noop,fn:o.program(6,j,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p.unless.call(r,r.visible,{hash:{},inverse:o.noop,fn:o.program(13,t,w),data:w});if(h||h===0){q+=h}q+='\n </div>\n\n <div class="dataset-selector"><span class="fa fa-2x fa-square-o"></span></div>\n <div class="dataset-primary-actions"></div>\n \n <div class="dataset-title-bar clear" tabindex="0">\n <span class="dataset-state-icon state-icon"></span>\n <div class="dataset-title">\n <span class="hda-hid">';if(h=p.hid){h=h.call(r,{hash:{},data:w})}else{h=r.hid;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n <span class="dataset-name">';if(h=p.name){h=h.call(r,{hash:{},data:w})}else{h=r.name;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n </div>\n </div>\n\n <div class="dataset-body"></div>\n</div>';return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel-anon"]=b(function(g,r,p,k,u){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);u=u||{};var q="",i,f,o=this,e="function",c=p.blockHelperMissing,d=this.escapeExpression;function n(z,y){var v="",x,w;v+='\n <div class="history-name" title="';w={hash:{},inverse:o.noop,fn:o.program(2,m,y),data:y};if(x=p.local){x=x.call(z,w)}else{x=z.local;x=typeof x===e?x.apply(z):x}if(!p.local){x=c.call(z,x,w)}if(x||x===0){v+=x}v+='">\n ';if(x=p.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===e?x.apply(z):x}v+=d(x)+"\n </div>\n ";return v}function m(w,v){return"You must be logged in to edit your history name"}function l(y,x){var v="",w;v+='\n <div class="history-size">';if(w=p.nice_size){w=w.call(y,{hash:{},data:x})}else{w=y.nice_size;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function j(y,x){var v="",w;v+='\n \n <div class="';if(w=p.status){w=w.call(y,{hash:{},data:x})}else{w=y.status;w=typeof w===e?w.apply(y):w}v+=d(w)+'message">';if(w=p.message){w=w.call(y,{hash:{},data:x})}else{w=y.message;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function h(w,v){return"You are over your disk quota"}function t(w,v){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function s(w,v){return"Your history is empty. Click 'Get Data' on the left pane to start"}q+='<div class="history-controls">\n <div class="history-search-controls"></div>\n\n <div class="history-title">\n \n ';i=p["if"].call(r,r.name,{hash:{},inverse:o.noop,fn:o.program(1,n,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=p["if"].call(r,r.nice_size,{hash:{},inverse:o.noop,fn:o.program(4,l,u),data:u});if(i||i===0){q+=i}q+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n <div class="message-container">\n ';i=p["if"].call(r,r.message,{hash:{},inverse:o.noop,fn:o.program(6,j,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:o.noop,fn:o.program(8,h,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+=".\n ";f={hash:{},inverse:o.noop,fn:o.program(10,t,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='.\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:o.noop,fn:o.program(12,s,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+="\n </div>";return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(h,s,q,l,y){this.compilerInfo=[4,">= 1.0.0"];q=this.merge(q,h.helpers);y=y||{};var r="",i,f,p=this,e="function",c=q.blockHelperMissing,d=this.escapeExpression;function o(D,C){var z="",B,A;z+='\n <div class="history-name" title="';A={hash:{},inverse:p.noop,fn:p.program(2,n,C),data:C};if(B=q.local){B=B.call(D,A)}else{B=D.local;B=typeof B===e?B.apply(D):B}if(!q.local){B=c.call(D,B,A)}if(B||B===0){z+=B}z+='">\n ';if(B=q.name){B=B.call(D,{hash:{},data:C})}else{B=D.name;B=typeof B===e?B.apply(D):B}z+=d(B)+"\n </div>\n ";return z}function n(A,z){return"Click to rename history"}function m(C,B){var z="",A;z+='\n <div class="history-size">';if(A=q.nice_size){A=A.call(C,{hash:{},data:B})}else{A=C.nice_size;A=typeof A===e?A.apply(C):A}z+=d(A)+"</div>\n ";return z}function k(D,C){var z="",B,A;z+='\n <div class="warningmessagesmall"><strong>\n ';A={hash:{},inverse:p.noop,fn:p.program(7,j,C),data:C};if(B=q.local){B=B.call(D,A)}else{B=D.local;B=typeof B===e?B.apply(D):B}if(!q.local){B=c.call(D,B,A)}if(B||B===0){z+=B}z+="\n </strong></div>\n ";return z}function j(A,z){return"You are currently viewing a deleted history!"}function g(C,B){var z="",A;z+='\n \n <div class="';if(A=q.status){A=A.call(C,{hash:{},data:B})}else{A=C.status;A=typeof A===e?A.apply(C):A}z+=d(A)+'message">';if(A=q.message){A=A.call(C,{hash:{},data:B})}else{A=C.message;A=typeof A===e?A.apply(C):A}z+=d(A)+"</div>\n ";return z}function x(A,z){return"You are over your disk quota"}function w(A,z){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function v(A,z){return"Select all"}function u(A,z){return"For all selected"}function t(A,z){return"Your history is empty. Click 'Get Data' on the left pane to start"}r+='<div class="history-controls">\n <div class="history-search-controls"></div>\n\n <div class="history-title">\n ';i=q["if"].call(s,s.name,{hash:{},inverse:p.noop,fn:p.program(1,o,y),data:y});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=q["if"].call(s,s.nice_size,{hash:{},inverse:p.noop,fn:p.program(4,m,y),data:y});if(i||i===0){r+=i}r+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n ';i=q["if"].call(s,s.deleted,{hash:{},inverse:p.noop,fn:p.program(6,k,y),data:y});if(i||i===0){r+=i}r+='\n\n <div class="message-container">\n ';i=q["if"].call(s,s.message,{hash:{},inverse:p.noop,fn:p.program(9,g,y),data:y});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:p.noop,fn:p.program(11,x,y),data:y};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+=".\n ";f={hash:{},inverse:p.noop,fn:p.program(13,w,y),data:y};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+='.\n </div>\n \n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n <div class="history-dataset-actions">\n <button class="history-select-all-datasets-btn btn btn-default"\n data-mode="select">';f={hash:{},inverse:p.noop,fn:p.program(15,v,y),data:y};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+='</button>\n <button class="history-dataset-action-popup-btn btn btn-default"\n >';f={hash:{},inverse:p.noop,fn:p.program(17,u,y),data:y};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+='...</button>\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:p.noop,fn:p.program(19,t,y),data:y};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+="\n </div>";return r})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-body"]=b(function(g,r,p,k,z){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);z=z||{};var q="",h,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(D,C){var A="",B;A+='\n <div class="dataset-summary">\n ';if(B=p.body){B=B.call(D,{hash:{},data:C})}else{B=D.body;B=typeof B===e?B.apply(D):B}if(B||B===0){A+=B}A+='\n </div>\n <div class="dataset-actions clear">\n <div class="left"></div>\n <div class="right"></div>\n </div>\n\n ';return A}function m(D,C){var A="",B;A+='\n <div class="dataset-summary">\n ';B=p["if"].call(D,D.misc_blurb,{hash:{},inverse:o.noop,fn:o.program(4,l,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.data_type,{hash:{},inverse:o.noop,fn:o.program(6,j,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.metadata_dbkey,{hash:{},inverse:o.noop,fn:o.program(9,f,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.misc_info,{hash:{},inverse:o.noop,fn:o.program(12,x,C),data:C});if(B||B===0){A+=B}A+='\n </div>\n\n <div class="dataset-actions clear">\n <div class="left"></div>\n <div class="right"></div>\n </div>\n\n ';B=p.unless.call(D,D.deleted,{hash:{},inverse:o.noop,fn:o.program(14,w,C),data:C});if(B||B===0){A+=B}A+="\n\n ";return A}function l(D,C){var A="",B;A+='\n <div class="dataset-blurb">\n <span class="value">';if(B=p.misc_blurb){B=B.call(D,{hash:{},data:C})}else{B=D.misc_blurb;B=typeof B===e?B.apply(D):B}A+=d(B)+"</span>\n </div>\n ";return A}function j(E,D){var A="",C,B;A+='\n <div class="dataset-datatype">\n <label class="prompt">';B={hash:{},inverse:o.noop,fn:o.program(7,i,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+='</label>\n <span class="value">';if(C=p.data_type){C=C.call(E,{hash:{},data:D})}else{C=E.data_type;C=typeof C===e?C.apply(E):C}A+=d(C)+"</span>\n </div>\n ";return A}function i(B,A){return"format"}function f(E,D){var A="",C,B;A+='\n <div class="dataset-dbkey">\n <label class="prompt">';B={hash:{},inverse:o.noop,fn:o.program(10,y,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+='</label>\n <span class="value">\n ';if(C=p.metadata_dbkey){C=C.call(E,{hash:{},data:D})}else{C=E.metadata_dbkey;C=typeof C===e?C.apply(E):C}A+=d(C)+"\n </span>\n </div>\n ";return A}function y(B,A){return"database"}function x(D,C){var A="",B;A+='\n <div class="dataset-info">\n <span class="value">';if(B=p.misc_info){B=B.call(D,{hash:{},data:C})}else{B=D.misc_info;B=typeof B===e?B.apply(D):B}A+=d(B)+"</span>\n </div>\n ";return A}function w(D,C){var A="",B;A+='\n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n <div class="dataset-display-applications">\n ';B=p.each.call(D,D.display_apps,{hash:{},inverse:o.noop,fn:o.program(15,v,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p.each.call(D,D.display_types,{hash:{},inverse:o.noop,fn:o.program(15,v,C),data:C});if(B||B===0){A+=B}A+='\n </div>\n\n <div class="dataset-peek">\n ';B=p["if"].call(D,D.peek,{hash:{},inverse:o.noop,fn:o.program(19,s,C),data:C});if(B||B===0){A+=B}A+="\n </div>\n\n ";return A}function v(D,C){var A="",B;A+='\n <div class="display-application">\n <span class="display-application-location">';if(B=p.label){B=B.call(D,{hash:{},data:C})}else{B=D.label;B=typeof B===e?B.apply(D):B}A+=d(B)+'</span>\n <span class="display-application-links">\n ';B=p.each.call(D,D.links,{hash:{},inverse:o.noop,fn:o.program(16,u,C),data:C});if(B||B===0){A+=B}A+="\n </span>\n </div>\n ";return A}function u(E,D){var A="",C,B;A+='\n <a target="';if(C=p.target){C=C.call(E,{hash:{},data:D})}else{C=E.target;C=typeof C===e?C.apply(E):C}A+=d(C)+'" href="';if(C=p.href){C=C.call(E,{hash:{},data:D})}else{C=E.href;C=typeof C===e?C.apply(E):C}A+=d(C)+'">';B={hash:{},inverse:o.noop,fn:o.program(17,t,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+="</a>\n ";return A}function t(C,B){var A;if(A=p.text){A=A.call(C,{hash:{},data:B})}else{A=C.text;A=typeof A===e?A.apply(C):A}return d(A)}function s(D,C){var A="",B;A+='\n <pre class="peek">';if(B=p.peek){B=B.call(D,{hash:{},data:C})}else{B=D.peek;B=typeof B===e?B.apply(D):B}if(B||B===0){A+=B}A+="</pre>\n ";return A}q+='<div class="dataset-body">\n ';h=p["if"].call(r,r.body,{hash:{},inverse:o.program(3,m,z),fn:o.program(1,n,z),data:z});if(h||h===0){q+=h}q+="\n</div>";return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-skeleton"]=b(function(f,r,p,k,w){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,f.helpers);w=w||{};var q="",h,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(B,A){var x="",z,y;x+='\n <div class="errormessagesmall">\n ';y={hash:{},inverse:o.noop,fn:o.program(2,m,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+=":\n ";y={hash:{},inverse:o.noop,fn:o.program(4,l,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </div>\n ";return x}function m(y,x){return"There was an error getting the data for this dataset"}function l(z,y){var x;if(x=p.error){x=x.call(z,{hash:{},data:y})}else{x=z.error;x=typeof x===e?x.apply(z):x}return d(x)}function j(A,z){var x="",y;x+="\n ";y=p["if"].call(A,A.purged,{hash:{},inverse:o.program(10,v,z),fn:o.program(7,i,z),data:z});if(y||y===0){x+=y}x+="\n ";return x}function i(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(8,g,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </strong></div>\n\n ";return x}function g(y,x){return"This dataset has been deleted and removed from disk."}function v(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(11,u,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n \n Click <a href="javascript:void(0);" class="dataset-undelete">here</a> to undelete it\n or <a href="javascript:void(0);" class="dataset-purge">here</a> to immediately remove it from disk\n </strong></div>\n ';return x}function u(y,x){return"This dataset has been deleted."}function t(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(14,s,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n Click <a href="javascript:void(0);" class="dataset-unhide">here</a> to unhide it\n </strong></div>\n ';return x}function s(y,x){return"This dataset has been hidden."}q+='<div class="dataset hda">\n <div class="dataset-warnings">\n ';h=p["if"].call(r,r.error,{hash:{},inverse:o.noop,fn:o.program(1,n,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p["if"].call(r,r.deleted,{hash:{},inverse:o.noop,fn:o.program(6,j,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p.unless.call(r,r.visible,{hash:{},inverse:o.noop,fn:o.program(13,t,w),data:w});if(h||h===0){q+=h}q+='\n </div>\n\n <div class="dataset-selector"><span class="fa fa-2x fa-square-o"></span></div>\n <div class="dataset-primary-actions"></div>\n \n <div class="dataset-title-bar clear" tabindex="0">\n <span class="dataset-state-icon state-icon"></span>\n <div class="dataset-title">\n <span class="hda-hid">';if(h=p.hid){h=h.call(r,{hash:{},data:w})}else{h=r.hid;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n <span class="dataset-name">';if(h=p.name){h=h.call(r,{hash:{},data:w})}else{h=r.name;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n </div>\n </div>\n\n <div class="dataset-body"></div>\n</div>';return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-skeleton"]=b(function(f,r,p,k,w){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,f.helpers);w=w||{};var q="",h,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(B,A){var x="",z,y;x+='\n <div class="errormessagesmall">\n ';y={hash:{},inverse:o.noop,fn:o.program(2,m,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+=":\n ";y={hash:{},inverse:o.noop,fn:o.program(4,l,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </div>\n ";return x}function m(y,x){return"There was an error getting the data for this dataset"}function l(z,y){var x;if(x=p.error){x=x.call(z,{hash:{},data:y})}else{x=z.error;x=typeof x===e?x.apply(z):x}return d(x)}function j(A,z){var x="",y;x+="\n ";y=p["if"].call(A,A.purged,{hash:{},inverse:o.program(10,v,z),fn:o.program(7,i,z),data:z});if(y||y===0){x+=y}x+="\n ";return x}function i(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(8,g,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </strong></div>\n\n ";return x}function g(y,x){return"This dataset has been deleted and removed from disk."}function v(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(11,u,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n \n Click <a href="javascript:void(0);" class="dataset-undelete">here</a> to undelete it\n or <a href="javascript:void(0);" class="dataset-purge">here</a> to immediately remove it from disk\n </strong></div>\n ';return x}function u(y,x){return"This dataset has been deleted."}function t(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(14,s,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n Click <a href="javascript:void(0);" class="dataset-unhide">here</a> to unhide it\n </strong></div>\n ';return x}function s(y,x){return"This dataset has been hidden."}q+='<div class="dataset hda">\n <div class="dataset-warnings">\n ';h=p["if"].call(r,r.error,{hash:{},inverse:o.noop,fn:o.program(1,n,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p["if"].call(r,r.deleted,{hash:{},inverse:o.noop,fn:o.program(6,j,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p.unless.call(r,r.visible,{hash:{},inverse:o.noop,fn:o.program(13,t,w),data:w});if(h||h===0){q+=h}q+='\n </div>\n\n <div class="dataset-selector"><span class="fa fa-2x fa-square-o"></span></div>\n <div class="dataset-primary-actions"></div>\n <div class="dataset-title-bar clear" tabindex="0">\n <span class="dataset-state-icon state-icon"></span>\n <div class="dataset-title">\n <span class="hda-hid">';if(h=p.hid){h=h.call(r,{hash:{},data:w})}else{h=r.hid;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n <span class="dataset-name">';if(h=p.name){h=h.call(r,{hash:{},data:w})}else{h=r.name;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n </div>\n </div>\n\n <div class="dataset-body"></div>\n</div>';return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel-anon"]=b(function(h,r,p,l,t){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,h.helpers);t=t||{};var q="",i,f,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(x,w){var u="",v;u+='\n <div class="history-name">\n ';if(v=p.name){v=v.call(x,{hash:{},data:w})}else{v=x.name;v=typeof v===e?v.apply(x):v}u+=d(v)+"\n </div>\n ";return u}function m(x,w){var u="",v;u+='\n <div class="history-size">';if(v=p.nice_size){v=v.call(x,{hash:{},data:w})}else{v=x.nice_size;v=typeof v===e?v.apply(x):v}u+=d(v)+"</div>\n ";return u}function k(x,w){var u="",v;u+='\n \n <div class="';if(v=p.status){v=v.call(x,{hash:{},data:w})}else{v=x.status;v=typeof v===e?v.apply(x):v}u+=d(v)+'message">';if(v=p.message){v=v.call(x,{hash:{},data:w})}else{v=x.message;v=typeof v===e?v.apply(x):v}u+=d(v)+"</div>\n ";return u}function j(v,u){return"You are over your disk quota"}function g(v,u){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function s(v,u){return"Your history is empty. Click 'Get Data' on the left pane to start"}q+='<div class="history-controls">\n <div class="history-search-controls"></div>\n\n <div class="history-title">\n \n ';i=p["if"].call(r,r.name,{hash:{},inverse:o.noop,fn:o.program(1,n,t),data:t});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=p["if"].call(r,r.nice_size,{hash:{},inverse:o.noop,fn:o.program(3,m,t),data:t});if(i||i===0){q+=i}q+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n <div class="message-container">\n ';i=p["if"].call(r,r.message,{hash:{},inverse:o.noop,fn:o.program(5,k,t),data:t});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:o.noop,fn:o.program(7,j,t),data:t};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+=".\n ";f={hash:{},inverse:o.noop,fn:o.program(9,g,t),data:t};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='.\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:o.noop,fn:o.program(11,s,t),data:t};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+="\n </div>";return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(g,r,p,l,x){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);x=x||{};var q="",i,f,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(B,A){var y="",z;y+='\n <div class="history-name">\n ';if(z=p.name){z=z.call(B,{hash:{},data:A})}else{z=B.name;z=typeof z===e?z.apply(B):z}y+=d(z)+"\n </div>\n ";return y}function m(B,A){var y="",z;y+='\n <div class="history-size">';if(z=p.nice_size){z=z.call(B,{hash:{},data:A})}else{z=B.nice_size;z=typeof z===e?z.apply(B):z}y+=d(z)+"</div>\n ";return y}function k(C,B){var y="",A,z;y+='\n <div class="warningmessagesmall"><strong>\n ';z={hash:{},inverse:o.noop,fn:o.program(6,j,B),data:B};if(A=p.local){A=A.call(C,z)}else{A=C.local;A=typeof A===e?A.apply(C):A}if(!p.local){A=c.call(C,A,z)}if(A||A===0){y+=A}y+="\n </strong></div>\n ";return y}function j(z,y){return"You are currently viewing a deleted history!"}function h(B,A){var y="",z;y+='\n \n <div class="';if(z=p.status){z=z.call(B,{hash:{},data:A})}else{z=B.status;z=typeof z===e?z.apply(B):z}y+=d(z)+'message">';if(z=p.message){z=z.call(B,{hash:{},data:A})}else{z=B.message;z=typeof z===e?z.apply(B):z}y+=d(z)+"</div>\n ";return y}function w(z,y){return"You are over your disk quota"}function v(z,y){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function u(z,y){return"Select all"}function t(z,y){return"For all selected"}function s(z,y){return"Your history is empty. Click 'Get Data' on the left pane to start"}q+='<div class="history-controls">\n <div class="history-search-controls"></div>\n\n <div class="history-title">\n ';i=p["if"].call(r,r.name,{hash:{},inverse:o.noop,fn:o.program(1,n,x),data:x});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=p["if"].call(r,r.nice_size,{hash:{},inverse:o.noop,fn:o.program(3,m,x),data:x});if(i||i===0){q+=i}q+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n ';i=p["if"].call(r,r.deleted,{hash:{},inverse:o.noop,fn:o.program(5,k,x),data:x});if(i||i===0){q+=i}q+='\n\n <div class="message-container">\n ';i=p["if"].call(r,r.message,{hash:{},inverse:o.noop,fn:o.program(8,h,x),data:x});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:o.noop,fn:o.program(10,w,x),data:x};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+=".\n ";f={hash:{},inverse:o.noop,fn:o.program(12,v,x),data:x};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='.\n </div>\n \n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n <div class="history-dataset-actions">\n <button class="history-select-all-datasets-btn btn btn-default"\n data-mode="select">';f={hash:{},inverse:o.noop,fn:o.program(14,u,x),data:x};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='</button>\n <button class="history-dataset-action-popup-btn btn btn-default"\n >';f={hash:{},inverse:o.noop,fn:o.program(16,t,x),data:x};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='...</button>\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:o.noop,fn:o.program(18,s,x),data:x};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+="\n </div>";return q})})();
\ No newline at end of file
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/scripts/packed/templates/compiled/template-history-historyPanel-anon.js
--- a/static/scripts/packed/templates/compiled/template-history-historyPanel-anon.js
+++ b/static/scripts/packed/templates/compiled/template-history-historyPanel-anon.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel-anon"]=b(function(g,r,p,k,u){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);u=u||{};var q="",i,f,o=this,e="function",c=p.blockHelperMissing,d=this.escapeExpression;function n(z,y){var v="",x,w;v+='\n <div class="history-name" title="';w={hash:{},inverse:o.noop,fn:o.program(2,m,y),data:y};if(x=p.local){x=x.call(z,w)}else{x=z.local;x=typeof x===e?x.apply(z):x}if(!p.local){x=c.call(z,x,w)}if(x||x===0){v+=x}v+='">\n ';if(x=p.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===e?x.apply(z):x}v+=d(x)+"\n </div>\n ";return v}function m(w,v){return"You must be logged in to edit your history name"}function l(y,x){var v="",w;v+='\n <div class="history-size">';if(w=p.nice_size){w=w.call(y,{hash:{},data:x})}else{w=y.nice_size;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function j(y,x){var v="",w;v+='\n \n <div class="';if(w=p.status){w=w.call(y,{hash:{},data:x})}else{w=y.status;w=typeof w===e?w.apply(y):w}v+=d(w)+'message">';if(w=p.message){w=w.call(y,{hash:{},data:x})}else{w=y.message;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function h(w,v){return"You are over your disk quota"}function t(w,v){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function s(w,v){return"Your history is empty. Click 'Get Data' on the left pane to start"}q+='<div class="history-controls">\n <div class="history-search-controls"></div>\n\n <div class="history-title">\n \n ';i=p["if"].call(r,r.name,{hash:{},inverse:o.noop,fn:o.program(1,n,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=p["if"].call(r,r.nice_size,{hash:{},inverse:o.noop,fn:o.program(4,l,u),data:u});if(i||i===0){q+=i}q+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n <div class="message-container">\n ';i=p["if"].call(r,r.message,{hash:{},inverse:o.noop,fn:o.program(6,j,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:o.noop,fn:o.program(8,h,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+=".\n ";f={hash:{},inverse:o.noop,fn:o.program(10,t,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='.\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:o.noop,fn:o.program(12,s,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+="\n </div>";return q})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel-anon"]=b(function(h,r,p,l,t){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,h.helpers);t=t||{};var q="",i,f,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(x,w){var u="",v;u+='\n <div class="history-name">\n ';if(v=p.name){v=v.call(x,{hash:{},data:w})}else{v=x.name;v=typeof v===e?v.apply(x):v}u+=d(v)+"\n </div>\n ";return u}function m(x,w){var u="",v;u+='\n <div class="history-size">';if(v=p.nice_size){v=v.call(x,{hash:{},data:w})}else{v=x.nice_size;v=typeof v===e?v.apply(x):v}u+=d(v)+"</div>\n ";return u}function k(x,w){var u="",v;u+='\n \n <div class="';if(v=p.status){v=v.call(x,{hash:{},data:w})}else{v=x.status;v=typeof v===e?v.apply(x):v}u+=d(v)+'message">';if(v=p.message){v=v.call(x,{hash:{},data:w})}else{v=x.message;v=typeof v===e?v.apply(x):v}u+=d(v)+"</div>\n ";return u}function j(v,u){return"You are over your disk quota"}function g(v,u){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function s(v,u){return"Your history is empty. Click 'Get Data' on the left pane to start"}q+='<div class="history-controls">\n <div class="history-search-controls"></div>\n\n <div class="history-title">\n \n ';i=p["if"].call(r,r.name,{hash:{},inverse:o.noop,fn:o.program(1,n,t),data:t});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=p["if"].call(r,r.nice_size,{hash:{},inverse:o.noop,fn:o.program(3,m,t),data:t});if(i||i===0){q+=i}q+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n <div class="message-container">\n ';i=p["if"].call(r,r.message,{hash:{},inverse:o.noop,fn:o.program(5,k,t),data:t});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:o.noop,fn:o.program(7,j,t),data:t};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+=".\n ";f={hash:{},inverse:o.noop,fn:o.program(9,g,t),data:t};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='.\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:o.noop,fn:o.program(11,s,t),data:t};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+="\n </div>";return q})})();
\ No newline at end of file
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/scripts/packed/templates/compiled/template-history-historyPanel.js
--- a/static/scripts/packed/templates/compiled/template-history-historyPanel.js
+++ b/static/scripts/packed/templates/compiled/template-history-historyPanel.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(h,s,q,l,y){this.compilerInfo=[4,">= 1.0.0"];q=this.merge(q,h.helpers);y=y||{};var r="",i,f,p=this,e="function",c=q.blockHelperMissing,d=this.escapeExpression;function o(D,C){var z="",B,A;z+='\n <div class="history-name" title="';A={hash:{},inverse:p.noop,fn:p.program(2,n,C),data:C};if(B=q.local){B=B.call(D,A)}else{B=D.local;B=typeof B===e?B.apply(D):B}if(!q.local){B=c.call(D,B,A)}if(B||B===0){z+=B}z+='">\n ';if(B=q.name){B=B.call(D,{hash:{},data:C})}else{B=D.name;B=typeof B===e?B.apply(D):B}z+=d(B)+"\n </div>\n ";return z}function n(A,z){return"Click to rename history"}function m(C,B){var z="",A;z+='\n <div class="history-size">';if(A=q.nice_size){A=A.call(C,{hash:{},data:B})}else{A=C.nice_size;A=typeof A===e?A.apply(C):A}z+=d(A)+"</div>\n ";return z}function k(D,C){var z="",B,A;z+='\n <div class="warningmessagesmall"><strong>\n ';A={hash:{},inverse:p.noop,fn:p.program(7,j,C),data:C};if(B=q.local){B=B.call(D,A)}else{B=D.local;B=typeof B===e?B.apply(D):B}if(!q.local){B=c.call(D,B,A)}if(B||B===0){z+=B}z+="\n </strong></div>\n ";return z}function j(A,z){return"You are currently viewing a deleted history!"}function g(C,B){var z="",A;z+='\n \n <div class="';if(A=q.status){A=A.call(C,{hash:{},data:B})}else{A=C.status;A=typeof A===e?A.apply(C):A}z+=d(A)+'message">';if(A=q.message){A=A.call(C,{hash:{},data:B})}else{A=C.message;A=typeof A===e?A.apply(C):A}z+=d(A)+"</div>\n ";return z}function x(A,z){return"You are over your disk quota"}function w(A,z){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function v(A,z){return"Select all"}function u(A,z){return"For all selected"}function t(A,z){return"Your history is empty. Click 'Get Data' on the left pane to start"}r+='<div class="history-controls">\n <div class="history-search-controls"></div>\n\n <div class="history-title">\n ';i=q["if"].call(s,s.name,{hash:{},inverse:p.noop,fn:p.program(1,o,y),data:y});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=q["if"].call(s,s.nice_size,{hash:{},inverse:p.noop,fn:p.program(4,m,y),data:y});if(i||i===0){r+=i}r+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n ';i=q["if"].call(s,s.deleted,{hash:{},inverse:p.noop,fn:p.program(6,k,y),data:y});if(i||i===0){r+=i}r+='\n\n <div class="message-container">\n ';i=q["if"].call(s,s.message,{hash:{},inverse:p.noop,fn:p.program(9,g,y),data:y});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:p.noop,fn:p.program(11,x,y),data:y};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+=".\n ";f={hash:{},inverse:p.noop,fn:p.program(13,w,y),data:y};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+='.\n </div>\n \n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n <div class="history-dataset-actions">\n <button class="history-select-all-datasets-btn btn btn-default"\n data-mode="select">';f={hash:{},inverse:p.noop,fn:p.program(15,v,y),data:y};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+='</button>\n <button class="history-dataset-action-popup-btn btn btn-default"\n >';f={hash:{},inverse:p.noop,fn:p.program(17,u,y),data:y};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+='...</button>\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:p.noop,fn:p.program(19,t,y),data:y};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+="\n </div>";return r})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(g,r,p,l,x){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);x=x||{};var q="",i,f,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(B,A){var y="",z;y+='\n <div class="history-name">\n ';if(z=p.name){z=z.call(B,{hash:{},data:A})}else{z=B.name;z=typeof z===e?z.apply(B):z}y+=d(z)+"\n </div>\n ";return y}function m(B,A){var y="",z;y+='\n <div class="history-size">';if(z=p.nice_size){z=z.call(B,{hash:{},data:A})}else{z=B.nice_size;z=typeof z===e?z.apply(B):z}y+=d(z)+"</div>\n ";return y}function k(C,B){var y="",A,z;y+='\n <div class="warningmessagesmall"><strong>\n ';z={hash:{},inverse:o.noop,fn:o.program(6,j,B),data:B};if(A=p.local){A=A.call(C,z)}else{A=C.local;A=typeof A===e?A.apply(C):A}if(!p.local){A=c.call(C,A,z)}if(A||A===0){y+=A}y+="\n </strong></div>\n ";return y}function j(z,y){return"You are currently viewing a deleted history!"}function h(B,A){var y="",z;y+='\n \n <div class="';if(z=p.status){z=z.call(B,{hash:{},data:A})}else{z=B.status;z=typeof z===e?z.apply(B):z}y+=d(z)+'message">';if(z=p.message){z=z.call(B,{hash:{},data:A})}else{z=B.message;z=typeof z===e?z.apply(B):z}y+=d(z)+"</div>\n ";return y}function w(z,y){return"You are over your disk quota"}function v(z,y){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function u(z,y){return"Select all"}function t(z,y){return"For all selected"}function s(z,y){return"Your history is empty. Click 'Get Data' on the left pane to start"}q+='<div class="history-controls">\n <div class="history-search-controls"></div>\n\n <div class="history-title">\n ';i=p["if"].call(r,r.name,{hash:{},inverse:o.noop,fn:o.program(1,n,x),data:x});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=p["if"].call(r,r.nice_size,{hash:{},inverse:o.noop,fn:o.program(3,m,x),data:x});if(i||i===0){q+=i}q+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n ';i=p["if"].call(r,r.deleted,{hash:{},inverse:o.noop,fn:o.program(5,k,x),data:x});if(i||i===0){q+=i}q+='\n\n <div class="message-container">\n ';i=p["if"].call(r,r.message,{hash:{},inverse:o.noop,fn:o.program(8,h,x),data:x});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:o.noop,fn:o.program(10,w,x),data:x};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+=".\n ";f={hash:{},inverse:o.noop,fn:o.program(12,v,x),data:x};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='.\n </div>\n \n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n <div class="history-dataset-actions">\n <button class="history-select-all-datasets-btn btn btn-default"\n data-mode="select">';f={hash:{},inverse:o.noop,fn:o.program(14,u,x),data:x};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='</button>\n <button class="history-dataset-action-popup-btn btn btn-default"\n >';f={hash:{},inverse:o.noop,fn:o.program(16,t,x),data:x};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='...</button>\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:o.noop,fn:o.program(18,s,x),data:x};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+="\n </div>";return q})})();
\ No newline at end of file
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/scripts/templates/compiled/history-templates.js
--- a/static/scripts/templates/compiled/history-templates.js
+++ b/static/scripts/templates/compiled/history-templates.js
@@ -305,34 +305,148 @@
});
})();(function() {
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
-templates['template-history-historyPanel-anon'] = template(function (Handlebars,depth0,helpers,partials,data) {
+templates['template-hda-skeleton'] = template(function (Handlebars,depth0,helpers,partials,data) {
this.compilerInfo = [4,'>= 1.0.0'];
helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
- var buffer = "", stack1, options, self=this, functionType="function", blockHelperMissing=helpers.blockHelperMissing, escapeExpression=this.escapeExpression;
+ var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing;
function program1(depth0,data) {
var buffer = "", stack1, options;
- buffer += "\n <div class=\"history-name\" title=\"";
+ buffer += "\n <div class=\"errormessagesmall\">\n ";
options = {hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\">\n ";
+ buffer += ":\n ";
+ options = {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n </div>\n ";
+ return buffer;
+ }
+function program2(depth0,data) {
+
+
+ return "There was an error getting the data for this dataset";
+ }
+
+function program4(depth0,data) {
+
+ var stack1;
+ if (stack1 = helpers.error) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.error; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ return escapeExpression(stack1);
+ }
+
+function program6(depth0,data) {
+
+ var buffer = "", stack1;
+ buffer += "\n ";
+ stack1 = helpers['if'].call(depth0, depth0.purged, {hash:{},inverse:self.program(10, program10, data),fn:self.program(7, program7, data),data:data});
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n ";
+ return buffer;
+ }
+function program7(depth0,data) {
+
+ var buffer = "", stack1, options;
+ buffer += "\n <div class=\"warningmessagesmall\"><strong>\n ";
+ options = {hash:{},inverse:self.noop,fn:self.program(8, program8, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n </strong></div>\n\n ";
+ return buffer;
+ }
+function program8(depth0,data) {
+
+
+ return "This dataset has been deleted and removed from disk.";
+ }
+
+function program10(depth0,data) {
+
+ var buffer = "", stack1, options;
+ buffer += "\n <div class=\"warningmessagesmall\"><strong>\n ";
+ options = {hash:{},inverse:self.noop,fn:self.program(11, program11, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n "
+ + "\n "
+ + "\n Click <a href=\"javascript:void(0);\" class=\"dataset-undelete\">here</a> to undelete it\n or <a href=\"javascript:void(0);\" class=\"dataset-purge\">here</a> to immediately remove it from disk\n </strong></div>\n ";
+ return buffer;
+ }
+function program11(depth0,data) {
+
+
+ return "This dataset has been deleted.";
+ }
+
+function program13(depth0,data) {
+
+ var buffer = "", stack1, options;
+ buffer += "\n <div class=\"warningmessagesmall\"><strong>\n ";
+ options = {hash:{},inverse:self.noop,fn:self.program(14, program14, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n "
+ + "\n Click <a href=\"javascript:void(0);\" class=\"dataset-unhide\">here</a> to unhide it\n </strong></div>\n ";
+ return buffer;
+ }
+function program14(depth0,data) {
+
+
+ return "This dataset has been hidden.";
+ }
+
+ buffer += "<div class=\"dataset hda\">\n <div class=\"dataset-warnings\">\n ";
+ stack1 = helpers['if'].call(depth0, depth0.error, {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n\n ";
+ stack1 = helpers['if'].call(depth0, depth0.deleted, {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n\n ";
+ stack1 = helpers.unless.call(depth0, depth0.visible, {hash:{},inverse:self.noop,fn:self.program(13, program13, data),data:data});
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n </div>\n\n <div class=\"dataset-selector\"><span class=\"fa fa-2x fa-square-o\"></span></div>\n <div class=\"dataset-primary-actions\"></div>\n <div class=\"dataset-title-bar clear\" tabindex=\"0\">\n <span class=\"dataset-state-icon state-icon\"></span>\n <div class=\"dataset-title\">\n <span class=\"hda-hid\">";
+ if (stack1 = helpers.hid) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.hid; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "</span>\n <span class=\"dataset-name\">";
+ if (stack1 = helpers.name) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.name; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "</span>\n </div>\n </div>\n\n <div class=\"dataset-body\"></div>\n</div>";
+ return buffer;
+ });
+})();(function() {
+ var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
+templates['template-history-historyPanel-anon'] = template(function (Handlebars,depth0,helpers,partials,data) {
+ this.compilerInfo = [4,'>= 1.0.0'];
+helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
+ var buffer = "", stack1, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing;
+
+function program1(depth0,data) {
+
+ var buffer = "", stack1;
+ buffer += "\n <div class=\"history-name\">\n ";
if (stack1 = helpers.name) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
else { stack1 = depth0.name; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
buffer += escapeExpression(stack1)
+ "\n </div>\n ";
return buffer;
}
-function program2(depth0,data) {
-
-
- return "You must be logged in to edit your history name";
- }
-function program4(depth0,data) {
+function program3(depth0,data) {
var buffer = "", stack1;
buffer += "\n <div class=\"history-size\">";
@@ -343,7 +457,7 @@
return buffer;
}
-function program6(depth0,data) {
+function program5(depth0,data) {
var buffer = "", stack1;
buffer += "\n "
@@ -359,19 +473,19 @@
return buffer;
}
-function program8(depth0,data) {
+function program7(depth0,data) {
return "You are over your disk quota";
}
-function program10(depth0,data) {
+function program9(depth0,data) {
return "Tool execution is on hold until your disk usage drops below your allocated quota";
}
-function program12(depth0,data) {
+function program11(depth0,data) {
return "Your history is empty. Click 'Get Data' on the left pane to start";
@@ -382,19 +496,19 @@
stack1 = helpers['if'].call(depth0, depth0.name, {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n </div>\n\n <div class=\"history-subtitle clear\">\n ";
- stack1 = helpers['if'].call(depth0, depth0.nice_size, {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data});
+ stack1 = helpers['if'].call(depth0, depth0.nice_size, {hash:{},inverse:self.noop,fn:self.program(3, program3, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n <div class=\"history-secondary-actions\"></div>\n </div>\n\n <div class=\"message-container\">\n ";
- stack1 = helpers['if'].call(depth0, depth0.message, {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
+ stack1 = helpers['if'].call(depth0, depth0.message, {hash:{},inverse:self.noop,fn:self.program(5, program5, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n </div>\n\n <div class=\"quota-message errormessage\">\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(8, program8, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(7, program7, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += ".\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(10, program10, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(9, program9, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
@@ -402,7 +516,7 @@
buffer += ".\n </div>\n\n </div>"
+ "\n\n "
+ "\n <div class=\"datasets-list\"></div>\n\n <div class=\"empty-history-message infomessagesmall\">\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(12, program12, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(11, program11, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
@@ -415,31 +529,20 @@
templates['template-history-historyPanel'] = template(function (Handlebars,depth0,helpers,partials,data) {
this.compilerInfo = [4,'>= 1.0.0'];
helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
- var buffer = "", stack1, options, self=this, functionType="function", blockHelperMissing=helpers.blockHelperMissing, escapeExpression=this.escapeExpression;
+ var buffer = "", stack1, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing;
function program1(depth0,data) {
- var buffer = "", stack1, options;
- buffer += "\n <div class=\"history-name\" title=\"";
- options = {hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data};
- if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
- else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
- if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
- if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\">\n ";
+ var buffer = "", stack1;
+ buffer += "\n <div class=\"history-name\">\n ";
if (stack1 = helpers.name) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
else { stack1 = depth0.name; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
buffer += escapeExpression(stack1)
+ "\n </div>\n ";
return buffer;
}
-function program2(depth0,data) {
-
-
- return "Click to rename history";
- }
-function program4(depth0,data) {
+function program3(depth0,data) {
var buffer = "", stack1;
buffer += "\n <div class=\"history-size\">";
@@ -450,11 +553,11 @@
return buffer;
}
-function program6(depth0,data) {
+function program5(depth0,data) {
var buffer = "", stack1, options;
buffer += "\n <div class=\"warningmessagesmall\"><strong>\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(7, program7, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
@@ -462,13 +565,13 @@
buffer += "\n </strong></div>\n ";
return buffer;
}
-function program7(depth0,data) {
+function program6(depth0,data) {
return "You are currently viewing a deleted history!";
}
-function program9(depth0,data) {
+function program8(depth0,data) {
var buffer = "", stack1;
buffer += "\n "
@@ -484,31 +587,31 @@
return buffer;
}
-function program11(depth0,data) {
+function program10(depth0,data) {
return "You are over your disk quota";
}
-function program13(depth0,data) {
+function program12(depth0,data) {
return "Tool execution is on hold until your disk usage drops below your allocated quota";
}
-function program15(depth0,data) {
+function program14(depth0,data) {
return "Select all";
}
-function program17(depth0,data) {
+function program16(depth0,data) {
return "For all selected";
}
-function program19(depth0,data) {
+function program18(depth0,data) {
return "Your history is empty. Click 'Get Data' on the left pane to start";
@@ -518,34 +621,34 @@
stack1 = helpers['if'].call(depth0, depth0.name, {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n </div>\n\n <div class=\"history-subtitle clear\">\n ";
- stack1 = helpers['if'].call(depth0, depth0.nice_size, {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data});
+ stack1 = helpers['if'].call(depth0, depth0.nice_size, {hash:{},inverse:self.noop,fn:self.program(3, program3, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n <div class=\"history-secondary-actions\"></div>\n </div>\n\n ";
- stack1 = helpers['if'].call(depth0, depth0.deleted, {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
+ stack1 = helpers['if'].call(depth0, depth0.deleted, {hash:{},inverse:self.noop,fn:self.program(5, program5, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n <div class=\"message-container\">\n ";
- stack1 = helpers['if'].call(depth0, depth0.message, {hash:{},inverse:self.noop,fn:self.program(9, program9, data),data:data});
+ stack1 = helpers['if'].call(depth0, depth0.message, {hash:{},inverse:self.noop,fn:self.program(8, program8, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n </div>\n\n <div class=\"quota-message errormessage\">\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(11, program11, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(10, program10, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += ".\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(13, program13, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(12, program12, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += ".\n </div>\n \n <div class=\"tags-display\"></div>\n <div class=\"annotation-display\"></div>\n\n <div class=\"history-dataset-actions\">\n <button class=\"history-select-all-datasets-btn btn btn-default\"\n data-mode=\"select\">";
- options = {hash:{},inverse:self.noop,fn:self.program(15, program15, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(14, program14, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "</button>\n <button class=\"history-dataset-action-popup-btn btn btn-default\"\n >";
- options = {hash:{},inverse:self.noop,fn:self.program(17, program17, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(16, program16, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
@@ -553,7 +656,7 @@
buffer += "...</button>\n </div>\n\n </div>"
+ "\n\n "
+ "\n <div class=\"datasets-list\"></div>\n\n <div class=\"empty-history-message infomessagesmall\">\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(19, program19, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(18, program18, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/scripts/templates/compiled/template-history-historyPanel-anon.js
--- a/static/scripts/templates/compiled/template-history-historyPanel-anon.js
+++ b/static/scripts/templates/compiled/template-history-historyPanel-anon.js
@@ -3,31 +3,20 @@
templates['template-history-historyPanel-anon'] = template(function (Handlebars,depth0,helpers,partials,data) {
this.compilerInfo = [4,'>= 1.0.0'];
helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
- var buffer = "", stack1, options, self=this, functionType="function", blockHelperMissing=helpers.blockHelperMissing, escapeExpression=this.escapeExpression;
+ var buffer = "", stack1, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing;
function program1(depth0,data) {
- var buffer = "", stack1, options;
- buffer += "\n <div class=\"history-name\" title=\"";
- options = {hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data};
- if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
- else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
- if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
- if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\">\n ";
+ var buffer = "", stack1;
+ buffer += "\n <div class=\"history-name\">\n ";
if (stack1 = helpers.name) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
else { stack1 = depth0.name; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
buffer += escapeExpression(stack1)
+ "\n </div>\n ";
return buffer;
}
-function program2(depth0,data) {
-
-
- return "You must be logged in to edit your history name";
- }
-function program4(depth0,data) {
+function program3(depth0,data) {
var buffer = "", stack1;
buffer += "\n <div class=\"history-size\">";
@@ -38,7 +27,7 @@
return buffer;
}
-function program6(depth0,data) {
+function program5(depth0,data) {
var buffer = "", stack1;
buffer += "\n "
@@ -54,19 +43,19 @@
return buffer;
}
-function program8(depth0,data) {
+function program7(depth0,data) {
return "You are over your disk quota";
}
-function program10(depth0,data) {
+function program9(depth0,data) {
return "Tool execution is on hold until your disk usage drops below your allocated quota";
}
-function program12(depth0,data) {
+function program11(depth0,data) {
return "Your history is empty. Click 'Get Data' on the left pane to start";
@@ -77,19 +66,19 @@
stack1 = helpers['if'].call(depth0, depth0.name, {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n </div>\n\n <div class=\"history-subtitle clear\">\n ";
- stack1 = helpers['if'].call(depth0, depth0.nice_size, {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data});
+ stack1 = helpers['if'].call(depth0, depth0.nice_size, {hash:{},inverse:self.noop,fn:self.program(3, program3, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n <div class=\"history-secondary-actions\"></div>\n </div>\n\n <div class=\"message-container\">\n ";
- stack1 = helpers['if'].call(depth0, depth0.message, {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
+ stack1 = helpers['if'].call(depth0, depth0.message, {hash:{},inverse:self.noop,fn:self.program(5, program5, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n </div>\n\n <div class=\"quota-message errormessage\">\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(8, program8, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(7, program7, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += ".\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(10, program10, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(9, program9, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
@@ -97,7 +86,7 @@
buffer += ".\n </div>\n\n </div>"
+ "\n\n "
+ "\n <div class=\"datasets-list\"></div>\n\n <div class=\"empty-history-message infomessagesmall\">\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(12, program12, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(11, program11, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/scripts/templates/compiled/template-history-historyPanel.js
--- a/static/scripts/templates/compiled/template-history-historyPanel.js
+++ b/static/scripts/templates/compiled/template-history-historyPanel.js
@@ -3,31 +3,20 @@
templates['template-history-historyPanel'] = template(function (Handlebars,depth0,helpers,partials,data) {
this.compilerInfo = [4,'>= 1.0.0'];
helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
- var buffer = "", stack1, options, self=this, functionType="function", blockHelperMissing=helpers.blockHelperMissing, escapeExpression=this.escapeExpression;
+ var buffer = "", stack1, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing;
function program1(depth0,data) {
- var buffer = "", stack1, options;
- buffer += "\n <div class=\"history-name\" title=\"";
- options = {hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data};
- if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
- else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
- if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
- if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\">\n ";
+ var buffer = "", stack1;
+ buffer += "\n <div class=\"history-name\">\n ";
if (stack1 = helpers.name) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
else { stack1 = depth0.name; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
buffer += escapeExpression(stack1)
+ "\n </div>\n ";
return buffer;
}
-function program2(depth0,data) {
-
-
- return "Click to rename history";
- }
-function program4(depth0,data) {
+function program3(depth0,data) {
var buffer = "", stack1;
buffer += "\n <div class=\"history-size\">";
@@ -38,11 +27,11 @@
return buffer;
}
-function program6(depth0,data) {
+function program5(depth0,data) {
var buffer = "", stack1, options;
buffer += "\n <div class=\"warningmessagesmall\"><strong>\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(7, program7, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
@@ -50,13 +39,13 @@
buffer += "\n </strong></div>\n ";
return buffer;
}
-function program7(depth0,data) {
+function program6(depth0,data) {
return "You are currently viewing a deleted history!";
}
-function program9(depth0,data) {
+function program8(depth0,data) {
var buffer = "", stack1;
buffer += "\n "
@@ -72,31 +61,31 @@
return buffer;
}
-function program11(depth0,data) {
+function program10(depth0,data) {
return "You are over your disk quota";
}
-function program13(depth0,data) {
+function program12(depth0,data) {
return "Tool execution is on hold until your disk usage drops below your allocated quota";
}
-function program15(depth0,data) {
+function program14(depth0,data) {
return "Select all";
}
-function program17(depth0,data) {
+function program16(depth0,data) {
return "For all selected";
}
-function program19(depth0,data) {
+function program18(depth0,data) {
return "Your history is empty. Click 'Get Data' on the left pane to start";
@@ -106,34 +95,34 @@
stack1 = helpers['if'].call(depth0, depth0.name, {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n </div>\n\n <div class=\"history-subtitle clear\">\n ";
- stack1 = helpers['if'].call(depth0, depth0.nice_size, {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data});
+ stack1 = helpers['if'].call(depth0, depth0.nice_size, {hash:{},inverse:self.noop,fn:self.program(3, program3, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n <div class=\"history-secondary-actions\"></div>\n </div>\n\n ";
- stack1 = helpers['if'].call(depth0, depth0.deleted, {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
+ stack1 = helpers['if'].call(depth0, depth0.deleted, {hash:{},inverse:self.noop,fn:self.program(5, program5, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n <div class=\"message-container\">\n ";
- stack1 = helpers['if'].call(depth0, depth0.message, {hash:{},inverse:self.noop,fn:self.program(9, program9, data),data:data});
+ stack1 = helpers['if'].call(depth0, depth0.message, {hash:{},inverse:self.noop,fn:self.program(8, program8, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n </div>\n\n <div class=\"quota-message errormessage\">\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(11, program11, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(10, program10, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += ".\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(13, program13, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(12, program12, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += ".\n </div>\n \n <div class=\"tags-display\"></div>\n <div class=\"annotation-display\"></div>\n\n <div class=\"history-dataset-actions\">\n <button class=\"history-select-all-datasets-btn btn btn-default\"\n data-mode=\"select\">";
- options = {hash:{},inverse:self.noop,fn:self.program(15, program15, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(14, program14, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "</button>\n <button class=\"history-dataset-action-popup-btn btn btn-default\"\n >";
- options = {hash:{},inverse:self.noop,fn:self.program(17, program17, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(16, program16, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
@@ -141,7 +130,7 @@
buffer += "...</button>\n </div>\n\n </div>"
+ "\n\n "
+ "\n <div class=\"datasets-list\"></div>\n\n <div class=\"empty-history-message infomessagesmall\">\n ";
- options = {hash:{},inverse:self.noop,fn:self.program(19, program19, data),data:data};
+ options = {hash:{},inverse:self.noop,fn:self.program(18, program18, data),data:data};
if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/scripts/templates/history-templates.html
--- a/static/scripts/templates/history-templates.html
+++ b/static/scripts/templates/history-templates.html
@@ -6,7 +6,7 @@
<div class="history-title">
{{#if name }}
- <div class="history-name" title="{{#local}}Click to rename history{{/local}}">
+ <div class="history-name">
{{name}}
</div>
{{/if}}
@@ -68,7 +68,7 @@
<div class="history-title">
{{! wouldn't this always be 'unnamed history'? }}
{{#if name }}
- <div class="history-name" title="{{#local}}You must be logged in to edit your history name{{/local}}">
+ <div class="history-name">
{{name}}
</div>
{{/if}}
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1511,7 +1511,7 @@
.icon-btn:hover{background-color:white;color:maroon}
.icon-btn.disabled{background-color:transparent;color:rgba(0,0,0,0.05)}
.search-input .search-query{width:100%;padding-right:24px}
-.search-input .search-clear,.search-input .search-loading{position:absolute;right:15px;top:10px;font-size:1.4em;line-height:23px;color:grey}
+.search-input .search-clear,.search-input .search-loading{position:relative;float:right;left:-4px;top:-23px;font-size:1.4em;line-height:23px;color:grey}
.search-input .search-clear:hover{color:#303030}
#history-refresh-button,#history-options-button{display:inline-block;height:20px;width:20px;text-align:center;line-height:17px;font-size:1.2em;padding:0px}
.history-panel [class$="messagesmall"]{margin:0px}
@@ -1522,7 +1522,7 @@
.history-panel .history-controls{margin:10px;padding:0px}.history-panel .history-controls .history-search-controls{display:none;padding:0px 0px 8px 0px}
.history-panel .history-controls .history-title{margin-bottom:4px}
.history-panel .history-controls .history-name{word-wrap:break-word;font-weight:bold}
-.history-panel .history-controls .history-title input{font-weight:bold;width:100%;margin:-2px 0 -2px -4px}
+.history-panel .history-controls .history-title input{width:100%;margin:-2px 0 -2px -4px;font-weight:bold}
.history-panel .history-controls .history-subtitle{margin-bottom:8px}
.history-panel .history-controls .history-size{float:left}
.history-panel .history-controls .history-secondary-actions{float:right}.history-panel .history-controls .history-secondary-actions .icon-btn{margin-left:2px}
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 static/style/src/less/history.less
--- a/static/style/src/less/history.less
+++ b/static/style/src/less/history.less
@@ -68,9 +68,10 @@
.search-clear,
.search-loading {
// it places the icons on the right of the bar (and puts the lotion on its skin)
- position : absolute;
- right : 15px;
- top : 10px;
+ position : relative;
+ float : right;
+ left : -4px;
+ top : -23px;
font-size : 1.4em;
line-height : 23px;
color : grey;
@@ -134,10 +135,10 @@
font-weight: bold;
}
.history-title input {
- font-weight: bold;
width: 100%;
// keep the text in position
margin: -2px 0px -2px -4px;
+ font-weight: bold;
}
.history-subtitle {
@@ -312,13 +313,6 @@
.dataset-padding;
.dataset-state-icon {
- //display: inline-block;
- //vertical-align: middle;
- //line-height: 16px;
- //width: 16px;
- //height: 16px;
- //background-position: 0 1px;
- //background-repeat: no-repeat;
}
.dataset-title {
display: inline;
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 templates/webapps/galaxy/history/history_panel.mako
--- a/templates/webapps/galaxy/history/history_panel.mako
+++ b/templates/webapps/galaxy/history/history_panel.mako
@@ -2,10 +2,12 @@
## ----------------------------------------------------------------------------
<%def name="current_history_panel( selector_to_attach_to=None, show_deleted=None, show_hidden=None, hda_id=None )">
+
+${history_panel_javascripts()}
+
<script type="text/javascript">
-function onModuleReady( historyPanel ){
+onhistoryready.done( function( historyPanel ){
// attach a panel to selector_to_attach_to and load the current history/hdas over the api
-
var currPanel = new historyPanel.HistoryPanel({
// is page sending in show settings? if so override history's
show_deleted : ${ 'true' if show_deleted == True else ( 'null' if show_deleted == None else 'false' ) },
@@ -22,43 +24,45 @@
}
});
Galaxy.currHistoryPanel = currPanel;
-}
+});
</script>
-
-${history_panel_javascripts()}
</%def>
## ----------------------------------------------------------------------------
<%def name="history_panel( history_id, selector_to_attach_to=None, \
show_deleted=None, show_hidden=None, hda_id=None )">
+
+${history_panel_javascripts()}
+
<script type="text/javascript">
-function onModuleReady( historyPanel ){
+onhistoryready.done( function( historyPanel ){
// attach a panel to selector_to_attach_to and load the history/hdas with the given history_id over the api
-
var panel = new historyPanel.HistoryPanel({
show_deleted : ${ 'true' if show_deleted == True else ( 'null' if show_deleted == None else 'false' ) },
show_hidden : ${ 'true' if show_hidden == True else ( 'null' if show_hidden == None else 'false' ) },
el : $( "${selector_to_attach_to}" ),
onready : function loadHistoryById(){
var panel = this;
- this.loadHistoryWithDetails( '${history_id}' )
+ this.loadHistoryWithHDADetails( '${history_id}' )
.fail( function(){
panel.render();
});
}
});
+});
</script>
-
-${history_panel_javascripts()}
</%def>
## ----------------------------------------------------------------------------
<%def name="bootstrapped_history_panel( history, hdas, selector_to_attach_to=None, \
show_deleted=None, show_hidden=None, hda_id=None )">
+
+${history_panel_javascripts()}
+
<script type="text/javascript">
-function onModuleReady( historyPanel ){
+onhistoryready.done( function( historyPanel ){
// attach a panel to selector_to_attach_to and use a history model with bootstrapped data
// history module is already in the dpn chain from the panel. We can re-scope it here.
@@ -67,9 +71,6 @@
historyJSON = ${h.to_json_string( history )},
hdaJSON = ${h.to_json_string( hdas )};
- // i don't like this history+user relationship, but user authentication changes views/behaviour
- historyJSON.user = Galaxy.currUser.toJSON();
-
var history = new historyModel.History( historyJSON, hdaJSON, {
logger: ( debugging )?( console ):( null )
});
@@ -81,16 +82,17 @@
model : history,
onready : function(){ this.render(); }
});
-}
+})
</script>
-
-${history_panel_javascripts()}
</%def>
## ----------------------------------------------------------------------------- generic 'base' function
<%def name="history_panel_javascripts()">
+<% print 'history_panel_javascripts' %>
${h.js(
+ "utils/localization",
+ "mvc/base-mvc",
"mvc/tags", "mvc/annotations"
)}
@@ -131,7 +133,9 @@
])}
<script type="text/javascript">
-var debugging = JSON.parse( sessionStorage.getItem( 'debugging' ) ) || false;
+var debugging = JSON.parse( sessionStorage.getItem( 'debugging' ) ) || false,
+ // use deferred to allow multiple callbacks (.done())
+ onhistoryready = jQuery.Deferred();
require.config({
baseUrl : "${h.url_for( '/static/scripts' )}"
@@ -145,7 +149,7 @@
//require([ "/static/scripts/history-panel.min.js" ], function( historyPanel ){
require([ "mvc/history/history-panel" ], function( historyPanel ){
- onModuleReady( historyPanel );
+ onhistoryready.resolve( historyPanel )
});
</script></%def>
diff -r 206055969b7cedcbfcac36c19428b9547cd5cb5d -r 7e45d419c54da8122f7b5d8e0ace3641e450a727 templates/webapps/galaxy/root/history.mako
--- a/templates/webapps/galaxy/root/history.mako
+++ b/templates/webapps/galaxy/root/history.mako
@@ -43,7 +43,8 @@
${history_panel_javascripts()}
<script type="text/javascript">
-function onModuleReady( historyPanel ){
+onhistoryready.done( function( historyPanel ){
+
// history module is already in the dpn chain from the panel. We can re-scope it here.
var historyModel = require( 'mvc/history/history-model' ),
debugging = JSON.parse( sessionStorage.getItem( 'debugging' ) ) || false,
@@ -66,7 +67,7 @@
}
}
});
-}
+})
</script></%def>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: UsesHistoryMixin: add get_user_histories; use in History API, index
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/206055969b7c/
Changeset: 206055969b7c
User: carlfeberhard
Date: 2013-12-11 17:55:59
Summary: UsesHistoryMixin: add get_user_histories; use in History API, index
Affected #: 2 files
diff -r a831eb375268fcf80479f7bf325ec7d8a757582c -r 206055969b7cedcbfcac36c19428b9547cd5cb5d lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -30,7 +30,7 @@
from galaxy.web.form_builder import AddressField, CheckboxField, SelectField, TextArea, TextField
from galaxy.web.form_builder import build_select_field, HistoryField, PasswordField, WorkflowField, WorkflowMappingField
from galaxy.workflow.modules import module_factory
-from galaxy.model.orm import eagerload, eagerload_all
+from galaxy.model.orm import eagerload, eagerload_all, desc
from galaxy.security.validate_user_input import validate_publicname
from galaxy.util.sanitize_html import sanitize_html
from galaxy.model.item_attrs import Dictifiable
@@ -341,6 +341,28 @@
history = self.security_check( trans, history, check_ownership, check_accessible )
return history
+ def get_user_histories( self, trans, user=None, include_deleted=False, only_deleted=False ):
+ """
+ Get all the histories for a given user (defaulting to `trans.user`)
+ ordered by update time and filtered on whether they've been deleted.
+ """
+ # handle default and/or anonymous user (which still may not have a history yet)
+ user = user or trans.user
+ if not user:
+ current_history = trans.get_history()
+ return [ current_history ] if current_history else []
+
+ history_model = trans.model.History
+ query = ( trans.sa_session.query( history_model )
+ .filter( history_model.user == user )
+ .order_by( desc( history_model.table.c.update_time ) ) )
+ if only_deleted:
+ query = query.filter( history_model.deleted == True )
+ elif not include_deleted:
+ query = query.filter( history_model.deleted == False )
+
+ return query.all()
+
def get_history_datasets( self, trans, history, show_deleted=False, show_hidden=False, show_purged=False ):
""" Returns history's datasets. """
query = trans.sa_session.query( trans.model.HistoryDatasetAssociation ) \
diff -r a831eb375268fcf80479f7bf325ec7d8a757582c -r 206055969b7cedcbfcac36c19428b9547cd5cb5d lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -41,11 +41,9 @@
deleted = string_as_bool( deleted )
try:
if trans.user:
- query = ( trans.sa_session.query( trans.app.model.History )
- .filter_by( user=trans.user, deleted=deleted )
- .order_by( desc( trans.app.model.History.table.c.update_time ) )
- .all() )
- for history in query:
+ histories = self.get_user_histories( trans, user=trans.user, only_deleted=deleted )
+ #for history in query:
+ for history in histories:
item = history.to_dict(value_mapper={'id':trans.security.encode_id})
item['url'] = url_for( 'history', id=trans.security.encode_id( history.id ) )
rval.append( item )
@@ -58,6 +56,7 @@
rval.append(item)
except Exception, e:
+ raise
rval = "Error in history API"
log.error( rval + ": %s" % str(e) )
trans.response.status = 500
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
10 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4ebd2f3313b2/
Changeset: 4ebd2f3313b2
User: jmchilton
Date: 2013-12-11 17:26:14
Summary: Reduce extra-module dependencies in galaxy.tools.deps.
Eliminte older elementtree dependency. Eliminate dependency on galaxy.util:string_as_bool. Only remaining dependency in galaxy.util.submodules.
PEP-8 fix up galaxy.util.submodules so it can be copied directly into the LWR.
This allowed adding the whole galaxy.tools.deps module and submodules into LWR for remote dependency resolution.
Affected #: 5 files
diff -r 98694eecdf76e7d69c77a0743d2b65fcb1ae3c12 -r 4ebd2f3313b21ecac0d327055b452911551ec279 lib/galaxy/tools/deps/__init__.py
--- a/lib/galaxy/tools/deps/__init__.py
+++ b/lib/galaxy/tools/deps/__init__.py
@@ -7,7 +7,7 @@
import logging
log = logging.getLogger( __name__ )
-from galaxy.util import parse_xml
+from xml.etree import ElementTree
from .resolvers import INDETERMINATE_DEPENDENCY
from .resolvers.galaxy_packages import GalaxyPackageDependencyResolver
@@ -69,8 +69,8 @@
def __build_dependency_resolvers( self, conf_file ):
if not conf_file or not os.path.exists( conf_file ):
return self.__default_dependency_resolvers()
- tree = parse_xml( conf_file )
- return self.__parse_resolver_conf_xml( tree )
+ root = ElementTree.parse( conf_file ).getroot()
+ return self.__parse_resolver_conf_xml( root )
def __default_dependency_resolvers( self ):
return [
@@ -78,14 +78,14 @@
GalaxyPackageDependencyResolver(self),
]
- def __parse_resolver_conf_xml(self, tree):
+ def __parse_resolver_conf_xml(self, root):
"""
- :param tree: Object representing the root ``<dependency_resolvers>`` object in the file.
- :type tree: ``xml.etree.ElementTree.Element``
+ :param root: Object representing the root ``<dependency_resolvers>`` object in the file.
+ :type root: ``xml.etree.ElementTree.Element``
"""
resolvers = []
- resolvers_element = tree.getroot()
+ resolvers_element = root
for resolver_element in resolvers_element.getchildren():
resolver_type = resolver_element.tag
resolver_kwds = dict(resolver_element.items())
diff -r 98694eecdf76e7d69c77a0743d2b65fcb1ae3c12 -r 4ebd2f3313b21ecac0d327055b452911551ec279 lib/galaxy/tools/deps/requirements.py
--- a/lib/galaxy/tools/deps/requirements.py
+++ b/lib/galaxy/tools/deps/requirements.py
@@ -19,8 +19,7 @@
def parse_requirements_from_xml( xml_root ):
"""
- >>> from galaxy.util import parse_xml
- >>> from elementtree import ElementTree
+ >>> from xml.etree import ElementTree
>>> def load_requirements( contents ):
... contents_document = '''<tool><requirements>%s</requirements></tool>'''
... root = ElementTree.fromstring( contents_document % contents )
@@ -43,7 +42,7 @@
requirements_elem = xml_root.find( "requirements" )
requirement_elems = []
- if requirements_elem:
+ if requirements_elem is not None:
requirement_elems = requirements_elem.findall( 'requirement' )
requirements = []
diff -r 98694eecdf76e7d69c77a0743d2b65fcb1ae3c12 -r 4ebd2f3313b21ecac0d327055b452911551ec279 lib/galaxy/tools/deps/resolvers/galaxy_packages.py
--- a/lib/galaxy/tools/deps/resolvers/galaxy_packages.py
+++ b/lib/galaxy/tools/deps/resolvers/galaxy_packages.py
@@ -1,7 +1,6 @@
from os.path import join, islink, realpath, basename, exists, abspath
from ..resolvers import DependencyResolver, INDETERMINATE_DEPENDENCY, Dependency
-from galaxy.util import string_as_bool
import logging
log = logging.getLogger( __name__ )
@@ -16,7 +15,7 @@
## the tool shed so allow a fallback version of the Galaxy package
## resolver that will just grab 'default' version of exact version
## unavailable.
- self.versionless = string_as_bool(kwds.get('versionless', "false"))
+ self.versionless = str(kwds.get('versionless', "false")).lower() == "true"
self.base_path = abspath( kwds.get('base_path', dependency_manager.default_base_path) )
def resolve( self, name, version, type, **kwds ):
diff -r 98694eecdf76e7d69c77a0743d2b65fcb1ae3c12 -r 4ebd2f3313b21ecac0d327055b452911551ec279 lib/galaxy/tools/deps/resolvers/modules.py
--- a/lib/galaxy/tools/deps/resolvers/modules.py
+++ b/lib/galaxy/tools/deps/resolvers/modules.py
@@ -12,7 +12,6 @@
from subprocess import Popen, PIPE
from ..resolvers import DependencyResolver, INDETERMINATE_DEPENDENCY, Dependency
-from galaxy.util import string_as_bool
import logging
log = logging.getLogger( __name__ )
@@ -28,9 +27,9 @@
resolver_type = "modules"
def __init__(self, dependency_manager, **kwds):
- self.versionless = string_as_bool(kwds.get('versionless', 'false'))
+ self.versionless = _string_as_bool(kwds.get('versionless', 'false'))
find_by = kwds.get('find_by', 'avail')
- prefetch = string_as_bool(kwds.get('prefetch', DEFAULT_MODULE_PREFETCH))
+ prefetch = _string_as_bool(kwds.get('prefetch', DEFAULT_MODULE_PREFETCH))
self.modulecmd = kwds.get('modulecmd', DEFAULT_MODULECMD_PATH)
if find_by == 'directory':
modulepath = kwds.get('modulepath', self.__default_modulespath())
@@ -150,4 +149,8 @@
command = 'eval `%s sh load %s`' % (self.module_dependency_resolver.modulecmd, module_to_load)
return command
+
+def _string_as_bool( value ):
+ return str( value ).lower() == "true"
+
__all__ = [ModuleDependencyResolver]
diff -r 98694eecdf76e7d69c77a0743d2b65fcb1ae3c12 -r 4ebd2f3313b21ecac0d327055b452911551ec279 lib/galaxy/util/submodules.py
--- a/lib/galaxy/util/submodules.py
+++ b/lib/galaxy/util/submodules.py
@@ -1,30 +1,31 @@
from os import listdir
+
import logging
-log = logging.getLogger( __name__ )
+log = logging.getLogger(__name__)
-def submodules( module ):
- unsorted_submodule_names = __submodule_names( module )
- submodule_names = sorted( unsorted_submodule_names, reverse=True )
+def submodules(module):
+ unsorted_submodule_names = __submodule_names(module)
+ submodule_names = sorted(unsorted_submodule_names, reverse=True)
submodules = []
for submodule_name in submodule_names:
- full_submodule = "%s.%s" % ( module.__name__, submodule_name )
+ full_submodule = "%s.%s" % (module.__name__, submodule_name)
try:
- __import__( full_submodule )
- submodule = getattr( module, submodule_name )
- submodules.append( submodule )
+ __import__(full_submodule)
+ submodule = getattr(module, submodule_name)
+ submodules.append(submodule)
except BaseException, exception:
- exception_str = str( exception )
- message = "%s dynamic module could not be loaded: %s" % ( full_submodule, exception_str )
- log.debug( message )
+ exception_str = str(exception)
+ message = "%s dynamic module could not be loaded: %s" % (full_submodule, exception_str)
+ log.debug(message)
return submodules
-def __submodule_names( module ):
- module_dir = module.__path__[ 0 ]
+def __submodule_names(module):
+ module_dir = module.__path__[0]
names = []
- for fname in listdir( module_dir ):
- if not( fname.startswith( "_" ) ) and fname.endswith( ".py" ):
- submodule_name = fname[ :-len( ".py" ) ]
- names.append( submodule_name )
+ for fname in listdir(module_dir):
+ if not(fname.startswith("_")) and fname.endswith(".py"):
+ submodule_name = fname[:-len(".py")]
+ names.append(submodule_name)
return names
https://bitbucket.org/galaxy/galaxy-central/commits/34694461de2c/
Changeset: 34694461de2c
User: jmchilton
Date: 2013-12-11 17:26:15
Summary: Refactor command_factory:build_command to reduce parameter count.
Grouping all parameters to tweak the building of this command line for remote servers (read LWR) - since I have at least one more to add.
Affected #: 3 files
diff -r 4ebd2f3313b21ecac0d327055b452911551ec279 -r 34694461de2c2863066aa24c7c0cee65837f29e5 lib/galaxy/jobs/command_factory.py
--- a/lib/galaxy/jobs/command_factory.py
+++ b/lib/galaxy/jobs/command_factory.py
@@ -2,7 +2,7 @@
from os.path import abspath
-def build_command( job, job_wrapper, include_metadata=False, include_work_dir_outputs=True, metadata_kwds={}, job_working_directory=None ):
+def build_command( job, job_wrapper, include_metadata=False, include_work_dir_outputs=True, remote_command_params={} ):
"""
Compose the sequence of commands necessary to execute a job. This will
currently include:
@@ -43,7 +43,10 @@
# Append commands to copy job outputs based on from_work_dir attribute.
if include_work_dir_outputs:
- work_dir_outputs = job.get_work_dir_outputs( job_wrapper, job_working_directory=job_working_directory )
+ work_dir_outputs_kwds = {}
+ if 'working_directory' in remote_command_params:
+ work_dir_outputs_kwds['job_working_directory'] = remote_command_params['working_directory']
+ work_dir_outputs = job.get_work_dir_outputs( job_wrapper, **work_dir_outputs_kwds )
if work_dir_outputs:
if not captured_return_code:
commands += capture_return_code_command
@@ -55,6 +58,7 @@
# Append metadata setting commands, we don't want to overwrite metadata
# that was copied over in init_meta(), as per established behavior
if include_metadata and job_wrapper.requires_setting_metadata:
+ metadata_kwds = remote_command_params.get('metadata_kwds', {})
exec_dir = metadata_kwds.get( 'exec_dir', abspath( getcwd() ) )
tmp_dir = metadata_kwds.get( 'tmp_dir', job_wrapper.working_directory )
dataset_files_path = metadata_kwds.get( 'dataset_files_path', job.app.model.Dataset.file_path )
diff -r 4ebd2f3313b21ecac0d327055b452911551ec279 -r 34694461de2c2863066aa24c7c0cee65837f29e5 lib/galaxy/jobs/runners/lwr.py
--- a/lib/galaxy/jobs/runners/lwr.py
+++ b/lib/galaxy/jobs/runners/lwr.py
@@ -107,13 +107,16 @@
remote_metadata = LwrJobRunner.__remote_metadata( client )
remote_work_dir_copy = LwrJobRunner.__remote_work_dir_copy( client )
metadata_kwds = self.__build_metadata_configuration(client, job_wrapper, remote_metadata, remote_job_config)
+ remote_command_params = dict(
+ working_directory=remote_job_config['working_directory'],
+ metadata_kwds=metadata_kwds,
+ )
command_line = build_command(
self,
job_wrapper=job_wrapper,
include_metadata=remote_metadata,
include_work_dir_outputs=remote_work_dir_copy,
- metadata_kwds=metadata_kwds,
- job_working_directory=remote_job_config['working_directory']
+ remote_command_params=remote_command_params,
)
except Exception:
job_wrapper.fail( "failure preparing job", exception=True )
diff -r 4ebd2f3313b21ecac0d327055b452911551ec279 -r 34694461de2c2863066aa24c7c0cee65837f29e5 test/unit/test_command_factory.py
--- a/test/unit/test_command_factory.py
+++ b/test/unit/test_command_factory.py
@@ -81,7 +81,7 @@
self.include_work_dir_outputs = False
self.job_wrapper.metadata_line = TEST_METADATA_LINE
if kwds:
- self.__command(metadata_kwds=kwds)
+ self.__command(remote_command_params=dict(metadata_kwds=kwds))
else:
self.__command()
return self.job_wrapper.configured_external_metadata_kwds
https://bitbucket.org/galaxy/galaxy-central/commits/e94ac0f171cb/
Changeset: e94ac0f171cb
User: jmchilton
Date: 2013-12-11 17:26:15
Summary: Allow new dependency_resolution destination for LWR runner.
It can be 'none', 'local', or 'remote'. At this point this allows one to disable command dependency injection if set to 'none' or 'remote'. Actually implementing logic for 'remote' resolution will follow.
In subsequent changes - 'remote' will make backward-imcompatiable API calls to the LWR - this is why 'none' is also provided as an option - it will be backward compatiable way to disable dependency resolution for an LWR destination.
Affected #: 3 files
diff -r 34694461de2c2863066aa24c7c0cee65837f29e5 -r e94ac0f171cb91325747434d0dd62ea6e9ea9187 lib/galaxy/jobs/command_factory.py
--- a/lib/galaxy/jobs/command_factory.py
+++ b/lib/galaxy/jobs/command_factory.py
@@ -31,8 +31,9 @@
if hasattr(job_wrapper, 'prepare_input_files_cmds') and job_wrapper.prepare_input_files_cmds is not None:
commands = "; ".join( job_wrapper.prepare_input_files_cmds + [ commands ] )
+ local_dependency_resolution = "dependency_resolution" not in remote_command_params or (remote_command_params["dependency_resolution"] == "local")
# Prepend dependency injection
- if job_wrapper.dependency_shell_commands:
+ if job_wrapper.dependency_shell_commands and local_dependency_resolution:
commands = "; ".join( job_wrapper.dependency_shell_commands + [ commands ] )
# Coping work dir outputs or setting metadata will mask return code of
diff -r 34694461de2c2863066aa24c7c0cee65837f29e5 -r e94ac0f171cb91325747434d0dd62ea6e9ea9187 lib/galaxy/jobs/runners/lwr.py
--- a/lib/galaxy/jobs/runners/lwr.py
+++ b/lib/galaxy/jobs/runners/lwr.py
@@ -106,10 +106,12 @@
remote_job_config = client.setup(tool.id, tool.version)
remote_metadata = LwrJobRunner.__remote_metadata( client )
remote_work_dir_copy = LwrJobRunner.__remote_work_dir_copy( client )
+ dependency_resolution = LwrJobRunner.__dependency_resolution( client )
metadata_kwds = self.__build_metadata_configuration(client, job_wrapper, remote_metadata, remote_job_config)
remote_command_params = dict(
working_directory=remote_job_config['working_directory'],
metadata_kwds=metadata_kwds,
+ dependency_resolution=dependency_resolution,
)
command_line = build_command(
self,
@@ -272,6 +274,13 @@
self.monitor_queue.put( job_state )
@staticmethod
+ def __dependency_resolution( lwr_client ):
+ dependency_resolution = lwr_client.destination_params.get( "dependency_resolution", "local" )
+ if dependency_resolution not in ["none", "local", "remote"]:
+ raise Exception("Unknown dependency_resolution value encountered %s" % dependency_resolution)
+ return dependency_resolution
+
+ @staticmethod
def __remote_metadata( lwr_client ):
remote_metadata = string_as_bool_or_none( lwr_client.destination_params.get( "remote_metadata", False ) )
return remote_metadata
diff -r 34694461de2c2863066aa24c7c0cee65837f29e5 -r e94ac0f171cb91325747434d0dd62ea6e9ea9187 test/unit/test_command_factory.py
--- a/test/unit/test_command_factory.py
+++ b/test/unit/test_command_factory.py
@@ -27,6 +27,19 @@
self.job_wrapper.dependency_shell_commands = dep_commands
self.__assert_command_is( "%s; %s" % (dep_commands[0], MOCK_COMMAND_LINE) )
+ def test_remote_dependency_resolution(self):
+ self.include_work_dir_outputs = False
+ dep_commands = [". /opt/galaxy/tools/bowtie/default/env.sh"]
+ self.job_wrapper.dependency_shell_commands = dep_commands
+ self.__assert_command_is(MOCK_COMMAND_LINE, remote_command_params=dict(dependency_resolution="remote"))
+
+ def test_explicit_local_dependency_resolution(self):
+ self.include_work_dir_outputs = False
+ dep_commands = [". /opt/galaxy/tools/bowtie/default/env.sh"]
+ self.job_wrapper.dependency_shell_commands = dep_commands
+ self.__assert_command_is("%s; %s" % (dep_commands[0], MOCK_COMMAND_LINE),
+ remote_command_params=dict(dependency_resolution="local"))
+
def test_set_metadata_skipped_if_unneeded(self):
self.include_metadata = True
self.include_work_dir_outputs = False
https://bitbucket.org/galaxy/galaxy-central/commits/dc4e5f648da2/
Changeset: dc4e5f648da2
User: jmchilton
Date: 2013-12-11 17:26:15
Summary: command_factory cleanup - fix very poorly named input parameter.
Affected #: 2 files
diff -r e94ac0f171cb91325747434d0dd62ea6e9ea9187 -r dc4e5f648da215f3a9da27fe5155d4dd2ebfbff0 lib/galaxy/jobs/command_factory.py
--- a/lib/galaxy/jobs/command_factory.py
+++ b/lib/galaxy/jobs/command_factory.py
@@ -2,7 +2,7 @@
from os.path import abspath
-def build_command( job, job_wrapper, include_metadata=False, include_work_dir_outputs=True, remote_command_params={} ):
+def build_command( runner, job_wrapper, include_metadata=False, include_work_dir_outputs=True, remote_command_params={} ):
"""
Compose the sequence of commands necessary to execute a job. This will
currently include:
@@ -47,7 +47,7 @@
work_dir_outputs_kwds = {}
if 'working_directory' in remote_command_params:
work_dir_outputs_kwds['job_working_directory'] = remote_command_params['working_directory']
- work_dir_outputs = job.get_work_dir_outputs( job_wrapper, **work_dir_outputs_kwds )
+ work_dir_outputs = runner.get_work_dir_outputs( job_wrapper, **work_dir_outputs_kwds )
if work_dir_outputs:
if not captured_return_code:
commands += capture_return_code_command
@@ -62,7 +62,7 @@
metadata_kwds = remote_command_params.get('metadata_kwds', {})
exec_dir = metadata_kwds.get( 'exec_dir', abspath( getcwd() ) )
tmp_dir = metadata_kwds.get( 'tmp_dir', job_wrapper.working_directory )
- dataset_files_path = metadata_kwds.get( 'dataset_files_path', job.app.model.Dataset.file_path )
+ dataset_files_path = metadata_kwds.get( 'dataset_files_path', runner.app.model.Dataset.file_path )
output_fnames = metadata_kwds.get( 'output_fnames', job_wrapper.get_output_fnames() )
config_root = metadata_kwds.get( 'config_root', None )
config_file = metadata_kwds.get( 'config_file', None )
diff -r e94ac0f171cb91325747434d0dd62ea6e9ea9187 -r dc4e5f648da215f3a9da27fe5155d4dd2ebfbff0 test/unit/test_command_factory.py
--- a/test/unit/test_command_factory.py
+++ b/test/unit/test_command_factory.py
@@ -13,7 +13,7 @@
def setUp(self):
self.job_wrapper = MockJobWrapper()
- self.job = Bunch(app=Bunch(model=Bunch(Dataset=Bunch(file_path=TEST_FILES_PATH))))
+ self.runner = Bunch(app=Bunch(model=Bunch(Dataset=Bunch(file_path=TEST_FILES_PATH))))
self.include_metadata = False
self.include_work_dir_outputs = True
@@ -105,7 +105,7 @@
def __command(self, **extra_kwds):
kwds = dict(
- job=self.job,
+ runner=self.runner,
job_wrapper=self.job_wrapper,
include_metadata=self.include_metadata,
include_work_dir_outputs=self.include_work_dir_outputs,
@@ -137,7 +137,3 @@
def get_output_fnames(self):
return ["output1"]
-
-
-class MockJob(object):
- app = Bunch()
https://bitbucket.org/galaxy/galaxy-central/commits/11888fd788bf/
Changeset: 11888fd788bf
User: jmchilton
Date: 2013-12-11 17:26:15
Summary: Add more unit tests for command_factory.
In particular for for task splitting commands and copying work dir outputs.
Affected #: 1 file
diff -r dc4e5f648da215f3a9da27fe5155d4dd2ebfbff0 -r 11888fd788bf4364acef861f545c4e27af05d6a8 test/unit/test_command_factory.py
--- a/test/unit/test_command_factory.py
+++ b/test/unit/test_command_factory.py
@@ -13,7 +13,13 @@
def setUp(self):
self.job_wrapper = MockJobWrapper()
- self.runner = Bunch(app=Bunch(model=Bunch(Dataset=Bunch(file_path=TEST_FILES_PATH))))
+ self.workdir_outputs = []
+
+ def workdir_outputs(job_wrapper, **kwds):
+ assert job_wrapper == self.job_wrapper
+ return self.workdir_outputs
+
+ self.runner = Bunch(app=Bunch(model=Bunch(Dataset=Bunch(file_path=TEST_FILES_PATH))), get_work_dir_outputs=workdir_outputs)
self.include_metadata = False
self.include_work_dir_outputs = True
@@ -40,6 +46,16 @@
self.__assert_command_is("%s; %s" % (dep_commands[0], MOCK_COMMAND_LINE),
remote_command_params=dict(dependency_resolution="local"))
+ def test_task_prepare_inputs(self):
+ self.include_work_dir_outputs = False
+ self.job_wrapper.prepare_input_files_cmds = ["/opt/split1", "/opt/split2"]
+ self.__assert_command_is( "/opt/split1; /opt/split2; %s" % MOCK_COMMAND_LINE )
+
+ def test_workdir_outputs(self):
+ self.include_work_dir_outputs = True
+ self.workdir_outputs = [("foo", "bar")]
+ self.__assert_command_is( '%s; return_code=$?; if [ -f foo ] ; then cp foo bar ; fi; sh -c "exit $return_code"' % MOCK_COMMAND_LINE )
+
def test_set_metadata_skipped_if_unneeded(self):
self.include_metadata = True
self.include_work_dir_outputs = False
@@ -123,6 +139,7 @@
self.metadata_line = None
self.configured_external_metadata_kwds = None
self.working_directory = "job1"
+ self.prepare_input_files_cmds = None
def get_command_line(self):
return self.command_line
https://bitbucket.org/galaxy/galaxy-central/commits/ef3e337d1fc7/
Changeset: ef3e337d1fc7
User: jmchilton
Date: 2013-12-11 17:26:15
Summary: command_factory cleanup - introduce abstraction for more readable command construction logic.
Affected #: 1 file
diff -r 11888fd788bf4364acef861f545c4e27af05d6a8 -r ef3e337d1fc7d4ee61bcf91e4ca50446eb087d6a lib/galaxy/jobs/command_factory.py
--- a/lib/galaxy/jobs/command_factory.py
+++ b/lib/galaxy/jobs/command_factory.py
@@ -13,34 +13,25 @@
- commands to set metadata (if include_metadata is True)
"""
- commands = job_wrapper.get_command_line()
+ commands_builder = CommandsBuilder(job_wrapper.get_command_line())
# All job runners currently handle this case which should never occur
- if not commands:
+ if not commands_builder.commands:
return None
- # Remove trailing semi-colon so we can start hacking up this command.
- # TODO: Refactor to compose a list and join with ';', would be more clean.
- commands = commands.rstrip("; ")
-
# Prepend version string
if job_wrapper.version_string_cmd:
- commands = "%s &> %s; " % ( job_wrapper.version_string_cmd, job_wrapper.get_version_string_path() ) + commands
+ version_command = "%s &> %s" % ( job_wrapper.version_string_cmd, job_wrapper.get_version_string_path() )
+ commands_builder.prepend_command(version_command)
# prepend getting input files (if defined)
if hasattr(job_wrapper, 'prepare_input_files_cmds') and job_wrapper.prepare_input_files_cmds is not None:
- commands = "; ".join( job_wrapper.prepare_input_files_cmds + [ commands ] )
+ commands_builder.prepend_commands(job_wrapper.prepare_input_files_cmds)
local_dependency_resolution = "dependency_resolution" not in remote_command_params or (remote_command_params["dependency_resolution"] == "local")
# Prepend dependency injection
if job_wrapper.dependency_shell_commands and local_dependency_resolution:
- commands = "; ".join( job_wrapper.dependency_shell_commands + [ commands ] )
-
- # Coping work dir outputs or setting metadata will mask return code of
- # tool command. If these are used capture the return code and ensure
- # the last thing that happens is an exit with return code.
- capture_return_code_command = "; return_code=$?"
- captured_return_code = False
+ commands_builder.prepend_commands(job_wrapper.dependency_shell_commands)
# Append commands to copy job outputs based on from_work_dir attribute.
if include_work_dir_outputs:
@@ -49,12 +40,9 @@
work_dir_outputs_kwds['job_working_directory'] = remote_command_params['working_directory']
work_dir_outputs = runner.get_work_dir_outputs( job_wrapper, **work_dir_outputs_kwds )
if work_dir_outputs:
- if not captured_return_code:
- commands += capture_return_code_command
- captured_return_code = True
-
- commands += "; " + "; ".join( [ "if [ -f %s ] ; then cp %s %s ; fi" %
- ( source_file, source_file, destination ) for ( source_file, destination ) in work_dir_outputs ] )
+ commands_builder.capture_return_code()
+ commands_builder.append_commands([ "if [ -f %s ] ; then cp %s %s ; fi" %
+ ( source_file, source_file, destination ) for ( source_file, destination ) in work_dir_outputs ])
# Append metadata setting commands, we don't want to overwrite metadata
# that was copied over in init_meta(), as per established behavior
@@ -80,12 +68,44 @@
) or ''
metadata_command = metadata_command.strip()
if metadata_command:
- if not captured_return_code:
- commands += capture_return_code_command
- captured_return_code = True
- commands += "; cd %s; %s" % (exec_dir, metadata_command)
+ commands_builder.capture_return_code()
+ commands_builder.append_command("cd %s; %s" % (exec_dir, metadata_command))
- if captured_return_code:
- commands += '; sh -c "exit $return_code"'
+ return commands_builder.build()
- return commands
+
+class CommandsBuilder(object):
+
+ def __init__(self, initial_command):
+ # Remove trailing semi-colon so we can start hacking up this command.
+ # TODO: Refactor to compose a list and join with ';', would be more clean.
+ commands = initial_command.rstrip("; ")
+ self.commands = commands
+
+ # Coping work dir outputs or setting metadata will mask return code of
+ # tool command. If these are used capture the return code and ensure
+ # the last thing that happens is an exit with return code.
+ self.return_code_captured = False
+
+ def prepend_command(self, command):
+ self.commands = "%s; %s" % (command, self.commands)
+ return self
+
+ def prepend_commands(self, commands):
+ return self.prepend_command("; ".join(commands))
+
+ def append_command(self, command):
+ self.commands = "%s; %s" % (self.commands, command)
+
+ def append_commands(self, commands):
+ self.append_command("; ".join(commands))
+
+ def capture_return_code(self):
+ if not self.return_code_captured:
+ self.return_code_captured = True
+ self.append_command("return_code=$?")
+
+ def build(self):
+ if self.return_code_captured:
+ self.append_command('sh -c "exit $return_code"')
+ return self.commands
https://bitbucket.org/galaxy/galaxy-central/commits/188df80a411c/
Changeset: 188df80a411c
User: jmchilton
Date: 2013-12-11 17:26:15
Summary: command_factory cleanup - split big build_command method into smaller well-named pieces.
Affected #: 1 file
diff -r ef3e337d1fc7d4ee61bcf91e4ca50446eb087d6a -r 188df80a411c01272d03e7143d2afa343d575f81 lib/galaxy/jobs/command_factory.py
--- a/lib/galaxy/jobs/command_factory.py
+++ b/lib/galaxy/jobs/command_factory.py
@@ -19,59 +19,77 @@
if not commands_builder.commands:
return None
+ __handle_version_command(commands_builder, job_wrapper)
+ __handle_task_splitting(commands_builder, job_wrapper)
+ __handle_dependency_resolution(commands_builder, job_wrapper, remote_command_params)
+
+ if include_work_dir_outputs:
+ __handle_work_dir_outputs(commands_builder, job_wrapper, runner, remote_command_params)
+
+ if include_metadata and job_wrapper.requires_setting_metadata:
+ __handle_metadata(commands_builder, job_wrapper, runner, remote_command_params)
+
+ return commands_builder.build()
+
+
+def __handle_version_command(commands_builder, job_wrapper):
# Prepend version string
if job_wrapper.version_string_cmd:
version_command = "%s &> %s" % ( job_wrapper.version_string_cmd, job_wrapper.get_version_string_path() )
commands_builder.prepend_command(version_command)
+
+def __handle_task_splitting(commands_builder, job_wrapper):
# prepend getting input files (if defined)
- if hasattr(job_wrapper, 'prepare_input_files_cmds') and job_wrapper.prepare_input_files_cmds is not None:
+ if getattr(job_wrapper, 'prepare_input_files_cmds', None):
commands_builder.prepend_commands(job_wrapper.prepare_input_files_cmds)
+
+def __handle_dependency_resolution(commands_builder, job_wrapper, remote_command_params):
local_dependency_resolution = "dependency_resolution" not in remote_command_params or (remote_command_params["dependency_resolution"] == "local")
# Prepend dependency injection
if job_wrapper.dependency_shell_commands and local_dependency_resolution:
commands_builder.prepend_commands(job_wrapper.dependency_shell_commands)
+
+def __handle_work_dir_outputs(commands_builder, job_wrapper, runner, remote_command_params):
# Append commands to copy job outputs based on from_work_dir attribute.
- if include_work_dir_outputs:
- work_dir_outputs_kwds = {}
- if 'working_directory' in remote_command_params:
- work_dir_outputs_kwds['job_working_directory'] = remote_command_params['working_directory']
- work_dir_outputs = runner.get_work_dir_outputs( job_wrapper, **work_dir_outputs_kwds )
- if work_dir_outputs:
- commands_builder.capture_return_code()
- commands_builder.append_commands([ "if [ -f %s ] ; then cp %s %s ; fi" %
- ( source_file, source_file, destination ) for ( source_file, destination ) in work_dir_outputs ])
+ work_dir_outputs_kwds = {}
+ if 'working_directory' in remote_command_params:
+ work_dir_outputs_kwds['job_working_directory'] = remote_command_params['working_directory']
+ work_dir_outputs = runner.get_work_dir_outputs( job_wrapper, **work_dir_outputs_kwds )
+ if work_dir_outputs:
+ commands_builder.capture_return_code()
+ commands_builder.append_commands([ "if [ -f %s ] ; then cp %s %s ; fi" %
+ ( source_file, source_file, destination ) for ( source_file, destination ) in work_dir_outputs ])
+
+def __handle_metadata(commands_builder, job_wrapper, runner, remote_command_params):
# Append metadata setting commands, we don't want to overwrite metadata
# that was copied over in init_meta(), as per established behavior
- if include_metadata and job_wrapper.requires_setting_metadata:
- metadata_kwds = remote_command_params.get('metadata_kwds', {})
- exec_dir = metadata_kwds.get( 'exec_dir', abspath( getcwd() ) )
- tmp_dir = metadata_kwds.get( 'tmp_dir', job_wrapper.working_directory )
- dataset_files_path = metadata_kwds.get( 'dataset_files_path', runner.app.model.Dataset.file_path )
- output_fnames = metadata_kwds.get( 'output_fnames', job_wrapper.get_output_fnames() )
- config_root = metadata_kwds.get( 'config_root', None )
- config_file = metadata_kwds.get( 'config_file', None )
- datatypes_config = metadata_kwds.get( 'datatypes_config', None )
- metadata_command = job_wrapper.setup_external_metadata(
- exec_dir=exec_dir,
- tmp_dir=tmp_dir,
- dataset_files_path=dataset_files_path,
- output_fnames=output_fnames,
- set_extension=False,
- config_root=config_root,
- config_file=config_file,
- datatypes_config=datatypes_config,
- kwds={ 'overwrite' : False }
- ) or ''
- metadata_command = metadata_command.strip()
- if metadata_command:
- commands_builder.capture_return_code()
- commands_builder.append_command("cd %s; %s" % (exec_dir, metadata_command))
-
- return commands_builder.build()
+ metadata_kwds = remote_command_params.get('metadata_kwds', {})
+ exec_dir = metadata_kwds.get( 'exec_dir', abspath( getcwd() ) )
+ tmp_dir = metadata_kwds.get( 'tmp_dir', job_wrapper.working_directory )
+ dataset_files_path = metadata_kwds.get( 'dataset_files_path', runner.app.model.Dataset.file_path )
+ output_fnames = metadata_kwds.get( 'output_fnames', job_wrapper.get_output_fnames() )
+ config_root = metadata_kwds.get( 'config_root', None )
+ config_file = metadata_kwds.get( 'config_file', None )
+ datatypes_config = metadata_kwds.get( 'datatypes_config', None )
+ metadata_command = job_wrapper.setup_external_metadata(
+ exec_dir=exec_dir,
+ tmp_dir=tmp_dir,
+ dataset_files_path=dataset_files_path,
+ output_fnames=output_fnames,
+ set_extension=False,
+ config_root=config_root,
+ config_file=config_file,
+ datatypes_config=datatypes_config,
+ kwds={ 'overwrite' : False }
+ ) or ''
+ metadata_command = metadata_command.strip()
+ if metadata_command:
+ commands_builder.capture_return_code()
+ commands_builder.append_command("cd %s; %s" % (exec_dir, metadata_command))
class CommandsBuilder(object):
https://bitbucket.org/galaxy/galaxy-central/commits/b513c61601ef/
Changeset: b513c61601ef
User: jmchilton
Date: 2013-12-11 17:26:15
Summary: command_factory cleanup - a couple more small tweaks for readability.
Affected #: 1 file
diff -r 188df80a411c01272d03e7143d2afa343d575f81 -r b513c61601ef6bec6713320cd4e23fc4e020359e lib/galaxy/jobs/command_factory.py
--- a/lib/galaxy/jobs/command_factory.py
+++ b/lib/galaxy/jobs/command_factory.py
@@ -1,6 +1,9 @@
from os import getcwd
from os.path import abspath
+CAPTURE_RETURN_CODE = "return_code=$?"
+YIELD_CAPTURED_CODE = 'sh -c "exit $return_code"'
+
def build_command( runner, job_wrapper, include_metadata=False, include_work_dir_outputs=True, remote_command_params={} ):
"""
@@ -46,7 +49,8 @@
def __handle_dependency_resolution(commands_builder, job_wrapper, remote_command_params):
- local_dependency_resolution = "dependency_resolution" not in remote_command_params or (remote_command_params["dependency_resolution"] == "local")
+ local_dependency_resolution = remote_command_params.get("dependency_resolution", "local") == "local"
+
# Prepend dependency injection
if job_wrapper.dependency_shell_commands and local_dependency_resolution:
commands_builder.prepend_commands(job_wrapper.dependency_shell_commands)
@@ -60,8 +64,8 @@
work_dir_outputs = runner.get_work_dir_outputs( job_wrapper, **work_dir_outputs_kwds )
if work_dir_outputs:
commands_builder.capture_return_code()
- commands_builder.append_commands([ "if [ -f %s ] ; then cp %s %s ; fi" %
- ( source_file, source_file, destination ) for ( source_file, destination ) in work_dir_outputs ])
+ copy_commands = map(__copy_if_exists_command, work_dir_outputs)
+ commands_builder.append_commands(copy_commands)
def __handle_metadata(commands_builder, job_wrapper, runner, remote_command_params):
@@ -92,6 +96,11 @@
commands_builder.append_command("cd %s; %s" % (exec_dir, metadata_command))
+def __copy_if_exists_command(work_dir_output):
+ source_file, destination = work_dir_output
+ return "if [ -f %s ] ; then cp %s %s ; fi" % ( source_file, source_file, destination )
+
+
class CommandsBuilder(object):
def __init__(self, initial_command):
@@ -121,9 +130,11 @@
def capture_return_code(self):
if not self.return_code_captured:
self.return_code_captured = True
- self.append_command("return_code=$?")
+ self.append_command(CAPTURE_RETURN_CODE)
def build(self):
if self.return_code_captured:
- self.append_command('sh -c "exit $return_code"')
+ self.append_command(YIELD_CAPTURED_CODE)
return self.commands
+
+__all__ = [build_command]
https://bitbucket.org/galaxy/galaxy-central/commits/3a7dee0e35b7/
Changeset: 3a7dee0e35b7
User: jmchilton
Date: 2013-12-11 17:26:15
Summary: Implement 'remote' dependency_resolution for LWR.
Set LWR destination parameter 'dependency_resolution' to remote. This will disable all dependency resolution on Galaxy side when building up command line and instead pass the tool's requirements along to the LWR server for resolution on that end. This requires a very up-to-date LWR server.
I think right now 'galaxy_packages' and 'modules' resolution would work but not 'tool_shed_package' resolution - I think more repository information related to the tool needs to be passed along to the LWR to enable this.
Updates the LWR client code through LWR changeset 4380e65 - mostly bringing in changes to enable this but also includes other small refactorings to stager.py.
Affected #: 4 files
diff -r b513c61601ef6bec6713320cd4e23fc4e020359e -r 3a7dee0e35b7b83617c8df8b943e74199941ff55 lib/galaxy/jobs/runners/lwr.py
--- a/lib/galaxy/jobs/runners/lwr.py
+++ b/lib/galaxy/jobs/runners/lwr.py
@@ -68,6 +68,9 @@
return
try:
+ dependency_resolution = LwrJobRunner.__dependency_resolution( client )
+ remote_dependency_resolution = dependency_resolution == "remote"
+ requirements = job_wrapper.tool.requirements if remote_dependency_resolution else []
client_job_description = ClientJobDescription(
command_line=command_line,
output_files=self.get_output_files(job_wrapper),
@@ -75,6 +78,7 @@
working_directory=job_wrapper.working_directory,
tool=job_wrapper.tool,
config_files=job_wrapper.extra_filenames,
+ requirements=requirements,
)
job_id = lwr_submit_job(client, client_job_description, remote_job_config)
log.info("lwr job submitted with job_id %s" % job_id)
diff -r b513c61601ef6bec6713320cd4e23fc4e020359e -r 3a7dee0e35b7b83617c8df8b943e74199941ff55 lib/galaxy/jobs/runners/lwr_client/client.py
--- a/lib/galaxy/jobs/runners/lwr_client/client.py
+++ b/lib/galaxy/jobs/runners/lwr_client/client.py
@@ -197,7 +197,7 @@
}
self._raw_execute("download_output", output_params, output_path=output_path)
- def launch(self, command_line):
+ def launch(self, command_line, requirements=[]):
"""
Run or queue up the execution of the supplied
`command_line` on the remote server.
@@ -211,6 +211,8 @@
submit_params = self._submit_params
if submit_params:
launch_params['params'] = dumps(submit_params)
+ if requirements:
+ launch_params['requirements'] = dumps([requirement.to_dict() for requirement in requirements])
return self._raw_execute("launch", launch_params)
def kill(self):
diff -r b513c61601ef6bec6713320cd4e23fc4e020359e -r 3a7dee0e35b7b83617c8df8b943e74199941ff55 lib/galaxy/jobs/runners/lwr_client/stager.py
--- a/lib/galaxy/jobs/runners/lwr_client/stager.py
+++ b/lib/galaxy/jobs/runners/lwr_client/stager.py
@@ -3,6 +3,7 @@
from re import findall
from re import compile
from io import open
+from contextlib import contextmanager
from .action_mapper import FileActionMapper
@@ -297,41 +298,58 @@
def finish_job(client, cleanup_job, job_completed_normally, working_directory, work_dir_outputs, output_files, working_directory_contents=[]):
"""
"""
+ download_failure_exceptions = []
+ if job_completed_normally:
+ download_failure_exceptions = __download_results(client, working_directory, work_dir_outputs, output_files, working_directory_contents)
+ return __clean(download_failure_exceptions, cleanup_job, client)
+
+
+def __download_results(client, working_directory, work_dir_outputs, output_files, working_directory_contents):
action_mapper = FileActionMapper(client)
- download_failure_exceptions = []
downloaded_working_directory_files = []
- if job_completed_normally:
- # Fetch explicit working directory outputs.
- for source_file, output_file in work_dir_outputs:
- name = basename(source_file)
- try:
- action = action_mapper.action(output_file, 'output')
- client.fetch_work_dir_output(name, working_directory, output_file, action[0])
- downloaded_working_directory_files.append(name)
- except Exception as e:
- download_failure_exceptions.append(e)
- # Remove from full output_files list so don't try to download directly.
- output_files.remove(output_file)
+ exception_tracker = DownloadExceptionTracker()
- # Fetch output files.
- for output_file in output_files:
- try:
- action = action_mapper.action(output_file, 'output')
- client.fetch_output(output_file, working_directory=working_directory, action=action[0])
- except Exception as e:
- download_failure_exceptions.append(e)
+ # Fetch explicit working directory outputs.
+ for source_file, output_file in work_dir_outputs:
+ name = basename(source_file)
+ with exception_tracker():
+ action = action_mapper.action(output_file, 'output')
+ client.fetch_work_dir_output(name, working_directory, output_file, action[0])
+ downloaded_working_directory_files.append(name)
+ # Remove from full output_files list so don't try to download directly.
+ output_files.remove(output_file)
- # Fetch remaining working directory outputs of interest.
- for name in working_directory_contents:
- if name in downloaded_working_directory_files:
- continue
- if COPY_FROM_WORKING_DIRECTORY_PATTERN.match(name):
+ # Fetch output files.
+ for output_file in output_files:
+ with exception_tracker():
+ action = action_mapper.action(output_file, 'output')
+ client.fetch_output(output_file, working_directory=working_directory, action=action[0])
+
+ # Fetch remaining working directory outputs of interest.
+ for name in working_directory_contents:
+ if name in downloaded_working_directory_files:
+ continue
+ if COPY_FROM_WORKING_DIRECTORY_PATTERN.match(name):
+ with exception_tracker():
output_file = join(working_directory, name)
action = action_mapper.action(output_file, 'output')
client.fetch_work_dir_output(name, working_directory, output_file, action=action[0])
downloaded_working_directory_files.append(name)
- return __clean(download_failure_exceptions, cleanup_job, client)
+ return exception_tracker.download_failure_exceptions
+
+
+class DownloadExceptionTracker(object):
+
+ def __init__(self):
+ self.download_failure_exceptions = []
+
+ @contextmanager
+ def __call__(self):
+ try:
+ yield
+ except Exception as e:
+ self.download_failure_exceptions.append(e)
def __clean(download_failure_exceptions, cleanup_job, client):
@@ -350,7 +368,7 @@
file_stager = FileStager(client, client_job_description, job_config)
rebuilt_command_line = file_stager.get_rewritten_command_line()
job_id = file_stager.job_id
- client.launch(rebuilt_command_line)
+ client.launch(rebuilt_command_line, requirements=client_job_description.requirements)
return job_id
@@ -383,15 +401,17 @@
Directory containing tool to execute (if a wrapper is used, it will be transferred to remote server).
working_directory : str
Local path created by Galaxy for running this job.
+ requirements : list
+ List of requirements for tool execution.
"""
- def __init__(self, tool, command_line, config_files, input_files, output_files, working_directory):
+ def __init__(self, tool, command_line, config_files, input_files, output_files, working_directory, requirements):
self.tool = tool
self.command_line = command_line
self.config_files = config_files
self.input_files = input_files
self.output_files = output_files
self.working_directory = working_directory
-
+ self.requirements = requirements
__all__ = [submit_job, ClientJobDescription, finish_job]
diff -r b513c61601ef6bec6713320cd4e23fc4e020359e -r 3a7dee0e35b7b83617c8df8b943e74199941ff55 lib/galaxy/tools/deps/requirements.py
--- a/lib/galaxy/tools/deps/requirements.py
+++ b/lib/galaxy/tools/deps/requirements.py
@@ -15,6 +15,16 @@
self.type = type
self.version = version
+ def to_dict( self ):
+ return dict(name=self.name, type=self.type, version=self.version)
+
+ @staticmethod
+ def from_dict( dict ):
+ version = dict.get( "version", None )
+ name = dict.get("name", None)
+ type = dict.get("type", None)
+ return ToolRequirement( name=name, type=type, version=version )
+
def parse_requirements_from_xml( xml_root ):
"""
https://bitbucket.org/galaxy/galaxy-central/commits/a831eb375268/
Changeset: a831eb375268
User: jmchilton
Date: 2013-12-11 17:26:15
Summary: Fill out job_conf.xml example with LWR options added over recent months.
Affected #: 1 file
diff -r 3a7dee0e35b7b83617c8df8b943e74199941ff55 -r a831eb375268fcf80479f7bf325ec7d8a757582c job_conf.xml.sample_advanced
--- a/job_conf.xml.sample_advanced
+++ b/job_conf.xml.sample_advanced
@@ -52,8 +52,37 @@
<param id="private_token">123456789changeme</param><!-- Uncomment the following statement to disable file staging (e.g.
if there is a shared file system between Galaxy and the LWR
- server). -->
+ server). Alternatively action can be set to 'copy' - to replace
+ http transfers with file system copies. --><!-- <param id="default_file_action">none</param> -->
+ <!-- The above option is just the default, the transfer behavior
+ none|copy|http can be configured on a per path basis via the
+ following file. See lib/galaxy/jobs/runners/lwr_client/action_mapper.py
+ for examples of how to configure this file. This is very beta
+ and nature of file will likely change.
+ -->
+ <!-- <param id="file_action_config">file_actions.json</param> -->
+ <!-- Uncomment following option to disable Galaxy tool dependency
+ resolution and utilize remote LWR's configuraiton of tool
+ dependency resolution instead (same options as Galaxy for
+ dependency resolution are available in LWR).
+ -->
+ <!-- <param id="dependency_resolution">remote</params> -->
+ <!-- Uncomment following option to enable setting metadata on remote
+ LWR server. The 'use_remote_datatypes' option is available for
+ determining whether to use remotely configured datatypes or local
+ ones (both alternatives are a little brittle). -->
+ <!-- <param id="remote_metadata">true</param> -->
+ <!-- <param id="use_remote_datatypes">false</param> -->
+ <!-- If remote LWR server is configured to run jobs as the real user,
+ uncomment the following line to pass the current Galaxy user
+ along. -->
+ <!-- <param id="submit_user">$__user_name__</param> -->
+ <!-- Various other submission parameters can be passed along to the LWR
+ whose use will depend on the remote LWR's configured job manager.
+ For instance:
+ -->
+ <!-- <param id="submit_native_specification">-P bignodes -R y -pe threads 8</param> --></destination><destination id="ssh_torque" runner="cli"><param id="shell_plugin">SecureShell</param>
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: dan: Add a redirect for Data Source tools, with the goal of subverting mix-mode content blocking in browsers, i.e. accessing http data source from an https Galaxy. Tested as working on Safari 7.0 and FireFox 26. Subverting did not work on Chrome 31.
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/98694eecdf76/
Changeset: 98694eecdf76
User: dan
Date: 2013-12-11 16:58:48
Summary: Add a redirect for Data Source tools, with the goal of subverting mix-mode content blocking in browsers, i.e. accessing http data source from an https Galaxy. Tested as working on Safari 7.0 and FireFox 26. Subverting did not work on Chrome 31.
Affected #: 2 files
diff -r 35ae5ce8be84dcccadaf58c9b569fb9cf9daccbf -r 98694eecdf76e7d69c77a0743d2b65fcb1ae3c12 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -3003,10 +3003,10 @@
# Add link details.
if link_details:
# Add details for creating a hyperlink to the tool.
- if not self.tool_type.startswith( 'data_source' ):
- link = url_for( '/tool_runner', tool_id=self.id )
+ if not isinstance( self, DataSourceTool ):
+ link = url_for( controller='tool_runner', tool_id=self.id )
else:
- link = url_for( self.action, **self.get_static_param_values( trans ) )
+ link = url_for( controller='tool_runner', action='data_source_redirect', tool_id=self.id )
# Basic information
tool_dict.update( { 'link': link,
diff -r 35ae5ce8be84dcccadaf58c9b569fb9cf9daccbf -r 98694eecdf76e7d69c77a0743d2b65fcb1ae3c12 lib/galaxy/webapps/galaxy/controllers/tool_runner.py
--- a/lib/galaxy/webapps/galaxy/controllers/tool_runner.py
+++ b/lib/galaxy/webapps/galaxy/controllers/tool_runner.py
@@ -6,6 +6,7 @@
import galaxy.util
from galaxy import web
from galaxy.tools import DefaultToolState
+from galaxy.tools import DataSourceTool
from galaxy.tools.actions import upload_common
from galaxy.tools.parameters import params_to_incoming
from galaxy.tools.parameters import visit_input_values
@@ -233,6 +234,35 @@
**vars )
@web.expose
+ def data_source_redirect( self, trans, tool_id=None ):
+ """
+ Redirects a user accessing a Data Source tool to its target action link.
+ This method will subvert mix-mode content blocking in several browsers when
+ accessing non-https data_source tools from an https galaxy server.
+
+ Tested as working on Safari 7.0 and FireFox 26
+ Subverting did not work on Chrome 31
+ """
+ if tool_id is None:
+ return trans.response.send_redirect( url_for( controller="root", action="welcome" ) )
+ tool_version_select_field, tools, tool = self.__get_tool_components( tool_id,
+ tool_version=None,
+ get_loaded_tools_by_lineage=False,
+ set_selected=False )
+ # No tool matching the tool id, display an error (shouldn't happen)
+ if not tool:
+ log.error( "data_source_redirect called with tool id '%s' but no such tool exists", tool_id )
+ trans.log_event( "Tool id '%s' does not exist" % tool_id )
+ trans.response.status = 404
+ return "Tool '%s' does not exist, kwd=%s " % ( tool_id, kwd )
+
+ if isinstance( tool, DataSourceTool ):
+ link = url_for( tool.action, **tool.get_static_param_values( trans ) )
+ else:
+ link = url_for( controller='tool_runner', tool_id=tool.id )
+ return trans.response.send_redirect( link )
+
+ @web.expose
def redirect( self, trans, redirect_url=None, **kwd ):
if not redirect_url:
return trans.show_error_message( "Required URL for redirection missing" )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/1b78bcbb1bc2/
Changeset: 1b78bcbb1bc2
User: jmchilton
Date: 2013-12-11 16:55:54
Summary: Add some higher-level methods to mapping unit test.
Affected #: 1 file
diff -r df88d6121d48b0b193d34445ce49916adf17a2d2 -r 1b78bcbb1bc2bc0f39149726855418ccc890a3ff test/unit/test_galaxy_mapping.py
--- a/test/unit/test_galaxy_mapping.py
+++ b/test/unit/test_galaxy_mapping.py
@@ -3,10 +3,10 @@
class MappingTests( unittest.TestCase ):
+
def test_basic( self ):
- # Start the database and connect the mapping
- model = mapping.init( "/tmp", "sqlite:///:memory:", create_tables=True )
- assert model.engine is not None
+ model = self.model
+
# Make some changes and commit them
u = model.User( email="james(a)foo.bar.baz", password="password" )
# gs = model.GalaxySession()
@@ -14,15 +14,14 @@
#h1.queries.append( model.Query( "h1->q1" ) )
#h1.queries.append( model.Query( "h1->q2" ) )
h2 = model.History( name=( "H" * 1024 ) )
- model.session.add_all( ( u, h1, h2 ) )
+ self.persist( u, h1, h2 )
#q1 = model.Query( "h2->q1" )
metadata = dict( chromCol=1, startCol=2, endCol=3 )
d1 = model.HistoryDatasetAssociation( extension="interval", metadata=metadata, history=h2, create_dataset=True, sa_session=model.session )
#h2.queries.append( q1 )
#h2.queries.append( model.Query( "h2->q2" ) )
- model.session.add( ( d1 ) )
- model.session.flush()
- model.session.expunge_all()
+ self.persist( d1 )
+
# Check
users = model.session.query( model.User ).all()
assert len( users ) == 1
@@ -41,13 +40,33 @@
#assert hists[1].datasets[0].file_name == os.path.join( "/tmp", *directory_hash_id( id ) ) + ( "/dataset_%d.dat" % id )
# Do an update and check
hists[1].name = "History 2b"
- model.session.flush()
- model.session.expunge_all()
+ self.expunge()
hists = model.session.query( model.History ).all()
assert hists[0].name == "History 1"
assert hists[1].name == "History 2b"
# gvk TODO need to ad test for GalaxySessions, but not yet sure what they should look like.
+ @classmethod
+ def setUpClass(cls):
+ # Start the database and connect the mapping
+ cls.model = mapping.init( "/tmp", "sqlite:///:memory:", create_tables=True )
+ assert cls.model.engine is not None
+
+ @classmethod
+ def query( cls, type ):
+ return cls.model.session.query( type )
+
+ @classmethod
+ def persist(cls, *args):
+ for arg in args:
+ cls.model.session.add( arg )
+ cls.expunge()
+
+ @classmethod
+ def expunge(cls):
+ cls.model.session.flush()
+ cls.model.session.expunge_all()
+
def get_suite():
suite = unittest.TestSuite()
https://bitbucket.org/galaxy/galaxy-central/commits/35ae5ce8be84/
Changeset: 35ae5ce8be84
User: jmchilton
Date: 2013-12-11 16:55:54
Summary: Higher-level abstractions for defining annotation, tag, and rating mappings...
... as well unit tests.
Affected #: 2 files
diff -r 1b78bcbb1bc2bc0f39149726855418ccc890a3ff -r 35ae5ce8be84dcccadaf58c9b569fb9cf9daccbf lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -1050,8 +1050,11 @@
Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
Column( "key", TrimmedString( 32 ), index=True, unique=True ) )
+
# With the tables defined we can define the mappers and setup the
# relationships between the model objects.
+def simple_mapping( model, **kwds ):
+ mapper( model, model.table, properties=kwds )
mapper( model.Sample, model.Sample.table,
@@ -1200,64 +1203,62 @@
mapper( model.ValidationError, model.ValidationError.table )
-mapper( model.HistoryDatasetAssociation, model.HistoryDatasetAssociation.table,
- properties=dict(
- dataset=relation(
- model.Dataset,
- primaryjoin=( model.Dataset.table.c.id == model.HistoryDatasetAssociation.table.c.dataset_id ), lazy=False ),
- # .history defined in History mapper
- copied_from_history_dataset_association=relation(
- model.HistoryDatasetAssociation,
- primaryjoin=( model.HistoryDatasetAssociation.table.c.copied_from_history_dataset_association_id == model.HistoryDatasetAssociation.table.c.id ),
- remote_side=[model.HistoryDatasetAssociation.table.c.id],
- uselist=False ),
- copied_to_history_dataset_associations=relation(
- model.HistoryDatasetAssociation,
- primaryjoin=( model.HistoryDatasetAssociation.table.c.copied_from_history_dataset_association_id == model.HistoryDatasetAssociation.table.c.id ) ),
- copied_from_library_dataset_dataset_association=relation(
- model.LibraryDatasetDatasetAssociation,
- primaryjoin=( model.HistoryDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == model.LibraryDatasetDatasetAssociation.table.c.id ),
- uselist=False ),
- copied_to_library_dataset_dataset_associations=relation(
- model.LibraryDatasetDatasetAssociation,
- primaryjoin=( model.HistoryDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == model.LibraryDatasetDatasetAssociation.table.c.id ) ),
- implicitly_converted_datasets=relation(
- model.ImplicitlyConvertedDatasetAssociation,
- primaryjoin=( model.ImplicitlyConvertedDatasetAssociation.table.c.hda_parent_id == model.HistoryDatasetAssociation.table.c.id ) ),
- implicitly_converted_parent_datasets=relation(
- model.ImplicitlyConvertedDatasetAssociation,
- primaryjoin=( model.ImplicitlyConvertedDatasetAssociation.table.c.hda_id == model.HistoryDatasetAssociation.table.c.id ) ),
- children=relation(
- model.HistoryDatasetAssociation,
- primaryjoin=( model.HistoryDatasetAssociation.table.c.parent_id == model.HistoryDatasetAssociation.table.c.id ),
- backref=backref( "parent", primaryjoin=( model.HistoryDatasetAssociation.table.c.parent_id == model.HistoryDatasetAssociation.table.c.id ), remote_side=[model.HistoryDatasetAssociation.table.c.id], uselist=False ) ),
- visible_children=relation(
- model.HistoryDatasetAssociation,
- primaryjoin=( ( model.HistoryDatasetAssociation.table.c.parent_id == model.HistoryDatasetAssociation.table.c.id ) & ( model.HistoryDatasetAssociation.table.c.visible == True ) ) ),
- tags=relation( model.HistoryDatasetAssociationTagAssociation, order_by=model.HistoryDatasetAssociationTagAssociation.table.c.id, backref='history_tag_associations' ),
- annotations=relation( model.HistoryDatasetAssociationAnnotationAssociation, order_by=model.HistoryDatasetAssociationAnnotationAssociation.table.c.id, backref="hdas" ),
- ratings=relation( model.HistoryDatasetAssociationRatingAssociation, order_by=model.HistoryDatasetAssociationRatingAssociation.table.c.id, backref="hdas" ) )
- )
+simple_mapping( model.HistoryDatasetAssociation,
+ dataset=relation(
+ model.Dataset,
+ primaryjoin=( model.Dataset.table.c.id == model.HistoryDatasetAssociation.table.c.dataset_id ), lazy=False ),
+ # .history defined in History mapper
+ copied_from_history_dataset_association=relation(
+ model.HistoryDatasetAssociation,
+ primaryjoin=( model.HistoryDatasetAssociation.table.c.copied_from_history_dataset_association_id == model.HistoryDatasetAssociation.table.c.id ),
+ remote_side=[model.HistoryDatasetAssociation.table.c.id],
+ uselist=False ),
+ copied_to_history_dataset_associations=relation(
+ model.HistoryDatasetAssociation,
+ primaryjoin=( model.HistoryDatasetAssociation.table.c.copied_from_history_dataset_association_id == model.HistoryDatasetAssociation.table.c.id ) ),
+ copied_from_library_dataset_dataset_association=relation(
+ model.LibraryDatasetDatasetAssociation,
+ primaryjoin=( model.HistoryDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == model.LibraryDatasetDatasetAssociation.table.c.id ),
+ uselist=False ),
+ copied_to_library_dataset_dataset_associations=relation(
+ model.LibraryDatasetDatasetAssociation,
+ primaryjoin=( model.HistoryDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == model.LibraryDatasetDatasetAssociation.table.c.id ) ),
+ implicitly_converted_datasets=relation(
+ model.ImplicitlyConvertedDatasetAssociation,
+ primaryjoin=( model.ImplicitlyConvertedDatasetAssociation.table.c.hda_parent_id == model.HistoryDatasetAssociation.table.c.id ) ),
+ implicitly_converted_parent_datasets=relation(
+ model.ImplicitlyConvertedDatasetAssociation,
+ primaryjoin=( model.ImplicitlyConvertedDatasetAssociation.table.c.hda_id == model.HistoryDatasetAssociation.table.c.id ) ),
+ children=relation(
+ model.HistoryDatasetAssociation,
+ primaryjoin=( model.HistoryDatasetAssociation.table.c.parent_id == model.HistoryDatasetAssociation.table.c.id ),
+ backref=backref( "parent", primaryjoin=( model.HistoryDatasetAssociation.table.c.parent_id == model.HistoryDatasetAssociation.table.c.id ), remote_side=[model.HistoryDatasetAssociation.table.c.id], uselist=False ) ),
+ visible_children=relation(
+ model.HistoryDatasetAssociation,
+ primaryjoin=( ( model.HistoryDatasetAssociation.table.c.parent_id == model.HistoryDatasetAssociation.table.c.id ) & ( model.HistoryDatasetAssociation.table.c.visible == True ) ) ),
+ tags=relation( model.HistoryDatasetAssociationTagAssociation, order_by=model.HistoryDatasetAssociationTagAssociation.table.c.id, backref='history_tag_associations' ),
+ annotations=relation( model.HistoryDatasetAssociationAnnotationAssociation, order_by=model.HistoryDatasetAssociationAnnotationAssociation.table.c.id, backref="hdas" ),
+ ratings=relation( model.HistoryDatasetAssociationRatingAssociation, order_by=model.HistoryDatasetAssociationRatingAssociation.table.c.id, backref="hdas" )
+)
-mapper( model.Dataset, model.Dataset.table,
- properties=dict(
- history_associations=relation(
- model.HistoryDatasetAssociation,
- primaryjoin=( model.Dataset.table.c.id == model.HistoryDatasetAssociation.table.c.dataset_id ) ),
- active_history_associations=relation(
- model.HistoryDatasetAssociation,
- primaryjoin=( ( model.Dataset.table.c.id == model.HistoryDatasetAssociation.table.c.dataset_id ) & ( model.HistoryDatasetAssociation.table.c.deleted == False ) & ( model.HistoryDatasetAssociation.table.c.purged == False ) ) ),
- purged_history_associations=relation(
- model.HistoryDatasetAssociation,
- primaryjoin=( ( model.Dataset.table.c.id == model.HistoryDatasetAssociation.table.c.dataset_id ) & ( model.HistoryDatasetAssociation.table.c.purged == True ) ) ),
- library_associations=relation(
- model.LibraryDatasetDatasetAssociation,
- primaryjoin=( model.Dataset.table.c.id == model.LibraryDatasetDatasetAssociation.table.c.dataset_id ) ),
- active_library_associations=relation(
- model.LibraryDatasetDatasetAssociation,
- primaryjoin=( ( model.Dataset.table.c.id == model.LibraryDatasetDatasetAssociation.table.c.dataset_id ) & ( model.LibraryDatasetDatasetAssociation.table.c.deleted == False ) ) ),
- tags=relation(model.DatasetTagAssociation, order_by=model.DatasetTagAssociation.table.c.id, backref='datasets')
- ) )
+simple_mapping( model.Dataset,
+ history_associations=relation(
+ model.HistoryDatasetAssociation,
+ primaryjoin=( model.Dataset.table.c.id == model.HistoryDatasetAssociation.table.c.dataset_id ) ),
+ active_history_associations=relation(
+ model.HistoryDatasetAssociation,
+ primaryjoin=( ( model.Dataset.table.c.id == model.HistoryDatasetAssociation.table.c.dataset_id ) & ( model.HistoryDatasetAssociation.table.c.deleted == False ) & ( model.HistoryDatasetAssociation.table.c.purged == False ) ) ),
+ purged_history_associations=relation(
+ model.HistoryDatasetAssociation,
+ primaryjoin=( ( model.Dataset.table.c.id == model.HistoryDatasetAssociation.table.c.dataset_id ) & ( model.HistoryDatasetAssociation.table.c.purged == True ) ) ),
+ library_associations=relation(
+ model.LibraryDatasetDatasetAssociation,
+ primaryjoin=( model.Dataset.table.c.id == model.LibraryDatasetDatasetAssociation.table.c.dataset_id ) ),
+ active_library_associations=relation(
+ model.LibraryDatasetDatasetAssociation,
+ primaryjoin=( ( model.Dataset.table.c.id == model.LibraryDatasetDatasetAssociation.table.c.dataset_id ) & ( model.LibraryDatasetDatasetAssociation.table.c.deleted == False ) ) ),
+ tags=relation(model.DatasetTagAssociation, order_by=model.DatasetTagAssociation.table.c.id, backref='datasets')
+)
mapper( model.HistoryDatasetAssociationDisplayAtAuthorization, model.HistoryDatasetAssociationDisplayAtAuthorization.table,
properties=dict( history_dataset_association = relation( model.HistoryDatasetAssociation ),
@@ -1751,90 +1752,63 @@
) )
# Tag tables.
+simple_mapping( model.Tag,
+ children=relation(model.Tag, backref=backref( 'parent', remote_side=[model.Tag.table.c.id] ) )
+)
-mapper( model.Tag, model.Tag.table,
- properties=dict( children=relation(model.Tag, backref=backref( 'parent', remote_side=[model.Tag.table.c.id] ) )
- ) )
-mapper( model.HistoryTagAssociation, model.HistoryTagAssociation.table,
- properties=dict( tag=relation(model.Tag, backref="tagged_histories"), user=relation( model.User ) )
- )
+def tag_mapping( tag_association_class, backref_name ):
+ simple_mapping( tag_association_class, tag=relation( model.Tag, backref=backref_name), user=relation( model.User ) )
-mapper( model.DatasetTagAssociation, model.DatasetTagAssociation.table,
- properties=dict( tag=relation(model.Tag, backref="tagged_datasets"), user=relation( model.User ) )
- )
+tag_mapping( model.HistoryTagAssociation, "tagged_histories" )
-mapper( model.HistoryDatasetAssociationTagAssociation, model.HistoryDatasetAssociationTagAssociation.table,
- properties=dict( tag=relation(model.Tag, backref="tagged_history_dataset_associations"), user=relation( model.User ) )
- )
+tag_mapping( model.DatasetTagAssociation, "tagged_datasets" )
-mapper( model.PageTagAssociation, model.PageTagAssociation.table,
- properties=dict( tag=relation(model.Tag, backref="tagged_pages"), user=relation( model.User ) )
- )
+tag_mapping( model.HistoryDatasetAssociationTagAssociation, "tagged_history_dataset_associations" )
-mapper( model.StoredWorkflowTagAssociation, model.StoredWorkflowTagAssociation.table,
- properties=dict( tag=relation(model.Tag, backref="tagged_workflows"), user=relation( model.User ) )
- )
+tag_mapping( model.PageTagAssociation, "tagged_pages" )
-mapper( model.WorkflowStepTagAssociation, model.WorkflowStepTagAssociation.table,
- properties=dict( tag=relation(model.Tag, backref="tagged_workflow_steps"), user=relation( model.User ) )
- )
+tag_mapping( model.StoredWorkflowTagAssociation, "tagged_workflows" )
-mapper( model.VisualizationTagAssociation, model.VisualizationTagAssociation.table,
- properties=dict( tag=relation(model.Tag, backref="tagged_visualizations"), user=relation( model.User ) )
- )
+tag_mapping( model.WorkflowStepTagAssociation, "tagged_workflow_steps" )
-mapper( model.ToolTagAssociation, model.ToolTagAssociation.table,
- properties=dict( tag=relation(model.Tag, backref="tagged_tools"), user=relation( model.User ) )
- )
+tag_mapping( model.VisualizationTagAssociation, "tagged_visualizations" )
+
+tag_mapping( model.ToolTagAssociation, "tagged_tools" )
+
# Annotation tables.
+def annotation_mapping( annotation_class, **kwds ):
+ kwds = dict( [ (key, relation( value ) ) for key, value in kwds.iteritems() ] )
+ simple_mapping( annotation_class, **dict(user=relation( model.User ), **kwds ) )
-mapper( model.HistoryAnnotationAssociation, model.HistoryAnnotationAssociation.table,
- properties=dict( history=relation( model.History ), user=relation( model.User ) )
- )
+annotation_mapping( model.HistoryAnnotationAssociation, history=model.History )
-mapper( model.HistoryDatasetAssociationAnnotationAssociation, model.HistoryDatasetAssociationAnnotationAssociation.table,
- properties=dict( hda=relation( model.HistoryDatasetAssociation ), user=relation( model.User ) )
- )
+annotation_mapping( model.HistoryDatasetAssociationAnnotationAssociation, hda=model.HistoryDatasetAssociation )
-mapper( model.StoredWorkflowAnnotationAssociation, model.StoredWorkflowAnnotationAssociation.table,
- properties=dict( stored_workflow=relation( model.StoredWorkflow ), user=relation( model.User ) )
- )
+annotation_mapping( model.StoredWorkflowAnnotationAssociation, stored_workflow=model.StoredWorkflow )
-mapper( model.WorkflowStepAnnotationAssociation, model.WorkflowStepAnnotationAssociation.table,
- properties=dict( workflow_step=relation( model.WorkflowStep ), user=relation( model.User ) )
- )
+annotation_mapping( model.WorkflowStepAnnotationAssociation, workflow_step=model.WorkflowStep )
-mapper( model.PageAnnotationAssociation, model.PageAnnotationAssociation.table,
- properties=dict( page=relation( model.Page ), user=relation( model.User ) )
- )
+annotation_mapping( model.PageAnnotationAssociation, page=model.Page )
-mapper( model.VisualizationAnnotationAssociation, model.VisualizationAnnotationAssociation.table,
- properties=dict( visualization=relation( model.Visualization ), user=relation( model.User ) )
- )
+annotation_mapping( model.VisualizationAnnotationAssociation, visualization=model.Visualization )
+
# Rating tables.
+def rating_mapping( rating_class, **kwds ):
+ kwds = dict( [ (key, relation( value ) ) for key, value in kwds.iteritems() ] )
+ simple_mapping( rating_class, **dict(user=relation( model.User ), **kwds ) )
-mapper( model.HistoryRatingAssociation, model.HistoryRatingAssociation.table,
- properties=dict( history=relation( model.History ), user=relation( model.User ) )
- )
+rating_mapping( model.HistoryRatingAssociation, history=model.History )
-mapper( model.HistoryDatasetAssociationRatingAssociation, model.HistoryDatasetAssociationRatingAssociation.table,
- properties=dict( hda=relation( model.HistoryDatasetAssociation ), user=relation( model.User ) )
- )
+rating_mapping( model.HistoryDatasetAssociationRatingAssociation, hda=model.HistoryDatasetAssociation )
-mapper( model.StoredWorkflowRatingAssociation, model.StoredWorkflowRatingAssociation.table,
- properties=dict( stored_workflow=relation( model.StoredWorkflow ), user=relation( model.User ) )
- )
+rating_mapping( model.StoredWorkflowRatingAssociation, stored_workflow=model.StoredWorkflow )
-mapper( model.PageRatingAssociation, model.PageRatingAssociation.table,
- properties=dict( page=relation( model.Page ), user=relation( model.User ) )
- )
+rating_mapping( model.PageRatingAssociation, page=model.Page )
-mapper( model.VisualizationRatingAssociation, model.VisualizationRatingAssociation.table,
- properties=dict( visualization=relation( model.Visualization ), user=relation( model.User ) )
- )
+rating_mapping( model.VisualizationRatingAssociation, visualizaiton=model.Visualization )
#Data Manager tables
mapper( model.DataManagerHistoryAssociation, model.DataManagerHistoryAssociation.table,
diff -r 1b78bcbb1bc2bc0f39149726855418ccc890a3ff -r 35ae5ce8be84dcccadaf58c9b569fb9cf9daccbf test/unit/test_galaxy_mapping.py
--- a/test/unit/test_galaxy_mapping.py
+++ b/test/unit/test_galaxy_mapping.py
@@ -4,9 +4,138 @@
class MappingTests( unittest.TestCase ):
+ def test_annotations( self ):
+ model = self.model
+
+ u = model.User( email="annotator(a)example.com", password="password" )
+ self.persist( u )
+
+ def persist_and_check_annotation( annotation_class, **kwds ):
+ annotated_association = annotation_class()
+ annotated_association.annotation = "Test Annotation"
+ annotated_association.user = u
+ for key, value in kwds.iteritems():
+ setattr(annotated_association, key, value)
+ self.persist( annotated_association )
+ self.expunge()
+ stored_annotation = self.query( annotation_class ).all()[0]
+ assert stored_annotation.annotation == "Test Annotation"
+ assert stored_annotation.user.email == "annotator(a)example.com"
+
+ sw = model.StoredWorkflow()
+ sw.user = u
+ self.persist( sw )
+ persist_and_check_annotation( model.StoredWorkflowAnnotationAssociation, stored_workflow=sw )
+
+ workflow = model.Workflow()
+ workflow.stored_workflow = sw
+ self.persist( workflow )
+
+ ws = model.WorkflowStep()
+ ws.workflow = workflow
+ self.persist( ws )
+ persist_and_check_annotation( model.WorkflowStepAnnotationAssociation, workflow_step=ws )
+
+ h = model.History( name="History for Annotation", user=u)
+ self.persist( h )
+ persist_and_check_annotation( model.HistoryAnnotationAssociation, history=h )
+
+ d1 = model.HistoryDatasetAssociation( extension="txt", history=h, create_dataset=True, sa_session=model.session )
+ self.persist( d1 )
+ persist_and_check_annotation( model.HistoryDatasetAssociationAnnotationAssociation, hda=d1 )
+
+ page = model.Page()
+ page.user = u
+ self.persist( page )
+ persist_and_check_annotation( model.PageAnnotationAssociation, page=page )
+
+ visualization = model.Visualization()
+ visualization.user = u
+ self.persist( visualization )
+ persist_and_check_annotation( model.VisualizationAnnotationAssociation, visualization=visualization )
+
+ def test_ratings( self ):
+ model = self.model
+
+ u = model.User( email="rater(a)example.com", password="password" )
+ self.persist( u )
+
+ def persist_and_check_rating( rating_class, **kwds ):
+ rating_association = rating_class()
+ rating_association.rating = 5
+ rating_association.user = u
+ for key, value in kwds.iteritems():
+ setattr(rating_association, key, value)
+ self.persist( rating_association )
+ self.expunge()
+ stored_annotation = self.query( rating_class ).all()[0]
+ assert stored_annotation.rating == 5
+ assert stored_annotation.user.email == "rater(a)example.com"
+
+ sw = model.StoredWorkflow()
+ sw.user = u
+ self.persist( sw )
+ persist_and_check_rating( model.StoredWorkflowRatingAssociation, stored_workflow=sw )
+
+ h = model.History( name="History for Rating", user=u)
+ self.persist( h )
+ persist_and_check_rating( model.HistoryRatingAssociation, history=h )
+
+ d1 = model.HistoryDatasetAssociation( extension="txt", history=h, create_dataset=True, sa_session=model.session )
+ self.persist( d1 )
+ persist_and_check_rating( model.HistoryDatasetAssociationRatingAssociation, hda=d1 )
+
+ page = model.Page()
+ page.user = u
+ self.persist( page )
+ persist_and_check_rating( model.PageRatingAssociation, page=page )
+
+ visualization = model.Visualization()
+ visualization.user = u
+ self.persist( visualization )
+ persist_and_check_rating( model.VisualizationRatingAssociation, visualization=visualization )
+
+ def test_tags( self ):
+ model = self.model
+
+ my_tag = model.Tag(name="Test Tag")
+ u = model.User( email="tagger(a)example.com", password="password" )
+ self.persist( my_tag, u )
+
+ def tag_and_test( taggable_object, tag_association_class, backref_name ):
+ assert len( getattr(self.query( model.Tag ).filter( model.Tag.name == "Test Tag" ).all()[0], backref_name) ) == 0
+
+ tag_association = tag_association_class()
+ tag_association.tag = my_tag
+ taggable_object.tags = [ tag_association ]
+ self.persist( tag_association, taggable_object )
+
+ assert len( getattr(self.query( model.Tag ).filter( model.Tag.name == "Test Tag" ).all()[0], backref_name) ) == 1
+
+ sw = model.StoredWorkflow()
+ sw.user = u
+ #self.persist( sw )
+ tag_and_test( sw, model.StoredWorkflowTagAssociation, "tagged_workflows" )
+
+ h = model.History( name="History for Tagging", user=u)
+ tag_and_test( h, model.HistoryTagAssociation, "tagged_histories" )
+
+ d1 = model.HistoryDatasetAssociation( extension="txt", history=h, create_dataset=True, sa_session=model.session )
+ tag_and_test( d1, model.HistoryDatasetAssociationTagAssociation, "tagged_history_dataset_associations" )
+
+ page = model.Page()
+ page.user = u
+ tag_and_test( page, model.PageTagAssociation, "tagged_pages" )
+
+ visualization = model.Visualization()
+ visualization.user = u
+ tag_and_test( visualization, model.VisualizationTagAssociation, "tagged_visualizations" )
+
def test_basic( self ):
model = self.model
+ original_user_count = len( model.session.query( model.User ).all() )
+
# Make some changes and commit them
u = model.User( email="james(a)foo.bar.baz", password="password" )
# gs = model.GalaxySession()
@@ -24,26 +153,31 @@
# Check
users = model.session.query( model.User ).all()
- assert len( users ) == 1
- assert users[0].email == "james(a)foo.bar.baz"
- assert users[0].password == "password"
- assert len( users[0].histories ) == 1
- assert users[0].histories[0].name == "History 1"
+ assert len( users ) == original_user_count + 1
+ user = [user for user in users if user.email == "james(a)foo.bar.baz"][0]
+ assert user.email == "james(a)foo.bar.baz"
+ assert user.password == "password"
+ assert len( user.histories ) == 1
+ assert user.histories[0].name == "History 1"
hists = model.session.query( model.History ).all()
- assert hists[0].name == "History 1"
- assert hists[1].name == ( "H" * 255 )
- assert hists[0].user == users[0]
- assert hists[1].user is None
- assert hists[1].datasets[0].metadata.chromCol == 1
+ hist0 = [history for history in hists if history.name == "History 1"][0]
+ hist1 = [history for history in hists if history.name == "H" * 255][0]
+ assert hist0.name == "History 1"
+ assert hist1.name == ( "H" * 255 )
+ assert hist0.user == user
+ assert hist1.user is None
+ assert hist1.datasets[0].metadata.chromCol == 1
# The filename test has moved to objecstore
- #id = hists[1].datasets[0].id
- #assert hists[1].datasets[0].file_name == os.path.join( "/tmp", *directory_hash_id( id ) ) + ( "/dataset_%d.dat" % id )
+ #id = hist1.datasets[0].id
+ #assert hist1.datasets[0].file_name == os.path.join( "/tmp", *directory_hash_id( id ) ) + ( "/dataset_%d.dat" % id )
# Do an update and check
- hists[1].name = "History 2b"
+ hist1.name = "History 2b"
self.expunge()
hists = model.session.query( model.History ).all()
- assert hists[0].name == "History 1"
- assert hists[1].name == "History 2b"
+ hist0 = [history for history in hists if history.name == "History 1"][0]
+ hist1 = [history for history in hists if history.name == "History 2b"][0]
+ assert hist0.name == "History 1"
+ assert hist1.name == "History 2b"
# gvk TODO need to ad test for GalaxySessions, but not yet sure what they should look like.
@classmethod
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: inithello: Add script to check the filesystem for empty tool dependency installation paths and optionally delete them.
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/df88d6121d48/
Changeset: df88d6121d48
User: inithello
Date: 2013-12-11 15:53:11
Summary: Add script to check the filesystem for empty tool dependency installation paths and optionally delete them.
Affected #: 1 file
diff -r 575625b28b035bb38e30c3ef994f0918844923e4 -r df88d6121d48b0b193d34445ce49916adf17a2d2 lib/tool_shed/scripts/check_filesystem_for_empty_tool_dependency_installation_paths.py
--- /dev/null
+++ b/lib/tool_shed/scripts/check_filesystem_for_empty_tool_dependency_installation_paths.py
@@ -0,0 +1,70 @@
+import argparse
+import os
+import sys
+import shutil
+
+new_path = [ os.path.join( os.getcwd(), "lib" ) ]
+new_path.extend( sys.path[1:] )
+sys.path = new_path
+
+from tool_shed.galaxy_install.tool_dependencies.fabric_util import INSTALLATION_LOG
+
+def main( args ):
+ empty_installation_paths = []
+ if not os.path.exists( args.basepath ):
+ print 'Tool dependency path %s does not exist.' % str( args.basepath )
+ return 1
+ print 'Checking path %s for empty tool dependency installation directories.' % args.basepath
+ for root, dirs, files in os.walk( args.basepath ):
+ path_parts = root.replace( args.basepath, '' ).lstrip( '/' ).split( os.sep )
+ # Skip certain special directories.
+ if '__virtualenv_src' in dirs:
+ dirs.remove( '__virtualenv_src' )
+ if 'environment_settings' in dirs:
+ dirs.remove( 'environment_settings' )
+ # Do not process the current path if it does not match the pattern
+ # <name>/<version>/<owner>/<repository>/<changeset>.
+ if len( path_parts ) != 5:
+ continue
+ # We have a tool dependency installation path.
+ no_dirs = False
+ no_files = False
+ if len( dirs ) == 0:
+ no_dirs = True
+ if len( files ) == 0 or len( files ) == 1 and INSTALLATION_LOG in files:
+ no_files = True
+ if no_files and no_dirs and root not in empty_installation_paths:
+ empty_installation_paths.append( root )
+ if len( empty_installation_paths ) > 0:
+ print 'The following %d tool dependency installation directories were found to be empty or contain only the file %s.' % \
+ ( len( empty_installation_paths ), INSTALLATION_LOG )
+ if args.delete:
+ for path in empty_installation_paths:
+ if os.path.exists( path ):
+ shutil.rmtree( path )
+ print 'Deleted %s.' % path
+ else:
+ for empty_installation_path in empty_installation_paths:
+ print empty_installation_path
+ else:
+ print 'No empty tool dependency installation directories found.'
+ return 0
+
+if __name__ == '__main__':
+ description = 'Determine if there are any tool dependency installation paths that should be removed. Remove them if '
+ description += 'the --delete command line argument is provided.'
+ parser = argparse.ArgumentParser( description=description )
+ parser.add_argument( '--delete',
+ dest='delete',
+ required=False,
+ action='store_true',
+ default=False,
+ help='Whether to delete empty folders or list them on exit.' )
+ parser.add_argument( '--basepath',
+ dest='basepath',
+ required=True,
+ action='store',
+ metavar='name',
+ help='The base path where tool dependencies are installed.' )
+ args = parser.parse_args()
+ sys.exit( main( args ) )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Fix for exception logging in Datatypes registry.
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/575625b28b03/
Changeset: 575625b28b03
User: dan
Date: 2013-12-11 15:48:47
Summary: Fix for exception logging in Datatypes registry.
Affected #: 1 file
diff -r 9e30fa92a4ab5531a834a1e9015a4e6d19ef8861 -r 575625b28b035bb38e30c3ef994f0918844923e4 lib/galaxy/datatypes/registry.py
--- a/lib/galaxy/datatypes/registry.py
+++ b/lib/galaxy/datatypes/registry.py
@@ -348,7 +348,7 @@
try:
aclass = getattr( module, datatype_class_name )()
except Exception, e:
- self.log.exception( 'Error calling method %s from class %s: %s' ( str( datatype_class_name ), str( module ), str( e ) ) )
+ self.log.exception( 'Error calling method %s from class %s: %s', str( datatype_class_name ), str( module ), str( e ) )
ok = False
if ok:
if deactivate:
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: dan: Rename functions to prevent encapsulation / name mangling in test_toolbox.py and test_data_managers.py
by commits-noreply@bitbucket.org 11 Dec '13
by commits-noreply@bitbucket.org 11 Dec '13
11 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9e30fa92a4ab/
Changeset: 9e30fa92a4ab
User: dan
Date: 2013-12-11 15:00:01
Summary: Rename functions to prevent encapsulation / name mangling in test_toolbox.py and test_data_managers.py
Affected #: 2 files
diff -r 4541fabfeacf4d166d33eb8da6ba7fd638721850 -r 9e30fa92a4ab5531a834a1e9015a4e6d19ef8861 test/functional/test_data_managers.py
--- a/test/functional/test_data_managers.py
+++ b/test/functional/test_data_managers.py
@@ -19,9 +19,9 @@
"""
shed_tool_id = self.shed_tool_id
- self.__handle_test_def_errors( testdef )
+ self._handle_test_def_errors( testdef )
- galaxy_interactor = self.__galaxy_interactor( testdef )
+ galaxy_interactor = self._galaxy_interactor( testdef )
test_history = galaxy_interactor.new_history() #history where inputs will be put, if any
@@ -41,50 +41,11 @@
self.assertTrue( data_list )
- self.__verify_outputs( testdef, data_manager_history, shed_tool_id, data_list, galaxy_interactor )
+ self._verify_outputs( testdef, data_manager_history, shed_tool_id, data_list, galaxy_interactor )
self.switch_history( id=self.security.encode_id( test_history.id ) )
galaxy_interactor.delete_history( test_history )
-
-
- #Methods below are from test_toolbox.py:ToolTestCase, but are not inherited properly
-
- def __galaxy_interactor( self, testdef ):
- return build_interactor( self, testdef.interactor )
-
- def __handle_test_def_errors(self, testdef):
- # If the test generation had an error, raise
- if testdef.error:
- if testdef.exception:
- raise testdef.exception
- else:
- raise Exception( "Test parse failure" )
-
- def __verify_outputs( self, testdef, history, shed_tool_id, data_list, galaxy_interactor ):
- maxseconds = testdef.maxseconds
-
- for output_index, output_tuple in enumerate(testdef.outputs):
- # Get the correct hid
- name, outfile, attributes = output_tuple
- try:
- output_data = data_list[ name ]
- except (TypeError, KeyError):
- # Legacy - fall back on ordered data list access if data_list is
- # just a list (case with twill variant or if output changes its
- # name).
- if hasattr(data_list, "values"):
- output_data = data_list.values()[ output_index ]
- else:
- output_data = data_list[ len(data_list) - len(testdef.outputs) + output_index ]
- self.assertTrue( output_data is not None )
- try:
- galaxy_interactor.verify_output( history, output_data, outfile, attributes=attributes, shed_tool_id=shed_tool_id, maxseconds=maxseconds )
- except Exception:
- for stream in ['stdout', 'stderr']:
- stream_output = galaxy_interactor.get_job_stream( history, output_data, stream=stream )
- print >>sys.stderr, self._format_stream( stream_output, stream=stream, format=True )
- raise
def build_tests( tmp_dir=None, testing_shed_tools=False, master_api_key=None, user_api_key=None ):
"""
diff -r 4541fabfeacf4d166d33eb8da6ba7fd638721850 -r 9e30fa92a4ab5531a834a1e9015a4e6d19ef8861 test/functional/test_toolbox.py
--- a/test/functional/test_toolbox.py
+++ b/test/functional/test_toolbox.py
@@ -20,9 +20,9 @@
"""
shed_tool_id = self.shed_tool_id
- self.__handle_test_def_errors( testdef )
+ self._handle_test_def_errors( testdef )
- galaxy_interactor = self.__galaxy_interactor( testdef )
+ galaxy_interactor = self._galaxy_interactor( testdef )
test_history = galaxy_interactor.new_history()
@@ -31,14 +31,14 @@
data_list = galaxy_interactor.run_tool( testdef, test_history )
self.assertTrue( data_list )
- self.__verify_outputs( testdef, test_history, shed_tool_id, data_list, galaxy_interactor )
+ self._verify_outputs( testdef, test_history, shed_tool_id, data_list, galaxy_interactor )
galaxy_interactor.delete_history( test_history )
- def __galaxy_interactor( self, testdef ):
+ def _galaxy_interactor( self, testdef ):
return build_interactor( self, testdef.interactor )
- def __handle_test_def_errors(self, testdef):
+ def _handle_test_def_errors(self, testdef):
# If the test generation had an error, raise
if testdef.error:
if testdef.exception:
@@ -46,7 +46,7 @@
else:
raise Exception( "Test parse failure" )
- def __verify_outputs( self, testdef, history, shed_tool_id, data_list, galaxy_interactor ):
+ def _verify_outputs( self, testdef, history, shed_tool_id, data_list, galaxy_interactor ):
maxseconds = testdef.maxseconds
for output_index, output_tuple in enumerate(testdef.outputs):
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: History API, show: include user_id
by commits-noreply@bitbucket.org 10 Dec '13
by commits-noreply@bitbucket.org 10 Dec '13
10 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4541fabfeacf/
Changeset: 4541fabfeacf
User: carlfeberhard
Date: 2013-12-10 22:18:25
Summary: History API, show: include user_id
Affected #: 1 file
diff -r da82785d730737313cf9af7348791cb4b0afc937 -r 4541fabfeacf4d166d33eb8da6ba7fd638721850 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -474,6 +474,9 @@
"""Returns history data in the form of a dictionary.
"""
history_dict = history.to_dict( view='element', value_mapper={ 'id':trans.security.encode_id })
+ history_dict[ 'user_id' ] = None
+ if history.user_id:
+ history_dict[ 'user_id' ] = trans.security.encode_id( history.user_id )
history_dict[ 'nice_size' ] = history.get_disk_size( nice_size=True )
history_dict[ 'annotation' ] = history.get_item_annotation_str( trans.sa_session, trans.user, history )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Fix for defining an error message when installing a tool dependency along with a tool shed repository.
by commits-noreply@bitbucket.org 10 Dec '13
by commits-noreply@bitbucket.org 10 Dec '13
10 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/da82785d7307/
Changeset: da82785d7307
User: greg
Date: 2013-12-10 21:27:51
Summary: Fix for defining an error message when installing a tool dependency along with a tool shed repository.
Affected #: 1 file
diff -r 8bdb1113ad0425aab54f31b4c5a37fe456a675d2 -r da82785d730737313cf9af7348791cb4b0afc937 lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
@@ -93,7 +93,7 @@
env_file_builder.append_line( action="source", value=required_tool_dependency_env_file_path )
return_code = env_file_builder.return_code
if return_code:
- error_message = 'Error defining env.sh file for package %s, return_code: %s' % ( str( package_name, str( return_code ) ) )
+ error_message = 'Error defining env.sh file for package %s, return_code: %s' % ( str( package_name ), str( return_code ) )
tool_dependency = tool_dependency_util.handle_tool_dependency_installation_error( app,
tool_dependency,
error_message,
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: Scatterplot (framework): remove backbone-relational
by commits-noreply@bitbucket.org 10 Dec '13
by commits-noreply@bitbucket.org 10 Dec '13
10 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8bdb1113ad04/
Changeset: 8bdb1113ad04
User: carlfeberhard
Date: 2013-12-10 20:11:37
Summary: Scatterplot (framework): remove backbone-relational
Affected #: 1 file
diff -r d5217f01960360a9d7298fa679b839c806cab893 -r 8bdb1113ad0425aab54f31b4c5a37fe456a675d2 config/plugins/visualizations/scatterplot/templates/scatterplot.mako
--- a/config/plugins/visualizations/scatterplot/templates/scatterplot.mako
+++ b/config/plugins/visualizations/scatterplot/templates/scatterplot.mako
@@ -15,7 +15,6 @@
<script type="text/javascript" src="/static/scripts/libs/jquery/jquery.migrate.js"></script><script type="text/javascript" src="/static/scripts/libs/underscore.js"></script><script type="text/javascript" src="/static/scripts/libs/backbone/backbone.js"></script>
-<script type="text/javascript" src="/static/scripts/libs/backbone/backbone-relational.js"></script><script type="text/javascript" src="/static/scripts/libs/handlebars.runtime.js"></script><script type="text/javascript" src="/static/scripts/libs/d3.js"></script><script type="text/javascript" src="/static/scripts/libs/bootstrap.js"></script>
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: dan: Add Functional Testing support for locally and ToolShed installed Data Managers.
by commits-noreply@bitbucket.org 10 Dec '13
by commits-noreply@bitbucket.org 10 Dec '13
10 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d5217f019603/
Changeset: d5217f019603
User: dan
Date: 2013-12-10 18:59:29
Summary: Add Functional Testing support for locally and ToolShed installed Data Managers.
Affected #: 7 files
diff -r e76d57c33b48638268f9f4428165d1041298fc4b -r d5217f01960360a9d7298fa679b839c806cab893 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -394,6 +394,10 @@
return tool
#No tool matches by version, simply return the first available tool found
return rval[0]
+ #We now likely have a Toolshed guid passed in, but no supporting database entries
+ #If the tool exists by exact id and is loaded then provide exact match within a list
+ if tool_id in self.tools_by_id:
+ return[ self.tools_by_id[ tool_id ] ]
return None
def get_loaded_tools_by_lineage( self, tool_id ):
diff -r e76d57c33b48638268f9f4428165d1041298fc4b -r d5217f01960360a9d7298fa679b839c806cab893 lib/galaxy/tools/data_manager/manager.py
--- a/lib/galaxy/tools/data_manager/manager.py
+++ b/lib/galaxy/tools/data_manager/manager.py
@@ -133,7 +133,16 @@
self.tool_shed_repository_info_dict = dict( tool_shed=tool_shed, name=repository_name, owner=repository_owner, installed_changeset_revision=installed_changeset_revision )
#get tool_shed repo id
tool_shed_repository = suc.get_tool_shed_repository_by_shed_name_owner_installed_changeset_revision( self.data_managers.app, tool_shed, repository_name, repository_owner, installed_changeset_revision )
- tool_shed_repository_id = self.data_managers.app.security.encode_id( tool_shed_repository.id )
+ if tool_shed_repository is None:
+ log.warning( 'Could not determine tool shed repository from database. This should only ever happen when running tests.' )
+ #we'll set tool_path manually here from shed_conf_file
+ tool_shed_repository_id = None
+ try:
+ tool_path = util.parse_xml( elem.get( 'shed_conf_file' ) ).getroot().get( 'tool_path', tool_path )
+ except Exception, e:
+ log.error( 'Error determining tool_path for Data Manager during testing: %s', e )
+ else:
+ tool_shed_repository_id = self.data_managers.app.security.encode_id( tool_shed_repository.id )
#use shed_conf_file to determine tool_path
shed_conf_file = elem.get( "shed_conf_file", None )
if shed_conf_file:
diff -r e76d57c33b48638268f9f4428165d1041298fc4b -r d5217f01960360a9d7298fa679b839c806cab893 run_functional_tests.sh
--- a/run_functional_tests.sh
+++ b/run_functional_tests.sh
@@ -16,6 +16,7 @@
echo "'run_functional_tests.sh -workflow test.xml' for running a workflow test case as defined by supplied workflow xml test file"
echo "'run_functional_tests.sh -framework' for running through example tool tests testing framework features in test/functional/tools"
echo "'run_functional_tests.sh -framework -id toolid' for testing one framework tool (in test/functional/tools/) with id 'toolid'"
+ echo "'run_functional_tests.sh -data_managers -id data_manager_id' for testing one Data Manager with id 'data_manager_id'"
elif [ $1 = '-id' ]; then
python ./scripts/functional_tests.py -v functional.test_toolbox:TestForTool_$2 --with-nosehtml --html-report-file run_functional_tests.html
elif [ $1 = '-sid' ]; then
@@ -51,6 +52,14 @@
fi
elif [ $1 = '-workflow' ]; then
python ./scripts/functional_tests.py -v functional.test_workflow:WorkflowTestCase --with-nosehtml --html-report-file ./test/tool_shed/run_functional_tests.html -workflow $2
+elif [ $1 = '-data_managers' ]; then
+ if [ ! $2 ]; then
+ python ./scripts/functional_tests.py -v functional.test_data_managers --with-nosehtml --html-report-file run_functional_tests.html -data_managers
+ elif [ $2 = '-id' ]; then
+ python ./scripts/functional_tests.py -v functional.test_data_managers:TestForDataManagerTool_$3 --with-nosehtml --html-report-file run_functional_tests.html -data_managers
+ else
+ python ./scripts/functional_tests.py -v functional.test_data_managers --with-nosehtml --html-report-file run_functional_tests.html -data_managers
+ fi
elif [ $1 = '-framework' ]; then
if [ ! $2 ]; then
python ./scripts/functional_tests.py -v functional.test_toolbox --with-nosehtml --html-report-file run_functional_tests.html -framework
diff -r e76d57c33b48638268f9f4428165d1041298fc4b -r d5217f01960360a9d7298fa679b839c806cab893 scripts/functional_tests.py
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -335,6 +335,11 @@
except OSError:
pass
+ #Data Manager testing temp path
+ #For storing Data Manager outputs and .loc files so that real ones don't get clobbered
+ data_manager_test_tmp_path = tempfile.mkdtemp( prefix='data_manager_test_tmp', dir=galaxy_test_tmp_dir )
+ galaxy_data_manager_data_path = tempfile.mkdtemp( prefix='data_manager_tool-data', dir=data_manager_test_tmp_path )
+
# ---- Build Application --------------------------------------------------
master_api_key = os.environ.get( "GALAXY_TEST_MASTER_API_KEY", default_galaxy_master_key )
app = None
@@ -360,6 +365,7 @@
tool_config_file=tool_config_file,
tool_data_table_config_path=tool_data_table_config_path,
tool_path=tool_path,
+ galaxy_data_manager_data_path=galaxy_data_manager_data_path,
tool_parse_help=False,
update_integrated_tool_panel=False,
use_heartbeat=False,
@@ -469,13 +475,24 @@
functional.test_workflow.WorkflowTestCase.workflow_test_file = workflow_test
functional.test_workflow.WorkflowTestCase.master_api_key = master_api_key
functional.test_workflow.WorkflowTestCase.user_api_key = os.environ.get( "GALAXY_TEST_USER_API_KEY", default_galaxy_user_key )
- import functional.test_toolbox
- functional.test_toolbox.toolbox = app.toolbox
- functional.test_toolbox.build_tests(
- testing_shed_tools=testing_shed_tools,
- master_api_key=master_api_key,
- user_api_key=os.environ.get( "GALAXY_TEST_USER_API_KEY", default_galaxy_user_key ),
- )
+ data_manager_test = __check_arg( '-data_managers', param=False )
+ if data_manager_test:
+ import functional.test_data_managers
+ functional.test_data_managers.data_managers = app.data_managers #seems like a hack...
+ functional.test_data_managers.build_tests(
+ tmp_dir=data_manager_test_tmp_path,
+ testing_shed_tools=testing_shed_tools,
+ master_api_key=master_api_key,
+ user_api_key=os.environ.get( "GALAXY_TEST_USER_API_KEY", default_galaxy_user_key ),
+ )
+ else: #when testing data managers, do not test toolbox
+ import functional.test_toolbox
+ functional.test_toolbox.toolbox = app.toolbox
+ functional.test_toolbox.build_tests(
+ testing_shed_tools=testing_shed_tools,
+ master_api_key=master_api_key,
+ user_api_key=os.environ.get( "GALAXY_TEST_USER_API_KEY", default_galaxy_user_key ),
+ )
test_config = nose.config.Config( env=os.environ, ignoreFiles=ignore_files, plugins=nose.plugins.manager.DefaultPluginManager() )
test_config.configure( sys.argv )
result = run_tests( test_config )
diff -r e76d57c33b48638268f9f4428165d1041298fc4b -r d5217f01960360a9d7298fa679b839c806cab893 test/functional/test_data_managers.py
--- /dev/null
+++ b/test/functional/test_data_managers.py
@@ -0,0 +1,149 @@
+import new
+import sys
+import tempfile
+import os.path
+import shutil
+from test_toolbox import ToolTestCase
+from base.interactor import build_interactor, stage_data_in_history
+import logging
+log = logging.getLogger( __name__ )
+
+data_managers = None
+
+class DataManagerToolTestCase( ToolTestCase ):
+ """Test case that runs Data Manager tests based on a `galaxy.tools.test.ToolTest`"""
+
+ def do_it( self, testdef ):
+ """
+ Run through a tool test case.
+ """
+ shed_tool_id = self.shed_tool_id
+
+ self.__handle_test_def_errors( testdef )
+
+ galaxy_interactor = self.__galaxy_interactor( testdef )
+
+ test_history = galaxy_interactor.new_history() #history where inputs will be put, if any
+
+ stage_data_in_history( galaxy_interactor, testdef.test_data(), test_history, shed_tool_id )
+
+ data_list = galaxy_interactor.run_tool( testdef, test_history ) #test_history will have inputs only, outputs are placed in the specialized data manager history
+
+ #FIXME: Move history determination and switching into the interactor
+ data_manager_history = None
+ for assoc in reversed( test_history.user.data_manager_histories ):
+ if not assoc.history.deleted:
+ data_manager_history = assoc.history
+ break
+ self.switch_history( id=self.security.encode_id( data_manager_history.id ) )
+ data_list = self.get_history_as_data_list()
+ #end
+
+ self.assertTrue( data_list )
+
+ self.__verify_outputs( testdef, data_manager_history, shed_tool_id, data_list, galaxy_interactor )
+
+ self.switch_history( id=self.security.encode_id( test_history.id ) )
+
+ galaxy_interactor.delete_history( test_history )
+
+
+ #Methods below are from test_toolbox.py:ToolTestCase, but are not inherited properly
+
+ def __galaxy_interactor( self, testdef ):
+ return build_interactor( self, testdef.interactor )
+
+ def __handle_test_def_errors(self, testdef):
+ # If the test generation had an error, raise
+ if testdef.error:
+ if testdef.exception:
+ raise testdef.exception
+ else:
+ raise Exception( "Test parse failure" )
+
+ def __verify_outputs( self, testdef, history, shed_tool_id, data_list, galaxy_interactor ):
+ maxseconds = testdef.maxseconds
+
+ for output_index, output_tuple in enumerate(testdef.outputs):
+ # Get the correct hid
+ name, outfile, attributes = output_tuple
+ try:
+ output_data = data_list[ name ]
+ except (TypeError, KeyError):
+ # Legacy - fall back on ordered data list access if data_list is
+ # just a list (case with twill variant or if output changes its
+ # name).
+ if hasattr(data_list, "values"):
+ output_data = data_list.values()[ output_index ]
+ else:
+ output_data = data_list[ len(data_list) - len(testdef.outputs) + output_index ]
+ self.assertTrue( output_data is not None )
+ try:
+ galaxy_interactor.verify_output( history, output_data, outfile, attributes=attributes, shed_tool_id=shed_tool_id, maxseconds=maxseconds )
+ except Exception:
+ for stream in ['stdout', 'stderr']:
+ stream_output = galaxy_interactor.get_job_stream( history, output_data, stream=stream )
+ print >>sys.stderr, self._format_stream( stream_output, stream=stream, format=True )
+ raise
+
+def build_tests( tmp_dir=None, testing_shed_tools=False, master_api_key=None, user_api_key=None ):
+ """
+ If the module level variable `data_managers` is set, generate `DataManagerToolTestCase`
+ classes for all of its tests and put them into this modules globals() so
+ they can be discovered by nose.
+ """
+
+ if data_managers is None:
+ log.warning( 'data_managers was not set for Data Manager functional testing. Will not test.' )
+ return
+
+ # Push all the data_managers tests to module level
+ G = globals()
+
+ # Eliminate all previous tests from G.
+ for key, val in G.items():
+ if key.startswith( 'TestForDataManagerTool_' ):
+ del G[ key ]
+
+ #first we will loop through data table loc files and copy them to temporary location, then swap out filenames:
+ for data_table_name, data_table in data_managers.app.tool_data_tables.get_tables().iteritems():
+ for filename, value in list( data_table.filenames.items() ):
+ new_filename = tempfile.NamedTemporaryFile( prefix=os.path.basename( filename ), dir=tmp_dir ).name
+ try:
+ shutil.copy( filename, new_filename )
+ except IOError, e:
+ log.warning( "Failed to copy '%s' to '%s', will create empty file at '%s': %s", filename, new_filename, new_filename, e )
+ open( new_filename, 'wb' ).close()
+ if 'filename' in value:
+ value[ 'filename' ] = new_filename
+ del data_table.filenames[ filename ] #remove filename:value pair
+ data_table.filenames[ new_filename ] = value #add new value by
+
+ for i, ( data_manager_id, data_manager ) in enumerate( data_managers.data_managers.iteritems() ):
+ tool = data_manager.tool
+ if not tool:
+ log.warning( "No Tool has been specified for Data Manager: %s", data_manager_id )
+ tool_data_tables = data_manager.data_managers.app.tool_data_tables
+ if tool.tests:
+ ##fixme data_manager.tool_shed_repository_info_dict should be filled when is toolshed based
+ shed_tool_id = None if not testing_shed_tools else tool.id
+ # Create a new subclass of ToolTestCase, dynamically adding methods
+ # named test_tool_XXX that run each test defined in the tool config.
+ name = "TestForDataManagerTool_" + data_manager_id.replace( ' ', '_' )
+ baseclasses = ( DataManagerToolTestCase, )
+ namespace = dict()
+ for j, testdef in enumerate( tool.tests ):
+ def make_test_method( td ):
+ def test_tool( self ):
+ self.do_it( td )
+ return test_tool
+ test_method = make_test_method( testdef )
+ test_method.__doc__ = "%s ( %s ) > %s" % ( tool.name, tool.id, testdef.name )
+ namespace[ 'test_tool_%06d' % j ] = test_method
+ namespace[ 'shed_tool_id' ] = shed_tool_id
+ namespace[ 'master_api_key' ] = master_api_key
+ namespace[ 'user_api_key' ] = user_api_key
+ # 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
diff -r e76d57c33b48638268f9f4428165d1041298fc4b -r d5217f01960360a9d7298fa679b839c806cab893 test/functional/test_toolbox.py
--- a/test/functional/test_toolbox.py
+++ b/test/functional/test_toolbox.py
@@ -2,11 +2,14 @@
import sys
from base.twilltestcase import TwillTestCase
from base.interactor import build_interactor, stage_data_in_history
+from galaxy.tools import DataManagerTool
import logging
log = logging.getLogger( __name__ )
toolbox = None
+#Do not test Data Managers as part of the standard Tool Test Framework.
+TOOL_TYPES_NO_TEST = ( DataManagerTool, )
class ToolTestCase( TwillTestCase ):
"""Abstract test case that runs tests based on a `galaxy.tools.test.ToolTest`"""
@@ -88,6 +91,9 @@
for i, tool_id in enumerate( toolbox.tools_by_id ):
tool = toolbox.get_tool( tool_id )
+ if isinstance( tool, TOOL_TYPES_NO_TEST ):
+ #We do not test certain types of tools (e.g. Data Manager tools) as part of ToolTestCase
+ continue
if tool.tests:
shed_tool_id = None if not testing_shed_tools else tool.id
# Create a new subclass of ToolTestCase, dynamically adding methods
diff -r e76d57c33b48638268f9f4428165d1041298fc4b -r d5217f01960360a9d7298fa679b839c806cab893 test/tool_shed/test_data/1460_files/data_manager_files/test_data_manager.tar
Binary file test/tool_shed/test_data/1460_files/data_manager_files/test_data_manager.tar has changed
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
10 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/e76d57c33b48/
Changeset: e76d57c33b48
User: carlfeberhard
Date: 2013-12-10 17:23:03
Summary: (pack scripts)
Affected #: 1 file
diff -r a06cdfe0a180c4c8aefaeb2bbc51d54ef7d64380 -r e76d57c33b48638268f9f4428165d1041298fc4b 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 @@
-define(["mvc/dataset/hda-model","mvc/dataset/hda-base"],function(d,a){var f=a.HDABaseView.extend(LoggableMixin).extend({initialize:function(g){a.HDABaseView.prototype.initialize.call(this,g);this.hasUser=g.hasUser;this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton,this._render_rerunButton]},_render_titleButtons:function(){return a.HDABaseView.prototype._render_titleButtons.call(this).concat([this._render_editButton(),this._render_deleteButton()])},_render_editButton:function(){if((this.model.get("state")===d.HistoryDatasetAssociation.STATES.NEW)||(this.model.get("state")===d.HistoryDatasetAssociation.STATES.DISCARDED)||(this.model.get("state")===d.HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){return null}var i=this.model.get("purged"),g=this.model.get("deleted"),h={title:_l("Edit Attributes"),href:this.urls.edit,target:this.linkTarget,classes:"dataset-edit"};if(g||i){h.disabled=true;if(i){h.title=_l("Cannot edit attributes of datasets removed from disk")}else{if(g){h.title=_l("Undelete dataset to edit attributes")}}}else{if(this.model.get("state")===d.HistoryDatasetAssociation.STATES.UPLOAD){h.disabled=true;h.title=_l("This dataset must finish uploading before it can be edited")}}h.faIcon="fa-pencil";return faIconButton(h)},_render_deleteButton:function(){if((this.model.get("state")===d.HistoryDatasetAssociation.STATES.NEW)||(this.model.get("state")===d.HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){return null}var g=this,h={title:_l("Delete"),classes:"dataset-delete",onclick:function(){g.$el.find(".icon-btn.dataset-delete").trigger("mouseout");g.model["delete"]()}};if(this.model.get("deleted")||this.model.get("purged")){h={title:_l("Dataset is already deleted"),disabled:true}}h.faIcon="fa-times";return faIconButton(h)},_render_errButton:function(){if(this.model.get("state")!==d.HistoryDatasetAssociation.STATES.ERROR){return null}return faIconButton({title:_l("View or report this error"),href:this.urls.report_error,target:this.linkTarget,faIcon:"fa-bug"})},_render_rerunButton:function(){return faIconButton({title:_l("Run this job again"),href:this.urls.rerun,target:this.linkTarget,faIcon:"fa-refresh"})},_render_visualizationsButton:function(){var g=this.model.get("visualizations");if((!this.hasUser)||(!this.model.hasData())||(_.isEmpty(g))){return null}if(_.isObject(g[0])){return this._render_visualizationsFrameworkButton(g)}if(!this.urls.visualization){return null}var i=this.model.get("dbkey"),m=this.urls.visualization,j={},n={dataset_id:this.model.get("id"),hda_ldda:"hda"};if(i){n.dbkey=i}var h=faIconButton({title:_l("Visualize"),href:this.urls.visualization,faIcon:"fa-bar-chart-o"});var l=this;function k(o){switch(o){case"trackster":return b(m,n,i);case"scatterplot":return e(m,n,l.linkTarget);default:return function(){Galaxy.frame.add({title:"Visualization",type:"url",content:m+"/"+o+"?"+$.param(n)})}}}if(g.length===1){h.attr("data-original-title",g[0]);h.click(k(g[0]))}else{_.each(g,function(p){var o=p.charAt(0).toUpperCase()+p.slice(1);j[_l(o)]=k(p)});make_popupmenu(h,j)}return h},_render_visualizationsFrameworkButton:function(g){if(!(this.model.hasData())||!(g&&!_.isEmpty(g))){return null}var i=faIconButton({title:_l("Visualize"),faIcon:"fa-bar-chart-o"});i.addClass("visualize-icon");if(_.keys(g).length===1){i.attr("title",_.keys(g)[0]);i.attr("href",_.values(g)[0])}else{var j=[];_.each(g,function(k){j.push(k)});var h=new PopupMenu(i,j)}return i},_render_body_failed_metadata:function(){var h=$("<a/>").attr({href:this.urls.edit,target:this.linkTarget}).text(_l("set it manually or retry auto-detection")),g=$("<span/>").text(". "+_l("You may be able to")+" ").append(h),i=a.HDABaseView.prototype._render_body_failed_metadata.call(this);i.find(".warningmessagesmall strong").append(g);return i},_render_body_error:function(){var g=a.HDABaseView.prototype._render_body_error.call(this);g.find(".dataset-actions .left").prepend(this._render_errButton());return g},_render_body_ok:function(){var g=a.HDABaseView.prototype._render_body_ok.call(this);if(this.model.isDeletedOrPurged()){return g}this.makeDbkeyEditLink(g);if(this.hasUser){g.find(".dataset-actions .left").append(this._render_visualizationsButton());this._renderTags(g);this._renderAnnotation(g)}return g},_renderTags:function(g){this.tagsEditor=new TagsEditor({model:this.model,el:g.find(".tags-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit dataset tags"),classes:"dataset-tag-btn",faIcon:"fa-tags"}).appendTo(g.find(".dataset-actions .right"))})},_renderAnnotation:function(g){this.annotationEditor=new AnnotationEditor({model:this.model,el:g.find(".annotation-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit dataset annotation"),classes:"dataset-annotate-btn",faIcon:"fa-comment"}).appendTo(g.find(".dataset-actions .right"))})},makeDbkeyEditLink:function(g){if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){g.find(".dataset-dbkey .value").replaceWith($('<a target="'+this.linkTarget+'">?</a>').attr("href",this.urls.edit))}},events:_.extend(_.clone(a.HDABaseView.prototype.events),{"click .dataset-undelete":function(g){this.model.undelete();return false},"click .dataset-unhide":function(g){this.model.unhide();return false},"click .dataset-purge":"confirmPurge"}),confirmPurge:function c(g){this.model.purge();return false},toString:function(){var g=(this.model)?(this.model+""):("(no model)");return"HDAView("+g+")"}});function e(g,i,h){action=function(){Galaxy.frame.add({title:"Scatterplot",type:"url",content:g+"/scatterplot?"+$.param(i),target:h,scratchbook:true});$("div.popmenu-wrapper").remove();return false};return action}function b(g,i,h){return function(){var j={};if(h){j["f-dbkey"]=h}$.ajax({url:g+"/list_tracks?"+$.param(j),dataType:"html",error:function(){alert(("Could not add this dataset to browser")+".")},success:function(k){var l=window.parent;l.Galaxy.modal.show({title:"View Data in a New or Saved Visualization",buttons:{Cancel:function(){l.Galaxy.modal.hide()},"View in saved visualization":function(){l.Galaxy.modal.show({title:"Add Data to Saved Visualization",body:k,buttons:{Cancel:function(){l.Galaxy.modal.hide()},"Add to visualization":function(){$(l.document).find("input[name=id]:checked").each(function(){l.Galaxy.modal.hide();var m=$(this).val();i.id=m;l.Galaxy.frame.add({title:"Trackster",type:"url",content:g+"/trackster?"+$.param(i),scratchbook:true})})}}})},"View in new visualization":function(){l.Galaxy.modal.hide();var m=g+"/trackster?"+$.param(i);l.Galaxy.frame.add({title:"Trackster",type:"url",content:m,scratchbook:true})}}})}});return false}}return{HDAEditView:f}});
\ No newline at end of file
+define(["mvc/dataset/hda-model","mvc/dataset/hda-base"],function(d,a){var f=a.HDABaseView.extend(LoggableMixin).extend({initialize:function(g){a.HDABaseView.prototype.initialize.call(this,g);this.hasUser=g.hasUser;this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton,this._render_rerunButton]},_render_titleButtons:function(){return a.HDABaseView.prototype._render_titleButtons.call(this).concat([this._render_editButton(),this._render_deleteButton()])},_render_editButton:function(){if((this.model.get("state")===d.HistoryDatasetAssociation.STATES.NEW)||(this.model.get("state")===d.HistoryDatasetAssociation.STATES.DISCARDED)||(this.model.get("state")===d.HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){return null}var i=this.model.get("purged"),g=this.model.get("deleted"),h={title:_l("Edit Attributes"),href:this.urls.edit,target:this.linkTarget,classes:"dataset-edit"};if(g||i){h.disabled=true;if(i){h.title=_l("Cannot edit attributes of datasets removed from disk")}else{if(g){h.title=_l("Undelete dataset to edit attributes")}}}else{if(this.model.get("state")===d.HistoryDatasetAssociation.STATES.UPLOAD){h.disabled=true;h.title=_l("This dataset must finish uploading before it can be edited")}}h.faIcon="fa-pencil";return faIconButton(h)},_render_deleteButton:function(){if((this.model.get("state")===d.HistoryDatasetAssociation.STATES.NEW)||(this.model.get("state")===d.HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){return null}var g=this,h={title:_l("Delete"),classes:"dataset-delete",onclick:function(){g.$el.find(".icon-btn.dataset-delete").trigger("mouseout");g.model["delete"]()}};if(this.model.get("deleted")||this.model.get("purged")){h={title:_l("Dataset is already deleted"),disabled:true}}h.faIcon="fa-times";return faIconButton(h)},_render_errButton:function(){if(this.model.get("state")!==d.HistoryDatasetAssociation.STATES.ERROR){return null}return faIconButton({title:_l("View or report this error"),href:this.urls.report_error,target:this.linkTarget,faIcon:"fa-bug"})},_render_rerunButton:function(){return faIconButton({title:_l("Run this job again"),href:this.urls.rerun,target:this.linkTarget,faIcon:"fa-refresh"})},_render_visualizationsButton:function(){var n=this.model.get("visualizations");if((!this.hasUser)||(!this.model.hasData())||(_.isEmpty(n))){return null}if(_.isObject(n[0])){return this._render_visualizationsFrameworkButton(n)}if(!this.urls.visualization){return null}var k=this.model.get("dbkey"),g=this.urls.visualization,j={},h={dataset_id:this.model.get("id"),hda_ldda:"hda"};if(k){h.dbkey=k}var l=faIconButton({title:_l("Visualize"),faIcon:"fa-bar-chart-o"});var m=this;function i(p){switch(p){case"trackster":return b(g,h,k);case"scatterplot":return e(g,h,m.linkTarget);default:return function(){Galaxy.frame.add({title:"Visualization",type:"url",content:g+"/"+p+"?"+$.param(h)})}}}function o(p){return p.charAt(0).toUpperCase()+p.slice(1)}if(n.length===1){l.attr("data-original-title",_l("Visualize in ")+_l(o(n[0])));l.click(i(n[0]))}else{_.each(n,function(p){j[_l(o(p))]=i(p)});make_popupmenu(l,j)}return l},_render_visualizationsFrameworkButton:function(g){if(!(this.model.hasData())||!(g&&!_.isEmpty(g))){return null}var i=faIconButton({title:_l("Visualize"),faIcon:"fa-bar-chart-o"});i.addClass("visualize-icon");if(_.keys(g).length===1){i.attr("title",_.keys(g)[0]);i.attr("href",_.values(g)[0])}else{var j=[];_.each(g,function(k){j.push(k)});var h=new PopupMenu(i,j)}return i},_render_body_failed_metadata:function(){var h=$("<a/>").attr({href:this.urls.edit,target:this.linkTarget}).text(_l("set it manually or retry auto-detection")),g=$("<span/>").text(". "+_l("You may be able to")+" ").append(h),i=a.HDABaseView.prototype._render_body_failed_metadata.call(this);i.find(".warningmessagesmall strong").append(g);return i},_render_body_error:function(){var g=a.HDABaseView.prototype._render_body_error.call(this);g.find(".dataset-actions .left").prepend(this._render_errButton());return g},_render_body_ok:function(){var g=a.HDABaseView.prototype._render_body_ok.call(this);if(this.model.isDeletedOrPurged()){return g}this.makeDbkeyEditLink(g);if(this.hasUser){g.find(".dataset-actions .left").append(this._render_visualizationsButton());this._renderTags(g);this._renderAnnotation(g)}return g},_renderTags:function(g){this.tagsEditor=new TagsEditor({model:this.model,el:g.find(".tags-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit dataset tags"),classes:"dataset-tag-btn",faIcon:"fa-tags"}).appendTo(g.find(".dataset-actions .right"))})},_renderAnnotation:function(g){this.annotationEditor=new AnnotationEditor({model:this.model,el:g.find(".annotation-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit dataset annotation"),classes:"dataset-annotate-btn",faIcon:"fa-comment"}).appendTo(g.find(".dataset-actions .right"))})},makeDbkeyEditLink:function(g){if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){g.find(".dataset-dbkey .value").replaceWith($('<a target="'+this.linkTarget+'">?</a>').attr("href",this.urls.edit))}},events:_.extend(_.clone(a.HDABaseView.prototype.events),{"click .dataset-undelete":function(g){this.model.undelete();return false},"click .dataset-unhide":function(g){this.model.unhide();return false},"click .dataset-purge":"confirmPurge"}),confirmPurge:function c(g){this.model.purge();return false},toString:function(){var g=(this.model)?(this.model+""):("(no model)");return"HDAView("+g+")"}});function e(g,i,h){action=function(){Galaxy.frame.add({title:"Scatterplot",type:"url",content:g+"/scatterplot?"+$.param(i),target:h,scratchbook:true});$("div.popmenu-wrapper").remove();return false};return action}function b(g,i,h){return function(){var j={};if(h){j["f-dbkey"]=h}$.ajax({url:g+"/list_tracks?"+$.param(j),dataType:"html",error:function(){alert(("Could not add this dataset to browser")+".")},success:function(k){var l=window.parent;l.Galaxy.modal.show({title:"View Data in a New or Saved Visualization",buttons:{Cancel:function(){l.Galaxy.modal.hide()},"View in saved visualization":function(){l.Galaxy.modal.show({title:"Add Data to Saved Visualization",body:k,buttons:{Cancel:function(){l.Galaxy.modal.hide()},"Add to visualization":function(){$(l.document).find("input[name=id]:checked").each(function(){l.Galaxy.modal.hide();var m=$(this).val();i.id=m;l.Galaxy.frame.add({title:"Trackster",type:"url",content:g+"/trackster?"+$.param(i),scratchbook:true})})}}})},"View in new visualization":function(){l.Galaxy.modal.hide();var m=g+"/trackster?"+$.param(i);l.Galaxy.frame.add({title:"Trackster",type:"url",content:m,scratchbook:true})}}})}});return false}}return{HDAEditView:f}});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: History panel: fix href/click fn collision in visualizations button
by commits-noreply@bitbucket.org 10 Dec '13
by commits-noreply@bitbucket.org 10 Dec '13
10 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a06cdfe0a180/
Changeset: a06cdfe0a180
User: carlfeberhard
Date: 2013-12-10 17:21:16
Summary: History panel: fix href/click fn collision in visualizations button
Affected #: 1 file
diff -r 9202b520908dd37a25fce0cf53b585df10b6b59e -r a06cdfe0a180c4c8aefaeb2bbc51d54ef7d64380 static/scripts/mvc/dataset/hda-edit.js
--- a/static/scripts/mvc/dataset/hda-edit.js
+++ b/static/scripts/mvc/dataset/hda-edit.js
@@ -184,7 +184,6 @@
var $icon = faIconButton({
title : _l( 'Visualize' ),
- href : this.urls.visualization,
faIcon : 'fa-bar-chart-o'
});
@@ -199,9 +198,8 @@
case 'scatterplot':
return create_scatterplot_action_fn( visualization_url, params, hdaView.linkTarget );
default:
- return function(){// add widget
- Galaxy.frame.add(
- {
+ return function(){
+ Galaxy.frame.add({
title : "Visualization",
type : "url",
content : visualization_url + '/' + visualization + '?' + $.param( params )
@@ -210,16 +208,19 @@
}
}
+ function titleCase( string ){
+ return string.charAt( 0 ).toUpperCase() + string.slice( 1 );
+ }
+
// No need for popup menu because there's a single visualization.
if( visualizations.length === 1 ){
- $icon.attr( 'data-original-title', visualizations[0] );
+ $icon.attr( 'data-original-title', _l( 'Visualize in ' ) + _l( titleCase( visualizations[0] ) ) );
$icon.click( create_viz_action( visualizations[0] ) );
// >1: Populate menu dict with visualization fns, make the popupmenu
} else {
_.each( visualizations, function( visualization ) {
- var titleCaseVisualization = visualization.charAt( 0 ).toUpperCase() + visualization.slice( 1 );
- popup_menu_dict[ _l( titleCaseVisualization ) ] = create_viz_action( visualization );
+ popup_menu_dict[ _l( titleCase( visualization ) ) ] = create_viz_action( visualization );
});
make_popupmenu( $icon, popup_menu_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: dan: Allow ftp for GALAXY_TEST_DB_TEMPLATE and stricter check for protocol URL prefixes.
by commits-noreply@bitbucket.org 10 Dec '13
by commits-noreply@bitbucket.org 10 Dec '13
10 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9202b520908d/
Changeset: 9202b520908d
User: dan
Date: 2013-12-10 17:08:13
Summary: Allow ftp for GALAXY_TEST_DB_TEMPLATE and stricter check for protocol URL prefixes.
Affected #: 1 file
diff -r 738839e77188c2f42d956998f38daea619f3c35e -r 9202b520908dd37a25fce0cf53b585df10b6b59e scripts/functional_tests.py
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -182,7 +182,7 @@
if os.path.exists( source ):
shutil.copy( source, db_path )
assert os.path.exists( db_path )
- elif source.lower().startswith( "http" ):
+ elif source.lower().startswith( ( "http://", "https://", "ftp://" ) ):
urllib.urlretrieve( source, db_path )
else:
raise Exception( "Failed to copy database template from source %s" % source )
@@ -323,6 +323,7 @@
# GALAXY_TEST_DBURI. The former requires a lot of setup
# time, the latter results in test failures in certain
# cases (namely tool shed tests expecting clean database).
+ log.debug( "Copying database template from %s.", os.environ['GALAXY_TEST_DB_TEMPLATE'] )
__copy_database_template(os.environ['GALAXY_TEST_DB_TEMPLATE'], db_path)
database_auto_migrate = True
database_connection = 'sqlite:///%s' % db_path
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0