galaxy-commits
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
5 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/60ce4bb8e4ce/
Changeset: 60ce4bb8e4ce
User: dannon
Date: 2015-02-08 23:02:26+00:00
Summary: Allow specifying connection at launch of GalaxyQueueWorker.
Affected #: 1 file
diff -r ea23071cf22ea78b699264e04b59e3adf88ec619 -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 lib/galaxy/queue_worker.py
--- a/lib/galaxy/queue_worker.py
+++ b/lib/galaxy/queue_worker.py
@@ -30,10 +30,13 @@
handler, will have one of these used for dispatching so called 'control'
tasks.
"""
- def __init__(self, app, queue, task_mapping):
+ def __init__(self, app, queue, task_mapping, connection=None):
super(GalaxyQueueWorker, self).__init__()
log.info("Initalizing Galaxy Queue Worker on %s" % app.config.amqp_internal_connection)
- self.connection = Connection(app.config.amqp_internal_connection)
+ if connection:
+ self.connection = connection
+ else:
+ self.connection = Connection(app.config.amqp_internal_connection)
self.app = app
# Eventually we may want different workers w/ their own queues and task
# mappings. Right now, there's only the one.
https://bitbucket.org/galaxy/galaxy-central/commits/01ac77bb90de/
Changeset: 01ac77bb90de
User: dannon
Date: 2015-02-09 16:36:45+00:00
Summary: Merge.
Affected #: 32 files
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 CONTRIBUTING.md
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,12 +1,13 @@
# Contributing
This document briefly describes how to contribute to the
-galaxy-central core project - also checkout the video of our [2013
-Galaxy Community Conference
-presentation](http://vimeo.com/channels/581875/73486255) on the
-topic. For information on contributing more broadly to the Galaxy
-ecosystem and a deeper discussion of some of these points - please see
-the [Develop](https://wiki.galaxyproject.org/Develop/) section of the
+galaxy-central core project - also checkout our 2013 Galaxy Community
+Conference presentation] on the topic
+([video](http://vimeo.com/channels/581875/73486255),
+[presentation](https://wiki.galaxyproject.org/Documents/Presentations/GCC2013?action=AttachFile&do=view&target=BakerContribute.pdf)). For
+information on contributing more broadly to the Galaxy ecosystem and a
+deeper discussion of some of these points - please see the
+[Develop](https://wiki.galaxyproject.org/Develop/) section of the
[Galaxy Wiki](https://wiki.galaxyproject.org/).
## Before you Begin
@@ -80,6 +81,13 @@
* A description of how to test the change.
+## Ideas
+
+Galaxy's [Trello board](http://bit.ly/gxytrello) is filled with bugs and ideas
+for enhancements, but we maintain a [card](https://trello.com/c/eFdPIdIB) with
+links to smaller issues we believe would make the best entry points for new
+developers.
+
## A Quick Note about Tools
For the most part, Galaxy tools should be published to the
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 client/galaxy/scripts/mvc/tools/tools-form-workflow.js
--- a/client/galaxy/scripts/mvc/tools/tools-form-workflow.js
+++ b/client/galaxy/scripts/mvc/tools/tools-form-workflow.js
@@ -275,10 +275,16 @@
/** Request a new model for an already created tool form and updates the form inputs
*/
_updateModel: function() {
+ // link self
+ var self = this;
+
// create the request dictionary
- var self = this;
- var current_state = this.tree.finalize();
-
+ var current_state = {
+ tool_id : this.options.id,
+ tool_version : this.options.version,
+ inputs : this.tree.finalize()
+ }
+
// log tool state
console.debug('tools-form-workflow::_refreshForm() - Refreshing states.');
console.debug(current_state);
@@ -287,11 +293,11 @@
var process_id = this.deferred.register();
// build model url for request
- var model_url = galaxy_config.root + 'workflow/editor_form_post?tool_id=' + this.options.id + '&__is_dynamic__=False';
+ var model_url = galaxy_config.root + 'api/workflows/build_module';
// post job
Utils.request({
- type : 'GET',
+ type : 'POST',
url : model_url,
data : current_state,
success : function(data) {
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 client/galaxy/scripts/mvc/tools/tools-input.js
--- a/client/galaxy/scripts/mvc/tools/tools-input.js
+++ b/client/galaxy/scripts/mvc/tools/tools-input.js
@@ -34,8 +34,7 @@
this.field.skip = false;
var v = this.field.value && this.field.value();
this.field.skip = Boolean(options.optional &&
- ((this.default_value === undefined) ||
- ((this.field.validate && !this.field.validate()) || !v ||
+ (((this.field.validate && !this.field.validate()) || !v ||
(v == this.default_value) || (Number(v) == Number(this.default_value)) ||
(JSON.stringify(v) == JSON.stringify(this.default_value)))));
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 client/galaxy/scripts/mvc/tools/tools-section.js
--- a/client/galaxy/scripts/mvc/tools/tools-section.js
+++ b/client/galaxy/scripts/mvc/tools/tools-section.js
@@ -294,17 +294,20 @@
// get id
var id = input_def.id;
+ // add regular/default value if missing
+ if (input_def.value === undefined) {
+ input_def.value = null;
+ }
+ if (input_def.default_value === undefined) {
+ input_def.default_value = input_def.value;
+ }
+
// create input field
var field = this._createField(input_def);
// add to field list
this.app.field_list[id] = field;
- // fix default value if missing
- if (input_def.default_value === undefined) {
- input_def.default_value = input_def.value;
- }
-
// create input field wrapper
var input_element = new InputElement(this.app, {
label : input_def.label,
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 client/galaxy/scripts/mvc/tools/tools-tree.js
--- a/client/galaxy/scripts/mvc/tools/tools-tree.js
+++ b/client/galaxy/scripts/mvc/tools/tools-tree.js
@@ -10,13 +10,13 @@
initialize: function(app) {
this.app = app;
},
-
+
/** Convert dictionary representation into tool api specific flat dictionary format.
*/
finalize: function(patch) {
// link this
var self = this;
-
+
// dictionary with api specific identifiers
this.map_dict = {};
@@ -24,24 +24,24 @@
if (!this.app.section) {
return {};
}
-
+
// ensure that dictionary with patching functions exists
patch = patch || {};
-
+
// dictionary formatted for job submission or tool form update
var result_dict = {};
// prepare full dictionary
var dict = {};
-
+
// fill dictionary from dom
this._iterate(this.app.section.$el, dict);
-
+
// add identifier and value to job definition
function add(job_input_id, input_id, input_value) {
// add entry to result dictionary
result_dict[job_input_id] = input_value;
-
+
// backup id mapping
self.map_dict[job_input_id] = input_id;
};
@@ -53,21 +53,21 @@
if (node.input) {
// get node
var input = node.input;
-
+
// create identifier
var job_input_id = identifier;
if (identifier != '') {
job_input_id += '|';
}
job_input_id += input.name;
-
+
// process input type
switch (input.type) {
// handle repeats
case 'repeat':
// section identifier
var section_label = 'section-';
-
+
// collect repeat block identifiers
var block_indices = [];
var block_prefix = null;
@@ -81,10 +81,10 @@
}
}
}
-
+
// sort repeat blocks
block_indices.sort(function(a,b) { return a - b; });
-
+
// add to response dictionary in created order
var index = 0;
for (var i in block_indices) {
@@ -98,10 +98,10 @@
if (patch[input.test_param.type]) {
value = patch[input.test_param.type](value);
}
-
+
// add conditional value
add (job_input_id + '|' + input.test_param.name, input.id, value);
-
+
// identify selected case
var selectedCase = self.matchCase(input, value);
if (selectedCase != -1) {
@@ -116,22 +116,17 @@
// get field
var field = self.app.field_list[input.id];
if (field && field.value) {
+ // validate field value
+ var value = field.value();
+ if (field.validate && !field.validate()) {
+ value = null;
+ }
+
// get and patch field value
- var value = field.value();
if (patch[input.type]) {
value = patch[input.type](value);
}
- // validate field value
- if (field.skip) {
- continue;
- }
-
- // validate field value
- if (field.validate && !field.validate()) {
- value = null;
- }
-
// ignore certain values
if (input.ignore === undefined || (value !== null && input.ignore != value)) {
// add value to submission
@@ -149,20 +144,20 @@
}
}
}
-
+
// start conversion
convert('', dict);
-
+
// return result
return result_dict;
},
-
+
/** Match job definition identifier to input element identifier
*/
match: function (job_input_id) {
return this.map_dict && this.map_dict[job_input_id];
},
-
+
/** Match conditional values to selected cases
*/
matchCase: function(input, value) {
@@ -174,27 +169,27 @@
value = input.test_param.falsevalue || 'false';
}
}
-
+
// find selected case
for (var i in input.cases) {
if (input.cases[i].value == value) {
return i;
}
}
-
+
// selected case not found
return -1;
},
-
+
/** Matches identifier from api model to input elements
*/
matchModel: function(model, callback) {
// final result dictionary
var result = {};
-
+
// link this
var self = this;
-
+
// search throughout response
function search (id, head) {
for (var i in head) {
@@ -224,23 +219,23 @@
}
}
}
-
+
// match all ids and return messages
search('', model.inputs);
// return matched results
return result;
},
-
+
/** Matches identifier from api response to input elements
*/
matchResponse: function(response) {
// final result dictionary
var result = {};
-
+
// link this
var self = this;
-
+
// search throughout response
function search (id, head) {
if (typeof head === 'string') {
@@ -262,14 +257,14 @@
}
}
}
-
+
// match all ids and return messages
search('', response);
-
+
// return matched results
return result;
},
-
+
/** Iterate through the tool form dom and map it to the dictionary.
*/
_iterate: function(parent, dict) {
@@ -279,15 +274,15 @@
children.each(function() {
// get child element
var child = this;
-
+
// get id
var id = $(child).attr('id');
-
+
// create new branch
if ($(child).hasClass('section-row')) {
// create sub dictionary
dict[id] = {};
-
+
// add input element if it exists
var input = self.app.input_list[id];
if (input) {
@@ -295,7 +290,7 @@
input : input
}
}
-
+
// fill sub dictionary
self._iterate(child, dict[id]);
} else {
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 client/galaxy/scripts/utils/metrics-logger.js
--- a/client/galaxy/scripts/utils/metrics-logger.js
+++ b/client/galaxy/scripts/utils/metrics-logger.js
@@ -34,7 +34,7 @@
var self = this;
///** get the current user's id from bootstrapped data or options */
- self.userId = window.bootstrapped? window.bootstrapped.user.id: null;
+ self.userId = ( window.bootstrapped && window.bootstrapped.user )? window.bootstrapped.user.id: null;
self.userId = self.userId || options.userId || null;
/** the (optional) console to emit logs to */
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 config/plugins/visualizations/scatterplot/package.json
--- a/config/plugins/visualizations/scatterplot/package.json
+++ b/config/plugins/visualizations/scatterplot/package.json
@@ -16,8 +16,8 @@
"devDependencies": {
"grunt": "~0.4.1",
"grunt-cli": "~0.1.9",
- "grunt-contrib-handlebars": "~0.5.10",
"grunt-contrib-concat": "~0.3.0",
+ "grunt-contrib-handlebars": "^0.9.3",
"grunt-contrib-uglify": "~0.2.2",
"grunt-contrib-watch": "~0.5.3"
}
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 config/plugins/visualizations/scatterplot/static/scatterplot-edit.js
--- a/config/plugins/visualizations/scatterplot/static/scatterplot-edit.js
+++ b/config/plugins/visualizations/scatterplot/static/scatterplot-edit.js
@@ -1,1 +1,1 @@
-function scatterplot(a,b,c){function d(){var a={v:{},h:{}};return a.v.lines=p.selectAll("line.v-grid-line").data(m.x.ticks(q.x.fn.ticks()[0])),a.v.lines.enter().append("svg:line").classed("grid-line v-grid-line",!0),a.v.lines.attr("x1",m.x).attr("x2",m.x).attr("y1",0).attr("y2",b.height),a.v.lines.exit().remove(),a.h.lines=p.selectAll("line.h-grid-line").data(m.y.ticks(q.y.fn.ticks()[0])),a.h.lines.enter().append("svg:line").classed("grid-line h-grid-line",!0),a.h.lines.attr("x1",0).attr("x2",b.width).attr("y1",m.y).attr("y2",m.y),a.h.lines.exit().remove(),a}function e(){return t.attr("cx",function(a,b){return m.x(j(a,b))}).attr("cy",function(a,b){return m.y(k(a,b))}).style("display","block").filter(function(){var a=d3.select(this).attr("cx"),c=d3.select(this).attr("cy");return 0>a||a>b.width?!0:0>c||c>b.height?!0:!1}).style("display","none")}function f(){$(".chart-info-box").remove(),q.redraw(),e(),s=d(),$(o.node()).trigger("zoom.scatterplot",{scale:n.scale(),translate:n.translate()})}function g(a,c,d){return c+=8,$(['<div class="chart-info-box" style="position: absolute">',void 0!==b.idColumn?"<div>"+d[b.idColumn]+"</div>":"","<div>",j(d),"</div>","<div>",k(d),"</div>","</div>"].join("")).css({top:a,left:c,"z-index":2})}var h=function(a,b){return"translate("+a+","+b+")"},i=function(a,b,c){return"rotate("+a+","+b+","+c+")"},j=function(a){return a[b.xColumn]},k=function(a){return a[b.yColumn]},l={x:{extent:d3.extent(c,j)},y:{extent:d3.extent(c,k)}},m={x:d3.scale.linear().domain(l.x.extent).range([0,b.width]),y:d3.scale.linear().domain(l.y.extent).range([b.height,0])},n=d3.behavior.zoom().x(m.x).y(m.y).scaleExtent([1,30]).scale(b.scale||1).translate(b.translate||[0,0]),o=d3.select(a).attr("class","scatterplot").attr("width","100%").attr("height",b.height+(b.margin.top+b.margin.bottom)),p=o.append("g").attr("class","content").attr("transform",h(b.margin.left,b.margin.top)).call(n);p.append("rect").attr("class","zoom-rect").attr("width",b.width).attr("height",b.height).style("fill","transparent");var q={x:{},y:{}};q.x.fn=d3.svg.axis().orient("bottom").scale(m.x).ticks(b.xTicks).tickFormat(d3.format("s")),q.y.fn=d3.svg.axis().orient("left").scale(m.y).ticks(b.yTicks).tickFormat(d3.format("s")),q.x.g=p.append("g").attr("class","x axis").attr("transform",h(0,b.height)).call(q.x.fn),q.y.g=p.append("g").attr("class","y axis").call(q.y.fn);var r=6;q.x.label=o.append("text").attr("id","x-axis-label").attr("class","axis-label").text(b.xLabel).attr("text-anchor","middle").attr("dominant-baseline","text-after-edge").attr("x",b.width/2+b.margin.left).attr("y",b.height+b.margin.bottom+b.margin.top-r),q.y.label=o.append("text").attr("id","y-axis-label").attr("class","axis-label").text(b.yLabel).attr("text-anchor","middle").attr("dominant-baseline","text-before-edge").attr("x",r).attr("y",b.height/2).attr("transform",i(-90,r,b.height/2)),q.redraw=function(){o.select(".x.axis").call(q.x.fn),o.select(".y.axis").call(q.y.fn)};var s=d(),t=p.selectAll(".glyph").data(c).enter().append("svg:circle").classed("glyph",!0).attr("cx",function(a,b){return m.x(j(a,b))}).attr("cy",function(a,b){return m.y(k(a,b))}).attr("r",0);t.transition().duration(b.animDuration).attr("r",b.datapointSize),e(),n.on("zoom",f),t.on("mouseover",function(a,c){var d=d3.select(this);d.classed("highlight",!0).style("fill","red").style("fill-opacity",1),p.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",d.attr("cx")-b.datapointSize).attr("y1",d.attr("cy")).attr("x2",0).attr("y2",d.attr("cy")).classed("hoverline",!0),d.attr("cy")<b.height&&p.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",d.attr("cx")).attr("y1",+d.attr("cy")+b.datapointSize).attr("x2",d.attr("cx")).attr("y2",b.height).classed("hoverline",!0);var e=this.getBoundingClientRect();$("body").append(g(e.top,e.right,a)),$(o.node()).trigger("mouseover-datapoint.scatterplot",[this,a,c])}),t.on("mouseout",function(){d3.select(this).classed("highlight",!1).style("fill","black").style("fill-opacity",.2),p.selectAll(".hoverline").remove(),$(".chart-info-box").remove()})}this.scatterplot=this.scatterplot||{},this.scatterplot.chartcontrol=Handlebars.template(function(a,b,c,d,e){this.compilerInfo=[4,">= 1.0.0"],c=this.merge(c,a.helpers),e=e||{};var f,g="",h="function",i=this.escapeExpression;return g+='<p class="help-text">\n Use the following controls to how the chart is displayed.\n The slide controls can be moved by the mouse or, if the \'handle\' is in focus, your keyboard\'s arrow keys.\n Move the focus between controls by using the tab or shift+tab keys on your keyboard.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n</p>\n\n<div data-config-key="datapointSize" class="form-input numeric-slider-input">\n <label for="datapointSize">Size of data point: </label>\n <div class="slider-output">',(f=c.datapointSize)?f=f.call(b,{hash:{},data:e}):(f=b.datapointSize,f=typeof f===h?f.apply(b):f),g+=i(f)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n Size of the graphic representation of each data point\n </p>\n</div>\n\n<div data-config-key="width" class="form-input numeric-slider-input">\n <label for="width">Chart width: </label>\n <div class="slider-output">',(f=c.width)?f=f.call(b,{hash:{},data:e}):(f=b.width,f=typeof f===h?f.apply(b):f),g+=i(f)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart margins and axes)\n </p>\n</div>\n\n<div data-config-key="height" class="form-input numeric-slider-input">\n <label for="height">Chart height: </label>\n <div class="slider-output">',(f=c.height)?f=f.call(b,{hash:{},data:e}):(f=b.height,f=typeof f===h?f.apply(b):f),g+=i(f)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart margins and axes)\n </p>\n</div>\n\n<div data-config-key="X-axis-label"class="text-input form-input">\n <label for="X-axis-label">Re-label the X axis: </label>\n <input type="text" name="X-axis-label" id="X-axis-label" value="',(f=c.xLabel)?f=f.call(b,{hash:{},data:e}):(f=b.xLabel,f=typeof f===h?f.apply(b):f),g+=i(f)+'" />\n <p class="form-help help-text-small"></p>\n</div>\n\n<div data-config-key="Y-axis-label" class="text-input form-input">\n <label for="Y-axis-label">Re-label the Y axis: </label>\n <input type="text" name="Y-axis-label" id="Y-axis-label" value="',(f=c.yLabel)?f=f.call(b,{hash:{},data:e}):(f=b.yLabel,f=typeof f===h?f.apply(b):f),g+=i(f)+'" />\n <p class="form-help help-text-small"></p>\n</div>\n\n<button class="render-button btn btn-primary active">Draw</button>\n'}),this.scatterplot.datacontrol=Handlebars.template(function(a,b,c,d,e){this.compilerInfo=[4,">= 1.0.0"],c=this.merge(c,a.helpers),e=e||{};var f,g="",h="function";return g+='<p class="help-text">\n Use the following control to change which columns are used by the chart. Click any cell\n from the last three rows of the table to select the column for the appropriate data.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n</p>\n\n<ul class="help-text" style="margin-left: 8px">\n <li><b>X Column</b>: which column values will be used for the x axis of the chart.</li>\n <li><b>Y Column</b>: which column values will be used for the y axis of the chart.</li>\n <li><b>ID Column</b>: an additional column value displayed when the user hovers over a data point.\n It may be useful to select unique or categorical identifiers here (such as gene ids).\n </li>\n</ul>\n\n<div class="column-selection">\n <pre class="peek">',(f=c.peek)?f=f.call(b,{hash:{},data:e}):(f=b.peek,f=typeof f===h?f.apply(b):f),(f||0===f)&&(g+=f),g+='</pre>\n</div>\n\n<p class="help-text help-text-small">\n <b>Note</b>: If it can be determined from the dataset\'s filetype that a column is not numeric,\n that column choice may be disabled for either the x or y axis.\n</p>\n\n<button class="render-button btn btn-primary active">Draw</button>\n'}),this.scatterplot.editor=Handlebars.template(function(a,b,c,d,e){this.compilerInfo=[4,">= 1.0.0"],c=this.merge(c,a.helpers),e=e||{};var f="";return f+='<div class="scatterplot-editor tabbable tabs-left">\n \n <ul class="nav nav-tabs">\n \n <li class="active">\n <a title="Use this tab to change which data are used"\n href="#data-control" data-toggle="tab">Data Controls</a>\n </li>\n <li>\n <a title="Use this tab to change how the chart is drawn"\n href="#chart-control" data-toggle="tab" >Chart Controls</a>\n </li>\n \n <li class="disabled">\n <a title="This tab will display the chart"\n href="#chart-display" data-toggle="tab">Chart</a>\n </li>\n \n <li class="file-controls">\n<!-- <button class="copy-btn btn btn-default"\n title="Save this as a new visualization">Save to new</button>-->\n <button class="save-btn btn btn-default">Save</button>\n </li>\n </ul>\n\n \n <div class="tab-content">\n \n <div id="data-control" class="scatterplot-config-control tab-pane active">\n \n </div>\n \n \n <div id="chart-control" class="scatterplot-config-control tab-pane">\n \n </div>\n\n \n <div id="chart-display" class="scatterplot-display tab-pane"></div>\n\n </div>\n</div>\n'});var ScatterplotConfigEditor=Backbone.View.extend({className:"scatterplot-control-form",initialize:function(a){if(this.model||(this.model=new Visualization({type:"scatterplot"})),!a||!a.dataset)throw new Error("ScatterplotConfigEditor requires a dataset");this.dataset=a.dataset,this.display=new ScatterplotDisplay({dataset:a.dataset,model:this.model})},render:function(){this.$el.empty().append(ScatterplotConfigEditor.templates.mainLayout({})),this.model.id&&(this.$el.find(".copy-btn").show(),this.$el.find(".save-btn").text("Update saved")),this.$el.find("[title]").tooltip(),this._render_dataControl(),this._render_chartControls(),this._render_chartDisplay();var a=this.model.get("config");return this.model.id&&_.isFinite(a.xColumn)&&_.isFinite(a.yColumn)&&this.renderChart(),this},_getColumnIndecesByType:function(){var a={numeric:[],text:[],all:[]};return _.each(this.dataset.metadata_column_types||[],function(b,c){"int"===b||"float"===b?a.numeric.push(c):("str"===b||"list"===b)&&a.text.push(c),a.all.push(c)}),a.numeric.length<2&&(a.numeric=[]),a},_render_dataControl:function(a){a=a||this.$el;var b=this,c=this.model.get("config"),d=this._getColumnIndecesByType(),e=a.find(".tab-pane#data-control");return e.html(ScatterplotConfigEditor.templates.dataControl({peek:this.dataset.peek})),e.find(".peek").peekColumnSelector({controls:[{label:"X Column",id:"xColumn",selected:c.xColumn,disabled:d.text},{label:"Y Column",id:"yColumn",selected:c.yColumn,disabled:d.text},{label:"ID Column",id:"idColumn",selected:c.idColumn}]}).on("peek-column-selector.change",function(a,c){b.model.set("config",c)}).on("peek-column-selector.rename",function(){}),e.find("[title]").tooltip(),e},_render_chartControls:function(a){function b(){var a=$(this),b=a.slider("value");c.model.set("config",_.object([[a.parent().data("config-key"),b]])),a.siblings(".slider-output").text(b)}a=a||this.$el;var c=this,d=this.model.get("config"),e=a.find("#chart-control");e.html(ScatterplotConfigEditor.templates.chartControl(d));var f={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};e.find(".numeric-slider-input").each(function(){var a=$(this),c=a.attr("data-config-key"),e=_.extend(f[c],{value:d[c],change:b,slide:b});a.find(".slider").slider(e),a.children(".slider-output").text(d[c])});var g=this.dataset.metadata_column_names||[],h=d.xLabel||g[d.xColumn]||"X",i=d.yLabel||g[d.yColumn]||"Y";return e.find('input[name="X-axis-label"]').val(h).on("change",function(){c.model.set("config",{xLabel:$(this).val()})}),e.find('input[name="Y-axis-label"]').val(i).on("change",function(){c.model.set("config",{yLabel:$(this).val()})}),e.find("[title]").tooltip(),e},_render_chartDisplay:function(a){a=a||this.$el;var b=a.find(".tab-pane#chart-display");return this.display.setElement(b),this.display.render(),b.find("[title]").tooltip(),b},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","click #data-control .render-button":"renderChart","click #chart-control .render-button":"renderChart","click .save-btn":"saveVisualization"},saveVisualization:function(){var a=this;this.model.save().fail(function(b,c,d){console.error(b,c,d),a.trigger("save:error",view),alert("Error loading data:\n"+b.responseText)}).then(function(){a.display.render()})},toggleThirdColumnSelector:function(){this.$el.find('select[name="idColumn"]').parent().toggle()},renderChart:function(){this.$el.find(".nav li.disabled").removeClass("disabled"),this.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show"),this.display.fetchData()},toString:function(){return"ScatterplotConfigEditor("+(this.dataset?this.dataset.id:"")+")"}});ScatterplotConfigEditor.templates={mainLayout:scatterplot.editor,dataControl:scatterplot.datacontrol,chartControl:scatterplot.chartcontrol};var ScatterplotDisplay=Backbone.View.extend({initialize:function(a){this.data=null,this.dataset=a.dataset,this.lineCount=this.dataset.metadata_data_lines||null},fetchData:function(){this.showLoadingIndicator();var a=this,b=this.model.get("config"),c=jQuery.getJSON("/api/datasets/"+this.dataset.id,{data_type:"raw_data",provider:"dataset-column",limit:b.pagination.perPage,offset:b.pagination.currPage*b.pagination.perPage});return c.done(function(b){a.data=b.data,a.trigger("data:fetched",a),a.renderData()}),c.fail(function(b,c,d){console.error(b,c,d),a.trigger("data:error",a),alert("Error loading data:\n"+b.responseText)}),c},showLoadingIndicator:function(){this.$el.find(".scatterplot-data-info").html(['<div class="loading-indicator">','<span class="fa fa-spinner fa-spin"></span>','<span class="loading-indicator-message">loading...</span>',"</div>"].join(""))},template:function(){var a=['<div class="controls clear">','<div class="right">','<p class="scatterplot-data-info"></p>','<button class="stats-toggle-btn">Stats</button>','<button class="rerender-btn">Redraw</button>',"</div>",'<div class="left">','<div class="page-control"></div>',"</div>","</div>","<svg/>",'<div class="stats-display"></div>'].join("");return a},render:function(){return this.$el.addClass("scatterplot-display").html(this.template()),this.data&&this.renderData(),this},renderData:function(){this.renderLeftControls(),this.renderRightControls(),this.renderPlot(this.data),this.getStats()},renderLeftControls:function(){var a=this,b=this.model.get("config");return this.$el.find(".controls .left .page-control").pagination({startingPage:b.pagination.currPage,perPage:b.pagination.perPage,totalDataSize:this.lineCount,currDataSize:this.data.length}).off().on("pagination.page-change",function(c,d){b.pagination.currPage=d,a.model.set("config",{pagination:b.pagination}),a.resetZoom(),a.fetchData()}),this},renderRightControls:function(){var a=this;this.setLineInfo(this.data),this.$el.find(".stats-toggle-btn").off().click(function(){a.toggleStats()}),this.$el.find(".rerender-btn").off().click(function(){a.resetZoom(),a.renderPlot(this.data)})},renderPlot:function(){var a=this,b=this.$el.find("svg");this.toggleStats(!1),b.off().empty().show().on("zoom.scatterplot",function(b,c){a.model.set("config",c)}),scatterplot(b.get(0),this.model.get("config"),this.data)},setLineInfo:function(a,b){if(a){var c=this.model.get("config"),d=this.lineCount||"an unknown total",e=c.pagination.currPage*c.pagination.perPage,f=e+a.length;this.$el.find(".controls p.scatterplot-data-info").text([e+1,"to",f,"of",d].join(" "))}else this.$el.find(".controls p.scatterplot-data-info").html(b||"");return this},resetZoom:function(a,b){return a=void 0!==a?a:1,b=void 0!==b?b:[0,0],this.model.set("config",{scale:a,translate:b}),this},getStats:function(){if(this.data){var a=this,b=this.model.get("config"),c=new Worker("/plugins/visualizations/scatterplot/static/worker-stats.js");c.postMessage({data:this.data,keys:[b.xColumn,b.yColumn]}),c.onerror=function(){c.terminate()},c.onmessage=function(b){a.renderStats(b.data)}}},renderStats:function(a){var b=this.model.get("config"),c=this.$el.find(".stats-display"),d=b.xLabel,e=b.yLabel,f=$("<table/>").addClass("table").append(["<thead><th></th><th>",d,"</th><th>",e,"</th></thead>"].join("")).append(_.map(a,function(a,b){return $(["<tr><td>",b,"</td><td>",a[0],"</td><td>",a[1],"</td></tr>"].join(""))}));c.empty().append(f)},toggleStats:function(a){var b=this.$el.find(".stats-display");a=void 0===a?b.is(":hidden"):a,a?(this.$el.find("svg").hide(),b.show(),this.$el.find(".controls .stats-toggle-btn").text("Plot")):(b.hide(),this.$el.find("svg").show(),this.$el.find(".controls .stats-toggle-btn").text("Stats"))},toString:function(){return"ScatterplotView()"}}),ScatterplotModel=Visualization.extend({defaults:{type:"scatterplot",config:{pagination:{currPage:0,perPage:3e3},width:400,height:400,margin:{top:16,right:16,bottom:40,left:54},xTicks:10,xLabel:"X",yTicks:10,yLabel:"Y",datapointSize:4,animDuration:500,scale:1,translate:[0,0]}}});
\ No newline at end of file
+function scatterplot(a,b,c){function d(){var a={v:{},h:{}};return a.v.lines=p.selectAll("line.v-grid-line").data(m.x.ticks(q.x.fn.ticks()[0])),a.v.lines.enter().append("svg:line").classed("grid-line v-grid-line",!0),a.v.lines.attr("x1",m.x).attr("x2",m.x).attr("y1",0).attr("y2",b.height),a.v.lines.exit().remove(),a.h.lines=p.selectAll("line.h-grid-line").data(m.y.ticks(q.y.fn.ticks()[0])),a.h.lines.enter().append("svg:line").classed("grid-line h-grid-line",!0),a.h.lines.attr("x1",0).attr("x2",b.width).attr("y1",m.y).attr("y2",m.y),a.h.lines.exit().remove(),a}function e(){return t.attr("cx",function(a,b){return m.x(j(a,b))}).attr("cy",function(a,b){return m.y(k(a,b))}).style("display","block").filter(function(){var a=d3.select(this).attr("cx"),c=d3.select(this).attr("cy");return 0>a||a>b.width?!0:0>c||c>b.height?!0:!1}).style("display","none")}function f(){$(".chart-info-box").remove(),q.redraw(),e(),s=d(),$(o.node()).trigger("zoom.scatterplot",{scale:n.scale(),translate:n.translate()})}function g(a,c,d){return c+=8,$(['<div class="chart-info-box" style="position: absolute">',void 0!==b.idColumn?"<div>"+d[b.idColumn]+"</div>":"","<div>",j(d),"</div>","<div>",k(d),"</div>","</div>"].join("")).css({top:a,left:c,"z-index":2})}var h=function(a,b){return"translate("+a+","+b+")"},i=function(a,b,c){return"rotate("+a+","+b+","+c+")"},j=function(a){return a[b.xColumn]},k=function(a){return a[b.yColumn]},l={x:{extent:d3.extent(c,j)},y:{extent:d3.extent(c,k)}},m={x:d3.scale.linear().domain(l.x.extent).range([0,b.width]),y:d3.scale.linear().domain(l.y.extent).range([b.height,0])},n=d3.behavior.zoom().x(m.x).y(m.y).scaleExtent([1,30]).scale(b.scale||1).translate(b.translate||[0,0]),o=d3.select(a).attr("class","scatterplot").attr("width","100%").attr("height",b.height+(b.margin.top+b.margin.bottom)),p=o.append("g").attr("class","content").attr("transform",h(b.margin.left,b.margin.top)).call(n);p.append("rect").attr("class","zoom-rect").attr("width",b.width).attr("height",b.height).style("fill","transparent");var q={x:{},y:{}};q.x.fn=d3.svg.axis().orient("bottom").scale(m.x).ticks(b.xTicks).tickFormat(d3.format("s")),q.y.fn=d3.svg.axis().orient("left").scale(m.y).ticks(b.yTicks).tickFormat(d3.format("s")),q.x.g=p.append("g").attr("class","x axis").attr("transform",h(0,b.height)).call(q.x.fn),q.y.g=p.append("g").attr("class","y axis").call(q.y.fn);var r=6;q.x.label=o.append("text").attr("id","x-axis-label").attr("class","axis-label").text(b.xLabel).attr("text-anchor","middle").attr("dominant-baseline","text-after-edge").attr("x",b.width/2+b.margin.left).attr("y",b.height+b.margin.bottom+b.margin.top-r),q.y.label=o.append("text").attr("id","y-axis-label").attr("class","axis-label").text(b.yLabel).attr("text-anchor","middle").attr("dominant-baseline","text-before-edge").attr("x",r).attr("y",b.height/2).attr("transform",i(-90,r,b.height/2)),q.redraw=function(){o.select(".x.axis").call(q.x.fn),o.select(".y.axis").call(q.y.fn)};var s=d(),t=p.selectAll(".glyph").data(c).enter().append("svg:circle").classed("glyph",!0).attr("cx",function(a,b){return m.x(j(a,b))}).attr("cy",function(a,b){return m.y(k(a,b))}).attr("r",0);t.transition().duration(b.animDuration).attr("r",b.datapointSize),e(),n.on("zoom",f),t.on("mouseover",function(a,c){var d=d3.select(this);d.classed("highlight",!0).style("fill","red").style("fill-opacity",1),p.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",d.attr("cx")-b.datapointSize).attr("y1",d.attr("cy")).attr("x2",0).attr("y2",d.attr("cy")).classed("hoverline",!0),d.attr("cy")<b.height&&p.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",d.attr("cx")).attr("y1",+d.attr("cy")+b.datapointSize).attr("x2",d.attr("cx")).attr("y2",b.height).classed("hoverline",!0);var e=this.getBoundingClientRect();$("body").append(g(e.top,e.right,a)),$(o.node()).trigger("mouseover-datapoint.scatterplot",[this,a,c])}),t.on("mouseout",function(){d3.select(this).classed("highlight",!1).style("fill","black").style("fill-opacity",.2),p.selectAll(".hoverline").remove(),$(".chart-info-box").remove()})}this.scatterplot=this.scatterplot||{},this.scatterplot.chartcontrol=Handlebars.template({compiler:[6,">= 2.0.0-beta.1"],main:function(a,b,c,d){var e,f="function",g=b.helperMissing,h=this.escapeExpression;return'<p class="help-text">\n Use the following controls to how the chart is displayed.\n The slide controls can be moved by the mouse or, if the \'handle\' is in focus, your keyboard\'s arrow keys.\n Move the focus between controls by using the tab or shift+tab keys on your keyboard.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n</p>\n\n<div data-config-key="datapointSize" class="form-input numeric-slider-input">\n <label for="datapointSize">Size of data point: </label>\n <div class="slider-output">'+h((e=null!=(e=b.datapointSize||(null!=a?a.datapointSize:a))?e:g,typeof e===f?e.call(a,{name:"datapointSize",hash:{},data:d}):e))+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n Size of the graphic representation of each data point\n </p>\n</div>\n\n<div data-config-key="width" class="form-input numeric-slider-input">\n <label for="width">Chart width: </label>\n <div class="slider-output">'+h((e=null!=(e=b.width||(null!=a?a.width:a))?e:g,typeof e===f?e.call(a,{name:"width",hash:{},data:d}):e))+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart margins and axes)\n </p>\n</div>\n\n<div data-config-key="height" class="form-input numeric-slider-input">\n <label for="height">Chart height: </label>\n <div class="slider-output">'+h((e=null!=(e=b.height||(null!=a?a.height:a))?e:g,typeof e===f?e.call(a,{name:"height",hash:{},data:d}):e))+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart margins and axes)\n </p>\n</div>\n\n<div data-config-key="X-axis-label"class="text-input form-input">\n <label for="X-axis-label">Re-label the X axis: </label>\n <input type="text" name="X-axis-label" id="X-axis-label" value="'+h((e=null!=(e=b.xLabel||(null!=a?a.xLabel:a))?e:g,typeof e===f?e.call(a,{name:"xLabel",hash:{},data:d}):e))+'" />\n <p class="form-help help-text-small"></p>\n</div>\n\n<div data-config-key="Y-axis-label" class="text-input form-input">\n <label for="Y-axis-label">Re-label the Y axis: </label>\n <input type="text" name="Y-axis-label" id="Y-axis-label" value="'+h((e=null!=(e=b.yLabel||(null!=a?a.yLabel:a))?e:g,typeof e===f?e.call(a,{name:"yLabel",hash:{},data:d}):e))+'" />\n <p class="form-help help-text-small"></p>\n</div>\n\n<button class="render-button btn btn-primary active">Draw</button>\n'},useData:!0}),this.scatterplot.datacontrol=Handlebars.template({compiler:[6,">= 2.0.0-beta.1"],main:function(a,b,c,d){var e,f,g="function",h=b.helperMissing,i='<p class="help-text">\n Use the following control to change which columns are used by the chart. Click any cell\n from the last three rows of the table to select the column for the appropriate data.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n</p>\n\n<ul class="help-text" style="margin-left: 8px">\n <li><b>X Column</b>: which column values will be used for the x axis of the chart.</li>\n <li><b>Y Column</b>: which column values will be used for the y axis of the chart.</li>\n <li><b>ID Column</b>: an additional column value displayed when the user hovers over a data point.\n It may be useful to select unique or categorical identifiers here (such as gene ids).\n </li>\n</ul>\n\n<div class="column-selection">\n <pre class="peek">';return f=null!=(f=b.peek||(null!=a?a.peek:a))?f:h,e=typeof f===g?f.call(a,{name:"peek",hash:{},data:d}):f,null!=e&&(i+=e),i+'</pre>\n</div>\n\n<p class="help-text help-text-small">\n <b>Note</b>: If it can be determined from the dataset\'s filetype that a column is not numeric,\n that column choice may be disabled for either the x or y axis.\n</p>\n\n<button class="render-button btn btn-primary active">Draw</button>\n'},useData:!0}),this.scatterplot.editor=Handlebars.template({compiler:[6,">= 2.0.0-beta.1"],main:function(){return'<div class="scatterplot-editor tabbable tabs-left">\n <ul class="nav nav-tabs">\n <li class="active">\n <a title="Use this tab to change which data are used"\n href="#data-control" data-toggle="tab">Data Controls</a>\n </li>\n <li>\n <a title="Use this tab to change how the chart is drawn"\n href="#chart-control" data-toggle="tab" >Chart Controls</a>\n </li>\n <li class="disabled">\n <a title="This tab will display the chart"\n href="#chart-display" data-toggle="tab">Chart</a>\n </li>\n <li class="file-controls">\n<!-- <button class="copy-btn btn btn-default"\n title="Save this as a new visualization">Save to new</button>-->\n <button class="save-btn btn btn-default">Save</button>\n </li>\n </ul>\n\n <div class="tab-content">\n <div id="data-control" class="scatterplot-config-control tab-pane active">\n </div>\n \n <div id="chart-control" class="scatterplot-config-control tab-pane">\n </div>\n\n <div id="chart-display" class="scatterplot-display tab-pane"></div>\n\n </div>\n</div>\n'},useData:!0});var ScatterplotConfigEditor=Backbone.View.extend({className:"scatterplot-control-form",initialize:function(a){if(this.model||(this.model=new Visualization({type:"scatterplot"})),!a||!a.dataset)throw new Error("ScatterplotConfigEditor requires a dataset");this.dataset=a.dataset,this.display=new ScatterplotDisplay({dataset:a.dataset,model:this.model})},render:function(){this.$el.empty().append(ScatterplotConfigEditor.templates.mainLayout({})),this.model.id&&(this.$el.find(".copy-btn").show(),this.$el.find(".save-btn").text("Update saved")),this.$el.find("[title]").tooltip(),this._render_dataControl(),this._render_chartControls(),this._render_chartDisplay();var a=this.model.get("config");return this.model.id&&_.isFinite(a.xColumn)&&_.isFinite(a.yColumn)&&this.renderChart(),this},_getColumnIndecesByType:function(){var a={numeric:[],text:[],all:[]};return _.each(this.dataset.metadata_column_types||[],function(b,c){"int"===b||"float"===b?a.numeric.push(c):("str"===b||"list"===b)&&a.text.push(c),a.all.push(c)}),a.numeric.length<2&&(a.numeric=[]),a},_render_dataControl:function(a){a=a||this.$el;var b=this,c=this.model.get("config"),d=this._getColumnIndecesByType(),e=a.find(".tab-pane#data-control");return e.html(ScatterplotConfigEditor.templates.dataControl({peek:this.dataset.peek})),e.find(".peek").peekColumnSelector({controls:[{label:"X Column",id:"xColumn",selected:c.xColumn,disabled:d.text},{label:"Y Column",id:"yColumn",selected:c.yColumn,disabled:d.text},{label:"ID Column",id:"idColumn",selected:c.idColumn}]}).on("peek-column-selector.change",function(a,c){b.model.set("config",c)}).on("peek-column-selector.rename",function(){}),e.find("[title]").tooltip(),e},_render_chartControls:function(a){function b(){var a=$(this),b=a.slider("value");c.model.set("config",_.object([[a.parent().data("config-key"),b]])),a.siblings(".slider-output").text(b)}a=a||this.$el;var c=this,d=this.model.get("config"),e=a.find("#chart-control");e.html(ScatterplotConfigEditor.templates.chartControl(d));var f={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};e.find(".numeric-slider-input").each(function(){var a=$(this),c=a.attr("data-config-key"),e=_.extend(f[c],{value:d[c],change:b,slide:b});a.find(".slider").slider(e),a.children(".slider-output").text(d[c])});var g=this.dataset.metadata_column_names||[],h=d.xLabel||g[d.xColumn]||"X",i=d.yLabel||g[d.yColumn]||"Y";return e.find('input[name="X-axis-label"]').val(h).on("change",function(){c.model.set("config",{xLabel:$(this).val()})}),e.find('input[name="Y-axis-label"]').val(i).on("change",function(){c.model.set("config",{yLabel:$(this).val()})}),e.find("[title]").tooltip(),e},_render_chartDisplay:function(a){a=a||this.$el;var b=a.find(".tab-pane#chart-display");return this.display.setElement(b),this.display.render(),b.find("[title]").tooltip(),b},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","click #data-control .render-button":"renderChart","click #chart-control .render-button":"renderChart","click .save-btn":"saveVisualization"},saveVisualization:function(){var a=this;this.model.save().fail(function(b,c,d){console.error(b,c,d),a.trigger("save:error",view),alert("Error loading data:\n"+b.responseText)}).then(function(){a.display.render()})},toggleThirdColumnSelector:function(){this.$el.find('select[name="idColumn"]').parent().toggle()},renderChart:function(){this.$el.find(".nav li.disabled").removeClass("disabled"),this.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show"),this.display.fetchData()},toString:function(){return"ScatterplotConfigEditor("+(this.dataset?this.dataset.id:"")+")"}});ScatterplotConfigEditor.templates={mainLayout:scatterplot.editor,dataControl:scatterplot.datacontrol,chartControl:scatterplot.chartcontrol};var ScatterplotDisplay=Backbone.View.extend({initialize:function(a){this.data=null,this.dataset=a.dataset,this.lineCount=this.dataset.metadata_data_lines||null},fetchData:function(){this.showLoadingIndicator();var a=this,b=this.model.get("config"),c=jQuery.getJSON("/api/datasets/"+this.dataset.id,{data_type:"raw_data",provider:"dataset-column",limit:b.pagination.perPage,offset:b.pagination.currPage*b.pagination.perPage});return c.done(function(b){a.data=b.data,a.trigger("data:fetched",a),a.renderData()}),c.fail(function(b,c,d){console.error(b,c,d),a.trigger("data:error",a),alert("Error loading data:\n"+b.responseText)}),c},showLoadingIndicator:function(){this.$el.find(".scatterplot-data-info").html(['<div class="loading-indicator">','<span class="fa fa-spinner fa-spin"></span>','<span class="loading-indicator-message">loading...</span>',"</div>"].join(""))},template:function(){var a=['<div class="controls clear">','<div class="right">','<p class="scatterplot-data-info"></p>','<button class="stats-toggle-btn">Stats</button>','<button class="rerender-btn">Redraw</button>',"</div>",'<div class="left">','<div class="page-control"></div>',"</div>","</div>","<svg/>",'<div class="stats-display"></div>'].join("");return a},render:function(){return this.$el.addClass("scatterplot-display").html(this.template()),this.data&&this.renderData(),this},renderData:function(){this.renderLeftControls(),this.renderRightControls(),this.renderPlot(this.data),this.getStats()},renderLeftControls:function(){var a=this,b=this.model.get("config");return this.$el.find(".controls .left .page-control").pagination({startingPage:b.pagination.currPage,perPage:b.pagination.perPage,totalDataSize:this.lineCount,currDataSize:this.data.length}).off().on("pagination.page-change",function(c,d){b.pagination.currPage=d,a.model.set("config",{pagination:b.pagination}),a.resetZoom(),a.fetchData()}),this},renderRightControls:function(){var a=this;this.setLineInfo(this.data),this.$el.find(".stats-toggle-btn").off().click(function(){a.toggleStats()}),this.$el.find(".rerender-btn").off().click(function(){a.resetZoom(),a.renderPlot(this.data)})},renderPlot:function(){var a=this,b=this.$el.find("svg");this.toggleStats(!1),b.off().empty().show().on("zoom.scatterplot",function(b,c){a.model.set("config",c)}),scatterplot(b.get(0),this.model.get("config"),this.data)},setLineInfo:function(a,b){if(a){var c=this.model.get("config"),d=this.lineCount||"an unknown total",e=c.pagination.currPage*c.pagination.perPage,f=e+a.length;this.$el.find(".controls p.scatterplot-data-info").text([e+1,"to",f,"of",d].join(" "))}else this.$el.find(".controls p.scatterplot-data-info").html(b||"");return this},resetZoom:function(a,b){return a=void 0!==a?a:1,b=void 0!==b?b:[0,0],this.model.set("config",{scale:a,translate:b}),this},getStats:function(){if(this.data){var a=this,b=this.model.get("config"),c=new Worker("/plugins/visualizations/scatterplot/static/worker-stats.js");c.postMessage({data:this.data,keys:[b.xColumn,b.yColumn]}),c.onerror=function(){c.terminate()},c.onmessage=function(b){a.renderStats(b.data)}}},renderStats:function(a){var b=this.model.get("config"),c=this.$el.find(".stats-display"),d=b.xLabel,e=b.yLabel,f=$("<table/>").addClass("table").append(["<thead><th></th><th>",d,"</th><th>",e,"</th></thead>"].join("")).append(_.map(a,function(a,b){return $(["<tr><td>",b,"</td><td>",a[0],"</td><td>",a[1],"</td></tr>"].join(""))}));c.empty().append(f)},toggleStats:function(a){var b=this.$el.find(".stats-display");a=void 0===a?b.is(":hidden"):a,a?(this.$el.find("svg").hide(),b.show(),this.$el.find(".controls .stats-toggle-btn").text("Plot")):(b.hide(),this.$el.find("svg").show(),this.$el.find(".controls .stats-toggle-btn").text("Stats"))},toString:function(){return"ScatterplotView()"}}),ScatterplotModel=Visualization.extend({defaults:{type:"scatterplot",config:{pagination:{currPage:0,perPage:3e3},width:400,height:400,margin:{top:16,right:16,bottom:40,left:54},xTicks:10,xLabel:"X",yTicks:10,yLabel:"Y",datapointSize:4,animDuration:500,scale:1,translate:[0,0]}}});
\ No newline at end of file
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 lib/galaxy/datatypes/dataproviders/column.py
--- a/lib/galaxy/datatypes/dataproviders/column.py
+++ b/lib/galaxy/datatypes/dataproviders/column.py
@@ -3,6 +3,9 @@
is further subdivided into multiple data (e.g. columns from a line).
"""
+import urllib
+import re
+
import line
_TODO = """
@@ -34,12 +37,13 @@
'column_count' : 'int',
'column_types' : 'list:str',
'parse_columns' : 'bool',
- 'deliminator' : 'str'
+ 'deliminator' : 'str',
+ 'filters' : 'list:str'
}
def __init__( self, source, indeces=None,
column_count=None, column_types=None, parsers=None, parse_columns=True,
- deliminator='\t', **kwargs ):
+ deliminator='\t', filters=None, **kwargs ):
"""
:param indeces: a list of indeces of columns to gather from each row
Optional: will default to `None`.
@@ -103,6 +107,104 @@
# overwrite with user desired parsers
self.parsers.update( parsers or {} )
+ filters = filters or []
+ self.column_filters = []
+ for filter_ in filters:
+ parsed = self.parse_filter( filter_ )
+ #TODO: might be better to error on bad filter/None here
+ if callable( parsed ):
+ self.column_filters.append( parsed )
+
+ def parse_filter( self, filter_param_str ):
+ split = filter_param_str.split( '-', 3 )
+ if not len( split ) == 3:
+ return None
+ column, op, val = split
+
+ # better checking v. len and indeces
+ column = int( column )
+ if column > len( self.column_types ):
+ return None
+ if self.column_types[ column ] in ( 'float', 'int' ):
+ return self.create_numeric_filter( column, op, val )
+ if self.column_types[ column ] in ( 'str' ):
+ return self.create_string_filter( column, op, val )
+ if self.column_types[ column ] in ( 'list' ):
+ return self.create_list_filter( column, op, val )
+ return None
+
+ def create_numeric_filter( self, column, op, val ):
+ """
+ Return an anonymous filter function that will be passed the array
+ of parsed columns. Return None if no filter function can be
+ created for the given params.
+
+ The function will compare the column at index `column` against `val`
+ using the given op where op is one of:
+ lt: less than, le: less than or equal to,
+ eq: equal to, ne: not equal to,
+ ge: greather than or equal to, gt: greater than
+
+ `val` is cast as float here and will return None if there's a parsing error.
+ """
+ try:
+ val = float( val )
+ except ValueError:
+ return None
+ if 'lt' == op:
+ return lambda d: d[column] < val
+ elif 'le' == op:
+ return lambda d: d[column] <= val
+ elif 'eq' == op:
+ return lambda d: d[column] == val
+ elif 'ne' == op:
+ return lambda d: d[column] != val
+ elif 'ge' == op:
+ return lambda d: d[column] >= val
+ elif 'gt' == op:
+ return lambda d: d[column] > val
+ return None
+
+ def create_string_filter( self, column, op, val ):
+ """
+ Return an anonymous filter function that will be passed the array
+ of parsed columns. Return None if no filter function can be
+ created for the given params.
+
+ The function will compare the column at index `column` against `val`
+ using the given op where op is one of:
+ eq: exactly matches,
+ has: the column contains the substring `val`,
+ re: the column matches the regular expression in `val`
+ """
+ if 'eq' == op:
+ return lambda d: d[column] == val
+ elif 'has' == op:
+ return lambda d: val in d[column]
+ elif 're' == op:
+ val = urllib.unquote_plus( val )
+ val = re.compile( val )
+ return lambda d: val.match( d[column] ) is not None
+ return None
+
+ def create_list_filter( self, column, op, val ):
+ """
+ Return an anonymous filter function that will be passed the array
+ of parsed columns. Return None if no filter function can be
+ created for the given params.
+
+ The function will compare the column at index `column` against `val`
+ using the given op where op is one of:
+ eq: the list `val` exactly matches the list in the column,
+ has: the list in the column contains the sublist `val`,
+ """
+ if 'eq' == op:
+ val = self.parse_value( val, 'list' )
+ return lambda d: d[column] == val
+ elif 'has' == op:
+ return lambda d: val in d[column]
+ return None
+
def get_default_parsers( self ):
"""
Return parser dictionary keyed for each columnar type
@@ -140,6 +242,39 @@
#'gffstrand': # -, +, ?, or '.' for None, etc.
}
+ def filter( self, line ):
+ line = super( ColumnarDataProvider, self ).filter( line )
+ if line == None:
+ return line
+ columns = self.parse_columns_from_line( line )
+ return self.filter_by_columns( columns )
+
+ def parse_columns_from_line( self, line ):
+ """
+ Returns a list of the desired, parsed columns.
+ :param line: the line to parse
+ :type line: str
+ """
+ #TODO: too much going on in this loop - the above should all be precomputed AMAP...
+ all_columns = line.split( self.deliminator )
+ # if no indeces were passed to init, return all columns
+ selected_indeces = self.selected_column_indeces or list( xrange( len( all_columns ) ) )
+ parsed_columns = []
+ for parser_index, column_index in enumerate( selected_indeces ):
+ parsed_columns.append( self.parse_column_at_index( all_columns, parser_index, column_index ) )
+ return parsed_columns
+
+ def parse_column_at_index( self, columns, parser_index, index ):
+ """
+ Get the column type for the parser from `self.column_types` or `None`
+ if the type is unavailable.
+ """
+ try:
+ return self.parse_value( columns[ index ], self.get_column_type( parser_index ) )
+ # if a selected index is not within columns, return None
+ except IndexError, index_err:
+ return None
+
def parse_value( self, val, type ):
"""
Attempt to parse and return the given value based on the given type.
@@ -173,51 +308,11 @@
except IndexError, ind_err:
return None
- def parse_column_at_index( self, columns, parser_index, index ):
- """
- Get the column type for the parser from `self.column_types` or `None`
- if the type is unavailable.
- """
- try:
- return self.parse_value( columns[ index ], self.get_column_type( parser_index ) )
- # if a selected index is not within columns, return None
- except IndexError, index_err:
- return None
-
- def parse_columns_from_line( self, line ):
- """
- Returns a list of the desired, parsed columns.
- :param line: the line to parse
- :type line: str
- """
- #TODO: too much going on in this loop - the above should all be precomputed AMAP...
- all_columns = line.split( self.deliminator )
- # if no indeces were passed to init, return all columns
- selected_indeces = self.selected_column_indeces or list( xrange( len( all_columns ) ) )
- parsed_columns = []
- for parser_index, column_index in enumerate( selected_indeces ):
- parsed_columns.append( self.parse_column_at_index( all_columns, parser_index, column_index ) )
- return parsed_columns
-
- def __iter__( self ):
- parent_gen = super( ColumnarDataProvider, self ).__iter__()
- for line in parent_gen:
- columns = self.parse_columns_from_line( line )
- yield columns
-
- #TODO: implement column filters here and not below - flatten hierarchy
-
-class FilteredByColumnDataProvider( ColumnarDataProvider ):
- """
- Data provider that provide a list of columns from the lines of its source
- _only_ if they pass a given filter function.
-
- e.g. column #3 is type int and > N
- """
- # TODO: how to do this and still have limit and offset work?
- def __init__( self, source, **kwargs ):
- raise NotImplementedError()
- super( FilteredByColumnDataProvider, self ).__init__( source, **kwargs )
+ def filter_by_columns( self, columns ):
+ for filter_fn in self.column_filters:
+ if not filter_fn( columns ):
+ return None
+ return columns
class DictDataProvider( ColumnarDataProvider ):
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 lib/galaxy/jobs/runners/util/cli/job/slurm.py
--- a/lib/galaxy/jobs/runners/util/cli/job/slurm.py
+++ b/lib/galaxy/jobs/runners/util/cli/job/slurm.py
@@ -7,7 +7,7 @@
except ImportError:
# Not in Galaxy, map Galaxy job states to Pulsar ones.
from galaxy.util import enum
- job_states = enum(RUNNING='running', OK='complete', QUEUED='queued')
+ job_states = enum(RUNNING='running', OK='complete', QUEUED='queued', ERROR="failed")
from ..job import BaseJobExec
@@ -59,10 +59,10 @@
return 'scancel %s' % job_id
def get_status(self, job_ids=None):
- return 'squeue -a -o \\"%A %t\\"'
+ return "squeue -a -o '%A %t'"
def get_single_status(self, job_id):
- return 'squeue -a -o \\"%A %t\\" -j ' + job_id
+ return "squeue -a -o '%A %t' -j " + job_id
def parse_status(self, status, job_ids):
# Get status for each job, skipping header.
@@ -80,6 +80,7 @@
# Job still on cluster and has state.
id, state = status[1].split()
return self._get_job_state(state)
+ # else line like "slurm_load_jobs error: Invalid job id specified"
return job_states.OK
def _get_job_state(self, state):
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 lib/galaxy/managers/users.py
--- a/lib/galaxy/managers/users.py
+++ b/lib/galaxy/managers/users.py
@@ -199,6 +199,42 @@
#TODO: use quota manager
return self.app.quota_agent.get_percent( user=user )
+ def tags_used( self, trans, user, tag_models=None ):
+ """
+ Return a list of distinct 'user_tname:user_value' strings that the
+ given user has used.
+ """
+ #TODO: simplify and unify with tag manager
+ if self.is_anonymous( user ):
+ return []
+
+ # get all the taggable model TagAssociations
+ if not tag_models:
+ tag_models = [ v.tag_assoc_class for v in self.app.tag_handler.item_tag_assoc_info.values() ]
+ # create a union of subqueries for each for this user - getting only the tname and user_value
+ all_tags_query = None
+ for tag_model in tag_models:
+ subq = ( self.app.model.context.query( tag_model.user_tname, tag_model.user_value )
+ .filter( tag_model.user == trans.user ) )
+ all_tags_query = subq if all_tags_query is None else all_tags_query.union( subq )
+
+ # if nothing init'd the query, bail
+ if all_tags_query is None:
+ return []
+
+ # boil the tag tuples down into a sorted list of DISTINCT name:val strings
+ tags = all_tags_query.distinct().all()
+ tags = [( ( name + ':' + val ) if val else name ) for name, val in tags ]
+ return sorted( tags )
+
+ def has_requests( self, trans, user ):
+ """
+ """
+ if self.is_anonymous( user ):
+ return False
+ request_types = self.app.security_agent.get_accessible_request_types( trans, user )
+ return ( user.requests or request_types )
+
class UserSerializer( base.ModelSerializer, deletable.PurgableSerializerMixin ):
@@ -214,21 +250,22 @@
'id', 'email', 'username'
])
self.add_view( 'detailed', [
- 'update_time',
- 'create_time',
-
- 'deleted',
- 'purged',
- 'active',
+ #'update_time',
+ #'create_time',
'total_disk_usage',
'nice_total_disk_usage',
'quota_percent'
- # 'preferences',
- # # all tags
- # 'tags',
- # # all annotations
- # 'annotations'
+
+ #'deleted',
+ #'purged',
+ #'active',
+
+ #'preferences',
+ # all tags
+ 'tags_used',
+ ## all annotations
+ #'annotations'
], include_keys_from='summary' )
def add_serializers( self ):
@@ -240,7 +277,13 @@
'create_time' : self.serialize_date,
'update_time' : self.serialize_date,
'is_admin' : lambda t, i, k: self.user_manager.is_admin( t, i ),
- 'quota_percent' : lambda t, i, k: self.user_manager.quota( t, i )
+
+ 'total_disk_usage' : lambda t, i, k: float( i.total_disk_usage ),
+ 'quota_percent' : lambda t, i, k: self.user_manager.quota( t, i ),
+
+ 'tags_used' : lambda t, i, k: self.user_manager.tags_used( t, i ),
+ #TODO: 'has_requests' is more apt
+ 'requests' : lambda t, i, k: self.user_manager.has_requests( t, i )
})
def serialize_current_anonymous_user( self, trans, user, keys ):
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -2250,13 +2250,12 @@
return tool_dict
- def to_json (self, trans, **kwd):
+ def to_json (self, trans, kwd={}, is_dynamic=True):
"""
Recursively creates a tool dictionary containing repeats, dynamic options and updated states.
"""
job_id = kwd.get('__job_id__', None)
dataset_id = kwd.get('__dataset_id__', None)
- is_dynamic = string_as_bool(kwd.get('__is_dynamic__', True))
# load job details if provided
job = None
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -1618,6 +1618,8 @@
return UnvalidatedValue( None )
initial_values = []
recurse_options( initial_values, self.get_options( trans=trans, other_values=context ) )
+ if len( initial_values ) == 0:
+ initial_values = None
return initial_values
def value_to_display_text( self, value, app ):
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 lib/galaxy/web/__init__.py
--- a/lib/galaxy/web/__init__.py
+++ b/lib/galaxy/web/__init__.py
@@ -19,6 +19,7 @@
from framework.decorators import _future_expose_api_raw
from framework.decorators import _future_expose_api_raw_anonymous
from framework.decorators import _future_expose_api_anonymous_and_sessionless
+from framework.decorators import _future_expose_api_raw_anonymous_and_sessionless
from framework.formbuilder import form
from framework.formbuilder import FormBuilder
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 lib/galaxy/web/framework/decorators.py
--- a/lib/galaxy/web/framework/decorators.py
+++ b/lib/galaxy/web/framework/decorators.py
@@ -344,3 +344,6 @@
def _future_expose_api_raw_anonymous( func ):
return _future_expose_api( func, to_json=False, user_required=False )
+
+def _future_expose_api_raw_anonymous_and_sessionless( func ):
+ return _future_expose_api( func, to_json=False, user_required=False, user_or_session_required=False )
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 lib/galaxy/webapps/galaxy/api/job_files.py
--- a/lib/galaxy/webapps/galaxy/api/job_files.py
+++ b/lib/galaxy/webapps/galaxy/api/job_files.py
@@ -8,8 +8,8 @@
from galaxy import util
from galaxy import model
from galaxy.web.base.controller import BaseAPIController
-from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous
-from galaxy.web import _future_expose_api_raw_anonymous as expose_api_raw_anonymous
+from galaxy.web import _future_expose_api_anonymous_and_sessionless as expose_api_anonymous_and_sessionless
+from galaxy.web import _future_expose_api_raw_anonymous_and_sessionless as expose_api_raw_anonymous_and_sessionless
import logging
@@ -28,7 +28,7 @@
security model for tool execution.
"""
- @expose_api_raw_anonymous
+ @expose_api_raw_anonymous_and_sessionless
def index( self, trans, job_id, **kwargs ):
"""
index( self, trans, job_id, **kwargs )
@@ -54,7 +54,7 @@
path = kwargs.get("path", None)
return open(path, 'rb')
- @expose_api_anonymous
+ @expose_api_anonymous_and_sessionless
def create( self, trans, job_id, payload, **kwargs ):
"""
create( self, trans, job_id, payload, **kwargs )
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -76,14 +76,10 @@
GET /api/tools/{tool_id}/build
Returns a tool model including dynamic parameters and updated values, repeats block etc.
"""
- tool_id = urllib.unquote_plus( id )
tool_version = kwd.get( 'tool_version', None )
- tool = self.app.toolbox.get_tool( tool_id, tool_version )
- if not tool:
- trans.response.status = 500
- return { 'error': 'Could not find tool with id \'%s\'' % tool_id }
- return tool.to_json(trans, **kwd)
-
+ tool = self._get_tool( id, tool_version=tool_version, user=trans.user )
+ return tool.to_json(trans, kwd)
+
@_future_expose_api
@web.require_admin
def reload( self, trans, tool_id, **kwd ):
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -6,6 +6,8 @@
import uuid
import logging
+import copy
+import urllib
from sqlalchemy import desc, or_, and_
from galaxy import exceptions, util
from galaxy.model.item_attrs import UsesAnnotations
@@ -17,6 +19,7 @@
from galaxy.workflow.extract import extract_workflow
from galaxy.workflow.run import invoke, queue_invoke
from galaxy.workflow.run_request import build_workflow_run_config
+from galaxy.workflow.modules import module_factory
log = logging.getLogger(__name__)
@@ -305,6 +308,52 @@
raise exceptions.RequestParameterInvalidException( message )
return self.workflow_contents_manager.workflow_to_dict( trans, stored_workflow, style="instance" )
+ @expose_api
+ def build_module( self, trans, payload={}):
+ """
+ POST /api/workflows/build_module
+ Builds module details including a tool model for the workflow editor.
+ """
+ tool_id = payload.get( 'tool_id', None )
+ tool_version = payload.get( 'tool_version', None )
+ tool_inputs = payload.get( 'inputs', None )
+ annotation = payload.get( 'annotation', '' )
+
+ # load tool
+ tool = self._get_tool( tool_id, tool_version=tool_version, user=trans.user )
+
+ # initialize module
+ trans.workflow_building_mode = True
+ module = module_factory.from_dict( trans, {
+ 'type' : 'tool',
+ 'tool_id' : tool.id,
+ 'tool_state' : None
+ } )
+
+ # create tool model and default tool state (if missing)
+ tool_model = module.tool.to_json(trans, tool_inputs, is_dynamic=False)
+ module.state.inputs = copy.deepcopy(tool_model['state_inputs'])
+ return {
+ 'tool_model' : tool_model,
+ 'tool_state' : module.get_state(),
+ 'data_inputs' : module.get_data_inputs(),
+ 'data_outputs' : module.get_data_outputs(),
+ 'tool_errors' : module.get_errors(),
+ 'form_html' : module.get_config_form(),
+ 'annotation' : annotation,
+ 'post_job_actions' : module.get_post_job_actions(tool_inputs)
+ }
+
+ #
+ # -- Helper methods --
+ #
+ def _get_tool( self, id, tool_version=None, user=None ):
+ id = urllib.unquote_plus( id )
+ tool = self.app.toolbox.get_tool( id, tool_version )
+ if not tool or not tool.allow_user_access( user ):
+ raise exceptions.ObjectNotFound("Could not find tool with id '%s'" % id)
+ return tool
+
def __api_import_new_workflow( self, trans, payload, **kwd ):
data = payload['workflow']
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 lib/galaxy/webapps/galaxy/buildapp.py
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -217,6 +217,7 @@
webapp.mapper.resource_with_deleted( 'user', 'users', path_prefix='/api' )
webapp.mapper.resource( 'genome', 'genomes', path_prefix='/api' )
webapp.mapper.resource( 'visualization', 'visualizations', path_prefix='/api' )
+ webapp.mapper.connect( '/api/workflows/build_module', action='build_module', controller="workflows" )
webapp.mapper.resource( 'workflow', 'workflows', path_prefix='/api' )
webapp.mapper.resource_with_deleted( 'history', 'histories', path_prefix='/api' )
webapp.mapper.connect( '/api/histories/{history_id}/citations', action='citations', controller="histories" )
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -609,7 +609,6 @@
This is used for the form shown in the right pane when a node
is selected.
"""
-
tool_state = incoming.pop('tool_state', None)
trans.workflow_building_mode = True
module = module_factory.from_dict( trans, {
@@ -617,22 +616,7 @@
'tool_id': tool_id,
'tool_state': tool_state
} )
-
- # create tool model and default tool state (if missing)
- if type == 'tool' and not tool_state:
- tool_model = module.tool.to_json(trans, **incoming)
- module.state.inputs = copy.deepcopy(tool_model['state_inputs'])
- return {
- 'tool_model': tool_model,
- 'tool_state': module.get_state(),
- 'data_inputs': module.get_data_inputs(),
- 'data_outputs': module.get_data_outputs(),
- 'tool_errors': module.get_errors(),
- 'form_html': module.get_config_form(),
- 'annotation': annotation,
- 'post_job_actions': module.get_post_job_actions(incoming)
- }
-
+
# update module state
module.update_state( incoming )
@@ -669,7 +653,8 @@
module = module_factory.new( trans, type, **kwargs )
tool_model = None
if type == 'tool':
- tool_model = module.tool.to_json(trans)
+ tool_model = module.tool.to_json(trans, is_dynamic=False)
+ module.state.inputs = copy.deepcopy(tool_model['state_inputs'])
return {
'type': module.type,
'name': module.get_name(),
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 static/scripts/mvc/tools/tools-form-workflow.js
--- a/static/scripts/mvc/tools/tools-form-workflow.js
+++ b/static/scripts/mvc/tools/tools-form-workflow.js
@@ -275,10 +275,16 @@
/** Request a new model for an already created tool form and updates the form inputs
*/
_updateModel: function() {
+ // link self
+ var self = this;
+
// create the request dictionary
- var self = this;
- var current_state = this.tree.finalize();
-
+ var current_state = {
+ tool_id : this.options.id,
+ tool_version : this.options.version,
+ inputs : this.tree.finalize()
+ }
+
// log tool state
console.debug('tools-form-workflow::_refreshForm() - Refreshing states.');
console.debug(current_state);
@@ -287,11 +293,11 @@
var process_id = this.deferred.register();
// build model url for request
- var model_url = galaxy_config.root + 'workflow/editor_form_post?tool_id=' + this.options.id + '&__is_dynamic__=False';
+ var model_url = galaxy_config.root + 'api/workflows/build_module';
// post job
Utils.request({
- type : 'GET',
+ type : 'POST',
url : model_url,
data : current_state,
success : function(data) {
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 static/scripts/mvc/tools/tools-input.js
--- a/static/scripts/mvc/tools/tools-input.js
+++ b/static/scripts/mvc/tools/tools-input.js
@@ -34,8 +34,7 @@
this.field.skip = false;
var v = this.field.value && this.field.value();
this.field.skip = Boolean(options.optional &&
- ((this.default_value === undefined) ||
- ((this.field.validate && !this.field.validate()) || !v ||
+ (((this.field.validate && !this.field.validate()) || !v ||
(v == this.default_value) || (Number(v) == Number(this.default_value)) ||
(JSON.stringify(v) == JSON.stringify(this.default_value)))));
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 static/scripts/mvc/tools/tools-section.js
--- a/static/scripts/mvc/tools/tools-section.js
+++ b/static/scripts/mvc/tools/tools-section.js
@@ -294,17 +294,20 @@
// get id
var id = input_def.id;
+ // add regular/default value if missing
+ if (input_def.value === undefined) {
+ input_def.value = null;
+ }
+ if (input_def.default_value === undefined) {
+ input_def.default_value = input_def.value;
+ }
+
// create input field
var field = this._createField(input_def);
// add to field list
this.app.field_list[id] = field;
- // fix default value if missing
- if (input_def.default_value === undefined) {
- input_def.default_value = input_def.value;
- }
-
// create input field wrapper
var input_element = new InputElement(this.app, {
label : input_def.label,
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 static/scripts/mvc/tools/tools-tree.js
--- a/static/scripts/mvc/tools/tools-tree.js
+++ b/static/scripts/mvc/tools/tools-tree.js
@@ -10,13 +10,13 @@
initialize: function(app) {
this.app = app;
},
-
+
/** Convert dictionary representation into tool api specific flat dictionary format.
*/
finalize: function(patch) {
// link this
var self = this;
-
+
// dictionary with api specific identifiers
this.map_dict = {};
@@ -24,24 +24,24 @@
if (!this.app.section) {
return {};
}
-
+
// ensure that dictionary with patching functions exists
patch = patch || {};
-
+
// dictionary formatted for job submission or tool form update
var result_dict = {};
// prepare full dictionary
var dict = {};
-
+
// fill dictionary from dom
this._iterate(this.app.section.$el, dict);
-
+
// add identifier and value to job definition
function add(job_input_id, input_id, input_value) {
// add entry to result dictionary
result_dict[job_input_id] = input_value;
-
+
// backup id mapping
self.map_dict[job_input_id] = input_id;
};
@@ -53,21 +53,21 @@
if (node.input) {
// get node
var input = node.input;
-
+
// create identifier
var job_input_id = identifier;
if (identifier != '') {
job_input_id += '|';
}
job_input_id += input.name;
-
+
// process input type
switch (input.type) {
// handle repeats
case 'repeat':
// section identifier
var section_label = 'section-';
-
+
// collect repeat block identifiers
var block_indices = [];
var block_prefix = null;
@@ -81,10 +81,10 @@
}
}
}
-
+
// sort repeat blocks
block_indices.sort(function(a,b) { return a - b; });
-
+
// add to response dictionary in created order
var index = 0;
for (var i in block_indices) {
@@ -98,10 +98,10 @@
if (patch[input.test_param.type]) {
value = patch[input.test_param.type](value);
}
-
+
// add conditional value
add (job_input_id + '|' + input.test_param.name, input.id, value);
-
+
// identify selected case
var selectedCase = self.matchCase(input, value);
if (selectedCase != -1) {
@@ -116,22 +116,17 @@
// get field
var field = self.app.field_list[input.id];
if (field && field.value) {
+ // validate field value
+ var value = field.value();
+ if (field.validate && !field.validate()) {
+ value = null;
+ }
+
// get and patch field value
- var value = field.value();
if (patch[input.type]) {
value = patch[input.type](value);
}
- // validate field value
- if (field.skip) {
- continue;
- }
-
- // validate field value
- if (field.validate && !field.validate()) {
- value = null;
- }
-
// ignore certain values
if (input.ignore === undefined || (value !== null && input.ignore != value)) {
// add value to submission
@@ -149,20 +144,20 @@
}
}
}
-
+
// start conversion
convert('', dict);
-
+
// return result
return result_dict;
},
-
+
/** Match job definition identifier to input element identifier
*/
match: function (job_input_id) {
return this.map_dict && this.map_dict[job_input_id];
},
-
+
/** Match conditional values to selected cases
*/
matchCase: function(input, value) {
@@ -174,27 +169,27 @@
value = input.test_param.falsevalue || 'false';
}
}
-
+
// find selected case
for (var i in input.cases) {
if (input.cases[i].value == value) {
return i;
}
}
-
+
// selected case not found
return -1;
},
-
+
/** Matches identifier from api model to input elements
*/
matchModel: function(model, callback) {
// final result dictionary
var result = {};
-
+
// link this
var self = this;
-
+
// search throughout response
function search (id, head) {
for (var i in head) {
@@ -224,23 +219,23 @@
}
}
}
-
+
// match all ids and return messages
search('', model.inputs);
// return matched results
return result;
},
-
+
/** Matches identifier from api response to input elements
*/
matchResponse: function(response) {
// final result dictionary
var result = {};
-
+
// link this
var self = this;
-
+
// search throughout response
function search (id, head) {
if (typeof head === 'string') {
@@ -262,14 +257,14 @@
}
}
}
-
+
// match all ids and return messages
search('', response);
-
+
// return matched results
return result;
},
-
+
/** Iterate through the tool form dom and map it to the dictionary.
*/
_iterate: function(parent, dict) {
@@ -279,15 +274,15 @@
children.each(function() {
// get child element
var child = this;
-
+
// get id
var id = $(child).attr('id');
-
+
// create new branch
if ($(child).hasClass('section-row')) {
// create sub dictionary
dict[id] = {};
-
+
// add input element if it exists
var input = self.app.input_list[id];
if (input) {
@@ -295,7 +290,7 @@
input : input
}
}
-
+
// fill sub dictionary
self._iterate(child, dict[id]);
} else {
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 static/scripts/packed/mvc/tools/tools-form-workflow.js
--- a/static/scripts/packed/mvc/tools/tools-form-workflow.js
+++ b/static/scripts/packed/mvc/tools/tools-form-workflow.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/tools/tools-form-base"],function(b,a){var c=a.extend({initialize:function(e){this.node=workflow.active_node;if(!this.node){console.debug("FAILED - tools-form-workflow:initialize() - Node not found in workflow.");return}this.post_job_actions=this.node.post_job_actions||{};this.options=e;this.options.text_enable="In Advance";this.options.text_disable="At Runtime";this.options.is_dynamic=false;this.options.narrow=true;this.options.initial_errors=true;this.options.cls_portlet="ui-portlet-narrow";b.deepeach(e.inputs,function(f){if(f.type){f.optional=(["data","data_hidden","hidden","drill_down","repeat","conditional"]).indexOf(f.type)==-1}});b.deepeach(e.inputs,function(f){if(f.type){if(f.type=="conditional"){f.test_param.optional=false}}});var d=this;b.get({url:galaxy_config.root+"api/datatypes",cache:true,success:function(f){d.datatypes=f;d._makeSections(e.inputs);a.prototype.initialize.call(d,e)}})},_makeSections:function(d){d[b.uuid()]={label:"Annotation / Notes",name:"annotation",type:"text",area:true,help:"Add an annotation or note for this step. It will be shown with the workflow.",value:this.node.annotation};var f=this.node.output_terminals&&Object.keys(this.node.output_terminals)[0];if(f){d[b.uuid()]={name:"pja__"+f+"__EmailAction",label:"Email notification",type:"boolean",value:String(Boolean(this.post_job_actions["EmailAction"+f])),ignore:"false",help:"An email notification will be send when the job has completed.",payload:{host:window.location.host}};d[b.uuid()]={name:"pja__"+f+"__DeleteIntermediatesAction",label:"Output cleanup",type:"boolean",value:String(Boolean(this.post_job_actions["DeleteIntermediatesAction"+f])),ignore:"false",help:"Delete intermediate outputs if they are not used as input for another job."};for(var e in this.node.output_terminals){d[b.uuid()]=this._makeSection(e)}}},_makeSection:function(h){var g=[];for(key in this.datatypes){g.push({0:this.datatypes[key],1:this.datatypes[key]})}g.sort(function(j,i){return j.label>i.label?1:j.label<i.label?-1:0});g.unshift({0:"Sequences",1:"Sequences"});g.unshift({0:"Roadmaps",1:"Roadmaps"});g.unshift({0:"Leave unchanged",1:""});var f={label:"Add Actions: '"+h+"'",type:"section",inputs:[{action:"RenameDatasetAction",argument:"newname",label:"Rename dataset",type:"text",value:"",ignore:"",help:'This action will rename the result dataset. Click <a href="https://wiki.galaxyproject.org/Learn/AdvancedWorkflow/Variables">here</a> for more information.'},{action:"ChangeDatatypeAction",argument:"newtype",label:"Change datatype",type:"select",ignore:"",options:g,help:"This action will change the datatype of the output to the indicated value."},{action:"TagDatasetAction",argument:"tags",label:"Tags",type:"text",value:"",ignore:"",help:"This action will set tags for the dataset."},{label:"Assign columns",type:"section",inputs:[{action:"ColumnSetAction",argument:"chromCol",label:"Chrom column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"startCol",label:"Start column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"endCol",label:"End column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"strandCol",label:"Strand column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"nameCol",label:"Name column",type:"integer",value:"",ignore:""}],help:"This action will set column assignments in the output dataset. Blank fields are ignored."}]};var d=this;function e(n,o){o=o||[];o.push(n);for(var m in n.inputs){var k=n.inputs[m];if(k.action){k.name="pja__"+h+"__"+k.action;if(k.argument){k.name+="__"+k.argument}if(k.payload){for(var s in k.payload){var q=k.payload[s];k.payload[k.name+"__"+s]=q;delete q}}var r=d.post_job_actions[k.action+h];if(r){for(var l in o){o[l].expand=true}if(k.argument){k.value=r.action_arguments&&r.action_arguments[k.argument]||k.value}else{k.value="true"}}}if(k.inputs){e(k,o.slice(0))}}}e(f);return f},_buildModel:function(){Galaxy.modal.show({title:"Coming soon...",body:"This feature has not been implemented yet.",buttons:{Close:function(){Galaxy.modal.hide()}}})},_updateModel:function(){var d=this;var e=this.tree.finalize();console.debug("tools-form-workflow::_refreshForm() - Refreshing states.");console.debug(e);var g=this.deferred.register();var f=galaxy_config.root+"workflow/editor_form_post?tool_id="+this.options.id+"&__is_dynamic__=False";b.request({type:"GET",url:f,data:e,success:function(h){d.node.update_field_data(h);d._errors(h&&h.tool_model);d.deferred.done(g);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(h)},error:function(h){d.deferred.done(g);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(h)}})}});return{View:c}});
\ No newline at end of file
+define(["utils/utils","mvc/tools/tools-form-base"],function(b,a){var c=a.extend({initialize:function(e){this.node=workflow.active_node;if(!this.node){console.debug("FAILED - tools-form-workflow:initialize() - Node not found in workflow.");return}this.post_job_actions=this.node.post_job_actions||{};this.options=e;this.options.text_enable="In Advance";this.options.text_disable="At Runtime";this.options.is_dynamic=false;this.options.narrow=true;this.options.initial_errors=true;this.options.cls_portlet="ui-portlet-narrow";b.deepeach(e.inputs,function(f){if(f.type){f.optional=(["data","data_hidden","hidden","drill_down","repeat","conditional"]).indexOf(f.type)==-1}});b.deepeach(e.inputs,function(f){if(f.type){if(f.type=="conditional"){f.test_param.optional=false}}});var d=this;b.get({url:galaxy_config.root+"api/datatypes",cache:true,success:function(f){d.datatypes=f;d._makeSections(e.inputs);a.prototype.initialize.call(d,e)}})},_makeSections:function(d){d[b.uuid()]={label:"Annotation / Notes",name:"annotation",type:"text",area:true,help:"Add an annotation or note for this step. It will be shown with the workflow.",value:this.node.annotation};var f=this.node.output_terminals&&Object.keys(this.node.output_terminals)[0];if(f){d[b.uuid()]={name:"pja__"+f+"__EmailAction",label:"Email notification",type:"boolean",value:String(Boolean(this.post_job_actions["EmailAction"+f])),ignore:"false",help:"An email notification will be send when the job has completed.",payload:{host:window.location.host}};d[b.uuid()]={name:"pja__"+f+"__DeleteIntermediatesAction",label:"Output cleanup",type:"boolean",value:String(Boolean(this.post_job_actions["DeleteIntermediatesAction"+f])),ignore:"false",help:"Delete intermediate outputs if they are not used as input for another job."};for(var e in this.node.output_terminals){d[b.uuid()]=this._makeSection(e)}}},_makeSection:function(h){var g=[];for(key in this.datatypes){g.push({0:this.datatypes[key],1:this.datatypes[key]})}g.sort(function(j,i){return j.label>i.label?1:j.label<i.label?-1:0});g.unshift({0:"Sequences",1:"Sequences"});g.unshift({0:"Roadmaps",1:"Roadmaps"});g.unshift({0:"Leave unchanged",1:""});var f={label:"Add Actions: '"+h+"'",type:"section",inputs:[{action:"RenameDatasetAction",argument:"newname",label:"Rename dataset",type:"text",value:"",ignore:"",help:'This action will rename the result dataset. Click <a href="https://wiki.galaxyproject.org/Learn/AdvancedWorkflow/Variables">here</a> for more information.'},{action:"ChangeDatatypeAction",argument:"newtype",label:"Change datatype",type:"select",ignore:"",options:g,help:"This action will change the datatype of the output to the indicated value."},{action:"TagDatasetAction",argument:"tags",label:"Tags",type:"text",value:"",ignore:"",help:"This action will set tags for the dataset."},{label:"Assign columns",type:"section",inputs:[{action:"ColumnSetAction",argument:"chromCol",label:"Chrom column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"startCol",label:"Start column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"endCol",label:"End column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"strandCol",label:"Strand column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"nameCol",label:"Name column",type:"integer",value:"",ignore:""}],help:"This action will set column assignments in the output dataset. Blank fields are ignored."}]};var d=this;function e(n,o){o=o||[];o.push(n);for(var m in n.inputs){var k=n.inputs[m];if(k.action){k.name="pja__"+h+"__"+k.action;if(k.argument){k.name+="__"+k.argument}if(k.payload){for(var s in k.payload){var q=k.payload[s];k.payload[k.name+"__"+s]=q;delete q}}var r=d.post_job_actions[k.action+h];if(r){for(var l in o){o[l].expand=true}if(k.argument){k.value=r.action_arguments&&r.action_arguments[k.argument]||k.value}else{k.value="true"}}}if(k.inputs){e(k,o.slice(0))}}}e(f);return f},_buildModel:function(){Galaxy.modal.show({title:"Coming soon...",body:"This feature has not been implemented yet.",buttons:{Close:function(){Galaxy.modal.hide()}}})},_updateModel:function(){var d=this;var e={tool_id:this.options.id,tool_version:this.options.version,inputs:this.tree.finalize()};console.debug("tools-form-workflow::_refreshForm() - Refreshing states.");console.debug(e);var g=this.deferred.register();var f=galaxy_config.root+"api/workflows/build_module";b.request({type:"POST",url:f,data:e,success:function(h){d.node.update_field_data(h);d._errors(h&&h.tool_model);d.deferred.done(g);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(h)},error:function(h){d.deferred.done(g);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(h)}})}});return{View:c}});
\ No newline at end of file
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 static/scripts/packed/mvc/tools/tools-input.js
--- a/static/scripts/packed/mvc/tools/tools-input.js
+++ b/static/scripts/packed/mvc/tools/tools-input.js
@@ -1,1 +1,1 @@
-define([],function(){return Backbone.View.extend({initialize:function(d,c){this.app=d;this.text_enable=d.options.text_enable||"Enable";this.text_disable=d.options.text_disable||"Disable";this.field=c.field;this.default_value=c.default_value;this.setElement(this._template(c));this.$field=this.$el.find(".ui-table-form-field");this.$title_optional=this.$el.find(".ui-table-form-title-optional");this.$error_text=this.$el.find(".ui-table-form-error-text");this.$error=this.$el.find(".ui-table-form-error");this.$field.prepend(this.field.$el);this.field.skip=false;var b=this.field.value&&this.field.value();this.field.skip=Boolean(c.optional&&((this.default_value===undefined)||((this.field.validate&&!this.field.validate())||!b||(b==this.default_value)||(Number(b)==Number(this.default_value))||(JSON.stringify(b)==JSON.stringify(this.default_value)))));this._refresh();var a=this;this.$title_optional.on("click",function(){a.field.skip=!a.field.skip;a._refresh()})},error:function(a){this.$error_text.html(a);this.$error.show();this.$el.addClass("ui-error")},reset:function(){this.$error.hide();this.$el.removeClass("ui-error")},_refresh:function(){if(!this.field.skip){this.$field.fadeIn("fast");this.$title_optional.html(this.text_disable)}else{this.reset();this.$field.hide();this.$title_optional.html(this.text_enable);this.field.value&&this.field.value(this.default_value)}this.app.trigger("refresh")},_template:function(a){var b='<div class="ui-table-form-element"><div class="ui-table-form-error ui-error"><span class="fa fa-arrow-down"/><span class="ui-table-form-error-text"/></div><div class="ui-table-form-title-strong">';if(a.optional){b+=a.label+'<span> [<span class="ui-table-form-title-optional"/>]</span>'}else{b+=a.label}b+='</div><div class="ui-table-form-field">';if(a.help){b+='<div class="ui-table-form-info">'+a.help+"</div>"}b+="</div></div>";return b}})});
\ No newline at end of file
+define([],function(){return Backbone.View.extend({initialize:function(d,c){this.app=d;this.text_enable=d.options.text_enable||"Enable";this.text_disable=d.options.text_disable||"Disable";this.field=c.field;this.default_value=c.default_value;this.setElement(this._template(c));this.$field=this.$el.find(".ui-table-form-field");this.$title_optional=this.$el.find(".ui-table-form-title-optional");this.$error_text=this.$el.find(".ui-table-form-error-text");this.$error=this.$el.find(".ui-table-form-error");this.$field.prepend(this.field.$el);this.field.skip=false;var b=this.field.value&&this.field.value();this.field.skip=Boolean(c.optional&&(((this.field.validate&&!this.field.validate())||!b||(b==this.default_value)||(Number(b)==Number(this.default_value))||(JSON.stringify(b)==JSON.stringify(this.default_value)))));this._refresh();var a=this;this.$title_optional.on("click",function(){a.field.skip=!a.field.skip;a._refresh()})},error:function(a){this.$error_text.html(a);this.$error.show();this.$el.addClass("ui-error")},reset:function(){this.$error.hide();this.$el.removeClass("ui-error")},_refresh:function(){if(!this.field.skip){this.$field.fadeIn("fast");this.$title_optional.html(this.text_disable)}else{this.reset();this.$field.hide();this.$title_optional.html(this.text_enable);this.field.value&&this.field.value(this.default_value)}this.app.trigger("refresh")},_template:function(a){var b='<div class="ui-table-form-element"><div class="ui-table-form-error ui-error"><span class="fa fa-arrow-down"/><span class="ui-table-form-error-text"/></div><div class="ui-table-form-title-strong">';if(a.optional){b+=a.label+'<span> [<span class="ui-table-form-title-optional"/>]</span>'}else{b+=a.label}b+='</div><div class="ui-table-form-field">';if(a.help){b+='<div class="ui-table-form-info">'+a.help+"</div>"}b+="</div></div>";return b}})});
\ No newline at end of file
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 static/scripts/packed/mvc/tools/tools-section.js
--- a/static/scripts/packed/mvc/tools/tools-section.js
+++ b/static/scripts/packed/mvc/tools/tools-section.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/ui/ui-portlet","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(e,b,h,d,c,a,f){var g=Backbone.View.extend({initialize:function(j,i){this.app=j;this.inputs=i.inputs;i.cls="ui-table-plain";i.cls_tr="section-row";this.table=new b.View(i);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var j in this.inputs){this.add(this.inputs[j])}},add:function(k){var j=this;var i=jQuery.extend(true,{},k);i.id=k.id=e.uuid();this.app.input_list[i.id]=i;var l=i.type;switch(l){case"conditional":this._addConditional(i);break;case"repeat":this._addRepeat(i);break;case"section":this._addSection(i);break;default:this._addRow(i)}},_addConditional:function(j){var k=this;j.test_param.id=j.id;var n=this._addRow(j.test_param);n.options.onchange=function(w){var v=k.app.tree.matchCase(j,w);for(var u in j.cases){var q=j.cases[u];var t=j.id+"-section-"+u;var p=k.table.get(t);var s=false;for(var r in q.inputs){if(!q.inputs[r].hidden){s=true;break}}if(u==v&&s){p.fadeIn("fast")}else{p.hide()}}k.app.trigger("refresh")};for(var m in j.cases){var l=j.id+"-section-"+m;var o=new g(this.app,{inputs:j.cases[m].inputs});o.$el.addClass("ui-table-section");this.table.add(o.$el);this.table.append(l)}n.trigger("change")},_addRepeat:function(p){var s=this;var q=0;var l=new c.View({title:p.title,title_new:p.title,min:p.min,max:p.max,onnew:function(){n(p.inputs);s.app.trigger("refresh")}});function n(i){var t=p.id+"-section-"+(q++);var u=new g(s.app,{inputs:i});l.add({id:t,$el:u.$el,ondel:function(){l.del(t);s.app.trigger("refresh")}})}var j=p.min;var r=_.size(p.cache);for(var m=0;m<Math.max(r,j);m++){var o=null;if(m<r){o=p.cache[m]}else{o=p.inputs}n(o)}var k=new f(this.app,{label:p.title,help:p.help,field:l});this.table.add(k.$el);this.table.append(p.id)},_addSection:function(i){var j=this;var n=new g(j.app,{inputs:i.inputs});var m=new h.ButtonIcon({icon:"fa-eye-slash",tooltip:"Show/hide section",cls:"ui-button-icon-plain"});var l=new d.View({title:i.label,cls:"ui-portlet-section",operations:{button_visible:m}});l.append(n.$el);l.append($("<div/>").addClass("ui-table-form-info").html(i.help));var k=false;l.$content.hide();l.$header.css("cursor","pointer");l.$header.on("click",function(){if(k){k=false;l.$content.hide();m.setIcon("fa-eye-slash")}else{k=true;l.$content.fadeIn("fast");m.setIcon("fa-eye")}});if(i.expand){l.$header.trigger("click")}this.table.add(l.$el);this.table.append(i.id)},_addRow:function(i){var l=i.id;var j=this._createField(i);this.app.field_list[l]=j;if(i.default_value===undefined){i.default_value=i.value}var k=new f(this.app,{label:i.label,default_value:i.default_value,optional:i.optional,help:i.help,field:j});this.app.element_list[l]=k;this.table.add(k.$el);this.table.append(l);if(i.hidden){this.table.get(l).hide()}return j},_createField:function(i){var j=null;switch(i.type){case"text":j=this._fieldText(i);break;case"select":j=this._fieldSelect(i);break;case"data":j=this._fieldData(i);break;case"data_collection":j=this._fieldData(i);break;case"data_column":i.error_text="Missing columns in referenced dataset.";j=this._fieldSelect(i);break;case"hidden":j=this._fieldHidden(i);break;case"hidden_data":j=this._fieldHidden(i);break;case"integer":j=this._fieldSlider(i);break;case"float":j=this._fieldSlider(i);break;case"boolean":j=this._fieldBoolean(i);break;case"genomebuild":i.searchable=true;j=this._fieldSelect(i);break;case"drill_down":j=this._fieldDrilldown(i);break;case"baseurl":j=this._fieldHidden(i);break;default:this.app.incompatible=true;if(i.options){j=this._fieldSelect(i)}else{j=this._fieldText(i)}console.debug("tools-form::_addRow() : Auto matched field type ("+i.type+").")}if(i.value!==undefined){j.value(i.value)}return j},_fieldData:function(i){if(!this.app.options.is_dynamic){i.info="Data input '"+i.name+"' ("+e.textify(i.extensions.toString())+")";i.value=null;return this._fieldHidden(i)}var j=this;return new a.View(this.app,{id:"field-"+i.id,extensions:i.extensions,optional:i.optional,multiple:i.multiple,type:i.type,data:i.options,onchange:function(){j.app.trigger("refresh")}})},_fieldSelect:function(j){if(!this.app.options.is_dynamic&&j.is_dynamic){return this._fieldText(j)}var l=[];for(var m in j.options){var n=j.options[m];l.push({label:n[0],value:n[1]})}var o=h.Select;switch(j.display){case"checkboxes":o=h.Checkbox;break;case"radio":o=h.Radio;break}var k=this;return new o.View({id:"field-"+j.id,data:l,error_text:j.error_text||"No options available",multiple:j.multiple,searchable:j.searchable,onchange:function(){k.app.trigger("refresh")}})},_fieldDrilldown:function(i){if(!this.app.options.is_dynamic&&i.is_dynamic){return this._fieldText(i)}var j=this;return new h.Drilldown.View({id:"field-"+i.id,data:i.options,display:i.display,onchange:function(){j.app.trigger("refresh")}})},_fieldText:function(i){if(i.options){i.area=i.multiple;if(!e.validate(i.value)){i.value=""}else{if(i.value instanceof Array){i.value=value.toString()}else{i.value=String(i.value).replace(/[\[\]'"\s]/g,"");if(i.multiple){i.value=i.value.replace(/,/g,"\n")}}}}var j=this;return new h.Input({id:"field-"+i.id,area:i.area,onchange:function(){j.app.trigger("refresh")}})},_fieldSlider:function(i){var j=this;return new h.Slider.View({id:"field-"+i.id,precise:i.type=="float",min:i.min,max:i.max,onchange:function(){j.app.trigger("refresh")}})},_fieldHidden:function(i){return new h.Hidden({id:"field-"+i.id,info:i.info})},_fieldBoolean:function(i){var j=this;return new h.RadioButton.View({id:"field-"+i.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}],onchange:function(){j.app.trigger("refresh")}})}});return{View:g}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/ui/ui-portlet","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(e,b,h,d,c,a,f){var g=Backbone.View.extend({initialize:function(j,i){this.app=j;this.inputs=i.inputs;i.cls="ui-table-plain";i.cls_tr="section-row";this.table=new b.View(i);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var j in this.inputs){this.add(this.inputs[j])}},add:function(k){var j=this;var i=jQuery.extend(true,{},k);i.id=k.id=e.uuid();this.app.input_list[i.id]=i;var l=i.type;switch(l){case"conditional":this._addConditional(i);break;case"repeat":this._addRepeat(i);break;case"section":this._addSection(i);break;default:this._addRow(i)}},_addConditional:function(j){var k=this;j.test_param.id=j.id;var n=this._addRow(j.test_param);n.options.onchange=function(w){var v=k.app.tree.matchCase(j,w);for(var u in j.cases){var q=j.cases[u];var t=j.id+"-section-"+u;var p=k.table.get(t);var s=false;for(var r in q.inputs){if(!q.inputs[r].hidden){s=true;break}}if(u==v&&s){p.fadeIn("fast")}else{p.hide()}}k.app.trigger("refresh")};for(var m in j.cases){var l=j.id+"-section-"+m;var o=new g(this.app,{inputs:j.cases[m].inputs});o.$el.addClass("ui-table-section");this.table.add(o.$el);this.table.append(l)}n.trigger("change")},_addRepeat:function(p){var s=this;var q=0;var l=new c.View({title:p.title,title_new:p.title,min:p.min,max:p.max,onnew:function(){n(p.inputs);s.app.trigger("refresh")}});function n(i){var t=p.id+"-section-"+(q++);var u=new g(s.app,{inputs:i});l.add({id:t,$el:u.$el,ondel:function(){l.del(t);s.app.trigger("refresh")}})}var j=p.min;var r=_.size(p.cache);for(var m=0;m<Math.max(r,j);m++){var o=null;if(m<r){o=p.cache[m]}else{o=p.inputs}n(o)}var k=new f(this.app,{label:p.title,help:p.help,field:l});this.table.add(k.$el);this.table.append(p.id)},_addSection:function(i){var j=this;var n=new g(j.app,{inputs:i.inputs});var m=new h.ButtonIcon({icon:"fa-eye-slash",tooltip:"Show/hide section",cls:"ui-button-icon-plain"});var l=new d.View({title:i.label,cls:"ui-portlet-section",operations:{button_visible:m}});l.append(n.$el);l.append($("<div/>").addClass("ui-table-form-info").html(i.help));var k=false;l.$content.hide();l.$header.css("cursor","pointer");l.$header.on("click",function(){if(k){k=false;l.$content.hide();m.setIcon("fa-eye-slash")}else{k=true;l.$content.fadeIn("fast");m.setIcon("fa-eye")}});if(i.expand){l.$header.trigger("click")}this.table.add(l.$el);this.table.append(i.id)},_addRow:function(i){var l=i.id;if(i.value===undefined){i.value=null}if(i.default_value===undefined){i.default_value=i.value}var j=this._createField(i);this.app.field_list[l]=j;var k=new f(this.app,{label:i.label,default_value:i.default_value,optional:i.optional,help:i.help,field:j});this.app.element_list[l]=k;this.table.add(k.$el);this.table.append(l);if(i.hidden){this.table.get(l).hide()}return j},_createField:function(i){var j=null;switch(i.type){case"text":j=this._fieldText(i);break;case"select":j=this._fieldSelect(i);break;case"data":j=this._fieldData(i);break;case"data_collection":j=this._fieldData(i);break;case"data_column":i.error_text="Missing columns in referenced dataset.";j=this._fieldSelect(i);break;case"hidden":j=this._fieldHidden(i);break;case"hidden_data":j=this._fieldHidden(i);break;case"integer":j=this._fieldSlider(i);break;case"float":j=this._fieldSlider(i);break;case"boolean":j=this._fieldBoolean(i);break;case"genomebuild":i.searchable=true;j=this._fieldSelect(i);break;case"drill_down":j=this._fieldDrilldown(i);break;case"baseurl":j=this._fieldHidden(i);break;default:this.app.incompatible=true;if(i.options){j=this._fieldSelect(i)}else{j=this._fieldText(i)}console.debug("tools-form::_addRow() : Auto matched field type ("+i.type+").")}if(i.value!==undefined){j.value(i.value)}return j},_fieldData:function(i){if(!this.app.options.is_dynamic){i.info="Data input '"+i.name+"' ("+e.textify(i.extensions.toString())+")";i.value=null;return this._fieldHidden(i)}var j=this;return new a.View(this.app,{id:"field-"+i.id,extensions:i.extensions,optional:i.optional,multiple:i.multiple,type:i.type,data:i.options,onchange:function(){j.app.trigger("refresh")}})},_fieldSelect:function(j){if(!this.app.options.is_dynamic&&j.is_dynamic){return this._fieldText(j)}var l=[];for(var m in j.options){var n=j.options[m];l.push({label:n[0],value:n[1]})}var o=h.Select;switch(j.display){case"checkboxes":o=h.Checkbox;break;case"radio":o=h.Radio;break}var k=this;return new o.View({id:"field-"+j.id,data:l,error_text:j.error_text||"No options available",multiple:j.multiple,searchable:j.searchable,onchange:function(){k.app.trigger("refresh")}})},_fieldDrilldown:function(i){if(!this.app.options.is_dynamic&&i.is_dynamic){return this._fieldText(i)}var j=this;return new h.Drilldown.View({id:"field-"+i.id,data:i.options,display:i.display,onchange:function(){j.app.trigger("refresh")}})},_fieldText:function(i){if(i.options){i.area=i.multiple;if(!e.validate(i.value)){i.value=""}else{if(i.value instanceof Array){i.value=value.toString()}else{i.value=String(i.value).replace(/[\[\]'"\s]/g,"");if(i.multiple){i.value=i.value.replace(/,/g,"\n")}}}}var j=this;return new h.Input({id:"field-"+i.id,area:i.area,onchange:function(){j.app.trigger("refresh")}})},_fieldSlider:function(i){var j=this;return new h.Slider.View({id:"field-"+i.id,precise:i.type=="float",min:i.min,max:i.max,onchange:function(){j.app.trigger("refresh")}})},_fieldHidden:function(i){return new h.Hidden({id:"field-"+i.id,info:i.info})},_fieldBoolean:function(i){var j=this;return new h.RadioButton.View({id:"field-"+i.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}],onchange:function(){j.app.trigger("refresh")}})}});return{View:g}});
\ No newline at end of file
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 static/scripts/packed/mvc/tools/tools-tree.js
--- a/static/scripts/packed/mvc/tools/tools-tree.js
+++ b/static/scripts/packed/mvc/tools/tools-tree.js
@@ -1,1 +1,1 @@
-define(["utils/utils"],function(a){return Backbone.Model.extend({initialize:function(b){this.app=b},finalize:function(g){var b=this;this.map_dict={};if(!this.app.section){return{}}g=g||{};var f={};var e={};this._iterate(this.app.section.$el,e);function d(j,i,h){f[j]=h;b.map_dict[j]=i}function c(p,s){for(var n in s){var k=s[n];if(k.input){var u=k.input;var o=p;if(p!=""){o+="|"}o+=u.name;switch(u.type){case"repeat":var j="section-";var x=[];var r=null;for(var w in k){var q=w.indexOf(j);if(q!=-1){q+=j.length;x.push(parseInt(w.substr(q)));if(!r){r=w.substr(0,q)}}}x.sort(function(y,i){return y-i});var n=0;for(var l in x){c(o+"_"+n++,k[r+x[l]])}break;case"conditional":var v=b.app.field_list[u.id].value();if(g[u.test_param.type]){v=g[u.test_param.type](v)}d(o+"|"+u.test_param.name,u.id,v);var h=b.matchCase(u,v);if(h!=-1){c(o,s[u.id+"-section-"+h])}break;case"section":c("",k);break;default:var t=b.app.field_list[u.id];if(t&&t.value){var v=t.value();if(g[u.type]){v=g[u.type](v)}if(t.skip){continue}if(t.validate&&!t.validate()){v=null}if(u.ignore===undefined||(v!==null&&u.ignore!=v)){d(o,u.id,v);if(u.payload){for(var m in u.payload){d(m,u.id,u.payload[m])}}}}}}}}c("",e);return f},match:function(b){return this.map_dict&&this.map_dict[b]},matchCase:function(b,d){if(b.test_param.type=="boolean"){if(d=="true"){d=b.test_param.truevalue||"true"}else{d=b.test_param.falsevalue||"false"}}for(var c in b.cases){if(b.cases[c].value==d){return c}}return -1},matchModel:function(d,f){var b={};var c=this;function e(g,p){for(var m in p){var k=p[m];var n=k.name;if(g!=""){n=g+"|"+n}switch(k.type){case"repeat":for(var l in k.cache){e(n+"_"+l,k.cache[l])}break;case"conditional":var q=k.test_param&&k.test_param.value;var h=c.matchCase(k,q);if(h!=-1){e(n,k.cases[h].inputs)}break;default:var o=c.map_dict[n];if(o){f(o,k)}}}}e("",d.inputs);return b},matchResponse:function(d){var b={};var c=this;function e(l,j){if(typeof j==="string"){var g=c.map_dict[l];if(g){b[g]=j}}else{for(var h in j){var f=h;if(l!==""){var k="|";if(j instanceof Array){k="_"}f=l+k+f}e(f,j[h])}}}e("",d);return b},_iterate:function(d,e){var b=this;var c=$(d).children();c.each(function(){var h=this;var g=$(h).attr("id");if($(h).hasClass("section-row")){e[g]={};var f=b.app.input_list[g];if(f){e[g]={input:f}}b._iterate(h,e[g])}else{b._iterate(h,e)}})}})});
\ No newline at end of file
+define(["utils/utils"],function(a){return Backbone.Model.extend({initialize:function(b){this.app=b},finalize:function(g){var b=this;this.map_dict={};if(!this.app.section){return{}}g=g||{};var f={};var e={};this._iterate(this.app.section.$el,e);function d(j,i,h){f[j]=h;b.map_dict[j]=i}function c(p,s){for(var n in s){var k=s[n];if(k.input){var u=k.input;var o=p;if(p!=""){o+="|"}o+=u.name;switch(u.type){case"repeat":var j="section-";var x=[];var r=null;for(var w in k){var q=w.indexOf(j);if(q!=-1){q+=j.length;x.push(parseInt(w.substr(q)));if(!r){r=w.substr(0,q)}}}x.sort(function(y,i){return y-i});var n=0;for(var l in x){c(o+"_"+n++,k[r+x[l]])}break;case"conditional":var v=b.app.field_list[u.id].value();if(g[u.test_param.type]){v=g[u.test_param.type](v)}d(o+"|"+u.test_param.name,u.id,v);var h=b.matchCase(u,v);if(h!=-1){c(o,s[u.id+"-section-"+h])}break;case"section":c("",k);break;default:var t=b.app.field_list[u.id];if(t&&t.value){var v=t.value();if(t.validate&&!t.validate()){v=null}if(g[u.type]){v=g[u.type](v)}if(u.ignore===undefined||(v!==null&&u.ignore!=v)){d(o,u.id,v);if(u.payload){for(var m in u.payload){d(m,u.id,u.payload[m])}}}}}}}}c("",e);return f},match:function(b){return this.map_dict&&this.map_dict[b]},matchCase:function(b,d){if(b.test_param.type=="boolean"){if(d=="true"){d=b.test_param.truevalue||"true"}else{d=b.test_param.falsevalue||"false"}}for(var c in b.cases){if(b.cases[c].value==d){return c}}return -1},matchModel:function(d,f){var b={};var c=this;function e(g,p){for(var m in p){var k=p[m];var n=k.name;if(g!=""){n=g+"|"+n}switch(k.type){case"repeat":for(var l in k.cache){e(n+"_"+l,k.cache[l])}break;case"conditional":var q=k.test_param&&k.test_param.value;var h=c.matchCase(k,q);if(h!=-1){e(n,k.cases[h].inputs)}break;default:var o=c.map_dict[n];if(o){f(o,k)}}}}e("",d.inputs);return b},matchResponse:function(d){var b={};var c=this;function e(l,j){if(typeof j==="string"){var g=c.map_dict[l];if(g){b[g]=j}}else{for(var h in j){var f=h;if(l!==""){var k="|";if(j instanceof Array){k="_"}f=l+k+f}e(f,j[h])}}}e("",d);return b},_iterate:function(d,e){var b=this;var c=$(d).children();c.each(function(){var h=this;var g=$(h).attr("id");if($(h).hasClass("section-row")){e[g]={};var f=b.app.input_list[g];if(f){e[g]={input:f}}b._iterate(h,e[g])}else{b._iterate(h,e)}})}})});
\ No newline at end of file
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 static/scripts/packed/utils/metrics-logger.js
--- a/static/scripts/packed/utils/metrics-logger.js
+++ b/static/scripts/packed/utils/metrics-logger.js
@@ -1,1 +1,1 @@
-define([],function(){function i(D){D=D||{};var C=this;C.userId=window.bootstrapped?window.bootstrapped.user.id:null;C.userId=C.userId||D.userId||null;C.consoleLogger=D.consoleLogger||null;C._init(D);return C}i.ALL=0;i.DEBUG=10;i.INFO=20;i.WARN=30;i.ERROR=40;i.METRIC=50;i.NONE=100;i.defaultOptions={logLevel:i.NONE,consoleLevel:i.NONE,defaultNamespace:"Galaxy",clientPrefix:"client.",maxCacheSize:3000,postSize:1000,addTime:true,cacheKeyPrefix:"logs-",postUrl:"/api/metrics",delayPostInMs:1000*60*10,getPingData:undefined,onServerResponse:undefined};i.prototype._init=function j(E){var D=this;D.options={};for(var C in i.defaultOptions){if(i.defaultOptions.hasOwnProperty(C)){D.options[C]=(E.hasOwnProperty(C))?(E[C]):(i.defaultOptions[C])}}D.options.logLevel=D._parseLevel(D.options.logLevel);D.options.consoleLevel=D._parseLevel(D.options.consoleLevel);D._sending=false;D._waiting=null;D._postSize=D.options.postSize;D._initCache();return D};i.prototype._initCache=function a(){try{this.cache=new z({maxSize:this.options.maxCacheSize,key:this.options.cacheKeyPrefix+this.userId})}catch(C){this._emitToConsole("warn","MetricsLogger",["Could not intitialize logging cache:",C]);this.options.logLevel=i.NONE}};i.prototype._parseLevel=function n(E){var D=typeof E;if(D==="number"){return E}if(D==="string"){var C=E.toUpperCase();if(i.hasOwnProperty(C)){return i[C]}}throw new Error("Unknown log level: "+E)};i.prototype.emit=function q(F,E,D){var C=this;E=E||C.options.defaultNamespace;if(!F||!D){return C}F=C._parseLevel(F);if(F>=C.options.logLevel){C._addToCache(F,E,D)}if(C.consoleLogger&&F>=C.options.consoleLevel){C._emitToConsole(F,E,D)}return C};i.prototype._addToCache=function b(H,E,D){this._emitToConsole("debug","MetricsLogger",["_addToCache:",arguments,this.options.addTime,this.cache.length()]);var C=this;try{var G=C.cache.add(C._buildEntry(H,E,D));if(G>=C._postSize){C._postCache()}}catch(F){C._emitToConsole("warn","MetricsLogger",["Metrics logger could not stringify logArguments:",E,D]);C._emitToConsole("error","MetricsLogger",[F])}return C};i.prototype._buildEntry=function u(F,D,C){this._emitToConsole("debug","MetricsLogger",["_buildEntry:",arguments]);var E={level:F,namespace:this.options.clientPrefix+D,args:C};if(this.options.addTime){E.time=new Date().toISOString()}return E};i.prototype._postCache=function v(F){F=F||{};this._emitToConsole("info","MetricsLogger",["_postCache",F,this._postSize]);if(!this.options.postUrl||this._sending){return jQuery.when({})}var E=this,H=F.count||E._postSize,C=E.cache.get(H),G=C.length,D=(typeof E.options.getPingData==="function")?(E.options.getPingData()):({});D.metrics=JSON.stringify(C);E._sending=true;return jQuery.post(E.options.postUrl,D).always(function(){E._sending=false}).fail(function(K,I,J){E._postSize=E.options.maxCacheSize;this.emit("error","MetricsLogger",["_postCache error:",K.readyState,K.status,K.responseJSON||K.responseText])}).done(function(I){if(typeof E.options.onServerResponse==="function"){E.options.onServerResponse(I)}E.cache.remove(G);E._postSize=E.options.postSize})};i.prototype._delayPost=function k(){var C=this;C._waiting=setTimeout(function(){C._waiting=null},C.options.delayPostInMs)};i.prototype._emitToConsole=function c(G,F,E){var C=this;if(!C.consoleLogger){return C}var D=Array.prototype.slice.call(E,0);D.unshift(F);if(G>=i.METRIC&&typeof(C.consoleLogger.info)==="function"){return C.consoleLogger.info.apply(C.consoleLogger,D)}else{if(G>=i.ERROR&&typeof(C.consoleLogger.error)==="function"){return C.consoleLogger.error.apply(C.consoleLogger,D)}else{if(G>=i.WARN&&typeof(C.consoleLogger.warn)==="function"){C.consoleLogger.warn.apply(C.consoleLogger,D)}else{if(G>=i.INFO&&typeof(C.consoleLogger.info)==="function"){C.consoleLogger.info.apply(C.consoleLogger,D)}else{if(G>=i.DEBUG&&typeof(C.consoleLogger.debug)==="function"){C.consoleLogger.debug.apply(C.consoleLogger,D)}else{if(typeof(C.consoleLogger.log)==="function"){C.consoleLogger.log.apply(C.consoleLogger,D)}}}}}}return C};i.prototype.log=function h(){this.emit(1,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.debug=function p(){this.emit(i.DEBUG,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.info=function x(){this.emit(i.INFO,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.warn=function w(){this.emit(i.WARN,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.error=function t(){this.emit(i.ERROR,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.metric=function r(){this.emit(i.METRIC,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};function z(D){var C=this;return C._init(D||{})}z.defaultOptions={maxSize:5000};z.prototype._init=function j(C){if(!this._hasStorage()){throw new Error("LoggingCache needs localStorage")}if(!C.key){throw new Error("LoggingCache needs key for localStorage")}this.key=C.key;this._initStorage();this.maxSize=C.maxSize||z.defaultOptions.maxSize;return this};z.prototype._hasStorage=function A(){var D="test";try{localStorage.setItem(D,D);localStorage.removeItem(D);return true}catch(C){return false}};z.prototype._initStorage=function m(){if(localStorage.getItem(this.key)===null){return this.empty()}return this};z.prototype.add=function o(E){var D=this,F=D._fetchAndParse(),C=(F.length+1)-D.maxSize;if(C>0){F.splice(0,C)}F.push(E);D._unparseAndStore(F);return F.length};z.prototype._fetchAndParse=function g(){var C=this;return JSON.parse(localStorage.getItem(C.key))};z.prototype._unparseAndStore=function f(C){var D=this;return localStorage.setItem(D.key,JSON.stringify(C))};z.prototype.length=function e(){return this._fetchAndParse().length};z.prototype.get=function y(C){return this._fetchAndParse().slice(0,C)};z.prototype.remove=function B(C){var E=this._fetchAndParse(),D=E.splice(0,C);this._unparseAndStore(E);return D};z.prototype.empty=function l(){localStorage.setItem(this.key,"[]");return this};z.prototype.stringify=function s(C){return JSON.stringify(this.get(C))};z.prototype.print=function d(){console.log(JSON.stringify(this._fetchAndParse(),null," "))};return{MetricsLogger:i,LoggingCache:z}});
\ No newline at end of file
+define([],function(){function i(D){D=D||{};var C=this;C.userId=(window.bootstrapped&&window.bootstrapped.user)?window.bootstrapped.user.id:null;C.userId=C.userId||D.userId||null;C.consoleLogger=D.consoleLogger||null;C._init(D);return C}i.ALL=0;i.DEBUG=10;i.INFO=20;i.WARN=30;i.ERROR=40;i.METRIC=50;i.NONE=100;i.defaultOptions={logLevel:i.NONE,consoleLevel:i.NONE,defaultNamespace:"Galaxy",clientPrefix:"client.",maxCacheSize:3000,postSize:1000,addTime:true,cacheKeyPrefix:"logs-",postUrl:"/api/metrics",delayPostInMs:1000*60*10,getPingData:undefined,onServerResponse:undefined};i.prototype._init=function j(E){var D=this;D.options={};for(var C in i.defaultOptions){if(i.defaultOptions.hasOwnProperty(C)){D.options[C]=(E.hasOwnProperty(C))?(E[C]):(i.defaultOptions[C])}}D.options.logLevel=D._parseLevel(D.options.logLevel);D.options.consoleLevel=D._parseLevel(D.options.consoleLevel);D._sending=false;D._waiting=null;D._postSize=D.options.postSize;D._initCache();return D};i.prototype._initCache=function a(){try{this.cache=new z({maxSize:this.options.maxCacheSize,key:this.options.cacheKeyPrefix+this.userId})}catch(C){this._emitToConsole("warn","MetricsLogger",["Could not intitialize logging cache:",C]);this.options.logLevel=i.NONE}};i.prototype._parseLevel=function n(E){var D=typeof E;if(D==="number"){return E}if(D==="string"){var C=E.toUpperCase();if(i.hasOwnProperty(C)){return i[C]}}throw new Error("Unknown log level: "+E)};i.prototype.emit=function q(F,E,D){var C=this;E=E||C.options.defaultNamespace;if(!F||!D){return C}F=C._parseLevel(F);if(F>=C.options.logLevel){C._addToCache(F,E,D)}if(C.consoleLogger&&F>=C.options.consoleLevel){C._emitToConsole(F,E,D)}return C};i.prototype._addToCache=function b(H,E,D){this._emitToConsole("debug","MetricsLogger",["_addToCache:",arguments,this.options.addTime,this.cache.length()]);var C=this;try{var G=C.cache.add(C._buildEntry(H,E,D));if(G>=C._postSize){C._postCache()}}catch(F){C._emitToConsole("warn","MetricsLogger",["Metrics logger could not stringify logArguments:",E,D]);C._emitToConsole("error","MetricsLogger",[F])}return C};i.prototype._buildEntry=function u(F,D,C){this._emitToConsole("debug","MetricsLogger",["_buildEntry:",arguments]);var E={level:F,namespace:this.options.clientPrefix+D,args:C};if(this.options.addTime){E.time=new Date().toISOString()}return E};i.prototype._postCache=function v(F){F=F||{};this._emitToConsole("info","MetricsLogger",["_postCache",F,this._postSize]);if(!this.options.postUrl||this._sending){return jQuery.when({})}var E=this,H=F.count||E._postSize,C=E.cache.get(H),G=C.length,D=(typeof E.options.getPingData==="function")?(E.options.getPingData()):({});D.metrics=JSON.stringify(C);E._sending=true;return jQuery.post(E.options.postUrl,D).always(function(){E._sending=false}).fail(function(K,I,J){E._postSize=E.options.maxCacheSize;this.emit("error","MetricsLogger",["_postCache error:",K.readyState,K.status,K.responseJSON||K.responseText])}).done(function(I){if(typeof E.options.onServerResponse==="function"){E.options.onServerResponse(I)}E.cache.remove(G);E._postSize=E.options.postSize})};i.prototype._delayPost=function k(){var C=this;C._waiting=setTimeout(function(){C._waiting=null},C.options.delayPostInMs)};i.prototype._emitToConsole=function c(G,F,E){var C=this;if(!C.consoleLogger){return C}var D=Array.prototype.slice.call(E,0);D.unshift(F);if(G>=i.METRIC&&typeof(C.consoleLogger.info)==="function"){return C.consoleLogger.info.apply(C.consoleLogger,D)}else{if(G>=i.ERROR&&typeof(C.consoleLogger.error)==="function"){return C.consoleLogger.error.apply(C.consoleLogger,D)}else{if(G>=i.WARN&&typeof(C.consoleLogger.warn)==="function"){C.consoleLogger.warn.apply(C.consoleLogger,D)}else{if(G>=i.INFO&&typeof(C.consoleLogger.info)==="function"){C.consoleLogger.info.apply(C.consoleLogger,D)}else{if(G>=i.DEBUG&&typeof(C.consoleLogger.debug)==="function"){C.consoleLogger.debug.apply(C.consoleLogger,D)}else{if(typeof(C.consoleLogger.log)==="function"){C.consoleLogger.log.apply(C.consoleLogger,D)}}}}}}return C};i.prototype.log=function h(){this.emit(1,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.debug=function p(){this.emit(i.DEBUG,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.info=function x(){this.emit(i.INFO,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.warn=function w(){this.emit(i.WARN,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.error=function t(){this.emit(i.ERROR,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.metric=function r(){this.emit(i.METRIC,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};function z(D){var C=this;return C._init(D||{})}z.defaultOptions={maxSize:5000};z.prototype._init=function j(C){if(!this._hasStorage()){throw new Error("LoggingCache needs localStorage")}if(!C.key){throw new Error("LoggingCache needs key for localStorage")}this.key=C.key;this._initStorage();this.maxSize=C.maxSize||z.defaultOptions.maxSize;return this};z.prototype._hasStorage=function A(){var D="test";try{localStorage.setItem(D,D);localStorage.removeItem(D);return true}catch(C){return false}};z.prototype._initStorage=function m(){if(localStorage.getItem(this.key)===null){return this.empty()}return this};z.prototype.add=function o(E){var D=this,F=D._fetchAndParse(),C=(F.length+1)-D.maxSize;if(C>0){F.splice(0,C)}F.push(E);D._unparseAndStore(F);return F.length};z.prototype._fetchAndParse=function g(){var C=this;return JSON.parse(localStorage.getItem(C.key))};z.prototype._unparseAndStore=function f(C){var D=this;return localStorage.setItem(D.key,JSON.stringify(C))};z.prototype.length=function e(){return this._fetchAndParse().length};z.prototype.get=function y(C){return this._fetchAndParse().slice(0,C)};z.prototype.remove=function B(C){var E=this._fetchAndParse(),D=E.splice(0,C);this._unparseAndStore(E);return D};z.prototype.empty=function l(){localStorage.setItem(this.key,"[]");return this};z.prototype.stringify=function s(C){return JSON.stringify(this.get(C))};z.prototype.print=function d(){console.log(JSON.stringify(this._fetchAndParse(),null," "))};return{MetricsLogger:i,LoggingCache:z}});
\ No newline at end of file
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 static/scripts/utils/metrics-logger.js
--- a/static/scripts/utils/metrics-logger.js
+++ b/static/scripts/utils/metrics-logger.js
@@ -34,7 +34,7 @@
var self = this;
///** get the current user's id from bootstrapped data or options */
- self.userId = window.bootstrapped? window.bootstrapped.user.id: null;
+ self.userId = ( window.bootstrapped && window.bootstrapped.user )? window.bootstrapped.user.id: null;
self.userId = self.userId || options.userId || null;
/** the (optional) console to emit logs to */
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 templates/webapps/galaxy/tool_form.mako
--- a/templates/webapps/galaxy/tool_form.mako
+++ b/templates/webapps/galaxy/tool_form.mako
@@ -10,7 +10,7 @@
## This avoids making two separate requests since the classic form requires the mako anyway.
params = dict(trans.request.params)
params['__dataset_id__'] = params.get('id', None)
- self.form_config = tool.to_json(trans, **params)
+ self.form_config = tool.to_json(trans, params)
self.form_config.update({
'id' : tool.id,
'job_id' : trans.security.encode_id( job.id ) if job else None,
diff -r 60ce4bb8e4cea17bf39b1799680b5bb45adf57b8 -r 01ac77bb90de2c285325abb27419f7e9880c8687 templates/webapps/galaxy/workflow/editor_tool_form.mako
--- a/templates/webapps/galaxy/workflow/editor_tool_form.mako
+++ b/templates/webapps/galaxy/workflow/editor_tool_form.mako
@@ -6,11 +6,9 @@
## TEMPORARY: create tool dictionary in mako while both tool forms are in use.
## This avoids making two separate requests since the classic form requires the mako anyway.
from galaxy.tools.parameters import params_to_incoming
- incoming = {
- '__is_dynamic__' : False
- }
+ incoming = {}
params_to_incoming( incoming, tool.inputs, module.state.inputs, trans.app, to_html=False)
- self.form_config = tool.to_json(trans, **incoming)
+ self.form_config = tool.to_json(trans, incoming, is_dynamic=False)
self.form_config.update({
'id' : tool.id,
'job_id' : trans.security.encode_id( job.id ) if job else None,
https://bitbucket.org/galaxy/galaxy-central/commits/70b67e2355d0/
Changeset: 70b67e2355d0
User: dannon
Date: 2015-02-09 17:16:01+00:00
Summary: Merge.
Affected #: 2 files
diff -r 01ac77bb90de2c285325abb27419f7e9880c8687 -r 70b67e2355d0bf455df62355807db413cca39c04 lib/galaxy/datatypes/registry.py
--- a/lib/galaxy/datatypes/registry.py
+++ b/lib/galaxy/datatypes/registry.py
@@ -308,7 +308,7 @@
append_to_sniff_order()
def load_build_sites( self, root ):
- if root.find( 'build_sites' ):
+ if root.find( 'build_sites' ) is not None:
for elem in root.find( 'build_sites' ).findall( 'site' ):
if not (elem.get( 'type' ) and elem.get( 'file' )):
self.log.exception( "Site is missing required 'type' and 'file' attributes: %s" )
diff -r 01ac77bb90de2c285325abb27419f7e9880c8687 -r 70b67e2355d0bf455df62355807db413cca39c04 lib/galaxy/webapps/galaxy/api/configuration.py
--- a/lib/galaxy/webapps/galaxy/api/configuration.py
+++ b/lib/galaxy/webapps/galaxy/api/configuration.py
@@ -31,18 +31,25 @@
serialization_params = self._parse_serialization_params( kwd, 'all' )
return self.get_config_dict( trans, is_admin, **serialization_params )
- def get_config_dict( self, trans, return_admin=False, **kwargs ):
+ def get_config_dict( self, trans, return_admin=False, view=None, keys=None, default_view='all' ):
+ """
+ Return a dictionary with (a subset of) current Galaxy settings.
+
+ If `return_admin` also include a subset of more sensitive keys.
+ Pass in `view` (String) and comma seperated list of keys to control which
+ configuration settings are returned.
+ """
serializer = self.config_serializer
if return_admin:
#TODO: this should probably just be under a different route: 'admin/configuration'
serializer = self.admin_config_serializer
- if 'default_view' not in kwargs:
- kwargs[ 'default_view' ] = serializer.default_view
- serialized = serializer.serialize_to_view( trans, self.app.config, **kwargs )
+ serialized = serializer.serialize_to_view( trans, self.app.config,
+ view=view, keys=keys, default_view=default_view )
return serialized
+#TODO: for lack of a manager file for the config. May well be better in config.py? Circ imports?
class ConfigSerializer( base.ModelSerializer ):
def __init__( self, app ):
@@ -54,42 +61,42 @@
def default_serializer( self, trans, config, key ):
return config.get( key, None )
- def _defaults_to( self, default ):
- return lambda t, i, k: i.get( k, default )
+ def add_serializers( self ):
+ def _defaults_to( default ):
+ return lambda t, i, k: i.get( k, default )
- def add_serializers( self ):
self.serializers = {
#TODO: this is available from user data, remove
'is_admin_user' : lambda *a: False,
- 'brand' : lambda t, i, k: i.get( k, "" ),
+ 'brand' : _defaults_to( '' ),
#TODO: this doesn't seem right
- 'logo_url' : lambda t, i, k: self.url_for( i.get( k, '/') ),
- 'terms_url' : lambda t, i, k: i.get( k, "" ),
+ 'logo_url' : lambda t, i, k: self.url_for( i.get( k, '/' ) ),
+ 'terms_url' : _defaults_to( '' ),
#TODO: don't hardcode here - hardcode defaults once in config.py
- 'wiki_url' : self._defaults_to( "http://galaxyproject.org/" ),
- 'search_url' : self._defaults_to( "http://galaxyproject.org/search/usegalaxy/" ),
- 'mailing_lists' : self._defaults_to( "http://wiki.galaxyproject.org/MailingLists" ),
- 'screencasts_url' : self._defaults_to( "http://vimeo.com/galaxyproject" ),
- 'citation_url' : self._defaults_to( "http://wiki.galaxyproject.org/CitingGalaxy" ),
- 'support_url' : self._defaults_to( "http://wiki.galaxyproject.org/Support" ),
- 'lims_doc_url' : self._defaults_to( "http://main.g2.bx.psu.edu/u/rkchak/p/sts" ),
- 'biostar_url' : lambda t, i, k: i.biostar_url,
+ 'wiki_url' : _defaults_to( "http://galaxyproject.org/" ),
+ 'search_url' : _defaults_to( "http://galaxyproject.org/search/usegalaxy/" ),
+ 'mailing_lists' : _defaults_to( "http://wiki.galaxyproject.org/MailingLists" ),
+ 'screencasts_url' : _defaults_to( "http://vimeo.com/galaxyproject" ),
+ 'citation_url' : _defaults_to( "http://wiki.galaxyproject.org/CitingGalaxy" ),
+ 'support_url' : _defaults_to( "http://wiki.galaxyproject.org/Support" ),
+ 'lims_doc_url' : _defaults_to( "http://main.g2.bx.psu.edu/u/rkchak/p/sts" ),
+ 'biostar_url' : _defaults_to( '' ),
'biostar_url_redirect' : lambda *a: self.url_for( controller='biostar', action='biostar_redirect',
- qualified=True ),
+ qualified=True ),
- 'allow_user_creation' : lambda t, i, k: i.allow_user_creation,
- 'use_remote_user' : lambda t, i, k: i.use_remote_user,
- 'remote_user_logout_href' : lambda t, i, k: i.remote_user_logout_href,
- 'enable_cloud_launch' : self._defaults_to( False ),
- 'datatypes_disable_auto' : self._defaults_to( False ),
- 'allow_user_dataset_purge' : self._defaults_to( False ),
- 'enable_unique_workflow_defaults' : self._defaults_to( False ),
+ 'allow_user_creation' : _defaults_to( False ),
+ 'use_remote_user' : _defaults_to( None ),
+ 'remote_user_logout_href' : _defaults_to( '' ),
+ 'enable_cloud_launch' : _defaults_to( False ),
+ 'datatypes_disable_auto' : _defaults_to( False ),
+ 'allow_user_dataset_purge' : _defaults_to( False ),
+ 'enable_unique_workflow_defaults' : _defaults_to( False ),
- 'nginx_upload_path' : self._defaults_to( self.url_for( controller='api', action='tools' ) ),
- 'ftp_upload_dir' : self._defaults_to( None ),
- 'ftp_upload_site' : self._defaults_to( None ),
+ 'nginx_upload_path' : _defaults_to( self.url_for( controller='api', action='tools' ) ),
+ 'ftp_upload_dir' : _defaults_to( None ),
+ 'ftp_upload_site' : _defaults_to( None ),
}
@@ -98,14 +105,16 @@
def add_serializers( self ):
super( AdminConfigSerializer, self ).add_serializers()
+ def _defaults_to( default ):
+ return lambda t, i, k: i.get( k, default )
self.serializers.update({
#TODO: this is available from user data, remove
'is_admin_user' : lambda *a: True,
- 'library_import_dir' : self._defaults_to( None ),
- 'user_library_import_dir' : self._defaults_to( None ),
- 'allow_library_path_paste' : self._defaults_to( None ),
- 'allow_user_creation' : self._defaults_to( False ),
- 'allow_user_deletion' : self._defaults_to( False ),
+ 'library_import_dir' : _defaults_to( None ),
+ 'user_library_import_dir' : _defaults_to( None ),
+ 'allow_library_path_paste' : _defaults_to( False ),
+ 'allow_user_creation' : _defaults_to( False ),
+ 'allow_user_deletion' : _defaults_to( False ),
})
https://bitbucket.org/galaxy/galaxy-central/commits/38717ecbec32/
Changeset: 38717ecbec32
User: dannon
Date: 2015-02-09 19:49:35+00:00
Summary: Prevent last_action column from being populated with time.now() in the entire database and function correctly with null values here. Related bugfixes.
Affected #: 4 files
diff -r 70b67e2355d0bf455df62355807db413cca39c04 -r 38717ecbec32e88f43652bda0739a20ad7b3faf6 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2986,7 +2986,8 @@
current_history=None,
session_key=None,
is_valid=False,
- prev_session_id=None ):
+ prev_session_id=None,
+ last_action=None ):
self.id = id
self.user = user
self.remote_host = remote_host
@@ -2997,7 +2998,7 @@
self.is_valid = is_valid
self.prev_session_id = prev_session_id
self.histories = []
- self.last_action = galaxy.model.orm.now.now()
+ self.last_action = last_action or datetime.now()
def add_history( self, history, association=None ):
if association is None:
diff -r 70b67e2355d0bf455df62355807db413cca39c04 -r 38717ecbec32e88f43652bda0739a20ad7b3faf6 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -683,7 +683,8 @@
Column( "session_key", TrimmedString( 255 ), index=True, unique=True ), # unique 128 bit random number coerced to a string
Column( "is_valid", Boolean, default=False ),
Column( "prev_session_id", Integer ), # saves a reference to the previous session so we have a way to chain them together
- Column( "disk_usage", Numeric( 15, 0 ), index=True ) )
+ Column( "disk_usage", Numeric( 15, 0 ), index=True ),
+ Column( "last_action", DateTime) )
model.GalaxySessionToHistoryAssociation.table = Table( "galaxy_session_to_history", metadata,
Column( "id", Integer, primary_key=True ),
diff -r 70b67e2355d0bf455df62355807db413cca39c04 -r 38717ecbec32e88f43652bda0739a20ad7b3faf6 lib/galaxy/model/migrate/versions/0128_session_timeout.py
--- a/lib/galaxy/model/migrate/versions/0128_session_timeout.py
+++ b/lib/galaxy/model/migrate/versions/0128_session_timeout.py
@@ -21,7 +21,7 @@
print __doc__
metadata.reflect()
- lastaction_column = Column( "last_action", DateTime, default=now )
+ lastaction_column = Column( "last_action", DateTime )
__add_column( lastaction_column, "galaxy_session", metadata )
diff -r 70b67e2355d0bf455df62355807db413cca39c04 -r 38717ecbec32e88f43652bda0739a20ad7b3faf6 lib/galaxy/web/framework/webapp.py
--- a/lib/galaxy/web/framework/webapp.py
+++ b/lib/galaxy/web/framework/webapp.py
@@ -221,7 +221,13 @@
# Make sure we're not past the duration, and either log out or
# update timestamp.
now = datetime.datetime.now()
- expiration_time = self.galaxy_session.update_time + datetime.timedelta(minutes=config.session_duration)
+ if self.galaxy_session.last_action:
+ expiration_time = self.galaxy_session.last_action + datetime.timedelta(minutes=config.session_duration)
+ else:
+ expiration_time = now
+ self.galaxy_session.last_action = now - datetime.timedelta(seconds=1)
+ self.sa_session.add(self.galaxy_session)
+ self.sa_session.flush()
if expiration_time < now:
# Expiration time has passed.
self.handle_user_logout()
@@ -236,7 +242,7 @@
status='info',
use_panels=True ) )
else:
- self.galaxy_session.update_time = datetime.datetime.now()
+ self.galaxy_session.last_action = now
self.sa_session.add(self.galaxy_session)
self.sa_session.flush()
https://bitbucket.org/galaxy/galaxy-central/commits/e99cb7eea9d7/
Changeset: e99cb7eea9d7
User: dannon
Date: 2015-02-09 19:50:00+00:00
Summary: Merge.
Affected #: 3 files
diff -r 38717ecbec32e88f43652bda0739a20ad7b3faf6 -r e99cb7eea9d785245398e33166e3f53606d24ed4 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2711,12 +2711,16 @@
error_message = "Dataset collection has no %s with key %s." % ( get_by_attribute, key )
raise KeyError( error_message )
- def copy( self ):
+ def copy( self, destination=None, element_destination=None ):
new_collection = DatasetCollection(
collection_type=self.collection_type,
)
for element in self.elements:
- element.copy_to_collection( new_collection )
+ element.copy_to_collection(
+ new_collection,
+ destination=destination,
+ element_destination=element_destination,
+ )
object_session( self ).add( new_collection )
object_session( self ).flush()
return new_collection
@@ -2835,20 +2839,24 @@
break
return matching_collection
- def copy( self ):
+ def copy( self, element_destination=None ):
"""
Create a copy of this history dataset collection association. Copy
underlying collection.
"""
hdca = HistoryDatasetCollectionAssociation(
hid=self.hid,
- collection=self.collection.copy(),
+ collection=None,
visible=self.visible,
deleted=self.deleted,
name=self.name,
copied_from_history_dataset_collection_association=self,
)
-
+ collection_copy = self.collection.copy(
+ destination=hdca,
+ element_destination=element_destination,
+ )
+ hdca.collection = collection_copy
object_session( self ).add( hdca )
object_session( self ).flush()
return hdca
@@ -2957,9 +2965,26 @@
else:
return element_object
- def copy_to_collection( self, collection ):
+ def copy_to_collection( self, collection, destination=None, element_destination=None ):
+ element_object = self.element_object
+ if element_destination:
+ if self.is_collection:
+ element_object = element_object.copy(
+ destination=destination,
+ element_destination=element_destination
+ )
+ else:
+ new_element_object = element_object.copy( copy_children=True )
+ if destination is not None and element_object.hidden_beneath_collection_instance:
+ new_element_object.hidden_beneath_collection_instance = destination
+ # Ideally we would not need to give the following
+ # element an HID and it would exist in the history only
+ # as an element of the containing collection.
+ element_destination.add_dataset( new_element_object )
+ element_object = new_element_object
+
new_element = DatasetCollectionElement(
- element=self.element_object,
+ element=element_object,
collection=collection,
element_index=self.element_index,
element_identifier=self.element_identifier,
diff -r 38717ecbec32e88f43652bda0739a20ad7b3faf6 -r e99cb7eea9d785245398e33166e3f53606d24ed4 lib/galaxy/tools/deps/brew_exts.py
--- a/lib/galaxy/tools/deps/brew_exts.py
+++ b/lib/galaxy/tools/deps/brew_exts.py
@@ -21,7 +21,10 @@
from __future__ import print_function
-import argparse
+try:
+ import argparse
+except ImportError:
+ argparse = None
import contextlib
import json
import glob
diff -r 38717ecbec32e88f43652bda0739a20ad7b3faf6 -r e99cb7eea9d785245398e33166e3f53606d24ed4 lib/galaxy/webapps/galaxy/controllers/dataset.py
--- a/lib/galaxy/webapps/galaxy/controllers/dataset.py
+++ b/lib/galaxy/webapps/galaxy/controllers/dataset.py
@@ -1074,7 +1074,11 @@
if content.history_content_type == "dataset":
hist.add_dataset( content.copy( copy_children=True ) )
else:
- hist.add_dataset_collection( content.copy( ) )
+ copy_collected_datasets = True
+ copy_kwds = {}
+ if copy_collected_datasets:
+ copy_kwds["element_destination"] = hist
+ hist.add_dataset_collection( content.copy( **copy_kwds ) )
if current_history in target_histories:
refresh_frames = ['history']
trans.sa_session.flush()
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: When copying individual collections via the GUI - copy HDAs by default also.
by commits-noreply@bitbucket.org 10 Feb '15
by commits-noreply@bitbucket.org 10 Feb '15
10 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4d62fbb0458b/
Changeset: 4d62fbb0458b
User: jmchilton
Date: 2015-02-09 18:29:45+00:00
Summary: When copying individual collections via the GUI - copy HDAs by default also.
We may want to be able to turn this off someday in certain scenarios - but usually this will result in less confusion for the user.
Doing this for whole histories also needs to be done - but it is a bit trickier (don't want the HDA copied twice). Might be better on the other side of eliminating the nessecity that these things have HIDs.
Affected #: 2 files
diff -r d9325c4bf7d670b6024b33c9723bb83e1856db6e -r 4d62fbb0458b49add6a009d86f17719dece7452f lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2711,12 +2711,16 @@
error_message = "Dataset collection has no %s with key %s." % ( get_by_attribute, key )
raise KeyError( error_message )
- def copy( self ):
+ def copy( self, destination=None, element_destination=None ):
new_collection = DatasetCollection(
collection_type=self.collection_type,
)
for element in self.elements:
- element.copy_to_collection( new_collection )
+ element.copy_to_collection(
+ new_collection,
+ destination=destination,
+ element_destination=element_destination,
+ )
object_session( self ).add( new_collection )
object_session( self ).flush()
return new_collection
@@ -2835,20 +2839,24 @@
break
return matching_collection
- def copy( self ):
+ def copy( self, element_destination=None ):
"""
Create a copy of this history dataset collection association. Copy
underlying collection.
"""
hdca = HistoryDatasetCollectionAssociation(
hid=self.hid,
- collection=self.collection.copy(),
+ collection=None,
visible=self.visible,
deleted=self.deleted,
name=self.name,
copied_from_history_dataset_collection_association=self,
)
-
+ collection_copy = self.collection.copy(
+ destination=hdca,
+ element_destination=element_destination,
+ )
+ hdca.collection = collection_copy
object_session( self ).add( hdca )
object_session( self ).flush()
return hdca
@@ -2957,9 +2965,26 @@
else:
return element_object
- def copy_to_collection( self, collection ):
+ def copy_to_collection( self, collection, destination=None, element_destination=None ):
+ element_object = self.element_object
+ if element_destination:
+ if self.is_collection:
+ element_object = element_object.copy(
+ destination=destination,
+ element_destination=element_destination
+ )
+ else:
+ new_element_object = element_object.copy( copy_children=True )
+ if destination is not None and element_object.hidden_beneath_collection_instance:
+ new_element_object.hidden_beneath_collection_instance = destination
+ # Ideally we would not need to give the following
+ # element an HID and it would exist in the history only
+ # as an element of the containing collection.
+ element_destination.add_dataset( new_element_object )
+ element_object = new_element_object
+
new_element = DatasetCollectionElement(
- element=self.element_object,
+ element=element_object,
collection=collection,
element_index=self.element_index,
element_identifier=self.element_identifier,
diff -r d9325c4bf7d670b6024b33c9723bb83e1856db6e -r 4d62fbb0458b49add6a009d86f17719dece7452f lib/galaxy/webapps/galaxy/controllers/dataset.py
--- a/lib/galaxy/webapps/galaxy/controllers/dataset.py
+++ b/lib/galaxy/webapps/galaxy/controllers/dataset.py
@@ -1074,7 +1074,11 @@
if content.history_content_type == "dataset":
hist.add_dataset( content.copy( copy_children=True ) )
else:
- hist.add_dataset_collection( content.copy( ) )
+ copy_collected_datasets = True
+ copy_kwds = {}
+ if copy_collected_datasets:
+ copy_kwds["element_destination"] = hist
+ hist.add_dataset_collection( content.copy( **copy_kwds ) )
if current_history in target_histories:
refresh_frames = ['history']
trans.sa_session.flush()
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Do not import argparse unconditionally in lib/galaxy/tools/deps/brew_exts.py.
by commits-noreply@bitbucket.org 09 Feb '15
by commits-noreply@bitbucket.org 09 Feb '15
09 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d9325c4bf7d6/
Changeset: d9325c4bf7d6
User: jmchilton
Date: 2015-02-09 17:22:22+00:00
Summary: Do not import argparse unconditionally in lib/galaxy/tools/deps/brew_exts.py.
Affected #: 1 file
diff -r 42648ced82d2ea0f47279fda0a244c6e8b655db3 -r d9325c4bf7d670b6024b33c9723bb83e1856db6e lib/galaxy/tools/deps/brew_exts.py
--- a/lib/galaxy/tools/deps/brew_exts.py
+++ b/lib/galaxy/tools/deps/brew_exts.py
@@ -21,7 +21,10 @@
from __future__ import print_function
-import argparse
+try:
+ import argparse
+except ImportError:
+ argparse = None
import contextlib
import json
import glob
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: API, configuration: doc and clean up
by commits-noreply@bitbucket.org 09 Feb '15
by commits-noreply@bitbucket.org 09 Feb '15
09 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/42648ced82d2/
Changeset: 42648ced82d2
User: carlfeberhard
Date: 2015-02-09 16:49:49+00:00
Summary: API, configuration: doc and clean up
Affected #: 1 file
diff -r 56d2d104edc249ec56eeefaaa6b25349bfcccd8d -r 42648ced82d2ea0f47279fda0a244c6e8b655db3 lib/galaxy/webapps/galaxy/api/configuration.py
--- a/lib/galaxy/webapps/galaxy/api/configuration.py
+++ b/lib/galaxy/webapps/galaxy/api/configuration.py
@@ -31,18 +31,25 @@
serialization_params = self._parse_serialization_params( kwd, 'all' )
return self.get_config_dict( trans, is_admin, **serialization_params )
- def get_config_dict( self, trans, return_admin=False, **kwargs ):
+ def get_config_dict( self, trans, return_admin=False, view=None, keys=None, default_view='all' ):
+ """
+ Return a dictionary with (a subset of) current Galaxy settings.
+
+ If `return_admin` also include a subset of more sensitive keys.
+ Pass in `view` (String) and comma seperated list of keys to control which
+ configuration settings are returned.
+ """
serializer = self.config_serializer
if return_admin:
#TODO: this should probably just be under a different route: 'admin/configuration'
serializer = self.admin_config_serializer
- if 'default_view' not in kwargs:
- kwargs[ 'default_view' ] = serializer.default_view
- serialized = serializer.serialize_to_view( trans, self.app.config, **kwargs )
+ serialized = serializer.serialize_to_view( trans, self.app.config,
+ view=view, keys=keys, default_view=default_view )
return serialized
+#TODO: for lack of a manager file for the config. May well be better in config.py? Circ imports?
class ConfigSerializer( base.ModelSerializer ):
def __init__( self, app ):
@@ -54,42 +61,42 @@
def default_serializer( self, trans, config, key ):
return config.get( key, None )
- def _defaults_to( self, default ):
- return lambda t, i, k: i.get( k, default )
+ def add_serializers( self ):
+ def _defaults_to( default ):
+ return lambda t, i, k: i.get( k, default )
- def add_serializers( self ):
self.serializers = {
#TODO: this is available from user data, remove
'is_admin_user' : lambda *a: False,
- 'brand' : lambda t, i, k: i.get( k, "" ),
+ 'brand' : _defaults_to( '' ),
#TODO: this doesn't seem right
- 'logo_url' : lambda t, i, k: self.url_for( i.get( k, '/') ),
- 'terms_url' : lambda t, i, k: i.get( k, "" ),
+ 'logo_url' : lambda t, i, k: self.url_for( i.get( k, '/' ) ),
+ 'terms_url' : _defaults_to( '' ),
#TODO: don't hardcode here - hardcode defaults once in config.py
- 'wiki_url' : self._defaults_to( "http://galaxyproject.org/" ),
- 'search_url' : self._defaults_to( "http://galaxyproject.org/search/usegalaxy/" ),
- 'mailing_lists' : self._defaults_to( "http://wiki.galaxyproject.org/MailingLists" ),
- 'screencasts_url' : self._defaults_to( "http://vimeo.com/galaxyproject" ),
- 'citation_url' : self._defaults_to( "http://wiki.galaxyproject.org/CitingGalaxy" ),
- 'support_url' : self._defaults_to( "http://wiki.galaxyproject.org/Support" ),
- 'lims_doc_url' : self._defaults_to( "http://main.g2.bx.psu.edu/u/rkchak/p/sts" ),
- 'biostar_url' : lambda t, i, k: i.biostar_url,
+ 'wiki_url' : _defaults_to( "http://galaxyproject.org/" ),
+ 'search_url' : _defaults_to( "http://galaxyproject.org/search/usegalaxy/" ),
+ 'mailing_lists' : _defaults_to( "http://wiki.galaxyproject.org/MailingLists" ),
+ 'screencasts_url' : _defaults_to( "http://vimeo.com/galaxyproject" ),
+ 'citation_url' : _defaults_to( "http://wiki.galaxyproject.org/CitingGalaxy" ),
+ 'support_url' : _defaults_to( "http://wiki.galaxyproject.org/Support" ),
+ 'lims_doc_url' : _defaults_to( "http://main.g2.bx.psu.edu/u/rkchak/p/sts" ),
+ 'biostar_url' : _defaults_to( '' ),
'biostar_url_redirect' : lambda *a: self.url_for( controller='biostar', action='biostar_redirect',
- qualified=True ),
+ qualified=True ),
- 'allow_user_creation' : lambda t, i, k: i.allow_user_creation,
- 'use_remote_user' : lambda t, i, k: i.use_remote_user,
- 'remote_user_logout_href' : lambda t, i, k: i.remote_user_logout_href,
- 'enable_cloud_launch' : self._defaults_to( False ),
- 'datatypes_disable_auto' : self._defaults_to( False ),
- 'allow_user_dataset_purge' : self._defaults_to( False ),
- 'enable_unique_workflow_defaults' : self._defaults_to( False ),
+ 'allow_user_creation' : _defaults_to( False ),
+ 'use_remote_user' : _defaults_to( None ),
+ 'remote_user_logout_href' : _defaults_to( '' ),
+ 'enable_cloud_launch' : _defaults_to( False ),
+ 'datatypes_disable_auto' : _defaults_to( False ),
+ 'allow_user_dataset_purge' : _defaults_to( False ),
+ 'enable_unique_workflow_defaults' : _defaults_to( False ),
- 'nginx_upload_path' : self._defaults_to( self.url_for( controller='api', action='tools' ) ),
- 'ftp_upload_dir' : self._defaults_to( None ),
- 'ftp_upload_site' : self._defaults_to( None ),
+ 'nginx_upload_path' : _defaults_to( self.url_for( controller='api', action='tools' ) ),
+ 'ftp_upload_dir' : _defaults_to( None ),
+ 'ftp_upload_site' : _defaults_to( None ),
}
@@ -98,14 +105,16 @@
def add_serializers( self ):
super( AdminConfigSerializer, self ).add_serializers()
+ def _defaults_to( default ):
+ return lambda t, i, k: i.get( k, default )
self.serializers.update({
#TODO: this is available from user data, remove
'is_admin_user' : lambda *a: True,
- 'library_import_dir' : self._defaults_to( None ),
- 'user_library_import_dir' : self._defaults_to( None ),
- 'allow_library_path_paste' : self._defaults_to( None ),
- 'allow_user_creation' : self._defaults_to( False ),
- 'allow_user_deletion' : self._defaults_to( False ),
+ 'library_import_dir' : _defaults_to( None ),
+ 'user_library_import_dir' : _defaults_to( None ),
+ 'allow_library_path_paste' : _defaults_to( False ),
+ 'allow_user_creation' : _defaults_to( False ),
+ 'allow_user_deletion' : _defaults_to( False ),
})
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
[galaxyproject/usegalaxy-playbook] e94739: Updated Test and UCSC builds on Test.
by GitHub 09 Feb '15
by GitHub 09 Feb '15
09 Feb '15
Branch: refs/heads/master
Home: https://github.com/galaxyproject/usegalaxy-playbook
Commit: e9473948a1dee0298b2f04f48e95a095acbddb7d
https://github.com/galaxyproject/usegalaxy-playbook/commit/e9473948a1dee029…
Author: Nate Coraor <nate(a)bx.psu.edu>
Date: 2015-02-09 (Mon, 09 Feb 2015)
Changed paths:
M files/galaxy/test.galaxyproject.org/config/builds.txt
M files/galaxy/test.galaxyproject.org/config/ucsc_build_sites.txt
M stage/group_vars/all.yml
Log Message:
-----------
Updated Test and UCSC builds on Test.
1
0
commit/galaxy-central: natefoo: Fix warning causing tool failure:
by commits-noreply@bitbucket.org 09 Feb '15
by commits-noreply@bitbucket.org 09 Feb '15
09 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/56d2d104edc2/
Changeset: 56d2d104edc2
User: natefoo
Date: 2015-02-09 16:43:26+00:00
Summary: Fix warning causing tool failure:
FutureWarning: The behavior of this method will change in future versions. Use specific 'len(elem)' or 'elem is not None' test instead.
Affected #: 1 file
diff -r 3de5356639ef95ee8a6e9a16b56fe49c5f37f504 -r 56d2d104edc249ec56eeefaaa6b25349bfcccd8d lib/galaxy/datatypes/registry.py
--- a/lib/galaxy/datatypes/registry.py
+++ b/lib/galaxy/datatypes/registry.py
@@ -308,7 +308,7 @@
append_to_sniff_order()
def load_build_sites( self, root ):
- if root.find( 'build_sites' ):
+ if root.find( 'build_sites' ) is not None:
for elem in root.find( 'build_sites' ).findall( 'site' ):
if not (elem.get( 'type' ) and elem.get( 'file' )):
self.log.exception( "Site is missing required 'type' and 'file' attributes: %s" )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: Managers, users: add tags_used and requests to user serializer to match info bootstrapped in galaxy.masthead.mako and galaxy_client_app.mako
by commits-noreply@bitbucket.org 09 Feb '15
by commits-noreply@bitbucket.org 09 Feb '15
09 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/3de5356639ef/
Changeset: 3de5356639ef
User: carlfeberhard
Date: 2015-02-09 16:34:47+00:00
Summary: Managers, users: add tags_used and requests to user serializer to match info bootstrapped in galaxy.masthead.mako and galaxy_client_app.mako
Affected #: 1 file
diff -r 9903d71660073038dca04743c8b227bd1a9db5ff -r 3de5356639ef95ee8a6e9a16b56fe49c5f37f504 lib/galaxy/managers/users.py
--- a/lib/galaxy/managers/users.py
+++ b/lib/galaxy/managers/users.py
@@ -199,6 +199,42 @@
#TODO: use quota manager
return self.app.quota_agent.get_percent( user=user )
+ def tags_used( self, trans, user, tag_models=None ):
+ """
+ Return a list of distinct 'user_tname:user_value' strings that the
+ given user has used.
+ """
+ #TODO: simplify and unify with tag manager
+ if self.is_anonymous( user ):
+ return []
+
+ # get all the taggable model TagAssociations
+ if not tag_models:
+ tag_models = [ v.tag_assoc_class for v in self.app.tag_handler.item_tag_assoc_info.values() ]
+ # create a union of subqueries for each for this user - getting only the tname and user_value
+ all_tags_query = None
+ for tag_model in tag_models:
+ subq = ( self.app.model.context.query( tag_model.user_tname, tag_model.user_value )
+ .filter( tag_model.user == trans.user ) )
+ all_tags_query = subq if all_tags_query is None else all_tags_query.union( subq )
+
+ # if nothing init'd the query, bail
+ if all_tags_query is None:
+ return []
+
+ # boil the tag tuples down into a sorted list of DISTINCT name:val strings
+ tags = all_tags_query.distinct().all()
+ tags = [( ( name + ':' + val ) if val else name ) for name, val in tags ]
+ return sorted( tags )
+
+ def has_requests( self, trans, user ):
+ """
+ """
+ if self.is_anonymous( user ):
+ return False
+ request_types = self.app.security_agent.get_accessible_request_types( trans, user )
+ return ( user.requests or request_types )
+
class UserSerializer( base.ModelSerializer, deletable.PurgableSerializerMixin ):
@@ -214,21 +250,22 @@
'id', 'email', 'username'
])
self.add_view( 'detailed', [
- 'update_time',
- 'create_time',
-
- 'deleted',
- 'purged',
- 'active',
+ #'update_time',
+ #'create_time',
'total_disk_usage',
'nice_total_disk_usage',
'quota_percent'
- # 'preferences',
- # # all tags
- # 'tags',
- # # all annotations
- # 'annotations'
+
+ #'deleted',
+ #'purged',
+ #'active',
+
+ #'preferences',
+ # all tags
+ 'tags_used',
+ ## all annotations
+ #'annotations'
], include_keys_from='summary' )
def add_serializers( self ):
@@ -240,7 +277,13 @@
'create_time' : self.serialize_date,
'update_time' : self.serialize_date,
'is_admin' : lambda t, i, k: self.user_manager.is_admin( t, i ),
- 'quota_percent' : lambda t, i, k: self.user_manager.quota( t, i )
+
+ 'total_disk_usage' : lambda t, i, k: float( i.total_disk_usage ),
+ 'quota_percent' : lambda t, i, k: self.user_manager.quota( t, i ),
+
+ 'tags_used' : lambda t, i, k: self.user_manager.tags_used( t, i ),
+ #TODO: 'has_requests' is more apt
+ 'requests' : lambda t, i, k: self.user_manager.has_requests( t, i )
})
def serialize_current_anonymous_user( self, trans, user, keys ):
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
[galaxyproject/usegalaxy-playbook] 42f09d: Update Test and fetch mutable configs.
by GitHub 09 Feb '15
by GitHub 09 Feb '15
09 Feb '15
Branch: refs/heads/master
Home: https://github.com/galaxyproject/usegalaxy-playbook
Commit: 42f09d2438b27080901488ac2a62995bf1a160ee
https://github.com/galaxyproject/usegalaxy-playbook/commit/42f09d2438b27080…
Author: Nate Coraor <nate(a)bx.psu.edu>
Date: 2015-02-09 (Mon, 09 Feb 2015)
Changed paths:
M files/galaxy/test.galaxyproject.org/var/integrated_tool_panel.xml
M files/galaxy/test.galaxyproject.org/var/migrated_tools_conf.xml
M files/galaxy/test.galaxyproject.org/var/shed_tool_conf.xml
M files/galaxy/test.galaxyproject.org/var/shed_tool_data_table_conf.xml
M stage/group_vars/all.yml
Log Message:
-----------
Update Test and fetch mutable configs.
1
0
commit/galaxy-central: carlfeberhard: UI: better defesive prog in metrics logger
by commits-noreply@bitbucket.org 09 Feb '15
by commits-noreply@bitbucket.org 09 Feb '15
09 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9903d7166007/
Changeset: 9903d7166007
User: carlfeberhard
Date: 2015-02-09 16:18:11+00:00
Summary: UI: better defesive prog in metrics logger
Affected #: 3 files
diff -r 2b238c4e79f4f3784e3dd1325c546a4f5377142f -r 9903d71660073038dca04743c8b227bd1a9db5ff client/galaxy/scripts/utils/metrics-logger.js
--- a/client/galaxy/scripts/utils/metrics-logger.js
+++ b/client/galaxy/scripts/utils/metrics-logger.js
@@ -34,7 +34,7 @@
var self = this;
///** get the current user's id from bootstrapped data or options */
- self.userId = window.bootstrapped? window.bootstrapped.user.id: null;
+ self.userId = ( window.bootstrapped && window.bootstrapped.user )? window.bootstrapped.user.id: null;
self.userId = self.userId || options.userId || null;
/** the (optional) console to emit logs to */
diff -r 2b238c4e79f4f3784e3dd1325c546a4f5377142f -r 9903d71660073038dca04743c8b227bd1a9db5ff static/scripts/packed/utils/metrics-logger.js
--- a/static/scripts/packed/utils/metrics-logger.js
+++ b/static/scripts/packed/utils/metrics-logger.js
@@ -1,1 +1,1 @@
-define([],function(){function i(D){D=D||{};var C=this;C.userId=window.bootstrapped?window.bootstrapped.user.id:null;C.userId=C.userId||D.userId||null;C.consoleLogger=D.consoleLogger||null;C._init(D);return C}i.ALL=0;i.DEBUG=10;i.INFO=20;i.WARN=30;i.ERROR=40;i.METRIC=50;i.NONE=100;i.defaultOptions={logLevel:i.NONE,consoleLevel:i.NONE,defaultNamespace:"Galaxy",clientPrefix:"client.",maxCacheSize:3000,postSize:1000,addTime:true,cacheKeyPrefix:"logs-",postUrl:"/api/metrics",delayPostInMs:1000*60*10,getPingData:undefined,onServerResponse:undefined};i.prototype._init=function j(E){var D=this;D.options={};for(var C in i.defaultOptions){if(i.defaultOptions.hasOwnProperty(C)){D.options[C]=(E.hasOwnProperty(C))?(E[C]):(i.defaultOptions[C])}}D.options.logLevel=D._parseLevel(D.options.logLevel);D.options.consoleLevel=D._parseLevel(D.options.consoleLevel);D._sending=false;D._waiting=null;D._postSize=D.options.postSize;D._initCache();return D};i.prototype._initCache=function a(){try{this.cache=new z({maxSize:this.options.maxCacheSize,key:this.options.cacheKeyPrefix+this.userId})}catch(C){this._emitToConsole("warn","MetricsLogger",["Could not intitialize logging cache:",C]);this.options.logLevel=i.NONE}};i.prototype._parseLevel=function n(E){var D=typeof E;if(D==="number"){return E}if(D==="string"){var C=E.toUpperCase();if(i.hasOwnProperty(C)){return i[C]}}throw new Error("Unknown log level: "+E)};i.prototype.emit=function q(F,E,D){var C=this;E=E||C.options.defaultNamespace;if(!F||!D){return C}F=C._parseLevel(F);if(F>=C.options.logLevel){C._addToCache(F,E,D)}if(C.consoleLogger&&F>=C.options.consoleLevel){C._emitToConsole(F,E,D)}return C};i.prototype._addToCache=function b(H,E,D){this._emitToConsole("debug","MetricsLogger",["_addToCache:",arguments,this.options.addTime,this.cache.length()]);var C=this;try{var G=C.cache.add(C._buildEntry(H,E,D));if(G>=C._postSize){C._postCache()}}catch(F){C._emitToConsole("warn","MetricsLogger",["Metrics logger could not stringify logArguments:",E,D]);C._emitToConsole("error","MetricsLogger",[F])}return C};i.prototype._buildEntry=function u(F,D,C){this._emitToConsole("debug","MetricsLogger",["_buildEntry:",arguments]);var E={level:F,namespace:this.options.clientPrefix+D,args:C};if(this.options.addTime){E.time=new Date().toISOString()}return E};i.prototype._postCache=function v(F){F=F||{};this._emitToConsole("info","MetricsLogger",["_postCache",F,this._postSize]);if(!this.options.postUrl||this._sending){return jQuery.when({})}var E=this,H=F.count||E._postSize,C=E.cache.get(H),G=C.length,D=(typeof E.options.getPingData==="function")?(E.options.getPingData()):({});D.metrics=JSON.stringify(C);E._sending=true;return jQuery.post(E.options.postUrl,D).always(function(){E._sending=false}).fail(function(K,I,J){E._postSize=E.options.maxCacheSize;this.emit("error","MetricsLogger",["_postCache error:",K.readyState,K.status,K.responseJSON||K.responseText])}).done(function(I){if(typeof E.options.onServerResponse==="function"){E.options.onServerResponse(I)}E.cache.remove(G);E._postSize=E.options.postSize})};i.prototype._delayPost=function k(){var C=this;C._waiting=setTimeout(function(){C._waiting=null},C.options.delayPostInMs)};i.prototype._emitToConsole=function c(G,F,E){var C=this;if(!C.consoleLogger){return C}var D=Array.prototype.slice.call(E,0);D.unshift(F);if(G>=i.METRIC&&typeof(C.consoleLogger.info)==="function"){return C.consoleLogger.info.apply(C.consoleLogger,D)}else{if(G>=i.ERROR&&typeof(C.consoleLogger.error)==="function"){return C.consoleLogger.error.apply(C.consoleLogger,D)}else{if(G>=i.WARN&&typeof(C.consoleLogger.warn)==="function"){C.consoleLogger.warn.apply(C.consoleLogger,D)}else{if(G>=i.INFO&&typeof(C.consoleLogger.info)==="function"){C.consoleLogger.info.apply(C.consoleLogger,D)}else{if(G>=i.DEBUG&&typeof(C.consoleLogger.debug)==="function"){C.consoleLogger.debug.apply(C.consoleLogger,D)}else{if(typeof(C.consoleLogger.log)==="function"){C.consoleLogger.log.apply(C.consoleLogger,D)}}}}}}return C};i.prototype.log=function h(){this.emit(1,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.debug=function p(){this.emit(i.DEBUG,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.info=function x(){this.emit(i.INFO,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.warn=function w(){this.emit(i.WARN,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.error=function t(){this.emit(i.ERROR,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.metric=function r(){this.emit(i.METRIC,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};function z(D){var C=this;return C._init(D||{})}z.defaultOptions={maxSize:5000};z.prototype._init=function j(C){if(!this._hasStorage()){throw new Error("LoggingCache needs localStorage")}if(!C.key){throw new Error("LoggingCache needs key for localStorage")}this.key=C.key;this._initStorage();this.maxSize=C.maxSize||z.defaultOptions.maxSize;return this};z.prototype._hasStorage=function A(){var D="test";try{localStorage.setItem(D,D);localStorage.removeItem(D);return true}catch(C){return false}};z.prototype._initStorage=function m(){if(localStorage.getItem(this.key)===null){return this.empty()}return this};z.prototype.add=function o(E){var D=this,F=D._fetchAndParse(),C=(F.length+1)-D.maxSize;if(C>0){F.splice(0,C)}F.push(E);D._unparseAndStore(F);return F.length};z.prototype._fetchAndParse=function g(){var C=this;return JSON.parse(localStorage.getItem(C.key))};z.prototype._unparseAndStore=function f(C){var D=this;return localStorage.setItem(D.key,JSON.stringify(C))};z.prototype.length=function e(){return this._fetchAndParse().length};z.prototype.get=function y(C){return this._fetchAndParse().slice(0,C)};z.prototype.remove=function B(C){var E=this._fetchAndParse(),D=E.splice(0,C);this._unparseAndStore(E);return D};z.prototype.empty=function l(){localStorage.setItem(this.key,"[]");return this};z.prototype.stringify=function s(C){return JSON.stringify(this.get(C))};z.prototype.print=function d(){console.log(JSON.stringify(this._fetchAndParse(),null," "))};return{MetricsLogger:i,LoggingCache:z}});
\ No newline at end of file
+define([],function(){function i(D){D=D||{};var C=this;C.userId=(window.bootstrapped&&window.bootstrapped.user)?window.bootstrapped.user.id:null;C.userId=C.userId||D.userId||null;C.consoleLogger=D.consoleLogger||null;C._init(D);return C}i.ALL=0;i.DEBUG=10;i.INFO=20;i.WARN=30;i.ERROR=40;i.METRIC=50;i.NONE=100;i.defaultOptions={logLevel:i.NONE,consoleLevel:i.NONE,defaultNamespace:"Galaxy",clientPrefix:"client.",maxCacheSize:3000,postSize:1000,addTime:true,cacheKeyPrefix:"logs-",postUrl:"/api/metrics",delayPostInMs:1000*60*10,getPingData:undefined,onServerResponse:undefined};i.prototype._init=function j(E){var D=this;D.options={};for(var C in i.defaultOptions){if(i.defaultOptions.hasOwnProperty(C)){D.options[C]=(E.hasOwnProperty(C))?(E[C]):(i.defaultOptions[C])}}D.options.logLevel=D._parseLevel(D.options.logLevel);D.options.consoleLevel=D._parseLevel(D.options.consoleLevel);D._sending=false;D._waiting=null;D._postSize=D.options.postSize;D._initCache();return D};i.prototype._initCache=function a(){try{this.cache=new z({maxSize:this.options.maxCacheSize,key:this.options.cacheKeyPrefix+this.userId})}catch(C){this._emitToConsole("warn","MetricsLogger",["Could not intitialize logging cache:",C]);this.options.logLevel=i.NONE}};i.prototype._parseLevel=function n(E){var D=typeof E;if(D==="number"){return E}if(D==="string"){var C=E.toUpperCase();if(i.hasOwnProperty(C)){return i[C]}}throw new Error("Unknown log level: "+E)};i.prototype.emit=function q(F,E,D){var C=this;E=E||C.options.defaultNamespace;if(!F||!D){return C}F=C._parseLevel(F);if(F>=C.options.logLevel){C._addToCache(F,E,D)}if(C.consoleLogger&&F>=C.options.consoleLevel){C._emitToConsole(F,E,D)}return C};i.prototype._addToCache=function b(H,E,D){this._emitToConsole("debug","MetricsLogger",["_addToCache:",arguments,this.options.addTime,this.cache.length()]);var C=this;try{var G=C.cache.add(C._buildEntry(H,E,D));if(G>=C._postSize){C._postCache()}}catch(F){C._emitToConsole("warn","MetricsLogger",["Metrics logger could not stringify logArguments:",E,D]);C._emitToConsole("error","MetricsLogger",[F])}return C};i.prototype._buildEntry=function u(F,D,C){this._emitToConsole("debug","MetricsLogger",["_buildEntry:",arguments]);var E={level:F,namespace:this.options.clientPrefix+D,args:C};if(this.options.addTime){E.time=new Date().toISOString()}return E};i.prototype._postCache=function v(F){F=F||{};this._emitToConsole("info","MetricsLogger",["_postCache",F,this._postSize]);if(!this.options.postUrl||this._sending){return jQuery.when({})}var E=this,H=F.count||E._postSize,C=E.cache.get(H),G=C.length,D=(typeof E.options.getPingData==="function")?(E.options.getPingData()):({});D.metrics=JSON.stringify(C);E._sending=true;return jQuery.post(E.options.postUrl,D).always(function(){E._sending=false}).fail(function(K,I,J){E._postSize=E.options.maxCacheSize;this.emit("error","MetricsLogger",["_postCache error:",K.readyState,K.status,K.responseJSON||K.responseText])}).done(function(I){if(typeof E.options.onServerResponse==="function"){E.options.onServerResponse(I)}E.cache.remove(G);E._postSize=E.options.postSize})};i.prototype._delayPost=function k(){var C=this;C._waiting=setTimeout(function(){C._waiting=null},C.options.delayPostInMs)};i.prototype._emitToConsole=function c(G,F,E){var C=this;if(!C.consoleLogger){return C}var D=Array.prototype.slice.call(E,0);D.unshift(F);if(G>=i.METRIC&&typeof(C.consoleLogger.info)==="function"){return C.consoleLogger.info.apply(C.consoleLogger,D)}else{if(G>=i.ERROR&&typeof(C.consoleLogger.error)==="function"){return C.consoleLogger.error.apply(C.consoleLogger,D)}else{if(G>=i.WARN&&typeof(C.consoleLogger.warn)==="function"){C.consoleLogger.warn.apply(C.consoleLogger,D)}else{if(G>=i.INFO&&typeof(C.consoleLogger.info)==="function"){C.consoleLogger.info.apply(C.consoleLogger,D)}else{if(G>=i.DEBUG&&typeof(C.consoleLogger.debug)==="function"){C.consoleLogger.debug.apply(C.consoleLogger,D)}else{if(typeof(C.consoleLogger.log)==="function"){C.consoleLogger.log.apply(C.consoleLogger,D)}}}}}}return C};i.prototype.log=function h(){this.emit(1,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.debug=function p(){this.emit(i.DEBUG,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.info=function x(){this.emit(i.INFO,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.warn=function w(){this.emit(i.WARN,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.error=function t(){this.emit(i.ERROR,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.metric=function r(){this.emit(i.METRIC,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};function z(D){var C=this;return C._init(D||{})}z.defaultOptions={maxSize:5000};z.prototype._init=function j(C){if(!this._hasStorage()){throw new Error("LoggingCache needs localStorage")}if(!C.key){throw new Error("LoggingCache needs key for localStorage")}this.key=C.key;this._initStorage();this.maxSize=C.maxSize||z.defaultOptions.maxSize;return this};z.prototype._hasStorage=function A(){var D="test";try{localStorage.setItem(D,D);localStorage.removeItem(D);return true}catch(C){return false}};z.prototype._initStorage=function m(){if(localStorage.getItem(this.key)===null){return this.empty()}return this};z.prototype.add=function o(E){var D=this,F=D._fetchAndParse(),C=(F.length+1)-D.maxSize;if(C>0){F.splice(0,C)}F.push(E);D._unparseAndStore(F);return F.length};z.prototype._fetchAndParse=function g(){var C=this;return JSON.parse(localStorage.getItem(C.key))};z.prototype._unparseAndStore=function f(C){var D=this;return localStorage.setItem(D.key,JSON.stringify(C))};z.prototype.length=function e(){return this._fetchAndParse().length};z.prototype.get=function y(C){return this._fetchAndParse().slice(0,C)};z.prototype.remove=function B(C){var E=this._fetchAndParse(),D=E.splice(0,C);this._unparseAndStore(E);return D};z.prototype.empty=function l(){localStorage.setItem(this.key,"[]");return this};z.prototype.stringify=function s(C){return JSON.stringify(this.get(C))};z.prototype.print=function d(){console.log(JSON.stringify(this._fetchAndParse(),null," "))};return{MetricsLogger:i,LoggingCache:z}});
\ No newline at end of file
diff -r 2b238c4e79f4f3784e3dd1325c546a4f5377142f -r 9903d71660073038dca04743c8b227bd1a9db5ff static/scripts/utils/metrics-logger.js
--- a/static/scripts/utils/metrics-logger.js
+++ b/static/scripts/utils/metrics-logger.js
@@ -34,7 +34,7 @@
var self = this;
///** get the current user's id from bootstrapped data or options */
- self.userId = window.bootstrapped? window.bootstrapped.user.id: null;
+ self.userId = ( window.bootstrapped && window.bootstrapped.user )? window.bootstrapped.user.id: null;
self.userId = self.userId || options.userId || null;
/** the (optional) console to emit logs to */
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: Visualizations, scatterplot: update handlebars since server runtime was updated
by commits-noreply@bitbucket.org 09 Feb '15
by commits-noreply@bitbucket.org 09 Feb '15
09 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2b238c4e79f4/
Changeset: 2b238c4e79f4
User: carlfeberhard
Date: 2015-02-09 16:02:31+00:00
Summary: Visualizations, scatterplot: update handlebars since server runtime was updated
Affected #: 2 files
diff -r d020537061694aabfc7d3786aeec419a0ed318de -r 2b238c4e79f4f3784e3dd1325c546a4f5377142f config/plugins/visualizations/scatterplot/package.json
--- a/config/plugins/visualizations/scatterplot/package.json
+++ b/config/plugins/visualizations/scatterplot/package.json
@@ -16,8 +16,8 @@
"devDependencies": {
"grunt": "~0.4.1",
"grunt-cli": "~0.1.9",
- "grunt-contrib-handlebars": "~0.5.10",
"grunt-contrib-concat": "~0.3.0",
+ "grunt-contrib-handlebars": "^0.9.3",
"grunt-contrib-uglify": "~0.2.2",
"grunt-contrib-watch": "~0.5.3"
}
diff -r d020537061694aabfc7d3786aeec419a0ed318de -r 2b238c4e79f4f3784e3dd1325c546a4f5377142f config/plugins/visualizations/scatterplot/static/scatterplot-edit.js
--- a/config/plugins/visualizations/scatterplot/static/scatterplot-edit.js
+++ b/config/plugins/visualizations/scatterplot/static/scatterplot-edit.js
@@ -1,1 +1,1 @@
-function scatterplot(a,b,c){function d(){var a={v:{},h:{}};return a.v.lines=p.selectAll("line.v-grid-line").data(m.x.ticks(q.x.fn.ticks()[0])),a.v.lines.enter().append("svg:line").classed("grid-line v-grid-line",!0),a.v.lines.attr("x1",m.x).attr("x2",m.x).attr("y1",0).attr("y2",b.height),a.v.lines.exit().remove(),a.h.lines=p.selectAll("line.h-grid-line").data(m.y.ticks(q.y.fn.ticks()[0])),a.h.lines.enter().append("svg:line").classed("grid-line h-grid-line",!0),a.h.lines.attr("x1",0).attr("x2",b.width).attr("y1",m.y).attr("y2",m.y),a.h.lines.exit().remove(),a}function e(){return t.attr("cx",function(a,b){return m.x(j(a,b))}).attr("cy",function(a,b){return m.y(k(a,b))}).style("display","block").filter(function(){var a=d3.select(this).attr("cx"),c=d3.select(this).attr("cy");return 0>a||a>b.width?!0:0>c||c>b.height?!0:!1}).style("display","none")}function f(){$(".chart-info-box").remove(),q.redraw(),e(),s=d(),$(o.node()).trigger("zoom.scatterplot",{scale:n.scale(),translate:n.translate()})}function g(a,c,d){return c+=8,$(['<div class="chart-info-box" style="position: absolute">',void 0!==b.idColumn?"<div>"+d[b.idColumn]+"</div>":"","<div>",j(d),"</div>","<div>",k(d),"</div>","</div>"].join("")).css({top:a,left:c,"z-index":2})}var h=function(a,b){return"translate("+a+","+b+")"},i=function(a,b,c){return"rotate("+a+","+b+","+c+")"},j=function(a){return a[b.xColumn]},k=function(a){return a[b.yColumn]},l={x:{extent:d3.extent(c,j)},y:{extent:d3.extent(c,k)}},m={x:d3.scale.linear().domain(l.x.extent).range([0,b.width]),y:d3.scale.linear().domain(l.y.extent).range([b.height,0])},n=d3.behavior.zoom().x(m.x).y(m.y).scaleExtent([1,30]).scale(b.scale||1).translate(b.translate||[0,0]),o=d3.select(a).attr("class","scatterplot").attr("width","100%").attr("height",b.height+(b.margin.top+b.margin.bottom)),p=o.append("g").attr("class","content").attr("transform",h(b.margin.left,b.margin.top)).call(n);p.append("rect").attr("class","zoom-rect").attr("width",b.width).attr("height",b.height).style("fill","transparent");var q={x:{},y:{}};q.x.fn=d3.svg.axis().orient("bottom").scale(m.x).ticks(b.xTicks).tickFormat(d3.format("s")),q.y.fn=d3.svg.axis().orient("left").scale(m.y).ticks(b.yTicks).tickFormat(d3.format("s")),q.x.g=p.append("g").attr("class","x axis").attr("transform",h(0,b.height)).call(q.x.fn),q.y.g=p.append("g").attr("class","y axis").call(q.y.fn);var r=6;q.x.label=o.append("text").attr("id","x-axis-label").attr("class","axis-label").text(b.xLabel).attr("text-anchor","middle").attr("dominant-baseline","text-after-edge").attr("x",b.width/2+b.margin.left).attr("y",b.height+b.margin.bottom+b.margin.top-r),q.y.label=o.append("text").attr("id","y-axis-label").attr("class","axis-label").text(b.yLabel).attr("text-anchor","middle").attr("dominant-baseline","text-before-edge").attr("x",r).attr("y",b.height/2).attr("transform",i(-90,r,b.height/2)),q.redraw=function(){o.select(".x.axis").call(q.x.fn),o.select(".y.axis").call(q.y.fn)};var s=d(),t=p.selectAll(".glyph").data(c).enter().append("svg:circle").classed("glyph",!0).attr("cx",function(a,b){return m.x(j(a,b))}).attr("cy",function(a,b){return m.y(k(a,b))}).attr("r",0);t.transition().duration(b.animDuration).attr("r",b.datapointSize),e(),n.on("zoom",f),t.on("mouseover",function(a,c){var d=d3.select(this);d.classed("highlight",!0).style("fill","red").style("fill-opacity",1),p.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",d.attr("cx")-b.datapointSize).attr("y1",d.attr("cy")).attr("x2",0).attr("y2",d.attr("cy")).classed("hoverline",!0),d.attr("cy")<b.height&&p.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",d.attr("cx")).attr("y1",+d.attr("cy")+b.datapointSize).attr("x2",d.attr("cx")).attr("y2",b.height).classed("hoverline",!0);var e=this.getBoundingClientRect();$("body").append(g(e.top,e.right,a)),$(o.node()).trigger("mouseover-datapoint.scatterplot",[this,a,c])}),t.on("mouseout",function(){d3.select(this).classed("highlight",!1).style("fill","black").style("fill-opacity",.2),p.selectAll(".hoverline").remove(),$(".chart-info-box").remove()})}this.scatterplot=this.scatterplot||{},this.scatterplot.chartcontrol=Handlebars.template(function(a,b,c,d,e){this.compilerInfo=[4,">= 1.0.0"],c=this.merge(c,a.helpers),e=e||{};var f,g="",h="function",i=this.escapeExpression;return g+='<p class="help-text">\n Use the following controls to how the chart is displayed.\n The slide controls can be moved by the mouse or, if the \'handle\' is in focus, your keyboard\'s arrow keys.\n Move the focus between controls by using the tab or shift+tab keys on your keyboard.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n</p>\n\n<div data-config-key="datapointSize" class="form-input numeric-slider-input">\n <label for="datapointSize">Size of data point: </label>\n <div class="slider-output">',(f=c.datapointSize)?f=f.call(b,{hash:{},data:e}):(f=b.datapointSize,f=typeof f===h?f.apply(b):f),g+=i(f)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n Size of the graphic representation of each data point\n </p>\n</div>\n\n<div data-config-key="width" class="form-input numeric-slider-input">\n <label for="width">Chart width: </label>\n <div class="slider-output">',(f=c.width)?f=f.call(b,{hash:{},data:e}):(f=b.width,f=typeof f===h?f.apply(b):f),g+=i(f)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart margins and axes)\n </p>\n</div>\n\n<div data-config-key="height" class="form-input numeric-slider-input">\n <label for="height">Chart height: </label>\n <div class="slider-output">',(f=c.height)?f=f.call(b,{hash:{},data:e}):(f=b.height,f=typeof f===h?f.apply(b):f),g+=i(f)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart margins and axes)\n </p>\n</div>\n\n<div data-config-key="X-axis-label"class="text-input form-input">\n <label for="X-axis-label">Re-label the X axis: </label>\n <input type="text" name="X-axis-label" id="X-axis-label" value="',(f=c.xLabel)?f=f.call(b,{hash:{},data:e}):(f=b.xLabel,f=typeof f===h?f.apply(b):f),g+=i(f)+'" />\n <p class="form-help help-text-small"></p>\n</div>\n\n<div data-config-key="Y-axis-label" class="text-input form-input">\n <label for="Y-axis-label">Re-label the Y axis: </label>\n <input type="text" name="Y-axis-label" id="Y-axis-label" value="',(f=c.yLabel)?f=f.call(b,{hash:{},data:e}):(f=b.yLabel,f=typeof f===h?f.apply(b):f),g+=i(f)+'" />\n <p class="form-help help-text-small"></p>\n</div>\n\n<button class="render-button btn btn-primary active">Draw</button>\n'}),this.scatterplot.datacontrol=Handlebars.template(function(a,b,c,d,e){this.compilerInfo=[4,">= 1.0.0"],c=this.merge(c,a.helpers),e=e||{};var f,g="",h="function";return g+='<p class="help-text">\n Use the following control to change which columns are used by the chart. Click any cell\n from the last three rows of the table to select the column for the appropriate data.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n</p>\n\n<ul class="help-text" style="margin-left: 8px">\n <li><b>X Column</b>: which column values will be used for the x axis of the chart.</li>\n <li><b>Y Column</b>: which column values will be used for the y axis of the chart.</li>\n <li><b>ID Column</b>: an additional column value displayed when the user hovers over a data point.\n It may be useful to select unique or categorical identifiers here (such as gene ids).\n </li>\n</ul>\n\n<div class="column-selection">\n <pre class="peek">',(f=c.peek)?f=f.call(b,{hash:{},data:e}):(f=b.peek,f=typeof f===h?f.apply(b):f),(f||0===f)&&(g+=f),g+='</pre>\n</div>\n\n<p class="help-text help-text-small">\n <b>Note</b>: If it can be determined from the dataset\'s filetype that a column is not numeric,\n that column choice may be disabled for either the x or y axis.\n</p>\n\n<button class="render-button btn btn-primary active">Draw</button>\n'}),this.scatterplot.editor=Handlebars.template(function(a,b,c,d,e){this.compilerInfo=[4,">= 1.0.0"],c=this.merge(c,a.helpers),e=e||{};var f="";return f+='<div class="scatterplot-editor tabbable tabs-left">\n \n <ul class="nav nav-tabs">\n \n <li class="active">\n <a title="Use this tab to change which data are used"\n href="#data-control" data-toggle="tab">Data Controls</a>\n </li>\n <li>\n <a title="Use this tab to change how the chart is drawn"\n href="#chart-control" data-toggle="tab" >Chart Controls</a>\n </li>\n \n <li class="disabled">\n <a title="This tab will display the chart"\n href="#chart-display" data-toggle="tab">Chart</a>\n </li>\n \n <li class="file-controls">\n<!-- <button class="copy-btn btn btn-default"\n title="Save this as a new visualization">Save to new</button>-->\n <button class="save-btn btn btn-default">Save</button>\n </li>\n </ul>\n\n \n <div class="tab-content">\n \n <div id="data-control" class="scatterplot-config-control tab-pane active">\n \n </div>\n \n \n <div id="chart-control" class="scatterplot-config-control tab-pane">\n \n </div>\n\n \n <div id="chart-display" class="scatterplot-display tab-pane"></div>\n\n </div>\n</div>\n'});var ScatterplotConfigEditor=Backbone.View.extend({className:"scatterplot-control-form",initialize:function(a){if(this.model||(this.model=new Visualization({type:"scatterplot"})),!a||!a.dataset)throw new Error("ScatterplotConfigEditor requires a dataset");this.dataset=a.dataset,this.display=new ScatterplotDisplay({dataset:a.dataset,model:this.model})},render:function(){this.$el.empty().append(ScatterplotConfigEditor.templates.mainLayout({})),this.model.id&&(this.$el.find(".copy-btn").show(),this.$el.find(".save-btn").text("Update saved")),this.$el.find("[title]").tooltip(),this._render_dataControl(),this._render_chartControls(),this._render_chartDisplay();var a=this.model.get("config");return this.model.id&&_.isFinite(a.xColumn)&&_.isFinite(a.yColumn)&&this.renderChart(),this},_getColumnIndecesByType:function(){var a={numeric:[],text:[],all:[]};return _.each(this.dataset.metadata_column_types||[],function(b,c){"int"===b||"float"===b?a.numeric.push(c):("str"===b||"list"===b)&&a.text.push(c),a.all.push(c)}),a.numeric.length<2&&(a.numeric=[]),a},_render_dataControl:function(a){a=a||this.$el;var b=this,c=this.model.get("config"),d=this._getColumnIndecesByType(),e=a.find(".tab-pane#data-control");return e.html(ScatterplotConfigEditor.templates.dataControl({peek:this.dataset.peek})),e.find(".peek").peekColumnSelector({controls:[{label:"X Column",id:"xColumn",selected:c.xColumn,disabled:d.text},{label:"Y Column",id:"yColumn",selected:c.yColumn,disabled:d.text},{label:"ID Column",id:"idColumn",selected:c.idColumn}]}).on("peek-column-selector.change",function(a,c){b.model.set("config",c)}).on("peek-column-selector.rename",function(){}),e.find("[title]").tooltip(),e},_render_chartControls:function(a){function b(){var a=$(this),b=a.slider("value");c.model.set("config",_.object([[a.parent().data("config-key"),b]])),a.siblings(".slider-output").text(b)}a=a||this.$el;var c=this,d=this.model.get("config"),e=a.find("#chart-control");e.html(ScatterplotConfigEditor.templates.chartControl(d));var f={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};e.find(".numeric-slider-input").each(function(){var a=$(this),c=a.attr("data-config-key"),e=_.extend(f[c],{value:d[c],change:b,slide:b});a.find(".slider").slider(e),a.children(".slider-output").text(d[c])});var g=this.dataset.metadata_column_names||[],h=d.xLabel||g[d.xColumn]||"X",i=d.yLabel||g[d.yColumn]||"Y";return e.find('input[name="X-axis-label"]').val(h).on("change",function(){c.model.set("config",{xLabel:$(this).val()})}),e.find('input[name="Y-axis-label"]').val(i).on("change",function(){c.model.set("config",{yLabel:$(this).val()})}),e.find("[title]").tooltip(),e},_render_chartDisplay:function(a){a=a||this.$el;var b=a.find(".tab-pane#chart-display");return this.display.setElement(b),this.display.render(),b.find("[title]").tooltip(),b},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","click #data-control .render-button":"renderChart","click #chart-control .render-button":"renderChart","click .save-btn":"saveVisualization"},saveVisualization:function(){var a=this;this.model.save().fail(function(b,c,d){console.error(b,c,d),a.trigger("save:error",view),alert("Error loading data:\n"+b.responseText)}).then(function(){a.display.render()})},toggleThirdColumnSelector:function(){this.$el.find('select[name="idColumn"]').parent().toggle()},renderChart:function(){this.$el.find(".nav li.disabled").removeClass("disabled"),this.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show"),this.display.fetchData()},toString:function(){return"ScatterplotConfigEditor("+(this.dataset?this.dataset.id:"")+")"}});ScatterplotConfigEditor.templates={mainLayout:scatterplot.editor,dataControl:scatterplot.datacontrol,chartControl:scatterplot.chartcontrol};var ScatterplotDisplay=Backbone.View.extend({initialize:function(a){this.data=null,this.dataset=a.dataset,this.lineCount=this.dataset.metadata_data_lines||null},fetchData:function(){this.showLoadingIndicator();var a=this,b=this.model.get("config"),c=jQuery.getJSON("/api/datasets/"+this.dataset.id,{data_type:"raw_data",provider:"dataset-column",limit:b.pagination.perPage,offset:b.pagination.currPage*b.pagination.perPage});return c.done(function(b){a.data=b.data,a.trigger("data:fetched",a),a.renderData()}),c.fail(function(b,c,d){console.error(b,c,d),a.trigger("data:error",a),alert("Error loading data:\n"+b.responseText)}),c},showLoadingIndicator:function(){this.$el.find(".scatterplot-data-info").html(['<div class="loading-indicator">','<span class="fa fa-spinner fa-spin"></span>','<span class="loading-indicator-message">loading...</span>',"</div>"].join(""))},template:function(){var a=['<div class="controls clear">','<div class="right">','<p class="scatterplot-data-info"></p>','<button class="stats-toggle-btn">Stats</button>','<button class="rerender-btn">Redraw</button>',"</div>",'<div class="left">','<div class="page-control"></div>',"</div>","</div>","<svg/>",'<div class="stats-display"></div>'].join("");return a},render:function(){return this.$el.addClass("scatterplot-display").html(this.template()),this.data&&this.renderData(),this},renderData:function(){this.renderLeftControls(),this.renderRightControls(),this.renderPlot(this.data),this.getStats()},renderLeftControls:function(){var a=this,b=this.model.get("config");return this.$el.find(".controls .left .page-control").pagination({startingPage:b.pagination.currPage,perPage:b.pagination.perPage,totalDataSize:this.lineCount,currDataSize:this.data.length}).off().on("pagination.page-change",function(c,d){b.pagination.currPage=d,a.model.set("config",{pagination:b.pagination}),a.resetZoom(),a.fetchData()}),this},renderRightControls:function(){var a=this;this.setLineInfo(this.data),this.$el.find(".stats-toggle-btn").off().click(function(){a.toggleStats()}),this.$el.find(".rerender-btn").off().click(function(){a.resetZoom(),a.renderPlot(this.data)})},renderPlot:function(){var a=this,b=this.$el.find("svg");this.toggleStats(!1),b.off().empty().show().on("zoom.scatterplot",function(b,c){a.model.set("config",c)}),scatterplot(b.get(0),this.model.get("config"),this.data)},setLineInfo:function(a,b){if(a){var c=this.model.get("config"),d=this.lineCount||"an unknown total",e=c.pagination.currPage*c.pagination.perPage,f=e+a.length;this.$el.find(".controls p.scatterplot-data-info").text([e+1,"to",f,"of",d].join(" "))}else this.$el.find(".controls p.scatterplot-data-info").html(b||"");return this},resetZoom:function(a,b){return a=void 0!==a?a:1,b=void 0!==b?b:[0,0],this.model.set("config",{scale:a,translate:b}),this},getStats:function(){if(this.data){var a=this,b=this.model.get("config"),c=new Worker("/plugins/visualizations/scatterplot/static/worker-stats.js");c.postMessage({data:this.data,keys:[b.xColumn,b.yColumn]}),c.onerror=function(){c.terminate()},c.onmessage=function(b){a.renderStats(b.data)}}},renderStats:function(a){var b=this.model.get("config"),c=this.$el.find(".stats-display"),d=b.xLabel,e=b.yLabel,f=$("<table/>").addClass("table").append(["<thead><th></th><th>",d,"</th><th>",e,"</th></thead>"].join("")).append(_.map(a,function(a,b){return $(["<tr><td>",b,"</td><td>",a[0],"</td><td>",a[1],"</td></tr>"].join(""))}));c.empty().append(f)},toggleStats:function(a){var b=this.$el.find(".stats-display");a=void 0===a?b.is(":hidden"):a,a?(this.$el.find("svg").hide(),b.show(),this.$el.find(".controls .stats-toggle-btn").text("Plot")):(b.hide(),this.$el.find("svg").show(),this.$el.find(".controls .stats-toggle-btn").text("Stats"))},toString:function(){return"ScatterplotView()"}}),ScatterplotModel=Visualization.extend({defaults:{type:"scatterplot",config:{pagination:{currPage:0,perPage:3e3},width:400,height:400,margin:{top:16,right:16,bottom:40,left:54},xTicks:10,xLabel:"X",yTicks:10,yLabel:"Y",datapointSize:4,animDuration:500,scale:1,translate:[0,0]}}});
\ No newline at end of file
+function scatterplot(a,b,c){function d(){var a={v:{},h:{}};return a.v.lines=p.selectAll("line.v-grid-line").data(m.x.ticks(q.x.fn.ticks()[0])),a.v.lines.enter().append("svg:line").classed("grid-line v-grid-line",!0),a.v.lines.attr("x1",m.x).attr("x2",m.x).attr("y1",0).attr("y2",b.height),a.v.lines.exit().remove(),a.h.lines=p.selectAll("line.h-grid-line").data(m.y.ticks(q.y.fn.ticks()[0])),a.h.lines.enter().append("svg:line").classed("grid-line h-grid-line",!0),a.h.lines.attr("x1",0).attr("x2",b.width).attr("y1",m.y).attr("y2",m.y),a.h.lines.exit().remove(),a}function e(){return t.attr("cx",function(a,b){return m.x(j(a,b))}).attr("cy",function(a,b){return m.y(k(a,b))}).style("display","block").filter(function(){var a=d3.select(this).attr("cx"),c=d3.select(this).attr("cy");return 0>a||a>b.width?!0:0>c||c>b.height?!0:!1}).style("display","none")}function f(){$(".chart-info-box").remove(),q.redraw(),e(),s=d(),$(o.node()).trigger("zoom.scatterplot",{scale:n.scale(),translate:n.translate()})}function g(a,c,d){return c+=8,$(['<div class="chart-info-box" style="position: absolute">',void 0!==b.idColumn?"<div>"+d[b.idColumn]+"</div>":"","<div>",j(d),"</div>","<div>",k(d),"</div>","</div>"].join("")).css({top:a,left:c,"z-index":2})}var h=function(a,b){return"translate("+a+","+b+")"},i=function(a,b,c){return"rotate("+a+","+b+","+c+")"},j=function(a){return a[b.xColumn]},k=function(a){return a[b.yColumn]},l={x:{extent:d3.extent(c,j)},y:{extent:d3.extent(c,k)}},m={x:d3.scale.linear().domain(l.x.extent).range([0,b.width]),y:d3.scale.linear().domain(l.y.extent).range([b.height,0])},n=d3.behavior.zoom().x(m.x).y(m.y).scaleExtent([1,30]).scale(b.scale||1).translate(b.translate||[0,0]),o=d3.select(a).attr("class","scatterplot").attr("width","100%").attr("height",b.height+(b.margin.top+b.margin.bottom)),p=o.append("g").attr("class","content").attr("transform",h(b.margin.left,b.margin.top)).call(n);p.append("rect").attr("class","zoom-rect").attr("width",b.width).attr("height",b.height).style("fill","transparent");var q={x:{},y:{}};q.x.fn=d3.svg.axis().orient("bottom").scale(m.x).ticks(b.xTicks).tickFormat(d3.format("s")),q.y.fn=d3.svg.axis().orient("left").scale(m.y).ticks(b.yTicks).tickFormat(d3.format("s")),q.x.g=p.append("g").attr("class","x axis").attr("transform",h(0,b.height)).call(q.x.fn),q.y.g=p.append("g").attr("class","y axis").call(q.y.fn);var r=6;q.x.label=o.append("text").attr("id","x-axis-label").attr("class","axis-label").text(b.xLabel).attr("text-anchor","middle").attr("dominant-baseline","text-after-edge").attr("x",b.width/2+b.margin.left).attr("y",b.height+b.margin.bottom+b.margin.top-r),q.y.label=o.append("text").attr("id","y-axis-label").attr("class","axis-label").text(b.yLabel).attr("text-anchor","middle").attr("dominant-baseline","text-before-edge").attr("x",r).attr("y",b.height/2).attr("transform",i(-90,r,b.height/2)),q.redraw=function(){o.select(".x.axis").call(q.x.fn),o.select(".y.axis").call(q.y.fn)};var s=d(),t=p.selectAll(".glyph").data(c).enter().append("svg:circle").classed("glyph",!0).attr("cx",function(a,b){return m.x(j(a,b))}).attr("cy",function(a,b){return m.y(k(a,b))}).attr("r",0);t.transition().duration(b.animDuration).attr("r",b.datapointSize),e(),n.on("zoom",f),t.on("mouseover",function(a,c){var d=d3.select(this);d.classed("highlight",!0).style("fill","red").style("fill-opacity",1),p.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",d.attr("cx")-b.datapointSize).attr("y1",d.attr("cy")).attr("x2",0).attr("y2",d.attr("cy")).classed("hoverline",!0),d.attr("cy")<b.height&&p.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",d.attr("cx")).attr("y1",+d.attr("cy")+b.datapointSize).attr("x2",d.attr("cx")).attr("y2",b.height).classed("hoverline",!0);var e=this.getBoundingClientRect();$("body").append(g(e.top,e.right,a)),$(o.node()).trigger("mouseover-datapoint.scatterplot",[this,a,c])}),t.on("mouseout",function(){d3.select(this).classed("highlight",!1).style("fill","black").style("fill-opacity",.2),p.selectAll(".hoverline").remove(),$(".chart-info-box").remove()})}this.scatterplot=this.scatterplot||{},this.scatterplot.chartcontrol=Handlebars.template({compiler:[6,">= 2.0.0-beta.1"],main:function(a,b,c,d){var e,f="function",g=b.helperMissing,h=this.escapeExpression;return'<p class="help-text">\n Use the following controls to how the chart is displayed.\n The slide controls can be moved by the mouse or, if the \'handle\' is in focus, your keyboard\'s arrow keys.\n Move the focus between controls by using the tab or shift+tab keys on your keyboard.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n</p>\n\n<div data-config-key="datapointSize" class="form-input numeric-slider-input">\n <label for="datapointSize">Size of data point: </label>\n <div class="slider-output">'+h((e=null!=(e=b.datapointSize||(null!=a?a.datapointSize:a))?e:g,typeof e===f?e.call(a,{name:"datapointSize",hash:{},data:d}):e))+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n Size of the graphic representation of each data point\n </p>\n</div>\n\n<div data-config-key="width" class="form-input numeric-slider-input">\n <label for="width">Chart width: </label>\n <div class="slider-output">'+h((e=null!=(e=b.width||(null!=a?a.width:a))?e:g,typeof e===f?e.call(a,{name:"width",hash:{},data:d}):e))+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart margins and axes)\n </p>\n</div>\n\n<div data-config-key="height" class="form-input numeric-slider-input">\n <label for="height">Chart height: </label>\n <div class="slider-output">'+h((e=null!=(e=b.height||(null!=a?a.height:a))?e:g,typeof e===f?e.call(a,{name:"height",hash:{},data:d}):e))+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart margins and axes)\n </p>\n</div>\n\n<div data-config-key="X-axis-label"class="text-input form-input">\n <label for="X-axis-label">Re-label the X axis: </label>\n <input type="text" name="X-axis-label" id="X-axis-label" value="'+h((e=null!=(e=b.xLabel||(null!=a?a.xLabel:a))?e:g,typeof e===f?e.call(a,{name:"xLabel",hash:{},data:d}):e))+'" />\n <p class="form-help help-text-small"></p>\n</div>\n\n<div data-config-key="Y-axis-label" class="text-input form-input">\n <label for="Y-axis-label">Re-label the Y axis: </label>\n <input type="text" name="Y-axis-label" id="Y-axis-label" value="'+h((e=null!=(e=b.yLabel||(null!=a?a.yLabel:a))?e:g,typeof e===f?e.call(a,{name:"yLabel",hash:{},data:d}):e))+'" />\n <p class="form-help help-text-small"></p>\n</div>\n\n<button class="render-button btn btn-primary active">Draw</button>\n'},useData:!0}),this.scatterplot.datacontrol=Handlebars.template({compiler:[6,">= 2.0.0-beta.1"],main:function(a,b,c,d){var e,f,g="function",h=b.helperMissing,i='<p class="help-text">\n Use the following control to change which columns are used by the chart. Click any cell\n from the last three rows of the table to select the column for the appropriate data.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n</p>\n\n<ul class="help-text" style="margin-left: 8px">\n <li><b>X Column</b>: which column values will be used for the x axis of the chart.</li>\n <li><b>Y Column</b>: which column values will be used for the y axis of the chart.</li>\n <li><b>ID Column</b>: an additional column value displayed when the user hovers over a data point.\n It may be useful to select unique or categorical identifiers here (such as gene ids).\n </li>\n</ul>\n\n<div class="column-selection">\n <pre class="peek">';return f=null!=(f=b.peek||(null!=a?a.peek:a))?f:h,e=typeof f===g?f.call(a,{name:"peek",hash:{},data:d}):f,null!=e&&(i+=e),i+'</pre>\n</div>\n\n<p class="help-text help-text-small">\n <b>Note</b>: If it can be determined from the dataset\'s filetype that a column is not numeric,\n that column choice may be disabled for either the x or y axis.\n</p>\n\n<button class="render-button btn btn-primary active">Draw</button>\n'},useData:!0}),this.scatterplot.editor=Handlebars.template({compiler:[6,">= 2.0.0-beta.1"],main:function(){return'<div class="scatterplot-editor tabbable tabs-left">\n <ul class="nav nav-tabs">\n <li class="active">\n <a title="Use this tab to change which data are used"\n href="#data-control" data-toggle="tab">Data Controls</a>\n </li>\n <li>\n <a title="Use this tab to change how the chart is drawn"\n href="#chart-control" data-toggle="tab" >Chart Controls</a>\n </li>\n <li class="disabled">\n <a title="This tab will display the chart"\n href="#chart-display" data-toggle="tab">Chart</a>\n </li>\n <li class="file-controls">\n<!-- <button class="copy-btn btn btn-default"\n title="Save this as a new visualization">Save to new</button>-->\n <button class="save-btn btn btn-default">Save</button>\n </li>\n </ul>\n\n <div class="tab-content">\n <div id="data-control" class="scatterplot-config-control tab-pane active">\n </div>\n \n <div id="chart-control" class="scatterplot-config-control tab-pane">\n </div>\n\n <div id="chart-display" class="scatterplot-display tab-pane"></div>\n\n </div>\n</div>\n'},useData:!0});var ScatterplotConfigEditor=Backbone.View.extend({className:"scatterplot-control-form",initialize:function(a){if(this.model||(this.model=new Visualization({type:"scatterplot"})),!a||!a.dataset)throw new Error("ScatterplotConfigEditor requires a dataset");this.dataset=a.dataset,this.display=new ScatterplotDisplay({dataset:a.dataset,model:this.model})},render:function(){this.$el.empty().append(ScatterplotConfigEditor.templates.mainLayout({})),this.model.id&&(this.$el.find(".copy-btn").show(),this.$el.find(".save-btn").text("Update saved")),this.$el.find("[title]").tooltip(),this._render_dataControl(),this._render_chartControls(),this._render_chartDisplay();var a=this.model.get("config");return this.model.id&&_.isFinite(a.xColumn)&&_.isFinite(a.yColumn)&&this.renderChart(),this},_getColumnIndecesByType:function(){var a={numeric:[],text:[],all:[]};return _.each(this.dataset.metadata_column_types||[],function(b,c){"int"===b||"float"===b?a.numeric.push(c):("str"===b||"list"===b)&&a.text.push(c),a.all.push(c)}),a.numeric.length<2&&(a.numeric=[]),a},_render_dataControl:function(a){a=a||this.$el;var b=this,c=this.model.get("config"),d=this._getColumnIndecesByType(),e=a.find(".tab-pane#data-control");return e.html(ScatterplotConfigEditor.templates.dataControl({peek:this.dataset.peek})),e.find(".peek").peekColumnSelector({controls:[{label:"X Column",id:"xColumn",selected:c.xColumn,disabled:d.text},{label:"Y Column",id:"yColumn",selected:c.yColumn,disabled:d.text},{label:"ID Column",id:"idColumn",selected:c.idColumn}]}).on("peek-column-selector.change",function(a,c){b.model.set("config",c)}).on("peek-column-selector.rename",function(){}),e.find("[title]").tooltip(),e},_render_chartControls:function(a){function b(){var a=$(this),b=a.slider("value");c.model.set("config",_.object([[a.parent().data("config-key"),b]])),a.siblings(".slider-output").text(b)}a=a||this.$el;var c=this,d=this.model.get("config"),e=a.find("#chart-control");e.html(ScatterplotConfigEditor.templates.chartControl(d));var f={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};e.find(".numeric-slider-input").each(function(){var a=$(this),c=a.attr("data-config-key"),e=_.extend(f[c],{value:d[c],change:b,slide:b});a.find(".slider").slider(e),a.children(".slider-output").text(d[c])});var g=this.dataset.metadata_column_names||[],h=d.xLabel||g[d.xColumn]||"X",i=d.yLabel||g[d.yColumn]||"Y";return e.find('input[name="X-axis-label"]').val(h).on("change",function(){c.model.set("config",{xLabel:$(this).val()})}),e.find('input[name="Y-axis-label"]').val(i).on("change",function(){c.model.set("config",{yLabel:$(this).val()})}),e.find("[title]").tooltip(),e},_render_chartDisplay:function(a){a=a||this.$el;var b=a.find(".tab-pane#chart-display");return this.display.setElement(b),this.display.render(),b.find("[title]").tooltip(),b},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","click #data-control .render-button":"renderChart","click #chart-control .render-button":"renderChart","click .save-btn":"saveVisualization"},saveVisualization:function(){var a=this;this.model.save().fail(function(b,c,d){console.error(b,c,d),a.trigger("save:error",view),alert("Error loading data:\n"+b.responseText)}).then(function(){a.display.render()})},toggleThirdColumnSelector:function(){this.$el.find('select[name="idColumn"]').parent().toggle()},renderChart:function(){this.$el.find(".nav li.disabled").removeClass("disabled"),this.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show"),this.display.fetchData()},toString:function(){return"ScatterplotConfigEditor("+(this.dataset?this.dataset.id:"")+")"}});ScatterplotConfigEditor.templates={mainLayout:scatterplot.editor,dataControl:scatterplot.datacontrol,chartControl:scatterplot.chartcontrol};var ScatterplotDisplay=Backbone.View.extend({initialize:function(a){this.data=null,this.dataset=a.dataset,this.lineCount=this.dataset.metadata_data_lines||null},fetchData:function(){this.showLoadingIndicator();var a=this,b=this.model.get("config"),c=jQuery.getJSON("/api/datasets/"+this.dataset.id,{data_type:"raw_data",provider:"dataset-column",limit:b.pagination.perPage,offset:b.pagination.currPage*b.pagination.perPage});return c.done(function(b){a.data=b.data,a.trigger("data:fetched",a),a.renderData()}),c.fail(function(b,c,d){console.error(b,c,d),a.trigger("data:error",a),alert("Error loading data:\n"+b.responseText)}),c},showLoadingIndicator:function(){this.$el.find(".scatterplot-data-info").html(['<div class="loading-indicator">','<span class="fa fa-spinner fa-spin"></span>','<span class="loading-indicator-message">loading...</span>',"</div>"].join(""))},template:function(){var a=['<div class="controls clear">','<div class="right">','<p class="scatterplot-data-info"></p>','<button class="stats-toggle-btn">Stats</button>','<button class="rerender-btn">Redraw</button>',"</div>",'<div class="left">','<div class="page-control"></div>',"</div>","</div>","<svg/>",'<div class="stats-display"></div>'].join("");return a},render:function(){return this.$el.addClass("scatterplot-display").html(this.template()),this.data&&this.renderData(),this},renderData:function(){this.renderLeftControls(),this.renderRightControls(),this.renderPlot(this.data),this.getStats()},renderLeftControls:function(){var a=this,b=this.model.get("config");return this.$el.find(".controls .left .page-control").pagination({startingPage:b.pagination.currPage,perPage:b.pagination.perPage,totalDataSize:this.lineCount,currDataSize:this.data.length}).off().on("pagination.page-change",function(c,d){b.pagination.currPage=d,a.model.set("config",{pagination:b.pagination}),a.resetZoom(),a.fetchData()}),this},renderRightControls:function(){var a=this;this.setLineInfo(this.data),this.$el.find(".stats-toggle-btn").off().click(function(){a.toggleStats()}),this.$el.find(".rerender-btn").off().click(function(){a.resetZoom(),a.renderPlot(this.data)})},renderPlot:function(){var a=this,b=this.$el.find("svg");this.toggleStats(!1),b.off().empty().show().on("zoom.scatterplot",function(b,c){a.model.set("config",c)}),scatterplot(b.get(0),this.model.get("config"),this.data)},setLineInfo:function(a,b){if(a){var c=this.model.get("config"),d=this.lineCount||"an unknown total",e=c.pagination.currPage*c.pagination.perPage,f=e+a.length;this.$el.find(".controls p.scatterplot-data-info").text([e+1,"to",f,"of",d].join(" "))}else this.$el.find(".controls p.scatterplot-data-info").html(b||"");return this},resetZoom:function(a,b){return a=void 0!==a?a:1,b=void 0!==b?b:[0,0],this.model.set("config",{scale:a,translate:b}),this},getStats:function(){if(this.data){var a=this,b=this.model.get("config"),c=new Worker("/plugins/visualizations/scatterplot/static/worker-stats.js");c.postMessage({data:this.data,keys:[b.xColumn,b.yColumn]}),c.onerror=function(){c.terminate()},c.onmessage=function(b){a.renderStats(b.data)}}},renderStats:function(a){var b=this.model.get("config"),c=this.$el.find(".stats-display"),d=b.xLabel,e=b.yLabel,f=$("<table/>").addClass("table").append(["<thead><th></th><th>",d,"</th><th>",e,"</th></thead>"].join("")).append(_.map(a,function(a,b){return $(["<tr><td>",b,"</td><td>",a[0],"</td><td>",a[1],"</td></tr>"].join(""))}));c.empty().append(f)},toggleStats:function(a){var b=this.$el.find(".stats-display");a=void 0===a?b.is(":hidden"):a,a?(this.$el.find("svg").hide(),b.show(),this.$el.find(".controls .stats-toggle-btn").text("Plot")):(b.hide(),this.$el.find("svg").show(),this.$el.find(".controls .stats-toggle-btn").text("Stats"))},toString:function(){return"ScatterplotView()"}}),ScatterplotModel=Visualization.extend({defaults:{type:"scatterplot",config:{pagination:{currPage:0,perPage:3e3},width:400,height:400,margin:{top:16,right:16,bottom:40,left:54},xTicks:10,xLabel:"X",yTicks:10,yLabel:"Y",datapointSize:4,animDuration:500,scale:1,translate:[0,0]}}});
\ 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: Remove escaping of quotes in the slurm cli status checks, I don't think they should be there (the format args should in fact be quoted).
by commits-noreply@bitbucket.org 09 Feb '15
by commits-noreply@bitbucket.org 09 Feb '15
09 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d02053706169/
Changeset: d02053706169
User: natefoo
Date: 2015-02-09 15:59:36+00:00
Summary: Remove escaping of quotes in the slurm cli status checks, I don't think they should be there (the format args should in fact be quoted).
Affected #: 1 file
diff -r bb9de7bc465630eb3f8d055df573a9007f670914 -r d020537061694aabfc7d3786aeec419a0ed318de lib/galaxy/jobs/runners/util/cli/job/slurm.py
--- a/lib/galaxy/jobs/runners/util/cli/job/slurm.py
+++ b/lib/galaxy/jobs/runners/util/cli/job/slurm.py
@@ -7,7 +7,7 @@
except ImportError:
# Not in Galaxy, map Galaxy job states to Pulsar ones.
from galaxy.util import enum
- job_states = enum(RUNNING='running', OK='complete', QUEUED='queued')
+ job_states = enum(RUNNING='running', OK='complete', QUEUED='queued', ERROR="failed")
from ..job import BaseJobExec
@@ -59,10 +59,10 @@
return 'scancel %s' % job_id
def get_status(self, job_ids=None):
- return 'squeue -a -o \\"%A %t\\"'
+ return "squeue -a -o '%A %t'"
def get_single_status(self, job_id):
- return 'squeue -a -o \\"%A %t\\" -j ' + job_id
+ return "squeue -a -o '%A %t' -j " + job_id
def parse_status(self, status, job_ids):
# Get status for each job, skipping header.
@@ -80,6 +80,7 @@
# Job still on cluster and has state.
id, state = status[1].split()
return self._get_job_state(state)
+ # else line like "slurm_load_jobs error: Invalid job id specified"
return job_states.OK
def _get_job_state(self, state):
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: Dataproviders, column: allow filtering data by parsed column values (numeric, list, and string)
by commits-noreply@bitbucket.org 09 Feb '15
by commits-noreply@bitbucket.org 09 Feb '15
09 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/bb9de7bc4656/
Changeset: bb9de7bc4656
User: carlfeberhard
Date: 2015-02-09 15:36:43+00:00
Summary: Dataproviders, column: allow filtering data by parsed column values (numeric, list, and string)
Affected #: 1 file
diff -r 9d795f2108c14bb7b8486be0b949b251cb0fd94c -r bb9de7bc465630eb3f8d055df573a9007f670914 lib/galaxy/datatypes/dataproviders/column.py
--- a/lib/galaxy/datatypes/dataproviders/column.py
+++ b/lib/galaxy/datatypes/dataproviders/column.py
@@ -3,6 +3,9 @@
is further subdivided into multiple data (e.g. columns from a line).
"""
+import urllib
+import re
+
import line
_TODO = """
@@ -34,12 +37,13 @@
'column_count' : 'int',
'column_types' : 'list:str',
'parse_columns' : 'bool',
- 'deliminator' : 'str'
+ 'deliminator' : 'str',
+ 'filters' : 'list:str'
}
def __init__( self, source, indeces=None,
column_count=None, column_types=None, parsers=None, parse_columns=True,
- deliminator='\t', **kwargs ):
+ deliminator='\t', filters=None, **kwargs ):
"""
:param indeces: a list of indeces of columns to gather from each row
Optional: will default to `None`.
@@ -103,6 +107,104 @@
# overwrite with user desired parsers
self.parsers.update( parsers or {} )
+ filters = filters or []
+ self.column_filters = []
+ for filter_ in filters:
+ parsed = self.parse_filter( filter_ )
+ #TODO: might be better to error on bad filter/None here
+ if callable( parsed ):
+ self.column_filters.append( parsed )
+
+ def parse_filter( self, filter_param_str ):
+ split = filter_param_str.split( '-', 3 )
+ if not len( split ) == 3:
+ return None
+ column, op, val = split
+
+ # better checking v. len and indeces
+ column = int( column )
+ if column > len( self.column_types ):
+ return None
+ if self.column_types[ column ] in ( 'float', 'int' ):
+ return self.create_numeric_filter( column, op, val )
+ if self.column_types[ column ] in ( 'str' ):
+ return self.create_string_filter( column, op, val )
+ if self.column_types[ column ] in ( 'list' ):
+ return self.create_list_filter( column, op, val )
+ return None
+
+ def create_numeric_filter( self, column, op, val ):
+ """
+ Return an anonymous filter function that will be passed the array
+ of parsed columns. Return None if no filter function can be
+ created for the given params.
+
+ The function will compare the column at index `column` against `val`
+ using the given op where op is one of:
+ lt: less than, le: less than or equal to,
+ eq: equal to, ne: not equal to,
+ ge: greather than or equal to, gt: greater than
+
+ `val` is cast as float here and will return None if there's a parsing error.
+ """
+ try:
+ val = float( val )
+ except ValueError:
+ return None
+ if 'lt' == op:
+ return lambda d: d[column] < val
+ elif 'le' == op:
+ return lambda d: d[column] <= val
+ elif 'eq' == op:
+ return lambda d: d[column] == val
+ elif 'ne' == op:
+ return lambda d: d[column] != val
+ elif 'ge' == op:
+ return lambda d: d[column] >= val
+ elif 'gt' == op:
+ return lambda d: d[column] > val
+ return None
+
+ def create_string_filter( self, column, op, val ):
+ """
+ Return an anonymous filter function that will be passed the array
+ of parsed columns. Return None if no filter function can be
+ created for the given params.
+
+ The function will compare the column at index `column` against `val`
+ using the given op where op is one of:
+ eq: exactly matches,
+ has: the column contains the substring `val`,
+ re: the column matches the regular expression in `val`
+ """
+ if 'eq' == op:
+ return lambda d: d[column] == val
+ elif 'has' == op:
+ return lambda d: val in d[column]
+ elif 're' == op:
+ val = urllib.unquote_plus( val )
+ val = re.compile( val )
+ return lambda d: val.match( d[column] ) is not None
+ return None
+
+ def create_list_filter( self, column, op, val ):
+ """
+ Return an anonymous filter function that will be passed the array
+ of parsed columns. Return None if no filter function can be
+ created for the given params.
+
+ The function will compare the column at index `column` against `val`
+ using the given op where op is one of:
+ eq: the list `val` exactly matches the list in the column,
+ has: the list in the column contains the sublist `val`,
+ """
+ if 'eq' == op:
+ val = self.parse_value( val, 'list' )
+ return lambda d: d[column] == val
+ elif 'has' == op:
+ return lambda d: val in d[column]
+ return None
+
def get_default_parsers( self ):
"""
Return parser dictionary keyed for each columnar type
@@ -140,6 +242,39 @@
#'gffstrand': # -, +, ?, or '.' for None, etc.
}
+ def filter( self, line ):
+ line = super( ColumnarDataProvider, self ).filter( line )
+ if line == None:
+ return line
+ columns = self.parse_columns_from_line( line )
+ return self.filter_by_columns( columns )
+
+ def parse_columns_from_line( self, line ):
+ """
+ Returns a list of the desired, parsed columns.
+ :param line: the line to parse
+ :type line: str
+ """
+ #TODO: too much going on in this loop - the above should all be precomputed AMAP...
+ all_columns = line.split( self.deliminator )
+ # if no indeces were passed to init, return all columns
+ selected_indeces = self.selected_column_indeces or list( xrange( len( all_columns ) ) )
+ parsed_columns = []
+ for parser_index, column_index in enumerate( selected_indeces ):
+ parsed_columns.append( self.parse_column_at_index( all_columns, parser_index, column_index ) )
+ return parsed_columns
+
+ def parse_column_at_index( self, columns, parser_index, index ):
+ """
+ Get the column type for the parser from `self.column_types` or `None`
+ if the type is unavailable.
+ """
+ try:
+ return self.parse_value( columns[ index ], self.get_column_type( parser_index ) )
+ # if a selected index is not within columns, return None
+ except IndexError, index_err:
+ return None
+
def parse_value( self, val, type ):
"""
Attempt to parse and return the given value based on the given type.
@@ -173,51 +308,11 @@
except IndexError, ind_err:
return None
- def parse_column_at_index( self, columns, parser_index, index ):
- """
- Get the column type for the parser from `self.column_types` or `None`
- if the type is unavailable.
- """
- try:
- return self.parse_value( columns[ index ], self.get_column_type( parser_index ) )
- # if a selected index is not within columns, return None
- except IndexError, index_err:
- return None
-
- def parse_columns_from_line( self, line ):
- """
- Returns a list of the desired, parsed columns.
- :param line: the line to parse
- :type line: str
- """
- #TODO: too much going on in this loop - the above should all be precomputed AMAP...
- all_columns = line.split( self.deliminator )
- # if no indeces were passed to init, return all columns
- selected_indeces = self.selected_column_indeces or list( xrange( len( all_columns ) ) )
- parsed_columns = []
- for parser_index, column_index in enumerate( selected_indeces ):
- parsed_columns.append( self.parse_column_at_index( all_columns, parser_index, column_index ) )
- return parsed_columns
-
- def __iter__( self ):
- parent_gen = super( ColumnarDataProvider, self ).__iter__()
- for line in parent_gen:
- columns = self.parse_columns_from_line( line )
- yield columns
-
- #TODO: implement column filters here and not below - flatten hierarchy
-
-class FilteredByColumnDataProvider( ColumnarDataProvider ):
- """
- Data provider that provide a list of columns from the lines of its source
- _only_ if they pass a given filter function.
-
- e.g. column #3 is type int and > N
- """
- # TODO: how to do this and still have limit and offset work?
- def __init__( self, source, **kwargs ):
- raise NotImplementedError()
- super( FilteredByColumnDataProvider, self ).__init__( source, **kwargs )
+ def filter_by_columns( self, columns ):
+ for filter_fn in self.column_filters:
+ if not filter_fn( columns ):
+ return None
+ return columns
class DictDataProvider( ColumnarDataProvider ):
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 a _future_expose_api_raw_anonymous_and_sessionless to restore functionality
by commits-noreply@bitbucket.org 09 Feb '15
by commits-noreply@bitbucket.org 09 Feb '15
09 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9d795f2108c1/
Changeset: 9d795f2108c1
User: natefoo
Date: 2015-02-09 15:17:53+00:00
Summary: Add a _future_expose_api_raw_anonymous_and_sessionless to restore functionality
that was previously available with _future_expose_api_raw_anonymous.
Affected #: 3 files
diff -r 48f8adbdab6e2b66fe563be547da9db9627b1a94 -r 9d795f2108c14bb7b8486be0b949b251cb0fd94c lib/galaxy/web/__init__.py
--- a/lib/galaxy/web/__init__.py
+++ b/lib/galaxy/web/__init__.py
@@ -19,6 +19,7 @@
from framework.decorators import _future_expose_api_raw
from framework.decorators import _future_expose_api_raw_anonymous
from framework.decorators import _future_expose_api_anonymous_and_sessionless
+from framework.decorators import _future_expose_api_raw_anonymous_and_sessionless
from framework.formbuilder import form
from framework.formbuilder import FormBuilder
diff -r 48f8adbdab6e2b66fe563be547da9db9627b1a94 -r 9d795f2108c14bb7b8486be0b949b251cb0fd94c lib/galaxy/web/framework/decorators.py
--- a/lib/galaxy/web/framework/decorators.py
+++ b/lib/galaxy/web/framework/decorators.py
@@ -344,3 +344,6 @@
def _future_expose_api_raw_anonymous( func ):
return _future_expose_api( func, to_json=False, user_required=False )
+
+def _future_expose_api_raw_anonymous_and_sessionless( func ):
+ return _future_expose_api( func, to_json=False, user_required=False, user_or_session_required=False )
diff -r 48f8adbdab6e2b66fe563be547da9db9627b1a94 -r 9d795f2108c14bb7b8486be0b949b251cb0fd94c lib/galaxy/webapps/galaxy/api/job_files.py
--- a/lib/galaxy/webapps/galaxy/api/job_files.py
+++ b/lib/galaxy/webapps/galaxy/api/job_files.py
@@ -8,8 +8,8 @@
from galaxy import util
from galaxy import model
from galaxy.web.base.controller import BaseAPIController
-from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous
-from galaxy.web import _future_expose_api_raw_anonymous as expose_api_raw_anonymous
+from galaxy.web import _future_expose_api_anonymous_and_sessionless as expose_api_anonymous_and_sessionless
+from galaxy.web import _future_expose_api_raw_anonymous_and_sessionless as expose_api_raw_anonymous_and_sessionless
import logging
@@ -28,7 +28,7 @@
security model for tool execution.
"""
- @expose_api_raw_anonymous
+ @expose_api_raw_anonymous_and_sessionless
def index( self, trans, job_id, **kwargs ):
"""
index( self, trans, job_id, **kwargs )
@@ -54,7 +54,7 @@
path = kwargs.get("path", None)
return open(path, 'rb')
- @expose_api_anonymous
+ @expose_api_anonymous_and_sessionless
def create( self, trans, job_id, payload, **kwargs ):
"""
create( self, trans, job_id, payload, **kwargs )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: ToolForm: Set missing values to null
by commits-noreply@bitbucket.org 09 Feb '15
by commits-noreply@bitbucket.org 09 Feb '15
09 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/48f8adbdab6e/
Changeset: 48f8adbdab6e
User: guerler
Date: 2015-02-09 14:15:25+00:00
Summary: ToolForm: Set missing values to null
Affected #: 6 files
diff -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 -r 48f8adbdab6e2b66fe563be547da9db9627b1a94 client/galaxy/scripts/mvc/tools/tools-input.js
--- a/client/galaxy/scripts/mvc/tools/tools-input.js
+++ b/client/galaxy/scripts/mvc/tools/tools-input.js
@@ -34,8 +34,7 @@
this.field.skip = false;
var v = this.field.value && this.field.value();
this.field.skip = Boolean(options.optional &&
- ((this.default_value === undefined) ||
- ((this.field.validate && !this.field.validate()) || !v ||
+ (((this.field.validate && !this.field.validate()) || !v ||
(v == this.default_value) || (Number(v) == Number(this.default_value)) ||
(JSON.stringify(v) == JSON.stringify(this.default_value)))));
diff -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 -r 48f8adbdab6e2b66fe563be547da9db9627b1a94 client/galaxy/scripts/mvc/tools/tools-section.js
--- a/client/galaxy/scripts/mvc/tools/tools-section.js
+++ b/client/galaxy/scripts/mvc/tools/tools-section.js
@@ -294,17 +294,20 @@
// get id
var id = input_def.id;
+ // add regular/default value if missing
+ if (input_def.value === undefined) {
+ input_def.value = null;
+ }
+ if (input_def.default_value === undefined) {
+ input_def.default_value = input_def.value;
+ }
+
// create input field
var field = this._createField(input_def);
// add to field list
this.app.field_list[id] = field;
- // fix default value if missing
- if (input_def.default_value === undefined) {
- input_def.default_value = input_def.value;
- }
-
// create input field wrapper
var input_element = new InputElement(this.app, {
label : input_def.label,
diff -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 -r 48f8adbdab6e2b66fe563be547da9db9627b1a94 static/scripts/mvc/tools/tools-input.js
--- a/static/scripts/mvc/tools/tools-input.js
+++ b/static/scripts/mvc/tools/tools-input.js
@@ -34,8 +34,7 @@
this.field.skip = false;
var v = this.field.value && this.field.value();
this.field.skip = Boolean(options.optional &&
- ((this.default_value === undefined) ||
- ((this.field.validate && !this.field.validate()) || !v ||
+ (((this.field.validate && !this.field.validate()) || !v ||
(v == this.default_value) || (Number(v) == Number(this.default_value)) ||
(JSON.stringify(v) == JSON.stringify(this.default_value)))));
diff -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 -r 48f8adbdab6e2b66fe563be547da9db9627b1a94 static/scripts/mvc/tools/tools-section.js
--- a/static/scripts/mvc/tools/tools-section.js
+++ b/static/scripts/mvc/tools/tools-section.js
@@ -294,17 +294,20 @@
// get id
var id = input_def.id;
+ // add regular/default value if missing
+ if (input_def.value === undefined) {
+ input_def.value = null;
+ }
+ if (input_def.default_value === undefined) {
+ input_def.default_value = input_def.value;
+ }
+
// create input field
var field = this._createField(input_def);
// add to field list
this.app.field_list[id] = field;
- // fix default value if missing
- if (input_def.default_value === undefined) {
- input_def.default_value = input_def.value;
- }
-
// create input field wrapper
var input_element = new InputElement(this.app, {
label : input_def.label,
diff -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 -r 48f8adbdab6e2b66fe563be547da9db9627b1a94 static/scripts/packed/mvc/tools/tools-input.js
--- a/static/scripts/packed/mvc/tools/tools-input.js
+++ b/static/scripts/packed/mvc/tools/tools-input.js
@@ -1,1 +1,1 @@
-define([],function(){return Backbone.View.extend({initialize:function(d,c){this.app=d;this.text_enable=d.options.text_enable||"Enable";this.text_disable=d.options.text_disable||"Disable";this.field=c.field;this.default_value=c.default_value;this.setElement(this._template(c));this.$field=this.$el.find(".ui-table-form-field");this.$title_optional=this.$el.find(".ui-table-form-title-optional");this.$error_text=this.$el.find(".ui-table-form-error-text");this.$error=this.$el.find(".ui-table-form-error");this.$field.prepend(this.field.$el);this.field.skip=false;var b=this.field.value&&this.field.value();this.field.skip=Boolean(c.optional&&((this.default_value===undefined)||((this.field.validate&&!this.field.validate())||!b||(b==this.default_value)||(Number(b)==Number(this.default_value))||(JSON.stringify(b)==JSON.stringify(this.default_value)))));this._refresh();var a=this;this.$title_optional.on("click",function(){a.field.skip=!a.field.skip;a._refresh()})},error:function(a){this.$error_text.html(a);this.$error.show();this.$el.addClass("ui-error")},reset:function(){this.$error.hide();this.$el.removeClass("ui-error")},_refresh:function(){if(!this.field.skip){this.$field.fadeIn("fast");this.$title_optional.html(this.text_disable)}else{this.reset();this.$field.hide();this.$title_optional.html(this.text_enable);this.field.value&&this.field.value(this.default_value)}this.app.trigger("refresh")},_template:function(a){var b='<div class="ui-table-form-element"><div class="ui-table-form-error ui-error"><span class="fa fa-arrow-down"/><span class="ui-table-form-error-text"/></div><div class="ui-table-form-title-strong">';if(a.optional){b+=a.label+'<span> [<span class="ui-table-form-title-optional"/>]</span>'}else{b+=a.label}b+='</div><div class="ui-table-form-field">';if(a.help){b+='<div class="ui-table-form-info">'+a.help+"</div>"}b+="</div></div>";return b}})});
\ No newline at end of file
+define([],function(){return Backbone.View.extend({initialize:function(d,c){this.app=d;this.text_enable=d.options.text_enable||"Enable";this.text_disable=d.options.text_disable||"Disable";this.field=c.field;this.default_value=c.default_value;this.setElement(this._template(c));this.$field=this.$el.find(".ui-table-form-field");this.$title_optional=this.$el.find(".ui-table-form-title-optional");this.$error_text=this.$el.find(".ui-table-form-error-text");this.$error=this.$el.find(".ui-table-form-error");this.$field.prepend(this.field.$el);this.field.skip=false;var b=this.field.value&&this.field.value();this.field.skip=Boolean(c.optional&&(((this.field.validate&&!this.field.validate())||!b||(b==this.default_value)||(Number(b)==Number(this.default_value))||(JSON.stringify(b)==JSON.stringify(this.default_value)))));this._refresh();var a=this;this.$title_optional.on("click",function(){a.field.skip=!a.field.skip;a._refresh()})},error:function(a){this.$error_text.html(a);this.$error.show();this.$el.addClass("ui-error")},reset:function(){this.$error.hide();this.$el.removeClass("ui-error")},_refresh:function(){if(!this.field.skip){this.$field.fadeIn("fast");this.$title_optional.html(this.text_disable)}else{this.reset();this.$field.hide();this.$title_optional.html(this.text_enable);this.field.value&&this.field.value(this.default_value)}this.app.trigger("refresh")},_template:function(a){var b='<div class="ui-table-form-element"><div class="ui-table-form-error ui-error"><span class="fa fa-arrow-down"/><span class="ui-table-form-error-text"/></div><div class="ui-table-form-title-strong">';if(a.optional){b+=a.label+'<span> [<span class="ui-table-form-title-optional"/>]</span>'}else{b+=a.label}b+='</div><div class="ui-table-form-field">';if(a.help){b+='<div class="ui-table-form-info">'+a.help+"</div>"}b+="</div></div>";return b}})});
\ No newline at end of file
diff -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 -r 48f8adbdab6e2b66fe563be547da9db9627b1a94 static/scripts/packed/mvc/tools/tools-section.js
--- a/static/scripts/packed/mvc/tools/tools-section.js
+++ b/static/scripts/packed/mvc/tools/tools-section.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/ui/ui-portlet","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(e,b,h,d,c,a,f){var g=Backbone.View.extend({initialize:function(j,i){this.app=j;this.inputs=i.inputs;i.cls="ui-table-plain";i.cls_tr="section-row";this.table=new b.View(i);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var j in this.inputs){this.add(this.inputs[j])}},add:function(k){var j=this;var i=jQuery.extend(true,{},k);i.id=k.id=e.uuid();this.app.input_list[i.id]=i;var l=i.type;switch(l){case"conditional":this._addConditional(i);break;case"repeat":this._addRepeat(i);break;case"section":this._addSection(i);break;default:this._addRow(i)}},_addConditional:function(j){var k=this;j.test_param.id=j.id;var n=this._addRow(j.test_param);n.options.onchange=function(w){var v=k.app.tree.matchCase(j,w);for(var u in j.cases){var q=j.cases[u];var t=j.id+"-section-"+u;var p=k.table.get(t);var s=false;for(var r in q.inputs){if(!q.inputs[r].hidden){s=true;break}}if(u==v&&s){p.fadeIn("fast")}else{p.hide()}}k.app.trigger("refresh")};for(var m in j.cases){var l=j.id+"-section-"+m;var o=new g(this.app,{inputs:j.cases[m].inputs});o.$el.addClass("ui-table-section");this.table.add(o.$el);this.table.append(l)}n.trigger("change")},_addRepeat:function(p){var s=this;var q=0;var l=new c.View({title:p.title,title_new:p.title,min:p.min,max:p.max,onnew:function(){n(p.inputs);s.app.trigger("refresh")}});function n(i){var t=p.id+"-section-"+(q++);var u=new g(s.app,{inputs:i});l.add({id:t,$el:u.$el,ondel:function(){l.del(t);s.app.trigger("refresh")}})}var j=p.min;var r=_.size(p.cache);for(var m=0;m<Math.max(r,j);m++){var o=null;if(m<r){o=p.cache[m]}else{o=p.inputs}n(o)}var k=new f(this.app,{label:p.title,help:p.help,field:l});this.table.add(k.$el);this.table.append(p.id)},_addSection:function(i){var j=this;var n=new g(j.app,{inputs:i.inputs});var m=new h.ButtonIcon({icon:"fa-eye-slash",tooltip:"Show/hide section",cls:"ui-button-icon-plain"});var l=new d.View({title:i.label,cls:"ui-portlet-section",operations:{button_visible:m}});l.append(n.$el);l.append($("<div/>").addClass("ui-table-form-info").html(i.help));var k=false;l.$content.hide();l.$header.css("cursor","pointer");l.$header.on("click",function(){if(k){k=false;l.$content.hide();m.setIcon("fa-eye-slash")}else{k=true;l.$content.fadeIn("fast");m.setIcon("fa-eye")}});if(i.expand){l.$header.trigger("click")}this.table.add(l.$el);this.table.append(i.id)},_addRow:function(i){var l=i.id;var j=this._createField(i);this.app.field_list[l]=j;if(i.default_value===undefined){i.default_value=i.value}var k=new f(this.app,{label:i.label,default_value:i.default_value,optional:i.optional,help:i.help,field:j});this.app.element_list[l]=k;this.table.add(k.$el);this.table.append(l);if(i.hidden){this.table.get(l).hide()}return j},_createField:function(i){var j=null;switch(i.type){case"text":j=this._fieldText(i);break;case"select":j=this._fieldSelect(i);break;case"data":j=this._fieldData(i);break;case"data_collection":j=this._fieldData(i);break;case"data_column":i.error_text="Missing columns in referenced dataset.";j=this._fieldSelect(i);break;case"hidden":j=this._fieldHidden(i);break;case"hidden_data":j=this._fieldHidden(i);break;case"integer":j=this._fieldSlider(i);break;case"float":j=this._fieldSlider(i);break;case"boolean":j=this._fieldBoolean(i);break;case"genomebuild":i.searchable=true;j=this._fieldSelect(i);break;case"drill_down":j=this._fieldDrilldown(i);break;case"baseurl":j=this._fieldHidden(i);break;default:this.app.incompatible=true;if(i.options){j=this._fieldSelect(i)}else{j=this._fieldText(i)}console.debug("tools-form::_addRow() : Auto matched field type ("+i.type+").")}if(i.value!==undefined){j.value(i.value)}return j},_fieldData:function(i){if(!this.app.options.is_dynamic){i.info="Data input '"+i.name+"' ("+e.textify(i.extensions.toString())+")";i.value=null;return this._fieldHidden(i)}var j=this;return new a.View(this.app,{id:"field-"+i.id,extensions:i.extensions,optional:i.optional,multiple:i.multiple,type:i.type,data:i.options,onchange:function(){j.app.trigger("refresh")}})},_fieldSelect:function(j){if(!this.app.options.is_dynamic&&j.is_dynamic){return this._fieldText(j)}var l=[];for(var m in j.options){var n=j.options[m];l.push({label:n[0],value:n[1]})}var o=h.Select;switch(j.display){case"checkboxes":o=h.Checkbox;break;case"radio":o=h.Radio;break}var k=this;return new o.View({id:"field-"+j.id,data:l,error_text:j.error_text||"No options available",multiple:j.multiple,searchable:j.searchable,onchange:function(){k.app.trigger("refresh")}})},_fieldDrilldown:function(i){if(!this.app.options.is_dynamic&&i.is_dynamic){return this._fieldText(i)}var j=this;return new h.Drilldown.View({id:"field-"+i.id,data:i.options,display:i.display,onchange:function(){j.app.trigger("refresh")}})},_fieldText:function(i){if(i.options){i.area=i.multiple;if(!e.validate(i.value)){i.value=""}else{if(i.value instanceof Array){i.value=value.toString()}else{i.value=String(i.value).replace(/[\[\]'"\s]/g,"");if(i.multiple){i.value=i.value.replace(/,/g,"\n")}}}}var j=this;return new h.Input({id:"field-"+i.id,area:i.area,onchange:function(){j.app.trigger("refresh")}})},_fieldSlider:function(i){var j=this;return new h.Slider.View({id:"field-"+i.id,precise:i.type=="float",min:i.min,max:i.max,onchange:function(){j.app.trigger("refresh")}})},_fieldHidden:function(i){return new h.Hidden({id:"field-"+i.id,info:i.info})},_fieldBoolean:function(i){var j=this;return new h.RadioButton.View({id:"field-"+i.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}],onchange:function(){j.app.trigger("refresh")}})}});return{View:g}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/ui/ui-portlet","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(e,b,h,d,c,a,f){var g=Backbone.View.extend({initialize:function(j,i){this.app=j;this.inputs=i.inputs;i.cls="ui-table-plain";i.cls_tr="section-row";this.table=new b.View(i);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var j in this.inputs){this.add(this.inputs[j])}},add:function(k){var j=this;var i=jQuery.extend(true,{},k);i.id=k.id=e.uuid();this.app.input_list[i.id]=i;var l=i.type;switch(l){case"conditional":this._addConditional(i);break;case"repeat":this._addRepeat(i);break;case"section":this._addSection(i);break;default:this._addRow(i)}},_addConditional:function(j){var k=this;j.test_param.id=j.id;var n=this._addRow(j.test_param);n.options.onchange=function(w){var v=k.app.tree.matchCase(j,w);for(var u in j.cases){var q=j.cases[u];var t=j.id+"-section-"+u;var p=k.table.get(t);var s=false;for(var r in q.inputs){if(!q.inputs[r].hidden){s=true;break}}if(u==v&&s){p.fadeIn("fast")}else{p.hide()}}k.app.trigger("refresh")};for(var m in j.cases){var l=j.id+"-section-"+m;var o=new g(this.app,{inputs:j.cases[m].inputs});o.$el.addClass("ui-table-section");this.table.add(o.$el);this.table.append(l)}n.trigger("change")},_addRepeat:function(p){var s=this;var q=0;var l=new c.View({title:p.title,title_new:p.title,min:p.min,max:p.max,onnew:function(){n(p.inputs);s.app.trigger("refresh")}});function n(i){var t=p.id+"-section-"+(q++);var u=new g(s.app,{inputs:i});l.add({id:t,$el:u.$el,ondel:function(){l.del(t);s.app.trigger("refresh")}})}var j=p.min;var r=_.size(p.cache);for(var m=0;m<Math.max(r,j);m++){var o=null;if(m<r){o=p.cache[m]}else{o=p.inputs}n(o)}var k=new f(this.app,{label:p.title,help:p.help,field:l});this.table.add(k.$el);this.table.append(p.id)},_addSection:function(i){var j=this;var n=new g(j.app,{inputs:i.inputs});var m=new h.ButtonIcon({icon:"fa-eye-slash",tooltip:"Show/hide section",cls:"ui-button-icon-plain"});var l=new d.View({title:i.label,cls:"ui-portlet-section",operations:{button_visible:m}});l.append(n.$el);l.append($("<div/>").addClass("ui-table-form-info").html(i.help));var k=false;l.$content.hide();l.$header.css("cursor","pointer");l.$header.on("click",function(){if(k){k=false;l.$content.hide();m.setIcon("fa-eye-slash")}else{k=true;l.$content.fadeIn("fast");m.setIcon("fa-eye")}});if(i.expand){l.$header.trigger("click")}this.table.add(l.$el);this.table.append(i.id)},_addRow:function(i){var l=i.id;if(i.value===undefined){i.value=null}if(i.default_value===undefined){i.default_value=i.value}var j=this._createField(i);this.app.field_list[l]=j;var k=new f(this.app,{label:i.label,default_value:i.default_value,optional:i.optional,help:i.help,field:j});this.app.element_list[l]=k;this.table.add(k.$el);this.table.append(l);if(i.hidden){this.table.get(l).hide()}return j},_createField:function(i){var j=null;switch(i.type){case"text":j=this._fieldText(i);break;case"select":j=this._fieldSelect(i);break;case"data":j=this._fieldData(i);break;case"data_collection":j=this._fieldData(i);break;case"data_column":i.error_text="Missing columns in referenced dataset.";j=this._fieldSelect(i);break;case"hidden":j=this._fieldHidden(i);break;case"hidden_data":j=this._fieldHidden(i);break;case"integer":j=this._fieldSlider(i);break;case"float":j=this._fieldSlider(i);break;case"boolean":j=this._fieldBoolean(i);break;case"genomebuild":i.searchable=true;j=this._fieldSelect(i);break;case"drill_down":j=this._fieldDrilldown(i);break;case"baseurl":j=this._fieldHidden(i);break;default:this.app.incompatible=true;if(i.options){j=this._fieldSelect(i)}else{j=this._fieldText(i)}console.debug("tools-form::_addRow() : Auto matched field type ("+i.type+").")}if(i.value!==undefined){j.value(i.value)}return j},_fieldData:function(i){if(!this.app.options.is_dynamic){i.info="Data input '"+i.name+"' ("+e.textify(i.extensions.toString())+")";i.value=null;return this._fieldHidden(i)}var j=this;return new a.View(this.app,{id:"field-"+i.id,extensions:i.extensions,optional:i.optional,multiple:i.multiple,type:i.type,data:i.options,onchange:function(){j.app.trigger("refresh")}})},_fieldSelect:function(j){if(!this.app.options.is_dynamic&&j.is_dynamic){return this._fieldText(j)}var l=[];for(var m in j.options){var n=j.options[m];l.push({label:n[0],value:n[1]})}var o=h.Select;switch(j.display){case"checkboxes":o=h.Checkbox;break;case"radio":o=h.Radio;break}var k=this;return new o.View({id:"field-"+j.id,data:l,error_text:j.error_text||"No options available",multiple:j.multiple,searchable:j.searchable,onchange:function(){k.app.trigger("refresh")}})},_fieldDrilldown:function(i){if(!this.app.options.is_dynamic&&i.is_dynamic){return this._fieldText(i)}var j=this;return new h.Drilldown.View({id:"field-"+i.id,data:i.options,display:i.display,onchange:function(){j.app.trigger("refresh")}})},_fieldText:function(i){if(i.options){i.area=i.multiple;if(!e.validate(i.value)){i.value=""}else{if(i.value instanceof Array){i.value=value.toString()}else{i.value=String(i.value).replace(/[\[\]'"\s]/g,"");if(i.multiple){i.value=i.value.replace(/,/g,"\n")}}}}var j=this;return new h.Input({id:"field-"+i.id,area:i.area,onchange:function(){j.app.trigger("refresh")}})},_fieldSlider:function(i){var j=this;return new h.Slider.View({id:"field-"+i.id,precise:i.type=="float",min:i.min,max:i.max,onchange:function(){j.app.trigger("refresh")}})},_fieldHidden:function(i){return new h.Hidden({id:"field-"+i.id,info:i.info})},_fieldBoolean:function(i){var j=this;return new h.RadioButton.View({id:"field-"+i.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}],onchange:function(){j.app.trigger("refresh")}})}});return{View:g}});
\ 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
[galaxyproject/usegalaxy-playbook] 34a9d0: Swapped out Prestige server and SupAgro event from...
by GitHub 09 Feb '15
by GitHub 09 Feb '15
09 Feb '15
Branch: refs/heads/master
Home: https://github.com/galaxyproject/usegalaxy-playbook
Commit: 34a9d0483ff49564998b838e5e47f7b8421d0041
https://github.com/galaxyproject/usegalaxy-playbook/commit/34a9d0483ff49564…
Author: Dave Clements <clements(a)Clements-Galaxy.local>
Date: 2015-02-08 (Sun, 08 Feb 2015)
Changed paths:
A files/galaxy/common/static/welcome_img/GalaxyAdmins201502.png
A files/galaxy/common/static/welcome_img/kmerSVMGalaxy.png
M templates/galaxy/common/static/welcome.html.j2
Log Message:
-----------
Swapped out Prestige server and SupAgro event from slide deck. Add GalaxyAdmins Feb meetup, and kmer-SVM Galaxy server.
1
0
commit/galaxy-central: guerler: Parameters: Fix initial value for drill downs, Workflow/ToolForm: Move module building to api
by commits-noreply@bitbucket.org 09 Feb '15
by commits-noreply@bitbucket.org 09 Feb '15
09 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/de8fa2d2312e/
Changeset: de8fa2d2312e
User: guerler
Date: 2015-02-09 04:49:24+00:00
Summary: Parameters: Fix initial value for drill downs, Workflow/ToolForm: Move module building to api
Affected #: 14 files
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 client/galaxy/scripts/mvc/tools/tools-form-workflow.js
--- a/client/galaxy/scripts/mvc/tools/tools-form-workflow.js
+++ b/client/galaxy/scripts/mvc/tools/tools-form-workflow.js
@@ -275,10 +275,16 @@
/** Request a new model for an already created tool form and updates the form inputs
*/
_updateModel: function() {
+ // link self
+ var self = this;
+
// create the request dictionary
- var self = this;
- var current_state = this.tree.finalize();
-
+ var current_state = {
+ tool_id : this.options.id,
+ tool_version : this.options.version,
+ inputs : this.tree.finalize()
+ }
+
// log tool state
console.debug('tools-form-workflow::_refreshForm() - Refreshing states.');
console.debug(current_state);
@@ -287,11 +293,11 @@
var process_id = this.deferred.register();
// build model url for request
- var model_url = galaxy_config.root + 'workflow/editor_form_post?tool_id=' + this.options.id + '&__is_dynamic__=False';
+ var model_url = galaxy_config.root + 'api/workflows/build_module';
// post job
Utils.request({
- type : 'GET',
+ type : 'POST',
url : model_url,
data : current_state,
success : function(data) {
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 client/galaxy/scripts/mvc/tools/tools-tree.js
--- a/client/galaxy/scripts/mvc/tools/tools-tree.js
+++ b/client/galaxy/scripts/mvc/tools/tools-tree.js
@@ -10,13 +10,13 @@
initialize: function(app) {
this.app = app;
},
-
+
/** Convert dictionary representation into tool api specific flat dictionary format.
*/
finalize: function(patch) {
// link this
var self = this;
-
+
// dictionary with api specific identifiers
this.map_dict = {};
@@ -24,24 +24,24 @@
if (!this.app.section) {
return {};
}
-
+
// ensure that dictionary with patching functions exists
patch = patch || {};
-
+
// dictionary formatted for job submission or tool form update
var result_dict = {};
// prepare full dictionary
var dict = {};
-
+
// fill dictionary from dom
this._iterate(this.app.section.$el, dict);
-
+
// add identifier and value to job definition
function add(job_input_id, input_id, input_value) {
// add entry to result dictionary
result_dict[job_input_id] = input_value;
-
+
// backup id mapping
self.map_dict[job_input_id] = input_id;
};
@@ -53,21 +53,21 @@
if (node.input) {
// get node
var input = node.input;
-
+
// create identifier
var job_input_id = identifier;
if (identifier != '') {
job_input_id += '|';
}
job_input_id += input.name;
-
+
// process input type
switch (input.type) {
// handle repeats
case 'repeat':
// section identifier
var section_label = 'section-';
-
+
// collect repeat block identifiers
var block_indices = [];
var block_prefix = null;
@@ -81,10 +81,10 @@
}
}
}
-
+
// sort repeat blocks
block_indices.sort(function(a,b) { return a - b; });
-
+
// add to response dictionary in created order
var index = 0;
for (var i in block_indices) {
@@ -98,10 +98,10 @@
if (patch[input.test_param.type]) {
value = patch[input.test_param.type](value);
}
-
+
// add conditional value
add (job_input_id + '|' + input.test_param.name, input.id, value);
-
+
// identify selected case
var selectedCase = self.matchCase(input, value);
if (selectedCase != -1) {
@@ -116,22 +116,17 @@
// get field
var field = self.app.field_list[input.id];
if (field && field.value) {
+ // validate field value
+ var value = field.value();
+ if (field.validate && !field.validate()) {
+ value = null;
+ }
+
// get and patch field value
- var value = field.value();
if (patch[input.type]) {
value = patch[input.type](value);
}
- // validate field value
- if (field.skip) {
- continue;
- }
-
- // validate field value
- if (field.validate && !field.validate()) {
- value = null;
- }
-
// ignore certain values
if (input.ignore === undefined || (value !== null && input.ignore != value)) {
// add value to submission
@@ -149,20 +144,20 @@
}
}
}
-
+
// start conversion
convert('', dict);
-
+
// return result
return result_dict;
},
-
+
/** Match job definition identifier to input element identifier
*/
match: function (job_input_id) {
return this.map_dict && this.map_dict[job_input_id];
},
-
+
/** Match conditional values to selected cases
*/
matchCase: function(input, value) {
@@ -174,27 +169,27 @@
value = input.test_param.falsevalue || 'false';
}
}
-
+
// find selected case
for (var i in input.cases) {
if (input.cases[i].value == value) {
return i;
}
}
-
+
// selected case not found
return -1;
},
-
+
/** Matches identifier from api model to input elements
*/
matchModel: function(model, callback) {
// final result dictionary
var result = {};
-
+
// link this
var self = this;
-
+
// search throughout response
function search (id, head) {
for (var i in head) {
@@ -224,23 +219,23 @@
}
}
}
-
+
// match all ids and return messages
search('', model.inputs);
// return matched results
return result;
},
-
+
/** Matches identifier from api response to input elements
*/
matchResponse: function(response) {
// final result dictionary
var result = {};
-
+
// link this
var self = this;
-
+
// search throughout response
function search (id, head) {
if (typeof head === 'string') {
@@ -262,14 +257,14 @@
}
}
}
-
+
// match all ids and return messages
search('', response);
-
+
// return matched results
return result;
},
-
+
/** Iterate through the tool form dom and map it to the dictionary.
*/
_iterate: function(parent, dict) {
@@ -279,15 +274,15 @@
children.each(function() {
// get child element
var child = this;
-
+
// get id
var id = $(child).attr('id');
-
+
// create new branch
if ($(child).hasClass('section-row')) {
// create sub dictionary
dict[id] = {};
-
+
// add input element if it exists
var input = self.app.input_list[id];
if (input) {
@@ -295,7 +290,7 @@
input : input
}
}
-
+
// fill sub dictionary
self._iterate(child, dict[id]);
} else {
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -2250,13 +2250,12 @@
return tool_dict
- def to_json (self, trans, **kwd):
+ def to_json (self, trans, kwd={}, is_dynamic=True):
"""
Recursively creates a tool dictionary containing repeats, dynamic options and updated states.
"""
job_id = kwd.get('__job_id__', None)
dataset_id = kwd.get('__dataset_id__', None)
- is_dynamic = string_as_bool(kwd.get('__is_dynamic__', True))
# load job details if provided
job = None
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -1618,6 +1618,8 @@
return UnvalidatedValue( None )
initial_values = []
recurse_options( initial_values, self.get_options( trans=trans, other_values=context ) )
+ if len( initial_values ) == 0:
+ initial_values = None
return initial_values
def value_to_display_text( self, value, app ):
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -76,14 +76,10 @@
GET /api/tools/{tool_id}/build
Returns a tool model including dynamic parameters and updated values, repeats block etc.
"""
- tool_id = urllib.unquote_plus( id )
tool_version = kwd.get( 'tool_version', None )
- tool = self.app.toolbox.get_tool( tool_id, tool_version )
- if not tool:
- trans.response.status = 500
- return { 'error': 'Could not find tool with id \'%s\'' % tool_id }
- return tool.to_json(trans, **kwd)
-
+ tool = self._get_tool( id, tool_version=tool_version, user=trans.user )
+ return tool.to_json(trans, kwd)
+
@_future_expose_api
@web.require_admin
def reload( self, trans, tool_id, **kwd ):
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -6,6 +6,8 @@
import uuid
import logging
+import copy
+import urllib
from sqlalchemy import desc, or_, and_
from galaxy import exceptions, util
from galaxy.model.item_attrs import UsesAnnotations
@@ -17,6 +19,7 @@
from galaxy.workflow.extract import extract_workflow
from galaxy.workflow.run import invoke, queue_invoke
from galaxy.workflow.run_request import build_workflow_run_config
+from galaxy.workflow.modules import module_factory
log = logging.getLogger(__name__)
@@ -305,6 +308,52 @@
raise exceptions.RequestParameterInvalidException( message )
return self.workflow_contents_manager.workflow_to_dict( trans, stored_workflow, style="instance" )
+ @expose_api
+ def build_module( self, trans, payload={}):
+ """
+ POST /api/workflows/build_module
+ Builds module details including a tool model for the workflow editor.
+ """
+ tool_id = payload.get( 'tool_id', None )
+ tool_version = payload.get( 'tool_version', None )
+ tool_inputs = payload.get( 'inputs', None )
+ annotation = payload.get( 'annotation', '' )
+
+ # load tool
+ tool = self._get_tool( tool_id, tool_version=tool_version, user=trans.user )
+
+ # initialize module
+ trans.workflow_building_mode = True
+ module = module_factory.from_dict( trans, {
+ 'type' : 'tool',
+ 'tool_id' : tool.id,
+ 'tool_state' : None
+ } )
+
+ # create tool model and default tool state (if missing)
+ tool_model = module.tool.to_json(trans, tool_inputs, is_dynamic=False)
+ module.state.inputs = copy.deepcopy(tool_model['state_inputs'])
+ return {
+ 'tool_model' : tool_model,
+ 'tool_state' : module.get_state(),
+ 'data_inputs' : module.get_data_inputs(),
+ 'data_outputs' : module.get_data_outputs(),
+ 'tool_errors' : module.get_errors(),
+ 'form_html' : module.get_config_form(),
+ 'annotation' : annotation,
+ 'post_job_actions' : module.get_post_job_actions(tool_inputs)
+ }
+
+ #
+ # -- Helper methods --
+ #
+ def _get_tool( self, id, tool_version=None, user=None ):
+ id = urllib.unquote_plus( id )
+ tool = self.app.toolbox.get_tool( id, tool_version )
+ if not tool or not tool.allow_user_access( user ):
+ raise exceptions.ObjectNotFound("Could not find tool with id '%s'" % id)
+ return tool
+
def __api_import_new_workflow( self, trans, payload, **kwd ):
data = payload['workflow']
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 lib/galaxy/webapps/galaxy/buildapp.py
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -217,6 +217,7 @@
webapp.mapper.resource_with_deleted( 'user', 'users', path_prefix='/api' )
webapp.mapper.resource( 'genome', 'genomes', path_prefix='/api' )
webapp.mapper.resource( 'visualization', 'visualizations', path_prefix='/api' )
+ webapp.mapper.connect( '/api/workflows/build_module', action='build_module', controller="workflows" )
webapp.mapper.resource( 'workflow', 'workflows', path_prefix='/api' )
webapp.mapper.resource_with_deleted( 'history', 'histories', path_prefix='/api' )
webapp.mapper.connect( '/api/histories/{history_id}/citations', action='citations', controller="histories" )
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -609,7 +609,6 @@
This is used for the form shown in the right pane when a node
is selected.
"""
-
tool_state = incoming.pop('tool_state', None)
trans.workflow_building_mode = True
module = module_factory.from_dict( trans, {
@@ -617,22 +616,7 @@
'tool_id': tool_id,
'tool_state': tool_state
} )
-
- # create tool model and default tool state (if missing)
- if type == 'tool' and not tool_state:
- tool_model = module.tool.to_json(trans, **incoming)
- module.state.inputs = copy.deepcopy(tool_model['state_inputs'])
- return {
- 'tool_model': tool_model,
- 'tool_state': module.get_state(),
- 'data_inputs': module.get_data_inputs(),
- 'data_outputs': module.get_data_outputs(),
- 'tool_errors': module.get_errors(),
- 'form_html': module.get_config_form(),
- 'annotation': annotation,
- 'post_job_actions': module.get_post_job_actions(incoming)
- }
-
+
# update module state
module.update_state( incoming )
@@ -669,7 +653,8 @@
module = module_factory.new( trans, type, **kwargs )
tool_model = None
if type == 'tool':
- tool_model = module.tool.to_json(trans)
+ tool_model = module.tool.to_json(trans, is_dynamic=False)
+ module.state.inputs = copy.deepcopy(tool_model['state_inputs'])
return {
'type': module.type,
'name': module.get_name(),
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 static/scripts/mvc/tools/tools-form-workflow.js
--- a/static/scripts/mvc/tools/tools-form-workflow.js
+++ b/static/scripts/mvc/tools/tools-form-workflow.js
@@ -275,10 +275,16 @@
/** Request a new model for an already created tool form and updates the form inputs
*/
_updateModel: function() {
+ // link self
+ var self = this;
+
// create the request dictionary
- var self = this;
- var current_state = this.tree.finalize();
-
+ var current_state = {
+ tool_id : this.options.id,
+ tool_version : this.options.version,
+ inputs : this.tree.finalize()
+ }
+
// log tool state
console.debug('tools-form-workflow::_refreshForm() - Refreshing states.');
console.debug(current_state);
@@ -287,11 +293,11 @@
var process_id = this.deferred.register();
// build model url for request
- var model_url = galaxy_config.root + 'workflow/editor_form_post?tool_id=' + this.options.id + '&__is_dynamic__=False';
+ var model_url = galaxy_config.root + 'api/workflows/build_module';
// post job
Utils.request({
- type : 'GET',
+ type : 'POST',
url : model_url,
data : current_state,
success : function(data) {
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 static/scripts/mvc/tools/tools-tree.js
--- a/static/scripts/mvc/tools/tools-tree.js
+++ b/static/scripts/mvc/tools/tools-tree.js
@@ -10,13 +10,13 @@
initialize: function(app) {
this.app = app;
},
-
+
/** Convert dictionary representation into tool api specific flat dictionary format.
*/
finalize: function(patch) {
// link this
var self = this;
-
+
// dictionary with api specific identifiers
this.map_dict = {};
@@ -24,24 +24,24 @@
if (!this.app.section) {
return {};
}
-
+
// ensure that dictionary with patching functions exists
patch = patch || {};
-
+
// dictionary formatted for job submission or tool form update
var result_dict = {};
// prepare full dictionary
var dict = {};
-
+
// fill dictionary from dom
this._iterate(this.app.section.$el, dict);
-
+
// add identifier and value to job definition
function add(job_input_id, input_id, input_value) {
// add entry to result dictionary
result_dict[job_input_id] = input_value;
-
+
// backup id mapping
self.map_dict[job_input_id] = input_id;
};
@@ -53,21 +53,21 @@
if (node.input) {
// get node
var input = node.input;
-
+
// create identifier
var job_input_id = identifier;
if (identifier != '') {
job_input_id += '|';
}
job_input_id += input.name;
-
+
// process input type
switch (input.type) {
// handle repeats
case 'repeat':
// section identifier
var section_label = 'section-';
-
+
// collect repeat block identifiers
var block_indices = [];
var block_prefix = null;
@@ -81,10 +81,10 @@
}
}
}
-
+
// sort repeat blocks
block_indices.sort(function(a,b) { return a - b; });
-
+
// add to response dictionary in created order
var index = 0;
for (var i in block_indices) {
@@ -98,10 +98,10 @@
if (patch[input.test_param.type]) {
value = patch[input.test_param.type](value);
}
-
+
// add conditional value
add (job_input_id + '|' + input.test_param.name, input.id, value);
-
+
// identify selected case
var selectedCase = self.matchCase(input, value);
if (selectedCase != -1) {
@@ -116,22 +116,17 @@
// get field
var field = self.app.field_list[input.id];
if (field && field.value) {
+ // validate field value
+ var value = field.value();
+ if (field.validate && !field.validate()) {
+ value = null;
+ }
+
// get and patch field value
- var value = field.value();
if (patch[input.type]) {
value = patch[input.type](value);
}
- // validate field value
- if (field.skip) {
- continue;
- }
-
- // validate field value
- if (field.validate && !field.validate()) {
- value = null;
- }
-
// ignore certain values
if (input.ignore === undefined || (value !== null && input.ignore != value)) {
// add value to submission
@@ -149,20 +144,20 @@
}
}
}
-
+
// start conversion
convert('', dict);
-
+
// return result
return result_dict;
},
-
+
/** Match job definition identifier to input element identifier
*/
match: function (job_input_id) {
return this.map_dict && this.map_dict[job_input_id];
},
-
+
/** Match conditional values to selected cases
*/
matchCase: function(input, value) {
@@ -174,27 +169,27 @@
value = input.test_param.falsevalue || 'false';
}
}
-
+
// find selected case
for (var i in input.cases) {
if (input.cases[i].value == value) {
return i;
}
}
-
+
// selected case not found
return -1;
},
-
+
/** Matches identifier from api model to input elements
*/
matchModel: function(model, callback) {
// final result dictionary
var result = {};
-
+
// link this
var self = this;
-
+
// search throughout response
function search (id, head) {
for (var i in head) {
@@ -224,23 +219,23 @@
}
}
}
-
+
// match all ids and return messages
search('', model.inputs);
// return matched results
return result;
},
-
+
/** Matches identifier from api response to input elements
*/
matchResponse: function(response) {
// final result dictionary
var result = {};
-
+
// link this
var self = this;
-
+
// search throughout response
function search (id, head) {
if (typeof head === 'string') {
@@ -262,14 +257,14 @@
}
}
}
-
+
// match all ids and return messages
search('', response);
-
+
// return matched results
return result;
},
-
+
/** Iterate through the tool form dom and map it to the dictionary.
*/
_iterate: function(parent, dict) {
@@ -279,15 +274,15 @@
children.each(function() {
// get child element
var child = this;
-
+
// get id
var id = $(child).attr('id');
-
+
// create new branch
if ($(child).hasClass('section-row')) {
// create sub dictionary
dict[id] = {};
-
+
// add input element if it exists
var input = self.app.input_list[id];
if (input) {
@@ -295,7 +290,7 @@
input : input
}
}
-
+
// fill sub dictionary
self._iterate(child, dict[id]);
} else {
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 static/scripts/packed/mvc/tools/tools-form-workflow.js
--- a/static/scripts/packed/mvc/tools/tools-form-workflow.js
+++ b/static/scripts/packed/mvc/tools/tools-form-workflow.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/tools/tools-form-base"],function(b,a){var c=a.extend({initialize:function(e){this.node=workflow.active_node;if(!this.node){console.debug("FAILED - tools-form-workflow:initialize() - Node not found in workflow.");return}this.post_job_actions=this.node.post_job_actions||{};this.options=e;this.options.text_enable="In Advance";this.options.text_disable="At Runtime";this.options.is_dynamic=false;this.options.narrow=true;this.options.initial_errors=true;this.options.cls_portlet="ui-portlet-narrow";b.deepeach(e.inputs,function(f){if(f.type){f.optional=(["data","data_hidden","hidden","drill_down","repeat","conditional"]).indexOf(f.type)==-1}});b.deepeach(e.inputs,function(f){if(f.type){if(f.type=="conditional"){f.test_param.optional=false}}});var d=this;b.get({url:galaxy_config.root+"api/datatypes",cache:true,success:function(f){d.datatypes=f;d._makeSections(e.inputs);a.prototype.initialize.call(d,e)}})},_makeSections:function(d){d[b.uuid()]={label:"Annotation / Notes",name:"annotation",type:"text",area:true,help:"Add an annotation or note for this step. It will be shown with the workflow.",value:this.node.annotation};var f=this.node.output_terminals&&Object.keys(this.node.output_terminals)[0];if(f){d[b.uuid()]={name:"pja__"+f+"__EmailAction",label:"Email notification",type:"boolean",value:String(Boolean(this.post_job_actions["EmailAction"+f])),ignore:"false",help:"An email notification will be send when the job has completed.",payload:{host:window.location.host}};d[b.uuid()]={name:"pja__"+f+"__DeleteIntermediatesAction",label:"Output cleanup",type:"boolean",value:String(Boolean(this.post_job_actions["DeleteIntermediatesAction"+f])),ignore:"false",help:"Delete intermediate outputs if they are not used as input for another job."};for(var e in this.node.output_terminals){d[b.uuid()]=this._makeSection(e)}}},_makeSection:function(h){var g=[];for(key in this.datatypes){g.push({0:this.datatypes[key],1:this.datatypes[key]})}g.sort(function(j,i){return j.label>i.label?1:j.label<i.label?-1:0});g.unshift({0:"Sequences",1:"Sequences"});g.unshift({0:"Roadmaps",1:"Roadmaps"});g.unshift({0:"Leave unchanged",1:""});var f={label:"Add Actions: '"+h+"'",type:"section",inputs:[{action:"RenameDatasetAction",argument:"newname",label:"Rename dataset",type:"text",value:"",ignore:"",help:'This action will rename the result dataset. Click <a href="https://wiki.galaxyproject.org/Learn/AdvancedWorkflow/Variables">here</a> for more information.'},{action:"ChangeDatatypeAction",argument:"newtype",label:"Change datatype",type:"select",ignore:"",options:g,help:"This action will change the datatype of the output to the indicated value."},{action:"TagDatasetAction",argument:"tags",label:"Tags",type:"text",value:"",ignore:"",help:"This action will set tags for the dataset."},{label:"Assign columns",type:"section",inputs:[{action:"ColumnSetAction",argument:"chromCol",label:"Chrom column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"startCol",label:"Start column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"endCol",label:"End column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"strandCol",label:"Strand column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"nameCol",label:"Name column",type:"integer",value:"",ignore:""}],help:"This action will set column assignments in the output dataset. Blank fields are ignored."}]};var d=this;function e(n,o){o=o||[];o.push(n);for(var m in n.inputs){var k=n.inputs[m];if(k.action){k.name="pja__"+h+"__"+k.action;if(k.argument){k.name+="__"+k.argument}if(k.payload){for(var s in k.payload){var q=k.payload[s];k.payload[k.name+"__"+s]=q;delete q}}var r=d.post_job_actions[k.action+h];if(r){for(var l in o){o[l].expand=true}if(k.argument){k.value=r.action_arguments&&r.action_arguments[k.argument]||k.value}else{k.value="true"}}}if(k.inputs){e(k,o.slice(0))}}}e(f);return f},_buildModel:function(){Galaxy.modal.show({title:"Coming soon...",body:"This feature has not been implemented yet.",buttons:{Close:function(){Galaxy.modal.hide()}}})},_updateModel:function(){var d=this;var e=this.tree.finalize();console.debug("tools-form-workflow::_refreshForm() - Refreshing states.");console.debug(e);var g=this.deferred.register();var f=galaxy_config.root+"workflow/editor_form_post?tool_id="+this.options.id+"&__is_dynamic__=False";b.request({type:"GET",url:f,data:e,success:function(h){d.node.update_field_data(h);d._errors(h&&h.tool_model);d.deferred.done(g);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(h)},error:function(h){d.deferred.done(g);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(h)}})}});return{View:c}});
\ No newline at end of file
+define(["utils/utils","mvc/tools/tools-form-base"],function(b,a){var c=a.extend({initialize:function(e){this.node=workflow.active_node;if(!this.node){console.debug("FAILED - tools-form-workflow:initialize() - Node not found in workflow.");return}this.post_job_actions=this.node.post_job_actions||{};this.options=e;this.options.text_enable="In Advance";this.options.text_disable="At Runtime";this.options.is_dynamic=false;this.options.narrow=true;this.options.initial_errors=true;this.options.cls_portlet="ui-portlet-narrow";b.deepeach(e.inputs,function(f){if(f.type){f.optional=(["data","data_hidden","hidden","drill_down","repeat","conditional"]).indexOf(f.type)==-1}});b.deepeach(e.inputs,function(f){if(f.type){if(f.type=="conditional"){f.test_param.optional=false}}});var d=this;b.get({url:galaxy_config.root+"api/datatypes",cache:true,success:function(f){d.datatypes=f;d._makeSections(e.inputs);a.prototype.initialize.call(d,e)}})},_makeSections:function(d){d[b.uuid()]={label:"Annotation / Notes",name:"annotation",type:"text",area:true,help:"Add an annotation or note for this step. It will be shown with the workflow.",value:this.node.annotation};var f=this.node.output_terminals&&Object.keys(this.node.output_terminals)[0];if(f){d[b.uuid()]={name:"pja__"+f+"__EmailAction",label:"Email notification",type:"boolean",value:String(Boolean(this.post_job_actions["EmailAction"+f])),ignore:"false",help:"An email notification will be send when the job has completed.",payload:{host:window.location.host}};d[b.uuid()]={name:"pja__"+f+"__DeleteIntermediatesAction",label:"Output cleanup",type:"boolean",value:String(Boolean(this.post_job_actions["DeleteIntermediatesAction"+f])),ignore:"false",help:"Delete intermediate outputs if they are not used as input for another job."};for(var e in this.node.output_terminals){d[b.uuid()]=this._makeSection(e)}}},_makeSection:function(h){var g=[];for(key in this.datatypes){g.push({0:this.datatypes[key],1:this.datatypes[key]})}g.sort(function(j,i){return j.label>i.label?1:j.label<i.label?-1:0});g.unshift({0:"Sequences",1:"Sequences"});g.unshift({0:"Roadmaps",1:"Roadmaps"});g.unshift({0:"Leave unchanged",1:""});var f={label:"Add Actions: '"+h+"'",type:"section",inputs:[{action:"RenameDatasetAction",argument:"newname",label:"Rename dataset",type:"text",value:"",ignore:"",help:'This action will rename the result dataset. Click <a href="https://wiki.galaxyproject.org/Learn/AdvancedWorkflow/Variables">here</a> for more information.'},{action:"ChangeDatatypeAction",argument:"newtype",label:"Change datatype",type:"select",ignore:"",options:g,help:"This action will change the datatype of the output to the indicated value."},{action:"TagDatasetAction",argument:"tags",label:"Tags",type:"text",value:"",ignore:"",help:"This action will set tags for the dataset."},{label:"Assign columns",type:"section",inputs:[{action:"ColumnSetAction",argument:"chromCol",label:"Chrom column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"startCol",label:"Start column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"endCol",label:"End column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"strandCol",label:"Strand column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"nameCol",label:"Name column",type:"integer",value:"",ignore:""}],help:"This action will set column assignments in the output dataset. Blank fields are ignored."}]};var d=this;function e(n,o){o=o||[];o.push(n);for(var m in n.inputs){var k=n.inputs[m];if(k.action){k.name="pja__"+h+"__"+k.action;if(k.argument){k.name+="__"+k.argument}if(k.payload){for(var s in k.payload){var q=k.payload[s];k.payload[k.name+"__"+s]=q;delete q}}var r=d.post_job_actions[k.action+h];if(r){for(var l in o){o[l].expand=true}if(k.argument){k.value=r.action_arguments&&r.action_arguments[k.argument]||k.value}else{k.value="true"}}}if(k.inputs){e(k,o.slice(0))}}}e(f);return f},_buildModel:function(){Galaxy.modal.show({title:"Coming soon...",body:"This feature has not been implemented yet.",buttons:{Close:function(){Galaxy.modal.hide()}}})},_updateModel:function(){var d=this;var e={tool_id:this.options.id,tool_version:this.options.version,inputs:this.tree.finalize()};console.debug("tools-form-workflow::_refreshForm() - Refreshing states.");console.debug(e);var g=this.deferred.register();var f=galaxy_config.root+"api/workflows/build_module";b.request({type:"POST",url:f,data:e,success:function(h){d.node.update_field_data(h);d._errors(h&&h.tool_model);d.deferred.done(g);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(h)},error:function(h){d.deferred.done(g);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(h)}})}});return{View:c}});
\ No newline at end of file
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 static/scripts/packed/mvc/tools/tools-tree.js
--- a/static/scripts/packed/mvc/tools/tools-tree.js
+++ b/static/scripts/packed/mvc/tools/tools-tree.js
@@ -1,1 +1,1 @@
-define(["utils/utils"],function(a){return Backbone.Model.extend({initialize:function(b){this.app=b},finalize:function(g){var b=this;this.map_dict={};if(!this.app.section){return{}}g=g||{};var f={};var e={};this._iterate(this.app.section.$el,e);function d(j,i,h){f[j]=h;b.map_dict[j]=i}function c(p,s){for(var n in s){var k=s[n];if(k.input){var u=k.input;var o=p;if(p!=""){o+="|"}o+=u.name;switch(u.type){case"repeat":var j="section-";var x=[];var r=null;for(var w in k){var q=w.indexOf(j);if(q!=-1){q+=j.length;x.push(parseInt(w.substr(q)));if(!r){r=w.substr(0,q)}}}x.sort(function(y,i){return y-i});var n=0;for(var l in x){c(o+"_"+n++,k[r+x[l]])}break;case"conditional":var v=b.app.field_list[u.id].value();if(g[u.test_param.type]){v=g[u.test_param.type](v)}d(o+"|"+u.test_param.name,u.id,v);var h=b.matchCase(u,v);if(h!=-1){c(o,s[u.id+"-section-"+h])}break;case"section":c("",k);break;default:var t=b.app.field_list[u.id];if(t&&t.value){var v=t.value();if(g[u.type]){v=g[u.type](v)}if(t.skip){continue}if(t.validate&&!t.validate()){v=null}if(u.ignore===undefined||(v!==null&&u.ignore!=v)){d(o,u.id,v);if(u.payload){for(var m in u.payload){d(m,u.id,u.payload[m])}}}}}}}}c("",e);return f},match:function(b){return this.map_dict&&this.map_dict[b]},matchCase:function(b,d){if(b.test_param.type=="boolean"){if(d=="true"){d=b.test_param.truevalue||"true"}else{d=b.test_param.falsevalue||"false"}}for(var c in b.cases){if(b.cases[c].value==d){return c}}return -1},matchModel:function(d,f){var b={};var c=this;function e(g,p){for(var m in p){var k=p[m];var n=k.name;if(g!=""){n=g+"|"+n}switch(k.type){case"repeat":for(var l in k.cache){e(n+"_"+l,k.cache[l])}break;case"conditional":var q=k.test_param&&k.test_param.value;var h=c.matchCase(k,q);if(h!=-1){e(n,k.cases[h].inputs)}break;default:var o=c.map_dict[n];if(o){f(o,k)}}}}e("",d.inputs);return b},matchResponse:function(d){var b={};var c=this;function e(l,j){if(typeof j==="string"){var g=c.map_dict[l];if(g){b[g]=j}}else{for(var h in j){var f=h;if(l!==""){var k="|";if(j instanceof Array){k="_"}f=l+k+f}e(f,j[h])}}}e("",d);return b},_iterate:function(d,e){var b=this;var c=$(d).children();c.each(function(){var h=this;var g=$(h).attr("id");if($(h).hasClass("section-row")){e[g]={};var f=b.app.input_list[g];if(f){e[g]={input:f}}b._iterate(h,e[g])}else{b._iterate(h,e)}})}})});
\ No newline at end of file
+define(["utils/utils"],function(a){return Backbone.Model.extend({initialize:function(b){this.app=b},finalize:function(g){var b=this;this.map_dict={};if(!this.app.section){return{}}g=g||{};var f={};var e={};this._iterate(this.app.section.$el,e);function d(j,i,h){f[j]=h;b.map_dict[j]=i}function c(p,s){for(var n in s){var k=s[n];if(k.input){var u=k.input;var o=p;if(p!=""){o+="|"}o+=u.name;switch(u.type){case"repeat":var j="section-";var x=[];var r=null;for(var w in k){var q=w.indexOf(j);if(q!=-1){q+=j.length;x.push(parseInt(w.substr(q)));if(!r){r=w.substr(0,q)}}}x.sort(function(y,i){return y-i});var n=0;for(var l in x){c(o+"_"+n++,k[r+x[l]])}break;case"conditional":var v=b.app.field_list[u.id].value();if(g[u.test_param.type]){v=g[u.test_param.type](v)}d(o+"|"+u.test_param.name,u.id,v);var h=b.matchCase(u,v);if(h!=-1){c(o,s[u.id+"-section-"+h])}break;case"section":c("",k);break;default:var t=b.app.field_list[u.id];if(t&&t.value){var v=t.value();if(t.validate&&!t.validate()){v=null}if(g[u.type]){v=g[u.type](v)}if(u.ignore===undefined||(v!==null&&u.ignore!=v)){d(o,u.id,v);if(u.payload){for(var m in u.payload){d(m,u.id,u.payload[m])}}}}}}}}c("",e);return f},match:function(b){return this.map_dict&&this.map_dict[b]},matchCase:function(b,d){if(b.test_param.type=="boolean"){if(d=="true"){d=b.test_param.truevalue||"true"}else{d=b.test_param.falsevalue||"false"}}for(var c in b.cases){if(b.cases[c].value==d){return c}}return -1},matchModel:function(d,f){var b={};var c=this;function e(g,p){for(var m in p){var k=p[m];var n=k.name;if(g!=""){n=g+"|"+n}switch(k.type){case"repeat":for(var l in k.cache){e(n+"_"+l,k.cache[l])}break;case"conditional":var q=k.test_param&&k.test_param.value;var h=c.matchCase(k,q);if(h!=-1){e(n,k.cases[h].inputs)}break;default:var o=c.map_dict[n];if(o){f(o,k)}}}}e("",d.inputs);return b},matchResponse:function(d){var b={};var c=this;function e(l,j){if(typeof j==="string"){var g=c.map_dict[l];if(g){b[g]=j}}else{for(var h in j){var f=h;if(l!==""){var k="|";if(j instanceof Array){k="_"}f=l+k+f}e(f,j[h])}}}e("",d);return b},_iterate:function(d,e){var b=this;var c=$(d).children();c.each(function(){var h=this;var g=$(h).attr("id");if($(h).hasClass("section-row")){e[g]={};var f=b.app.input_list[g];if(f){e[g]={input:f}}b._iterate(h,e[g])}else{b._iterate(h,e)}})}})});
\ No newline at end of file
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 templates/webapps/galaxy/tool_form.mako
--- a/templates/webapps/galaxy/tool_form.mako
+++ b/templates/webapps/galaxy/tool_form.mako
@@ -10,7 +10,7 @@
## This avoids making two separate requests since the classic form requires the mako anyway.
params = dict(trans.request.params)
params['__dataset_id__'] = params.get('id', None)
- self.form_config = tool.to_json(trans, **params)
+ self.form_config = tool.to_json(trans, params)
self.form_config.update({
'id' : tool.id,
'job_id' : trans.security.encode_id( job.id ) if job else None,
diff -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 -r de8fa2d2312eaad8178fe9aa39a2278bae7da239 templates/webapps/galaxy/workflow/editor_tool_form.mako
--- a/templates/webapps/galaxy/workflow/editor_tool_form.mako
+++ b/templates/webapps/galaxy/workflow/editor_tool_form.mako
@@ -6,11 +6,9 @@
## TEMPORARY: create tool dictionary in mako while both tool forms are in use.
## This avoids making two separate requests since the classic form requires the mako anyway.
from galaxy.tools.parameters import params_to_incoming
- incoming = {
- '__is_dynamic__' : False
- }
+ incoming = {}
params_to_incoming( incoming, tool.inputs, module.state.inputs, trans.app, to_html=False)
- self.form_config = tool.to_json(trans, **incoming)
+ self.form_config = tool.to_json(trans, incoming, is_dynamic=False)
self.form_config.update({
'id' : tool.id,
'job_id' : trans.security.encode_id( job.id ) if job else 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
commit/galaxy-central: jmchilton: Link to "easiest ways to start" card in CONTRIBUTING.md.
by commits-noreply@bitbucket.org 09 Feb '15
by commits-noreply@bitbucket.org 09 Feb '15
09 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/28126538ef19/
Changeset: 28126538ef19
User: jmchilton
Date: 2015-02-08 23:17:10+00:00
Summary: Link to "easiest ways to start" card in CONTRIBUTING.md.
Affected #: 1 file
diff -r 7ad7c739fd195596fec28531fe55830cf7a3039e -r 28126538ef19e8dc9d5a5dede2ccf3080ccdf603 CONTRIBUTING.md
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -81,6 +81,13 @@
* A description of how to test the change.
+## Ideas
+
+Galaxy's [Trello board](http://bit.ly/gxytrello) is filled with bugs and ideas
+for enhancements, but we maintain a [card](https://trello.com/c/eFdPIdIB) with
+links to smaller issues we believe would make the best entry points for new
+developers.
+
## A Quick Note about Tools
For the most part, Galaxy tools should be published to the
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/edc4b7ae61b6/
Changeset: edc4b7ae61b6
User: jmchilton
Date: 2015-02-08 20:29:02+00:00
Summary: Add link to actual presentation slides to CONTRIBUTING.md.
For people who want to follow along with Dannon at home.
Affected #: 1 file
diff -r 2c93bedd4898c21ccaa0de413ffedcba91220bb1 -r edc4b7ae61b6036b2fdcbe032d35ae3f0a3115f0 CONTRIBUTING.md
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,12 +1,13 @@
# Contributing
This document briefly describes how to contribute to the
-galaxy-central core project - also checkout the video of our [2013
-Galaxy Community Conference
-presentation](http://vimeo.com/channels/581875/73486255) on the
-topic. For information on contributing more broadly to the Galaxy
-ecosystem and a deeper discussion of some of these points - please see
-the [Develop](https://wiki.galaxyproject.org/Develop/) section of the
+galaxy-central core project - also checkout our 2013 Galaxy Community
+Conference presentation] on the topic
+([video](http://vimeo.com/channels/581875/73486255),
+[presentation](https://wiki.galaxyproject.org/Documents/Presentations/GCC2013?action=AttachFile&do=view&target=BakerContribute.pdf)). For
+information on contributing more broadly to the Galaxy ecosystem and a
+deeper discussion of some of these points - please see the
+[Develop](https://wiki.galaxyproject.org/Develop/) section of the
[Galaxy Wiki](https://wiki.galaxyproject.org/).
## Before you Begin
https://bitbucket.org/galaxy/galaxy-central/commits/7ad7c739fd19/
Changeset: 7ad7c739fd19
User: jmchilton
Date: 2015-02-08 20:31:45+00:00
Summary: Merge.
Affected #: 3 files
diff -r edc4b7ae61b6036b2fdcbe032d35ae3f0a3115f0 -r 7ad7c739fd195596fec28531fe55830cf7a3039e lib/galaxy/forms/forms.py
--- a/lib/galaxy/forms/forms.py
+++ b/lib/galaxy/forms/forms.py
@@ -50,7 +50,7 @@
#load fields
fields = []
fields_elem = elem.find( 'fields' )
- if fields_elem:
+ if fields_elem is not None:
for field_elem in fields_elem.findall( 'field' ):
field_type = field_elem.get( 'type' )
assert field_type in self.field_type_factories, 'Invalid form field type ( %s ).' % field_type
diff -r edc4b7ae61b6036b2fdcbe032d35ae3f0a3115f0 -r 7ad7c739fd195596fec28531fe55830cf7a3039e lib/galaxy/sample_tracking/external_service_types.py
--- a/lib/galaxy/sample_tracking/external_service_types.py
+++ b/lib/galaxy/sample_tracking/external_service_types.py
@@ -96,9 +96,9 @@
def parse_run_details( self, root ):
self.run_details = {}
run_details_elem = root.find( 'run_details' )
- if run_details_elem:
+ if run_details_elem is not None:
results_elem = run_details_elem.find( 'results' )
- if results_elem:
+ if results_elem is not None:
# Get the list of resulting datatypes
# TODO: the 'results_urls' attribute is only useful if the transfer protocol is http(s), so check if that is the case.
self.run_details[ 'results' ], self.run_details[ 'results_urls' ] = self.parse_run_details_results( results_elem )
diff -r edc4b7ae61b6036b2fdcbe032d35ae3f0a3115f0 -r 7ad7c739fd195596fec28531fe55830cf7a3039e lib/galaxy/workflow/scheduling_manager.py
--- a/lib/galaxy/workflow/scheduling_manager.py
+++ b/lib/galaxy/workflow/scheduling_manager.py
@@ -31,11 +31,11 @@
self.app = app
self.__job_config = app.job_config
self.workflow_schedulers = {}
- self.active_workflow_schedulers = {} # Passive workflow schedulers
- # won't need to be monitored I
- # guess.
+ self.active_workflow_schedulers = {}
+ # Passive workflow schedulers won't need to be monitored I guess.
+
self.request_monitor = None
-
+
self.__plugin_classes = self.__plugins_dict()
self.__init_schedulers()
@@ -67,7 +67,7 @@
try:
self.request_monitor.shutdown()
except Exception:
- log.exception( "Failed to shutdown worklfow request monitor." )
+ log.exception( "Failed to shutdown workflow request monitor." )
def queue( self, workflow_invocation, request_params ):
workflow_invocation.state = model.WorkflowInvocation.states.NEW
@@ -112,8 +112,7 @@
def __init_schedulers_for_element( self, plugins_element ):
plugins_kwds = dict( plugins_element.items() )
self.default_scheduler_id = plugins_kwds.get( 'default', DEFAULT_SCHEDULER_ID )
-
- for plugin_element in plugins_element.getchildren():
+ for plugin_element in plugins_element:
plugin_type = plugin_element.tag
plugin_kwds = dict( plugin_element.items() )
workflow_scheduler_id = plugin_kwds.get( 'id', None )
@@ -134,7 +133,7 @@
self.workflow_schedulers[ workflow_scheduler_id ] = workflow_scheduler
if isinstance( workflow_scheduler, galaxy.workflow.schedulers.ActiveWorkflowSchedulingPlugin ):
self.active_workflow_schedulers[ workflow_scheduler_id ] = workflow_scheduler
-
+
def __start_request_monitor( self ):
self.request_monitor = WorkflowRequestMonitor( self.app, self )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/b654710d5844/
Changeset: b654710d5844
User: dannon
Date: 2015-02-08 16:16:14+00:00
Summary: Fix a few instances of incorrect (deprecated) use of value instead of identity testing in xml parsing.
Affected #: 3 files
diff -r 1b09e60f84db859ae49bed71c6f3fd838af612f5 -r b654710d58445917baae8e3ec8f78acc745ef262 lib/galaxy/forms/forms.py
--- a/lib/galaxy/forms/forms.py
+++ b/lib/galaxy/forms/forms.py
@@ -50,7 +50,7 @@
#load fields
fields = []
fields_elem = elem.find( 'fields' )
- if fields_elem:
+ if fields_elem is not None:
for field_elem in fields_elem.findall( 'field' ):
field_type = field_elem.get( 'type' )
assert field_type in self.field_type_factories, 'Invalid form field type ( %s ).' % field_type
diff -r 1b09e60f84db859ae49bed71c6f3fd838af612f5 -r b654710d58445917baae8e3ec8f78acc745ef262 lib/galaxy/sample_tracking/external_service_types.py
--- a/lib/galaxy/sample_tracking/external_service_types.py
+++ b/lib/galaxy/sample_tracking/external_service_types.py
@@ -96,9 +96,9 @@
def parse_run_details( self, root ):
self.run_details = {}
run_details_elem = root.find( 'run_details' )
- if run_details_elem:
+ if run_details_elem is not None:
results_elem = run_details_elem.find( 'results' )
- if results_elem:
+ if results_elem is not None:
# Get the list of resulting datatypes
# TODO: the 'results_urls' attribute is only useful if the transfer protocol is http(s), so check if that is the case.
self.run_details[ 'results' ], self.run_details[ 'results_urls' ] = self.parse_run_details_results( results_elem )
diff -r 1b09e60f84db859ae49bed71c6f3fd838af612f5 -r b654710d58445917baae8e3ec8f78acc745ef262 lib/galaxy/workflow/scheduling_manager.py
--- a/lib/galaxy/workflow/scheduling_manager.py
+++ b/lib/galaxy/workflow/scheduling_manager.py
@@ -112,8 +112,7 @@
def __init_schedulers_for_element( self, plugins_element ):
plugins_kwds = dict( plugins_element.items() )
self.default_scheduler_id = plugins_kwds.get( 'default', DEFAULT_SCHEDULER_ID )
-
- for plugin_element in plugins_element.getchildren():
+ for plugin_element in plugins_element:
plugin_type = plugin_element.tag
plugin_kwds = dict( plugin_element.items() )
workflow_scheduler_id = plugin_kwds.get( 'id', None )
https://bitbucket.org/galaxy/galaxy-central/commits/a02abac7d68d/
Changeset: a02abac7d68d
User: dannon
Date: 2015-02-08 16:21:42+00:00
Summary: Minor formatting, spelling in workflow scheduling_manager.
Affected #: 1 file
diff -r b654710d58445917baae8e3ec8f78acc745ef262 -r a02abac7d68dd4decd91e5a24022dc6648bf011c lib/galaxy/workflow/scheduling_manager.py
--- a/lib/galaxy/workflow/scheduling_manager.py
+++ b/lib/galaxy/workflow/scheduling_manager.py
@@ -31,11 +31,11 @@
self.app = app
self.__job_config = app.job_config
self.workflow_schedulers = {}
- self.active_workflow_schedulers = {} # Passive workflow schedulers
- # won't need to be monitored I
- # guess.
+ self.active_workflow_schedulers = {}
+ # Passive workflow schedulers won't need to be monitored I guess.
+
self.request_monitor = None
-
+
self.__plugin_classes = self.__plugins_dict()
self.__init_schedulers()
@@ -67,7 +67,7 @@
try:
self.request_monitor.shutdown()
except Exception:
- log.exception( "Failed to shutdown worklfow request monitor." )
+ log.exception( "Failed to shutdown workflow request monitor." )
def queue( self, workflow_invocation, request_params ):
workflow_invocation.state = model.WorkflowInvocation.states.NEW
@@ -133,7 +133,7 @@
self.workflow_schedulers[ workflow_scheduler_id ] = workflow_scheduler
if isinstance( workflow_scheduler, galaxy.workflow.schedulers.ActiveWorkflowSchedulingPlugin ):
self.active_workflow_schedulers[ workflow_scheduler_id ] = workflow_scheduler
-
+
def __start_request_monitor( self ):
self.request_monitor = WorkflowRequestMonitor( self.app, self )
https://bitbucket.org/galaxy/galaxy-central/commits/ea23071cf22e/
Changeset: ea23071cf22e
User: dannon
Date: 2015-02-08 20:09:23+00:00
Summary: Merge.
Affected #: 1 file
diff -r a02abac7d68dd4decd91e5a24022dc6648bf011c -r ea23071cf22ea78b699264e04b59e3adf88ec619 CONTRIBUTING.md
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,93 @@
+# Contributing
+
+This document briefly describes how to contribute to the
+galaxy-central core project - also checkout the video of our [2013
+Galaxy Community Conference
+presentation](http://vimeo.com/channels/581875/73486255) on the
+topic. For information on contributing more broadly to the Galaxy
+ecosystem and a deeper discussion of some of these points - please see
+the [Develop](https://wiki.galaxyproject.org/Develop/) section of the
+[Galaxy Wiki](https://wiki.galaxyproject.org/).
+
+## Before you Begin
+
+If you have an idea for a feature to add or an approach for a bugfix -
+it is best to communicate with Galaxy developers early. The most
+common venue for this is the [Galaxy Trello
+board](https://wiki.galaxyproject.org/Issues). Browse through existing
+cards [here](http://bit.ly/gxytrello) and if one seems related comment
+on it. If no existing cards seem appropriate, a new issue can be
+opened using [this form](http://galaxyproject.org/trello). Galaxy
+developers are also generally available via
+[IRC](https://wiki.galaxyproject.org/GetInvolved#IRC_Channel) and on
+the [development mailing list](http://dev.list.galaxyproject.org/).
+
+## How to Contribute
+
+* If you are new to Mercurial - please check out this [official
+ tutorial](http://mercurial.selenic.com/wiki/Tutorial)
+
+* Make sure you have a free [Bitbucket
+ account](https://bitbucket.org/account/signup/)
+
+* Fork the galaxy-central repository on
+ [Bitbucket](https://bitbucket.org/galaxy/galaxy-central/fork) to
+ make your changes. (Many Galaxy instances target
+ [galaxy-dist](https://bitbucket.org/galaxy/galaxy-dist) - but active
+ development happens on galaxy-central and this is where pull
+ requests should be made).
+
+* Choose the correct Mercurial branch to develop your changes against.
+
+ * Additions to the code base should be pushed to the `default`
+ branch (`hg checkout default`).
+
+ * Most bug fixes to previously release components (things in
+ galaxy-dist) should be pushed to the `stable` branch (`hg checkout
+ stable`).
+
+ * Serious security problems should not be fixed via pull request -
+ please responsibly disclose these by e-mailing them (with or
+ without patches) to galaxy-lab(a)bx.psu.edu. The Galaxy core
+ development team will issue patches to public servers before
+ announcing the issue to ensure there is time to patch and
+ highlight these fixes widely. We will provide you credit for the
+ discovery when publicly disclosing the issue.
+
+* If your changes modify code - please ensure the resulting files
+ conform to Galaxy [style
+ guidelines](https://wiki.galaxyproject.org/Develop/BestPractices).
+
+* Galaxy contains hundreds of tests of different types and complexity
+ and running each is difficult and probably not reasonable at this
+ time (someday we will provide a holistic test procedure to make this
+ possible). For now, please just review the [running tests
+ documentation](https://wiki.galaxyproject.org/Admin/RunningTests)
+ and run any that seem relevant. Developers reviewing your pull
+ request will be happy to help guide you to running the most relevant
+ tests as part of the pull request review process and may request the
+ output of these tests.
+
+* Commit and push your changes to your Bitbucket fork.
+
+* Open a [pull
+ request](https://confluence.atlassian.com/display/BITBUCKET/Fork+a+Repo,+Co…
+ with these changes. You pull request message should include:
+
+ * A description of why the change should be made.
+
+ * A description of implementation of the change.
+
+ * A description of how to test the change.
+
+## A Quick Note about Tools
+
+ For the most part, Galaxy tools should be published to the
+ [ToolShed](https://wiki.galaxyproject.org/ToolShed) and not in this
+ repository directly. If you are looking to supply fixes for migrated
+ core tools that used to exist in this repository - please checkout
+ the [tools-devteam](https://github.com/galaxyproject/tools-devteam)
+ repository on GitHub.
+
+ More information about tool development can be found [on the
+ wiki](https://wiki.galaxyproject.org/Develop).
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: First crack at a CONTRIBUTING file for galaxy-central.
by commits-noreply@bitbucket.org 09 Feb '15
by commits-noreply@bitbucket.org 09 Feb '15
09 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2c93bedd4898/
Changeset: 2c93bedd4898
User: jmchilton
Date: 2015-02-08 20:02:54+00:00
Summary: First crack at a CONTRIBUTING file for galaxy-central.
Ideally this would come in through a pull request but I am trying to rush through documentation related to Galaxy development ahead of a GSOC application - by all means I would encourage comments related to this commit as well as well as direct modifications.
CONTRIBUTING files are meant to encourge developers to contribute to open source projects by spelling out how to contribute and what is expected from contributions. More resources related to CONTRIBUTION files include:
- http://contribute.md/
- https://github.com/blog/1184-contributing-guidelines
This isn't coming at the expense of wiki documentation - I have already made dozens of enhancements to the Develop section of the wiki today and I am planning a huge walkthrough of how to contribute and learn about various aspect of the broader Galaxy community from a new developer perspective. Having this file in place though I feel is an important part of that however.
Affected #: 1 file
diff -r 1b09e60f84db859ae49bed71c6f3fd838af612f5 -r 2c93bedd4898c21ccaa0de413ffedcba91220bb1 CONTRIBUTING.md
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,93 @@
+# Contributing
+
+This document briefly describes how to contribute to the
+galaxy-central core project - also checkout the video of our [2013
+Galaxy Community Conference
+presentation](http://vimeo.com/channels/581875/73486255) on the
+topic. For information on contributing more broadly to the Galaxy
+ecosystem and a deeper discussion of some of these points - please see
+the [Develop](https://wiki.galaxyproject.org/Develop/) section of the
+[Galaxy Wiki](https://wiki.galaxyproject.org/).
+
+## Before you Begin
+
+If you have an idea for a feature to add or an approach for a bugfix -
+it is best to communicate with Galaxy developers early. The most
+common venue for this is the [Galaxy Trello
+board](https://wiki.galaxyproject.org/Issues). Browse through existing
+cards [here](http://bit.ly/gxytrello) and if one seems related comment
+on it. If no existing cards seem appropriate, a new issue can be
+opened using [this form](http://galaxyproject.org/trello). Galaxy
+developers are also generally available via
+[IRC](https://wiki.galaxyproject.org/GetInvolved#IRC_Channel) and on
+the [development mailing list](http://dev.list.galaxyproject.org/).
+
+## How to Contribute
+
+* If you are new to Mercurial - please check out this [official
+ tutorial](http://mercurial.selenic.com/wiki/Tutorial)
+
+* Make sure you have a free [Bitbucket
+ account](https://bitbucket.org/account/signup/)
+
+* Fork the galaxy-central repository on
+ [Bitbucket](https://bitbucket.org/galaxy/galaxy-central/fork) to
+ make your changes. (Many Galaxy instances target
+ [galaxy-dist](https://bitbucket.org/galaxy/galaxy-dist) - but active
+ development happens on galaxy-central and this is where pull
+ requests should be made).
+
+* Choose the correct Mercurial branch to develop your changes against.
+
+ * Additions to the code base should be pushed to the `default`
+ branch (`hg checkout default`).
+
+ * Most bug fixes to previously release components (things in
+ galaxy-dist) should be pushed to the `stable` branch (`hg checkout
+ stable`).
+
+ * Serious security problems should not be fixed via pull request -
+ please responsibly disclose these by e-mailing them (with or
+ without patches) to galaxy-lab(a)bx.psu.edu. The Galaxy core
+ development team will issue patches to public servers before
+ announcing the issue to ensure there is time to patch and
+ highlight these fixes widely. We will provide you credit for the
+ discovery when publicly disclosing the issue.
+
+* If your changes modify code - please ensure the resulting files
+ conform to Galaxy [style
+ guidelines](https://wiki.galaxyproject.org/Develop/BestPractices).
+
+* Galaxy contains hundreds of tests of different types and complexity
+ and running each is difficult and probably not reasonable at this
+ time (someday we will provide a holistic test procedure to make this
+ possible). For now, please just review the [running tests
+ documentation](https://wiki.galaxyproject.org/Admin/RunningTests)
+ and run any that seem relevant. Developers reviewing your pull
+ request will be happy to help guide you to running the most relevant
+ tests as part of the pull request review process and may request the
+ output of these tests.
+
+* Commit and push your changes to your Bitbucket fork.
+
+* Open a [pull
+ request](https://confluence.atlassian.com/display/BITBUCKET/Fork+a+Repo,+Co…
+ with these changes. You pull request message should include:
+
+ * A description of why the change should be made.
+
+ * A description of implementation of the change.
+
+ * A description of how to test the change.
+
+## A Quick Note about Tools
+
+ For the most part, Galaxy tools should be published to the
+ [ToolShed](https://wiki.galaxyproject.org/ToolShed) and not in this
+ repository directly. If you are looking to supply fixes for migrated
+ core tools that used to exist in this repository - please checkout
+ the [tools-devteam](https://github.com/galaxyproject/tools-devteam)
+ repository on GitHub.
+
+ More information about tool development can be found [on the
+ wiki](https://wiki.galaxyproject.org/Develop).
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/b0ff7d6cfe40/
Changeset: b0ff7d6cfe40
User: jmchilton
Date: 2015-02-08 00:32:16+00:00
Summary: Rework control queue setup to work in non-web contexts.
Namely in the new lib/galaxy/main.py. I think this break down of the code makes more sense also since control queues aren't inheriently something web-y so lib/galaxy/app.py makes more sense for configuring them. Dannon feel free to reorganize if you dislike this particular organization - I just wanted to make sure lib/galaxy/main.py could share in the new stuff.
Affected #: 3 files
diff -r 5964dac35d2eb268097632ca65c3abbbdf624716 -r b0ff7d6cfe407ecae40dc761b0970ac2cfaa76e2 lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -144,6 +144,12 @@
self.model.engine.dispose()
+ def setup_control_queue(self):
+ self.control_worker = GalaxyQueueWorker(self, galaxy.queues.control_queue_from_config(self.config),
+ galaxy.queue_worker.control_message_to_task)
+ self.control_worker.daemon = True
+ self.control_worker.start()
+
def shutdown( self ):
self.workflow_scheduling_manager.shutdown()
self.job_manager.shutdown()
diff -r 5964dac35d2eb268097632ca65c3abbbdf624716 -r b0ff7d6cfe407ecae40dc761b0970ac2cfaa76e2 lib/galaxy/main.py
--- a/lib/galaxy/main.py
+++ b/lib/galaxy/main.py
@@ -101,6 +101,7 @@
global_conf={"__file__": config_builder.ini_path},
**kwds
)
+ app.setup_control_queue()
return app
diff -r 5964dac35d2eb268097632ca65c3abbbdf624716 -r b0ff7d6cfe407ecae40dc761b0970ac2cfaa76e2 lib/galaxy/webapps/galaxy/buildapp.py
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -123,14 +123,10 @@
@postfork
def postfork_setup():
from galaxy.app import app
- from galaxy.queue_worker import GalaxyQueueWorker
if app.config.is_uwsgi:
import uwsgi
app.config.server_name += ".%s" % uwsgi.worker_id()
- app.control_worker = GalaxyQueueWorker(app, galaxy.queues.control_queue_from_config(app.config),
- galaxy.queue_worker.control_message_to_task)
- app.control_worker.daemon = True
- app.control_worker.start()
+ app.setup_control_queue()
def populate_api_routes( webapp, app ):
https://bitbucket.org/galaxy/galaxy-central/commits/1b09e60f84db/
Changeset: 1b09e60f84db
User: jmchilton
Date: 2015-02-08 00:32:16+00:00
Summary: Fix running tool tests for recent control reworking.
Affected #: 1 file
diff -r b0ff7d6cfe407ecae40dc761b0970ac2cfaa76e2 -r 1b09e60f84db859ae49bed71c6f3fd838af612f5 lib/galaxy/webapps/galaxy/buildapp.py
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -47,6 +47,7 @@
# Create the Galaxy application unless passed in
if 'app' in kwargs:
app = kwargs.pop( 'app' )
+ galaxy.app.app = app
else:
try:
app = galaxy.app.UniverseApplication( global_conf=global_conf, **kwargs )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: Ui: Use placeholder title
by commits-noreply@bitbucket.org 07 Feb '15
by commits-noreply@bitbucket.org 07 Feb '15
07 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5964dac35d2e/
Changeset: 5964dac35d2e
User: guerler
Date: 2015-02-07 04:32:58+00:00
Summary: Ui: Use placeholder title
Affected #: 3 files
diff -r 394cf89ac0044524bf1f2dac6971a4d593c714ec -r 5964dac35d2eb268097632ca65c3abbbdf624716 client/galaxy/scripts/mvc/tools/tools-repeat.js
--- a/client/galaxy/scripts/mvc/tools/tools-repeat.js
+++ b/client/galaxy/scripts/mvc/tools/tools-repeat.js
@@ -88,7 +88,7 @@
// create portlet
var portlet = new Portlet.View({
id : options.id,
- title : '<b>' + options.title + '</b>',
+ title : 'placeholder',
cls : 'ui-portlet-repeat',
operations : {
button_delete : button_delete
diff -r 394cf89ac0044524bf1f2dac6971a4d593c714ec -r 5964dac35d2eb268097632ca65c3abbbdf624716 static/scripts/mvc/tools/tools-repeat.js
--- a/static/scripts/mvc/tools/tools-repeat.js
+++ b/static/scripts/mvc/tools/tools-repeat.js
@@ -88,7 +88,7 @@
// create portlet
var portlet = new Portlet.View({
id : options.id,
- title : '<b>' + options.title + '</b>',
+ title : 'placeholder',
cls : 'ui-portlet-repeat',
operations : {
button_delete : button_delete
diff -r 394cf89ac0044524bf1f2dac6971a4d593c714ec -r 5964dac35d2eb268097632ca65c3abbbdf624716 static/scripts/packed/mvc/tools/tools-repeat.js
--- a/static/scripts/packed/mvc/tools/tools-repeat.js
+++ b/static/scripts/packed/mvc/tools/tools-repeat.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-portlet","mvc/ui/ui-misc"],function(c,a,b,e){var d=Backbone.View.extend({optionsDefault:{title:"Section",max:null,min:null},initialize:function(g){this.options=c.merge(g,this.optionsDefault);this.setElement("<div/>");var f=this;this.button_new=new e.ButtonIcon({icon:"fa-plus",title:"Insert "+g.title_new,tooltip:"Add new "+g.title_new+" block",floating:"clear",onclick:function(){if(g.onnew){g.onnew()}}});this.table=new a.View({cls:"ui-table-plain",content:""});this.$el.append(this.table.$el);this.$el.append($("<div/>").append(this.button_new.$el));this.list={};this.n=0},size:function(){return this.n},add:function(g){if(!g.id||this.list[g.id]){console.debug("tools-repeat::add - Duplicate repeat block id.");return}this.n++;var f=new e.ButtonIcon({icon:"fa-trash-o",tooltip:"Delete this repeat block",cls:"ui-button-icon-plain",onclick:function(){if(g.ondel){g.ondel()}}});var h=new b.View({id:g.id,title:"<b>"+g.title+"</b>",cls:"ui-portlet-repeat",operations:{button_delete:f}});h.append(g.$el);h.$el.addClass("section-row");this.list[g.id]=h;this.table.add(h.$el);this.table.append("row_"+g.id,true);if(this.options.max>0&&this.n>=this.options.max){this.button_new.disable()}this._refresh()},del:function(g){if(!this.list[g]){console.debug("tools-repeat::del - Invalid repeat block id.");return}this.n--;var f=this.table.get("row_"+g);f.remove();delete this.list[g];this.button_new.enable();this._refresh()},_refresh:function(){var f=0;for(var h in this.list){var g=this.list[h];g.title(++f+": "+this.options.title);if(this.n>this.options.min){g.showOperation("button_delete")}else{g.hideOperation("button_delete")}}}});return{View:d}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-portlet","mvc/ui/ui-misc"],function(c,a,b,e){var d=Backbone.View.extend({optionsDefault:{title:"Section",max:null,min:null},initialize:function(g){this.options=c.merge(g,this.optionsDefault);this.setElement("<div/>");var f=this;this.button_new=new e.ButtonIcon({icon:"fa-plus",title:"Insert "+g.title_new,tooltip:"Add new "+g.title_new+" block",floating:"clear",onclick:function(){if(g.onnew){g.onnew()}}});this.table=new a.View({cls:"ui-table-plain",content:""});this.$el.append(this.table.$el);this.$el.append($("<div/>").append(this.button_new.$el));this.list={};this.n=0},size:function(){return this.n},add:function(g){if(!g.id||this.list[g.id]){console.debug("tools-repeat::add - Duplicate repeat block id.");return}this.n++;var f=new e.ButtonIcon({icon:"fa-trash-o",tooltip:"Delete this repeat block",cls:"ui-button-icon-plain",onclick:function(){if(g.ondel){g.ondel()}}});var h=new b.View({id:g.id,title:"placeholder",cls:"ui-portlet-repeat",operations:{button_delete:f}});h.append(g.$el);h.$el.addClass("section-row");this.list[g.id]=h;this.table.add(h.$el);this.table.append("row_"+g.id,true);if(this.options.max>0&&this.n>=this.options.max){this.button_new.disable()}this._refresh()},del:function(g){if(!this.list[g]){console.debug("tools-repeat::del - Invalid repeat block id.");return}this.n--;var f=this.table.get("row_"+g);f.remove();delete this.list[g];this.button_new.enable();this._refresh()},_refresh:function(){var f=0;for(var h in this.list){var g=this.list[h];g.title(++f+": "+this.options.title);if(this.n>this.options.min){g.showOperation("button_delete")}else{g.hideOperation("button_delete")}}}});return{View:d}});
\ 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: guerler: ToolForm: Update repeat blocks
by commits-noreply@bitbucket.org 07 Feb '15
by commits-noreply@bitbucket.org 07 Feb '15
07 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/394cf89ac004/
Changeset: 394cf89ac004
User: guerler
Date: 2015-02-07 04:23:26+00:00
Summary: ToolForm: Update repeat blocks
Affected #: 6 files
diff -r ade75ceb5427c588756ab888c3944cf4d25ada73 -r 394cf89ac0044524bf1f2dac6971a4d593c714ec client/galaxy/scripts/mvc/tools/tools-repeat.js
--- a/client/galaxy/scripts/mvc/tools/tools-repeat.js
+++ b/client/galaxy/scripts/mvc/tools/tools-repeat.js
@@ -6,7 +6,9 @@
var View = Backbone.View.extend({
// default options
optionsDefault : {
- max : null
+ title : 'Section',
+ max : null,
+ min : null
},
/** Initialize
@@ -14,13 +16,13 @@
initialize : function(options) {
// configure options
this.options = Utils.merge(options, this.optionsDefault);
-
+
// create new element
this.setElement('<div/>');
-
+
// link this
var self = this;
-
+
// create button
this.button_new = new Ui.ButtonIcon({
icon : 'fa-plus',
@@ -33,32 +35,44 @@
}
}
});
-
+
// create table
this.table = new Table.View({
cls : 'ui-table-plain',
content : ''
});
-
+
// append button
this.$el.append(this.table.$el);
-
+
// add button
this.$el.append($('<div/>').append(this.button_new.$el));
-
+
// clear list
this.list = {};
+
+ // number of available repeats
+ this.n = 0;
},
-
+
/** Number of repeat blocks
*/
size: function() {
- return _.size(this.list);
+ return this.n;
},
-
+
/** Add new repeat block
*/
add: function(options) {
+ // repeat block already exists
+ if (!options.id || this.list[options.id]) {
+ console.debug('tools-repeat::add - Duplicate repeat block id.');
+ return;
+ }
+
+ // increase repeat block counter
+ this.n++;
+
// delete button
var button_delete = new Ui.ButtonIcon({
icon : 'fa-trash-o',
@@ -70,7 +84,7 @@
}
}
});
-
+
// create portlet
var portlet = new Portlet.View({
id : options.id,
@@ -80,53 +94,67 @@
button_delete : button_delete
}
});
-
- // hide button
- if (!options.ondel) {
- button_delete.remove();
- }
-
+
// append content
portlet.append(options.$el);
-
+
// tag as section row
portlet.$el.addClass('section-row');
-
+
// append to dom
this.list[options.id] = portlet;
-
+
// append to dom
this.table.add(portlet.$el);
this.table.append('row_' + options.id, true);
-
+
// validate maximum
- if (this.options.max > 0 && this.size() >= this.options.max) {
+ if (this.options.max > 0 && this.n >= this.options.max) {
this.button_new.disable();
}
+
+ // refresh view
+ this._refresh();
},
-
+
/** Delete repeat block
*/
del: function(id) {
- if (this.list[id]) {
- // delete table row
- var table_row = this.table.get('row_' + id);
- table_row.remove();
-
- // remove from list
- delete this.list[id];
-
- // enable new button
- this.button_new.enable();
+ // could not find element
+ if (!this.list[id]) {
+ console.debug('tools-repeat::del - Invalid repeat block id.');
+ return;
}
+
+ // decrease repeat block counter
+ this.n--;
+
+ // delete table row
+ var table_row = this.table.get('row_' + id);
+ table_row.remove();
+
+ // remove from list
+ delete this.list[id];
+
+ // enable new button
+ this.button_new.enable();
+
+ // refresh delete button visibility
+ this._refresh();
},
-
- /** Retitle/Enumerate repeat blocks
+
+ /** Refresh view
*/
- retitle: function(new_title) {
+ _refresh: function() {
var index = 0;
for (var id in this.list) {
- this.list[id].title(++index + ': ' + new_title);
+ var portlet = this.list[id];
+ portlet.title(++index + ': ' + this.options.title);
+ if (this.n > this.options.min) {
+ portlet.showOperation('button_delete');
+ } else {
+ portlet.hideOperation('button_delete');
+ }
}
}
});
diff -r ade75ceb5427c588756ab888c3944cf4d25ada73 -r 394cf89ac0044524bf1f2dac6971a4d593c714ec client/galaxy/scripts/mvc/tools/tools-section.js
--- a/client/galaxy/scripts/mvc/tools/tools-section.js
+++ b/client/galaxy/scripts/mvc/tools/tools-section.js
@@ -161,26 +161,26 @@
// block index
var block_index = 0;
+ // create repeat block element
+ var repeat = new Repeat.View({
+ title : input_def.title,
+ title_new : input_def.title,
+ min : input_def.min,
+ max : input_def.max,
+ onnew : function() {
+ // create
+ create(input_def.inputs);
+
+ // trigger refresh
+ self.app.trigger('refresh');
+ }
+ });
+
// helper function to create new repeat blocks
- function create (inputs, deleteable) {
+ function create (inputs) {
// create id tag
var sub_section_id = input_def.id + '-section-' + (block_index++);
- // enable/disable repeat delete button
- var ondel = null;
- if (deleteable) {
- ondel = function() {
- // delete repeat block
- repeat.del(sub_section_id);
-
- // retitle repeat block
- repeat.retitle(input_def.title);
-
- // trigger refresh
- self.app.trigger('refresh');
- }
- }
-
// create sub section
var sub_section = new View(self.app, {
inputs : inputs
@@ -189,37 +189,23 @@
// add tab
repeat.add({
id : sub_section_id,
- title : input_def.title,
$el : sub_section.$el,
- ondel : ondel
+ ondel : function() {
+ // delete repeat block
+ repeat.del(sub_section_id);
+
+ // trigger refresh
+ self.app.trigger('refresh');
+ }
});
-
- // retitle repeat block
- repeat.retitle(input_def.title);
}
//
- // create repeat block element
- //
- var repeat = new Repeat.View({
- title_new : input_def.title,
- max : input_def.max,
- onnew : function() {
- // create
- create(input_def.inputs, true);
-
- // trigger refresh
- self.app.trigger('refresh');
- }
- });
-
- //
// add parsed/minimum number of repeat blocks
//
var n_min = input_def.min;
var n_cache = _.size(input_def.cache);
for (var i = 0; i < Math.max(n_cache, n_min); i++) {
- // select input source
var inputs = null;
if (i < n_cache) {
inputs = input_def.cache[i];
@@ -228,7 +214,7 @@
}
// create repeat block
- create(inputs, i >= n_min);
+ create(inputs);
}
// create input field wrapper
diff -r ade75ceb5427c588756ab888c3944cf4d25ada73 -r 394cf89ac0044524bf1f2dac6971a4d593c714ec static/scripts/mvc/tools/tools-repeat.js
--- a/static/scripts/mvc/tools/tools-repeat.js
+++ b/static/scripts/mvc/tools/tools-repeat.js
@@ -6,7 +6,9 @@
var View = Backbone.View.extend({
// default options
optionsDefault : {
- max : null
+ title : 'Section',
+ max : null,
+ min : null
},
/** Initialize
@@ -14,13 +16,13 @@
initialize : function(options) {
// configure options
this.options = Utils.merge(options, this.optionsDefault);
-
+
// create new element
this.setElement('<div/>');
-
+
// link this
var self = this;
-
+
// create button
this.button_new = new Ui.ButtonIcon({
icon : 'fa-plus',
@@ -33,32 +35,44 @@
}
}
});
-
+
// create table
this.table = new Table.View({
cls : 'ui-table-plain',
content : ''
});
-
+
// append button
this.$el.append(this.table.$el);
-
+
// add button
this.$el.append($('<div/>').append(this.button_new.$el));
-
+
// clear list
this.list = {};
+
+ // number of available repeats
+ this.n = 0;
},
-
+
/** Number of repeat blocks
*/
size: function() {
- return _.size(this.list);
+ return this.n;
},
-
+
/** Add new repeat block
*/
add: function(options) {
+ // repeat block already exists
+ if (!options.id || this.list[options.id]) {
+ console.debug('tools-repeat::add - Duplicate repeat block id.');
+ return;
+ }
+
+ // increase repeat block counter
+ this.n++;
+
// delete button
var button_delete = new Ui.ButtonIcon({
icon : 'fa-trash-o',
@@ -70,7 +84,7 @@
}
}
});
-
+
// create portlet
var portlet = new Portlet.View({
id : options.id,
@@ -80,53 +94,67 @@
button_delete : button_delete
}
});
-
- // hide button
- if (!options.ondel) {
- button_delete.remove();
- }
-
+
// append content
portlet.append(options.$el);
-
+
// tag as section row
portlet.$el.addClass('section-row');
-
+
// append to dom
this.list[options.id] = portlet;
-
+
// append to dom
this.table.add(portlet.$el);
this.table.append('row_' + options.id, true);
-
+
// validate maximum
- if (this.options.max > 0 && this.size() >= this.options.max) {
+ if (this.options.max > 0 && this.n >= this.options.max) {
this.button_new.disable();
}
+
+ // refresh view
+ this._refresh();
},
-
+
/** Delete repeat block
*/
del: function(id) {
- if (this.list[id]) {
- // delete table row
- var table_row = this.table.get('row_' + id);
- table_row.remove();
-
- // remove from list
- delete this.list[id];
-
- // enable new button
- this.button_new.enable();
+ // could not find element
+ if (!this.list[id]) {
+ console.debug('tools-repeat::del - Invalid repeat block id.');
+ return;
}
+
+ // decrease repeat block counter
+ this.n--;
+
+ // delete table row
+ var table_row = this.table.get('row_' + id);
+ table_row.remove();
+
+ // remove from list
+ delete this.list[id];
+
+ // enable new button
+ this.button_new.enable();
+
+ // refresh delete button visibility
+ this._refresh();
},
-
- /** Retitle/Enumerate repeat blocks
+
+ /** Refresh view
*/
- retitle: function(new_title) {
+ _refresh: function() {
var index = 0;
for (var id in this.list) {
- this.list[id].title(++index + ': ' + new_title);
+ var portlet = this.list[id];
+ portlet.title(++index + ': ' + this.options.title);
+ if (this.n > this.options.min) {
+ portlet.showOperation('button_delete');
+ } else {
+ portlet.hideOperation('button_delete');
+ }
}
}
});
diff -r ade75ceb5427c588756ab888c3944cf4d25ada73 -r 394cf89ac0044524bf1f2dac6971a4d593c714ec static/scripts/mvc/tools/tools-section.js
--- a/static/scripts/mvc/tools/tools-section.js
+++ b/static/scripts/mvc/tools/tools-section.js
@@ -161,26 +161,26 @@
// block index
var block_index = 0;
+ // create repeat block element
+ var repeat = new Repeat.View({
+ title : input_def.title,
+ title_new : input_def.title,
+ min : input_def.min,
+ max : input_def.max,
+ onnew : function() {
+ // create
+ create(input_def.inputs);
+
+ // trigger refresh
+ self.app.trigger('refresh');
+ }
+ });
+
// helper function to create new repeat blocks
- function create (inputs, deleteable) {
+ function create (inputs) {
// create id tag
var sub_section_id = input_def.id + '-section-' + (block_index++);
- // enable/disable repeat delete button
- var ondel = null;
- if (deleteable) {
- ondel = function() {
- // delete repeat block
- repeat.del(sub_section_id);
-
- // retitle repeat block
- repeat.retitle(input_def.title);
-
- // trigger refresh
- self.app.trigger('refresh');
- }
- }
-
// create sub section
var sub_section = new View(self.app, {
inputs : inputs
@@ -189,37 +189,23 @@
// add tab
repeat.add({
id : sub_section_id,
- title : input_def.title,
$el : sub_section.$el,
- ondel : ondel
+ ondel : function() {
+ // delete repeat block
+ repeat.del(sub_section_id);
+
+ // trigger refresh
+ self.app.trigger('refresh');
+ }
});
-
- // retitle repeat block
- repeat.retitle(input_def.title);
}
//
- // create repeat block element
- //
- var repeat = new Repeat.View({
- title_new : input_def.title,
- max : input_def.max,
- onnew : function() {
- // create
- create(input_def.inputs, true);
-
- // trigger refresh
- self.app.trigger('refresh');
- }
- });
-
- //
// add parsed/minimum number of repeat blocks
//
var n_min = input_def.min;
var n_cache = _.size(input_def.cache);
for (var i = 0; i < Math.max(n_cache, n_min); i++) {
- // select input source
var inputs = null;
if (i < n_cache) {
inputs = input_def.cache[i];
@@ -228,7 +214,7 @@
}
// create repeat block
- create(inputs, i >= n_min);
+ create(inputs);
}
// create input field wrapper
diff -r ade75ceb5427c588756ab888c3944cf4d25ada73 -r 394cf89ac0044524bf1f2dac6971a4d593c714ec static/scripts/packed/mvc/tools/tools-repeat.js
--- a/static/scripts/packed/mvc/tools/tools-repeat.js
+++ b/static/scripts/packed/mvc/tools/tools-repeat.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-portlet","mvc/ui/ui-misc"],function(c,a,b,e){var d=Backbone.View.extend({optionsDefault:{max:null},initialize:function(g){this.options=c.merge(g,this.optionsDefault);this.setElement("<div/>");var f=this;this.button_new=new e.ButtonIcon({icon:"fa-plus",title:"Insert "+g.title_new,tooltip:"Add new "+g.title_new+" block",floating:"clear",onclick:function(){if(g.onnew){g.onnew()}}});this.table=new a.View({cls:"ui-table-plain",content:""});this.$el.append(this.table.$el);this.$el.append($("<div/>").append(this.button_new.$el));this.list={}},size:function(){return _.size(this.list)},add:function(g){var f=new e.ButtonIcon({icon:"fa-trash-o",tooltip:"Delete this repeat block",cls:"ui-button-icon-plain",onclick:function(){if(g.ondel){g.ondel()}}});var h=new b.View({id:g.id,title:"<b>"+g.title+"</b>",cls:"ui-portlet-repeat",operations:{button_delete:f}});if(!g.ondel){f.remove()}h.append(g.$el);h.$el.addClass("section-row");this.list[g.id]=h;this.table.add(h.$el);this.table.append("row_"+g.id,true);if(this.options.max>0&&this.size()>=this.options.max){this.button_new.disable()}},del:function(g){if(this.list[g]){var f=this.table.get("row_"+g);f.remove();delete this.list[g];this.button_new.enable()}},retitle:function(g){var f=0;for(var h in this.list){this.list[h].title(++f+": "+g)}}});return{View:d}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-portlet","mvc/ui/ui-misc"],function(c,a,b,e){var d=Backbone.View.extend({optionsDefault:{title:"Section",max:null,min:null},initialize:function(g){this.options=c.merge(g,this.optionsDefault);this.setElement("<div/>");var f=this;this.button_new=new e.ButtonIcon({icon:"fa-plus",title:"Insert "+g.title_new,tooltip:"Add new "+g.title_new+" block",floating:"clear",onclick:function(){if(g.onnew){g.onnew()}}});this.table=new a.View({cls:"ui-table-plain",content:""});this.$el.append(this.table.$el);this.$el.append($("<div/>").append(this.button_new.$el));this.list={};this.n=0},size:function(){return this.n},add:function(g){if(!g.id||this.list[g.id]){console.debug("tools-repeat::add - Duplicate repeat block id.");return}this.n++;var f=new e.ButtonIcon({icon:"fa-trash-o",tooltip:"Delete this repeat block",cls:"ui-button-icon-plain",onclick:function(){if(g.ondel){g.ondel()}}});var h=new b.View({id:g.id,title:"<b>"+g.title+"</b>",cls:"ui-portlet-repeat",operations:{button_delete:f}});h.append(g.$el);h.$el.addClass("section-row");this.list[g.id]=h;this.table.add(h.$el);this.table.append("row_"+g.id,true);if(this.options.max>0&&this.n>=this.options.max){this.button_new.disable()}this._refresh()},del:function(g){if(!this.list[g]){console.debug("tools-repeat::del - Invalid repeat block id.");return}this.n--;var f=this.table.get("row_"+g);f.remove();delete this.list[g];this.button_new.enable();this._refresh()},_refresh:function(){var f=0;for(var h in this.list){var g=this.list[h];g.title(++f+": "+this.options.title);if(this.n>this.options.min){g.showOperation("button_delete")}else{g.hideOperation("button_delete")}}}});return{View:d}});
\ No newline at end of file
diff -r ade75ceb5427c588756ab888c3944cf4d25ada73 -r 394cf89ac0044524bf1f2dac6971a4d593c714ec static/scripts/packed/mvc/tools/tools-section.js
--- a/static/scripts/packed/mvc/tools/tools-section.js
+++ b/static/scripts/packed/mvc/tools/tools-section.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/ui/ui-portlet","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(e,b,h,d,c,a,f){var g=Backbone.View.extend({initialize:function(j,i){this.app=j;this.inputs=i.inputs;i.cls="ui-table-plain";i.cls_tr="section-row";this.table=new b.View(i);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var j in this.inputs){this.add(this.inputs[j])}},add:function(k){var j=this;var i=jQuery.extend(true,{},k);i.id=k.id=e.uuid();this.app.input_list[i.id]=i;var l=i.type;switch(l){case"conditional":this._addConditional(i);break;case"repeat":this._addRepeat(i);break;case"section":this._addSection(i);break;default:this._addRow(i)}},_addConditional:function(j){var k=this;j.test_param.id=j.id;var n=this._addRow(j.test_param);n.options.onchange=function(w){var v=k.app.tree.matchCase(j,w);for(var u in j.cases){var q=j.cases[u];var t=j.id+"-section-"+u;var p=k.table.get(t);var s=false;for(var r in q.inputs){if(!q.inputs[r].hidden){s=true;break}}if(u==v&&s){p.fadeIn("fast")}else{p.hide()}}k.app.trigger("refresh")};for(var m in j.cases){var l=j.id+"-section-"+m;var o=new g(this.app,{inputs:j.cases[m].inputs});o.$el.addClass("ui-table-section");this.table.add(o.$el);this.table.append(l)}n.trigger("change")},_addRepeat:function(p){var s=this;var q=0;function n(i,u){var t=p.id+"-section-"+(q++);var v=null;if(u){v=function(){l.del(t);l.retitle(p.title);s.app.trigger("refresh")}}var w=new g(s.app,{inputs:i});l.add({id:t,title:p.title,$el:w.$el,ondel:v});l.retitle(p.title)}var l=new c.View({title_new:p.title,max:p.max,onnew:function(){n(p.inputs,true);s.app.trigger("refresh")}});var j=p.min;var r=_.size(p.cache);for(var m=0;m<Math.max(r,j);m++){var o=null;if(m<r){o=p.cache[m]}else{o=p.inputs}n(o,m>=j)}var k=new f(this.app,{label:p.title,help:p.help,field:l});this.table.add(k.$el);this.table.append(p.id)},_addSection:function(i){var j=this;var n=new g(j.app,{inputs:i.inputs});var m=new h.ButtonIcon({icon:"fa-eye-slash",tooltip:"Show/hide section",cls:"ui-button-icon-plain"});var l=new d.View({title:i.label,cls:"ui-portlet-section",operations:{button_visible:m}});l.append(n.$el);l.append($("<div/>").addClass("ui-table-form-info").html(i.help));var k=false;l.$content.hide();l.$header.css("cursor","pointer");l.$header.on("click",function(){if(k){k=false;l.$content.hide();m.setIcon("fa-eye-slash")}else{k=true;l.$content.fadeIn("fast");m.setIcon("fa-eye")}});if(i.expand){l.$header.trigger("click")}this.table.add(l.$el);this.table.append(i.id)},_addRow:function(i){var l=i.id;var j=this._createField(i);this.app.field_list[l]=j;if(i.default_value===undefined){i.default_value=i.value}var k=new f(this.app,{label:i.label,default_value:i.default_value,optional:i.optional,help:i.help,field:j});this.app.element_list[l]=k;this.table.add(k.$el);this.table.append(l);if(i.hidden){this.table.get(l).hide()}return j},_createField:function(i){var j=null;switch(i.type){case"text":j=this._fieldText(i);break;case"select":j=this._fieldSelect(i);break;case"data":j=this._fieldData(i);break;case"data_collection":j=this._fieldData(i);break;case"data_column":i.error_text="Missing columns in referenced dataset.";j=this._fieldSelect(i);break;case"hidden":j=this._fieldHidden(i);break;case"hidden_data":j=this._fieldHidden(i);break;case"integer":j=this._fieldSlider(i);break;case"float":j=this._fieldSlider(i);break;case"boolean":j=this._fieldBoolean(i);break;case"genomebuild":i.searchable=true;j=this._fieldSelect(i);break;case"drill_down":j=this._fieldDrilldown(i);break;case"baseurl":j=this._fieldHidden(i);break;default:this.app.incompatible=true;if(i.options){j=this._fieldSelect(i)}else{j=this._fieldText(i)}console.debug("tools-form::_addRow() : Auto matched field type ("+i.type+").")}if(i.value!==undefined){j.value(i.value)}return j},_fieldData:function(i){if(!this.app.options.is_dynamic){i.info="Data input '"+i.name+"' ("+e.textify(i.extensions.toString())+")";i.value=null;return this._fieldHidden(i)}var j=this;return new a.View(this.app,{id:"field-"+i.id,extensions:i.extensions,optional:i.optional,multiple:i.multiple,type:i.type,data:i.options,onchange:function(){j.app.trigger("refresh")}})},_fieldSelect:function(j){if(!this.app.options.is_dynamic&&j.is_dynamic){return this._fieldText(j)}var l=[];for(var m in j.options){var n=j.options[m];l.push({label:n[0],value:n[1]})}var o=h.Select;switch(j.display){case"checkboxes":o=h.Checkbox;break;case"radio":o=h.Radio;break}var k=this;return new o.View({id:"field-"+j.id,data:l,error_text:j.error_text||"No options available",multiple:j.multiple,searchable:j.searchable,onchange:function(){k.app.trigger("refresh")}})},_fieldDrilldown:function(i){if(!this.app.options.is_dynamic&&i.is_dynamic){return this._fieldText(i)}var j=this;return new h.Drilldown.View({id:"field-"+i.id,data:i.options,display:i.display,onchange:function(){j.app.trigger("refresh")}})},_fieldText:function(i){if(i.options){i.area=i.multiple;if(!e.validate(i.value)){i.value=""}else{if(i.value instanceof Array){i.value=value.toString()}else{i.value=String(i.value).replace(/[\[\]'"\s]/g,"");if(i.multiple){i.value=i.value.replace(/,/g,"\n")}}}}var j=this;return new h.Input({id:"field-"+i.id,area:i.area,onchange:function(){j.app.trigger("refresh")}})},_fieldSlider:function(i){var j=this;return new h.Slider.View({id:"field-"+i.id,precise:i.type=="float",min:i.min,max:i.max,onchange:function(){j.app.trigger("refresh")}})},_fieldHidden:function(i){return new h.Hidden({id:"field-"+i.id,info:i.info})},_fieldBoolean:function(i){var j=this;return new h.RadioButton.View({id:"field-"+i.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}],onchange:function(){j.app.trigger("refresh")}})}});return{View:g}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/ui/ui-portlet","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(e,b,h,d,c,a,f){var g=Backbone.View.extend({initialize:function(j,i){this.app=j;this.inputs=i.inputs;i.cls="ui-table-plain";i.cls_tr="section-row";this.table=new b.View(i);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var j in this.inputs){this.add(this.inputs[j])}},add:function(k){var j=this;var i=jQuery.extend(true,{},k);i.id=k.id=e.uuid();this.app.input_list[i.id]=i;var l=i.type;switch(l){case"conditional":this._addConditional(i);break;case"repeat":this._addRepeat(i);break;case"section":this._addSection(i);break;default:this._addRow(i)}},_addConditional:function(j){var k=this;j.test_param.id=j.id;var n=this._addRow(j.test_param);n.options.onchange=function(w){var v=k.app.tree.matchCase(j,w);for(var u in j.cases){var q=j.cases[u];var t=j.id+"-section-"+u;var p=k.table.get(t);var s=false;for(var r in q.inputs){if(!q.inputs[r].hidden){s=true;break}}if(u==v&&s){p.fadeIn("fast")}else{p.hide()}}k.app.trigger("refresh")};for(var m in j.cases){var l=j.id+"-section-"+m;var o=new g(this.app,{inputs:j.cases[m].inputs});o.$el.addClass("ui-table-section");this.table.add(o.$el);this.table.append(l)}n.trigger("change")},_addRepeat:function(p){var s=this;var q=0;var l=new c.View({title:p.title,title_new:p.title,min:p.min,max:p.max,onnew:function(){n(p.inputs);s.app.trigger("refresh")}});function n(i){var t=p.id+"-section-"+(q++);var u=new g(s.app,{inputs:i});l.add({id:t,$el:u.$el,ondel:function(){l.del(t);s.app.trigger("refresh")}})}var j=p.min;var r=_.size(p.cache);for(var m=0;m<Math.max(r,j);m++){var o=null;if(m<r){o=p.cache[m]}else{o=p.inputs}n(o)}var k=new f(this.app,{label:p.title,help:p.help,field:l});this.table.add(k.$el);this.table.append(p.id)},_addSection:function(i){var j=this;var n=new g(j.app,{inputs:i.inputs});var m=new h.ButtonIcon({icon:"fa-eye-slash",tooltip:"Show/hide section",cls:"ui-button-icon-plain"});var l=new d.View({title:i.label,cls:"ui-portlet-section",operations:{button_visible:m}});l.append(n.$el);l.append($("<div/>").addClass("ui-table-form-info").html(i.help));var k=false;l.$content.hide();l.$header.css("cursor","pointer");l.$header.on("click",function(){if(k){k=false;l.$content.hide();m.setIcon("fa-eye-slash")}else{k=true;l.$content.fadeIn("fast");m.setIcon("fa-eye")}});if(i.expand){l.$header.trigger("click")}this.table.add(l.$el);this.table.append(i.id)},_addRow:function(i){var l=i.id;var j=this._createField(i);this.app.field_list[l]=j;if(i.default_value===undefined){i.default_value=i.value}var k=new f(this.app,{label:i.label,default_value:i.default_value,optional:i.optional,help:i.help,field:j});this.app.element_list[l]=k;this.table.add(k.$el);this.table.append(l);if(i.hidden){this.table.get(l).hide()}return j},_createField:function(i){var j=null;switch(i.type){case"text":j=this._fieldText(i);break;case"select":j=this._fieldSelect(i);break;case"data":j=this._fieldData(i);break;case"data_collection":j=this._fieldData(i);break;case"data_column":i.error_text="Missing columns in referenced dataset.";j=this._fieldSelect(i);break;case"hidden":j=this._fieldHidden(i);break;case"hidden_data":j=this._fieldHidden(i);break;case"integer":j=this._fieldSlider(i);break;case"float":j=this._fieldSlider(i);break;case"boolean":j=this._fieldBoolean(i);break;case"genomebuild":i.searchable=true;j=this._fieldSelect(i);break;case"drill_down":j=this._fieldDrilldown(i);break;case"baseurl":j=this._fieldHidden(i);break;default:this.app.incompatible=true;if(i.options){j=this._fieldSelect(i)}else{j=this._fieldText(i)}console.debug("tools-form::_addRow() : Auto matched field type ("+i.type+").")}if(i.value!==undefined){j.value(i.value)}return j},_fieldData:function(i){if(!this.app.options.is_dynamic){i.info="Data input '"+i.name+"' ("+e.textify(i.extensions.toString())+")";i.value=null;return this._fieldHidden(i)}var j=this;return new a.View(this.app,{id:"field-"+i.id,extensions:i.extensions,optional:i.optional,multiple:i.multiple,type:i.type,data:i.options,onchange:function(){j.app.trigger("refresh")}})},_fieldSelect:function(j){if(!this.app.options.is_dynamic&&j.is_dynamic){return this._fieldText(j)}var l=[];for(var m in j.options){var n=j.options[m];l.push({label:n[0],value:n[1]})}var o=h.Select;switch(j.display){case"checkboxes":o=h.Checkbox;break;case"radio":o=h.Radio;break}var k=this;return new o.View({id:"field-"+j.id,data:l,error_text:j.error_text||"No options available",multiple:j.multiple,searchable:j.searchable,onchange:function(){k.app.trigger("refresh")}})},_fieldDrilldown:function(i){if(!this.app.options.is_dynamic&&i.is_dynamic){return this._fieldText(i)}var j=this;return new h.Drilldown.View({id:"field-"+i.id,data:i.options,display:i.display,onchange:function(){j.app.trigger("refresh")}})},_fieldText:function(i){if(i.options){i.area=i.multiple;if(!e.validate(i.value)){i.value=""}else{if(i.value instanceof Array){i.value=value.toString()}else{i.value=String(i.value).replace(/[\[\]'"\s]/g,"");if(i.multiple){i.value=i.value.replace(/,/g,"\n")}}}}var j=this;return new h.Input({id:"field-"+i.id,area:i.area,onchange:function(){j.app.trigger("refresh")}})},_fieldSlider:function(i){var j=this;return new h.Slider.View({id:"field-"+i.id,precise:i.type=="float",min:i.min,max:i.max,onchange:function(){j.app.trigger("refresh")}})},_fieldHidden:function(i){return new h.Hidden({id:"field-"+i.id,info:i.info})},_fieldBoolean:function(i){var j=this;return new h.RadioButton.View({id:"field-"+i.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}],onchange:function(){j.app.trigger("refresh")}})}});return{View:g}});
\ 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: guerler: ToolForm: More style adjustments
by commits-noreply@bitbucket.org 07 Feb '15
by commits-noreply@bitbucket.org 07 Feb '15
07 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ade75ceb5427/
Changeset: ade75ceb5427
User: guerler
Date: 2015-02-07 03:03:33+00:00
Summary: ToolForm: More style adjustments
Affected #: 8 files
diff -r 527b11f07d8107298c87293eb04469f2743e229e -r ade75ceb5427c588756ab888c3944cf4d25ada73 client/galaxy/scripts/mvc/tools/tools-select-content.js
--- a/client/galaxy/scripts/mvc/tools/tools-select-content.js
+++ b/client/galaxy/scripts/mvc/tools/tools-select-content.js
@@ -48,7 +48,11 @@
// add single dataset selector
if (this.mode == 'single') {
- radio_buttons.push({icon: 'fa-file-o', label: '', value: 'single', tooltip: 'Single dataset' });
+ radio_buttons.push({
+ icon : 'fa-file-o',
+ value : 'single',
+ tooltip : 'Single dataset'
+ });
this.select_single = new Ui.Select.View({
optional : options.optional,
error_text : hda_error,
@@ -64,7 +68,11 @@
// add multiple dataset selector
if (this.mode == 'single' || this.mode == 'multiple') {
- radio_buttons.push({icon: 'fa-files-o', label: '', value: 'multiple', tooltip: 'Multiple datasets' });
+ radio_buttons.push({
+ icon : 'fa-files-o',
+ value : 'multiple',
+ tooltip : 'Multiple datasets'
+ });
this.select_multiple = new Ui.Select.View({
multiple : true,
error_text : hda_error,
@@ -80,7 +88,11 @@
// add collection selector
if (this.mode == 'single' || this.mode == 'collection') {
- radio_buttons.push({icon: 'fa-folder-o', label: '', value: 'collection', tooltip: 'Dataset collection' });
+ radio_buttons.push({
+ icon : 'fa-folder-o',
+ value : 'collection',
+ tooltip : 'Dataset collection'
+ });
this.select_collection = new Ui.Select.View({
error_text : hdca_error,
optional : options.optional,
@@ -108,13 +120,17 @@
// add batch mode information
this.$batch = $(ToolTemplate.batchMode());
- // calculate button width (should be placed into css once its supported)
- var button_width = (_.size(this.list) - 1) * 60 + 'px';
-
- // add elements to dom
- if (_.size(this.list) > 1) {
+ // number of radio buttons
+ var n_buttons = _.size(this.list);
+
+ // add button to dom
+ var button_width = 0;
+ if (n_buttons > 1) {
this.$el.append(this.button_type.$el);
+ button_width = Math.max(0, _.size(this.list) * 35) + 'px';
}
+
+ // append field elements
for (var i in this.list) {
this.$el.append(this.list[i].field.$el.css({
'margin-left': button_width
diff -r 527b11f07d8107298c87293eb04469f2743e229e -r ade75ceb5427c588756ab888c3944cf4d25ada73 client/galaxy/scripts/mvc/ui/ui-options.js
--- a/client/galaxy/scripts/mvc/ui/ui-options.js
+++ b/client/galaxy/scripts/mvc/ui/ui-options.js
@@ -286,12 +286,19 @@
/** Template for a single option
*/
_templateOption: function(pair) {
+ var cls = 'fa ' + pair.icon;
+ if (!pair.label) {
+ cls += ' no-padding';
+ }
var tmpl = '<label class="btn btn-default">';
if (pair.icon) {
- tmpl += '<i class="fa ' + pair.icon + '"/>';
+ tmpl += '<i class="' + cls + '"/>';
}
- tmpl += '<input type="radio" name="' + this.options.id + '" value="' + pair.value + '">' + pair.label +
- '</label>';
+ tmpl += '<input type="radio" name="' + this.options.id + '" value="' + pair.value + '">';
+ if (pair.label) {
+ tmpl += pair.label;
+ }
+ tmpl += '</label>';
return tmpl;
},
diff -r 527b11f07d8107298c87293eb04469f2743e229e -r ade75ceb5427c588756ab888c3944cf4d25ada73 static/scripts/mvc/tools/tools-select-content.js
--- a/static/scripts/mvc/tools/tools-select-content.js
+++ b/static/scripts/mvc/tools/tools-select-content.js
@@ -48,7 +48,11 @@
// add single dataset selector
if (this.mode == 'single') {
- radio_buttons.push({icon: 'fa-file-o', label: '', value: 'single', tooltip: 'Single dataset' });
+ radio_buttons.push({
+ icon : 'fa-file-o',
+ value : 'single',
+ tooltip : 'Single dataset'
+ });
this.select_single = new Ui.Select.View({
optional : options.optional,
error_text : hda_error,
@@ -64,7 +68,11 @@
// add multiple dataset selector
if (this.mode == 'single' || this.mode == 'multiple') {
- radio_buttons.push({icon: 'fa-files-o', label: '', value: 'multiple', tooltip: 'Multiple datasets' });
+ radio_buttons.push({
+ icon : 'fa-files-o',
+ value : 'multiple',
+ tooltip : 'Multiple datasets'
+ });
this.select_multiple = new Ui.Select.View({
multiple : true,
error_text : hda_error,
@@ -80,7 +88,11 @@
// add collection selector
if (this.mode == 'single' || this.mode == 'collection') {
- radio_buttons.push({icon: 'fa-folder-o', label: '', value: 'collection', tooltip: 'Dataset collection' });
+ radio_buttons.push({
+ icon : 'fa-folder-o',
+ value : 'collection',
+ tooltip : 'Dataset collection'
+ });
this.select_collection = new Ui.Select.View({
error_text : hdca_error,
optional : options.optional,
@@ -108,13 +120,17 @@
// add batch mode information
this.$batch = $(ToolTemplate.batchMode());
- // calculate button width (should be placed into css once its supported)
- var button_width = (_.size(this.list) - 1) * 60 + 'px';
-
- // add elements to dom
- if (_.size(this.list) > 1) {
+ // number of radio buttons
+ var n_buttons = _.size(this.list);
+
+ // add button to dom
+ var button_width = 0;
+ if (n_buttons > 1) {
this.$el.append(this.button_type.$el);
+ button_width = Math.max(0, _.size(this.list) * 35) + 'px';
}
+
+ // append field elements
for (var i in this.list) {
this.$el.append(this.list[i].field.$el.css({
'margin-left': button_width
diff -r 527b11f07d8107298c87293eb04469f2743e229e -r ade75ceb5427c588756ab888c3944cf4d25ada73 static/scripts/mvc/ui/ui-options.js
--- a/static/scripts/mvc/ui/ui-options.js
+++ b/static/scripts/mvc/ui/ui-options.js
@@ -286,12 +286,19 @@
/** Template for a single option
*/
_templateOption: function(pair) {
+ var cls = 'fa ' + pair.icon;
+ if (!pair.label) {
+ cls += ' no-padding';
+ }
var tmpl = '<label class="btn btn-default">';
if (pair.icon) {
- tmpl += '<i class="fa ' + pair.icon + '"/>';
+ tmpl += '<i class="' + cls + '"/>';
}
- tmpl += '<input type="radio" name="' + this.options.id + '" value="' + pair.value + '">' + pair.label +
- '</label>';
+ tmpl += '<input type="radio" name="' + this.options.id + '" value="' + pair.value + '">';
+ if (pair.label) {
+ tmpl += pair.label;
+ }
+ tmpl += '</label>';
return tmpl;
},
diff -r 527b11f07d8107298c87293eb04469f2743e229e -r ade75ceb5427c588756ab888c3944cf4d25ada73 static/scripts/packed/mvc/tools/tools-select-content.js
--- a/static/scripts/packed/mvc/tools/tools-select-content.js
+++ b/static/scripts/packed/mvc/tools/tools-select-content.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs","mvc/tools/tools-template"],function(c,e,b,a){var d=Backbone.View.extend({initialize:function(f,o){this.app=f;this.options=o;var n=this;this.setElement('<div class="ui-select-content"/>');this.list={};var l=[];if(o.type=="data_collection"){this.mode="collection"}else{if(o.multiple){this.mode="multiple"}else{this.mode="single"}}this.current=this.mode;this.list={};var j=c.textify(o.extensions);var h="No dataset available.";if(j){h="No "+j+" dataset available."}var k="No dataset list available.";if(j){k="No "+j+" dataset collection available."}if(this.mode=="single"){l.push({icon:"fa-file-o",label:"",value:"single",tooltip:"Single dataset"});this.select_single=new e.Select.View({optional:o.optional,error_text:h,onchange:function(){n.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){l.push({icon:"fa-files-o",label:"",value:"multiple",tooltip:"Multiple datasets"});this.select_multiple=new e.Select.View({multiple:true,error_text:h,onchange:function(){n.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"}}if(this.mode=="single"||this.mode=="collection"){l.push({icon:"fa-folder-o",label:"",value:"collection",tooltip:"Dataset collection"});this.select_collection=new e.Select.View({error_text:k,optional:o.optional,onchange:function(){n.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"}}this.button_type=new e.RadioButton.View({value:this.current,data:l,onchange:function(i){n.current=i;n.refresh();n.trigger("change")}});this.$batch=$(a.batchMode());var m=(_.size(this.list)-1)*60+"px";if(_.size(this.list)>1){this.$el.append(this.button_type.$el)}for(var g in this.list){this.$el.append(this.list[g].field.$el.css({"margin-left":m}))}this.$el.append(this.$batch.css({"margin-left":m}));this.update(o.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(o.onchange){o.onchange(n.value())}})},wait:function(){for(var f in this.list){this.list[f].field.wait()}},unwait:function(){for(var f in this.list){this.list[f].field.unwait()}},update:function(g){var l=[];for(var j in g.hda){var k=g.hda[j];l.push({label:k.hid+": "+k.name,value:k.id})}var f=[];for(var j in g.hdca){var h=g.hdca[j];f.push({label:h.hid+": "+h.name,value:h.id})}this.select_single&&this.select_single.update(l);this.select_multiple&&this.select_multiple.update(l);this.select_collection&&this.select_collection.update(f);this.app.content.add(g)},value:function(h){if(h!==undefined){if(h&&h.values){try{var l=[];for(var g in h.values){l.push(h.values[g].id)}if(h&&h.values.length>0&&h.values[0].src=="hcda"){this.current="collection";this.select_collection.value(l[0])}else{if(this.mode=="multiple"){this.current="multiple";this.select_multiple.value(l)}else{this.current="single";this.select_single.value(l[0])}}}catch(k){console.debug("tools-select-content::value() - Skipped.")}}else{this.select_single&&this.select_single.value("__null__");this.select_multiple&&this.select_multiple.value("__null__");this.select_collection&&this.select_collection.value("__null__")}this.refresh()}var j=this._select().value();if(!(j instanceof Array)){j=[j]}var f={batch:this.mode=="single"&&this.current!="single",values:[]};for(var g in j){f.values.push({id:j[g],src:this.list[this.current].type})}return f},validate:function(){return this._select().validate()},refresh:function(){this.button_type.value(this.current);for(var g in this.list){var f=this.list[g].field.$el;if(this.current==g){f.show()}else{f.hide()}}if(this.mode=="single"&&this.current!="single"){this.$batch.show()}else{this.$batch.hide()}},_select:function(){return this.list[this.current].field}});return{View:d}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs","mvc/tools/tools-template"],function(c,e,b,a){var d=Backbone.View.extend({initialize:function(g,p){this.app=g;this.options=p;var o=this;this.setElement('<div class="ui-select-content"/>');this.list={};var m=[];if(p.type=="data_collection"){this.mode="collection"}else{if(p.multiple){this.mode="multiple"}else{this.mode="single"}}this.current=this.mode;this.list={};var k=c.textify(p.extensions);var j="No dataset available.";if(k){j="No "+k+" dataset available."}var l="No dataset list available.";if(k){l="No "+k+" dataset collection available."}if(this.mode=="single"){m.push({icon:"fa-file-o",value:"single",tooltip:"Single dataset"});this.select_single=new e.Select.View({optional:p.optional,error_text:j,onchange:function(){o.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){m.push({icon:"fa-files-o",value:"multiple",tooltip:"Multiple datasets"});this.select_multiple=new e.Select.View({multiple:true,error_text:j,onchange:function(){o.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"}}if(this.mode=="single"||this.mode=="collection"){m.push({icon:"fa-folder-o",value:"collection",tooltip:"Dataset collection"});this.select_collection=new e.Select.View({error_text:l,optional:p.optional,onchange:function(){o.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"}}this.button_type=new e.RadioButton.View({value:this.current,data:m,onchange:function(i){o.current=i;o.refresh();o.trigger("change")}});this.$batch=$(a.batchMode());var f=_.size(this.list);var n=0;if(f>1){this.$el.append(this.button_type.$el);n=Math.max(0,_.size(this.list)*35)+"px"}for(var h in this.list){this.$el.append(this.list[h].field.$el.css({"margin-left":n}))}this.$el.append(this.$batch.css({"margin-left":n}));this.update(p.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(p.onchange){p.onchange(o.value())}})},wait:function(){for(var f in this.list){this.list[f].field.wait()}},unwait:function(){for(var f in this.list){this.list[f].field.unwait()}},update:function(g){var l=[];for(var j in g.hda){var k=g.hda[j];l.push({label:k.hid+": "+k.name,value:k.id})}var f=[];for(var j in g.hdca){var h=g.hdca[j];f.push({label:h.hid+": "+h.name,value:h.id})}this.select_single&&this.select_single.update(l);this.select_multiple&&this.select_multiple.update(l);this.select_collection&&this.select_collection.update(f);this.app.content.add(g)},value:function(h){if(h!==undefined){if(h&&h.values){try{var l=[];for(var g in h.values){l.push(h.values[g].id)}if(h&&h.values.length>0&&h.values[0].src=="hcda"){this.current="collection";this.select_collection.value(l[0])}else{if(this.mode=="multiple"){this.current="multiple";this.select_multiple.value(l)}else{this.current="single";this.select_single.value(l[0])}}}catch(k){console.debug("tools-select-content::value() - Skipped.")}}else{this.select_single&&this.select_single.value("__null__");this.select_multiple&&this.select_multiple.value("__null__");this.select_collection&&this.select_collection.value("__null__")}this.refresh()}var j=this._select().value();if(!(j instanceof Array)){j=[j]}var f={batch:this.mode=="single"&&this.current!="single",values:[]};for(var g in j){f.values.push({id:j[g],src:this.list[this.current].type})}return f},validate:function(){return this._select().validate()},refresh:function(){this.button_type.value(this.current);for(var g in this.list){var f=this.list[g].field.$el;if(this.current==g){f.show()}else{f.hide()}}if(this.mode=="single"&&this.current!="single"){this.$batch.show()}else{this.$batch.hide()}},_select:function(){return this.list[this.current].field}});return{View:d}});
\ No newline at end of file
diff -r 527b11f07d8107298c87293eb04469f2743e229e -r ade75ceb5427c588756ab888c3944cf4d25ada73 static/scripts/packed/mvc/ui/ui-options.js
--- a/static/scripts/packed/mvc/ui/ui-options.js
+++ b/static/scripts/packed/mvc/ui/ui-options.js
@@ -1,1 +1,1 @@
-define(["utils/utils"],function(b){var a=Backbone.View.extend({initialize:function(g){this.optionsDefault={visible:true,data:[],id:b.uuid(),error_text:"No data available.",wait_text:"Please wait..."};this.options=b.merge(g,this.optionsDefault);this.setElement('<div class="ui-options"/>');this.$message=$("<div/>");this.$options=$(this._template(g));this.$el.append(this.$message);this.$el.append(this.$options);if(!this.options.visible){this.$el.hide()}this.update(this.options.data);if(this.options.value!==undefined){this.value(this.options.value)}var f=this;this.on("change",function(){f._change()})},update:function(g){var j=this._getValue();this.$options.empty();if(this._templateOptions){this.$options.append(this._templateOptions(g))}else{for(var h in g){var i=$(this._templateOption(g[h]));i.addClass("ui-option");i.tooltip({title:g[h].tooltip,placement:"bottom"});this.$options.append(i)}}var f=this;this.$el.find("input").on("change",function(){f.value(f._getValue());f._change()});this._refresh();this.value(j)},value:function(g){if(g!==undefined){if(!(g instanceof Array)){g=[g]}this.$el.find("input").prop("checked",false);for(var f in g){this.$el.find('input[value="'+g[f]+'"]').first().prop("checked",true)}}return this._getValue()},exists:function(g){if(g!==undefined){if(!(g instanceof Array)){g=[g]}for(var f in g){if(this.$el.find('input[value="'+g[f]+'"]').length>0){return true}}}return false},first:function(){var f=this.$el.find("input");if(f.length>0){return f.val()}else{return undefined}},validate:function(){return b.validate(this.value())},wait:function(){if(this._size()==0){this._messageShow(this.options.wait_text,"info");this.$options.hide()}},unwait:function(){this._messageHide();this._refresh()},_change:function(){if(this.options.onchange){this.options.onchange(this._getValue())}},_refresh:function(){if(this._size()==0){this._messageShow(this.options.error_text,"danger");this.$options.hide()}else{this._messageHide();this.$options.css("display","inline-block")}},_getValue:function(){var g=this.$el.find(":checked");if(g.length==0){return"__null__"}if(this.options.multiple){var f=[];g.each(function(){f.push($(this).val())});return f}else{return g.val()}},_size:function(){return this.$el.find(".ui-option").length},_messageShow:function(g,f){this.$message.show();this.$message.removeClass();this.$message.addClass("ui-message alert alert-"+f);this.$message.html(g)},_messageHide:function(){this.$message.hide()},_template:function(){return'<div class="ui-options-input"/>'}});var d={};d.View=a.extend({initialize:function(f){a.prototype.initialize.call(this,f)},_templateOption:function(f){return'<div><input type="radio" name="'+this.options.id+'" value="'+f.value+'"/>'+f.label+"<br></div>"}});var c={};c.View=a.extend({initialize:function(f){f.multiple=true;a.prototype.initialize.call(this,f)},_templateOption:function(f){return'<div><input type="checkbox" name="'+this.options.id+'" value="'+f.value+'"/>'+f.label+"<br></div>"}});var e={};e.View=a.extend({initialize:function(f){a.prototype.initialize.call(this,f)},value:function(f){if(f!==undefined){this.$el.find("input").prop("checked",false);this.$el.find("label").removeClass("active");this.$el.find('[value="'+f+'"]').prop("checked",true).closest("label").addClass("active")}return this._getValue()},_templateOption:function(g){var f='<label class="btn btn-default">';if(g.icon){f+='<i class="fa '+g.icon+'"/>'}f+='<input type="radio" name="'+this.options.id+'" value="'+g.value+'">'+g.label+"</label>";return f},_template:function(){return'<div class="btn-group ui-radiobutton" data-toggle="buttons"/>'}});return{Base:a,Radio:d,RadioButton:e,Checkbox:c}});
\ No newline at end of file
+define(["utils/utils"],function(b){var a=Backbone.View.extend({initialize:function(g){this.optionsDefault={visible:true,data:[],id:b.uuid(),error_text:"No data available.",wait_text:"Please wait..."};this.options=b.merge(g,this.optionsDefault);this.setElement('<div class="ui-options"/>');this.$message=$("<div/>");this.$options=$(this._template(g));this.$el.append(this.$message);this.$el.append(this.$options);if(!this.options.visible){this.$el.hide()}this.update(this.options.data);if(this.options.value!==undefined){this.value(this.options.value)}var f=this;this.on("change",function(){f._change()})},update:function(g){var j=this._getValue();this.$options.empty();if(this._templateOptions){this.$options.append(this._templateOptions(g))}else{for(var h in g){var i=$(this._templateOption(g[h]));i.addClass("ui-option");i.tooltip({title:g[h].tooltip,placement:"bottom"});this.$options.append(i)}}var f=this;this.$el.find("input").on("change",function(){f.value(f._getValue());f._change()});this._refresh();this.value(j)},value:function(g){if(g!==undefined){if(!(g instanceof Array)){g=[g]}this.$el.find("input").prop("checked",false);for(var f in g){this.$el.find('input[value="'+g[f]+'"]').first().prop("checked",true)}}return this._getValue()},exists:function(g){if(g!==undefined){if(!(g instanceof Array)){g=[g]}for(var f in g){if(this.$el.find('input[value="'+g[f]+'"]').length>0){return true}}}return false},first:function(){var f=this.$el.find("input");if(f.length>0){return f.val()}else{return undefined}},validate:function(){return b.validate(this.value())},wait:function(){if(this._size()==0){this._messageShow(this.options.wait_text,"info");this.$options.hide()}},unwait:function(){this._messageHide();this._refresh()},_change:function(){if(this.options.onchange){this.options.onchange(this._getValue())}},_refresh:function(){if(this._size()==0){this._messageShow(this.options.error_text,"danger");this.$options.hide()}else{this._messageHide();this.$options.css("display","inline-block")}},_getValue:function(){var g=this.$el.find(":checked");if(g.length==0){return"__null__"}if(this.options.multiple){var f=[];g.each(function(){f.push($(this).val())});return f}else{return g.val()}},_size:function(){return this.$el.find(".ui-option").length},_messageShow:function(g,f){this.$message.show();this.$message.removeClass();this.$message.addClass("ui-message alert alert-"+f);this.$message.html(g)},_messageHide:function(){this.$message.hide()},_template:function(){return'<div class="ui-options-input"/>'}});var d={};d.View=a.extend({initialize:function(f){a.prototype.initialize.call(this,f)},_templateOption:function(f){return'<div><input type="radio" name="'+this.options.id+'" value="'+f.value+'"/>'+f.label+"<br></div>"}});var c={};c.View=a.extend({initialize:function(f){f.multiple=true;a.prototype.initialize.call(this,f)},_templateOption:function(f){return'<div><input type="checkbox" name="'+this.options.id+'" value="'+f.value+'"/>'+f.label+"<br></div>"}});var e={};e.View=a.extend({initialize:function(f){a.prototype.initialize.call(this,f)},value:function(f){if(f!==undefined){this.$el.find("input").prop("checked",false);this.$el.find("label").removeClass("active");this.$el.find('[value="'+f+'"]').prop("checked",true).closest("label").addClass("active")}return this._getValue()},_templateOption:function(h){var f="fa "+h.icon;if(!h.label){f+=" no-padding"}var g='<label class="btn btn-default">';if(h.icon){g+='<i class="'+f+'"/>'}g+='<input type="radio" name="'+this.options.id+'" value="'+h.value+'">';if(h.label){g+=h.label}g+="</label>";return g},_template:function(){return'<div class="btn-group ui-radiobutton" data-toggle="buttons"/>'}});return{Base:a,Radio:d,RadioButton:e,Checkbox:c}});
\ No newline at end of file
diff -r 527b11f07d8107298c87293eb04469f2743e229e -r ade75ceb5427c588756ab888c3944cf4d25ada73 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1396,6 +1396,7 @@
.upload-header .select2-choice{max-height:20px;line-height:18px;background:transparent;text-align:center;font-weight:normal}.upload-header .select2-choice .select2-arrow b{background-position:0 -3px}
.upload-top{height:5%;text-align:center}.upload-top .upload-info{margin-top:0px;font-weight:normal;text-align:center}
.no-highlight,.ui-button-icon,.ui-portlet,.ui-portlet-repeat,.ui-portlet-limited,.ui-portlet-section,.ui-portlet-narrow{-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-ms-user-select:none;}
+.no-padding{padding:0px !important}
.ui-margin-top{padding-top:5px !important}
.ui-margin-bottom{margin-bottom:5px !important}
.ui-error{-moz-border-radius:3px;border-radius:3px;background:#f9c7c5;padding:5px}
diff -r 527b11f07d8107298c87293eb04469f2743e229e -r ade75ceb5427c588756ab888c3944cf4d25ada73 static/style/src/less/ui.less
--- a/static/style/src/less/ui.less
+++ b/static/style/src/less/ui.less
@@ -6,6 +6,11 @@
-ms-user-select: none; /* IE10+ */
}
+// remove padding
+.no-padding {
+ padding: 0px !important;
+}
+
// default margins
@ui-margin-vertical: 5px;
@ui-margin-horizontal: 5px;
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Merged in JenCabral/galaxy-central/tool_shed_test_fix-DB_initialization (pull request #662)
by commits-noreply@bitbucket.org 07 Feb '15
by commits-noreply@bitbucket.org 07 Feb '15
07 Feb '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/527b11f07d81/
Changeset: 527b11f07d81
User: jmchilton
Date: 2015-02-07 02:33:49+00:00
Summary: Merged in JenCabral/galaxy-central/tool_shed_test_fix-DB_initialization (pull request #662)
Fix tool shed tests - create database directory
Affected #: 2 files
diff -r 3dd2ec31034db4febf1954c295b81604cca62169 -r 527b11f07d8107298c87293eb04469f2743e229e test/install_and_test_tool_shed_repositories/repositories_with_tools/functional_tests.py
--- a/test/install_and_test_tool_shed_repositories/repositories_with_tools/functional_tests.py
+++ b/test/install_and_test_tool_shed_repositories/repositories_with_tools/functional_tests.py
@@ -407,6 +407,9 @@
else:
tempdir = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
galaxy_db_path = os.path.join( tempdir, 'database' )
+ # Checks if galaxy_db_path exists, if not create it.
+ if not os.path.exists(galaxy_db_path):
+ os.makedirs(galaxy_db_path)
# Configure the paths Galaxy needs to install and test tools.
galaxy_file_path = os.path.join( galaxy_db_path, 'files' )
galaxy_tempfiles = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
diff -r 3dd2ec31034db4febf1954c295b81604cca62169 -r 527b11f07d8107298c87293eb04469f2743e229e test/install_and_test_tool_shed_repositories/tool_dependency_definitions/functional_tests.py
--- a/test/install_and_test_tool_shed_repositories/tool_dependency_definitions/functional_tests.py
+++ b/test/install_and_test_tool_shed_repositories/tool_dependency_definitions/functional_tests.py
@@ -255,6 +255,9 @@
else:
tempdir = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
galaxy_db_path = os.path.join( tempdir, 'database' )
+ # Checks that galaxy_db_path exists and if not, create it.
+ if not os.path.exists(galaxy_db_path):
+ os.makedirs(galaxy_db_path)
# Configure the paths Galaxy needs to install and test tools.
galaxy_file_path = os.path.join( galaxy_db_path, 'files' )
galaxy_tempfiles = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
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