galaxy-commits
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
November 2012
- 1 participants
- 133 discussions
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/f3c2243d9f6c/
changeset: f3c2243d9f6c
user: carlfeberhard
date: 2012-11-15 18:03:38
summary: Enabling client side history panel
affected #: 4 files
diff -r b8c331135aedd1754ae170f311c33e2da315189c -r f3c2243d9f6c215f1b2d2ed01409d24b6e317075 lib/galaxy/webapps/galaxy/controllers/root.py
--- a/lib/galaxy/webapps/galaxy/controllers/root.py
+++ b/lib/galaxy/webapps/galaxy/controllers/root.py
@@ -122,18 +122,17 @@
show_hidden = util.string_as_bool_or_none( show_hidden )
datasets = []
- history_panel_template = "root/history.mako"
+ history_panel_template = "root/alternate_history.mako"
- # history panel -> backbone (WIP - uncomment next to use)
- #USE_ALTERNATE = True
- if 'USE_ALTERNATE' in locals():
+ # keeping this switch here for a while - uncomment the next line to use the original mako history panel
+ #USE_ORIGINAL = True
+ if 'USE_ORIGINAL' in locals():
+ datasets = self.get_history_datasets( trans, history, show_deleted, show_hidden, show_purged )
+ history_panel_template = "root/history.mako"
+
+ else:
datasets = self.get_history_datasets( trans, history,
show_deleted=True, show_hidden=True, show_purged=True )
- #datasets = self.get_history_datasets( trans, history, show_deleted, show_hidden, show_purged )
- history_panel_template = "root/alternate_history.mako"
-
- else:
- datasets = self.get_history_datasets( trans, history, show_deleted, show_hidden, show_purged )
return trans.stream_template_mako( history_panel_template,
history = history,
diff -r b8c331135aedd1754ae170f311c33e2da315189c -r f3c2243d9f6c215f1b2d2ed01409d24b6e317075 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
@@ -47,7 +47,7 @@
function program7(depth0,data) {
- return "Click to see more actions";}
+ return "Click to see more actions for this history";}
function program9(depth0,data) {
diff -r b8c331135aedd1754ae170f311c33e2da315189c -r f3c2243d9f6c215f1b2d2ed01409d24b6e317075 static/scripts/templates/history-templates.html
--- a/static/scripts/templates/history-templates.html
+++ b/static/scripts/templates/history-templates.html
@@ -17,7 +17,7 @@
{{/if}}
</div>
- <a id="history-action-popup" class="tooltip" title="{{#local}}Click to see more actions{{/local}}"
+ <a id="history-action-popup" class="tooltip" title="{{#local}}Click to see more actions for this history{{/local}}"
href="javascript:void(0);" style="float: right;"><span class="ficon cogs large"></span></a>
diff -r b8c331135aedd1754ae170f311c33e2da315189c -r f3c2243d9f6c215f1b2d2ed01409d24b6e317075 templates/root/alternate_history.mako
--- a/templates/root/alternate_history.mako
+++ b/templates/root/alternate_history.mako
@@ -284,7 +284,6 @@
// global backbone models
top.Galaxy.currUser = top.Galaxy.currUser;
top.Galaxy.currHistoryPanel = top.Galaxy.currHistoryPanel;
- top.Galaxy.historyPanels = top.Galaxy.historyPanels || [];
top.Galaxy.paths = galaxy_paths;
@@ -327,6 +326,7 @@
// i don't like this history+user relationship, but user authentication changes views/behaviour
history.user = user;
+ // create the history panel
var historyPanel = new HistoryPanel({
model : new History( history, hdas ),
urlTemplates : galaxy_paths.attributes,
@@ -380,7 +380,6 @@
if( !Galaxy.currHistoryPanel ){ Galaxy.currHistoryPanel = historyPanel; }
- if( !( historyPanel in Galaxy.historyPanels ) ){ Galaxy.historyPanels.unshift( historyPanel ); }
return;
});
https://bitbucket.org/galaxy/galaxy-central/changeset/0a1db9862210/
changeset: 0a1db9862210
user: carlfeberhard
date: 2012-11-15 18:04:17
summary: pack scripts
affected #: 1 file
diff -r f3c2243d9f6c215f1b2d2ed01409d24b6e317075 -r 0a1db986221074e72131afd6d16320357843c5f8 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(k,A,y,q,I){y=y||k.helpers;var z="",n,m,v=this,e="function",c=y.blockHelperMissing,d=this.escapeExpression;function t(N,M){var K="",L,J;K+='\n <div id="history-name" class="tooltip editable-text"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(2,s,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(2,s,M)})}if(L||L===0){K+=L}K+='">';J=y.name;if(J){L=J.call(N,{hash:{}})}else{L=N.name;L=typeof L===e?L():L}K+=d(L)+"</div>\n ";return K}function s(K,J){return"Click to rename history"}function r(N,M){var K="",L,J;K+='\n <div id="history-name" class="tooltip"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(5,p,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(5,p,M)})}if(L||L===0){K+=L}K+='">';J=y.name;if(J){L=J.call(N,{hash:{}})}else{L=N.name;L=typeof L===e?L():L}K+=d(L)+"</div>\n ";return K}function p(K,J){return"You must be logged in to edit your history name"}function o(K,J){return"Click to see more actions"}function j(N,M){var K="",L,J;K+='\n <div id="history-secondary-links" style="float: right;">\n <a id="history-tag" title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(10,H,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(10,H,M)})}if(L||L===0){K+=L}K+='"\n class="icon-button tags tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n <a id="history-annotate" title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(12,G,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(12,G,M)})}if(L||L===0){K+=L}K+='"\n class="icon-button annotate tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n </div>\n ';return K}function H(K,J){return"Edit history tags"}function G(K,J){return"Edit history annotation"}function F(N,M){var K="",L,J;K+="\n ";J=y.warningmessagesmall;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(15,E,M)})}else{L=N.warningmessagesmall;L=typeof L===e?L():L}if(!y.warningmessagesmall){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(15,E,M)})}if(L||L===0){K+=L}K+="\n ";return K}function E(M,L){var K,J;J=y.local;if(J){K=J.call(M,{hash:{},inverse:v.noop,fn:v.program(16,D,L)})}else{K=M.local;K=typeof K===e?K():K}if(!y.local){K=c.call(M,K,{hash:{},inverse:v.noop,fn:v.program(16,D,L)})}if(K||K===0){return K}else{return""}}function D(K,J){return"You are currently viewing a deleted history!"}function C(N,M){var K="",L,J;K+='\n <div id="history-tag-annotation">\n\n <div id="history-tag-area" style="display: none">\n <strong>';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(19,B,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(19,B,M)})}if(L||L===0){K+=L}K+=':</strong>\n <div class="tag-elt"></div>\n </div>\n\n <div id="history-annotation-area" style="display: none">\n <strong>';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(21,l,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(21,l,M)})}if(L||L===0){K+=L}K+=':</strong>\n <div id="history-annotation-container">\n <div id="history-annotation" class="tooltip editable-text"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(23,i,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(23,i,M)})}if(L||L===0){K+=L}K+='">\n ';L=N.annotation;L=y["if"].call(N,L,{hash:{},inverse:v.program(27,g,M),fn:v.program(25,h,M)});if(L||L===0){K+=L}K+="\n </div>\n </div>\n </div>\n </div>\n ";return K}function B(K,J){return"Tags"}function l(K,J){return"Annotation"}function i(K,J){return"Click to edit annotation"}function h(N,M){var K="",L,J;K+="\n ";J=y.annotation;if(J){L=J.call(N,{hash:{}})}else{L=N.annotation;L=typeof L===e?L():L}K+=d(L)+"\n ";return K}function g(N,M){var K="",L,J;K+="\n <em>";J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(28,f,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(28,f,M)})}if(L||L===0){K+=L}K+="</em>\n ";return K}function f(K,J){return"Describe or add notes to history"}function x(N,M){var K="",L,J;K+='\n <div id="message-container">\n <div class="';J=y.status;if(J){L=J.call(N,{hash:{}})}else{L=N.status;L=typeof L===e?L():L}K+=d(L)+'message">\n ';J=y.message;if(J){L=J.call(N,{hash:{}})}else{L=N.message;L=typeof L===e?L():L}K+=d(L)+"\n </div><br />\n </div>\n ";return K}function w(K,J){return"You are over your disk quota.\n Tool execution is on hold until your disk usage drops below your allocated quota."}function u(K,J){return"Your history is empty. Click 'Get Data' on the left pane to start"}z+='<div id="history-controls">\n <div id="history-title-area" class="historyLinks">\n\n ';z+='\n <div id="history-name-container" style="float: left;">\n ';z+="\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.program(4,r,I),fn:v.program(1,t,I)});if(n||n===0){z+=n}z+='\n </div>\n\n <a id="history-action-popup" class="tooltip" title="';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(7,o,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(7,o,I)})}if(n||n===0){z+=n}z+='"\n href="javascript:void(0);" style="float: right;">\n <span class="ficon cogs large"></span>\n </a>\n <div style="clear: both;"></div>\n </div>\n\n <div id="history-subtitle-area">\n <div id="history-size" style="float:left;">';m=y.nice_size;if(m){n=m.call(A,{hash:{}})}else{n=A.nice_size;n=typeof n===e?n():n}z+=d(n)+"</div>\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(9,j,I)});if(n||n===0){z+=n}z+='\n <div style="clear: both;"></div>\n </div>\n\n ';n=A.deleted;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(14,F,I)});if(n||n===0){z+=n}z+="\n\n ";z+="\n ";z+="\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(18,C,I)});if(n||n===0){z+=n}z+="\n\n ";n=A.message;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(30,x,I)});if(n||n===0){z+=n}z+='\n\n <div id="quota-message-container" style="display: none">\n <div id="quota-message" class="errormessage">\n ';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(32,w,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(32,w,I)})}if(n||n===0){z+=n}z+='\n </div>\n </div>\n</div>\n\n<div id="';m=y.id;if(m){n=m.call(A,{hash:{}})}else{n=A.id;n=typeof n===e?n():n}z+=d(n)+'-datasets" class="history-datasets-list"></div>\n\n<div class="infomessagesmall" id="emptyHistoryMessage" style="display: none;">\n ';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(34,u,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(34,u,I)})}if(n||n===0){z+=n}z+="\n</div>";return z})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(k,A,y,q,I){y=y||k.helpers;var z="",n,m,v=this,e="function",c=y.blockHelperMissing,d=this.escapeExpression;function t(N,M){var K="",L,J;K+='\n <div id="history-name" class="tooltip editable-text"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(2,s,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(2,s,M)})}if(L||L===0){K+=L}K+='">';J=y.name;if(J){L=J.call(N,{hash:{}})}else{L=N.name;L=typeof L===e?L():L}K+=d(L)+"</div>\n ";return K}function s(K,J){return"Click to rename history"}function r(N,M){var K="",L,J;K+='\n <div id="history-name" class="tooltip"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(5,p,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(5,p,M)})}if(L||L===0){K+=L}K+='">';J=y.name;if(J){L=J.call(N,{hash:{}})}else{L=N.name;L=typeof L===e?L():L}K+=d(L)+"</div>\n ";return K}function p(K,J){return"You must be logged in to edit your history name"}function o(K,J){return"Click to see more actions for this history"}function j(N,M){var K="",L,J;K+='\n <div id="history-secondary-links" style="float: right;">\n <a id="history-tag" title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(10,H,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(10,H,M)})}if(L||L===0){K+=L}K+='"\n class="icon-button tags tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n <a id="history-annotate" title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(12,G,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(12,G,M)})}if(L||L===0){K+=L}K+='"\n class="icon-button annotate tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n </div>\n ';return K}function H(K,J){return"Edit history tags"}function G(K,J){return"Edit history annotation"}function F(N,M){var K="",L,J;K+="\n ";J=y.warningmessagesmall;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(15,E,M)})}else{L=N.warningmessagesmall;L=typeof L===e?L():L}if(!y.warningmessagesmall){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(15,E,M)})}if(L||L===0){K+=L}K+="\n ";return K}function E(M,L){var K,J;J=y.local;if(J){K=J.call(M,{hash:{},inverse:v.noop,fn:v.program(16,D,L)})}else{K=M.local;K=typeof K===e?K():K}if(!y.local){K=c.call(M,K,{hash:{},inverse:v.noop,fn:v.program(16,D,L)})}if(K||K===0){return K}else{return""}}function D(K,J){return"You are currently viewing a deleted history!"}function C(N,M){var K="",L,J;K+='\n <div id="history-tag-annotation">\n\n <div id="history-tag-area" style="display: none">\n <strong>';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(19,B,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(19,B,M)})}if(L||L===0){K+=L}K+=':</strong>\n <div class="tag-elt"></div>\n </div>\n\n <div id="history-annotation-area" style="display: none">\n <strong>';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(21,l,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(21,l,M)})}if(L||L===0){K+=L}K+=':</strong>\n <div id="history-annotation-container">\n <div id="history-annotation" class="tooltip editable-text"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(23,i,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(23,i,M)})}if(L||L===0){K+=L}K+='">\n ';L=N.annotation;L=y["if"].call(N,L,{hash:{},inverse:v.program(27,g,M),fn:v.program(25,h,M)});if(L||L===0){K+=L}K+="\n </div>\n </div>\n </div>\n </div>\n ";return K}function B(K,J){return"Tags"}function l(K,J){return"Annotation"}function i(K,J){return"Click to edit annotation"}function h(N,M){var K="",L,J;K+="\n ";J=y.annotation;if(J){L=J.call(N,{hash:{}})}else{L=N.annotation;L=typeof L===e?L():L}K+=d(L)+"\n ";return K}function g(N,M){var K="",L,J;K+="\n <em>";J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(28,f,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(28,f,M)})}if(L||L===0){K+=L}K+="</em>\n ";return K}function f(K,J){return"Describe or add notes to history"}function x(N,M){var K="",L,J;K+='\n <div id="message-container">\n <div class="';J=y.status;if(J){L=J.call(N,{hash:{}})}else{L=N.status;L=typeof L===e?L():L}K+=d(L)+'message">\n ';J=y.message;if(J){L=J.call(N,{hash:{}})}else{L=N.message;L=typeof L===e?L():L}K+=d(L)+"\n </div><br />\n </div>\n ";return K}function w(K,J){return"You are over your disk quota.\n Tool execution is on hold until your disk usage drops below your allocated quota."}function u(K,J){return"Your history is empty. Click 'Get Data' on the left pane to start"}z+='<div id="history-controls">\n <div id="history-title-area" class="historyLinks">\n\n ';z+='\n <div id="history-name-container" style="float: left;">\n ';z+="\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.program(4,r,I),fn:v.program(1,t,I)});if(n||n===0){z+=n}z+='\n </div>\n\n <a id="history-action-popup" class="tooltip" title="';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(7,o,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(7,o,I)})}if(n||n===0){z+=n}z+='"\n href="javascript:void(0);" style="float: right;">\n <span class="ficon cogs large"></span>\n </a>\n <div style="clear: both;"></div>\n </div>\n\n <div id="history-subtitle-area">\n <div id="history-size" style="float:left;">';m=y.nice_size;if(m){n=m.call(A,{hash:{}})}else{n=A.nice_size;n=typeof n===e?n():n}z+=d(n)+"</div>\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(9,j,I)});if(n||n===0){z+=n}z+='\n <div style="clear: both;"></div>\n </div>\n\n ';n=A.deleted;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(14,F,I)});if(n||n===0){z+=n}z+="\n\n ";z+="\n ";z+="\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(18,C,I)});if(n||n===0){z+=n}z+="\n\n ";n=A.message;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(30,x,I)});if(n||n===0){z+=n}z+='\n\n <div id="quota-message-container" style="display: none">\n <div id="quota-message" class="errormessage">\n ';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(32,w,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(32,w,I)})}if(n||n===0){z+=n}z+='\n </div>\n </div>\n</div>\n\n<div id="';m=y.id;if(m){n=m.call(A,{hash:{}})}else{n=A.id;n=typeof n===e?n():n}z+=d(n)+'-datasets" class="history-datasets-list"></div>\n\n<div class="infomessagesmall" id="emptyHistoryMessage" style="display: none;">\n ';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(34,u,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(34,u,I)})}if(n||n===0){z+=n}z+="\n</div>";return z})})();
\ 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: natefoo: Fix the task runner I broke in 73e05bc. Thanks John Chilton.
by Bitbucket 15 Nov '12
by Bitbucket 15 Nov '12
15 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/b8c331135aed/
changeset: b8c331135aed
user: natefoo
date: 2012-11-15 17:48:00
summary: Fix the task runner I broke in 73e05bc. Thanks John Chilton.
affected #: 1 file
diff -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 -r b8c331135aedd1754ae170f311c33e2da315189c lib/galaxy/jobs/mapper.py
--- a/lib/galaxy/jobs/mapper.py
+++ b/lib/galaxy/jobs/mapper.py
@@ -116,7 +116,7 @@
def __cache_job_runner_url( self, params ):
# If there's already a runner set in the Job object, don't overwrite from the tool
- if self.job_runner_name is not None:
+ if self.job_runner_name is not None and not self.job_runner_name.startswith('tasks'):
raw_job_runner_url = self.job_runner_name
else:
raw_job_runner_url = self.job_wrapper.tool.get_job_runner_url( params )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/2d1402caf21a/
changeset: 2d1402caf21a
user: carlfeberhard
date: 2012-11-15 17:25:18
summary: static/scripts/mvc: jsDocs on all. I've used jsdoc-toolkit via node with success on these; the Rhino version should work also.
affected #: 11 files
diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/base-mvc.js
--- a/static/scripts/mvc/base-mvc.js
+++ b/static/scripts/mvc/base-mvc.js
@@ -43,14 +43,19 @@
//==============================================================================
-/**
- * Adds logging capabilities to your Models/Views
- * can be used with plain browser console (or something more complex like an AJAX logger)
+/** @class Mixin to add logging capabilities to an object.
+ * Designed to allow switching an objects log output off/on at one central
+ * statement. Can be used with plain browser console (or something more
+ * complex like an AJAX logger).
+ * <br />NOTE: currently only uses the console.debug log function
+ * (as opposed to debug, error, warn, etc.)
+ * @name LoggableMixin
*
- * add to your models/views at the definition using chaining:
+ * @example
+ * // Add to your models/views at the definition using chaining:
* var MyModel = BaseModel.extend( LoggableMixin ).extend({ // ... });
*
- * or - more explicitly AFTER the definition:
+ * // or - more explicitly AFTER the definition:
* var MyModel = BaseModel.extend({
* logger : console
* // ...
@@ -58,12 +63,19 @@
* })
* _.extend( MyModel.prototype, LoggableMixin )
*
- * NOTE: currently only uses the console.debug log function (as opposed to debug, error, warn, etc.)
*/
-var LoggableMixin = {
+var LoggableMixin = /** @lends LoggableMixin# */{
+
+ /** The logging object whose log function will be used to output
+ * messages. Null will supress all logging. Commonly set to console.
+ */
// replace null with console (if available) to see all logs
logger : null,
+ /** Output log messages/arguments to logger.
+ * @param {Arguments} ... (this function is variadic)
+ * @returns undefined if not this.logger
+ */
log : function(){
if( this.logger ){
return this.logger.log.apply( this.logger, arguments );
@@ -74,21 +86,29 @@
// =============================================================================
-/** Global string localization object (and global short form alias)
- * set with either:
- * GalaxyLocalization.setLocalizedString( original, localized )
- * GalaxyLocalization.setLocalizedString({ original1 : localized1, original2 : localized2 })
- * get with either:
- * GalaxyLocalization.localize( string )
- * _l( string )
+/** @class string localizer (and global short form alias)
+ *
+ * @example
+ * // set with either:
+ * GalaxyLocalization.setLocalizedString( original, localized )
+ * GalaxyLocalization.setLocalizedString({ original1 : localized1, original2 : localized2 })
+ * // get with either:
+ * GalaxyLocalization.localize( string )
+ * _l( string )
+ *
+ * @constructs
*/
//TODO: move to Galaxy.Localization (maybe galaxy.base.js)
var GalaxyLocalization = jQuery.extend( {}, {
+ /** shortened, alias reference to GalaxyLocalization.localize */
ALIAS_NAME : '_l',
+ /** map of available localized strings (english -> localized) */
localizedStrings : {},
- // Set a single English string -> localized string association, or set an entire map of those associations
- // Pass in either two strings (english, localized) or just an obj (map) of english : localized
+ /** Set a single English string -> localized string association, or set an entire map of those associations
+ * @param {String or Object} str_or_obj english (key) string or a map of english -> localized strings
+ * @param {String} localized string if str_or_obj was a string
+ */
setLocalizedString : function( str_or_obj, localizedString ){
//console.debug( this + '.setLocalizedString:', str_or_obj, localizedString );
var self = this;
@@ -117,7 +137,10 @@
}
},
- // Attempt to get a localized string for strToLocalize. If not found, return the original strToLocalize
+ /** Attempt to get a localized string for strToLocalize. If not found, return the original strToLocalize.
+ * @param {String} strToLocalize the string to localize
+ * @returns either the localized string if found or strToLocalize if not found
+ */
localize : function( strToLocalize ){
//console.debug( this + '.localize:', strToLocalize );
@@ -132,6 +155,7 @@
return this.localizedStrings[ strToLocalize ] || strToLocalize;
},
+ /** String representation. */
toString : function(){ return 'GalaxyLocalization'; }
});
@@ -146,16 +170,17 @@
//==============================================================================
/**
- * @class PersistantStorage
- * persistant storage adapter to:
- * provide an easy interface to object based storage using method chaining
- * allow easy change of the storage engine used (h5's local storage?)
+ * @class persistant storage adapter.
+ * Provides an easy interface to object based storage using method chaining.
+ * Allows easy change of the storage engine used (h5's local storage?).
+ * @augments StorageRecursionHelper
*
* @param {String} storageKey : the key the storage engine will place the storage object under
* @param {Object} storageDefaults : [optional] initial object to set up storage with
*
- * @example :
- * HistoryPanel.storage = new PersistanStorage( HistoryPanel.toString(), { visibleItems, {} })
+ * @example
+ * // example of construction and use
+ * HistoryPanel.storage = new PersistanStorage( HistoryPanel.toString(), { visibleItems, {} });
* itemView.bind( 'toggleBodyVisibility', function( id, visible ){
* if( visible ){
* HistoryPanel.storage.get( 'visibleItems' ).set( id, true );
@@ -163,6 +188,7 @@
* HistoryPanel.storage.get( 'visibleItems' ).deleteKey( id );
* }
* });
+ * @constructor
*/
var PersistantStorage = function( storageKey, storageDefaults ){
if( !storageKey ){
@@ -176,16 +202,21 @@
STORAGE_ENGINE_SETTER = jQuery.jStorage.set,
STORAGE_ENGINE_KEY_DELETER = jQuery.jStorage.deleteKey;
- // recursion helper for method chaining access
- var StorageRecursionHelper = function( data, parent ){
+ /** Inner, recursive, private class for method chaining access.
+ * @name StorageRecursionHelper
+ * @constructor
+ */
+ function StorageRecursionHelper( data, parent ){
//console.debug( 'new StorageRecursionHelper. data:', data );
data = data || {};
parent = parent || null;
- return {
- // get a value from the storage obj named 'key',
- // if it's an object - return a new StorageRecursionHelper wrapped around it
- // if it's something simpler - return the value
- // if this isn't passed a key - return the data at this level of recursion
+
+ return /** @lends StorageRecursionHelper.prototype */{
+ /** get a value from the storage obj named 'key',
+ * if it's an object - return a new StorageRecursionHelper wrapped around it
+ * if it's something simpler - return the value
+ * if this isn't passed a key - return the data at this level of recursion
+ */
get : function( key ){
//console.debug( this + '.get', key );
if( key === undefined ){
@@ -197,32 +228,33 @@
}
return undefined;
},
+ /** get the underlying data based on this key */
// set a value on the current data - then pass up to top to save current entire object in storage
set : function( key, value ){
//TODO: add parameterless variation setting the data somehow
// ??: difficult bc of obj by ref, closure
//console.debug( this + '.set', key, value );
data[ key ] = value;
- this.save();
+ this._save();
return this;
},
// remove a key at this level - then save entire (as 'set' above)
deleteKey : function( key ){
//console.debug( this + '.deleteKey', key );
delete data[ key ];
- this.save();
+ this._save();
return this;
},
// pass up the recursion chain (see below for base case)
- save : function(){
+ _save : function(){
//console.debug( this + '.save', parent );
- return parent.save();
+ return parent._save();
},
toString : function(){
return ( 'StorageRecursionHelper(' + data + ')' );
}
};
- };
+ }
//??: more readable to make another class?
var returnedStorage = {};
@@ -238,17 +270,26 @@
// the object returned by this constructor will be a modified StorageRecursionHelper
returnedStorage = new StorageRecursionHelper( data );
- // the base case for save()'s upward recursion - save everything to storage
- returnedStorage.save = function( newData ){
- //console.debug( returnedStorage, '.save:', JSON.stringify( returnedStorage.get() ) );
- STORAGE_ENGINE_SETTER( storageKey, returnedStorage.get() );
- };
- // delete function to remove the base data object from the storageEngine
- returnedStorage.destroy = function(){
- //console.debug( returnedStorage, '.destroy:' );
- STORAGE_ENGINE_KEY_DELETER( storageKey );
- };
- returnedStorage.toString = function(){ return 'PersistantStorage(' + data + ')'; };
+
+ jQuery.extend( returnedStorage, /** @lends PersistantStorage.prototype */{
+ /** The base case for save()'s upward recursion - save everything to storage.
+ * @private
+ * @param {Any} newData data object to save to storage
+ */
+ _save : function( newData ){
+ //console.debug( returnedStorage, '._save:', JSON.stringify( returnedStorage.get() ) );
+ return STORAGE_ENGINE_SETTER( storageKey, returnedStorage.get() );
+ },
+ /** Delete function to remove the entire base data object from the storageEngine.
+ */
+ destroy : function(){
+ //console.debug( returnedStorage, '.destroy:' );
+ return STORAGE_ENGINE_KEY_DELETER( storageKey );
+ },
+ /** String representation.
+ */
+ toString : function(){ return 'PersistantStorage(' + data + ')'; }
+ });
return returnedStorage;
};
diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/dataset/hda-base.js
--- a/static/scripts/mvc/dataset/hda-base.js
+++ b/static/scripts/mvc/dataset/hda-base.js
@@ -2,33 +2,47 @@
// "../mvc/base-mvc"
//], function(){
//==============================================================================
-/** read only view for HistoryDatasetAssociations
- *
+/** @class Read only view for HistoryDatasetAssociation.
+ * @name HDABaseView
+ *
+ * @augments BaseView
+ * @borrows LoggableMixin#logger as #logger
+ * @borrows LoggableMixin#log as #log
+ * @constructs
*/
-var HDABaseView = BaseView.extend( LoggableMixin ).extend({
- //??TODO: add alias in initialize this.hda = this.model?
- // view for HistoryDatasetAssociation model above
+var HDABaseView = BaseView.extend( LoggableMixin ).extend(
+/** @lends HDABaseView.prototype */{
- // uncomment this out see log messages
+ ///** logger used to record this.log messages, commonly set to console */
+ //// comment this out to suppress log output
//logger : console,
tagName : "div",
className : "historyItemContainer",
- // ................................................................................ SET UP
+ // ......................................................................... SET UP
+ /** Set up the view, cache url templates, bind listeners
+ * @param {Object} attributes
+ * @config {Object} urlTemplates nested object containing url templates for this view
+ * @throws 'needs urlTemplates' if urlTemplates isn't present
+ * @see Backbone.View#initialize
+ */
initialize : function( attributes ){
this.log( this + '.initialize:', attributes );
- // which buttons go in most states (ok/failed meta are more complicated)
+ /** list of rendering functions for the default, primary icon-buttons. */
this.defaultPrimaryActionButtonRenderers = [
this._render_showParamsButton
];
// render urlTemplates (gen. provided by GalaxyPaths) to urls
+ //TODO:?? render urls here or in render()?
if( !attributes.urlTemplates ){ throw( 'HDAView needs urlTemplates on initialize' ); }
- this.urls = this.renderUrls( attributes.urlTemplates, this.model.toJSON() );
+ /** web controller urls for functions relating to this hda. These
+ * are rendered from urlTemplates using the model data. */
+ this.urls = this._renderUrls( attributes.urlTemplates, this.model.toJSON() );
- // whether the body of this hda is expanded (shown)
+ /** is the body of this hda view expanded/not. */
this.expanded = attributes.expanded || false;
// re-render the entire view on any model change
@@ -38,22 +52,25 @@
//}, this );
},
- // urlTemplates is a map (or nested map) of underscore templates (currently, anyhoo)
- // use the templates to create the apropo urls for each action this ds could use
- renderUrls : function( urlTemplates, modelJson ){
+ /** render the urls for this hda using the model data and the url templates from initialize.
+ * @param {Object} urlTemplates a map (or nested map) of underscore templates (currently, anyhoo)
+ * @param {Object} modelJson data from the model
+ * @returns {Object} the templated urls
+ */
+ _renderUrls : function( urlTemplates, modelJson ){
var hdaView = this,
urls = {};
_.each( urlTemplates, function( urlTemplateOrObj, urlKey ){
// object == nested templates: recurse
if( _.isObject( urlTemplateOrObj ) ){
- urls[ urlKey ] = hdaView.renderUrls( urlTemplateOrObj, modelJson );
+ urls[ urlKey ] = hdaView._renderUrls( urlTemplateOrObj, modelJson );
// string == template:
} else {
// meta_down load is a special case (see renderMetaDownloadUrls)
//TODO: should be a better (gen.) way to handle this case
if( urlKey === 'meta_download' ){
- urls[ urlKey ] = hdaView.renderMetaDownloadUrls( urlTemplateOrObj, modelJson );
+ urls[ urlKey ] = hdaView._renderMetaDownloadUrls( urlTemplateOrObj, modelJson );
} else {
urls[ urlKey ] = _.template( urlTemplateOrObj, modelJson );
}
@@ -62,8 +79,13 @@
return urls;
},
- // there can be more than one meta_file to download, so return a list of url and file_type for each
- renderMetaDownloadUrls : function( urlTemplate, modelJson ){
+ /** there can be more than one meta_file (e.g. bam index) to download,
+ * so return a list of url and file_type for each
+ * @param {Object} urlTemplate underscore templates for meta download urls
+ * @param {Object} modelJson data from the model
+ * @returns {Object} url and filetype for each meta file
+ */
+ _renderMetaDownloadUrls : function( urlTemplate, modelJson ){
return _.map( modelJson.meta_files, function( meta_file ){
return {
url : _.template( urlTemplate, { id: modelJson.id, file_type: meta_file.file_type }),
@@ -72,8 +94,14 @@
});
},
- // ................................................................................ RENDER MAIN
- // events: rendered, rendered:ready, rendered:initial, rendered:ready:initial
+ // ......................................................................... RENDER MAIN
+ /** Render this HDA, set up ui.
+ * @fires rendered:ready when rendered and NO running HDAs
+ * @fires rendered when rendered and running HDAs
+ * @fires rendered:initial on first render with running HDAs
+ * @fires rendered:initial:ready when first rendered and NO running HDAs
+ * @returns {Object} this HDABaseView
+ */
render : function(){
var view = this,
id = this.model.get( 'id' ),
@@ -118,15 +146,19 @@
return this;
},
- // ................................................................................ RENDER WARNINGS
- // hda warnings including: is deleted, is purged, is hidden (including links to further actions (undelete, etc.))
+ // ................................................................................ RENDER titlebar
+ /** Render any hda warnings including: is deleted, is purged, is hidden.
+ * (including links to further actions (undelete, etc.))
+ * @returns {jQuery} rendered DOM
+ */
_render_warnings : function(){
// jQ errs on building dom with whitespace - if there are no messages, trim -> ''
return $( jQuery.trim( HDABaseView.templates.messages( this.model.toJSON() )));
},
- // ................................................................................ RENDER TITLEBAR
- // the part of an hda always shown (whether the body is expanded or not): title link, title buttons
+ /** Render the part of an hda always shown (whether the body is expanded or not): title link, title buttons.
+ * @returns {jQuery} rendered DOM
+ */
_render_titleBar : function(){
var titleBar = $( '<div class="historyItemTitleBar" style="overflow: hidden"></div>' );
titleBar.append( this._render_titleButtons() );
@@ -135,9 +167,9 @@
return titleBar;
},
- // ................................................................................ display, edit attr, delete
- // icon-button group for the common, most easily accessed actions
- //NOTE: these are generally displayed for almost every hda state (tho poss. disabled)
+ /** Render icon-button group for the common, most easily accessed actions.
+ * @returns {jQuery} rendered DOM
+ */
_render_titleButtons : function(){
// render the display, edit attr and delete icon-buttons
var buttonDiv = $( '<div class="historyItemButtons"></div>' );
@@ -145,7 +177,9 @@
return buttonDiv;
},
- // icon-button to display this hda in the galaxy main iframe
+ /** Render icon-button to display this hda in the galaxy main iframe.
+ * @returns {jQuery} rendered DOM
+ */
_render_displayButton : function(){
// don't show display if not in ready state, error'd, or not accessible
if( ( !this.model.inReadyState() )
@@ -175,23 +209,30 @@
return this.displayButton.render().$el;
},
- // ................................................................................ titleLink
- // render the hid and hda.name as a link (that will expand the body)
+ /** Render the hid and hda.name as a link (that will expand the body).
+ * @returns {jQuery} rendered DOM
+ */
_render_titleLink : function(){
return $( jQuery.trim( HDABaseView.templates.titleLink(
+ //TODO?? does this need urls?
_.extend( this.model.toJSON(), { urls: this.urls } )
)));
},
- // ................................................................................ RENDER BODY
- // render the data/metadata summary (format, size, misc info, etc.)
+ // ......................................................................... RENDER BODY
+ /** Render the data/metadata summary (format, size, misc info, etc.).
+ * @returns {jQuery} rendered DOM
+ */
_render_hdaSummary : function(){
var modelData = _.extend( this.model.toJSON(), { urls: this.urls } );
return HDABaseView.templates.hdaSummary( modelData );
},
- // ................................................................................ primary actions
- // render the icon-buttons gen. placed underneath the hda summary
+ // ......................................................................... primary actions
+ /** Render the icon-buttons gen. placed underneath the hda summary (e.g. download, show params, etc.)
+ * @param {Array} buttonRenderingFuncs array of rendering functions appending the results in order
+ * @returns {jQuery} rendered DOM
+ */
_render_primaryActionButtons : function( buttonRenderingFuncs ){
var view = this,
primaryActionButtons = $( '<div/>' ).attr( 'id', 'primary-actions-' + this.model.get( 'id' ) );
@@ -201,7 +242,9 @@
return primaryActionButtons;
},
- // icon-button/popupmenu to down the data (and/or the associated meta files (bai, etc.)) for this hda
+ /** Render icon-button/popupmenu to download the data (and/or the associated meta files (bai, etc.)) for this hda.
+ * @returns {jQuery} rendered DOM
+ */
_render_downloadButton : function(){
// don't show anything if the data's been purged
if( this.model.get( 'purged' ) || !this.model.hasData() ){ return null; }
@@ -215,7 +258,9 @@
return $( downloadLinkHTML );
},
- // icon-button to show the input and output (stdout/err) for the job that created this hda
+ /** Render icon-button to show the input and output (stdout/err) for the job that created this hda.
+ * @returns {jQuery} rendered DOM
+ */
_render_showParamsButton : function(){
// gen. safe to show in all cases
this.showParamsButton = new IconButtonView({ model : new IconButton({
@@ -227,8 +272,10 @@
return this.showParamsButton.render().$el;
},
- // ................................................................................ other elements
- // render links to external genome display applications (igb, gbrowse, etc.)
+ // ......................................................................... other elements
+ /** Render links to external genome display applications (igb, gbrowse, etc.).
+ * @returns {jQuery} rendered DOM
+ */
//TODO: not a fan of the style on these
_render_displayApps : function(){
if( !this.model.hasData() ){ return null; }
@@ -250,7 +297,9 @@
return displayAppsDiv;
},
- // render the data peek
+ /** Render the data peek.
+ * @returns {jQuery} rendered DOM
+ */
//TODO: curr. pre-formatted into table on the server side - may not be ideal/flexible
_render_peek : function(){
if( !this.model.get( 'peek' ) ){ return null; }
@@ -262,28 +311,99 @@
);
},
- // ................................................................................ state body renderers
- // _render_body fns for the various states
+ // ......................................................................... state body renderers
+ /** Render the (expanded) body of an HDA, dispatching to other functions based on the HDA state
+ * @returns {jQuery} rendered DOM
+ */
//TODO: only render these on expansion (or already expanded)
+ _render_body : function(){
+ //this.log( this + '_render_body' );
+
+ var body = $( '<div/>' )
+ .attr( 'id', 'info-' + this.model.get( 'id' ) )
+ .addClass( 'historyItemBody' )
+ .attr( 'style', 'display: block' );
+
+ //TODO: not a fan of this dispatch
+ switch( this.model.get( 'state' ) ){
+ case HistoryDatasetAssociation.STATES.NOT_VIEWABLE :
+ this._render_body_not_viewable( body );
+ break;
+ case HistoryDatasetAssociation.STATES.UPLOAD :
+ this._render_body_uploading( body );
+ break;
+ case HistoryDatasetAssociation.STATES.QUEUED :
+ this._render_body_queued( body );
+ break;
+ case HistoryDatasetAssociation.STATES.RUNNING :
+ this._render_body_running( body );
+ break;
+ case HistoryDatasetAssociation.STATES.ERROR :
+ this._render_body_error( body );
+ break;
+ case HistoryDatasetAssociation.STATES.DISCARDED :
+ this._render_body_discarded( body );
+ break;
+ case HistoryDatasetAssociation.STATES.SETTING_METADATA :
+ this._render_body_setting_metadata( body );
+ break;
+ case HistoryDatasetAssociation.STATES.EMPTY :
+ this._render_body_empty( body );
+ break;
+ case HistoryDatasetAssociation.STATES.FAILED_METADATA :
+ this._render_body_failed_metadata( body );
+ break;
+ case HistoryDatasetAssociation.STATES.OK :
+ this._render_body_ok( body );
+ break;
+ default:
+ //??: no body?
+ body.append( $( '<div>Error: unknown dataset state "' + state + '".</div>' ) );
+ }
+ body.append( '<div style="clear: both"></div>' );
+
+ if( this.expanded ){
+ body.show();
+ } else {
+ body.hide();
+ }
+ return body;
+ },
+
+ /** Render inaccessible, not-owned by curr user.
+ * @param {jQuery} parent DOM to which to append this body
+ */
_render_body_not_viewable : function( parent ){
//TODO: revisit - still showing display, edit, delete (as common) - that CAN'T be right
parent.append( $( '<div>' + _l( 'You do not have permission to view dataset' ) + '.</div>' ) );
},
+ /** Render an HDA still being uploaded.
+ * @param {jQuery} parent DOM to which to append this body
+ */
_render_body_uploading : function( parent ){
parent.append( $( '<div>' + _l( 'Dataset is uploading' ) + '</div>' ) );
},
+ /** Render an HDA whose job is queued.
+ * @param {jQuery} parent DOM to which to append this body
+ */
_render_body_queued : function( parent ){
parent.append( $( '<div>' + _l( 'Job is waiting to run' ) + '.</div>' ) );
parent.append( this._render_primaryActionButtons( this.defaultPrimaryActionButtonRenderers ));
},
+ /** Render an HDA whose job is running.
+ * @param {jQuery} parent DOM to which to append this body
+ */
_render_body_running : function( parent ){
parent.append( '<div>' + _l( 'Job is currently running' ) + '.</div>' );
parent.append( this._render_primaryActionButtons( this.defaultPrimaryActionButtonRenderers ));
},
+ /** Render an HDA whose job has failed.
+ * @param {jQuery} parent DOM to which to append this body
+ */
_render_body_error : function( parent ){
if( !this.model.get( 'purged' ) ){
parent.append( $( '<div>' + this.model.get( 'misc_blurb' ) + '</div>' ) );
@@ -295,15 +415,24 @@
));
},
+ /** Render an HDA which was deleted during upload.
+ * @param {jQuery} parent DOM to which to append this body
+ */
_render_body_discarded : function( parent ){
parent.append( '<div>' + _l( 'The job creating this dataset was cancelled before completion' ) + '.</div>' );
parent.append( this._render_primaryActionButtons( this.defaultPrimaryActionButtonRenderers ));
},
+ /** Render an HDA where the metadata is still being determined.
+ * @param {jQuery} parent DOM to which to append this body
+ */
_render_body_setting_metadata : function( parent ){
parent.append( $( '<div>' + _l( 'Metadata is being auto-detected' ) + '.</div>' ) );
},
+ /** Render an empty/no data HDA.
+ * @param {jQuery} parent DOM to which to append this body
+ */
_render_body_empty : function( parent ){
//TODO: replace i with dataset-misc-info class
//?? why are we showing the file size when we know it's zero??
@@ -311,6 +440,9 @@
parent.append( this._render_primaryActionButtons( this.defaultPrimaryActionButtonRenderers ));
},
+ /** Render an HDA where the metadata wasn't produced correctly.
+ * @param {jQuery} parent DOM to which to append this body
+ */
_render_body_failed_metadata : function( parent ){
//TODO: the css for this box is broken (unlike the others)
// add a message box about the failure at the top of the body...
@@ -319,6 +451,9 @@
this._render_body_ok( parent );
},
+ /** Render an HDA that's done running and where everything worked.
+ * @param {jQuery} parent DOM to which to append this body
+ */
_render_body_ok : function( parent ){
// most common state renderer and the most complicated
parent.append( this._render_hdaSummary() );
@@ -344,67 +479,18 @@
parent.append( this._render_peek() );
},
- _render_body : function(){
- //this.log( this + '_render_body' );
-
- var body = $( '<div/>' )
- .attr( 'id', 'info-' + this.model.get( 'id' ) )
- .addClass( 'historyItemBody' )
- .attr( 'style', 'display: block' );
-
- //TODO: not a fan of this dispatch
- switch( this.model.get( 'state' ) ){
- case HistoryDatasetAssociation.STATES.NOT_VIEWABLE :
- this._render_body_not_viewable( body );
- break;
- case HistoryDatasetAssociation.STATES.UPLOAD :
- this._render_body_uploading( body );
- break;
- case HistoryDatasetAssociation.STATES.QUEUED :
- this._render_body_queued( body );
- break;
- case HistoryDatasetAssociation.STATES.RUNNING :
- this._render_body_running( body );
- break;
- case HistoryDatasetAssociation.STATES.ERROR :
- this._render_body_error( body );
- break;
- case HistoryDatasetAssociation.STATES.DISCARDED :
- this._render_body_discarded( body );
- break;
- case HistoryDatasetAssociation.STATES.SETTING_METADATA :
- this._render_body_setting_metadata( body );
- break;
- case HistoryDatasetAssociation.STATES.EMPTY :
- this._render_body_empty( body );
- break;
- case HistoryDatasetAssociation.STATES.FAILED_METADATA :
- this._render_body_failed_metadata( body );
- break;
- case HistoryDatasetAssociation.STATES.OK :
- this._render_body_ok( body );
- break;
- default:
- //??: no body?
- body.append( $( '<div>Error: unknown dataset state "' + state + '".</div>' ) );
- }
- body.append( '<div style="clear: both"></div>' );
-
- if( this.expanded ){
- body.show();
- } else {
- body.hide();
- }
- return body;
- },
-
- // ................................................................................ EVENTS
+ // ......................................................................... EVENTS
+ /** event map */
events : {
'click .historyItemTitle' : 'toggleBodyVisibility'
},
- // expand/collapse body
- // event: body-visible, body-hidden
+ /** Render an HDA that's done running and where everything worked.
+ * @param {Event} event the event that triggered this (@link HDABaseView#events)
+ * @param {Boolean} expanded if true, expand; if false, collapse
+ * @fires body-expanded when a body has been expanded
+ * @fires body-collapsed when a body has been collapsed
+ */
toggleBodyVisibility : function( event, expanded ){
var hdaView = this,
$body = this.$el.find( '.historyItemBody' );
@@ -413,23 +499,23 @@
if( expanded ){
$body.slideDown( 'fast', function(){
- hdaView.trigger( 'body-visible', hdaView.model.get( 'id' ) );
+ hdaView.trigger( 'body-expanded', hdaView.model.get( 'id' ) );
});
} else {
$body.slideUp( 'fast', function(){
- hdaView.trigger( 'body-hidden', hdaView.model.get( 'id' ) );
+ hdaView.trigger( 'body-collapsed', hdaView.model.get( 'id' ) );
});
}
},
- // ................................................................................ UTILTIY
+ // ......................................................................... MISC
toString : function(){
var modelString = ( this.model )?( this.model + '' ):( '(no model)' );
return 'HDABaseView(' + modelString + ')';
}
});
-//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------ TEMPLATES
HDABaseView.templates = {
warningMsg : Handlebars.templates[ 'template-warningmessagesmall' ],
diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/dataset/hda-edit.js
--- a/static/scripts/mvc/dataset/hda-edit.js
+++ b/static/scripts/mvc/dataset/hda-edit.js
@@ -2,25 +2,42 @@
// "../mvc/base-mvc"
//], function(){
//==============================================================================
-/** editing view for HistoryDatasetAssociations
+/** @class Editing view for HistoryDatasetAssociation.
+ * @name HDAEditView
*
+ * @augments HDABaseView
+ * @borrows LoggableMixin#logger as #logger
+ * @borrows LoggableMixin#log as #log
+ * @constructs
*/
-var HDAEditView = HDABaseView.extend({
+var HDAEditView = HDABaseView.extend( LoggableMixin ).extend(
+/** @lends HDAEditView.prototype */{
- // ................................................................................ SET UP
+ // ......................................................................... SET UP
+ /** Set up the view, cache url templates, bind listeners.
+ * Overrides HDABaseView.initialize to change default actions (adding re-run).
+ * @param {Object} attributes
+ * @config {Object} urlTemplates nested object containing url templates for this view
+ * @throws 'needs urlTemplates' if urlTemplates isn't present
+ * @see HDABaseView#initialize
+ */
initialize : function( attributes ){
HDABaseView.prototype.initialize.call( this, attributes );
- // which buttons go in most states (ok/failed meta are more complicated)
- // HDAEdit gets the rerun button on almost all states
+ /** list of rendering functions for the default, primary icon-buttons. */
this.defaultPrimaryActionButtonRenderers = [
this._render_showParamsButton,
+ // HDAEdit gets the rerun button on almost all states
this._render_rerunButton
];
},
- // ................................................................................ RENDER WARNINGS
- // hda warnings including: is deleted, is purged, is hidden (including links to further actions (undelete, etc.))
+ // ......................................................................... RENDER WARNINGS
+ /** Render any hda warnings including: is deleted, is purged, is hidden.
+ * Overrides _render_warnings to include links to further actions (undelete, etc.)).
+ * @returns {Object} the templated urls
+ * @see HDABaseView#_render_warnings
+ */
_render_warnings : function(){
// jQ errs on building dom with whitespace - if there are no messages, trim -> ''
return $( jQuery.trim( HDABaseView.templates.messages(
@@ -28,9 +45,12 @@
)));
},
- // ................................................................................ display, edit attr, delete
- // icon-button group for the common, most easily accessed actions
- //NOTE: these are generally displayed for almost every hda state (tho poss. disabled)
+ // ......................................................................... edit attr, delete
+ /** Render icon-button group for the common, most easily accessed actions.
+ * Overrides _render_titleButtons to include edit and delete buttons.
+ * @see HDABaseView#_render_titleButtons
+ * @returns {jQuery} rendered DOM
+ */
_render_titleButtons : function(){
// render the display, edit attr and delete icon-buttons
var buttonDiv = $( '<div class="historyItemButtons"></div>' );
@@ -40,7 +60,9 @@
return buttonDiv;
},
- // icon-button to edit the attributes (format, permissions, etc.) this hda
+ /** Render icon-button to edit the attributes (format, permissions, etc.) this hda.
+ * @returns {jQuery} rendered DOM
+ */
_render_editButton : function(){
// don't show edit while uploading
//TODO??: error?
@@ -76,7 +98,9 @@
return this.editButton.render().$el;
},
- // icon-button to delete this hda
+ /** Render icon-button to delete this hda.
+ * @returns {jQuery} rendered DOM
+ */
_render_deleteButton : function(){
// don't show delete if...
//TODO??: not viewable/accessible are essentially the same (not viewable set from accessible)
@@ -103,8 +127,12 @@
return this.deleteButton.render().$el;
},
- // ................................................................................ RENDER BODY
- // render the data/metadata summary (format, size, misc info, etc.)
+ // ......................................................................... RENDER BODY
+ /** Render the data/metadata summary (format, size, misc info, etc.).
+ * Overrides _render_hdaSummary to include edit link in dbkey.
+ * @see HDABaseView#_render_hdaSummary
+ * @returns {jQuery} rendered DOM
+ */
_render_hdaSummary : function(){
var modelData = _.extend( this.model.toJSON(), { urls: this.urls } );
// if there's no dbkey and it's editable : pass a flag to the template to render a link to editing in the '?'
@@ -116,8 +144,10 @@
return HDABaseView.templates.hdaSummary( modelData );
},
- // ................................................................................ primary actions
- // icon-button to show the input and output (stdout/err) for the job that created this hda
+ // ......................................................................... primary actions
+ /** Render icon-button to report an error on this hda to the galaxy admin.
+ * @returns {jQuery} rendered DOM
+ */
_render_errButton : function(){
if( this.model.get( 'state' ) !== HistoryDatasetAssociation.STATES.ERROR ){
this.errButton = null;
@@ -133,7 +163,9 @@
return this.errButton.render().$el;
},
- // icon-button to re run the job that created this hda
+ /** Render icon-button to re-run the job that created this hda.
+ * @returns {jQuery} rendered DOM
+ */
_render_rerunButton : function(){
this.rerunButton = new IconButtonView({ model : new IconButton({
title : _l( 'Run this job again' ),
@@ -144,8 +176,10 @@
return this.rerunButton.render().$el;
},
- // build an icon-button or popupmenu based on the number of applicable visualizations
- // also map button/popup clicks to viz setup functions
+ /** Render an icon-button or popupmenu based on the number of applicable visualizations
+ * and map button/popup clicks to viz setup functions.
+ * @returns {jQuery} rendered DOM
+ */
_render_visualizationsButton : function(){
var dbkey = this.model.get( 'dbkey' ),
visualizations = this.model.get( 'visualizations' ),
@@ -179,6 +213,7 @@
// Add dbkey to params if it exists.
if( dbkey ){ params.dbkey = dbkey; }
+ /** @inner */
function create_viz_action( visualization ) {
switch( visualization ){
case 'trackster':
@@ -208,8 +243,11 @@
return $icon;
},
- // ................................................................................ secondary actions
- // secondary actions: currently tagging and annotation (if user is allowed)
+ // ......................................................................... secondary actions
+ /** Render secondary actions: currently tagging and annotation (if user is allowed).
+ * @param {Array} buttonRenderingFuncs array of rendering functions appending the results in order
+ * @returns {jQuery} rendered DOM
+ */
_render_secondaryActionButtons : function( buttonRenderingFuncs ){
// move to the right (same level as primary)
var secondaryActionButtons = $( '<div/>' ),
@@ -224,7 +262,9 @@
return secondaryActionButtons;
},
- // icon-button to load and display tagging html
+ /** Render icon-button to load and display tagging html.
+ * @returns {jQuery} rendered DOM
+ */
//TODO: these should be a sub-MV
_render_tagButton : function(){
//TODO: check for User
@@ -243,7 +283,9 @@
return this.tagButton.render().$el;
},
- // icon-button to load and display annotation html
+ /** Render icon-button to load and display annotation html.
+ * @returns {jQuery} rendered DOM
+ */
//TODO: these should be a sub-MV
_render_annotateButton : function(){
//TODO: check for User
@@ -261,10 +303,12 @@
return this.annotateButton.render().$el;
},
- // ................................................................................ other elements
+ // ......................................................................... other elements
+ /** Render area to display tags.
+ * @returns {jQuery} rendered DOM
+ */
//TODO: into sub-MV
//TODO: check for User
- // render the area used to load tag display
_render_tagArea : function(){
if( !this.urls.tags.set ){ return null; }
//TODO: move to mvc/tags.js
@@ -273,9 +317,11 @@
));
},
+ /** Render area to display annotation.
+ * @returns {jQuery} rendered DOM
+ */
//TODO: into sub-MV
//TODO: check for User
- // render the area used to load annotation display
_render_annotationArea : function(){
if( !this.urls.annotation.get ){ return null; }
//TODO: move to mvc/annotations.js
@@ -284,14 +330,23 @@
));
},
- // ................................................................................ state body renderers
+ // ......................................................................... state body renderers
+ /** Render an HDA whose job has failed.
+ * Overrides _render_body_error to prepend error report button to primary actions strip.
+ * @param {jQuery} parent DOM to which to append this body
+ * @see HDABaseView#_render_body_error
+ */
_render_body_error : function( parent ){
- // overridden to prepend error report button to primary actions strip
HDABaseView.prototype._render_body_error.call( this, parent );
var primaryActions = parent.find( '#primary-actions-' + this.model.get( 'id' ) );
primaryActions.prepend( this._render_errButton() );
},
+ /** Render an HDA that's done running and where everything worked.
+ * Overrides _render_body_ok to add tag/annotation functionality and additional primary actions
+ * @param {jQuery} parent DOM to which to append this body
+ * @see HDABaseView#_render_body_ok
+ */
_render_body_ok : function( parent ){
// most common state renderer and the most complicated
parent.append( this._render_hdaSummary() );
@@ -327,15 +382,17 @@
parent.append( this._render_peek() );
},
- // ................................................................................ EVENTS
+ // ......................................................................... EVENTS
+ /** event map */
events : {
'click .historyItemTitle' : 'toggleBodyVisibility',
'click a.icon-button.tags' : 'loadAndDisplayTags',
'click a.icon-button.annotate' : 'loadAndDisplayAnnotation'
},
- // ................................................................................ STATE CHANGES / MANIPULATION
- // find the tag area and, if initial: (via ajax) load the html for displaying them; otherwise, unhide/hide
+ // ......................................................................... STATE CHANGES / MANIPULATION
+ /** Find the tag area and, if initial: load the html (via ajax) for displaying them; otherwise, unhide/hide
+ */
//TODO: into sub-MV
loadAndDisplayTags : function( event ){
//BUG: broken with latest
@@ -369,7 +426,8 @@
return false;
},
- // find the annotation area and, if initial: (via ajax) load the html for displaying it; otherwise, unhide/hide
+ /** Find the annotation area and, if initial: load the html (via ajax) for displaying them; otherwise, unhide/hide
+ */
//TODO: into sub-MV
loadAndDisplayAnnotation : function( event ){
//TODO: this is a drop in from history.mako - should use MV as well
@@ -411,7 +469,8 @@
return false;
},
- // ................................................................................ UTILTIY
+ // ......................................................................... UTILTIY
+ /** string rep */
toString : function(){
var modelString = ( this.model )?( this.model + '' ):( '(no model)' );
return 'HDAView(' + modelString + ')';
@@ -427,8 +486,12 @@
//==============================================================================
//TODO: these belong somewhere else
-//TODO: should be imported from scatterplot.js
-//TODO: OR abstracted to 'load this in the galaxy_main frame'
+/** Create scatterplot loading/set up function for use with the visualizations popupmenu.
+ * @param {String} url url (gen. 'visualizations') to which to append 'scatterplot' and params
+ * @param {Object} params parameters to convert to query string for splot page
+ * @returns function that loads the scatterplot
+ */
+//TODO: should be imported from scatterplot.js OR abstracted to 'load this in the galaxy_main frame'
function create_scatterplot_action_fn( url, params ){
action = function() {
var galaxy_main = $( window.parent.document ).find( 'iframe#galaxy_main' ),
@@ -442,7 +505,12 @@
}
// -----------------------------------------------------------------------------
-// Create trackster action function.
+/** Create trackster loading/set up function for use with the visualizations popupmenu.
+ * Shows modal dialog for load old/create new.
+ * @param {String} vis_url visualizations url (gen. 'visualizations')
+ * @param {Object} dataset_params parameters to pass to trackster in the query string.
+ * @returns function that displays modal, loads trackster
+ */
//TODO: should be imported from trackster.js
function create_trackster_action_fn(vis_url, dataset_params, dbkey) {
return function() {
diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/dataset/hda-model.js
--- a/static/scripts/mvc/dataset/hda-model.js
+++ b/static/scripts/mvc/dataset/hda-model.js
@@ -2,15 +2,23 @@
// "../mvc/base-mvc"
//], function(){
//==============================================================================
-/**
+/** @class (HDA) model for a Galaxy dataset
+ * related to a history.
+ * @name HistoryDatasetAssociation
*
+ * @augments BaseModel
+ * @borrows LoggableMixin#logger as #logger
+ * @borrows LoggableMixin#log as #log
+ * @constructs
*/
-var HistoryDatasetAssociation = BaseModel.extend( LoggableMixin ).extend({
- // a single HDA model
+var HistoryDatasetAssociation = BaseModel.extend( LoggableMixin ).extend(
+/** @lends HistoryDatasetAssociation.prototype */{
- // uncomment this out see log messages
+ ///** logger used to record this.log messages, commonly set to console */
+ //// comment this out to suppress log output
//logger : console,
+ /** default attributes for a model */
defaults : {
// ---these are part of an HDA proper:
@@ -46,18 +54,22 @@
accessible : false
},
- // fetch location of this history in the api
+ /** fetch location of this history in the api */
+ urlRoot: 'api/histories/',
url : function(){
//TODO: get this via url router
return 'api/histories/' + this.get( 'history_id' ) + '/contents/' + this.get( 'id' );
},
- // (curr) only handles changing state of non-accessible hdas to STATES.NOT_VIEWABLE
+ /** Set up the model, determine if accessible, bind listeners
+ * @see Backbone.Model#initialize
+ */
//TODO:? use initialize (or validate) to check purged AND deleted -> purged XOR deleted
initialize : function(){
this.log( this + '.initialize', this.attributes );
this.log( '\tparent history_id: ' + this.get( 'history_id' ) );
+ // (curr) only handles changing state of non-accessible hdas to STATES.NOT_VIEWABLE
//!! this state is not in trans.app.model.Dataset.states - set it here -
//TODO: change to server side.
if( !this.get( 'accessible' ) ){
@@ -81,12 +93,18 @@
//});
},
+ /** Is this hda deleted or purged?
+ */
isDeletedOrPurged : function(){
return ( this.get( 'deleted' ) || this.get( 'purged' ) );
},
- // based on show_deleted, show_hidden (gen. from the container control), would this ds show in the list of ds's?
- //TODO: too many visibles
+ /** based on show_deleted, show_hidden (gen. from the container control),
+ * would this ds show in the list of ds's?
+ * @param {Boolean} show_deleted are we showing deleted hdas?
+ * @param {Boolean} show_hidden are we showing hidden hdas?
+ */
+ //TODO: too many 'visible's
isVisible : function( show_deleted, show_hidden ){
var isVisible = true;
if( ( !show_deleted )
@@ -100,7 +118,11 @@
return isVisible;
},
- // 'ready' states are states where no processing (for the ds) is left to do on the server
+ /** Is this HDA in a 'ready' state; where 'Ready' states are states where no
+ * processing (for the ds) is left to do on the server.
+ * Currently: NEW, OK, EMPTY, FAILED_METADATA, NOT_VIEWABLE, DISCARDED,
+ * and ERROR
+ */
inReadyState : function(){
var state = this.get( 'state' );
return (
@@ -114,12 +136,15 @@
);
},
- // convenience fn to match hda.has_data
+ /** Convenience function to match hda.has_data.
+ */
hasData : function(){
//TODO:?? is this equivalent to all possible hda.has_data calls?
return ( this.get( 'file_size' ) > 0 );
},
+ /** String representation
+ */
toString : function(){
var nameAndId = this.get( 'id' ) || '';
if( this.get( 'name' ) ){
@@ -130,48 +155,83 @@
});
//------------------------------------------------------------------------------
+/** Class level map of possible HDA states to their string equivalents.
+ * A port of galaxy.model.Dataset.states.
+ */
HistoryDatasetAssociation.STATES = {
+ // NOT ready states
+ /** is uploading and not ready */
UPLOAD : 'upload',
+ /** the job that will produce the dataset queued in the runner */
QUEUED : 'queued',
+ /** the job that will produce the dataset is running */
RUNNING : 'running',
+ /** metadata for the dataset is being discovered/set */
SETTING_METADATA : 'setting_metadata',
+ // ready states
+ /** was created without a tool */
NEW : 'new',
+ /** has no data */
+ EMPTY : 'empty',
+ /** has successfully completed running */
OK : 'ok',
- EMPTY : 'empty',
+ /** metadata discovery/setting failed or errored (but otherwise ok) */
FAILED_METADATA : 'failed_metadata',
+ /** not accessible to the current user (i.e. due to permissions) */
NOT_VIEWABLE : 'noPermission', // not in trans.app.model.Dataset.states
+ /** deleted while uploading */
DISCARDED : 'discarded',
+ /** the tool producing this dataset failed */
ERROR : 'error'
};
//==============================================================================
-/**
+/** @class Backbone collection of (HDA) models
*
+ * @borrows LoggableMixin#logger as #logger
+ * @borrows LoggableMixin#log as #log
+ * @constructs
*/
-var HDACollection = Backbone.Collection.extend( LoggableMixin ).extend({
+var HDACollection = Backbone.Collection.extend( LoggableMixin ).extend(
+/** @lends HDACollection.prototype */{
model : HistoryDatasetAssociation,
- //logger : console,
+ ///** logger used to record this.log messages, commonly set to console */
+ //// comment this out to suppress log output
+ //logger : console,
+ /** Set up.
+ * @see Backbone.Collection#initialize
+ */
initialize : function(){
//this.bind( 'all', function( event ){
// this.log( this + '', arguments );
//});
},
- // return the ids of every hda in this collection
+ /** Get the ids of every hda in this collection
+ * @returns array of encoded ids
+ */
ids : function(){
return this.map( function( item ){ return item.id; });
},
- // return an HDA collection containing every 'shown' hda based on show_deleted/hidden
+ /** Get every 'shown' hda in this collection based on show_deleted/hidden
+ * @param {Boolean} show_deleted are we showing deleted hdas?
+ * @param {Boolean} show_hidden are we showing hidden hdas?
+ * @returns array of hda models
+ * @see HistoryDatasetAssociation#isVisible
+ */
getVisible : function( show_deleted, show_hidden ){
return this.filter( function( item ){ return item.isVisible( show_deleted, show_hidden ); });
},
- // get a map where <possible hda state> : [ <list of hda ids in that state> ]
+ /** For each possible hda state, get an array of all hda ids in that state
+ * @returns a map of states -> hda ids
+ * @see HistoryDatasetAssociation#STATES
+ */
getStateLists : function(){
var stateLists = {};
_.each( _.values( HistoryDatasetAssociation.STATES ), function( state ){
@@ -184,7 +244,10 @@
return stateLists;
},
- // returns the id of every hda still running (not in a ready state)
+ /** Get the id of every hda in this collection not in a 'ready' state (running).
+ * @returns an array of hda ids
+ * @see HistoryDatasetAssociation#inReadyState
+ */
running : function(){
var idList = [];
this.each( function( item ){
@@ -195,7 +258,10 @@
return idList;
},
- // update (fetch -> render) the hdas with the ids given
+ /** Update (fetch) the data of the hdas with the given ids.
+ * @param {String[]} ids an array of hda ids to update
+ * @see HistoryDatasetAssociation#fetch
+ */
update : function( ids ){
this.log( this + 'update:', ids );
@@ -208,6 +274,7 @@
});
},
+ /** String representation. */
toString : function(){
return ( 'HDACollection(' + this.ids().join(',') + ')' );
}
diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/history/history-model.js
--- a/static/scripts/mvc/history/history-model.js
+++ b/static/scripts/mvc/history/history-model.js
@@ -2,13 +2,21 @@
// "../mvc/base-mvc"
//], function(){
//==============================================================================
-/**
+/** @class Model for a Galaxy history resource - both a record of user
+ * tool use and a collection of the datasets those tools produced.
+ * @name History
*
+ * @augments BaseModel
+ * @borrows LoggableMixin#logger as #logger
+ * @borrows LoggableMixin#log as #log
+ * @constructs
*/
-var History = BaseModel.extend( LoggableMixin ).extend({
+var History = BaseModel.extend( LoggableMixin ).extend(
+/** @lends History.prototype */{
//TODO: bind change events from items and collection to this (itemLengths, states)
- // uncomment this out see log messages
+ ///** logger used to record this.log messages, commonly set to console */
+ //// comment this out to suppress log output
//logger : console,
// values from api (may need more)
@@ -27,15 +35,23 @@
message : null
},
+ //TODO: hardcoded
+ urlRoot: 'api/histories/',
+ /** url for fetch */
url : function(){
// api location of history resource
- //TODO: hardcoded
return 'api/histories/' + this.get( 'id' );
},
+ /** Set up the hdas collection
+ * @param {Object} initialSettings model data for this History
+ * @param {Object[]} initialHdas array of model data for this History's HDAs
+ * @see BaseModel#initialize
+ */
initialize : function( initialSettings, initialHdas ){
this.log( this + ".initialize:", initialSettings, initialHdas );
+ /** HDACollection of the HDAs contained in this history. */
this.hdas = new HDACollection();
// if we've got hdas passed in the constructor, load them and set up updates if needed
@@ -44,6 +60,7 @@
this.checkForUpdates();
}
+ // events
//this.on( 'change', function( currModel, changedList ){
// this.log( this + ' has changed:', currModel, changedList );
//});
@@ -53,7 +70,11 @@
//});
},
- // get data via the api (alternative to sending options,hdas to initialize)
+ /** get data via the api (alternative to sending options, hdas to initialize)
+ * @param {String} historyId encoded id
+ * @param {Object[]} success
+ * @see BaseModel#initialize
+ */
//TODO: this needs work - move to more straightforward deferred
// events: loaded, loaded:user, loaded:hdas
loadFromApi : function( historyId, success ){
@@ -178,13 +199,22 @@
});
//==============================================================================
-/** A collection of histories (per user or admin)
- * (stub) currently unused
+/** @class A collection of histories (per user).
+ * (stub) currently unused.
+ * @name HistoryCollection
+ *
+ * @borrows LoggableMixin#logger as #logger
+ * @borrows LoggableMixin#log as #log
+ * @constructs
*/
-var HistoryCollection = Backbone.Collection.extend( LoggableMixin ).extend({
+var HistoryCollection = Backbone.Collection.extend( LoggableMixin ).extend(
+/** @lends HistoryCollection.prototype */{
model : History,
- urlRoot : 'api/histories',
- //logger : console
+ urlRoot : 'api/histories'
+
+ ///** logger used to record this.log messages, commonly set to console */
+ //// comment this out to suppress log output
+ //logger : console,
});
//==============================================================================
diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/history/history-panel.js
--- a/static/scripts/mvc/history/history-panel.js
+++ b/static/scripts/mvc/history/history-panel.js
@@ -102,22 +102,43 @@
sorting, re-shuffling
============================================================================= */
-/** view for the HDACollection (as per current right hand panel)
+/** @class View/Controller for the history model as used in the history
+ * panel (current right hand panel).
+ * @name HistoryPanel
*
+ * @augments BaseView
+ * @borrows LoggableMixin#logger as #logger
+ * @borrows LoggableMixin#log as #log
+ * @constructs
*/
-var HistoryPanel = BaseView.extend( LoggableMixin ).extend({
+var HistoryPanel = BaseView.extend( LoggableMixin ).extend(
+/** @lends HistoryPanel.prototype */{
- // uncomment this out see log messages
+ ///** logger used to record this.log messages, commonly set to console */
+ //// comment this out to suppress log output
//logger : console,
// direct attachment to existing element
el : 'body.historyPage',
+ /** which class to use for constructing the HDA views */
//HDAView : HDABaseView,
HDAView : HDAEditView,
- // init with the model, urlTemplates, set up storage, bind HDACollection events
- //NOTE: this will create or load PersistantStorage keyed under 'HistoryView.<id>'
- //pre: you'll need to pass in the urlTemplates (urlTemplates : { history : {...}, hda : {...} })
+ /** event map
+ */
+ events : {
+ 'click #history-tag' : 'loadAndDisplayTags'
+ },
+
+ // ......................................................................... SET UP
+ /** Set up the view, set up storage, bind listeners to HDACollection events
+ * @param {Object} attributes
+ * @config {Object} urlTemplates.history nested object containing url templates for this view
+ * @config {Object} urlTemplates.hda nested object containing url templates for HDAViews
+ * @throws 'needs urlTemplates' if urlTemplates.history or urlTemplates.hda aren't present
+ * @see PersistantStorage
+ * @see Backbone.View#initialize
+ */
initialize : function( attributes ){
this.log( this + '.initialize:', attributes );
@@ -128,81 +149,93 @@
if( !attributes.urlTemplates.history ){ throw( this + ' needs urlTemplates.history on initialize' ); }
if( !attributes.urlTemplates.hda ){ throw( this + ' needs urlTemplates.hda on initialize' ); }
this.urlTemplates = attributes.urlTemplates.history;
+ /** map web controller urls for history related actions */
this.hdaUrlTemplates = attributes.urlTemplates.hda;
+ this._setUpWebStorage( attributes.initiallyExpanded, attributes.show_deleted, attributes.show_hidden );
+
+ // bind events from the model's hda collection
+ // don't need to re-render entire model on all changes, just render disk size when it changes
+ //this.model.bind( 'change', this.render, this );
+ this.model.bind( 'change:nice_size', this.updateHistoryDiskSize, this );
+ this.model.hdas.bind( 'add', this.add, this );
+ this.model.hdas.bind( 'reset', this.addAll, this );
+ //this.bind( 'all', function(){
+ // this.log( arguments );
+ //}, this );
+
+ // set up instance vars
+ /** map of hda model ids to hda views */
+ this.hdaViews = {};
+ /** map web controller urls for history related actions */
+ this.urls = {};
+ },
+
+ /** Set up client side storage. Currently PersistanStorage keyed under 'HistoryPanel.<id>'
+ * @param {Object} initiallyExpanded
+ * @param {Boolean} show_deleted whether to show deleted HDAs (overrides stored)
+ * @param {Boolean} show_hidden
+ * @see PersistantStorage
+ */
+ _setUpWebStorage : function( initiallyExpanded, show_deleted, show_hidden ){
+
// data that needs to be persistant over page refreshes
// (note the key function which uses the history id as well)
this.storage = new PersistantStorage( 'HistoryView.' + this.model.get( 'id' ), {
+ //TODOL initiallyExpanded only works on first load right now
expandedHdas : {},
show_deleted : false,
show_hidden : false
});
this.log( 'this.storage:', this.storage.get() );
- // get the show_deleted/hidden settings giving priority to values passed into initialize, but
+ // expanded Hdas is a map of hda.ids -> a boolean rep'ing whether this hda's body is expanded
+ // store any pre-expanded ids passed in
+ if( initiallyExpanded ){
+ this.storage.set( 'exandedHdas', initiallyExpanded );
+ }
+
+ // get the show_deleted/hidden settings giving priority to values passed in,
// using web storage otherwise
- this.log( 'show_deleted:', attributes.show_deleted, 'show_hidden', attributes.show_hidden );
+ //this.log( 'show_deleted:', show_deleted, 'show_hidden', show_hidden );
// if the page has specifically requested show_deleted/hidden, these will be either true or false
// (as opposed to undefined, null) - and we give priority to that setting
- if( ( attributes.show_deleted === true ) || ( attributes.show_deleted === false ) ){
+ if( ( show_deleted === true ) || ( show_deleted === false ) ){
// save them to web storage
- this.storage.set( 'show_deleted', attributes.show_deleted );
+ this.storage.set( 'show_deleted', show_deleted );
}
- if( ( attributes.show_hidden === true ) || ( attributes.show_hidden === false ) ){
- this.storage.set( 'show_hidden', attributes.show_hidden );
+ if( ( show_hidden === true ) || ( show_hidden === false ) ){
+ this.storage.set( 'show_hidden', show_hidden );
}
- // pull show_deleted/hidden from the web storage if the page hasn't specified whether to show_deleted/hidden,
+ // if the page hasn't specified whether to show_deleted/hidden, pull show_deleted/hidden from the web storage
this.show_deleted = this.storage.get( 'show_deleted' );
this.show_hidden = this.storage.get( 'show_hidden' );
- this.log( 'this.show_deleted:', this.show_deleted, 'show_hidden', this.show_hidden );
- this.log( '(now) this.storage:', this.storage.get() );
-
- // bind events from the model's hda collection
- //this.model.bind( 'change', this.render, this );
- this.model.bind( 'change:nice_size', this.updateHistoryDiskSize, this );
-
- this.model.hdas.bind( 'add', this.add, this );
- this.model.hdas.bind( 'reset', this.addAll, this );
- this.model.hdas.bind( 'all', this.all, this );
-
- //this.bind( 'all', function(){
- // this.log( arguments );
- //}, this );
-
- // set up instance vars
- this.hdaViews = {};
- this.urls = {};
+ //this.log( 'this.show_deleted:', this.show_deleted, 'show_hidden', this.show_hidden );
+ this.log( '(init\'d) this.storage:', this.storage.get() );
},
+ /** Add an hda to this history's collection
+ * @param {HistoryDatasetAssociation} hda hda to add to the collection
+ */
add : function( hda ){
//console.debug( 'add.' + this, hda );
//TODO
},
+ /** Event hander to respond when hdas are reset
+ */
addAll : function(){
//console.debug( 'addAll.' + this );
// re render when all hdas are reset
this.render();
},
- all : function( event ){
- //console.debug( 'allItemEvents.' + this, event );
- //...for which to do the debuggings
- },
-
- // render the urls for this view using urlTemplates and the model data
- renderUrls : function( modelJson ){
- var historyView = this;
-
- historyView.urls = {};
- _.each( this.urlTemplates, function( urlTemplate, urlKey ){
- historyView.urls[ urlKey ] = _.template( urlTemplate, modelJson );
- });
- return historyView.urls;
- },
-
- // render urls, historyView body, and hdas (if any are shown), fade out, swap, fade in, set up behaviours
- // events: rendered, rendered:initial
+ // ......................................................................... RENDERING
+ /** Render urls, historyPanel body, and hdas (if any are shown)
+ * @see Backbone.View#render
+ */
+ /** event rendered triggered when the panel rendering is complete */
+ /** event rendered:initial triggered when the FIRST panel rendering is complete */
render : function(){
var historyView = this,
setUpQueueName = historyView.toString() + '.set-up',
@@ -213,13 +246,13 @@
//console.debug( this + '.render, initialRender:', initialRender );
// render the urls and add them to the model json
- modelJson.urls = this.renderUrls( modelJson );
+ modelJson.urls = this._renderUrls( modelJson );
// render the main template, tooltips
//NOTE: this is done before the items, since item views should handle theirs themselves
newRender.append( HistoryPanel.templates.historyPanel( modelJson ) );
newRender.find( '.tooltip' ).tooltip({ placement: 'bottom' });
- this.setUpActionButton( newRender.find( '#history-action-popup' ) );
+ this._setUpActionButton( newRender.find( '#history-action-popup' ) );
// render hda views (if any and any shown (show_deleted/hidden)
//TODO: this seems too elaborate
@@ -244,7 +277,7 @@
this.log( historyView + ' rendered:', historyView.$el );
//TODO: ideally, these would be set up before the fade in (can't because of async save text)
- historyView.setUpBehaviours();
+ historyView._setUpBehaviours();
if( initialRender ){
historyView.trigger( 'rendered:initial' );
@@ -258,7 +291,24 @@
return this;
},
- setUpActionButton : function( $button ){
+ /** Render the urls for this view using urlTemplates and the model data
+ * @param {Object} modelJson data from the model used to fill templates
+ */
+ _renderUrls : function( modelJson ){
+ var historyView = this;
+
+ historyView.urls = {};
+ _.each( this.urlTemplates, function( urlTemplate, urlKey ){
+ historyView.urls[ urlKey ] = _.template( urlTemplate, modelJson );
+ });
+ return historyView.urls;
+ },
+
+ /** Set up history actions popup menu
+ * @param {jQuery} $button jQuery dom object to turn into the 'button' that activates the menu
+ * @see make_popupmenu (galaxy-base.js)
+ */
+ _setUpActionButton : function( $button ){
var historyPanel = this,
show_deletedText = ( this.storage.get( 'show_deleted' ) )?( 'Hide deleted' ):( 'Show deleted' ),
show_hiddenText = ( this.storage.get( 'show_hidden' ) )?( 'Hide hidden' ):( 'Show hidden' ),
@@ -270,7 +320,11 @@
make_popupmenu( $button, menuActions );
},
- // set up a view for each item to be shown, init with model and listeners, cache to map ( model.id : view )
+ /** Set up/render a view for each HDA to be shown, init with model and listeners.
+ * HDA views are cached to the map this.hdaViews (using the model.id as key).
+ * @param {jQuery} $whereTo what dom element to prepend the HDA views to
+ * @returns the number of visible hda views
+ */
renderItems : function( $whereTo ){
this.hdaViews = {};
var historyView = this,
@@ -290,7 +344,7 @@
expanded : expanded,
urlTemplates : historyView.hdaUrlTemplates
});
- historyView.setUpHdaListeners( historyView.hdaViews[ hdaId ] );
+ historyView._setUpHdaListeners( historyView.hdaViews[ hdaId ] );
// render it (NOTE: reverse order, newest on top (prepend))
//TODO: by default send a reverse order list (although this may be more efficient - it's more confusing)
@@ -299,21 +353,25 @@
return visibleHdas.length;
},
- // set up HistoryView->HDAView listeners
- setUpHdaListeners : function( hdaView ){
+ /** Set up HistoryPanel listeners for HDAView events. Currently binds:
+ * HDAView#body-visible, HDAView#body-hidden to store expanded states
+ * @param {HDAView} hdaView HDAView (base or edit) to listen to
+ */
+ _setUpHdaListeners : function( hdaView ){
var historyView = this;
- // use storage to maintain a list of hdas whose bodies are expanded
- hdaView.bind( 'body-visible', function( id ){
+ // maintain a list of hdas whose bodies are expanded
+ hdaView.bind( 'body-expanded', function( id ){
historyView.storage.get( 'expandedHdas' ).set( id, true );
});
- hdaView.bind( 'body-hidden', function( id ){
+ hdaView.bind( 'body-collapsed', function( id ){
historyView.storage.get( 'expandedHdas' ).deleteKey( id );
});
},
- // set up js/widget behaviours: tooltips,
+ /** Set up HistoryPanel js/widget behaviours
+ */
//TODO: these should be either sub-MVs, or handled by events
- setUpBehaviours : function(){
+ _setUpBehaviours : function(){
// anon users shouldn't have access to any of these
if( !( this.model.get( 'user' ) && this.model.get( 'user' ).email ) ){ return; }
@@ -337,40 +395,51 @@
this.urls.annotate, "new_annotation", 18, true, 4 );
},
- // update the history size display (curr. upper right of panel)
+ // ......................................................................... EVENTS
+ /** Update the history size display (curr. upper right of panel).
+ */
updateHistoryDiskSize : function(){
this.$el.find( '#history-size' ).text( this.model.get( 'nice_size' ) );
},
- events : {
- 'click #history-tag' : 'loadAndDisplayTags'
- },
-
+ /** Show the over quota message (which happens to be in the history panel).
+ */
//TODO: this seems more like a per user message than a history message; IOW, this doesn't belong here
- showQuotaMessage : function( userData ){
+ showQuotaMessage : function(){
var msg = this.$el.find( '#quota-message-container' );
//this.log( this + ' showing quota message:', msg, userData );
if( msg.is( ':hidden' ) ){ msg.slideDown( 'fast' ); }
},
+ /** Hide the over quota message (which happens to be in the history panel).
+ */
//TODO: this seems more like a per user message than a history message
- hideQuotaMessage : function( userData ){
+ hideQuotaMessage : function(){
var msg = this.$el.find( '#quota-message-container' );
//this.log( this + ' hiding quota message:', msg, userData );
if( !msg.is( ':hidden' ) ){ msg.slideUp( 'fast' ); }
},
- toggleShowDeleted : function( x, y, z ){
+ /** Handle the user toggling the deleted visibility by:
+ * (1) storing the new value in the persistant storage
+ * (2) re-rendering the history
+ */
+ toggleShowDeleted : function(){
this.storage.set( 'show_deleted', !this.storage.get( 'show_deleted' ) );
this.render();
},
+ /** Handle the user toggling the deleted visibility by:
+ * (1) storing the new value in the persistant storage
+ * (2) re-rendering the history
+ */
toggleShowHidden : function(){
this.storage.set( 'show_hidden', !this.storage.get( 'show_hidden' ) );
this.render();
},
- // collapse all hda bodies
+ /** Collapse all hda bodies and clear expandedHdas in the storage
+ */
hideAllHdaBodies : function(){
_.each( this.hdaViews, function( item ){
item.toggleBodyVisibility( null, false );
@@ -378,7 +447,8 @@
this.storage.set( 'expandedHdas', {} );
},
- // find the tag area and, if initial: (via ajax) load the html for displaying them; otherwise, unhide/hide
+ /** Find the tag area and, if initial: load the html (via ajax) for displaying them; otherwise, unhide/hide
+ */
//TODO: into sub-MV
loadAndDisplayTags : function( event ){
this.log( this + '.loadAndDisplayTags', event );
@@ -414,13 +484,16 @@
return false;
},
+ // ......................................................................... MISC
+ /** Return a string rep of the history
+ */
toString : function(){
var nameString = this.model.get( 'name' ) || '';
- return 'HistoryView(' + nameString + ')';
+ return 'HistoryPanel(' + nameString + ')';
}
});
-//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------ TEMPLATES
HistoryPanel.templates = {
historyPanel : Handlebars.templates[ 'template-history-historyPanel' ]
};
diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/user/user-model.js
--- a/static/scripts/mvc/user/user-model.js
+++ b/static/scripts/mvc/user/user-model.js
@@ -1,15 +1,37 @@
-var User = BaseModel.extend( LoggableMixin ).extend({
- //logger : console,
+/** @class Model for a Galaxy user (including anonymous users).
+ * @name User
+ *
+ * @augments BaseModel
+ * @borrows LoggableMixin#logger as #logger
+ * @borrows LoggableMixin#log as #log
+ * @constructs
+ */
+var User = BaseModel.extend( LoggableMixin ).extend(
+/** @lends User.prototype */{
+
+ ///** logger used to record this.log messages, commonly set to console */
+ //// comment this out to suppress log output
+ //logger : console,
+
+ /** API location for this resource */
urlRoot : 'api/users',
- defaults : {
+ /** Model defaults
+ * Note: don't check for anon-users with the username as the default is '(anonymous user)'
+ * a safer method is if( !user.get( 'email' ) ) -> anon user
+ */
+ defaults : /** @lends User.prototype */{
id : null,
username : '(' + _l( "anonymous user" ) + ')',
email : "",
total_disk_usage : 0,
- nice_total_disk_usage : "0 bytes"
+ nice_total_disk_usage : "0 bytes",
+ quota_percent : null
},
+ /** Set up and bind events
+ * @param {Object} data Initial model data.
+ */
initialize : function( data ){
this.log( 'User.initialize:', data );
@@ -17,12 +39,25 @@
this.on( 'change', function( model, data ){ this.log( this + ' has changed:', model, data.changes ); });
},
- // events: loaded
+ isAnonymous : function(){
+ return ( !this.get( 'email' ) );
+ },
+
+ /** Load a user with the API using an id.
+ * If getting an anonymous user or no access to a user id, pass the User.CURRENT_ID_STR
+ * (e.g. 'current') and the API will return the current transaction's user data.
+ * @param {String} idOrCurrent encoded user id or the User.CURRENT_ID_STR
+ * @param {Object} options hash to pass to Backbone.Model.fetch. Can contain success, error fns.
+ * @fires loaded when the model has been loaded from the API, passing the newModel and AJAX response.
+ */
loadFromApi : function( idOrCurrent, options ){
idOrCurrent = idOrCurrent || User.CURRENT_ID_STR;
+
options = options || {};
var model = this,
userFn = options.success;
+
+ /** @ignore */
options.success = function( newModel, response ){
model.trigger( 'loaded', newModel, response );
if( userFn ){ userFn( newModel, response ); }
@@ -35,6 +70,7 @@
return BaseModel.prototype.fetch.call( this, options );
},
+ /** string representation */
toString : function(){
var userInfo = [ this.get( 'username' ) ];
if( this.get( 'id' ) ){
diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/user/user-quotameter.js
--- a/static/scripts/mvc/user/user-quotameter.js
+++ b/static/scripts/mvc/user/user-quotameter.js
@@ -1,17 +1,27 @@
-// strange view that spans two frames: renders to two separate elements based on a User's disk usage:
-// a quota/usage bar (curr. masthead), and
-// an over-quota message (curr. history panel)
+/** @class View to display a user's disk/storage usage
+ * either as a progress bar representing the percentage of a quota used
+ * or a simple text element displaying the human readable size used.
+ * @name UserQuotaMeter
+ *
+ * @augments BaseModel
+ * @borrows LoggableMixin#logger as #logger
+ * @borrows LoggableMixin#log as #log
+ * @constructs
+ */
+var UserQuotaMeter = BaseView.extend( LoggableMixin ).extend(
+/** @lends UserQuotaMeter.prototype */{
+
+ ///** logger used to record this.log messages, commonly set to console */
+ //// comment this out to suppress log output
+ //logger : console,
-// for now, keep the view in the history panel (where the message is), but render ALSO to the masthead
-
-var UserQuotaMeter = BaseView.extend( LoggableMixin ).extend({
- //logger : console,
-
+ /** Defaults for optional settings passed to initialize */
options : {
warnAtPercent : 85,
errorAtPercent : 100
},
+ /** Set up, accept options, and bind events */
initialize : function( options ){
this.log( this + '.initialize:', options );
_.extend( this.options, options );
@@ -20,18 +30,29 @@
this.model.bind( 'change:quota_percent change:total_disk_usage', this.render, this );
},
+ /** Re-load user model data from the api */
update : function( options ){
this.log( this + ' updating user data...', options );
this.model.loadFromApi( this.model.get( 'id' ), options );
return this;
},
+ /** Is the user over their quota (if there is one)?
+ * @returns {Boolean} true if over quota, false if no quota or under quota
+ */
isOverQuota : function(){
return ( this.model.get( 'quota_percent' ) !== null
&& this.model.get( 'quota_percent' ) >= this.options.errorAtPercent );
},
- // events: quota:over, quota:under, quota:under:approaching, quota:under:ok
+ /** Render the meter when they have an applicable quota. Will render as a progress bar
+ * with their percentage of that quota in text over the bar.
+ * @fires quota:over when user is over quota (>= this.errorAtPercent)
+ * @fires quota:under when user is under quota
+ * @fires quota:under:approaching when user is >= this.warnAtPercent of their quota
+ * @fires quota:under:ok when user is below this.warnAtPercent
+ * @returns {jQuery} the rendered meter
+ */
_render_quota : function(){
var modelJson = this.model.toJSON(),
//prevPercent = this.model.previous( 'quota_percent' ),
@@ -63,12 +84,20 @@
return meter;
},
+ /** Render the meter when the user has NO applicable quota. Will render as text
+ * showing the human readable sum storage their data is using.
+ * @returns {jQuery} the rendered text
+ */
_render_usage : function(){
var usage = $( UserQuotaMeter.templates.usage( this.model.toJSON() ) );
this.log( this + '.rendering usage:', usage );
return usage;
},
+ /** Render either the quota percentage meter or the human readable disk usage
+ * depending on whether the user model has quota info (quota_percent === null -> no quota)
+ * @returns {Object} this UserQuotaMeter
+ */
render : function(){
//this.log( this + '.rendering' );
var meterHtml = null;
@@ -93,6 +122,9 @@
return 'UserQuotaMeter(' + this.model + ')';
}
});
+
+
+//------------------------------------------------------------------------------ TEMPLATES
UserQuotaMeter.templates = {
quota : Handlebars.templates[ 'template-user-quotaMeter-quota' ],
usage : Handlebars.templates[ 'template-user-quotaMeter-usage' ]
diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e 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
@@ -193,7 +193,8 @@
return "Your history is empty. Click 'Get Data' on the left pane to start";}
- buffer += "\n<div id=\"history-controls\">\n <div id=\"history-title-area\" class=\"historyLinks\">\n\n <div id=\"history-name-container\" style=\"float: left;\">\n ";
+ buffer += "<div id=\"history-controls\">\n <div id=\"history-title-area\" class=\"historyLinks\">\n\n ";
+ buffer += "\n <div id=\"history-name-container\" style=\"float: left;\">\n ";
buffer += "\n ";
stack1 = depth0.user;
stack1 = stack1 == null || stack1 === false ? stack1 : stack1.email;
@@ -205,7 +206,7 @@
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(7, program7, data)}); }
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\"\n href=\"javascript:void(0);\" style=\"float: right;\">\n <span class=\"ficon cog large\"></span>\n </a>\n <div style=\"clear: both;\"></div>\n </div>\n\n <div id=\"history-subtitle-area\">\n <div id=\"history-size\" style=\"float:left;\">";
+ buffer += "\"\n href=\"javascript:void(0);\" style=\"float: right;\">\n <span class=\"ficon cogs large\"></span>\n </a>\n <div style=\"clear: both;\"></div>\n </div>\n\n <div id=\"history-subtitle-area\">\n <div id=\"history-size\" style=\"float:left;\">";
foundHelper = helpers.nice_size;
if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
else { stack1 = depth0.nice_size; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/templates/history-templates.html
--- a/static/scripts/templates/history-templates.html
+++ b/static/scripts/templates/history-templates.html
@@ -19,7 +19,7 @@
<a id="history-action-popup" class="tooltip" title="{{#local}}Click to see more actions{{/local}}"
href="javascript:void(0);" style="float: right;">
- <span class="ficon cog large"></span>
+ <span class="ficon cogs large"></span></a><div style="clear: both;"></div></div>
diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e templates/root/alternate_history.mako
--- a/templates/root/alternate_history.mako
+++ b/templates/root/alternate_history.mako
@@ -423,7 +423,6 @@
width: 90%;
margin: -2px 0px -3px -4px;
font-weight: bold;
- font-size: 110%;
color: black;
}
https://bitbucket.org/galaxy/galaxy-central/changeset/4e50648f6e5d/
changeset: 4e50648f6e5d
user: carlfeberhard
date: 2012-11-15 17:25:58
summary: pack scripts
affected #: 9 files
diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/mvc/base-mvc.js
--- a/static/scripts/packed/mvc/base-mvc.js
+++ b/static/scripts/packed/mvc/base-mvc.js
@@ -1,1 +1,1 @@
-var BaseModel=Backbone.RelationalModel.extend({defaults:{name:null,hidden:false},show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}});var BaseView=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){if(this.model.attributes.hidden){this.$el.hide()}else{this.$el.show()}}});var LoggableMixin={logger:null,log:function(){if(this.logger){return this.logger.log.apply(this.logger,arguments)}return undefined}};var GalaxyLocalization=jQuery.extend({},{ALIAS_NAME:"_l",localizedStrings:{},setLocalizedString:function(b,a){var c=this;var d=function(f,e){if(f!==e){c.localizedStrings[f]=e}};if(jQuery.type(b)==="string"){d(b,a)}else{if(jQuery.type(b)==="object"){jQuery.each(b,function(e,f){d(e,f)})}else{throw ("Localization.setLocalizedString needs either a string or object as the first argument, given: "+b)}}},localize:function(a){return this.localizedStrings[a]||a},toString:function(){return"GalaxyLocalization"}});window[GalaxyLocalization.ALIAS_NAME]=function(a){return GalaxyLocalization.localize(a)};var PersistantStorage=function(g,d){if(!g){throw ("PersistantStorage needs storageKey argument")}d=d||{};var b=jQuery.jStorage.get,c=jQuery.jStorage.set,a=jQuery.jStorage.deleteKey;var e=function(i,h){i=i||{};h=h||null;return{get:function(j){if(j===undefined){return i}else{if(i.hasOwnProperty(j)){return(jQuery.type(i[j])==="object")?(new e(i[j],this)):(i[j])}}return undefined},set:function(j,k){i[j]=k;this.save();return this},deleteKey:function(j){delete i[j];this.save();return this},save:function(){return h.save()},toString:function(){return("StorageRecursionHelper("+i+")")}}};var f={};data=b(g);if(data===null){data=jQuery.extend(true,{},d);c(g,data)}f=new e(data);f.save=function(h){c(g,f.get())};f.destroy=function(){a(g)};f.toString=function(){return"PersistantStorage("+data+")"};return f};
\ No newline at end of file
+var BaseModel=Backbone.RelationalModel.extend({defaults:{name:null,hidden:false},show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}});var BaseView=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){if(this.model.attributes.hidden){this.$el.hide()}else{this.$el.show()}}});var LoggableMixin={logger:null,log:function(){if(this.logger){return this.logger.log.apply(this.logger,arguments)}return undefined}};var GalaxyLocalization=jQuery.extend({},{ALIAS_NAME:"_l",localizedStrings:{},setLocalizedString:function(b,a){var c=this;var d=function(f,e){if(f!==e){c.localizedStrings[f]=e}};if(jQuery.type(b)==="string"){d(b,a)}else{if(jQuery.type(b)==="object"){jQuery.each(b,function(e,f){d(e,f)})}else{throw ("Localization.setLocalizedString needs either a string or object as the first argument, given: "+b)}}},localize:function(a){return this.localizedStrings[a]||a},toString:function(){return"GalaxyLocalization"}});window[GalaxyLocalization.ALIAS_NAME]=function(a){return GalaxyLocalization.localize(a)};var PersistantStorage=function(g,d){if(!g){throw ("PersistantStorage needs storageKey argument")}d=d||{};var b=jQuery.jStorage.get,c=jQuery.jStorage.set,a=jQuery.jStorage.deleteKey;function e(i,h){i=i||{};h=h||null;return{get:function(j){if(j===undefined){return i}else{if(i.hasOwnProperty(j)){return(jQuery.type(i[j])==="object")?(new e(i[j],this)):(i[j])}}return undefined},set:function(j,k){i[j]=k;this._save();return this},deleteKey:function(j){delete i[j];this._save();return this},_save:function(){return h._save()},toString:function(){return("StorageRecursionHelper("+i+")")}}}var f={};data=b(g);if(data===null){data=jQuery.extend(true,{},d);c(g,data)}f=new e(data);jQuery.extend(f,{_save:function(h){return c(g,f.get())},destroy:function(){return a(g)},toString:function(){return"PersistantStorage("+data+")"}});return f};
\ No newline at end of file
diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/mvc/dataset/hda-base.js
--- a/static/scripts/packed/mvc/dataset/hda-base.js
+++ b/static/scripts/packed/mvc/dataset/hda-base.js
@@ -1,1 +1,1 @@
-var HDABaseView=BaseView.extend(LoggableMixin).extend({tagName:"div",className:"historyItemContainer",initialize:function(a){this.log(this+".initialize:",a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton];if(!a.urlTemplates){throw ("HDAView needs urlTemplates on initialize")}this.urls=this.renderUrls(a.urlTemplates,this.model.toJSON());this.expanded=a.expanded||false;this.model.bind("change",this.render,this)},renderUrls:function(d,a){var b=this,c={};_.each(d,function(e,f){if(_.isObject(e)){c[f]=b.renderUrls(e,a)}else{if(f==="meta_download"){c[f]=b.renderMetaDownloadUrls(e,a)}else{c[f]=_.template(e,a)}}});return c},renderMetaDownloadUrls:function(b,a){return _.map(a.meta_files,function(c){return{url:_.template(b,{id:a.id,file_type:c.file_type}),file_type:c.file_type}})},render:function(){var b=this,e=this.model.get("id"),c=this.model.get("state"),a=$("<div/>").attr("id","historyItem-"+e),d=(this.$el.children().size()===0);this.$el.attr("id","historyItemContainer-"+e);a.addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+c);a.append(this._render_warnings());a.append(this._render_titleBar());this.body=$(this._render_body());a.append(this.body);make_popup_menus(a);a.find(".tooltip").tooltip({placement:"bottom"});this.$el.fadeOut("fast",function(){b.$el.children().remove();b.$el.append(a).fadeIn("fast",function(){b.log(b+" rendered:",b.$el);var f="rendered";if(d){f+=":initial"}else{if(b.model.inReadyState()){f+=":ready"}}b.trigger(f)})});return this},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());return a},_render_displayButton:function(){if((!this.model.inReadyState())||(this.model.get("state")===HistoryDatasetAssociation.STATES.ERROR)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.displayButton=null;return null}var a={icon_class:"display",target:"galaxy_main"};if(this.model.get("purged")){a.enabled=false;a.title=_l("Cannot display datasets removed from disk")}else{a.title=_l("Display data in browser");a.href=this.urls.display}this.displayButton=new IconButtonView({model:new IconButton(a)});return this.displayButton.render().$el},_render_titleLink:function(){return $(jQuery.trim(HDABaseView.templates.titleLink(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});return HDABaseView.templates.hdaSummary(a)},_render_primaryActionButtons:function(c){var a=this,b=$("<div/>").attr("id","primary-actions-"+this.model.get("id"));_.each(c,function(d){b.append(d.call(a))});return b},_render_downloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}var a=HDABaseView.templates.downloadLinks(_.extend(this.model.toJSON(),{urls:this.urls}));return $(a)},_render_showParamsButton:function(){this.showParamsButton=new IconButtonView({model:new IconButton({title:_l("View details"),href:this.urls.show_params,target:"galaxy_main",icon_class:"information"})});return this.showParamsButton.render().$el},_render_displayApps:function(){if(!this.model.hasData()){return null}var a=$("<div/>").addClass("display-apps");if(!_.isEmpty(this.model.get("display_types"))){a.append(HDABaseView.templates.displayApps({displayApps:this.model.get("display_types")}))}if(!_.isEmpty(this.model.get("display_apps"))){a.append(HDABaseView.templates.displayApps({displayApps:this.model.get("display_apps")}))}return a},_render_peek:function(){if(!this.model.get("peek")){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(this.model.get("peek")))},_render_body_not_viewable:function(a){a.append($("<div>"+_l("You do not have permission to view dataset")+".</div>"))},_render_body_uploading:function(a){a.append($("<div>"+_l("Dataset is uploading")+"</div>"))},_render_body_queued:function(a){a.append($("<div>"+_l("Job is waiting to run")+".</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_running:function(a){a.append("<div>"+_l("Job is currently running")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append((_l("An error occurred running this job")+": <i>"+$.trim(this.model.get("misc_info"))+"</i>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers.concat([this._render_downloadButton])))},_render_body_discarded:function(a){a.append("<div>"+_l("The job creating this dataset was cancelled before completion")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_setting_metadata:function(a){a.append($("<div>"+_l("Metadata is being auto-detected")+".</div>"))},_render_body_empty:function(a){a.append($("<div>"+_l("No data")+": <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_failed_metadata:function(a){a.append($(HDABaseView.templates.failedMetadata(this.model.toJSON())));this._render_body_ok(a)},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));a.append('<div class="clear"/>');a.append(this._render_displayApps());a.append(this._render_peek())},_render_body:function(){var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: block");switch(this.model.get("state")){case HistoryDatasetAssociation.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryDatasetAssociation.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryDatasetAssociation.STATES.QUEUED:this._render_body_queued(a);break;case HistoryDatasetAssociation.STATES.RUNNING:this._render_body_running(a);break;case HistoryDatasetAssociation.STATES.ERROR:this._render_body_error(a);break;case HistoryDatasetAssociation.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryDatasetAssociation.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryDatasetAssociation.STATES.EMPTY:this._render_body_empty(a);break;case HistoryDatasetAssociation.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryDatasetAssociation.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+state+'".</div>'))}a.append('<div style="clear: both"></div>');if(this.expanded){a.show()}else{a.hide()}return a},events:{"click .historyItemTitle":"toggleBodyVisibility"},toggleBodyVisibility:function(c,a){var b=this,d=this.$el.find(".historyItemBody");a=(a===undefined)?(!d.is(":visible")):(a);if(a){d.slideDown("fast",function(){b.trigger("body-visible",b.model.get("id"))})}else{d.slideUp("fast",function(){b.trigger("body-hidden",b.model.get("id"))})}},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDABaseView("+a+")"}});HDABaseView.templates={warningMsg:Handlebars.templates["template-warningmessagesmall"],messages:Handlebars.templates["template-hda-warning-messages"],titleLink:Handlebars.templates["template-hda-titleLink"],hdaSummary:Handlebars.templates["template-hda-hdaSummary"],downloadLinks:Handlebars.templates["template-hda-downloadLinks"],failedMetadata:Handlebars.templates["template-hda-failedMetaData"],displayApps:Handlebars.templates["template-hda-displayApps"]};
\ No newline at end of file
+var HDABaseView=BaseView.extend(LoggableMixin).extend({tagName:"div",className:"historyItemContainer",initialize:function(a){this.log(this+".initialize:",a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton];if(!a.urlTemplates){throw ("HDAView needs urlTemplates on initialize")}this.urls=this._renderUrls(a.urlTemplates,this.model.toJSON());this.expanded=a.expanded||false;this.model.bind("change",this.render,this)},_renderUrls:function(d,a){var b=this,c={};_.each(d,function(e,f){if(_.isObject(e)){c[f]=b._renderUrls(e,a)}else{if(f==="meta_download"){c[f]=b._renderMetaDownloadUrls(e,a)}else{c[f]=_.template(e,a)}}});return c},_renderMetaDownloadUrls:function(b,a){return _.map(a.meta_files,function(c){return{url:_.template(b,{id:a.id,file_type:c.file_type}),file_type:c.file_type}})},render:function(){var b=this,e=this.model.get("id"),c=this.model.get("state"),a=$("<div/>").attr("id","historyItem-"+e),d=(this.$el.children().size()===0);this.$el.attr("id","historyItemContainer-"+e);a.addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+c);a.append(this._render_warnings());a.append(this._render_titleBar());this.body=$(this._render_body());a.append(this.body);make_popup_menus(a);a.find(".tooltip").tooltip({placement:"bottom"});this.$el.fadeOut("fast",function(){b.$el.children().remove();b.$el.append(a).fadeIn("fast",function(){b.log(b+" rendered:",b.$el);var f="rendered";if(d){f+=":initial"}else{if(b.model.inReadyState()){f+=":ready"}}b.trigger(f)})});return this},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());return a},_render_displayButton:function(){if((!this.model.inReadyState())||(this.model.get("state")===HistoryDatasetAssociation.STATES.ERROR)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.displayButton=null;return null}var a={icon_class:"display",target:"galaxy_main"};if(this.model.get("purged")){a.enabled=false;a.title=_l("Cannot display datasets removed from disk")}else{a.title=_l("Display data in browser");a.href=this.urls.display}this.displayButton=new IconButtonView({model:new IconButton(a)});return this.displayButton.render().$el},_render_titleLink:function(){return $(jQuery.trim(HDABaseView.templates.titleLink(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});return HDABaseView.templates.hdaSummary(a)},_render_primaryActionButtons:function(c){var a=this,b=$("<div/>").attr("id","primary-actions-"+this.model.get("id"));_.each(c,function(d){b.append(d.call(a))});return b},_render_downloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}var a=HDABaseView.templates.downloadLinks(_.extend(this.model.toJSON(),{urls:this.urls}));return $(a)},_render_showParamsButton:function(){this.showParamsButton=new IconButtonView({model:new IconButton({title:_l("View details"),href:this.urls.show_params,target:"galaxy_main",icon_class:"information"})});return this.showParamsButton.render().$el},_render_displayApps:function(){if(!this.model.hasData()){return null}var a=$("<div/>").addClass("display-apps");if(!_.isEmpty(this.model.get("display_types"))){a.append(HDABaseView.templates.displayApps({displayApps:this.model.get("display_types")}))}if(!_.isEmpty(this.model.get("display_apps"))){a.append(HDABaseView.templates.displayApps({displayApps:this.model.get("display_apps")}))}return a},_render_peek:function(){if(!this.model.get("peek")){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(this.model.get("peek")))},_render_body:function(){var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: block");switch(this.model.get("state")){case HistoryDatasetAssociation.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryDatasetAssociation.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryDatasetAssociation.STATES.QUEUED:this._render_body_queued(a);break;case HistoryDatasetAssociation.STATES.RUNNING:this._render_body_running(a);break;case HistoryDatasetAssociation.STATES.ERROR:this._render_body_error(a);break;case HistoryDatasetAssociation.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryDatasetAssociation.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryDatasetAssociation.STATES.EMPTY:this._render_body_empty(a);break;case HistoryDatasetAssociation.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryDatasetAssociation.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+state+'".</div>'))}a.append('<div style="clear: both"></div>');if(this.expanded){a.show()}else{a.hide()}return a},_render_body_not_viewable:function(a){a.append($("<div>"+_l("You do not have permission to view dataset")+".</div>"))},_render_body_uploading:function(a){a.append($("<div>"+_l("Dataset is uploading")+"</div>"))},_render_body_queued:function(a){a.append($("<div>"+_l("Job is waiting to run")+".</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_running:function(a){a.append("<div>"+_l("Job is currently running")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append((_l("An error occurred running this job")+": <i>"+$.trim(this.model.get("misc_info"))+"</i>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers.concat([this._render_downloadButton])))},_render_body_discarded:function(a){a.append("<div>"+_l("The job creating this dataset was cancelled before completion")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_setting_metadata:function(a){a.append($("<div>"+_l("Metadata is being auto-detected")+".</div>"))},_render_body_empty:function(a){a.append($("<div>"+_l("No data")+": <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_failed_metadata:function(a){a.append($(HDABaseView.templates.failedMetadata(this.model.toJSON())));this._render_body_ok(a)},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));a.append('<div class="clear"/>');a.append(this._render_displayApps());a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility"},toggleBodyVisibility:function(c,a){var b=this,d=this.$el.find(".historyItemBody");a=(a===undefined)?(!d.is(":visible")):(a);if(a){d.slideDown("fast",function(){b.trigger("body-expanded",b.model.get("id"))})}else{d.slideUp("fast",function(){b.trigger("body-collapsed",b.model.get("id"))})}},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDABaseView("+a+")"}});HDABaseView.templates={warningMsg:Handlebars.templates["template-warningmessagesmall"],messages:Handlebars.templates["template-hda-warning-messages"],titleLink:Handlebars.templates["template-hda-titleLink"],hdaSummary:Handlebars.templates["template-hda-hdaSummary"],downloadLinks:Handlebars.templates["template-hda-downloadLinks"],failedMetadata:Handlebars.templates["template-hda-failedMetaData"],displayApps:Handlebars.templates["template-hda-displayApps"]};
\ No newline at end of file
diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/mvc/dataset/hda-edit.js
--- a/static/scripts/packed/mvc/dataset/hda-edit.js
+++ b/static/scripts/packed/mvc/dataset/hda-edit.js
@@ -1,1 +1,1 @@
-var HDAEditView=HDABaseView.extend({initialize:function(a){HDABaseView.prototype.initialize.call(this,a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton,this._render_rerunButton]},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());a.append(this._render_editButton());a.append(this._render_deleteButton());return a},_render_editButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.UPLOAD)||(this.model.get("state")===HistoryDatasetAssociation.STATES.ERROR)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.editButton=null;return null}var c=this.model.get("purged"),a=this.model.get("deleted"),b={title:_l("Edit Attributes"),href:this.urls.edit,target:"galaxy_main",icon_class:"edit"};if(a||c){b.enabled=false;if(c){b.title=_l("Cannot edit attributes of datasets removed from disk")}else{if(a){b.title=_l("Undelete dataset to edit attributes")}}}this.editButton=new IconButtonView({model:new IconButton(b)});return this.editButton.render().$el},_render_deleteButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.deleteButton=null;return null}var a={title:_l("Delete"),href:this.urls["delete"],id:"historyItemDeleter-"+this.model.get("id"),icon_class:"delete"};if(this.model.get("deleted")||this.model.get("purged")){a={title:_l("Dataset is already deleted"),icon_class:"delete",enabled:false}}this.deleteButton=new IconButtonView({model:new IconButton(a)});return this.deleteButton.render().$el},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){_.extend(a,{dbkey_unknown_and_editable:true})}return HDABaseView.templates.hdaSummary(a)},_render_errButton:function(){if(this.model.get("state")!==HistoryDatasetAssociation.STATES.ERROR){this.errButton=null;return null}this.errButton=new IconButtonView({model:new IconButton({title:_l("View or report this error"),href:this.urls.report_error,target:"galaxy_main",icon_class:"bug"})});return this.errButton.render().$el},_render_rerunButton:function(){this.rerunButton=new IconButtonView({model:new IconButton({title:_l("Run this job again"),href:this.urls.rerun,target:"galaxy_main",icon_class:"arrow-circle"})});return this.rerunButton.render().$el},_render_visualizationsButton:function(){var c=this.model.get("dbkey"),a=this.model.get("visualizations"),f=this.urls.visualization,d={},g={dataset_id:this.model.get("id"),hda_ldda:"hda"};if(!(this.model.hasData())||!(a&&a.length)||!(f)){this.visualizationsButton=null;return null}this.visualizationsButton=new IconButtonView({model:new IconButton({title:_l("Visualize"),href:f,icon_class:"chart_curve"})});var b=this.visualizationsButton.render().$el;b.addClass("visualize-icon");if(c){g.dbkey=c}function e(h){switch(h){case"trackster":return create_trackster_action_fn(f,g,c);case"scatterplot":return create_scatterplot_action_fn(f,g);default:return function(){window.parent.location=f+"/"+h+"?"+$.param(g)}}}if(a.length===1){b.attr("title",a[0]);b.click(e(a[0]))}else{_.each(a,function(i){var h=i.charAt(0).toUpperCase()+i.slice(1);d[_l(h)]=e(i)});make_popupmenu(b,d)}return b},_render_secondaryActionButtons:function(b){var c=$("<div/>"),a=this;c.attr("style","float: right;").attr("id","secondary-actions-"+this.model.get("id"));_.each(b,function(d){c.append(d.call(a))});return c},_render_tagButton:function(){if(!(this.model.hasData())||(!this.urls.tags.get)){this.tagButton=null;return null}this.tagButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset tags"),target:"galaxy_main",href:this.urls.tags.get,icon_class:"tags"})});return this.tagButton.render().$el},_render_annotateButton:function(){if(!(this.model.hasData())||(!this.urls.annotation.get)){this.annotateButton=null;return null}this.annotateButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset annotation"),target:"galaxy_main",icon_class:"annotate"})});return this.annotateButton.render().$el},_render_tagArea:function(){if(!this.urls.tags.set){return null}return $(HDAEditView.templates.tagArea(_.extend(this.model.toJSON(),{urls:this.urls})))},_render_annotationArea:function(){if(!this.urls.annotation.get){return null}return $(HDAEditView.templates.annotationArea(_.extend(this.model.toJSON(),{urls:this.urls})))},_render_body_error:function(a){HDABaseView.prototype._render_body_error.call(this,a);var b=a.find("#primary-actions-"+this.model.get("id"));b.prepend(this._render_errButton())},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton,this._render_visualizationsButton]));a.append(this._render_secondaryActionButtons([this._render_tagButton,this._render_annotateButton]));a.append('<div class="clear"/>');a.append(this._render_tagArea());a.append(this._render_annotationArea());a.append(this._render_displayApps());a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility","click a.icon-button.tags":"loadAndDisplayTags","click a.icon-button.annotate":"loadAndDisplayAnnotation"},loadAndDisplayTags:function(b){this.log(this+".loadAndDisplayTags",b);var c=this.$el.find(".tag-area"),a=c.find(".tag-elt");if(c.is(":hidden")){if(!jQuery.trim(a.html())){$.ajax({url:this.urls.tags.get,error:function(){alert(_l("Tagging failed"))},success:function(d){a.html(d);a.find(".tooltip").tooltip();c.slideDown("fast")}})}else{c.slideDown("fast")}}else{c.slideUp("fast")}return false},loadAndDisplayAnnotation:function(b){this.log(this+".loadAndDisplayAnnotation",b);var d=this.$el.find(".annotation-area"),c=d.find(".annotation-elt"),a=this.urls.annotation.set;if(d.is(":hidden")){if(!jQuery.trim(c.html())){$.ajax({url:this.urls.annotation.get,error:function(){alert(_l("Annotations failed"))},success:function(e){if(e===""){e="<em>"+_l("Describe or add notes to dataset")+"</em>"}c.html(e);d.find(".tooltip").tooltip();async_save_text(c.attr("id"),c.attr("id"),a,"new_annotation",18,true,4);d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDAView("+a+")"}});HDAEditView.templates={tagArea:Handlebars.templates["template-hda-tagArea"],annotationArea:Handlebars.templates["template-hda-annotationArea"]};function create_scatterplot_action_fn(a,b){action=function(){var d=$(window.parent.document).find("iframe#galaxy_main"),c=a+"/scatterplot?"+$.param(b);d.attr("src",c);$("div.popmenu-wrapper").remove();return false};return action}function create_trackster_action_fn(a,c,b){return function(){var d={};if(b){d.dbkey=b}$.ajax({url:a+"/list_tracks?f-"+$.param(d),dataType:"html",error:function(){alert(_l("Could not add this dataset to browser")+".")},success:function(e){var f=window.parent;f.show_modal(_l("View Data in a New or Saved Visualization"),"",{Cancel:function(){f.hide_modal()},"View in saved visualization":function(){f.show_modal(_l("Add Data to Saved Visualization"),e,{Cancel:function(){f.hide_modal()},"Add to visualization":function(){$(f.document).find("input[name=id]:checked").each(function(){var g=$(this).val();c.id=g;f.location=a+"/trackster?"+$.param(c)})}})},"View in new visualization":function(){f.location=a+"/trackster?"+$.param(c)}})}});return false}};
\ No newline at end of file
+var HDAEditView=HDABaseView.extend(LoggableMixin).extend({initialize:function(a){HDABaseView.prototype.initialize.call(this,a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton,this._render_rerunButton]},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());a.append(this._render_editButton());a.append(this._render_deleteButton());return a},_render_editButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.UPLOAD)||(this.model.get("state")===HistoryDatasetAssociation.STATES.ERROR)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.editButton=null;return null}var c=this.model.get("purged"),a=this.model.get("deleted"),b={title:_l("Edit Attributes"),href:this.urls.edit,target:"galaxy_main",icon_class:"edit"};if(a||c){b.enabled=false;if(c){b.title=_l("Cannot edit attributes of datasets removed from disk")}else{if(a){b.title=_l("Undelete dataset to edit attributes")}}}this.editButton=new IconButtonView({model:new IconButton(b)});return this.editButton.render().$el},_render_deleteButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.deleteButton=null;return null}var a={title:_l("Delete"),href:this.urls["delete"],id:"historyItemDeleter-"+this.model.get("id"),icon_class:"delete"};if(this.model.get("deleted")||this.model.get("purged")){a={title:_l("Dataset is already deleted"),icon_class:"delete",enabled:false}}this.deleteButton=new IconButtonView({model:new IconButton(a)});return this.deleteButton.render().$el},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){_.extend(a,{dbkey_unknown_and_editable:true})}return HDABaseView.templates.hdaSummary(a)},_render_errButton:function(){if(this.model.get("state")!==HistoryDatasetAssociation.STATES.ERROR){this.errButton=null;return null}this.errButton=new IconButtonView({model:new IconButton({title:_l("View or report this error"),href:this.urls.report_error,target:"galaxy_main",icon_class:"bug"})});return this.errButton.render().$el},_render_rerunButton:function(){this.rerunButton=new IconButtonView({model:new IconButton({title:_l("Run this job again"),href:this.urls.rerun,target:"galaxy_main",icon_class:"arrow-circle"})});return this.rerunButton.render().$el},_render_visualizationsButton:function(){var c=this.model.get("dbkey"),a=this.model.get("visualizations"),f=this.urls.visualization,d={},g={dataset_id:this.model.get("id"),hda_ldda:"hda"};if(!(this.model.hasData())||!(a&&a.length)||!(f)){this.visualizationsButton=null;return null}this.visualizationsButton=new IconButtonView({model:new IconButton({title:_l("Visualize"),href:f,icon_class:"chart_curve"})});var b=this.visualizationsButton.render().$el;b.addClass("visualize-icon");if(c){g.dbkey=c}function e(h){switch(h){case"trackster":return create_trackster_action_fn(f,g,c);case"scatterplot":return create_scatterplot_action_fn(f,g);default:return function(){window.parent.location=f+"/"+h+"?"+$.param(g)}}}if(a.length===1){b.attr("title",a[0]);b.click(e(a[0]))}else{_.each(a,function(i){var h=i.charAt(0).toUpperCase()+i.slice(1);d[_l(h)]=e(i)});make_popupmenu(b,d)}return b},_render_secondaryActionButtons:function(b){var c=$("<div/>"),a=this;c.attr("style","float: right;").attr("id","secondary-actions-"+this.model.get("id"));_.each(b,function(d){c.append(d.call(a))});return c},_render_tagButton:function(){if(!(this.model.hasData())||(!this.urls.tags.get)){this.tagButton=null;return null}this.tagButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset tags"),target:"galaxy_main",href:this.urls.tags.get,icon_class:"tags"})});return this.tagButton.render().$el},_render_annotateButton:function(){if(!(this.model.hasData())||(!this.urls.annotation.get)){this.annotateButton=null;return null}this.annotateButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset annotation"),target:"galaxy_main",icon_class:"annotate"})});return this.annotateButton.render().$el},_render_tagArea:function(){if(!this.urls.tags.set){return null}return $(HDAEditView.templates.tagArea(_.extend(this.model.toJSON(),{urls:this.urls})))},_render_annotationArea:function(){if(!this.urls.annotation.get){return null}return $(HDAEditView.templates.annotationArea(_.extend(this.model.toJSON(),{urls:this.urls})))},_render_body_error:function(a){HDABaseView.prototype._render_body_error.call(this,a);var b=a.find("#primary-actions-"+this.model.get("id"));b.prepend(this._render_errButton())},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton,this._render_visualizationsButton]));a.append(this._render_secondaryActionButtons([this._render_tagButton,this._render_annotateButton]));a.append('<div class="clear"/>');a.append(this._render_tagArea());a.append(this._render_annotationArea());a.append(this._render_displayApps());a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility","click a.icon-button.tags":"loadAndDisplayTags","click a.icon-button.annotate":"loadAndDisplayAnnotation"},loadAndDisplayTags:function(b){this.log(this+".loadAndDisplayTags",b);var c=this.$el.find(".tag-area"),a=c.find(".tag-elt");if(c.is(":hidden")){if(!jQuery.trim(a.html())){$.ajax({url:this.urls.tags.get,error:function(){alert(_l("Tagging failed"))},success:function(d){a.html(d);a.find(".tooltip").tooltip();c.slideDown("fast")}})}else{c.slideDown("fast")}}else{c.slideUp("fast")}return false},loadAndDisplayAnnotation:function(b){this.log(this+".loadAndDisplayAnnotation",b);var d=this.$el.find(".annotation-area"),c=d.find(".annotation-elt"),a=this.urls.annotation.set;if(d.is(":hidden")){if(!jQuery.trim(c.html())){$.ajax({url:this.urls.annotation.get,error:function(){alert(_l("Annotations failed"))},success:function(e){if(e===""){e="<em>"+_l("Describe or add notes to dataset")+"</em>"}c.html(e);d.find(".tooltip").tooltip();async_save_text(c.attr("id"),c.attr("id"),a,"new_annotation",18,true,4);d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDAView("+a+")"}});HDAEditView.templates={tagArea:Handlebars.templates["template-hda-tagArea"],annotationArea:Handlebars.templates["template-hda-annotationArea"]};function create_scatterplot_action_fn(a,b){action=function(){var d=$(window.parent.document).find("iframe#galaxy_main"),c=a+"/scatterplot?"+$.param(b);d.attr("src",c);$("div.popmenu-wrapper").remove();return false};return action}function create_trackster_action_fn(a,c,b){return function(){var d={};if(b){d.dbkey=b}$.ajax({url:a+"/list_tracks?f-"+$.param(d),dataType:"html",error:function(){alert(_l("Could not add this dataset to browser")+".")},success:function(e){var f=window.parent;f.show_modal(_l("View Data in a New or Saved Visualization"),"",{Cancel:function(){f.hide_modal()},"View in saved visualization":function(){f.show_modal(_l("Add Data to Saved Visualization"),e,{Cancel:function(){f.hide_modal()},"Add to visualization":function(){$(f.document).find("input[name=id]:checked").each(function(){var g=$(this).val();c.id=g;f.location=a+"/trackster?"+$.param(c)})}})},"View in new visualization":function(){f.location=a+"/trackster?"+$.param(c)}})}});return false}};
\ No newline at end of file
diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 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 @@
-var HistoryDatasetAssociation=BaseModel.extend(LoggableMixin).extend({defaults:{history_id:null,model_class:"HistoryDatasetAssociation",hid:0,id:null,name:"",state:"",data_type:null,file_size:0,meta_files:[],misc_blurb:"",misc_info:"",deleted:false,purged:false,visible:false,accessible:false},url:function(){return"api/histories/"+this.get("history_id")+"/contents/"+this.get("id")},initialize:function(){this.log(this+".initialize",this.attributes);this.log("\tparent history_id: "+this.get("history_id"));if(!this.get("accessible")){this.set("state",HistoryDatasetAssociation.STATES.NOT_VIEWABLE)}this.on("change:state",function(b,a){this.log(this+" has changed state:",b,a);if(this.inReadyState()){this.trigger("state:ready",this.get("id"),a,this.previous("state"),b)}})},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},isVisible:function(b,c){var a=true;if((!b)&&(this.get("deleted")||this.get("purged"))){a=false}if((!c)&&(!this.get("visible"))){a=false}return a},inReadyState:function(){var a=this.get("state");return((a===HistoryDatasetAssociation.STATES.NEW)||(a===HistoryDatasetAssociation.STATES.OK)||(a===HistoryDatasetAssociation.STATES.EMPTY)||(a===HistoryDatasetAssociation.STATES.FAILED_METADATA)||(a===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(a===HistoryDatasetAssociation.STATES.DISCARDED)||(a===HistoryDatasetAssociation.STATES.ERROR))},hasData:function(){return(this.get("file_size")>0)},toString:function(){var a=this.get("id")||"";if(this.get("name")){a+=':"'+this.get("name")+'"'}return"HistoryDatasetAssociation("+a+")"}});HistoryDatasetAssociation.STATES={UPLOAD:"upload",QUEUED:"queued",RUNNING:"running",SETTING_METADATA:"setting_metadata",NEW:"new",OK:"ok",EMPTY:"empty",FAILED_METADATA:"failed_metadata",NOT_VIEWABLE:"noPermission",DISCARDED:"discarded",ERROR:"error"};var HDACollection=Backbone.Collection.extend(LoggableMixin).extend({model:HistoryDatasetAssociation,initialize:function(){},ids:function(){return this.map(function(a){return a.id})},getVisible:function(a,b){return this.filter(function(c){return c.isVisible(a,b)})},getStateLists:function(){var a={};_.each(_.values(HistoryDatasetAssociation.STATES),function(b){a[b]=[]});this.each(function(b){a[b.get("state")].push(b.get("id"))});return a},running:function(){var a=[];this.each(function(b){if(!b.inReadyState()){a.push(b.get("id"))}});return a},update:function(a){this.log(this+"update:",a);if(!(a&&a.length)){return}var b=this;_.each(a,function(e,c){var d=b.get(e);d.fetch()})},toString:function(){return("HDACollection("+this.ids().join(",")+")")}});
\ No newline at end of file
+var HistoryDatasetAssociation=BaseModel.extend(LoggableMixin).extend({defaults:{history_id:null,model_class:"HistoryDatasetAssociation",hid:0,id:null,name:"",state:"",data_type:null,file_size:0,meta_files:[],misc_blurb:"",misc_info:"",deleted:false,purged:false,visible:false,accessible:false},urlRoot:"api/histories/",url:function(){return"api/histories/"+this.get("history_id")+"/contents/"+this.get("id")},initialize:function(){this.log(this+".initialize",this.attributes);this.log("\tparent history_id: "+this.get("history_id"));if(!this.get("accessible")){this.set("state",HistoryDatasetAssociation.STATES.NOT_VIEWABLE)}this.on("change:state",function(b,a){this.log(this+" has changed state:",b,a);if(this.inReadyState()){this.trigger("state:ready",this.get("id"),a,this.previous("state"),b)}})},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},isVisible:function(b,c){var a=true;if((!b)&&(this.get("deleted")||this.get("purged"))){a=false}if((!c)&&(!this.get("visible"))){a=false}return a},inReadyState:function(){var a=this.get("state");return((a===HistoryDatasetAssociation.STATES.NEW)||(a===HistoryDatasetAssociation.STATES.OK)||(a===HistoryDatasetAssociation.STATES.EMPTY)||(a===HistoryDatasetAssociation.STATES.FAILED_METADATA)||(a===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(a===HistoryDatasetAssociation.STATES.DISCARDED)||(a===HistoryDatasetAssociation.STATES.ERROR))},hasData:function(){return(this.get("file_size")>0)},toString:function(){var a=this.get("id")||"";if(this.get("name")){a+=':"'+this.get("name")+'"'}return"HistoryDatasetAssociation("+a+")"}});HistoryDatasetAssociation.STATES={UPLOAD:"upload",QUEUED:"queued",RUNNING:"running",SETTING_METADATA:"setting_metadata",NEW:"new",EMPTY:"empty",OK:"ok",FAILED_METADATA:"failed_metadata",NOT_VIEWABLE:"noPermission",DISCARDED:"discarded",ERROR:"error"};var HDACollection=Backbone.Collection.extend(LoggableMixin).extend({model:HistoryDatasetAssociation,initialize:function(){},ids:function(){return this.map(function(a){return a.id})},getVisible:function(a,b){return this.filter(function(c){return c.isVisible(a,b)})},getStateLists:function(){var a={};_.each(_.values(HistoryDatasetAssociation.STATES),function(b){a[b]=[]});this.each(function(b){a[b.get("state")].push(b.get("id"))});return a},running:function(){var a=[];this.each(function(b){if(!b.inReadyState()){a.push(b.get("id"))}});return a},update:function(a){this.log(this+"update:",a);if(!(a&&a.length)){return}var b=this;_.each(a,function(e,c){var d=b.get(e);d.fetch()})},toString:function(){return("HDACollection("+this.ids().join(",")+")")}});
\ No newline at end of file
diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/mvc/history/history-model.js
--- a/static/scripts/packed/mvc/history/history-model.js
+++ b/static/scripts/packed/mvc/history/history-model.js
@@ -1,1 +1,1 @@
-var History=BaseModel.extend(LoggableMixin).extend({defaults:{id:"",name:"",state:"",diskSize:0,deleted:false,annotation:null,message:null},url:function(){return"api/histories/"+this.get("id")},initialize:function(a,b){this.log(this+".initialize:",a,b);this.hdas=new HDACollection();if(b&&b.length){this.hdas.reset(b);this.checkForUpdates()}},loadFromApi:function(a,c){var b=this;b.attributes.id=a;jQuery.when(jQuery.ajax("api/users/current"),b.fetch()).then(function(e,d){b.attributes.user=e[0];b.trigger("loaded:user",e[0]);b.trigger("loaded",d[0])}).then(function(){jQuery.ajax(b.url()+"/contents?"+jQuery.param({ids:b.hdaIdsFromStateIds().join(",")})).success(function(d){b.hdas.reset(d);b.checkForUpdates();b.trigger("loaded:hdas",d);if(c){callback(b)}})})},hdaIdsFromStateIds:function(){return _.reduce(_.values(this.get("state_ids")),function(b,a){return b.concat(a)})},checkForUpdates:function(a){if(this.hdas.running().length){this.stateUpdater()}else{this.trigger("ready")}return this},stateUpdater:function(){var c=this,a=this.get("state"),b=this.get("state_ids");jQuery.ajax("api/histories/"+this.get("id")).success(function(d){c.set(d);c.log("current history state:",c.get("state"),"(was)",a,"new size:",c.get("nice_size"));var e=[];_.each(_.keys(d.state_ids),function(g){var f=_.difference(d.state_ids[g],b[g]);e=e.concat(f)});if(e.length){c.hdas.update(e)}if((c.get("state")===HistoryDatasetAssociation.STATES.RUNNING)||(c.get("state")===HistoryDatasetAssociation.STATES.QUEUED)){setTimeout(function(){c.stateUpdater()},4000)}else{c.trigger("ready")}}).error(function(f,d,e){if(console&&console.warn){console.warn("Error getting history updates from the server:",f,d,e)}alert(_l("Error getting history updates from the server.")+"\n"+e)})},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});var HistoryCollection=Backbone.Collection.extend(LoggableMixin).extend({model:History,urlRoot:"api/histories",});
\ No newline at end of file
+var History=BaseModel.extend(LoggableMixin).extend({defaults:{id:"",name:"",state:"",diskSize:0,deleted:false,annotation:null,message:null},urlRoot:"api/histories/",url:function(){return"api/histories/"+this.get("id")},initialize:function(a,b){this.log(this+".initialize:",a,b);this.hdas=new HDACollection();if(b&&b.length){this.hdas.reset(b);this.checkForUpdates()}},loadFromApi:function(a,c){var b=this;b.attributes.id=a;jQuery.when(jQuery.ajax("api/users/current"),b.fetch()).then(function(e,d){b.attributes.user=e[0];b.trigger("loaded:user",e[0]);b.trigger("loaded",d[0])}).then(function(){jQuery.ajax(b.url()+"/contents?"+jQuery.param({ids:b.hdaIdsFromStateIds().join(",")})).success(function(d){b.hdas.reset(d);b.checkForUpdates();b.trigger("loaded:hdas",d);if(c){callback(b)}})})},hdaIdsFromStateIds:function(){return _.reduce(_.values(this.get("state_ids")),function(b,a){return b.concat(a)})},checkForUpdates:function(a){if(this.hdas.running().length){this.stateUpdater()}else{this.trigger("ready")}return this},stateUpdater:function(){var c=this,a=this.get("state"),b=this.get("state_ids");jQuery.ajax("api/histories/"+this.get("id")).success(function(d){c.set(d);c.log("current history state:",c.get("state"),"(was)",a,"new size:",c.get("nice_size"));var e=[];_.each(_.keys(d.state_ids),function(g){var f=_.difference(d.state_ids[g],b[g]);e=e.concat(f)});if(e.length){c.hdas.update(e)}if((c.get("state")===HistoryDatasetAssociation.STATES.RUNNING)||(c.get("state")===HistoryDatasetAssociation.STATES.QUEUED)){setTimeout(function(){c.stateUpdater()},4000)}else{c.trigger("ready")}}).error(function(f,d,e){if(console&&console.warn){console.warn("Error getting history updates from the server:",f,d,e)}alert(_l("Error getting history updates from the server.")+"\n"+e)})},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});var HistoryCollection=Backbone.Collection.extend(LoggableMixin).extend({model:History,urlRoot:"api/histories"});
\ No newline at end of file
diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/mvc/history/history-panel.js
--- a/static/scripts/packed/mvc/history/history-panel.js
+++ b/static/scripts/packed/mvc/history/history-panel.js
@@ -1,1 +1,1 @@
-var HistoryPanel=BaseView.extend(LoggableMixin).extend({el:"body.historyPage",HDAView:HDAEditView,initialize:function(a){this.log(this+".initialize:",a);if(!a.urlTemplates){throw (this+" needs urlTemplates on initialize")}if(!a.urlTemplates.history){throw (this+" needs urlTemplates.history on initialize")}if(!a.urlTemplates.hda){throw (this+" needs urlTemplates.hda on initialize")}this.urlTemplates=a.urlTemplates.history;this.hdaUrlTemplates=a.urlTemplates.hda;this.storage=new PersistantStorage("HistoryView."+this.model.get("id"),{expandedHdas:{},show_deleted:false,show_hidden:false});this.log("this.storage:",this.storage.get());this.log("show_deleted:",a.show_deleted,"show_hidden",a.show_hidden);if((a.show_deleted===true)||(a.show_deleted===false)){this.storage.set("show_deleted",a.show_deleted)}if((a.show_hidden===true)||(a.show_hidden===false)){this.storage.set("show_hidden",a.show_hidden)}this.show_deleted=this.storage.get("show_deleted");this.show_hidden=this.storage.get("show_hidden");this.log("this.show_deleted:",this.show_deleted,"show_hidden",this.show_hidden);this.log("(now) this.storage:",this.storage.get());this.model.bind("change:nice_size",this.updateHistoryDiskSize,this);this.model.hdas.bind("add",this.add,this);this.model.hdas.bind("reset",this.addAll,this);this.model.hdas.bind("all",this.all,this);this.hdaViews={};this.urls={}},add:function(a){},addAll:function(){this.render()},all:function(a){},renderUrls:function(a){var b=this;b.urls={};_.each(this.urlTemplates,function(d,c){b.urls[c]=_.template(d,a)});return b.urls},render:function(){var b=this,d=b.toString()+".set-up",c=$("<div/>"),a=this.model.toJSON(),e=(this.$el.children().size()===0);a.urls=this.renderUrls(a);c.append(HistoryPanel.templates.historyPanel(a));c.find(".tooltip").tooltip({placement:"bottom"});this.setUpActionButton(c.find("#history-action-popup"));if(!this.model.hdas.length||!this.renderItems(c.find("#"+this.model.get("id")+"-datasets"))){c.find("#emptyHistoryMessage").show()}$(b).queue(d,function(f){b.$el.fadeOut("fast",function(){f()})});$(b).queue(d,function(f){b.$el.html("");b.$el.append(c.children());b.$el.fadeIn("fast",function(){f()})});$(b).queue(d,function(f){this.log(b+" rendered:",b.$el);b.setUpBehaviours();if(e){b.trigger("rendered:initial")}else{b.trigger("rendered")}f()});$(b).dequeue(d);return this},setUpActionButton:function(e){var c=this,d=(this.storage.get("show_deleted"))?("Hide deleted"):("Show deleted"),a=(this.storage.get("show_hidden"))?("Hide hidden"):("Show hidden"),b={};b[_l("refresh")]=function(){window.location.reload()};b[_l("collapse all")]=function(){c.hideAllHdaBodies()};b[_l(d)]=function(){c.toggleShowDeleted()};b[_l(a)]=function(){c.toggleShowHidden()};make_popupmenu(e,b)},renderItems:function(b){this.hdaViews={};var a=this,c=this.model.hdas.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"));_.each(c,function(f){var e=f.get("id"),d=a.storage.get("expandedHdas").get(e);a.hdaViews[e]=new a.HDAView({model:f,expanded:d,urlTemplates:a.hdaUrlTemplates});a.setUpHdaListeners(a.hdaViews[e]);b.prepend(a.hdaViews[e].render().$el)});return c.length},setUpHdaListeners:function(b){var a=this;b.bind("body-visible",function(c){a.storage.get("expandedHdas").set(c,true)});b.bind("body-hidden",function(c){a.storage.get("expandedHdas").deleteKey(c)})},setUpBehaviours:function(){if(!(this.model.get("user")&&this.model.get("user").email)){return}var a=this.$("#history-annotation-area");this.$("#history-annotate").click(function(){if(a.is(":hidden")){a.slideDown("fast")}else{a.slideUp("fast")}return false});async_save_text("history-name-container","history-name",this.urls.rename,"new_name",18);async_save_text("history-annotation-container","history-annotation",this.urls.annotate,"new_annotation",18,true,4)},updateHistoryDiskSize:function(){this.$el.find("#history-size").text(this.model.get("nice_size"))},events:{"click #history-tag":"loadAndDisplayTags"},showQuotaMessage:function(a){var b=this.$el.find("#quota-message-container");if(b.is(":hidden")){b.slideDown("fast")}},hideQuotaMessage:function(a){var b=this.$el.find("#quota-message-container");if(!b.is(":hidden")){b.slideUp("fast")}},toggleShowDeleted:function(a,c,b){this.storage.set("show_deleted",!this.storage.get("show_deleted"));this.render()},toggleShowHidden:function(){this.storage.set("show_hidden",!this.storage.get("show_hidden"));this.render()},hideAllHdaBodies:function(){_.each(this.hdaViews,function(a){a.toggleBodyVisibility(null,false)});this.storage.set("expandedHdas",{})},loadAndDisplayTags:function(c){this.log(this+".loadAndDisplayTags",c);var d=this.$el.find("#history-tag-area"),b=d.find(".tag-elt");this.log("\t tagArea",d," tagElt",b);if(d.is(":hidden")){if(!jQuery.trim(b.html())){var a=this;$.ajax({url:a.urls.tag,error:function(){alert(_l("Tagging failed"))},success:function(e){b.html(e);b.find(".tooltip").tooltip();d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=this.model.get("name")||"";return"HistoryView("+a+")"}});HistoryPanel.templates={historyPanel:Handlebars.templates["template-history-historyPanel"]};
\ No newline at end of file
+var HistoryPanel=BaseView.extend(LoggableMixin).extend({el:"body.historyPage",HDAView:HDAEditView,events:{"click #history-tag":"loadAndDisplayTags"},initialize:function(a){this.log(this+".initialize:",a);if(!a.urlTemplates){throw (this+" needs urlTemplates on initialize")}if(!a.urlTemplates.history){throw (this+" needs urlTemplates.history on initialize")}if(!a.urlTemplates.hda){throw (this+" needs urlTemplates.hda on initialize")}this.urlTemplates=a.urlTemplates.history;this.hdaUrlTemplates=a.urlTemplates.hda;this._setUpWebStorage(a.initiallyExpanded,a.show_deleted,a.show_hidden);this.model.bind("change:nice_size",this.updateHistoryDiskSize,this);this.model.hdas.bind("add",this.add,this);this.model.hdas.bind("reset",this.addAll,this);this.hdaViews={};this.urls={}},_setUpWebStorage:function(b,a,c){this.storage=new PersistantStorage("HistoryView."+this.model.get("id"),{expandedHdas:{},show_deleted:false,show_hidden:false});this.log("this.storage:",this.storage.get());if(b){this.storage.set("exandedHdas",b)}if((a===true)||(a===false)){this.storage.set("show_deleted",a)}if((c===true)||(c===false)){this.storage.set("show_hidden",c)}this.show_deleted=this.storage.get("show_deleted");this.show_hidden=this.storage.get("show_hidden");this.log("(init'd) this.storage:",this.storage.get())},add:function(a){},addAll:function(){this.render()},render:function(){var b=this,d=b.toString()+".set-up",c=$("<div/>"),a=this.model.toJSON(),e=(this.$el.children().size()===0);a.urls=this._renderUrls(a);c.append(HistoryPanel.templates.historyPanel(a));c.find(".tooltip").tooltip({placement:"bottom"});this._setUpActionButton(c.find("#history-action-popup"));if(!this.model.hdas.length||!this.renderItems(c.find("#"+this.model.get("id")+"-datasets"))){c.find("#emptyHistoryMessage").show()}$(b).queue(d,function(f){b.$el.fadeOut("fast",function(){f()})});$(b).queue(d,function(f){b.$el.html("");b.$el.append(c.children());b.$el.fadeIn("fast",function(){f()})});$(b).queue(d,function(f){this.log(b+" rendered:",b.$el);b._setUpBehaviours();if(e){b.trigger("rendered:initial")}else{b.trigger("rendered")}f()});$(b).dequeue(d);return this},_renderUrls:function(a){var b=this;b.urls={};_.each(this.urlTemplates,function(d,c){b.urls[c]=_.template(d,a)});return b.urls},_setUpActionButton:function(e){var c=this,d=(this.storage.get("show_deleted"))?("Hide deleted"):("Show deleted"),a=(this.storage.get("show_hidden"))?("Hide hidden"):("Show hidden"),b={};b[_l("refresh")]=function(){window.location.reload()};b[_l("collapse all")]=function(){c.hideAllHdaBodies()};b[_l(d)]=function(){c.toggleShowDeleted()};b[_l(a)]=function(){c.toggleShowHidden()};make_popupmenu(e,b)},renderItems:function(b){this.hdaViews={};var a=this,c=this.model.hdas.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"));_.each(c,function(f){var e=f.get("id"),d=a.storage.get("expandedHdas").get(e);a.hdaViews[e]=new a.HDAView({model:f,expanded:d,urlTemplates:a.hdaUrlTemplates});a._setUpHdaListeners(a.hdaViews[e]);b.prepend(a.hdaViews[e].render().$el)});return c.length},_setUpHdaListeners:function(b){var a=this;b.bind("body-expanded",function(c){a.storage.get("expandedHdas").set(c,true)});b.bind("body-collapsed",function(c){a.storage.get("expandedHdas").deleteKey(c)})},_setUpBehaviours:function(){if(!(this.model.get("user")&&this.model.get("user").email)){return}var a=this.$("#history-annotation-area");this.$("#history-annotate").click(function(){if(a.is(":hidden")){a.slideDown("fast")}else{a.slideUp("fast")}return false});async_save_text("history-name-container","history-name",this.urls.rename,"new_name",18);async_save_text("history-annotation-container","history-annotation",this.urls.annotate,"new_annotation",18,true,4)},updateHistoryDiskSize:function(){this.$el.find("#history-size").text(this.model.get("nice_size"))},showQuotaMessage:function(){var a=this.$el.find("#quota-message-container");if(a.is(":hidden")){a.slideDown("fast")}},hideQuotaMessage:function(){var a=this.$el.find("#quota-message-container");if(!a.is(":hidden")){a.slideUp("fast")}},toggleShowDeleted:function(){this.storage.set("show_deleted",!this.storage.get("show_deleted"));this.render()},toggleShowHidden:function(){this.storage.set("show_hidden",!this.storage.get("show_hidden"));this.render()},hideAllHdaBodies:function(){_.each(this.hdaViews,function(a){a.toggleBodyVisibility(null,false)});this.storage.set("expandedHdas",{})},loadAndDisplayTags:function(c){this.log(this+".loadAndDisplayTags",c);var d=this.$el.find("#history-tag-area"),b=d.find(".tag-elt");this.log("\t tagArea",d," tagElt",b);if(d.is(":hidden")){if(!jQuery.trim(b.html())){var a=this;$.ajax({url:a.urls.tag,error:function(){alert(_l("Tagging failed"))},success:function(e){b.html(e);b.find(".tooltip").tooltip();d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=this.model.get("name")||"";return"HistoryPanel("+a+")"}});HistoryPanel.templates={historyPanel:Handlebars.templates["template-history-historyPanel"]};
\ No newline at end of file
diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/mvc/user/user-model.js
--- a/static/scripts/packed/mvc/user/user-model.js
+++ b/static/scripts/packed/mvc/user/user-model.js
@@ -1,1 +1,1 @@
-var User=BaseModel.extend(LoggableMixin).extend({urlRoot:"api/users",defaults:{id:null,username:"("+_l("anonymous user")+")",email:"",total_disk_usage:0,nice_total_disk_usage:"0 bytes"},initialize:function(a){this.log("User.initialize:",a);this.on("loaded",function(b,c){this.log(this+" has loaded:",b,c)});this.on("change",function(b,c){this.log(this+" has changed:",b,c.changes)})},loadFromApi:function(d,b){d=d||User.CURRENT_ID_STR;b=b||{};var a=this,c=b.success;b.success=function(f,e){a.trigger("loaded",f,e);if(c){c(f,e)}};if(d===User.CURRENT_ID_STR){b.url=this.urlRoot+"/"+User.CURRENT_ID_STR}return BaseModel.prototype.fetch.call(this,b)},toString:function(){var a=[this.get("username")];if(this.get("id")){a.unshift(this.get("id"));a.push(this.get("email"))}return"User("+a.join(":")+")"}});User.CURRENT_ID_STR="current";User.getCurrentUserFromApi=function(b){var a=new User();a.loadFromApi(User.CURRENT_ID_STR,b);return a};var UserCollection=Backbone.Collection.extend(LoggableMixin).extend({model:User,urlRoot:"api/users"});
\ No newline at end of file
+var User=BaseModel.extend(LoggableMixin).extend({urlRoot:"api/users",defaults:{id:null,username:"("+_l("anonymous user")+")",email:"",total_disk_usage:0,nice_total_disk_usage:"0 bytes",quota_percent:null},initialize:function(a){this.log("User.initialize:",a);this.on("loaded",function(b,c){this.log(this+" has loaded:",b,c)});this.on("change",function(b,c){this.log(this+" has changed:",b,c.changes)})},isAnonymous:function(){return(!this.get("email"))},loadFromApi:function(d,b){d=d||User.CURRENT_ID_STR;b=b||{};var a=this,c=b.success;b.success=function(f,e){a.trigger("loaded",f,e);if(c){c(f,e)}};if(d===User.CURRENT_ID_STR){b.url=this.urlRoot+"/"+User.CURRENT_ID_STR}return BaseModel.prototype.fetch.call(this,b)},toString:function(){var a=[this.get("username")];if(this.get("id")){a.unshift(this.get("id"));a.push(this.get("email"))}return"User("+a.join(":")+")"}});User.CURRENT_ID_STR="current";User.getCurrentUserFromApi=function(b){var a=new User();a.loadFromApi(User.CURRENT_ID_STR,b);return a};var UserCollection=Backbone.Collection.extend(LoggableMixin).extend({model:User,urlRoot:"api/users"});
\ No newline at end of file
diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 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(k,A,y,q,I){y=y||k.helpers;var z="",n,m,v=this,e="function",c=y.blockHelperMissing,d=this.escapeExpression;function t(N,M){var K="",L,J;K+='\n <div id="history-name" class="tooltip editable-text"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(2,s,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(2,s,M)})}if(L||L===0){K+=L}K+='">';J=y.name;if(J){L=J.call(N,{hash:{}})}else{L=N.name;L=typeof L===e?L():L}K+=d(L)+"</div>\n ";return K}function s(K,J){return"Click to rename history"}function r(N,M){var K="",L,J;K+='\n <div id="history-name" class="tooltip"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(5,p,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(5,p,M)})}if(L||L===0){K+=L}K+='">';J=y.name;if(J){L=J.call(N,{hash:{}})}else{L=N.name;L=typeof L===e?L():L}K+=d(L)+"</div>\n ";return K}function p(K,J){return"You must be logged in to edit your history name"}function o(K,J){return"Click to see more actions"}function j(N,M){var K="",L,J;K+='\n <div id="history-secondary-links" style="float: right;">\n <a id="history-tag" title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(10,H,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(10,H,M)})}if(L||L===0){K+=L}K+='"\n class="icon-button tags tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n <a id="history-annotate" title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(12,G,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(12,G,M)})}if(L||L===0){K+=L}K+='"\n class="icon-button annotate tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n </div>\n ';return K}function H(K,J){return"Edit history tags"}function G(K,J){return"Edit history annotation"}function F(N,M){var K="",L,J;K+="\n ";J=y.warningmessagesmall;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(15,E,M)})}else{L=N.warningmessagesmall;L=typeof L===e?L():L}if(!y.warningmessagesmall){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(15,E,M)})}if(L||L===0){K+=L}K+="\n ";return K}function E(M,L){var K,J;J=y.local;if(J){K=J.call(M,{hash:{},inverse:v.noop,fn:v.program(16,D,L)})}else{K=M.local;K=typeof K===e?K():K}if(!y.local){K=c.call(M,K,{hash:{},inverse:v.noop,fn:v.program(16,D,L)})}if(K||K===0){return K}else{return""}}function D(K,J){return"You are currently viewing a deleted history!"}function C(N,M){var K="",L,J;K+='\n <div id="history-tag-annotation">\n\n <div id="history-tag-area" style="display: none">\n <strong>';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(19,B,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(19,B,M)})}if(L||L===0){K+=L}K+=':</strong>\n <div class="tag-elt"></div>\n </div>\n\n <div id="history-annotation-area" style="display: none">\n <strong>';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(21,l,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(21,l,M)})}if(L||L===0){K+=L}K+=':</strong>\n <div id="history-annotation-container">\n <div id="history-annotation" class="tooltip editable-text"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(23,i,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(23,i,M)})}if(L||L===0){K+=L}K+='">\n ';L=N.annotation;L=y["if"].call(N,L,{hash:{},inverse:v.program(27,g,M),fn:v.program(25,h,M)});if(L||L===0){K+=L}K+="\n </div>\n </div>\n </div>\n </div>\n ";return K}function B(K,J){return"Tags"}function l(K,J){return"Annotation"}function i(K,J){return"Click to edit annotation"}function h(N,M){var K="",L,J;K+="\n ";J=y.annotation;if(J){L=J.call(N,{hash:{}})}else{L=N.annotation;L=typeof L===e?L():L}K+=d(L)+"\n ";return K}function g(N,M){var K="",L,J;K+="\n <em>";J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(28,f,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(28,f,M)})}if(L||L===0){K+=L}K+="</em>\n ";return K}function f(K,J){return"Describe or add notes to history"}function x(N,M){var K="",L,J;K+='\n <div id="message-container">\n <div class="';J=y.status;if(J){L=J.call(N,{hash:{}})}else{L=N.status;L=typeof L===e?L():L}K+=d(L)+'message">\n ';J=y.message;if(J){L=J.call(N,{hash:{}})}else{L=N.message;L=typeof L===e?L():L}K+=d(L)+"\n </div><br />\n </div>\n ";return K}function w(K,J){return"You are over your disk quota.\n Tool execution is on hold until your disk usage drops below your allocated quota."}function u(K,J){return"Your history is empty. Click 'Get Data' on the left pane to start"}z+='\n<div id="history-controls">\n <div id="history-title-area" class="historyLinks">\n\n <div id="history-name-container" style="float: left;">\n ';z+="\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.program(4,r,I),fn:v.program(1,t,I)});if(n||n===0){z+=n}z+='\n </div>\n\n <a id="history-action-popup" class="tooltip" title="';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(7,o,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(7,o,I)})}if(n||n===0){z+=n}z+='"\n href="javascript:void(0);" style="float: right;">\n <span class="ficon cog large"></span>\n </a>\n <div style="clear: both;"></div>\n </div>\n\n <div id="history-subtitle-area">\n <div id="history-size" style="float:left;">';m=y.nice_size;if(m){n=m.call(A,{hash:{}})}else{n=A.nice_size;n=typeof n===e?n():n}z+=d(n)+"</div>\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(9,j,I)});if(n||n===0){z+=n}z+='\n <div style="clear: both;"></div>\n </div>\n\n ';n=A.deleted;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(14,F,I)});if(n||n===0){z+=n}z+="\n\n ";z+="\n ";z+="\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(18,C,I)});if(n||n===0){z+=n}z+="\n\n ";n=A.message;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(30,x,I)});if(n||n===0){z+=n}z+='\n\n <div id="quota-message-container" style="display: none">\n <div id="quota-message" class="errormessage">\n ';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(32,w,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(32,w,I)})}if(n||n===0){z+=n}z+='\n </div>\n </div>\n</div>\n\n<div id="';m=y.id;if(m){n=m.call(A,{hash:{}})}else{n=A.id;n=typeof n===e?n():n}z+=d(n)+'-datasets" class="history-datasets-list"></div>\n\n<div class="infomessagesmall" id="emptyHistoryMessage" style="display: none;">\n ';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(34,u,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(34,u,I)})}if(n||n===0){z+=n}z+="\n</div>";return z})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(k,A,y,q,I){y=y||k.helpers;var z="",n,m,v=this,e="function",c=y.blockHelperMissing,d=this.escapeExpression;function t(N,M){var K="",L,J;K+='\n <div id="history-name" class="tooltip editable-text"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(2,s,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(2,s,M)})}if(L||L===0){K+=L}K+='">';J=y.name;if(J){L=J.call(N,{hash:{}})}else{L=N.name;L=typeof L===e?L():L}K+=d(L)+"</div>\n ";return K}function s(K,J){return"Click to rename history"}function r(N,M){var K="",L,J;K+='\n <div id="history-name" class="tooltip"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(5,p,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(5,p,M)})}if(L||L===0){K+=L}K+='">';J=y.name;if(J){L=J.call(N,{hash:{}})}else{L=N.name;L=typeof L===e?L():L}K+=d(L)+"</div>\n ";return K}function p(K,J){return"You must be logged in to edit your history name"}function o(K,J){return"Click to see more actions"}function j(N,M){var K="",L,J;K+='\n <div id="history-secondary-links" style="float: right;">\n <a id="history-tag" title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(10,H,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(10,H,M)})}if(L||L===0){K+=L}K+='"\n class="icon-button tags tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n <a id="history-annotate" title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(12,G,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(12,G,M)})}if(L||L===0){K+=L}K+='"\n class="icon-button annotate tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n </div>\n ';return K}function H(K,J){return"Edit history tags"}function G(K,J){return"Edit history annotation"}function F(N,M){var K="",L,J;K+="\n ";J=y.warningmessagesmall;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(15,E,M)})}else{L=N.warningmessagesmall;L=typeof L===e?L():L}if(!y.warningmessagesmall){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(15,E,M)})}if(L||L===0){K+=L}K+="\n ";return K}function E(M,L){var K,J;J=y.local;if(J){K=J.call(M,{hash:{},inverse:v.noop,fn:v.program(16,D,L)})}else{K=M.local;K=typeof K===e?K():K}if(!y.local){K=c.call(M,K,{hash:{},inverse:v.noop,fn:v.program(16,D,L)})}if(K||K===0){return K}else{return""}}function D(K,J){return"You are currently viewing a deleted history!"}function C(N,M){var K="",L,J;K+='\n <div id="history-tag-annotation">\n\n <div id="history-tag-area" style="display: none">\n <strong>';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(19,B,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(19,B,M)})}if(L||L===0){K+=L}K+=':</strong>\n <div class="tag-elt"></div>\n </div>\n\n <div id="history-annotation-area" style="display: none">\n <strong>';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(21,l,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(21,l,M)})}if(L||L===0){K+=L}K+=':</strong>\n <div id="history-annotation-container">\n <div id="history-annotation" class="tooltip editable-text"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(23,i,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(23,i,M)})}if(L||L===0){K+=L}K+='">\n ';L=N.annotation;L=y["if"].call(N,L,{hash:{},inverse:v.program(27,g,M),fn:v.program(25,h,M)});if(L||L===0){K+=L}K+="\n </div>\n </div>\n </div>\n </div>\n ";return K}function B(K,J){return"Tags"}function l(K,J){return"Annotation"}function i(K,J){return"Click to edit annotation"}function h(N,M){var K="",L,J;K+="\n ";J=y.annotation;if(J){L=J.call(N,{hash:{}})}else{L=N.annotation;L=typeof L===e?L():L}K+=d(L)+"\n ";return K}function g(N,M){var K="",L,J;K+="\n <em>";J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(28,f,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(28,f,M)})}if(L||L===0){K+=L}K+="</em>\n ";return K}function f(K,J){return"Describe or add notes to history"}function x(N,M){var K="",L,J;K+='\n <div id="message-container">\n <div class="';J=y.status;if(J){L=J.call(N,{hash:{}})}else{L=N.status;L=typeof L===e?L():L}K+=d(L)+'message">\n ';J=y.message;if(J){L=J.call(N,{hash:{}})}else{L=N.message;L=typeof L===e?L():L}K+=d(L)+"\n </div><br />\n </div>\n ";return K}function w(K,J){return"You are over your disk quota.\n Tool execution is on hold until your disk usage drops below your allocated quota."}function u(K,J){return"Your history is empty. Click 'Get Data' on the left pane to start"}z+='<div id="history-controls">\n <div id="history-title-area" class="historyLinks">\n\n ';z+='\n <div id="history-name-container" style="float: left;">\n ';z+="\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.program(4,r,I),fn:v.program(1,t,I)});if(n||n===0){z+=n}z+='\n </div>\n\n <a id="history-action-popup" class="tooltip" title="';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(7,o,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(7,o,I)})}if(n||n===0){z+=n}z+='"\n href="javascript:void(0);" style="float: right;">\n <span class="ficon cogs large"></span>\n </a>\n <div style="clear: both;"></div>\n </div>\n\n <div id="history-subtitle-area">\n <div id="history-size" style="float:left;">';m=y.nice_size;if(m){n=m.call(A,{hash:{}})}else{n=A.nice_size;n=typeof n===e?n():n}z+=d(n)+"</div>\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(9,j,I)});if(n||n===0){z+=n}z+='\n <div style="clear: both;"></div>\n </div>\n\n ';n=A.deleted;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(14,F,I)});if(n||n===0){z+=n}z+="\n\n ";z+="\n ";z+="\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(18,C,I)});if(n||n===0){z+=n}z+="\n\n ";n=A.message;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(30,x,I)});if(n||n===0){z+=n}z+='\n\n <div id="quota-message-container" style="display: none">\n <div id="quota-message" class="errormessage">\n ';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(32,w,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(32,w,I)})}if(n||n===0){z+=n}z+='\n </div>\n </div>\n</div>\n\n<div id="';m=y.id;if(m){n=m.call(A,{hash:{}})}else{n=A.id;n=typeof n===e?n():n}z+=d(n)+'-datasets" class="history-datasets-list"></div>\n\n<div class="infomessagesmall" id="emptyHistoryMessage" style="display: none;">\n ';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(34,u,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(34,u,I)})}if(n||n===0){z+=n}z+="\n</div>";return z})})();
\ No newline at end of file
diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/viz/circster.js
--- a/static/scripts/packed/viz/circster.js
+++ b/static/scripts/packed/viz/circster.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","libs/d3","viz/visualization"],function(g,l,i){var m=Backbone.Model.extend({is_visible:function(q,n){var o=q.getBoundingClientRect(),p=$("svg")[0].getBoundingClientRect();if(o.right<0||o.left>p.right||o.bottom<0||o.top>p.bottom){return false}return true}});var h={drawTicks:function(r,q,v,p,n){var u=r.append("g").selectAll("g").data(q).enter().append("g").selectAll("g").data(v).enter().append("g").attr("class","tick").attr("transform",function(w){return"rotate("+(w.angle*180/Math.PI-90)+")translate("+w.radius+",0)"});var t=[],s=[],o=function(w){return w.angle>Math.PI?"end":null};if(n){t=[0,0,0,-4];s=[4,0,"",".35em"];o=null}else{t=[1,0,4,0];s=[0,4,".35em",""]}u.append("line").attr("x1",t[0]).attr("y1",t[1]).attr("x2",t[2]).attr("y1",t[3]).style("stroke","#000");u.append("text").attr("x",s[0]).attr("y",s[1]).attr("dx",s[2]).attr("dy",s[3]).attr("text-anchor",o).attr("transform",p).text(function(w){return w.label})},formatNum:function(o,n){var q=null;if(o<1){q=o.toPrecision(n)}else{var p=Math.round(o.toPrecision(n));if(o<1000){q=p}else{if(o<1000000){q=Math.round((p/1000).toPrecision(3)).toFixed(0)+"K"}else{if(o<1000000000){q=Math.round((p/1000000).toPrecision(3)).toFixed(0)+"M"}}}}return q}};var c=Backbone.Model.extend({});var a=Backbone.View.extend({className:"circster",initialize:function(n){this.total_gap=n.total_gap;this.genome=n.genome;this.dataset_arc_height=n.dataset_arc_height;this.track_gap=10;this.label_arc_height=50;this.scale=1;this.circular_views=null;this.chords_views=null;this.model.get("tracks").on("add",this.add_track,this);this.model.get("tracks").on("remove",this.remove_track,this);this.get_circular_tracks()},get_circular_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")!=="DiagonalHeatmapTrack"})},get_chord_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")==="DiagonalHeatmapTrack"})},get_tracks_bounds:function(){var o=this.get_circular_tracks();dataset_arc_height=this.dataset_arc_height,min_dimension=Math.min(this.$el.width(),this.$el.height()),radius_start=min_dimension/2-o.length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),tracks_start_radii=l.range(radius_start,min_dimension/2,this.dataset_arc_height+this.track_gap);var n=this;return g.map(tracks_start_radii,function(p){return[p,p+n.dataset_arc_height]})},render:function(){var w=this,q=this.dataset_arc_height,n=w.$el.width(),v=w.$el.height(),s=this.get_circular_tracks(),p=this.get_chord_tracks(),r=this.get_tracks_bounds(),o=l.select(w.$el[0]).append("svg").attr("width",n).attr("height",v).attr("pointer-events","all").append("svg:g").call(l.behavior.zoom().on("zoom",function(){var x=l.event.scale;o.attr("transform","translate("+l.event.translate+") scale("+x+")");if(w.scale!==x){if(w.zoom_drag_timeout){clearTimeout(w.zoom_drag_timeout)}w.zoom_drag_timeout=setTimeout(function(){},400)}})).attr("transform","translate("+n/2+","+v/2+")").append("svg:g").attr("class","tracks");this.circular_views=s.map(function(y,z){var A=(y.get("track_type")==="LineTrack"?d:e),x=new A({el:o.append("g")[0],track:y,radius_bounds:r[z],genome:w.genome,total_gap:w.total_gap});x.render();return x});this.chords_views=p.map(function(y){var x=new j({el:o.append("g")[0],track:y,radius_bounds:r[0],genome:w.genome,total_gap:w.total_gap});x.render();return x});var u=this.circular_views[this.circular_views.length-1].radius_bounds[1],t=[u,u+this.label_arc_height];this.label_track_view=new b({el:o.append("g")[0],track:new c(),radius_bounds:t,genome:w.genome,total_gap:w.total_gap});this.label_track_view.render()},add_track:function(t){if(t.get("track_type")==="DiagonalHeatmapTrack"){var p=this.circular_views[0].radius_bounds,s=new j({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:p,genome:this.genome,total_gap:this.total_gap});s.render();this.chords_views.push(s)}else{var r=this.get_tracks_bounds();g.each(this.circular_views,function(v,w){v.update_radius_bounds(r[w])});g.each(this.chords_views,function(v){v.update_radius_bounds(r[0])});var q=this.circular_views.length,u=(t.get("track_type")==="LineTrack"?d:e),n=new u({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:r[q],genome:this.genome,total_gap:this.total_gap});n.render();this.circular_views.push(n);var o=r[r.length-1];o[1]=o[0];this.label_track_view.update_radius_bounds(o)}},remove_track:function(o,q,p){var n=this.circular_views[p.index];this.circular_views.splice(p.index,1);n.$el.remove();var r=this.get_tracks_bounds();g.each(this.circular_views,function(s,t){s.update_radius_bounds(r[t])})}});var k=Backbone.View.extend({tagName:"g",initialize:function(n){this.bg_stroke="ccc";this.loading_bg_fill="000";this.bg_fill="ccc";this.total_gap=n.total_gap;this.track=n.track;this.radius_bounds=n.radius_bounds;this.genome=n.genome;this.chroms_layout=this._chroms_layout();this.data_bounds=[];this.scale=1;this.parent_elt=l.select(this.$el[0])},get_fill_color:function(){var n=this.track.get("config").get_value("block_color");if(!n){n=this.track.get("config").get_value("color")}return n},render:function(){var r=this.parent_elt;if(!r){console.log("no parent elt")}var q=this.chroms_layout,t=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]),n=r.selectAll("g").data(q).enter().append("svg:g"),p=n.append("path").attr("d",t).attr("class","chrom-background").style("stroke",this.bg_stroke).style("fill",this.loading_bg_fill);p.append("title").text(function(v){return v.data.chrom});var o=this,s=o.track.get("data_manager"),u=(s?s.data_is_ready():true);$.when(u).then(function(){$.when(o._render_data(r)).then(function(){p.style("fill",o.bg_fill);o.render_labels()})})},render_labels:function(){},update_radius_bounds:function(o){this.radius_bounds=o;var n=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]);this.parent_elt.selectAll("g>path.chrom-background").transition().duration(1000).attr("d",n);this._transition_chrom_data();this._transition_labels()},update_scale:function(q){var p=this.scale;this.scale=q;if(q<=p){return}var o=this,n=new m();this.parent_elt.selectAll("path.chrom-data").filter(function(s,r){return n.is_visible(this)}).each(function(x,t){var w=l.select(this),s=w.attr("chrom"),v=o.genome.get_chrom_region(s),u=o.track.get("data_manager"),r;if(!u.can_get_more_detailed_data(v)){return}r=o.track.get("data_manager").get_more_detailed_data(v,"Coverage",0,q);$.when(r).then(function(A){w.remove();o._update_data_bounds();var z=g.find(o.chroms_layout,function(B){return B.data.chrom===s});var y=o.get_fill_color();o._render_chrom_data(o.parent_elt,z,A).style("stroke",y).style("fill",y)})});return o},_transition_chrom_data:function(){var o=this.track,q=this.chroms_layout,n=this.parent_elt.selectAll("g>path.chrom-data"),r=n[0].length;if(r>0){var p=this;$.when(o.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){var s=g.reject(g.map(t,function(u,v){var w=null,x=p._get_path_function(q[v],u);if(x){w=x(u.data)}return w}),function(u){return u===null});n.each(function(v,u){l.select(this).transition().duration(1000).attr("d",s[u])})})}},_transition_labels:function(){},_update_data_bounds:function(){var n=this.data_bounds;this.data_bounds=this.get_data_bounds(this.track.get("data_manager").get_genome_wide_data(this.genome));if(this.data_bounds[0]<n[0]||this.data_bounds[1]>n[1]){this._transition_chrom_data()}},_render_data:function(q){var p=this,o=this.chroms_layout,n=this.track,r=$.Deferred();$.when(n.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){p.data_bounds=p.get_data_bounds(t);layout_and_data=g.zip(o,t),chroms_data_layout=g.map(layout_and_data,function(u){var v=u[0],w=u[1];return p._render_chrom_data(q,v,w)});var s=p.get_fill_color();p.parent_elt.selectAll("path.chrom-data").style("stroke",s).style("fill",s);r.resolve(q)});return r},_render_chrom_data:function(n,o,p){},_get_path_function:function(o,n){},_chroms_layout:function(){var o=this.genome.get_chroms_info(),q=l.layout.pie().value(function(s){return s.len}).sort(null),r=q(o),n=this.total_gap/o.length,p=g.map(r,function(u,t){var s=u.endAngle-n;u.endAngle=(s>u.startAngle?s:u.startAngle);return u});return p}});var b=k.extend({initialize:function(n){k.prototype.initialize.call(this,n);this.innerRadius=this.radius_bounds[0];this.radius_bounds[0]=this.radius_bounds[1];this.bg_stroke="fff";this.bg_fill="fff";this.min_arc_len=0.08},_render_data:function(p){var o=this,n=p.selectAll("g");n.selectAll("path").attr("id",function(t){return"label-"+t.data.chrom});n.append("svg:text").filter(function(t){return t.endAngle-t.startAngle>o.min_arc_len}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(t){return"#label-"+t.data.chrom}).attr("startOffset","25%").attr("font-weight","bold").text(function(t){return t.data.chrom});var q=function(v){var t=(v.endAngle-v.startAngle)/v.value,u=l.range(0,v.value,25000000).map(function(w,x){return{radius:o.innerRadius,angle:w*t+v.startAngle,label:x===0?0:(x%3?null:o.formatNum(w))}});if(u.length<4){u[u.length-1].label=o.formatNum(Math.round((u[u.length-1].angle-v.startAngle)/t))}return u};var s=function(t){return t.angle>Math.PI?"rotate(180)translate(-16)":null};var r=g.filter(this.chroms_layout,function(t){return t.endAngle-t.startAngle>o.min_arc_len});this.drawTicks(this.parent_elt,r,q,s)}});g.extend(b.prototype,h);var f=k.extend({_quantile:function(o,n){o.sort(l.ascending);return l.quantile(o,n)},_render_chrom_data:function(n,q,o){var r=this._get_path_function(q,o);if(!r){return null}var p=n.datum(o.data),s=p.append("path").attr("class","chrom-data").attr("chrom",q.data.chrom).attr("d",r);return s},_get_path_function:function(q,p){if(typeof p==="string"||!p.data||p.data.length===0){return null}var n=l.scale.linear().domain(this.data_bounds).range(this.radius_bounds).clamp(true);var r=l.scale.linear().domain([0,p.data.length]).range([q.startAngle,q.endAngle]);var o=l.svg.line.radial().interpolate("linear").radius(function(s){return n(s[1])}).angle(function(t,s){return r(s)});return l.svg.area.radial().interpolate(o.interpolate()).innerRadius(n(0)).outerRadius(o.radius()).angle(o.angle())},render_labels:function(){var n=this,q=function(){return"rotate(90)"};var p=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),o=g.filter(p,function(s,r){return r%3===0});this.drawTicks(this.parent_elt,o,this._data_bounds_ticks_fn(),q,true)},_transition_labels:function(){if(this.data_bounds.length===0){return}var o=this,q=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),p=g.filter(q,function(s,r){return r%3===0}),n=g.flatten(g.map(p,function(r){return o._data_bounds_ticks_fn()(r)}));this.parent_elt.selectAll("g.tick").data(n).transition().attr("transform",function(r){return"rotate("+(r.angle*180/Math.PI-90)+")translate("+r.radius+",0)"})},_data_bounds_ticks_fn:function(){var n=this;visibleChroms=0;return function(o){return[{radius:n.radius_bounds[0],angle:o.startAngle,label:n.formatNum(n.data_bounds[0])},{radius:n.radius_bounds[1],angle:o.startAngle,label:n.formatNum(n.data_bounds[1])}]}},get_data_bounds:function(n){}});g.extend(f.prototype,h);var e=f.extend({get_data_bounds:function(o){var n=g.map(o,function(p){if(typeof p==="string"||!p.max){return 0}return p.max});return[0,(n&&typeof n!=="string"?this._quantile(values,0.98):0)]}});var d=f.extend({get_data_bounds:function(o){var n=g.flatten(g.map(o,function(p){if(p){return g.map(p.data,function(q){return q[1]})}else{return 0}}));return[g.min(n),this._quantile(n,0.98)]}});var j=k.extend({render:function(){var n=this;$.when(n.track.get("data_manager").data_is_ready()).then(function(){$.when(n.track.get("data_manager").get_genome_wide_data(n.genome)).then(function(q){var p=[],o=n.genome.get_chroms_info();g.each(q,function(u,t){var r=o[t].chrom;var s=g.map(u.data,function(w){var v=n._get_region_angle(r,w[1]),x=n._get_region_angle(w[3],w[4]);return{source:{startAngle:v,endAngle:v+0.01},target:{startAngle:x,endAngle:x+0.01}}});p=p.concat(s)});n.parent_elt.append("g").attr("class","chord").selectAll("path").data(p).enter().append("path").style("fill",n.get_fill_color()).attr("d",l.svg.chord().radius(n.radius_bounds[0])).style("opacity",1)})})},update_radius_bounds:function(n){this.radius_bounds=n;this.parent_elt.selectAll("path").transition().attr("d",l.svg.chord().radius(this.radius_bounds[0]))},_get_region_angle:function(p,n){var o=g.find(this.chroms_layout,function(q){return q.data.chrom===p});return o.endAngle-((o.endAngle-o.startAngle)*(o.data.len-n)/o.data.len)}});return{CircsterView:a}});
\ No newline at end of file
+define(["libs/underscore","libs/d3","viz/visualization"],function(g,l,i){var m=Backbone.Model.extend({is_visible:function(q,n){var o=q.getBoundingClientRect(),p=$("svg")[0].getBoundingClientRect();if(o.right<0||o.left>p.right||o.bottom<0||o.top>p.bottom){return false}return true}});var h={drawTicks:function(r,q,v,p,n){var u=r.append("g").selectAll("g").data(q).enter().append("g").selectAll("g").data(v).enter().append("g").attr("class","tick").attr("transform",function(w){return"rotate("+(w.angle*180/Math.PI-90)+")translate("+w.radius+",0)"});var t=[],s=[],o=function(w){return w.angle>Math.PI?"end":null};if(n){t=[0,0,0,-4];s=[4,0,"",".35em"];o=null}else{t=[1,0,4,0];s=[0,4,".35em",""]}u.append("line").attr("x1",t[0]).attr("y1",t[1]).attr("x2",t[2]).attr("y1",t[3]).style("stroke","#000");u.append("text").attr("x",s[0]).attr("y",s[1]).attr("dx",s[2]).attr("dy",s[3]).attr("text-anchor",o).attr("transform",p).text(function(w){return w.label})},formatNum:function(o,n){if(n===undefined){n=2}var q=null;if(o<1){q=o.toPrecision(n)}else{var p=Math.round(o.toPrecision(n));if(o<1000){q=p}else{if(o<1000000){q=Math.round((p/1000).toPrecision(3)).toFixed(0)+"K"}else{if(o<1000000000){q=Math.round((p/1000000).toPrecision(3)).toFixed(0)+"M"}}}}return q}};var c=Backbone.Model.extend({});var a=Backbone.View.extend({className:"circster",initialize:function(n){this.total_gap=n.total_gap;this.genome=n.genome;this.dataset_arc_height=n.dataset_arc_height;this.track_gap=10;this.label_arc_height=50;this.scale=1;this.circular_views=null;this.chords_views=null;this.model.get("tracks").on("add",this.add_track,this);this.model.get("tracks").on("remove",this.remove_track,this);this.get_circular_tracks()},get_circular_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")!=="DiagonalHeatmapTrack"})},get_chord_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")==="DiagonalHeatmapTrack"})},get_tracks_bounds:function(){var o=this.get_circular_tracks();dataset_arc_height=this.dataset_arc_height,min_dimension=Math.min(this.$el.width(),this.$el.height()),radius_start=min_dimension/2-o.length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),tracks_start_radii=l.range(radius_start,min_dimension/2,this.dataset_arc_height+this.track_gap);var n=this;return g.map(tracks_start_radii,function(p){return[p,p+n.dataset_arc_height]})},render:function(){var w=this,q=this.dataset_arc_height,n=w.$el.width(),v=w.$el.height(),s=this.get_circular_tracks(),p=this.get_chord_tracks(),r=this.get_tracks_bounds(),o=l.select(w.$el[0]).append("svg").attr("width",n).attr("height",v).attr("pointer-events","all").append("svg:g").call(l.behavior.zoom().on("zoom",function(){var x=l.event.scale;o.attr("transform","translate("+l.event.translate+") scale("+x+")");if(w.scale!==x){if(w.zoom_drag_timeout){clearTimeout(w.zoom_drag_timeout)}w.zoom_drag_timeout=setTimeout(function(){},400)}})).attr("transform","translate("+n/2+","+v/2+")").append("svg:g").attr("class","tracks");this.circular_views=s.map(function(y,z){var A=(y.get("track_type")==="LineTrack"?d:e),x=new A({el:o.append("g")[0],track:y,radius_bounds:r[z],genome:w.genome,total_gap:w.total_gap});x.render();return x});this.chords_views=p.map(function(y){var x=new j({el:o.append("g")[0],track:y,radius_bounds:r[0],genome:w.genome,total_gap:w.total_gap});x.render();return x});var u=this.circular_views[this.circular_views.length-1].radius_bounds[1],t=[u,u+this.label_arc_height];this.label_track_view=new b({el:o.append("g")[0],track:new c(),radius_bounds:t,genome:w.genome,total_gap:w.total_gap});this.label_track_view.render()},add_track:function(t){if(t.get("track_type")==="DiagonalHeatmapTrack"){var p=this.circular_views[0].radius_bounds,s=new j({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:p,genome:this.genome,total_gap:this.total_gap});s.render();this.chords_views.push(s)}else{var r=this.get_tracks_bounds();g.each(this.circular_views,function(v,w){v.update_radius_bounds(r[w])});g.each(this.chords_views,function(v){v.update_radius_bounds(r[0])});var q=this.circular_views.length,u=(t.get("track_type")==="LineTrack"?d:e),n=new u({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:r[q],genome:this.genome,total_gap:this.total_gap});n.render();this.circular_views.push(n);var o=r[r.length-1];o[1]=o[0];this.label_track_view.update_radius_bounds(o)}},remove_track:function(o,q,p){var n=this.circular_views[p.index];this.circular_views.splice(p.index,1);n.$el.remove();var r=this.get_tracks_bounds();g.each(this.circular_views,function(s,t){s.update_radius_bounds(r[t])})}});var k=Backbone.View.extend({tagName:"g",initialize:function(n){this.bg_stroke="ccc";this.loading_bg_fill="000";this.bg_fill="ccc";this.total_gap=n.total_gap;this.track=n.track;this.radius_bounds=n.radius_bounds;this.genome=n.genome;this.chroms_layout=this._chroms_layout();this.data_bounds=[];this.scale=1;this.parent_elt=l.select(this.$el[0])},get_fill_color:function(){var n=this.track.get("config").get_value("block_color");if(!n){n=this.track.get("config").get_value("color")}return n},render:function(){var r=this.parent_elt;if(!r){console.log("no parent elt")}var q=this.chroms_layout,t=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]),n=r.selectAll("g").data(q).enter().append("svg:g"),p=n.append("path").attr("d",t).attr("class","chrom-background").style("stroke",this.bg_stroke).style("fill",this.loading_bg_fill);p.append("title").text(function(v){return v.data.chrom});var o=this,s=o.track.get("data_manager"),u=(s?s.data_is_ready():true);$.when(u).then(function(){$.when(o._render_data(r)).then(function(){p.style("fill",o.bg_fill);o.render_labels()})})},render_labels:function(){},update_radius_bounds:function(o){this.radius_bounds=o;var n=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]);this.parent_elt.selectAll("g>path.chrom-background").transition().duration(1000).attr("d",n);this._transition_chrom_data();this._transition_labels()},update_scale:function(q){var p=this.scale;this.scale=q;if(q<=p){return}var o=this,n=new m();this.parent_elt.selectAll("path.chrom-data").filter(function(s,r){return n.is_visible(this)}).each(function(x,t){var w=l.select(this),s=w.attr("chrom"),v=o.genome.get_chrom_region(s),u=o.track.get("data_manager"),r;if(!u.can_get_more_detailed_data(v)){return}r=o.track.get("data_manager").get_more_detailed_data(v,"Coverage",0,q);$.when(r).then(function(A){w.remove();o._update_data_bounds();var z=g.find(o.chroms_layout,function(B){return B.data.chrom===s});var y=o.get_fill_color();o._render_chrom_data(o.parent_elt,z,A).style("stroke",y).style("fill",y)})});return o},_transition_chrom_data:function(){var o=this.track,q=this.chroms_layout,n=this.parent_elt.selectAll("g>path.chrom-data"),r=n[0].length;if(r>0){var p=this;$.when(o.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){var s=g.reject(g.map(t,function(u,v){var w=null,x=p._get_path_function(q[v],u);if(x){w=x(u.data)}return w}),function(u){return u===null});n.each(function(v,u){l.select(this).transition().duration(1000).attr("d",s[u])})})}},_transition_labels:function(){},_update_data_bounds:function(){var n=this.data_bounds;this.data_bounds=this.get_data_bounds(this.track.get("data_manager").get_genome_wide_data(this.genome));if(this.data_bounds[0]<n[0]||this.data_bounds[1]>n[1]){this._transition_chrom_data()}},_render_data:function(q){var p=this,o=this.chroms_layout,n=this.track,r=$.Deferred();$.when(n.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){p.data_bounds=p.get_data_bounds(t);layout_and_data=g.zip(o,t),chroms_data_layout=g.map(layout_and_data,function(u){var v=u[0],w=u[1];return p._render_chrom_data(q,v,w)});var s=p.get_fill_color();p.parent_elt.selectAll("path.chrom-data").style("stroke",s).style("fill",s);r.resolve(q)});return r},_render_chrom_data:function(n,o,p){},_get_path_function:function(o,n){},_chroms_layout:function(){var o=this.genome.get_chroms_info(),q=l.layout.pie().value(function(s){return s.len}).sort(null),r=q(o),n=this.total_gap/o.length,p=g.map(r,function(u,t){var s=u.endAngle-n;u.endAngle=(s>u.startAngle?s:u.startAngle);return u});return p}});var b=k.extend({initialize:function(n){k.prototype.initialize.call(this,n);this.innerRadius=this.radius_bounds[0];this.radius_bounds[0]=this.radius_bounds[1];this.bg_stroke="fff";this.bg_fill="fff";this.min_arc_len=0.08},_render_data:function(p){var o=this,n=p.selectAll("g");n.selectAll("path").attr("id",function(t){return"label-"+t.data.chrom});n.append("svg:text").filter(function(t){return t.endAngle-t.startAngle>o.min_arc_len}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(t){return"#label-"+t.data.chrom}).attr("startOffset","25%").attr("font-weight","bold").text(function(t){return t.data.chrom});var q=function(v){var t=(v.endAngle-v.startAngle)/v.value,u=l.range(0,v.value,25000000).map(function(w,x){return{radius:o.innerRadius,angle:w*t+v.startAngle,label:x===0?0:(x%3?null:o.formatNum(w))}});if(u.length<4){u[u.length-1].label=o.formatNum(Math.round((u[u.length-1].angle-v.startAngle)/t))}return u};var s=function(t){return t.angle>Math.PI?"rotate(180)translate(-16)":null};var r=g.filter(this.chroms_layout,function(t){return t.endAngle-t.startAngle>o.min_arc_len});this.drawTicks(this.parent_elt,r,q,s)}});g.extend(b.prototype,h);var f=k.extend({_quantile:function(o,n){o.sort(l.ascending);return l.quantile(o,n)},_render_chrom_data:function(n,q,o){var r=this._get_path_function(q,o);if(!r){return null}var p=n.datum(o.data),s=p.append("path").attr("class","chrom-data").attr("chrom",q.data.chrom).attr("d",r);return s},_get_path_function:function(q,p){if(typeof p==="string"||!p.data||p.data.length===0){return null}var n=l.scale.linear().domain(this.data_bounds).range(this.radius_bounds).clamp(true);var r=l.scale.linear().domain([0,p.data.length]).range([q.startAngle,q.endAngle]);var o=l.svg.line.radial().interpolate("linear").radius(function(s){return n(s[1])}).angle(function(t,s){return r(s)});return l.svg.area.radial().interpolate(o.interpolate()).innerRadius(n(0)).outerRadius(o.radius()).angle(o.angle())},render_labels:function(){var n=this,q=function(){return"rotate(90)"};var p=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),o=g.filter(p,function(s,r){return r%3===0});this.drawTicks(this.parent_elt,o,this._data_bounds_ticks_fn(),q,true)},_transition_labels:function(){if(this.data_bounds.length===0){return}var o=this,q=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),p=g.filter(q,function(s,r){return r%3===0}),n=g.flatten(g.map(p,function(r){return o._data_bounds_ticks_fn()(r)}));this.parent_elt.selectAll("g.tick").data(n).transition().attr("transform",function(r){return"rotate("+(r.angle*180/Math.PI-90)+")translate("+r.radius+",0)"})},_data_bounds_ticks_fn:function(){var n=this;visibleChroms=0;return function(o){return[{radius:n.radius_bounds[0],angle:o.startAngle,label:n.formatNum(n.data_bounds[0])},{radius:n.radius_bounds[1],angle:o.startAngle,label:n.formatNum(n.data_bounds[1])}]}},get_data_bounds:function(n){}});g.extend(f.prototype,h);var e=f.extend({get_data_bounds:function(o){var n=g.map(o,function(p){if(typeof p==="string"||!p.max){return 0}return p.max});return[0,(n&&typeof n!=="string"?this._quantile(n,0.98):0)]}});var d=f.extend({get_data_bounds:function(o){var n=g.flatten(g.map(o,function(p){if(p){return g.map(p.data,function(q){return q[1]})}else{return 0}}));return[g.min(n),this._quantile(n,0.98)]}});var j=k.extend({render:function(){var n=this;$.when(n.track.get("data_manager").data_is_ready()).then(function(){$.when(n.track.get("data_manager").get_genome_wide_data(n.genome)).then(function(q){var p=[],o=n.genome.get_chroms_info();g.each(q,function(u,t){var r=o[t].chrom;var s=g.map(u.data,function(w){var v=n._get_region_angle(r,w[1]),x=n._get_region_angle(w[3],w[4]);return{source:{startAngle:v,endAngle:v+0.01},target:{startAngle:x,endAngle:x+0.01}}});p=p.concat(s)});n.parent_elt.append("g").attr("class","chord").selectAll("path").data(p).enter().append("path").style("fill",n.get_fill_color()).attr("d",l.svg.chord().radius(n.radius_bounds[0])).style("opacity",1)})})},update_radius_bounds:function(n){this.radius_bounds=n;this.parent_elt.selectAll("path").transition().attr("d",l.svg.chord().radius(this.radius_bounds[0]))},_get_region_angle:function(p,n){var o=g.find(this.chroms_layout,function(q){return q.data.chrom===p});return o.endAngle-((o.endAngle-o.startAngle)*(o.data.len-n)/o.data.len)}});return{CircsterView:a}});
\ 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: natefoo: Make 'paused' a terminal state so that the history no longer polls for updates when it contains paused datasets.
by Bitbucket 15 Nov '12
by Bitbucket 15 Nov '12
15 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/94627de62528/
changeset: 94627de62528
user: natefoo
date: 2012-11-15 17:21:13
summary: Make 'paused' a terminal state so that the history no longer polls for updates when it contains paused datasets.
affected #: 2 files
diff -r a478d3fb1d07fd929f22ba55e90ee96a81393cf3 -r 94627de6252824193ff0ff659807d17e59e4f94f lib/galaxy/jobs/handler.py
--- a/lib/galaxy/jobs/handler.py
+++ b/lib/galaxy/jobs/handler.py
@@ -195,7 +195,7 @@
job.state = model.Job.states.PAUSED
for dataset_assoc in job.output_datasets + job.output_library_datasets:
dataset_assoc.dataset.dataset.state = model.Dataset.states.PAUSED
- dataset_assoc.dataset.blurb = "Execution of this dataset's job is paused because you were over your disk quota at the time it was ready to run"
+ dataset_assoc.dataset.info = "Execution of this dataset's job is paused because you were over your disk quota at the time it was ready to run"
self.sa_session.add( dataset_assoc.dataset.dataset )
self.sa_session.add( job )
else:
diff -r a478d3fb1d07fd929f22ba55e90ee96a81393cf3 -r 94627de6252824193ff0ff659807d17e59e4f94f templates/root/history.mako
--- a/templates/root/history.mako
+++ b/templates/root/history.mako
@@ -30,7 +30,7 @@
<script type="text/javascript">
-<% TERMINAL_STATES = ["ok", "error", "empty", "deleted", "discarded", "failed_metadata"] %>
+<% TERMINAL_STATES = ["ok", "error", "empty", "deleted", "discarded", "failed_metadata", "paused"] %>
TERMINAL_STATES = ${ h.to_json_string(TERMINAL_STATES) };
// Tag handling.
@@ -708,4 +708,4 @@
</div></body>
-</html>
\ No newline at end of file
+</html>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: natefoo: When a job fails, pause any dependent jobs (and the dependent jobs' outputs).
by Bitbucket 15 Nov '12
by Bitbucket 15 Nov '12
15 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/a478d3fb1d07/
changeset: a478d3fb1d07
user: natefoo
date: 2012-11-15 17:11:23
summary: When a job fails, pause any dependent jobs (and the dependent jobs' outputs).
affected #: 5 files
diff -r 0074aa873198dc48ae9e8e5f5b7c70a99dc0cf54 -r a478d3fb1d07fd929f22ba55e90ee96a81393cf3 lib/galaxy/jobs/__init__.py
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -245,6 +245,9 @@
# Update (non-library) job output datasets through the object store
if dataset not in job.output_library_datasets:
self.app.object_store.update_from_file(dataset.dataset, create=True)
+ # Pause any dependent jobs (and those jobs' outputs)
+ for dep_job_assoc in dataset.dependent_jobs:
+ self.pause( dep_job_assoc.job, "Execution of this dataset's job is paused because its input datasets are in an error state." )
self.sa_session.add( dataset )
self.sa_session.flush()
job.state = job.states.ERROR
@@ -275,6 +278,19 @@
if self.app.config.cleanup_job == 'always' or (self.app.config.cleanup_job == 'onsuccess' and job.state == job.states.DELETED):
self.cleanup()
+ def pause( self, job=None, message=None ):
+ if job is None:
+ job = self.get_job()
+ if message is None:
+ message = "Execution of this dataset's job is paused"
+ if job.state == job.states.NEW:
+ for dataset_assoc in job.output_datasets + job.output_library_datasets:
+ dataset_assoc.dataset.dataset.state = dataset_assoc.dataset.dataset.states.PAUSED
+ dataset_assoc.dataset.info = message
+ self.sa_session.add( dataset_assoc.dataset )
+ job.state = job.states.PAUSED
+ self.sa_session.add( job )
+
def change_state( self, state, info = False ):
job = self.get_job()
self.sa_session.refresh( job )
@@ -437,6 +453,9 @@
log.debug( "setting dataset state to ERROR" )
# TODO: This is where the state is being set to error. Change it!
dataset_assoc.dataset.dataset.state = model.Dataset.states.ERROR
+ # Pause any dependent jobs (and those jobs' outputs)
+ for dep_job_assoc in dataset_assoc.dataset.dependent_jobs:
+ self.pause( dep_job_assoc.job, "Execution of this dataset's job is paused because its input datasets are in an error state." )
else:
dataset_assoc.dataset.dataset.state = model.Dataset.states.OK
# If any of the rest of the finish method below raises an
diff -r 0074aa873198dc48ae9e8e5f5b7c70a99dc0cf54 -r a478d3fb1d07fd929f22ba55e90ee96a81393cf3 lib/galaxy/jobs/handler.py
--- a/lib/galaxy/jobs/handler.py
+++ b/lib/galaxy/jobs/handler.py
@@ -193,6 +193,10 @@
elif job_state == JOB_USER_OVER_QUOTA:
log.info( "(%d) User (%s) is over quota: job paused" % ( job.id, job.user_id ) )
job.state = model.Job.states.PAUSED
+ for dataset_assoc in job.output_datasets + job.output_library_datasets:
+ dataset_assoc.dataset.dataset.state = model.Dataset.states.PAUSED
+ dataset_assoc.dataset.blurb = "Execution of this dataset's job is paused because you were over your disk quota at the time it was ready to run"
+ self.sa_session.add( dataset_assoc.dataset.dataset )
self.sa_session.add( job )
else:
log.error( "(%d) Job in unknown state '%s'" % ( job.id, job_state ) )
diff -r 0074aa873198dc48ae9e8e5f5b7c70a99dc0cf54 -r a478d3fb1d07fd929f22ba55e90ee96a81393cf3 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -870,6 +870,7 @@
EMPTY = 'empty',
ERROR = 'error',
DISCARDED = 'discarded',
+ PAUSED = 'paused',
SETTING_METADATA = 'setting_metadata',
FAILED_METADATA = 'failed_metadata' )
permitted_actions = get_permitted_actions( filter='DATASET' )
diff -r 0074aa873198dc48ae9e8e5f5b7c70a99dc0cf54 -r a478d3fb1d07fd929f22ba55e90ee96a81393cf3 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -1571,13 +1571,13 @@
) )
assign_mapper( context, JobToInputDatasetAssociation, JobToInputDatasetAssociation.table,
- properties=dict( job=relation( Job ), dataset=relation( HistoryDatasetAssociation, lazy=False ) ) )
+ properties=dict( job=relation( Job ), dataset=relation( HistoryDatasetAssociation, lazy=False, backref="dependent_jobs" ) ) )
assign_mapper( context, JobToOutputDatasetAssociation, JobToOutputDatasetAssociation.table,
properties=dict( job=relation( Job ), dataset=relation( HistoryDatasetAssociation, lazy=False ) ) )
assign_mapper( context, JobToInputLibraryDatasetAssociation, JobToInputLibraryDatasetAssociation.table,
- properties=dict( job=relation( Job ), dataset=relation( LibraryDatasetDatasetAssociation, lazy=False ) ) )
+ properties=dict( job=relation( Job ), dataset=relation( LibraryDatasetDatasetAssociation, lazy=False, backref="dependent_jobs" ) ) )
assign_mapper( context, JobToOutputLibraryDatasetAssociation, JobToOutputLibraryDatasetAssociation.table,
properties=dict( job=relation( Job ), dataset=relation( LibraryDatasetDatasetAssociation, lazy=False ) ) )
diff -r 0074aa873198dc48ae9e8e5f5b7c70a99dc0cf54 -r a478d3fb1d07fd929f22ba55e90ee96a81393cf3 templates/root/history_common.mako
--- a/templates/root/history_common.mako
+++ b/templates/root/history_common.mako
@@ -153,7 +153,7 @@
</div>
%elif data_state == "paused":
<div>
- ${_('Job is currently paused. Check your quota and parent jobs for failure, use the history menu to resume.')}</div>
+ ${_('Job is currently paused:')} <i>${data.display_info().strip().rstrip('.')}.</i> ${_('Use the history menu to resume.')}</div><div><a href="${h.url_for( controller='dataset', action='show_params', dataset_id=dataset_id )}" target="galaxy_main" title='${_("View Details")}' class="icon-button information tooltip"></a>
%if for_editing:
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: Add missing attributes to the ToolDataTable class.
by Bitbucket 15 Nov '12
by Bitbucket 15 Nov '12
15 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/0074aa873198/
changeset: 0074aa873198
user: greg
date: 2012-11-15 15:35:25
summary: Add missing attributes to the ToolDataTable class.
affected #: 1 file
diff -r 340438c62171578078323d39da398d5053b69d0a -r 0074aa873198dc48ae9e8e5f5b7c70a99dc0cf54 lib/galaxy/tools/data/__init__.py
--- a/lib/galaxy/tools/data/__init__.py
+++ b/lib/galaxy/tools/data/__init__.py
@@ -118,6 +118,14 @@
class ToolDataTable( object ):
def __init__( self, config_element, tool_data_path ):
self.name = config_element.get( 'name' )
+ self.comment_char = config_element.get( 'comment_char' )
+ for file_elem in config_element.findall( 'file' ):
+ # There should only be one file_elem.
+ if 'path' in file_elem.attrib:
+ tool_data_file_path = file_elem.get( 'path' )
+ self.tool_data_file = os.path.split( tool_data_file_path )[1]
+ else:
+ self.tool_data_file = None
self.tool_data_path = tool_data_path
self.missing_index_file = None
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/340438c62171/
changeset: 340438c62171
user: jgoecks
date: 2012-11-15 00:50:20
summary: Small bug fixes for Circster.
affected #: 1 file
diff -r cc7df5ca1d47dbbd98614c21589435f84c67f9f5 -r 340438c62171578078323d39da398d5053b69d0a static/scripts/viz/circster.js
--- a/static/scripts/viz/circster.js
+++ b/static/scripts/viz/circster.js
@@ -84,6 +84,11 @@
* Format number for display at a tick.
*/
formatNum: function(num, sigDigits) {
+ // Use default of 2 sig. digits.
+ if (sigDigits === undefined) {
+ sigDigits = 2;
+ }
+
var rval = null;
if (num < 1) {
rval = num.toPrecision(sigDigits);
@@ -866,7 +871,7 @@
if (typeof d === 'string' || !d.max) { return 0; }
return d.max;
});
- return [ 0, (max_data && typeof max_data !== 'string' ? this._quantile(values, 0.98) : 0) ];
+ return [ 0, (max_data && typeof max_data !== 'string' ? this._quantile(max_data, 0.98) : 0) ];
}
});
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Introduction of the dataset "Paused" state and basic resume-all functionality for a history. This will need to be reimplemented in backbone, when that's committed and enabled.
by Bitbucket 14 Nov '12
by Bitbucket 14 Nov '12
14 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/cc7df5ca1d47/
changeset: cc7df5ca1d47
user: dannon
date: 2012-11-14 22:18:26
summary: Introduction of the dataset "Paused" state and basic resume-all functionality for a history. This will need to be reimplemented in backbone, when that's committed and enabled.
affected #: 7 files
diff -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb -r cc7df5ca1d47dbbd98614c21589435f84c67f9f5 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -698,6 +698,11 @@
def unhide_datasets( self ):
for dataset in self.datasets:
dataset.mark_unhidden()
+ def resume_paused_jobs( self ):
+ for dataset in self.datasets:
+ job = dataset.creating_job
+ if job.state == Job.states.PAUSED:
+ job.set_state(Job.states.QUEUED)
def get_disk_size( self, nice_size=False ):
# unique datasets only
db_session = object_session( self )
diff -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb -r cc7df5ca1d47dbbd98614c21589435f84c67f9f5 lib/galaxy/webapps/galaxy/controllers/history.py
--- a/lib/galaxy/webapps/galaxy/controllers/history.py
+++ b/lib/galaxy/webapps/galaxy/controllers/history.py
@@ -564,6 +564,20 @@
return trans.show_ok_message( "Your datasets have been unhidden.", refresh_frames=refresh_frames )
@web.expose
+ def resume_paused_jobs( self, trans, current=False, ids=None ):
+ """Resume paused jobs the active history -- this does not require a logged in user."""
+ if not ids and util.string_as_bool( current ):
+ histories = [ trans.get_history() ]
+ refresh_frames = ['history']
+ else:
+ raise NotImplementedError( "You can currently only resume all the datasets of the current history." )
+ for history in histories:
+ history.resume_paused_jobs()
+ trans.sa_session.add( history )
+ trans.sa_session.flush()
+ return trans.show_ok_message( "Your jobs have been resumed.", refresh_frames=refresh_frames )
+
+ @web.expose
@web.require_login( "rate items" )
@web.json
def rate_async( self, trans, id, rating ):
diff -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb -r cc7df5ca1d47dbbd98614c21589435f84c67f9f5 static/june_2007_style/base.less
--- a/static/june_2007_style/base.less
+++ b/static/june_2007_style/base.less
@@ -1637,6 +1637,11 @@
opacity: .60;
}
+div.historyItem-paused {
+ // border-color: @history_paused_border;
+ background: @history_paused_bg;
+}
+
// Special case for showing the spinner but not changing the background
div.historyItemTitleBar.spinner .state-icon {
background: url(data_running.gif) 0 1px no-repeat !important;
diff -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb -r cc7df5ca1d47dbbd98614c21589435f84c67f9f5 static/june_2007_style/blue/base.css
--- a/static/june_2007_style/blue/base.css
+++ b/static/june_2007_style/blue/base.css
@@ -851,6 +851,7 @@
div.historyItem-upload{background:#ccccff;}div.historyItem-upload .state-icon{background-image:url(data_upload.gif);}
div.historyItem-queued{background:#eeeeee;}
div.historyItem-noPermission{filter:alpha(opacity=60);-moz-opacity:.60;opacity:.60;}
+div.historyItem-paused{background:#d9edf7;}
div.historyItemTitleBar.spinner .state-icon{background:url(data_running.gif) 0 1px no-repeat !important;}
div.historyItemButtons{float:right;}
div.historyItemBody div{padding-top:2px;}
diff -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb -r cc7df5ca1d47dbbd98614c21589435f84c67f9f5 static/june_2007_style/blue_colors.ini
--- a/static/june_2007_style/blue_colors.ini
+++ b/static/june_2007_style/blue_colors.ini
@@ -44,6 +44,8 @@
history_deleted_bg=#3399FF
history_error_border=#AA6666
history_error_bg=#FFCCCC
+history_paused_border=#6666AA
+history_paused_bg=#d9edf7
history_running_border=#AAAA66
history_running_bg=#FFFFCC
history_ok_border=#66AA66
diff -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb -r cc7df5ca1d47dbbd98614c21589435f84c67f9f5 templates/root/history_common.mako
--- a/templates/root/history_common.mako
+++ b/templates/root/history_common.mako
@@ -127,7 +127,12 @@
%endif
%endif
</div>
- <span class="state-icon"></span>
+ ## Hack, do it in css
+ %if data_state == "paused":
+ <span class="ficon pause"></span>
+ %else:
+ <span class="state-icon"></span>
+ %endif
<span class="historyItemTitle">${hid}: ${data.display_name()}</span></div>
@@ -146,6 +151,15 @@
<a href="${h.url_for( controller='tool_runner', action='rerun', id=data.id )}" target="galaxy_main" title='${_("Run this job again")}' class="icon-button arrow-circle tooltip"></a>
%endif
</div>
+ %elif data_state == "paused":
+ <div>
+ ${_('Job is currently paused. Check your quota and parent jobs for failure, use the history menu to resume.')}</div>
+ <div>
+ <a href="${h.url_for( controller='dataset', action='show_params', dataset_id=dataset_id )}" target="galaxy_main" title='${_("View Details")}' class="icon-button information tooltip"></a>
+ %if for_editing:
+ <a href="${h.url_for( controller='tool_runner', action='rerun', id=data.id )}" target="galaxy_main" title='${_("Run this job again")}' class="icon-button arrow-circle tooltip"></a>
+ %endif
+ </div>
%elif data_state == "running":
<div>${_('Job is currently running')}</div><div>
diff -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb -r cc7df5ca1d47dbbd98614c21589435f84c67f9f5 templates/root/index.mako
--- a/templates/root/index.mako
+++ b/templates/root/index.mako
@@ -37,6 +37,9 @@
"${_("Dataset Security")}": function() {
galaxy_main.location = "${h.url_for( controller='root', action='history_set_default_permissions' )}";
},
+ "${_("Resume Paused Jobs")}": function() {
+ galaxy_history.location = "${h.url_for( controller='history', action='resume_paused_jobs', current=True)}";
+ },
"${_("Show Deleted Datasets")}": function() {
galaxy_history.location = "${h.url_for( controller='root', action='history', show_deleted=True)}";
},
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: natefoo: Add more featureful job limiting and optimize the query for checking whether
by Bitbucket 13 Nov '12
by Bitbucket 13 Nov '12
13 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/73e05bc14cf1/
changeset: 73e05bc14cf1
user: natefoo
date: 2012-11-13 21:00:55
summary: Add more featureful job limiting and optimize the query for checking whether
jobs are ready to run. Input dependency checks are now performed via SQL
rather than walking up the object chain. Limits on the number of jobs a user
can run can now be set across the entire instance and a job runner URL.
Quota checks at job runtime are only performed once, after limit checks. If a
user is over quota, jobs are moved to a "paused" state. Once the user is under
quota, jobs can be unpaused and continue to run (once this UI is added in
another commit, shortly). This obviates the need for quota checks on every
job, on every queue cycle.
When a job's input dataset errors, the job (and all jobs dependent upon that
job) are no longer errored. It will then be possible to remap a job to new
inputs to allow execution to continue from the point of failure. Commit for
that is also coming shortly.
affected #: 7 files
diff -r ed0738c6001654d5456dd36579b278cd10fcd00c -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -124,6 +124,9 @@
self.enable_beta_job_managers = string_as_bool( kwargs.get( 'enable_beta_job_managers', 'False' ) )
# Per-user Job concurrency limitations
self.user_job_limit = int( kwargs.get( 'user_job_limit', 0 ) )
+ # user_job_limit for backwards-compatibility
+ self.registered_user_job_limit = int( kwargs.get( 'registered_user_job_limit', self.user_job_limit ) )
+ self.anonymous_user_job_limit = int( kwargs.get( 'anonymous_user_job_limit', self.user_job_limit ) )
self.default_cluster_job_runner = kwargs.get( 'default_cluster_job_runner', 'local:///' )
self.pbs_application_server = kwargs.get('pbs_application_server', "" )
self.pbs_dataset_server = kwargs.get('pbs_dataset_server', "" )
@@ -216,6 +219,19 @@
self.job_manager = kwargs.get('job_manager', self.server_name).strip()
self.job_handlers = [ x.strip() for x in kwargs.get('job_handlers', self.server_name).split(',') ]
self.default_job_handlers = [ x.strip() for x in kwargs.get('default_job_handlers', ','.join( self.job_handlers ) ).split(',') ]
+ # parse the [galaxy:job_limits] section
+ self.job_limits = {}
+ try:
+ job_limits = global_conf_parser.items( 'galaxy:job_limits' )
+ for k, v in job_limits:
+ # ConfigParser considers the first colon to be the delimiter, undo this behavior
+ more_k, v = v.split('=', 1)
+ k = '%s:%s' % (k, more_k.strip())
+ v = v.strip().rsplit(None, 1)
+ v[1] = int(v[1])
+ self.job_limits[k] = v
+ except ConfigParser.NoSectionError:
+ pass
# Use database for IPC unless this is a standalone server (or multiple servers doing self dispatching in memory)
if self.track_jobs_in_database is None or self.track_jobs_in_database == "None":
self.track_jobs_in_database = True
diff -r ed0738c6001654d5456dd36579b278cd10fcd00c -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb lib/galaxy/jobs/__init__.py
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -81,7 +81,7 @@
self.tool_provided_job_metadata = None
# Wrapper holding the info required to restore and clean up from files used for setting metadata externally
self.external_output_metadata = metadata.JobExternalOutputMetadataWrapper( job )
- self.job_runner_mapper = JobRunnerMapper( self )
+ self.job_runner_mapper = JobRunnerMapper( self, job.job_runner_name )
self.params = None
if job.params:
self.params = from_json_string( job.params )
diff -r ed0738c6001654d5456dd36579b278cd10fcd00c -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb lib/galaxy/jobs/handler.py
--- a/lib/galaxy/jobs/handler.py
+++ b/lib/galaxy/jobs/handler.py
@@ -8,7 +8,7 @@
import threading
from Queue import Queue, Empty
-from sqlalchemy.sql.expression import and_, or_
+from sqlalchemy.sql.expression import and_, or_, select, func
from galaxy import util, model
from galaxy.jobs import Sleeper, JobWrapper, TaskWrapper
@@ -16,7 +16,7 @@
log = logging.getLogger( __name__ )
# States for running a job. These are NOT the same as data states
-JOB_WAIT, JOB_ERROR, JOB_INPUT_ERROR, JOB_INPUT_DELETED, JOB_READY, JOB_DELETED, JOB_ADMIN_DELETED = 'wait', 'error', 'input_error', 'input_deleted', 'ready', 'deleted', 'admin_deleted'
+JOB_WAIT, JOB_ERROR, JOB_INPUT_ERROR, JOB_INPUT_DELETED, JOB_READY, JOB_DELETED, JOB_ADMIN_DELETED, JOB_USER_OVER_QUOTA = 'wait', 'error', 'input_error', 'input_deleted', 'ready', 'deleted', 'admin_deleted', 'user_over_quota'
class JobHandler( object ):
"""
@@ -126,9 +126,32 @@
# Clear the session so we get fresh states for job and all datasets
self.sa_session.expunge_all()
# Fetch all new jobs
- jobs_to_check = self.sa_session.query( model.Job ).enable_eagerloads( False ) \
- .filter( ( model.Job.state == model.Job.states.NEW ) \
- & ( model.Job.handler == self.app.config.server_name ) ).all()
+ hda_not_ready = self.sa_session.query(model.Job.id).enable_eagerloads(False) \
+ .join(model.JobToInputDatasetAssociation) \
+ .join(model.HistoryDatasetAssociation) \
+ .join(model.Dataset) \
+ .filter(and_((model.Job.state == model.Job.states.NEW),
+ or_((model.HistoryDatasetAssociation._state != None),
+ (model.HistoryDatasetAssociation.deleted == True ),
+ (model.Dataset.state != model.Dataset.states.OK ),
+ (model.Dataset.deleted == True)))).subquery()
+ ldda_not_ready = self.sa_session.query(model.Job.id).enable_eagerloads(False) \
+ .join(model.JobToInputLibraryDatasetAssociation) \
+ .join(model.LibraryDatasetDatasetAssociation) \
+ .join(model.Dataset) \
+ .filter(and_((model.Job.state == model.Job.states.NEW),
+ or_((model.LibraryDatasetDatasetAssociation._state != None),
+ (model.LibraryDatasetDatasetAssociation.deleted == True),
+ (model.Dataset.state != model.Dataset.states.OK),
+ (model.Dataset.deleted == True)))).subquery()
+ jobs_to_check = self.sa_session.query(model.Job).enable_eagerloads(False) \
+ .filter(and_((model.Job.state == model.Job.states.NEW),
+ (model.Job.handler == self.app.config.server_name),
+ ~model.Job.table.c.id.in_(hda_not_ready),
+ ~model.Job.table.c.id.in_(ldda_not_ready))) \
+ .order_by(model.Job.id).all()
+ # Ensure that we get new job counts on each iteration
+ self.__clear_user_job_count()
else:
# Get job objects and append to watch queue for any which were
# previously waiting
@@ -150,7 +173,8 @@
new_waiting_jobs = []
for job in jobs_to_check:
try:
- # Check the job's dependencies, requeue if they're not done
+ # Check the job's dependencies, requeue if they're not done.
+ # Some of these states will only happen when using the in-memory job queue
job_state = self.__check_if_ready_to_run( job )
if job_state == JOB_WAIT:
if not self.track_jobs_in_database:
@@ -166,6 +190,10 @@
log.info( "(%d) Job deleted by user while still queued" % job.id )
elif job_state == JOB_ADMIN_DELETED:
log.info( "(%d) Job deleted by admin while still queued" % job.id )
+ elif job_state == JOB_USER_OVER_QUOTA:
+ log.info( "(%d) User (%s) is over quota: job paused" % ( job.id, job.user_id ) )
+ job.state = model.Job.states.PAUSED
+ self.sa_session.add( job )
else:
log.error( "(%d) Job in unknown state '%s'" % ( job.id, job_state ) )
if not self.track_jobs_in_database:
@@ -174,6 +202,8 @@
log.exception( "failure running job %d" % job.id )
# Update the waiting list
self.waiting_jobs = new_waiting_jobs
+ # Flush, if we updated the state
+ self.sa_session.flush()
# Done with the session
self.sa_session.remove()
@@ -187,57 +217,88 @@
job can be dispatched. Otherwise, return JOB_WAIT indicating that input
datasets are still being prepared.
"""
- if job.state == model.Job.states.DELETED:
- return JOB_DELETED
- elif job.state == model.Job.states.ERROR:
- return JOB_ADMIN_DELETED
- elif self.app.config.enable_quotas:
+ # If tracking in the database, job.state is guaranteed to be NEW and the inputs are guaranteed to be OK
+ if not self.track_jobs_in_database:
+ if job.state == model.Job.states.DELETED:
+ return JOB_DELETED
+ elif job.state == model.Job.states.ERROR:
+ return JOB_ADMIN_DELETED
+ for dataset_assoc in job.input_datasets + job.input_library_datasets:
+ idata = dataset_assoc.dataset
+ if not idata:
+ continue
+ # don't run jobs for which the input dataset was deleted
+ if idata.deleted:
+ JobWrapper( job, self ).fail( "input data %s (file: %s) was deleted before the job started" % ( idata.hid, idata.file_name ) )
+ return JOB_INPUT_DELETED
+ # an error in the input data causes us to bail immediately
+ elif idata.state == idata.states.ERROR:
+ JobWrapper( job, self ).fail( "input data %s is in error state" % ( idata.hid ) )
+ return JOB_INPUT_ERROR
+ elif idata.state == idata.states.FAILED_METADATA:
+ JobWrapper( job, self ).fail( "input data %s failed to properly set metadata" % ( idata.hid ) )
+ return JOB_INPUT_ERROR
+ elif idata.state != idata.states.OK and not ( idata.state == idata.states.SETTING_METADATA and job.tool_id is not None and job.tool_id == self.app.datatypes_registry.set_external_metadata_tool.id ):
+ # need to requeue
+ return JOB_WAIT
+ state = self.__check_user_jobs( job )
+ if state == JOB_READY and self.app.config.enable_quotas:
quota = self.app.quota_agent.get_quota( job.user )
if quota is not None:
try:
usage = self.app.quota_agent.get_usage( user=job.user, history=job.history )
if usage > quota:
- return JOB_WAIT
+ return JOB_USER_OVER_QUOTA
except AssertionError, e:
pass # No history, should not happen with an anon user
- for dataset_assoc in job.input_datasets + job.input_library_datasets:
- idata = dataset_assoc.dataset
- if not idata:
- continue
- # don't run jobs for which the input dataset was deleted
- if idata.deleted:
- JobWrapper( job, self ).fail( "input data %s (file: %s) was deleted before the job started" % ( idata.hid, idata.file_name ) )
- return JOB_INPUT_DELETED
- # an error in the input data causes us to bail immediately
- elif idata.state == idata.states.ERROR:
- JobWrapper( job, self ).fail( "input data %s is in error state" % ( idata.hid ) )
- return JOB_INPUT_ERROR
- elif idata.state == idata.states.FAILED_METADATA:
- JobWrapper( job, self ).fail( "input data %s failed to properly set metadata" % ( idata.hid ) )
- return JOB_INPUT_ERROR
- elif idata.state != idata.states.OK and not ( idata.state == idata.states.SETTING_METADATA and job.tool_id is not None and job.tool_id == self.app.datatypes_registry.set_external_metadata_tool.id ):
- # need to requeue
- return JOB_WAIT
- return self.__check_user_jobs( job )
+ return state
+
+ def __clear_user_job_count( self ):
+ self.user_job_count = {}
+ self.user_job_count_per_runner = {}
def __check_user_jobs( self, job ):
- if not self.app.config.user_job_limit:
- return JOB_READY
if job.user:
- count = self.sa_session.query( model.Job ).enable_eagerloads( False ) \
- .filter( and_( model.Job.user_id == job.user.id,
- or_( model.Job.state == model.Job.states.RUNNING,
- model.Job.state == model.Job.states.QUEUED ) ) ).count()
+ # Check the hard limit first
+ if self.app.config.registered_user_job_limit:
+ # Cache the job count if necessary
+ if not self.user_job_count:
+ query = self.sa_session.execute(select([model.Job.table.c.user_id, func.count(model.Job.table.c.user_id)]) \
+ .where(and_(model.Job.table.c.state.in_((model.Job.states.QUEUED, model.Job.states.RUNNING)), (model.Job.table.c.user_id is not None))) \
+ .group_by(model.Job.table.c.user_id))
+ for row in query:
+ self.user_job_count[row[0]] = row[1]
+ if self.user_job_count.get(job.user_id, 0) >= self.app.config.registered_user_job_limit:
+ return JOB_WAIT
+ # If we pass the hard limit, also check the per-runner count
+ if job.job_runner_name in self.app.config.job_limits:
+ # Cache the job count if necessary
+ if job.job_runner_name not in self.user_job_count_per_runner:
+ self.user_job_count_per_runner[job.job_runner_name] = {}
+ query_url, limit = self.app.config.job_limits[job.job_runner_name]
+ base_query = select([model.Job.table.c.user_id, model.Job.table.c.job_runner_name, func.count(model.Job.table.c.user_id).label('job_count')]) \
+ .where(model.Job.table.c.state.in_((model.Job.states.QUEUED, model.Job.states.RUNNING))) \
+ .group_by(model.Job.table.c.user_id, model.Job.table.c.job_runner_name)
+ if '%' in query_url or '_' in query_url:
+ subq = base_query.having(model.Job.table.c.job_runner_name.like(query_url)).alias('subq')
+ query = self.sa_session.execute(select([subq.c.user_id, func.sum(subq.c.job_count).label('job_count')]).group_by(subq.c.user_id))
+ else:
+ query = self.sa_session.execute(base_query.having(model.Job.table.c.job_runner_name == query_url))
+ for row in query:
+ self.user_job_count_per_runner[job.job_runner_name][row['user_id']] = row['job_count']
+ if self.user_job_count_per_runner[job.job_runner_name].get(job.user_id, 0) >= self.app.config.job_limits[job.job_runner_name][1]:
+ return JOB_WAIT
elif job.galaxy_session:
- count = self.sa_session.query( model.Job ).enable_eagerloads( False ) \
- .filter( and_( model.Job.session_id == job.galaxy_session.id,
- or_( model.Job.state == model.Job.states.RUNNING,
- model.Job.state == model.Job.states.QUEUED ) ) ).count()
+ # Anonymous users only get the hard limit
+ if self.app.config.anonymous_user_job_limit:
+ count = self.sa_session.query( model.Job ).enable_eagerloads( False ) \
+ .filter( and_( model.Job.session_id == job.galaxy_session.id,
+ or_( model.Job.state == model.Job.states.RUNNING,
+ model.Job.state == model.Job.states.QUEUED ) ) ).count()
+ if count >= self.app.config.anonymous_user_job_limit:
+ return JOB_WAIT
else:
log.warning( 'Job %s is not associated with a user or session so job concurrency limit cannot be checked.' % job.id )
- return JOB_READY
- if count >= self.app.config.user_job_limit:
- return JOB_WAIT
return JOB_READY
def put( self, job_id, tool_id ):
diff -r ed0738c6001654d5456dd36579b278cd10fcd00c -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb lib/galaxy/jobs/manager.py
--- a/lib/galaxy/jobs/manager.py
+++ b/lib/galaxy/jobs/manager.py
@@ -146,6 +146,7 @@
for job in jobs_to_check:
job.handler = self.__get_handler( job )
+ job.job_runner_name = self.__get_runner_url( job )
log.debug( "(%s) Job assigned to handler '%s'" % ( job.id, job.handler ) )
self.sa_session.add( job )
@@ -168,6 +169,14 @@
log.exception( "(%s) Caught exception attempting to get tool-specific job handler for tool '%s', selecting at random from available handlers instead:" % ( job.id, job.tool_id ) )
return random.choice( self.app.config.job_handlers )
+ def __get_runner_url( self, job ):
+ """This fetches the raw runner URL, and does not perform any computation e.g. for the dynamic runner"""
+ try:
+ return self.app.toolbox.tools_by_id.get( job.tool_id, None ).get_job_runner_url( job.params )
+ except Exception, e:
+ log.warning( 'Unable to determine job runner URL for job %s: %s' % (job.id, str(e)) )
+ return None
+
def put( self, job_id, tool ):
"""Add a job to the queue (by job identifier)"""
if not self.app.config.track_jobs_in_database:
diff -r ed0738c6001654d5456dd36579b278cd10fcd00c -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb lib/galaxy/jobs/mapper.py
--- a/lib/galaxy/jobs/mapper.py
+++ b/lib/galaxy/jobs/mapper.py
@@ -14,8 +14,9 @@
(in the form of job_wrappers) to job runner url strings.
"""
- def __init__( self, job_wrapper ):
+ def __init__( self, job_wrapper, job_runner_name=None ):
self.job_wrapper = job_wrapper
+ self.job_runner_name = job_runner_name
self.rule_modules = self.__get_rule_modules( )
def __get_rule_modules( self ):
@@ -114,7 +115,11 @@
raise Exception( "Unhandled dynamic job runner type specified - %s" % expand_type )
def __cache_job_runner_url( self, params ):
- raw_job_runner_url = self.job_wrapper.tool.get_job_runner_url( params )
+ # If there's already a runner set in the Job object, don't overwrite from the tool
+ if self.job_runner_name is not None:
+ raw_job_runner_url = self.job_runner_name
+ else:
+ raw_job_runner_url = self.job_wrapper.tool.get_job_runner_url( params )
if raw_job_runner_url.startswith( DYNAMIC_RUNNER_PREFIX ):
job_runner_url = self.__expand_dynamic_job_runner_url( raw_job_runner_url[ len( DYNAMIC_RUNNER_PREFIX ) : ] )
else:
diff -r ed0738c6001654d5456dd36579b278cd10fcd00c -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -112,6 +112,7 @@
RUNNING = 'running',
OK = 'ok',
ERROR = 'error',
+ PAUSED = 'paused',
DELETED = 'deleted',
DELETED_NEW = 'deleted_new' )
# Please include an accessor (get/set pair) for any new columns/members.
diff -r ed0738c6001654d5456dd36579b278cd10fcd00c -r 73e05bc14cf1478b5ff9d8e8fffdf28d701dd2cb universe_wsgi.ini.sample
--- a/universe_wsgi.ini.sample
+++ b/universe_wsgi.ini.sample
@@ -659,12 +659,6 @@
# bytes). 0 for no limit.
#output_size_limit = 0
-# Jobs can be held back from submission to a runner if a user already has more
-# jobs queued or running than the number specified below. This prevents a
-# single user from stuffing the queue and preventing other users from being
-# able to run jobs.
-#user_job_limit = None
-
# Clustering Galaxy is not a straightforward process and requires some
# pre-configuration. See the the wiki before attempting to set any of these
# options:
@@ -717,6 +711,36 @@
# Details" option in the history. Administrators can always see this.
#expose_dataset_path = False
+# -- Job Limiting
+
+# A hard limit on the total number of jobs a user can have running across all
+# configured job destinations can be configured here.
+#registered_user_job_limit = None
+#anonymous_user_job_limit = None
+
+# Additionally, jobs can be limited based on runner URLs (or matching of runner
+# URLs). Matching is via SQL's 'LIKE' operator, so the wildcard characters are
+# '_' and '%' (regex is not supported). Since the job runner code often
+# rewrites the URL once the job has been submitted to the cluster, you will
+# need to define how to match the runner URL stored in the database. When in
+# doubt, you can run a job and then examine the stored value of
+# 'job_runner_name' in the 'job' table of the database to see what you'll need
+# to match.
+#
+# For example, if default_cluster_job_runner is set to pbs:/// and the default
+# Torque cluster happens to be pbs.example.org, the job_runner_name is likely
+# to be stored as 'pbs://pbs.example.org/'. To limit the number of jobs a user
+# can run on this cluster to 4, use the following:
+#
+# pbs:/// = pbs://pbs.example.org/ 4
+#
+# An example that uses matching (if, for example, your runner URL contains
+# native options):
+#
+# drmaa:/// = drmaa://sge.example.org/% 4
+
+[galaxy:job_limits]
+
# ---- Per-Tool Job Management ----------------------------------------------
# Per-tool job handler and runner overrides. Parameters can be included to define multiple
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
13 Nov '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/ed0738c60016/
changeset: ed0738c60016
user: greg
date: 2012-11-13 20:36:40
summary: Relocate the tool shed's ShedCounter.
affected #: 3 files
diff -r 424d407c67f7ea4f830317b7ab033815415a5a3b -r ed0738c6001654d5456dd36579b278cd10fcd00c lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -1,7 +1,6 @@
import sys, os, tempfile, shutil, logging, string, urllib2
import galaxy.tools.data
from datetime import date, datetime, timedelta
-from time import strftime, gmtime
from galaxy import util
from galaxy.web import url_for
from galaxy.web.form_builder import SelectField
@@ -40,85 +39,6 @@
VALID_CHARS = set( string.letters + string.digits + "'\"-=_.()/+*^,:?!#[]%\\$@;{}" )
TOOL_SHED_ADMIN_CONTROLLER = 'TOOL_SHED_ADMIN_CONTROLLER'
-class ShedCounter( object ):
- def __init__( self, model ):
- # TODO: Enhance the ShedCounter to retrieve information from the db instead of displaying what's currently in memory.
- self.model = model
- self.generation_time = strftime( "%b %d, %Y", gmtime() )
- self.repositories = 0
- #self.new_repositories = 0
- self.deleted_repositories = 0
- self.invalid_tools = 0
- self.valid_tools = 0
- self.workflows = 0
- self.proprietary_datatypes = 0
- self.total_clones = 0
- self.generate_statistics()
- @property
- def sa_session( self ):
- """Returns a SQLAlchemy session"""
- return self.model.context
- def generate_statistics( self ):
- self.repositories = 0
- #self.new_repositories = 0
- self.deleted_repositories = 0
- self.invalid_tools = 0
- self.valid_tools = 0
- self.workflows = 0
- self.proprietary_datatypes = 0
- self.total_clones = 0
- for repository in self.sa_session.query( self.model.Repository ):
- self.repositories += 1
- self.total_clones += repository.times_downloaded
- is_deleted = repository.deleted
- #is_new = repository.is_new
- #if is_deleted and is_new:
- if is_deleted:
- self.deleted_repositories += 1
- # self.new_repositories += 1
- #elif is_deleted:
- # self.deleted_repositories += 1
- #elif is_new:
- # self.new_repositories += 1
- else:
- processed_guids = []
- processed_invalid_tool_configs = []
- processed_relative_workflow_paths = []
- processed_datatypes = []
- # A repository's metadata_revisions are those that ignore the value of the repository_metadata.downloadable column.
- for metadata_revision in repository.metadata_revisions:
- metadata = metadata_revision.metadata
- if 'tools' in metadata:
- tool_dicts = metadata[ 'tools' ]
- for tool_dict in tool_dicts:
- if 'guid' in tool_dict:
- guid = tool_dict[ 'guid' ]
- if guid not in processed_guids:
- self.valid_tools += 1
- processed_guids.append( guid )
- if 'invalid_tools' in metadata:
- invalid_tool_configs = metadata[ 'invalid_tools' ]
- for invalid_tool_config in invalid_tool_configs:
- if invalid_tool_config not in processed_invalid_tool_configs:
- self.invalid_tools += 1
- processed_invalid_tool_configs.append( invalid_tool_config )
- if 'datatypes' in metadata:
- datatypes = metadata[ 'datatypes' ]
- for datatypes_dict in datatypes:
- if 'extension' in datatypes_dict:
- extension = datatypes_dict[ 'extension' ]
- if extension not in processed_datatypes:
- self.proprietary_datatypes += 1
- processed_datatypes.append( extension )
- if 'workflows' in metadata:
- workflows = metadata[ 'workflows' ]
- for workflow_tup in workflows:
- relative_path, exported_workflow_dict = workflow_tup
- if relative_path not in processed_relative_workflow_paths:
- self.workflows += 1
- processed_relative_workflow_paths.append( relative_path )
- self.generation_time = strftime( "%b %d, %Y", gmtime() )
-
def add_to_shed_tool_config( app, shed_tool_conf_dict, elem_list ):
# A tool shed repository is being installed so change the shed_tool_conf file. Parse the config file to generate the entire list
# of config_elems instead of using the in-memory list since it will be a subset of the entire list if one or more repositories have
diff -r 424d407c67f7ea4f830317b7ab033815415a5a3b -r ed0738c6001654d5456dd36579b278cd10fcd00c lib/galaxy/webapps/community/model/mapping.py
--- a/lib/galaxy/webapps/community/model/mapping.py
+++ b/lib/galaxy/webapps/community/model/mapping.py
@@ -13,7 +13,7 @@
from galaxy.model.orm.ext.assignmapper import *
from galaxy.model.custom_types import *
from galaxy.util.bunch import Bunch
-from galaxy.util.shed_util import ShedCounter
+from galaxy.webapps.community.util.shed_statistics import *
from galaxy.webapps.community.util.hgweb_config import *
from galaxy.webapps.community.security import CommunityRBACAgent
diff -r 424d407c67f7ea4f830317b7ab033815415a5a3b -r ed0738c6001654d5456dd36579b278cd10fcd00c lib/galaxy/webapps/community/util/shed_statistics.py
--- /dev/null
+++ b/lib/galaxy/webapps/community/util/shed_statistics.py
@@ -0,0 +1,80 @@
+from time import strftime, gmtime
+
+class ShedCounter( object ):
+ def __init__( self, model ):
+ # TODO: Enhance the ShedCounter to retrieve information from the db instead of displaying what's currently in memory.
+ self.model = model
+ self.generation_time = strftime( "%b %d, %Y", gmtime() )
+ self.repositories = 0
+ #self.new_repositories = 0
+ self.deleted_repositories = 0
+ self.invalid_tools = 0
+ self.valid_tools = 0
+ self.workflows = 0
+ self.proprietary_datatypes = 0
+ self.total_clones = 0
+ self.generate_statistics()
+ @property
+ def sa_session( self ):
+ """Returns a SQLAlchemy session"""
+ return self.model.context
+ def generate_statistics( self ):
+ self.repositories = 0
+ #self.new_repositories = 0
+ self.deleted_repositories = 0
+ self.invalid_tools = 0
+ self.valid_tools = 0
+ self.workflows = 0
+ self.proprietary_datatypes = 0
+ self.total_clones = 0
+ for repository in self.sa_session.query( self.model.Repository ):
+ self.repositories += 1
+ self.total_clones += repository.times_downloaded
+ is_deleted = repository.deleted
+ #is_new = repository.is_new
+ #if is_deleted and is_new:
+ if is_deleted:
+ self.deleted_repositories += 1
+ # self.new_repositories += 1
+ #elif is_deleted:
+ # self.deleted_repositories += 1
+ #elif is_new:
+ # self.new_repositories += 1
+ else:
+ processed_guids = []
+ processed_invalid_tool_configs = []
+ processed_relative_workflow_paths = []
+ processed_datatypes = []
+ # A repository's metadata_revisions are those that ignore the value of the repository_metadata.downloadable column.
+ for metadata_revision in repository.metadata_revisions:
+ metadata = metadata_revision.metadata
+ if 'tools' in metadata:
+ tool_dicts = metadata[ 'tools' ]
+ for tool_dict in tool_dicts:
+ if 'guid' in tool_dict:
+ guid = tool_dict[ 'guid' ]
+ if guid not in processed_guids:
+ self.valid_tools += 1
+ processed_guids.append( guid )
+ if 'invalid_tools' in metadata:
+ invalid_tool_configs = metadata[ 'invalid_tools' ]
+ for invalid_tool_config in invalid_tool_configs:
+ if invalid_tool_config not in processed_invalid_tool_configs:
+ self.invalid_tools += 1
+ processed_invalid_tool_configs.append( invalid_tool_config )
+ if 'datatypes' in metadata:
+ datatypes = metadata[ 'datatypes' ]
+ for datatypes_dict in datatypes:
+ if 'extension' in datatypes_dict:
+ extension = datatypes_dict[ 'extension' ]
+ if extension not in processed_datatypes:
+ self.proprietary_datatypes += 1
+ processed_datatypes.append( extension )
+ if 'workflows' in metadata:
+ workflows = metadata[ 'workflows' ]
+ for workflow_tup in workflows:
+ relative_path, exported_workflow_dict = workflow_tup
+ if relative_path not in processed_relative_workflow_paths:
+ self.workflows += 1
+ processed_relative_workflow_paths.append( relative_path )
+ self.generation_time = strftime( "%b %d, %Y", gmtime() )
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