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
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4ceb95d03fc6/
Changeset: 4ceb95d03fc6
User: dannon
Date: 2015-01-07 19:51:11+00:00
Summary: Slightly bump the width of the Message field for bug reports.
Affected #: 1 file
diff -r 8c57fc528cb7255ab11d20b03b5dd8509e3ea5a0 -r 4ceb95d03fc6554aad5d63e5ab8be6da948121e8 templates/webapps/galaxy/dataset/errors.mako
--- a/templates/webapps/galaxy/dataset/errors.mako
+++ b/templates/webapps/galaxy/dataset/errors.mako
@@ -99,7 +99,7 @@
</div><div class="form-row"><label>Message</label>
- <textarea name="message" rows="10" cols="40"></textarea>
+ <textarea name="message" rows="10" cols="60"></textarea></div><div class="form-row"><input type="submit" name="submit_error_report" value="Report" onclick="return sendReport( this, this.form, '_self' );"/>
https://bitbucket.org/galaxy/galaxy-central/commits/23fddbbd5153/
Changeset: 23fddbbd5153
User: dannon
Date: 2015-01-07 19:51:24+00:00
Summary: Strip whitespace.
Affected #: 1 file
diff -r 4ceb95d03fc6554aad5d63e5ab8be6da948121e8 -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e templates/webapps/galaxy/dataset/errors.mako
--- a/templates/webapps/galaxy/dataset/errors.mako
+++ b/templates/webapps/galaxy/dataset/errors.mako
@@ -32,7 +32,7 @@
{
form.elements[i].disabled = true;
}
-
+
}
var hiddenInput = document.createElement('input');
hiddenInput.type = 'hidden';
@@ -52,7 +52,7 @@
<p><b>Dataset ${hda.hid}: ${hda.display_name() | h}</b></p><% job = hda.creating_job %>
%if job:
-
+
%if job.traceback:
The Galaxy framework encountered the following error while attempting to run the tool:
<pre>${ util.unicodify( job.traceback ) | h}</pre>
@@ -82,8 +82,8 @@
%><h2>Report this error to the Galaxy Team</h2><p>
- The Galaxy team regularly reviews errors that occur in the application.
- However, if you would like to provide additional information (such as
+ The Galaxy team regularly reviews errors that occur in the application.
+ However, if you would like to provide additional information (such as
what you were trying to do when the error occurred) and a contact e-mail
address, we will be better able to investigate your problem and get back
to you.
https://bitbucket.org/galaxy/galaxy-central/commits/85e8fb54b285/
Changeset: 85e8fb54b285
User: dannon
Date: 2015-01-12 13:59:51+00:00
Summary: Merge.
Affected #: 62 files
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 client/galaxy/scripts/galaxy.workflow_editor.canvas.js
--- a/client/galaxy/scripts/galaxy.workflow_editor.canvas.js
+++ b/client/galaxy/scripts/galaxy.workflow_editor.canvas.js
@@ -805,7 +805,7 @@
nodeView.addDataOutput( output );
} );
nodeView.render();
- workflow.node_changed( this );
+ workflow.node_changed( this, true);
},
update_field_data : function( data ) {
var node = this;
@@ -1094,9 +1094,9 @@
this.active_node = node;
}
},
- node_changed : function ( node ) {
+ node_changed : function ( node, force ) {
this.has_changes = true;
- if ( this.active_node == node ) {
+ if ( this.active_node == node && (!parent.__NEWTOOLFORM__ || force)) {
// Reactive with new form_html
this.check_changes_in_active_form(); //Force changes to be saved even on new connection (previously dumped)
parent.show_form_for_tool( node.form_html + node.tooltip, node );
@@ -1305,6 +1305,12 @@
return node;
}
+function update_node( data ) {
+ var node = workflow.active_node;
+ if (node) {
+ node.update_field_data(data, true);
+ }
+}
var ext_to_type = null;
var type_to_type = null;
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 client/galaxy/scripts/mvc/tools/tools-form-base.js
--- /dev/null
+++ b/client/galaxy/scripts/mvc/tools/tools-form-base.js
@@ -0,0 +1,315 @@
+/**
+ This is the main class of the tool form plugin. It is referenced as 'app' in all lower level modules.
+*/
+define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
+ 'mvc/citation/citation-model', 'mvc/citation/citation-view',
+ 'mvc/tools', 'mvc/tools/tools-template', 'mvc/tools/tools-content', 'mvc/tools/tools-section', 'mvc/tools/tools-tree'],
+ function(Utils, Deferred, Portlet, Ui, CitationModel, CitationView,
+ Tools, ToolTemplate, ToolContent, ToolSection, ToolTree) {
+
+ // create form view
+ return Backbone.View.extend({
+ // initialize
+ initialize: function(options) {
+ // log options
+ console.debug(options);
+
+ // link galaxy modal or create one
+ var galaxy = parent.Galaxy;
+ if (galaxy && galaxy.modal) {
+ this.modal = galaxy.modal;
+ } else {
+ this.modal = new Ui.Modal.View();
+ }
+
+ // check if the user is an admin
+ if (galaxy && galaxy.currUser) {
+ this.is_admin = galaxy.currUser.get('is_admin');
+ } else {
+ this.is_admin = false;
+ }
+
+ // link options
+ this.options = options;
+
+ // link container
+ this.container = this.options.container || 'body';
+
+ // create deferred processing queue handler
+ // this handler reduces the number of requests to the api by filtering redundant requests
+ this.deferred = new Deferred();
+
+ // set element
+ this.setElement('<div/>');
+
+ // add to main element
+ $(this.container).append(this.$el);
+
+ // build this form
+ this._buildForm();
+ },
+
+ /** Shows the final message (usually upon successful job submission)
+ */
+ reciept: function($el) {
+ $(this.container).empty();
+ $(this.container).append($el);
+ },
+
+ /** Highlight and scroll to input element (currently only used for error notifications)
+ */
+ highlight: function (input_id, message, silent) {
+ // get input field
+ var input_element = this.element_list[input_id];
+
+ // check input element
+ if (input_element) {
+ // mark error
+ input_element.error(message || 'Please verify this parameter.');
+
+ // scroll to first input element
+ if (!silent) {
+ $(this.container).animate({
+ scrollTop: input_element.$el.offset().top - 20
+ }, 500);
+ }
+ }
+ },
+
+ /** Main tool form build function. This function is called once a new model is available.
+ */
+ _buildForm: function() {
+ // link this
+ var self = this;
+
+ // reset events
+ this.off('refresh');
+ this.off('reset');
+
+ // reset field list, which contains the input field elements
+ this.field_list = {};
+
+ // reset sequential input definition list, which contains the input definitions as provided from the api
+ this.input_list = {};
+
+ // reset input element list, which contains the dom elements of each input element (includes also the input field)
+ this.element_list = {};
+
+ // creates a tree/json data structure from the input form
+ this.tree = new ToolTree(this);
+
+ // request history content and build form
+ this.content = new ToolContent(this);
+
+ // link model options
+ var options = this.options;
+
+ // create ui elements
+ this._renderForm(options);
+
+ // rebuild the underlying data structure
+ this.tree.finalize();
+
+ // show errors
+ if (!this.workflow && options.errors) {
+ var error_messages = this.tree.matchResponse(options.errors);
+ for (var input_id in error_messages) {
+ this.highlight(input_id, error_messages[input_id], true);
+ }
+ }
+
+ // add refresh listener
+ this.on('refresh', function() {
+ // by using/reseting the deferred ajax queue the number of redundant calls is reduced
+ self.deferred.reset();
+ self.deferred.execute(function(){self._updateModel()});
+ });
+
+ // add reset listener
+ this.on('reset', function() {
+ for (var i in this.element_list) {
+ this.element_list[i].reset();
+ }
+ });
+ },
+
+ /** Renders the UI elements required for the form
+ */
+ _renderForm: function(options) {
+ // link this
+ var self = this;
+
+ // create message view
+ this.message = new Ui.Message();
+
+ // button for version selection
+ var requirements_button = new Ui.ButtonIcon({
+ icon : 'fa-info-circle',
+ title : 'Requirements',
+ tooltip : 'Display tool requirements',
+ onclick : function() {
+ if (!this.visible) {
+ this.visible = true;
+ self.message.update({
+ persistent : true,
+ message : ToolTemplate.requirements(options),
+ status : 'info'
+ });
+ } else {
+ this.visible = false;
+ self.message.update({
+ message : ''
+ });
+ }
+ }
+ });
+ if (!options.requirements || options.requirements.length == 0) {
+ requirements_button.$el.hide();
+ }
+
+ // button for version selection
+ var versions_button = new Ui.ButtonMenu({
+ icon : 'fa-cubes',
+ title : 'Versions',
+ tooltip : 'Select another tool version'
+ });
+ if (options.versions && options.versions.length > 1) {
+ for (var i in options.versions) {
+ var version = options.versions[i];
+ if (version != options.version) {
+ versions_button.addMenu({
+ title : 'Switch to ' + version,
+ version : version,
+ icon : 'fa-cube',
+ onclick : function() {
+ // here we update the tool version (some tools encode the version also in the id)
+ options.id = options.id.replace(options.version, this.version);
+ options.version = this.version;
+
+ // rebuild the model and form
+ self.deferred.reset();
+ self.deferred.execute(function(){self._buildModel()});
+ }
+ });
+ }
+ }
+ } else {
+ versions_button.$el.hide();
+ }
+
+ // button menu
+ var menu_button = new Ui.ButtonMenu({
+ icon : 'fa-caret-down',
+ title : 'Options',
+ tooltip : 'View available options'
+ });
+
+ // configure button selection
+ if(options.biostar_url) {
+ // add question option
+ menu_button.addMenu({
+ icon : 'fa-question-circle',
+ title : 'Question?',
+ tooltip : 'Ask a question about this tool (Biostar)',
+ onclick : function() {
+ window.open(options.biostar_url + '/p/new/post/');
+ }
+ });
+
+ // create search button
+ menu_button.addMenu({
+ icon : 'fa-search',
+ title : 'Search',
+ tooltip : 'Search help for this tool (Biostar)',
+ onclick : function() {
+ window.open(options.biostar_url + '/t/' + options.id + '/');
+ }
+ });
+ };
+
+ // create share button
+ menu_button.addMenu({
+ icon : 'fa-share',
+ title : 'Share',
+ tooltip : 'Share this tool',
+ onclick : function() {
+ prompt('Copy to clipboard: Ctrl+C, Enter', window.location.origin + galaxy_config.root + 'root?tool_id=' + options.id);
+ }
+ });
+
+ // add admin operations
+ if (this.is_admin) {
+ // create download button
+ menu_button.addMenu({
+ icon : 'fa-download',
+ title : 'Download',
+ tooltip : 'Download this tool',
+ onclick : function() {
+ window.location.href = galaxy_config.root + 'api/tools/' + options.id + '/download';
+ }
+ });
+ }
+
+ // create tool form section
+ this.section = new ToolSection.View(self, {
+ inputs : options.inputs,
+ cls : 'ui-table-plain'
+ });
+
+ // switch to classic tool form mako if the form definition is incompatible
+ if (this.incompatible) {
+ this.$el.hide();
+ $('#tool-form-classic').show();
+ return;
+ }
+
+ // create portlet
+ this.portlet = new Portlet.View({
+ icon : 'fa-wrench',
+ title : '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Tool Version ' + options.version + ')',
+ cls : 'ui-portlet-slim',
+ operations: {
+ requirements : requirements_button,
+ menu : menu_button,
+ versions : versions_button
+ },
+ buttons : this.buttons
+ });
+
+ // append message
+ this.portlet.append(this.message.$el, true);
+
+ // append tool section
+ this.portlet.append(this.section.$el);
+
+ // start form
+ this.$el.empty();
+ this.$el.append(this.portlet.$el);
+
+ // append help
+ if (options.help != '') {
+ this.$el.append(ToolTemplate.help(options.help));
+ }
+
+ // append citations
+ if (options.citations) {
+ var $citations = $('<div/>');
+ var citations = new CitationModel.ToolCitationCollection();
+ citations.tool_id = options.id;
+ var citation_list_view = new CitationView.CitationListView({ el: $citations, collection: citations } );
+ citation_list_view.render();
+ citations.fetch();
+ this.$el.append($citations);
+ }
+
+ // show message if available in model
+ if (options.message) {
+ this.message.update({
+ persistent : true,
+ status : 'warning',
+ message : options.message
+ });
+ }
+ }
+ });
+});
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 client/galaxy/scripts/mvc/tools/tools-form-workflow.js
--- /dev/null
+++ b/client/galaxy/scripts/mvc/tools/tools-form-workflow.js
@@ -0,0 +1,66 @@
+/**
+ This is the main class of the tool form plugin. It is referenced as 'app' in all lower level modules.
+*/
+define(['utils/utils', 'mvc/tools/tools-form-base'],
+ function(Utils, ToolFormBase) {
+
+ // create form view
+ var View = ToolFormBase.extend({
+ initialize: function(options) {
+ this.workflow = true;
+ ToolFormBase.prototype.initialize.call(this, options);
+ },
+
+ /** Builds a new model through api call and recreates the entire form
+ */
+ _buildModel: function() {
+ },
+
+ /** Request a new model for an already created tool form and updates the form inputs
+ */
+ _updateModel: function() {
+ // create the request dictionary
+ var self = this;
+ var current_state = this.tree.finalize();
+
+ // log tool state
+ console.debug('tools-form-workflow::_refreshForm() - Refreshing states.');
+ console.debug(current_state);
+
+ // register process
+ 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;
+
+ // post job
+ Utils.request({
+ type : 'GET',
+ url : model_url,
+ data : current_state,
+ success : function(node) {
+ parent.update_node(node);
+
+ // process completed
+ self.deferred.done(process_id);
+
+ // log success
+ console.debug('tools-form::_refreshForm() - States refreshed.');
+ console.debug(node);
+ },
+ error : function(response) {
+ // process completed
+ self.deferred.done(process_id);
+
+ // log error
+ console.debug('tools-form::_refreshForm() - Refresh request failed.');
+ console.debug(response);
+ }
+ });
+ }
+ });
+
+ return {
+ View: View
+ };
+});
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 client/galaxy/scripts/mvc/tools/tools-form.js
--- a/client/galaxy/scripts/mvc/tools/tools-form.js
+++ b/client/galaxy/scripts/mvc/tools/tools-form.js
@@ -1,79 +1,28 @@
/**
This is the main class of the tool form plugin. It is referenced as 'app' in all lower level modules.
*/
-define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
- 'mvc/citation/citation-model', 'mvc/citation/citation-view',
- 'mvc/tools', 'mvc/tools/tools-template', 'mvc/tools/tools-content', 'mvc/tools/tools-section', 'mvc/tools/tools-tree', 'mvc/tools/tools-jobs'],
- function(Utils, Deferred, Portlet, Ui, CitationModel, CitationView,
- Tools, ToolTemplate, ToolContent, ToolSection, ToolTree, ToolJobs) {
+define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools/tools-jobs'],
+ function(Utils, Ui, ToolFormBase, ToolJobs) {
// create form view
- var View = Backbone.View.extend({
- // base element
- container: 'body',
-
+ var View = ToolFormBase.extend({
// initialize
initialize: function(options) {
- // log options
- console.debug(options);
-
- // link galaxy modal or create one
- var galaxy = parent.Galaxy;
- if (galaxy && galaxy.modal) {
- this.modal = galaxy.modal;
- } else {
- this.modal = new Ui.Modal.View();
+ var self = this;
+ this.job_handler = new ToolJobs(this);
+ this.buttons = {
+ execute : new Ui.Button({
+ icon : 'fa-check',
+ tooltip : 'Execute: ' + options.name,
+ title : 'Execute',
+ cls : 'btn btn-primary',
+ floating : 'clear',
+ onclick : function() {
+ self.job_handler.submit();
+ }
+ })
}
-
- // check if the user is an admin
- if (galaxy && galaxy.currUser) {
- this.is_admin = galaxy.currUser.get('is_admin')
- } else {
- this.is_admin = false;
- }
-
- // link options
- this.options = options;
-
- // create deferred processing queue handler
- // this handler reduces the number of requests to the api by filtering redundant requests
- this.deferred = new Deferred();
-
- // set element
- this.setElement('<div/>');
-
- // add to main element
- $(this.container).append(this.$el);
-
- // build this form
- this._buildForm();
- },
-
- /** Shows the final message (usually upon successful job submission)
- */
- reciept: function($el) {
- $(this.container).empty();
- $(this.container).append($el);
- },
-
- /** Highlight and scroll to input element (currently only used for error notifications)
- */
- highlight: function (input_id, message, silent) {
- // get input field
- var input_element = this.element_list[input_id];
-
- // check input element
- if (input_element) {
- // mark error
- input_element.error(message || 'Please verify this parameter.');
-
- // scroll to first input element
- if (!silent) {
- $(this.container).animate({
- scrollTop: input_element.$el.offset().top - 20
- }, 500);
- }
- }
+ ToolFormBase.prototype.initialize.call(this, options);
},
/** Builds a new model through api call and recreates the entire form
@@ -250,256 +199,6 @@
console.debug(response);
}
});
- },
-
- /** Main tool form build function. This function is called once a new model is available.
- */
- _buildForm: function() {
- // link this
- var self = this;
-
- // reset events
- this.off('refresh');
- this.off('reset');
-
- // reset field list, which contains the input field elements
- this.field_list = {};
-
- // reset sequential input definition list, which contains the input definitions as provided from the api
- this.input_list = {};
-
- // reset input element list, which contains the dom elements of each input element (includes also the input field)
- this.element_list = {};
-
- // creates a tree/json data structure from the input form
- this.tree = new ToolTree(this);
-
- // creates the job handler
- this.job_handler = new ToolJobs(this);
-
- // request history content and build form
- this.content = new ToolContent(this);
-
- // link model options
- var options = this.options;
-
- // create ui elements
- this._renderForm(options);
-
- // rebuild the underlying data structure
- this.tree.finalize();
-
- // show errors
- if (options.errors) {
- var error_messages = this.tree.matchResponse(options.errors);
- for (var input_id in error_messages) {
- this.highlight(input_id, error_messages[input_id], true);
- }
- }
-
- // add refresh listener
- this.on('refresh', function() {
- // by using/reseting the deferred ajax queue the number of redundant calls is reduced
- self.deferred.reset();
- self.deferred.execute(function(){self._updateModel()});
- });
-
- // add reset listener
- this.on('reset', function() {
- for (var i in this.element_list) {
- this.element_list[i].reset();
- }
- });
- },
-
- /** Renders the UI elements required for the form
- */
- _renderForm: function(options) {
- // link this
- var self = this;
-
- // create message view
- this.message = new Ui.Message();
-
- // button for version selection
- var requirements_button = new Ui.ButtonIcon({
- icon : 'fa-info-circle',
- title : 'Requirements',
- tooltip : 'Display tool requirements',
- onclick : function() {
- if (!this.visible) {
- this.visible = true;
- self.message.update({
- persistent : true,
- message : ToolTemplate.requirements(options),
- status : 'info'
- });
- } else {
- this.visible = false;
- self.message.update({
- message : ''
- });
- }
- }
- });
- if (!options.requirements || options.requirements.length == 0) {
- requirements_button.$el.hide();
- }
-
- // button for version selection
- var versions_button = new Ui.ButtonMenu({
- icon : 'fa-cubes',
- title : 'Versions',
- tooltip : 'Select another tool version'
- });
- if (options.versions && options.versions.length > 1) {
- for (var i in options.versions) {
- var version = options.versions[i];
- if (version != options.version) {
- versions_button.addMenu({
- title : 'Switch to ' + version,
- version : version,
- icon : 'fa-cube',
- onclick : function() {
- // here we update the tool version (some tools encode the version also in the id)
- options.id = options.id.replace(options.version, this.version);
- options.version = this.version;
-
- // rebuild the model and form
- self.deferred.reset();
- self.deferred.execute(function(){self._buildModel()});
- }
- });
- }
- }
- } else {
- versions_button.$el.hide();
- }
-
- // button menu
- var menu_button = new Ui.ButtonMenu({
- icon : 'fa-caret-down',
- title : 'Options',
- tooltip : 'View available options'
- });
-
- // configure button selection
- if(options.biostar_url) {
- // add question option
- menu_button.addMenu({
- icon : 'fa-question-circle',
- title : 'Question?',
- tooltip : 'Ask a question about this tool (Biostar)',
- onclick : function() {
- window.open(options.biostar_url + '/p/new/post/');
- }
- });
-
- // create search button
- menu_button.addMenu({
- icon : 'fa-search',
- title : 'Search',
- tooltip : 'Search help for this tool (Biostar)',
- onclick : function() {
- window.open(options.biostar_url + '/t/' + options.id + '/');
- }
- });
- };
-
- // create share button
- menu_button.addMenu({
- icon : 'fa-share',
- title : 'Share',
- tooltip : 'Share this tool',
- onclick : function() {
- prompt('Copy to clipboard: Ctrl+C, Enter', window.location.origin + galaxy_config.root + 'root?tool_id=' + options.id);
- }
- });
-
- // add admin operations
- if (this.is_admin) {
- // create download button
- menu_button.addMenu({
- icon : 'fa-download',
- title : 'Download',
- tooltip : 'Download this tool',
- onclick : function() {
- window.location.href = galaxy_config.root + 'api/tools/' + options.id + '/download';
- }
- });
- }
-
- // create tool form section
- this.section = new ToolSection.View(self, {
- inputs : options.inputs,
- cls : 'ui-table-plain'
- });
-
- // switch to classic tool form mako if the form definition is incompatible
- if (this.incompatible) {
- this.$el.hide();
- $('#tool-form-classic').show();
- return;
- }
-
- // create portlet
- this.portlet = new Portlet.View({
- icon : 'fa-wrench',
- title : '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Tool Version ' + options.version + ')',
- cls : 'ui-portlet-slim',
- operations: {
- requirements : requirements_button,
- menu : menu_button,
- versions : versions_button
- },
- buttons: {
- execute : new Ui.Button({
- icon : 'fa-check',
- tooltip : 'Execute: ' + options.name,
- title : 'Execute',
- cls : 'btn btn-primary',
- floating : 'clear',
- onclick : function() {
- self.job_handler.submit();
- }
- })
- }
- });
-
- // append message
- this.portlet.append(this.message.$el, true);
-
- // append tool section
- this.portlet.append(this.section.$el);
-
- // start form
- this.$el.empty();
- this.$el.append(this.portlet.$el);
-
- // append help
- if (options.help != '') {
- this.$el.append(ToolTemplate.help(options.help));
- }
-
- // append citations
- if (options.citations) {
- var $citations = $('<div/>');
- var citations = new CitationModel.ToolCitationCollection();
- citations.tool_id = options.id;
- var citation_list_view = new CitationView.CitationListView({ el: $citations, collection: citations } );
- citation_list_view.render();
- citations.fetch();
- this.$el.append($citations);
- }
-
- // show message if available in model
- if (options.message) {
- this.message.update({
- persistent : true,
- status : 'warning',
- message : options.message
- });
- }
}
});
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 client/galaxy/scripts/mvc/tools/tools-jobs.js
--- a/client/galaxy/scripts/mvc/tools/tools-jobs.js
+++ b/client/galaxy/scripts/mvc/tools/tools-jobs.js
@@ -98,7 +98,7 @@
}
// validate non-optional fields
- if (!input_def.optional && input_field.validate && !input_field.validate()) {
+ if (!input_def.optional && input_value == null) {
this.app.highlight(input_id);
return false;
}
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 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
@@ -382,6 +382,11 @@
/** Data input field
*/
_fieldData : function(input_def) {
+ if (this.app.workflow) {
+ var extensions = Utils.textify(input_def.extensions.toString());
+ input_def.info = 'Data input \'' + input_def.name + '\' (' + extensions + ')';
+ return this._fieldHidden(input_def);
+ }
var self = this;
return new SelectContent.View(this.app, {
id : 'field-' + input_def.id,
@@ -398,6 +403,14 @@
/** Select/Checkbox/Radio options field
*/
_fieldSelect : function (input_def) {
+ // show text field in workflow
+ if (this.app.workflow && input_def.is_dynamic) {
+ if (!Utils.validate(input_def.value)) {
+ input_def.value = '';
+ }
+ return this._fieldText(input_def);
+ }
+
// configure options fields
var options = [];
for (var i in input_def.options) {
@@ -475,7 +488,8 @@
*/
_fieldHidden : function(input_def) {
return new Ui.Hidden({
- id : 'field-' + input_def.id
+ id : 'field-' + input_def.id,
+ info : input_def.info
});
},
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 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
@@ -36,14 +36,7 @@
this.list = {};
// error messages
- var extensions = options.extensions.toString();
- if (extensions) {
- extensions = extensions.replace(/,/g, ', ');
- var pos = extensions.lastIndexOf(', ');
- if (pos != -1) {
- extensions = extensions.substr(0, pos) + ' or ' + extensions.substr(pos+1);
- }
- }
+ var extensions = Utils.textify(options.extensions);
var hda_error = 'No dataset available.';
if (extensions) {
hda_error = 'No ' + extensions + ' dataset available.';
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 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
@@ -2,7 +2,7 @@
This class maps the tool form dom to an api compatible javascript dictionary.
*/
// dependencies
-define([], function() {
+define(['utils/utils'], function(Utils) {
// tool form tree
return Backbone.Model.extend({
@@ -120,7 +120,7 @@
// handle default value
if (!field.skip) {
- if (input.optional && field.validate && !field.validate()) {
+ if (field.validate && !field.validate(value)) {
value = null;
}
add (job_input_id, input.id, value);
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 client/galaxy/scripts/mvc/ui/ui-misc.js
--- a/client/galaxy/scripts/mvc/ui/ui-misc.js
+++ b/client/galaxy/scripts/mvc/ui/ui-misc.js
@@ -412,7 +412,7 @@
initialize : function(options) {
// configure options
this.options = options;
-
+
// create new element
this.setElement(this._template(this.options));
@@ -425,14 +425,20 @@
// value
value : function (new_val) {
if (new_val !== undefined) {
- this.$el.val(new_val);
+ this.$('hidden').val(new_val);
}
- return this.$el.val();
+ return this.$('hidden').val();
},
// element
_template: function(options) {
- return '<hidden id="' + options.id + '" value="' + options.value + '"/>';
+ var tmpl = '<div id="' + options.id + '" >';
+ if (options.info) {
+ tmpl += '<label>' + options.info + '</label>';
+ }
+ tmpl += '<hidden value="' + options.value + '"/>' +
+ '</div>';
+ return tmpl;
}
});
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 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
@@ -137,16 +137,7 @@
/** Validate the selected option/options
*/
validate: function() {
- var current = this.value();
- if (!(current instanceof Array)) {
- current = [current];
- }
- for (var i in current) {
- if ([null, 'null', undefined].indexOf(current[i]) > -1) {
- return false;
- }
- }
- return true;
+ return Utils.validate(this.value());
},
/** Wait message during request processing
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 client/galaxy/scripts/mvc/ui/ui-select-default.js
--- a/client/galaxy/scripts/mvc/ui/ui-select-default.js
+++ b/client/galaxy/scripts/mvc/ui/ui-select-default.js
@@ -96,16 +96,7 @@
/** Validate the current selection
*/
validate: function() {
- var current = this.value();
- if (!(current instanceof Array)) {
- current = [current];
- }
- for (var i in current) {
- if ([null, 'null', undefined].indexOf(current[i]) > -1) {
- return false;
- }
- }
- return true;
+ return Utils.validate(this.value());
},
/** Return the label/text of the current selection
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 client/galaxy/scripts/mvc/upload/upload-view.js
--- a/client/galaxy/scripts/mvc/upload/upload-view.js
+++ b/client/galaxy/scripts/mvc/upload/upload-view.js
@@ -104,7 +104,7 @@
});
// define location
- $('#left .unified-panel-header-inner').append((new UploadButton.View(this.ui_button)).$el);
+ $('.with-upload-button').append((new UploadButton.View(this.ui_button)).$el);
// load extension
var self = this;
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 client/galaxy/scripts/utils/utils.js
--- a/client/galaxy/scripts/utils/utils.js
+++ b/client/galaxy/scripts/utils/utils.js
@@ -15,6 +15,40 @@
};
/**
+ * Validate atomic values or list of values
+ * usually used for selectable options
+ * @param{String} value - Value or list to be validated
+ */
+function validate (value) {
+ if (!(value instanceof Array)) {
+ value = [value];
+ }
+ for (var i in value) {
+ if (['None', null, 'null', undefined, 'undefined'].indexOf(value[i]) > -1) {
+ return false;
+ }
+ }
+ return true;
+};
+
+/**
+ * Convert list to pretty string
+ * @param{String} lst - List of strings to be converted in human readable list sentence
+ */
+function textify(lst) {
+ var lst = lst.toString();
+ if (lst) {
+ lst = lst.replace(/,/g, ', ');
+ var pos = lst.lastIndexOf(', ');
+ if (pos != -1) {
+ lst = lst.substr(0, pos) + ' or ' + lst.substr(pos+1);
+ }
+ return lst;
+ }
+ return '';
+};
+
+/**
* Request handler for GET
* @param{String} url - Url request is made to
* @param{Function} success - Callback on success
@@ -212,7 +246,9 @@
time: time,
wrap: wrap,
request: request,
- sanitize: sanitize
+ sanitize: sanitize,
+ textify: textify,
+ validate: validate
};
});
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 config/datatypes_conf.xml.sample
--- a/config/datatypes_conf.xml.sample
+++ b/config/datatypes_conf.xml.sample
@@ -181,7 +181,8 @@
<datatype extension="taxonomy" type="galaxy.datatypes.tabular:Taxonomy" display_in_upload="true"/><datatype extension="tabular" type="galaxy.datatypes.tabular:Tabular" display_in_upload="true" description="Any data in tab delimited format (tabular)." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#Tabular_.28tab_delimited.29"/><datatype extension="twobit" type="galaxy.datatypes.binary:TwoBit" mimetype="application/octet-stream" display_in_upload="true"/>
- <datatype extension="sqlite" type="galaxy.datatypes.binary:SQlite" mimetype="application/octet-stream" display_in_upload="true"/>
+ <datatype extension="sqlite" type="galaxy.datatypes.binary:SQlite" mimetype="application/octet-stream" display_in_upload="true"/>
+ <datatype extension="gemini.sqlite" type="galaxy.datatypes.binary:GeminiSQLite" mimetype="application/octet-stream" display_in_upload="True" /><datatype extension="txt" type="galaxy.datatypes.data:Text" display_in_upload="true" description="Any text file." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#Plain_text"/><datatype extension="linecount" type="galaxy.datatypes.data:LineCount" display_in_upload="false"/><datatype extension="memexml" type="galaxy.datatypes.xml:MEMEXml" mimetype="application/xml" display_in_upload="true"/>
@@ -271,6 +272,7 @@
--><sniffer type="galaxy.datatypes.tabular:Vcf"/><sniffer type="galaxy.datatypes.binary:TwoBit"/>
+ <sniffer type="galaxy.datatypes.binary:GeminiSQLite"/><sniffer type="galaxy.datatypes.binary:SQlite"/><sniffer type="galaxy.datatypes.binary:Bam"/><sniffer type="galaxy.datatypes.binary:Sff"/>
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 lib/galaxy/datatypes/binary.py
--- a/lib/galaxy/datatypes/binary.py
+++ b/lib/galaxy/datatypes/binary.py
@@ -20,7 +20,7 @@
from bx.seq.twobit import TWOBIT_MAGIC_NUMBER, TWOBIT_MAGIC_NUMBER_SWAP, TWOBIT_MAGIC_SIZE
from galaxy.util import sqlite
-from galaxy.datatypes.metadata import MetadataElement,ListParameter,DictParameter
+from galaxy.datatypes.metadata import MetadataElement, MetadataParameter, ListParameter, DictParameter
from galaxy.datatypes import metadata
import dataproviders
@@ -640,8 +640,66 @@
return dataproviders.dataset.SQliteDataDictProvider( dataset_source, **settings )
+#Binary.register_sniffable_binary_format("sqlite", "sqlite", SQlite)
+
+
+class GeminiSQLite( SQlite ):
+ """Class describing a Gemini Sqlite database """
+ MetadataElement( name="gemini_version", default='0.10.0' , param=MetadataParameter, desc="Gemini Version",
+ readonly=True, visible=True, no_value='0.10.0' )
+ file_ext = "gemini.sqlite"
+
+ def set_meta( self, dataset, overwrite = True, **kwd ):
+ super( GeminiSQLite, self ).set_meta( dataset, overwrite = overwrite, **kwd )
+ try:
+ conn = sqlite.connect( dataset.file_name )
+ c = conn.cursor()
+ tables_query = "SELECT version FROM version"
+ result = c.execute( tables_query ).fetchall()
+ for version, in result:
+ dataset.metadata.gemini_version = version
+ # TODO: Can/should we detect even more attributes, such as use of PED file, what was input annotation type, etc.
+ except Exception, e:
+ log.warn( '%s, set_meta Exception: %s', self, e )
+
+ def sniff( self, filename ):
+ if super( GeminiSQLite, self ).sniff( filename ):
+ gemini_table_names = [ "gene_detailed", "gene_summary", "resources", "sample_genotype_counts", "sample_genotypes", "samples",
+ "variant_impacts", "variants", "version" ]
+ try:
+ conn = sqlite.connect( filename )
+ c = conn.cursor()
+ tables_query = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
+ result = c.execute( tables_query ).fetchall()
+ result = map( lambda x: x[0], result )
+ for table_name in gemini_table_names:
+ if table_name not in result:
+ return False
+ return True
+ except Exception, e:
+ log.warn( '%s, sniff Exception: %s', self, e )
+ return False
+
+ def set_peek( self, dataset, is_multi_byte=False ):
+ if not dataset.dataset.purged:
+ dataset.peek = "Gemini SQLite Database, version %s" % ( dataset.metadata.gemini_version or 'unknown' )
+ dataset.blurb = data.nice_size( dataset.get_size() )
+ else:
+ dataset.peek = 'file does not exist'
+ dataset.blurb = 'file purged from disk'
+
+ def display_peek( self, dataset ):
+ try:
+ return dataset.peek
+ except:
+ return "Gemini SQLite Database, version %s" % ( dataset.metadata.gemini_version or 'unknown' )
+
+Binary.register_sniffable_binary_format( "gemini.sqlite", "gemini.sqlite", GeminiSQLite )
+# FIXME: We need to register gemini.sqlite before sqlite, since register_sniffable_binary_format and is_sniffable_binary called in upload.py
+# ignores sniff order declared in datatypes_conf.xml
Binary.register_sniffable_binary_format("sqlite", "sqlite", SQlite)
+
class Xlsx(Binary):
"""Class for Excel 2007 (xlsx) files"""
file_ext="xlsx"
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -33,7 +33,7 @@
from galaxy.tools.actions.data_source import DataSourceToolAction
from galaxy.tools.actions.data_manager import DataManagerToolAction
from galaxy.tools.deps import build_dependency_manager
-from galaxy.tools.parameters import check_param, params_from_strings, params_to_strings
+from galaxy.tools.parameters import params_to_incoming, check_param, params_from_strings, params_to_strings
from galaxy.tools.parameters import output_collect
from galaxy.tools.parameters.basic import (BaseURLToolParameter,
DataToolParameter, HiddenToolParameter, LibraryDatasetToolParameter,
@@ -1843,7 +1843,8 @@
"""Return a list of commands to be run to populate the current environment to include this tools requirements."""
return self.app.toolbox.dependency_manager.dependency_shell_commands(
self.requirements,
- installed_tool_dependencies=self.installed_tool_dependencies
+ installed_tool_dependencies=self.installed_tool_dependencies,
+ tool_dir=self.tool_dir,
)
@property
@@ -2072,6 +2073,336 @@
return tool_dict
+ def to_json (self, trans, **kwd):
+ """
+ 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)
+
+ # load job details if provided
+ job = None
+ if job_id:
+ try:
+ job_id = trans.security.decode_id( job_id )
+ job = trans.sa_session.query( trans.app.model.Job ).get( job_id )
+ except Exception, exception:
+ trans.response.status = 500
+ log.error('Failed to retrieve job.')
+ return { 'error': 'Failed to retrieve job.' }
+ elif dataset_id:
+ try:
+ dataset_id = trans.security.decode_id( dataset_id )
+ data = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( dataset_id )
+ if not ( trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), data.dataset ) ):
+ trans.response.status = 500
+ log.error('User has no access to dataset.')
+ return { 'error': 'User has no access to dataset.' }
+ job = data.creating_job
+ if not job:
+ trans.response.status = 500
+ log.error('Creating job not found.')
+ return { 'error': 'Creating job not found.' }
+ except Exception, exception:
+ trans.response.status = 500
+ log.error('Failed to get job information.')
+ return { 'error': 'Failed to get job information.' }
+
+ # load job parameters into incoming
+ tool_message = ''
+ if job:
+ try:
+ job_params = job.get_param_values( trans.app, ignore_errors = True )
+ job_messages = self.check_and_update_param_values( job_params, trans, update_values=False )
+ tool_message = self._compare_tool_version(trans, job)
+ params_to_incoming( kwd, self.inputs, job_params, trans.app )
+ except Exception, exception:
+ trans.response.status = 500
+ return { 'error': str( exception ) }
+
+ # create parameter object
+ params = galaxy.util.Params( kwd, sanitize = False )
+
+ # convert value to jsonifiable value
+ def jsonify(v):
+ # check if value is numeric
+ isnumber = False
+ try:
+ float(v)
+ isnumber = True
+ except Exception:
+ pass
+
+ # fix hda parsing
+ if isinstance(v, trans.app.model.HistoryDatasetAssociation):
+ return {
+ 'id' : trans.security.encode_id(v.id),
+ 'src' : 'hda'
+ }
+ elif isinstance(v, bool):
+ if v is True:
+ return 'true'
+ else:
+ return 'false'
+ elif isinstance(v, basestring) or isnumber:
+ return v
+ else:
+ return None
+
+ # ensures that input dictionary is jsonifiable
+ def sanitize(dict):
+ # get current value
+ value = dict['value'] if 'value' in dict else None
+
+ # jsonify by type
+ if dict['type'] in ['data']:
+ if isinstance(value, list):
+ value = [ jsonify(v) for v in value ]
+ else:
+ value = [ jsonify(value) ]
+ value = { 'values': value }
+ elif isinstance(value, list):
+ value = [ jsonify(v) for v in value ]
+ else:
+ value = jsonify(value)
+
+ # update and return
+ dict['value'] = value
+ return dict
+
+ # initialize state using default parameters
+ def initialize_state(trans, inputs, state, context=None):
+ context = ExpressionContext(state, context)
+ for input in inputs.itervalues():
+ state[input.name] = input.get_initial_value(trans, context)
+
+ # check the current state of a value and update it if necessary
+ def check_state(trans, input, default_value, context):
+ value = default_value
+ error = 'State validation failed.'
+ try:
+ # resolves the inconsistent definition of boolean parameters (see base.py) without modifying shared code
+ if input.type == 'boolean' and isinstance(default_value, basestring):
+ value, error = [util.string_as_bool(default_value), None]
+ else:
+ value, error = check_param(trans, input, default_value, context)
+ except Exception, err:
+ log.error('Checking parameter failed. %s', str(err))
+ pass
+ return [value, error]
+
+ # populates state with incoming url parameters
+ def populate_state(trans, inputs, state, errors, incoming, prefix="", context=None ):
+ context = ExpressionContext(state, context)
+ for input in inputs.itervalues():
+ key = prefix + input.name
+ if input.type == 'repeat':
+ group_state = state[input.name]
+ rep_index = 0
+ del group_state[:]
+ while True:
+ rep_name = "%s_%d" % (key, rep_index)
+ if not any([incoming_key.startswith(rep_name) for incoming_key in incoming.keys()]):
+ break
+ if rep_index < input.max:
+ new_state = {}
+ new_state['__index__'] = rep_index
+ initialize_state(trans, input.inputs, new_state, context)
+ group_state.append(new_state)
+ populate_state(trans, input.inputs, new_state, errors, incoming, prefix=rep_name + "|", context=context)
+ rep_index += 1
+ elif input.type == 'conditional':
+ group_state = state[input.name]
+ group_prefix = "%s|" % ( key )
+ test_param_key = group_prefix + input.test_param.name
+ default_value = incoming.get(test_param_key, group_state.get(input.test_param.name, None))
+ value, error = check_state(trans, input.test_param, default_value, context)
+ if error:
+ errors[test_param_key] = error
+ else:
+ try:
+ current_case = input.get_current_case(value, trans)
+ group_state = state[input.name] = {}
+ initialize_state(trans, input.cases[current_case].inputs, group_state, context)
+ populate_state( trans, input.cases[current_case].inputs, group_state, errors, incoming, prefix=group_prefix, context=context)
+ group_state['__current_case__'] = current_case
+ except Exception, e:
+ errors[test_param_key] = 'The selected case is unavailable/invalid.'
+ pass
+ group_state[input.test_param.name] = value
+ else:
+ default_value = incoming.get(key, state.get(input.name, None))
+ value, error = check_state(trans, input, default_value, context)
+ if error:
+ errors[key] = error
+ state[input.name] = value
+
+ # builds tool model including all attributes
+ def iterate(group_inputs, inputs, state_inputs, other_values=None):
+ other_values = ExpressionContext( state_inputs, other_values )
+ for input_index, input in enumerate( inputs.itervalues() ):
+ # create model dictionary
+ tool_dict = input.to_dict(trans)
+ if tool_dict is None:
+ continue
+
+ # state for subsection/group
+ group_state = state_inputs[input.name]
+
+ # iterate and update values
+ if input.type == 'repeat':
+ group_cache = tool_dict['cache'] = {}
+ for i in range( len( group_state ) ):
+ group_cache[i] = {}
+ iterate( group_cache[i], input.inputs, group_state[i], other_values )
+ elif input.type == 'conditional':
+ if 'test_param' in tool_dict:
+ test_param = tool_dict['test_param']
+ test_param['value'] = jsonify(group_state[test_param['name']])
+ if '__current_case__' in group_state:
+ i = group_state['__current_case__']
+ iterate(tool_dict['cases'][i]['inputs'], input.cases[i].inputs, group_state, other_values)
+ else:
+ # create input dictionary, try to pass other_values if to_dict function supports it e.g. dynamic options
+ try:
+ tool_dict = input.to_dict(trans, other_values=other_values)
+ except Exception:
+ pass
+
+ # identify name
+ input_name = tool_dict.get('name')
+ if input_name:
+ # update input value from tool state
+ if input_name in state_inputs:
+ tool_dict['value'] = state_inputs[input_name]
+
+ # sanitize if value exists
+ tool_dict = sanitize(tool_dict)
+
+ # backup final input dictionary
+ group_inputs[input_index] = tool_dict
+
+ # sanatization for the final tool state
+ def sanitize_state(state):
+ keys = None
+ if isinstance(state, dict):
+ keys = state
+ elif isinstance(state, list):
+ keys = range( len(state) )
+ if keys:
+ for k in keys:
+ if isinstance(state[k], dict) or isinstance(state[k], list):
+ sanitize_state(state[k])
+ else:
+ state[k] = jsonify(state[k])
+
+ # do param translation here, used by datasource tools
+ if self.input_translator:
+ self.input_translator.translate( params )
+
+ # initialize and populate tool state
+ state_inputs = {}
+ state_errors = {}
+ initialize_state(trans, self.inputs, state_inputs)
+ populate_state(trans, self.inputs, state_inputs, state_errors, params.__dict__)
+
+ # create basic tool model
+ tool_model = self.to_dict(trans)
+ tool_model['inputs'] = {}
+
+ # build tool model and tool state
+ iterate(tool_model['inputs'], self.inputs, state_inputs, '')
+
+ # sanitize tool state
+ sanitize_state(state_inputs)
+
+ # load tool help
+ tool_help = ''
+ if self.help:
+ tool_help = self.help
+ tool_help = tool_help.render( static_path=url_for( '/static' ), host_url=url_for('/', qualified=True) )
+ if type( tool_help ) is not unicode:
+ tool_help = unicode( tool_help, 'utf-8')
+
+ # check if citations exist
+ tool_citations = False
+ if self.citations:
+ tool_citations = True
+
+ # get tool versions
+ tool_versions = []
+ tools = self.app.toolbox.get_loaded_tools_by_lineage(self.id)
+ for t in tools:
+ tool_versions.append(t.version)
+
+ ## add information with underlying requirements and their versions
+ tool_requirements = []
+ if self.requirements:
+ for requirement in self.requirements:
+ tool_requirements.append({
+ 'name' : requirement.name,
+ 'version' : requirement.version
+ })
+
+ # add additional properties
+ tool_model.update({
+ 'help' : tool_help,
+ 'citations' : tool_citations,
+ 'biostar_url' : trans.app.config.biostar_url,
+ 'message' : tool_message,
+ 'versions' : tool_versions,
+ 'requirements' : tool_requirements,
+ 'errors' : state_errors,
+ 'state_inputs' : state_inputs
+ })
+
+ # check for errors
+ if 'error' in tool_message:
+ return tool_message
+
+ # return enriched tool model
+ return tool_model
+
+ def _compare_tool_version( self, trans, job ):
+ """
+ Compares a tool version with the tool version from a job (from ToolRunner).
+ """
+ tool_id = job.tool_id
+ tool_version = job.tool_version
+ message = ''
+ try:
+ select_field, tools, tool = self.app.toolbox.get_tool_components( tool_id, tool_version=tool_version, get_loaded_tools_by_lineage=False, set_selected=True )
+ if tool is None:
+ trans.response.status = 500
+ return { 'error': 'This dataset was created by an obsolete tool (%s). Can\'t re-run.' % tool_id }
+ if ( self.id != tool_id and self.old_id != tool_id ) or self.version != tool_version:
+ if self.id == tool_id:
+ if tool_version == None:
+ # for some reason jobs don't always keep track of the tool version.
+ message = ''
+ else:
+ message = 'This job was initially run with tool version "%s", which is currently not available. ' % tool_version
+ if len( tools ) > 1:
+ message += 'You can re-run the job with the selected tool or choose another derivation of the tool.'
+ else:
+ message += 'You can re-run the job with this tool version, which is a derivation of the original tool.'
+ else:
+ if len( tools ) > 1:
+ message = 'This job was initially run with tool version "%s", which is currently not available. ' % tool_version
+ message += 'You can re-run the job with the selected tool or choose another derivation of the tool.'
+ else:
+ message = 'This job was initially run with tool id "%s", version "%s", which is ' % ( tool_id, tool_version )
+ message += 'currently not available. You can re-run the job with this tool, which is a derivation of the original tool.'
+ except Exception, error:
+ trans.response.status = 500
+ return { 'error': str (error) }
+
+ # can't rerun upload, external data sources, et cetera. workflow compatible will proxy this for now
+ #if not self.is_workflow_compatible:
+ # trans.response.status = 500
+ # return { 'error': 'The \'%s\' tool does currently not support re-running.' % self.name }
+ return message
+
def get_default_history_by_trans( self, trans, create=False ):
return trans.get_history( create=create )
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 lib/galaxy/tools/deps/brew_exts.py
--- a/lib/galaxy/tools/deps/brew_exts.py
+++ b/lib/galaxy/tools/deps/brew_exts.py
@@ -28,6 +28,7 @@
import os
import re
import sys
+import string
import subprocess
WHITESPACE_PATTERN = re.compile("[\s]+")
@@ -43,6 +44,7 @@
CANNOT_DETERMINE_TAP_ERROR_MESSAGE = "Cannot determine tap of specified recipe - please use fully qualified recipe (e.g. homebrew/science/samtools)."
VERBOSE = False
RELAXED = False
+BREW_ARGS = []
class BrewContext(object):
@@ -104,6 +106,7 @@
def main():
global VERBOSE
global RELAXED
+ global BREW_ARGS
parser = argparse.ArgumentParser(description=DESCRIPTION)
parser.add_argument("--brew", help="Path to linuxbrew 'brew' executable to target")
actions = ["vinstall", "vuninstall", "vdeps", "vinfo", "env"]
@@ -114,11 +117,13 @@
parser.add_argument('version', metavar='version', help="Version for action (e.g. 0.1.19).")
parser.add_argument('--relaxed', action='store_true', help="Relaxed processing - for instance allow use of env on non-vinstall-ed recipes.")
parser.add_argument('--verbose', action='store_true', help="Verbose output")
+ parser.add_argument('restargs', nargs=argparse.REMAINDER)
args = parser.parse_args()
if args.verbose:
VERBOSE = True
if args.relaxed:
RELAXED = True
+ BREW_ARGS = args.restargs
if not action:
action = args.action
brew_context = BrewContext(args)
@@ -159,7 +164,7 @@
return self.message
-def versioned_install(recipe_context, package=None, version=None):
+def versioned_install(recipe_context, package=None, version=None, installed_deps=[]):
if package is None:
package = recipe_context.recipe
version = recipe_context.version
@@ -176,10 +181,15 @@
versioned = version_info[2]
if versioned:
dep_to_version[dep] = dep_version
+ if dep in installed_deps:
+ continue
versioned_install(recipe_context, dep, dep_version)
+ installed_deps.append(dep)
else:
# Install latest.
dep_to_version[dep] = None
+ if dep in installed_deps:
+ continue
unversioned_install(dep)
try:
for dep in deps:
@@ -198,7 +208,16 @@
}
deps_metadata.append(dep_metadata)
- brew_execute(["install", package])
+ cellar_root = recipe_context.brew_context.homebrew_cellar
+ cellar_path = recipe_context.cellar_path
+ env_actions = build_env_actions(deps_metadata, cellar_root, cellar_path, custom_only=True)
+ env = EnvAction.build_env(env_actions)
+ args = ["install"]
+ if VERBOSE:
+ args.append("--verbose")
+ args.extend(BREW_ARGS)
+ args.append(package)
+ brew_execute(args, env=env)
deps = brew_execute(["deps", package])
deps = [d.strip() for d in deps.split("\n") if d]
metadata = {
@@ -278,10 +297,10 @@
pass
-def brew_execute(args):
+def brew_execute(args, env=None):
os.environ["HOMEBREW_NO_EMOJI"] = "1" # simplify brew parsing.
cmds = ["brew"] + args
- return execute(cmds)
+ return execute(cmds, env=env)
def build_env_statements_from_recipe_context(recipe_context, **kwds):
@@ -290,11 +309,20 @@
return env_statements
-def build_env_statements(cellar_root, cellar_path, relaxed=None):
+def build_env_statements(cellar_root, cellar_path, relaxed=None, custom_only=False):
deps = load_versioned_deps(cellar_path, relaxed=relaxed)
+ actions = build_env_actions(deps, cellar_root, cellar_path, relaxed, custom_only)
+ env_statements = []
+ for action in actions:
+ env_statements.extend(action.to_statements())
+ return "\n".join(env_statements)
+
+
+def build_env_actions(deps, cellar_root, cellar_path, relaxed=None, custom_only=False):
path_appends = []
ld_path_appends = []
+ actions = []
def handle_keg(cellar_path):
bin_path = os.path.join(cellar_path, "bin")
@@ -303,6 +331,14 @@
lib_path = os.path.join(cellar_path, "lib")
if os.path.isdir(lib_path):
ld_path_appends.append(lib_path)
+ env_path = os.path.join(cellar_path, "platform_environment.json")
+ if os.path.exists(env_path):
+ with open(env_path, "r") as f:
+ env_metadata = json.load(f)
+ if "actions" in env_metadata:
+ def to_action(desc):
+ return EnvAction(cellar_path, desc)
+ actions.extend(map(to_action, env_metadata["actions"]))
for dep in deps:
package = dep['name']
@@ -311,14 +347,54 @@
handle_keg( dep_cellar_path )
handle_keg( cellar_path )
- env_statements = []
- if path_appends:
- env_statements.append("PATH=" + ":".join(path_appends) + ":$PATH")
- env_statements.append("export PATH")
- if ld_path_appends:
- env_statements.append("LD_LIBRARY_PATH=" + ":".join(ld_path_appends) + ":$LD_LIBRARY_PATH")
- env_statements.append("export LD_LIBRARY_PATH")
- return "\n".join(env_statements)
+ if not custom_only:
+ if path_appends:
+ actions.append(EnvAction(cellar_path, {"action": "prepend", "variable": "PATH", "value": ":".join(path_appends)}))
+ if ld_path_appends:
+ actions.append(EnvAction(cellar_path, {"action": "prepend", "variable": "LD_LIBRARY_PATH", "value": ":".join(path_appends)}))
+ return actions
+
+
+class EnvAction(object):
+
+ def __init__(self, keg_root, action_description):
+ self.variable = action_description["variable"]
+ self.action = action_description["action"]
+ self.value = string.Template(action_description["value"]).safe_substitute({
+ 'KEG_ROOT': keg_root,
+ })
+
+ @staticmethod
+ def build_env(env_actions):
+ new_env = os.environ.copy()
+ map(lambda env_action: env_action.modify_environ(new_env), env_actions)
+ return new_env
+
+ def modify_environ(self, environ):
+ if self.action == "set" or not environ.get(self.variable, ""):
+ environ[self.variable] = self.__eval("${value}")
+ elif self.action == "prepend":
+ environ[self.variable] = self.__eval("${value}:%s" % environ[self.variable])
+ else:
+ environ[self.variable] = self.__eval("%s:${value}" % environ[self.variable])
+
+ def __eval(self, template):
+ return string.Template(template).safe_substitute(
+ variable=self.variable,
+ value=self.value,
+ )
+
+ def to_statements(self):
+ if self.action == "set":
+ template = '''${variable}="${value}"'''
+ elif self.action == "prepend":
+ template = '''${variable}="${value}:$$${variable}"'''
+ else:
+ template = '''${variable}="$$${variable}:${value}"'''
+ return [
+ self.__eval(template),
+ "export %s" % self.variable
+ ]
@contextlib.contextmanager
@@ -350,8 +426,15 @@
return execute(cmds)
-def execute(cmds):
- p = subprocess.Popen(cmds, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+def execute(cmds, env=None):
+ subprocess_kwds = dict(
+ shell=False,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ if env:
+ subprocess_kwds["env"] = env
+ p = subprocess.Popen(cmds, **subprocess_kwds)
#log = p.stdout.read()
global VERBOSE
stdout, stderr = p.communicate()
@@ -363,7 +446,10 @@
def brew_deps(package):
- stdout = brew_execute(["deps", package])
+ args = ["deps"]
+ args.extend(BREW_ARGS)
+ args.append(package)
+ stdout = brew_execute(args)
return [p.strip() for p in stdout.split("\n") if p]
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 lib/galaxy/tools/deps/resolvers/brewed_tool_shed_packages.py
--- /dev/null
+++ b/lib/galaxy/tools/deps/resolvers/brewed_tool_shed_packages.py
@@ -0,0 +1,150 @@
+"""
+This dependency resolver resolves tool shed dependencies (those defined
+tool_dependencies.xml) installed using Platform Homebrew and converted
+via shed2tap (e.g. https://github.com/jmchilton/homebrew-toolshed)
+"""
+import logging
+import os
+from xml.etree import ElementTree as ET
+
+from .resolver_mixins import (
+ UsesHomebrewMixin,
+ UsesToolDependencyDirMixin,
+ UsesInstalledRepositoriesMixin,
+)
+from ..resolvers import DependencyResolver, INDETERMINATE_DEPENDENCY
+
+log = logging.getLogger(__name__)
+
+
+class HomebrewToolShedDependencyResolver(
+ DependencyResolver,
+ UsesHomebrewMixin,
+ UsesToolDependencyDirMixin,
+ UsesInstalledRepositoriesMixin,
+):
+ resolver_type = "tool_shed_tap"
+
+ def __init__(self, dependency_manager, **kwds):
+ self._init_homebrew(**kwds)
+ self._init_base_path(dependency_manager, **kwds)
+
+ def resolve(self, name, version, type, **kwds):
+ if type != "package":
+ return INDETERMINATE_DEPENDENCY
+
+ if version is None:
+ return INDETERMINATE_DEPENDENCY
+
+ return self._find_tool_dependencies(name, version, type, **kwds)
+
+ def _find_tool_dependencies(self, name, version, type, **kwds):
+ installed_tool_dependency = self._get_installed_dependency(name, type, version=version, **kwds)
+ if installed_tool_dependency:
+ return self._resolve_from_installed_tool_dependency(name, version, installed_tool_dependency)
+
+ if "tool_dir" in kwds:
+ tool_directory = os.path.abspath(kwds["tool_dir"])
+ tool_depenedencies_path = os.path.join(tool_directory, "tool_dependencies.xml")
+ if os.path.exists(tool_depenedencies_path):
+ return self._resolve_from_tool_dependencies_path(name, version, tool_depenedencies_path)
+
+ return INDETERMINATE_DEPENDENCY
+
+ def _resolve_from_installed_tool_dependency(self, name, version, installed_tool_dependency):
+ tool_shed_repository = installed_tool_dependency.tool_shed_repository
+ recipe_name = build_recipe_name(
+ package_name=name,
+ package_version=version,
+ repository_owner=tool_shed_repository.owner,
+ repository_name=tool_shed_repository.name,
+ )
+ return self._find_dep_default(recipe_name, None)
+
+ def _resolve_from_tool_dependencies_path(self, name, version, tool_dependencies_path):
+ try:
+ raw_dependencies = RawDependencies(tool_dependencies_path)
+ except Exception:
+ log.debug("Failed to parse dependencies in file %s" % tool_dependencies_path)
+ return INDETERMINATE_DEPENDENCY
+
+ raw_dependency = raw_dependencies.find(name, version)
+ if not raw_dependency:
+ return INDETERMINATE_DEPENDENCY
+
+ recipe_name = build_recipe_name(
+ package_name=name,
+ package_version=version,
+ repository_owner=raw_dependency.repository_owner,
+ repository_name=raw_dependency.repository_name
+ )
+ dep = self._find_dep_default(recipe_name, None)
+ return dep
+
+
+class RawDependencies(object):
+
+ def __init__(self, dependencies_file):
+ self.root = ET.parse(dependencies_file).getroot()
+ dependencies = []
+ package_els = self.root.findall("package") or []
+ for package_el in package_els:
+ repository_el = package_el.find("repository")
+ if repository_el is None:
+ continue
+ dependency = RawDependency(self, package_el, repository_el)
+ dependencies.append(dependency)
+ self.dependencies = dependencies
+
+ def find(self, package_name, package_version):
+ target_dependency = None
+
+ for dependency in self.dependencies:
+ if dependency.package_name == package_name and dependency.package_version == package_version:
+ target_dependency = dependency
+ break
+ return target_dependency
+
+
+class RawDependency(object):
+
+ def __init__(self, dependencies, package_el, repository_el):
+ self.dependencies = dependencies
+ self.package_el = package_el
+ self.repository_el = repository_el
+
+ def __repr__(self):
+ temp = "Dependency[package_name=%s,version=%s,dependent_package=%s]"
+ return temp % (
+ self.package_el.attrib["name"],
+ self.package_el.attrib["version"],
+ self.repository_el.attrib["name"]
+ )
+
+ @property
+ def repository_owner(self):
+ return self.repository_el.attrib["owner"]
+
+ @property
+ def repository_name(self):
+ return self.repository_el.attrib["name"]
+
+ @property
+ def package_name(self):
+ return self.package_el.attrib["name"]
+
+ @property
+ def package_version(self):
+ return self.package_el.attrib["version"]
+
+
+def build_recipe_name(package_name, package_version, repository_owner, repository_name):
+ # TODO: Consider baking package_name and package_version into name? (would be more "correct")
+ owner = repository_owner.replace("-", "")
+ name = repository_name
+ name = name.replace("_", "").replace("-", "")
+ base = "%s_%s" % (owner, name)
+ return base
+
+
+__all__ = [HomebrewToolShedDependencyResolver]
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 lib/galaxy/tools/deps/resolvers/galaxy_packages.py
--- a/lib/galaxy/tools/deps/resolvers/galaxy_packages.py
+++ b/lib/galaxy/tools/deps/resolvers/galaxy_packages.py
@@ -1,12 +1,13 @@
-from os.path import join, islink, realpath, basename, exists, abspath
+from os.path import join, islink, realpath, basename, exists
from ..resolvers import DependencyResolver, INDETERMINATE_DEPENDENCY, Dependency
+from .resolver_mixins import UsesToolDependencyDirMixin
import logging
log = logging.getLogger( __name__ )
-class GalaxyPackageDependencyResolver(DependencyResolver):
+class GalaxyPackageDependencyResolver(DependencyResolver, UsesToolDependencyDirMixin):
resolver_type = "galaxy_packages"
def __init__(self, dependency_manager, **kwds):
@@ -16,7 +17,7 @@
## resolver that will just grab 'default' version of exact version
## unavailable.
self.versionless = str(kwds.get('versionless', "false")).lower() == "true"
- self.base_path = abspath( kwds.get('base_path', dependency_manager.default_base_path) )
+ self._init_base_path( dependency_manager, **kwds )
def resolve( self, name, version, type, **kwds ):
"""
diff -r 23fddbbd5153ba3d6c8bbbbd33fcb5aa9225f35e -r 85e8fb54b2851454a000cab23d57ce102af6aa30 lib/galaxy/tools/deps/resolvers/homebrew.py
--- a/lib/galaxy/tools/deps/resolvers/homebrew.py
+++ b/lib/galaxy/tools/deps/resolvers/homebrew.py
@@ -12,20 +12,19 @@
incompatible changes coming.
"""
-import os
-from ..brew_exts import DEFAULT_HOMEBREW_ROOT, recipe_cellar_path, build_env_statements
-from ..resolvers import DependencyResolver, INDETERMINATE_DEPENDENCY, Dependency
+from .resolver_mixins import UsesHomebrewMixin
+from ..resolvers import DependencyResolver, INDETERMINATE_DEPENDENCY
# TODO: Implement prefer version linked...
PREFER_VERSION_LINKED = 'linked'
PREFER_VERSION_LATEST = 'latest'
-UNKNOWN_PREFER_VERSION_MESSAGE_TEMPLATE = "HomebrewDependencyResolver prefer_version must be latest %s"
+UNKNOWN_PREFER_VERSION_MESSAGE_TEMPLATE = "HomebrewDependencyResolver prefer_version must be %s"
UNKNOWN_PREFER_VERSION_MESSAGE = UNKNOWN_PREFER_VERSION_MESSAGE_TEMPLATE % (PREFER_VERSION_LATEST)
DEFAULT_PREFER_VERSION = PREFER_VERSION_LATEST
-class HomebrewDependencyResolver(DependencyResolver):
+class HomebrewDependencyResolver(DependencyResolver, UsesHomebrewMixin):
resolver_type = "homebrew"
def __init__(self, dependency_manager, **kwds):
@@ -38,11 +37,7 @@
if self.versionless and self.prefer_version not in [PREFER_VERSION_LATEST]:
raise Exception(UNKNOWN_PREFER_VERSION_MESSAGE)
- cellar_root = kwds.get('cellar', None)
- if cellar_root is None:
- cellar_root = os.path.join(DEFAULT_HOMEBREW_ROOT, "Cellar")
-
- self.cellar_root = cellar_root
+ self._init_homebrew(**kwds)
def resolve(self, name, version, type, **kwds):
if type != "package":
@@ -53,41 +48,6 @@
else:
return self._find_dep_versioned(name, version)
- def _find_dep_versioned(self, name, version):
- recipe_path = recipe_cellar_path(self.cellar_root, name, version)
- if not os.path.exists(recipe_path) or not os.path.isdir(recipe_path):
- return INDETERMINATE_DEPENDENCY
-
- commands = build_env_statements(self.cellar_root, recipe_path, relaxed=True)
- return HomebrewDependency(commands)
-
- def _find_dep_default(self, name, version):
- installed_versions = self._installed_versions(name)
- if not installed_versions:
- return INDETERMINATE_DEPENDENCY
-
- # Just grab newest installed version - may make sense some day to find
- # the linked version instead.
- default_version = sorted(installed_versions, reverse=True)[0]
- return self._find_dep_versioned(name, default_version)
-
- def _installed_versions(self, recipe):
- recipe_base_path = os.path.join(self.cellar_root, recipe)
- if not os.path.exists(recipe_base_path):
- return []
-
- names = os.listdir(recipe_base_path)
- return filter(lambda n: os.path.isdir(os.path.join(recipe_base_path, n)), names)
-
-
-class HomebrewDependency(Dependency):
-
- def __init__(self, commands):
- self.commands = commands
-
- def shell_commands(self, requirement):
- return self.commands.replace("\n", ";") + "\n"
-
def _string_as_bool( value ):
return str( value ).lower() == "true"
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Merged in nsoranzo/galaxy-central (pull request #628)
by commits-noreply@bitbucket.org 12 Jan '15
by commits-noreply@bitbucket.org 12 Jan '15
12 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d3dff45bbb05/
Changeset: d3dff45bbb05
User: dannon
Date: 2015-01-12 12:02:23+00:00
Summary: Merged in nsoranzo/galaxy-central (pull request #628)
PEP-8 fixes and API doc ehnancements to libraries API
Affected #: 2 files
diff -r eb61b02da1866c4a7da0f2fa357ce43e6c62b57c -r d3dff45bbb0554150da4491eb2d2031d11f90063 lib/galaxy/webapps/galaxy/api/libraries.py
--- a/lib/galaxy/webapps/galaxy/api/libraries.py
+++ b/lib/galaxy/webapps/galaxy/api/libraries.py
@@ -6,10 +6,7 @@
from galaxy.managers import libraries, folders, roles
from galaxy.web import _future_expose_api as expose_api
from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous
-from galaxy.model.orm import and_, not_, or_
from galaxy.web.base.controller import BaseAPIController
-from sqlalchemy.orm.exc import MultipleResultsFound
-from sqlalchemy.orm.exc import NoResultFound
import logging
log = logging.getLogger( __name__ )
@@ -48,7 +45,7 @@
def __decode_id( self, trans, encoded_id, object_name=None ):
"""
- Try to decode the id.
+ Try to decode the id.
:param object_name: Name of the object the id belongs to. (optional)
:type object_name: str
@@ -149,7 +146,7 @@
synopsis = payload.get( 'synopsis', None )
else:
raise exceptions.RequestParameterMissingException( "You did not specify any payload." )
- updated_library = self.library_manager.update( trans, library, name, description, synopsis )
+ updated_library = self.library_manager.update( trans, library, name, description, synopsis )
library_dict = self.library_manager.get_library_dict( trans, updated_library )
return library_dict
@@ -248,20 +245,20 @@
*POST /api/libraries/{encoded_library_id}/permissions
:param encoded_library_id: the encoded id of the library to set the permissions of
- :type encoded_library_id: an encoded id string
+ :type encoded_library_id: an encoded id string
:param action: (required) describes what action should be performed
available actions: remove_restrictions, set_permissions
- :type action: string
+ :type action: string
:param access_ids[]: list of Role.id defining roles that should have access permission on the library
- :type access_ids[]: string or list
+ :type access_ids[]: string or list
:param add_ids[]: list of Role.id defining roles that should have add item permission on the library
- :type add_ids[]: string or list
+ :type add_ids[]: string or list
:param manage_ids[]: list of Role.id defining roles that should have manage permission on the library
- :type manage_ids[]: string or list
+ :type manage_ids[]: string or list
:param modify_ids[]: list of Role.id defining roles that should have modify permission on the library
- :type modify_ids[]: string or list
+ :type modify_ids[]: string or list
:rtype: dictionary
:returns: dict of current roles for all available permission types
@@ -306,7 +303,7 @@
else:
invalid_access_roles_names.append( role_id )
if len( invalid_access_roles_names ) > 0:
- log.warning( "The following roles could not be added to the library access permission: " + str( invalid_access_roles_names ) )
+ log.warning( "The following roles could not be added to the library access permission: " + str( invalid_access_roles_names ) )
# ADD TO LIBRARY ROLES
valid_add_roles = []
@@ -319,8 +316,8 @@
else:
invalid_add_roles_names.append( role_id )
if len( invalid_add_roles_names ) > 0:
- log.warning( "The following roles could not be added to the add library item permission: " + str( invalid_add_roles_names ) )
-
+ log.warning( "The following roles could not be added to the add library item permission: " + str( invalid_add_roles_names ) )
+
# MANAGE LIBRARY ROLES
valid_manage_roles = []
invalid_manage_roles_names = []
@@ -332,8 +329,8 @@
else:
invalid_manage_roles_names.append( role_id )
if len( invalid_manage_roles_names ) > 0:
- log.warning( "The following roles could not be added to the manage library permission: " + str( invalid_manage_roles_names ) )
-
+ log.warning( "The following roles could not be added to the manage library permission: " + str( invalid_manage_roles_names ) )
+
# MODIFY LIBRARY ROLES
valid_modify_roles = []
invalid_modify_roles_names = []
@@ -345,7 +342,7 @@
else:
invalid_modify_roles_names.append( role_id )
if len( invalid_modify_roles_names ) > 0:
- log.warning( "The following roles could not be added to the modify library permission: " + str( invalid_modify_roles_names ) )
+ log.warning( "The following roles could not be added to the modify library permission: " + str( invalid_modify_roles_names ) )
permissions = { trans.app.security_agent.permitted_actions.LIBRARY_ACCESS : valid_access_roles }
permissions.update( { trans.app.security_agent.permitted_actions.LIBRARY_ADD : valid_add_roles } )
@@ -357,7 +354,7 @@
# Copy the permissions to the root folder
trans.app.security_agent.copy_library_permissions( trans, library, library.root_folder )
else:
- raise exceptions.RequestParameterInvalidException( 'The mandatory parameter "action" has an invalid value.'
+ raise exceptions.RequestParameterInvalidException( 'The mandatory parameter "action" has an invalid value.'
'Allowed values are: "remove_restrictions", set_permissions"' )
roles = self.library_manager.get_current_roles( trans, library )
return roles
@@ -369,18 +366,16 @@
POST /api/libraries/{encoded_library_id}/permissions
Updates the library permissions.
"""
- import galaxy.util
- params = galaxy.util.Params( payload )
+ params = util.Params( payload )
permissions = {}
for k, v in trans.app.model.Library.permitted_actions.items():
role_params = params.get( k + '_in', [] )
- in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( trans.security.decode_id( x ) ) for x in galaxy.util.listify( role_params ) ]
+ in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( trans.security.decode_id( x ) ) for x in util.listify( role_params ) ]
permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
trans.app.security_agent.set_all_library_permissions( trans, library, permissions )
trans.sa_session.refresh( library )
# Copy the permissions to the root folder
trans.app.security_agent.copy_library_permissions( trans, library, library.root_folder )
- message = "Permissions updated for library '%s'." % library.name
item = library.to_dict( view='element', value_mapper={ 'id' : trans.security.encode_id , 'root_folder_id' : trans.security.encode_id } )
return item
diff -r eb61b02da1866c4a7da0f2fa357ce43e6c62b57c -r d3dff45bbb0554150da4491eb2d2031d11f90063 lib/galaxy/webapps/galaxy/api/library_contents.py
--- a/lib/galaxy/webapps/galaxy/api/library_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/library_contents.py
@@ -29,12 +29,12 @@
.. note:: May be slow! Returns all content traversing recursively through all folders.
.. seealso:: :class:`galaxy.webapps.galaxy.api.FolderContentsController.index` for a non-recursive solution
- :param library_id: encoded id string of the library
- :type library_id: string
+ :param library_id: the encoded id of the library
+ :type library_id: str
:returns: list of dictionaries of the form:
* id: the encoded id of the library item
- * name: the 'libary path'
+ * name: the 'library path'
or relationship of the library item to the root
* type: 'file' or 'folder'
* url: the url to get detailed information on the library item
@@ -109,7 +109,7 @@
:param id: the encoded id of the library item to return
:type id: str
- :param library_id: encoded id string of the library that contains this item
+ :param library_id: the encoded id of the library that contains this item
:type library_id: str
:returns: detailed library item information
@@ -119,7 +119,7 @@
:func:`galaxy.model.LibraryDataset.to_dict` and
:attr:`galaxy.model.LibraryFolder.dict_element_visible_keys`
"""
- class_name, content_id = self.__decode_library_content_id( trans, id )
+ class_name, content_id = self.__decode_library_content_id( id )
if class_name == 'LibraryFolder':
content = self.get_library_folder( trans, content_id, check_ownership=False, check_accessible=True )
rval = content.to_dict( view='element', value_mapper={ 'id': trans.security.encode_id } )
@@ -146,27 +146,39 @@
the HDA's encoded id in ``from_hda_id`` (and optionally ``ldda_message``).
:type library_id: str
- :param library_id: encoded id string of the library where to create the new item
+ :param library_id: the encoded id of the library where to create the new item
:type payload: dict
:param payload: dictionary structure containing:
- * folder_id: the parent folder of the new item
+ * folder_id: the encoded id of the parent folder of the new item
* create_type: the type of item to create ('file', 'folder' or 'collection')
- * from_hda_id: (optional) the id of an accessible HDA to copy into the
- library
+ * from_hda_id: (optional, only if create_type is 'file') the
+ encoded id of an accessible HDA to copy into the library
* ldda_message: (optional) the new message attribute of the LDDA created
* extended_metadata: (optional) dub-dictionary containing any extended
metadata to associate with the item
- * link_data_only: (optional) either 'copy_files' (default) or 'link_to_files'
* upload_option: (optional) one of 'upload_file' (default), 'upload_directory' or 'upload_paths'
- * server_dir: (optional) only if upload_option is 'upload_directory'
- * filesystem_paths: (optional) only if upload_option is 'upload_paths' and the user is an admin
+ * server_dir: (optional, only if upload_option is
+ 'upload_directory') relative path of the subdirectory of Galaxy
+ ``library_import_dir`` to upload. All and only the files (i.e.
+ no subdirectories) contained in the specified directory will be
+ uploaded.
+ * filesystem_paths: (optional, only if upload_option is
+ 'upload_paths' and the user is an admin) file paths on the
+ Galaxy server to upload to the library, one file per line
+ * link_data_only: (optional, only when upload_option is
+ 'upload_directory' or 'upload_paths') either 'copy_files'
+ (default) or 'link_to_files'. Setting to 'link_to_files'
+ symlinks instead of copying the files
+ * name: (optional, only if create_type is 'folder') name of the
+ folder to create
+ * description: (optional, only if create_type is 'folder')
+ description of the folder to create
:rtype: dict
:returns: a dictionary containing the id, name,
and 'show' url of the new item
"""
- create_type = None
if 'create_type' not in payload:
trans.response.status = 400
return "Missing required 'create_type' parameter."
@@ -178,10 +190,10 @@
if 'folder_id' not in payload:
trans.response.status = 400
- return "Missing requred 'folder_id' parameter."
+ return "Missing required 'folder_id' parameter."
else:
folder_id = payload.pop( 'folder_id' )
- class_name, folder_id = self.__decode_library_content_id( trans, folder_id )
+ class_name, folder_id = self.__decode_library_content_id( folder_id )
try:
# security is checked in the downstream controller
parent = self.get_library_folder( trans, folder_id, check_ownership=False, check_accessible=False )
@@ -198,9 +210,7 @@
#check for extended metadata, store it and pop it out of the param
#otherwise sanitize_param will have a fit
- ex_meta_payload = None
- if 'extended_metadata' in payload:
- ex_meta_payload = payload.pop('extended_metadata')
+ ex_meta_payload = payload.pop('extended_metadata', None)
# Now create the desired content object, either file or folder.
if create_type == 'file':
@@ -272,7 +282,7 @@
def _copy_hda_to_library_folder( self, trans, from_hda_id, library_id, folder_id, ldda_message='' ):
"""
- Copies hda ``from_hda_id`` to library folder ``library_folder_id`` optionally
+ Copies hda ``from_hda_id`` to library folder ``folder_id``, optionally
adding ``ldda_message`` to the new ldda's ``message``.
``library_contents.create`` will branch to this if called with 'from_hda_id'
@@ -325,7 +335,7 @@
:type id: str
:param id: the encoded id of the library item to return
:type library_id: str
- :param library_id: encoded id string of the library that contains this item
+ :param library_id: the encoded id of the library that contains this item
:type payload: dict
:param payload: dictionary structure containing::
'converted_dataset_id':
@@ -344,7 +354,7 @@
trans.sa_session.add( assoc )
trans.sa_session.flush()
- def __decode_library_content_id( self, trans, content_id ):
+ def __decode_library_content_id( self, content_id ):
if len( content_id ) % 16 == 0:
return 'LibraryDataset', content_id
elif content_id.startswith( 'F' ):
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/841deccfb359/
Changeset: 841deccfb359
User: nsoranzo
Date: 2015-01-08 13:00:50+00:00
Summary: PEP-8 and style fixes.
Affected #: 2 files
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r 841deccfb359c7722eeeb6f5101caa4b5925fb6e lib/galaxy/webapps/galaxy/api/libraries.py
--- a/lib/galaxy/webapps/galaxy/api/libraries.py
+++ b/lib/galaxy/webapps/galaxy/api/libraries.py
@@ -6,10 +6,7 @@
from galaxy.managers import libraries, folders, roles
from galaxy.web import _future_expose_api as expose_api
from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous
-from galaxy.model.orm import and_, not_, or_
from galaxy.web.base.controller import BaseAPIController
-from sqlalchemy.orm.exc import MultipleResultsFound
-from sqlalchemy.orm.exc import NoResultFound
import logging
log = logging.getLogger( __name__ )
@@ -48,7 +45,7 @@
def __decode_id( self, trans, encoded_id, object_name=None ):
"""
- Try to decode the id.
+ Try to decode the id.
:param object_name: Name of the object the id belongs to. (optional)
:type object_name: str
@@ -149,7 +146,7 @@
synopsis = payload.get( 'synopsis', None )
else:
raise exceptions.RequestParameterMissingException( "You did not specify any payload." )
- updated_library = self.library_manager.update( trans, library, name, description, synopsis )
+ updated_library = self.library_manager.update( trans, library, name, description, synopsis )
library_dict = self.library_manager.get_library_dict( trans, updated_library )
return library_dict
@@ -248,20 +245,20 @@
*POST /api/libraries/{encoded_library_id}/permissions
:param encoded_library_id: the encoded id of the library to set the permissions of
- :type encoded_library_id: an encoded id string
+ :type encoded_library_id: an encoded id string
:param action: (required) describes what action should be performed
available actions: remove_restrictions, set_permissions
- :type action: string
+ :type action: string
:param access_ids[]: list of Role.id defining roles that should have access permission on the library
- :type access_ids[]: string or list
+ :type access_ids[]: string or list
:param add_ids[]: list of Role.id defining roles that should have add item permission on the library
- :type add_ids[]: string or list
+ :type add_ids[]: string or list
:param manage_ids[]: list of Role.id defining roles that should have manage permission on the library
- :type manage_ids[]: string or list
+ :type manage_ids[]: string or list
:param modify_ids[]: list of Role.id defining roles that should have modify permission on the library
- :type modify_ids[]: string or list
+ :type modify_ids[]: string or list
:rtype: dictionary
:returns: dict of current roles for all available permission types
@@ -306,7 +303,7 @@
else:
invalid_access_roles_names.append( role_id )
if len( invalid_access_roles_names ) > 0:
- log.warning( "The following roles could not be added to the library access permission: " + str( invalid_access_roles_names ) )
+ log.warning( "The following roles could not be added to the library access permission: " + str( invalid_access_roles_names ) )
# ADD TO LIBRARY ROLES
valid_add_roles = []
@@ -319,8 +316,8 @@
else:
invalid_add_roles_names.append( role_id )
if len( invalid_add_roles_names ) > 0:
- log.warning( "The following roles could not be added to the add library item permission: " + str( invalid_add_roles_names ) )
-
+ log.warning( "The following roles could not be added to the add library item permission: " + str( invalid_add_roles_names ) )
+
# MANAGE LIBRARY ROLES
valid_manage_roles = []
invalid_manage_roles_names = []
@@ -332,8 +329,8 @@
else:
invalid_manage_roles_names.append( role_id )
if len( invalid_manage_roles_names ) > 0:
- log.warning( "The following roles could not be added to the manage library permission: " + str( invalid_manage_roles_names ) )
-
+ log.warning( "The following roles could not be added to the manage library permission: " + str( invalid_manage_roles_names ) )
+
# MODIFY LIBRARY ROLES
valid_modify_roles = []
invalid_modify_roles_names = []
@@ -345,7 +342,7 @@
else:
invalid_modify_roles_names.append( role_id )
if len( invalid_modify_roles_names ) > 0:
- log.warning( "The following roles could not be added to the modify library permission: " + str( invalid_modify_roles_names ) )
+ log.warning( "The following roles could not be added to the modify library permission: " + str( invalid_modify_roles_names ) )
permissions = { trans.app.security_agent.permitted_actions.LIBRARY_ACCESS : valid_access_roles }
permissions.update( { trans.app.security_agent.permitted_actions.LIBRARY_ADD : valid_add_roles } )
@@ -357,7 +354,7 @@
# Copy the permissions to the root folder
trans.app.security_agent.copy_library_permissions( trans, library, library.root_folder )
else:
- raise exceptions.RequestParameterInvalidException( 'The mandatory parameter "action" has an invalid value.'
+ raise exceptions.RequestParameterInvalidException( 'The mandatory parameter "action" has an invalid value.'
'Allowed values are: "remove_restrictions", set_permissions"' )
roles = self.library_manager.get_current_roles( trans, library )
return roles
@@ -369,18 +366,16 @@
POST /api/libraries/{encoded_library_id}/permissions
Updates the library permissions.
"""
- import galaxy.util
- params = galaxy.util.Params( payload )
+ params = util.Params( payload )
permissions = {}
for k, v in trans.app.model.Library.permitted_actions.items():
role_params = params.get( k + '_in', [] )
- in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( trans.security.decode_id( x ) ) for x in galaxy.util.listify( role_params ) ]
+ in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( trans.security.decode_id( x ) ) for x in util.listify( role_params ) ]
permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
trans.app.security_agent.set_all_library_permissions( trans, library, permissions )
trans.sa_session.refresh( library )
# Copy the permissions to the root folder
trans.app.security_agent.copy_library_permissions( trans, library, library.root_folder )
- message = "Permissions updated for library '%s'." % library.name
item = library.to_dict( view='element', value_mapper={ 'id' : trans.security.encode_id , 'root_folder_id' : trans.security.encode_id } )
return item
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r 841deccfb359c7722eeeb6f5101caa4b5925fb6e lib/galaxy/webapps/galaxy/api/library_contents.py
--- a/lib/galaxy/webapps/galaxy/api/library_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/library_contents.py
@@ -119,7 +119,7 @@
:func:`galaxy.model.LibraryDataset.to_dict` and
:attr:`galaxy.model.LibraryFolder.dict_element_visible_keys`
"""
- class_name, content_id = self.__decode_library_content_id( trans, id )
+ class_name, content_id = self.__decode_library_content_id( id )
if class_name == 'LibraryFolder':
content = self.get_library_folder( trans, content_id, check_ownership=False, check_accessible=True )
rval = content.to_dict( view='element', value_mapper={ 'id': trans.security.encode_id } )
@@ -166,7 +166,6 @@
:returns: a dictionary containing the id, name,
and 'show' url of the new item
"""
- create_type = None
if 'create_type' not in payload:
trans.response.status = 400
return "Missing required 'create_type' parameter."
@@ -178,10 +177,10 @@
if 'folder_id' not in payload:
trans.response.status = 400
- return "Missing requred 'folder_id' parameter."
+ return "Missing required 'folder_id' parameter."
else:
folder_id = payload.pop( 'folder_id' )
- class_name, folder_id = self.__decode_library_content_id( trans, folder_id )
+ class_name, folder_id = self.__decode_library_content_id( folder_id )
try:
# security is checked in the downstream controller
parent = self.get_library_folder( trans, folder_id, check_ownership=False, check_accessible=False )
@@ -198,9 +197,7 @@
#check for extended metadata, store it and pop it out of the param
#otherwise sanitize_param will have a fit
- ex_meta_payload = None
- if 'extended_metadata' in payload:
- ex_meta_payload = payload.pop('extended_metadata')
+ ex_meta_payload = payload.pop('extended_metadata', None)
# Now create the desired content object, either file or folder.
if create_type == 'file':
@@ -344,7 +341,7 @@
trans.sa_session.add( assoc )
trans.sa_session.flush()
- def __decode_library_content_id( self, trans, content_id ):
+ def __decode_library_content_id( self, content_id ):
if len( content_id ) % 16 == 0:
return 'LibraryDataset', content_id
elif content_id.startswith( 'F' ):
https://bitbucket.org/galaxy/galaxy-central/commits/dbdc660f2a86/
Changeset: dbdc660f2a86
User: nsoranzo
Date: 2015-01-09 22:57:23+00:00
Summary: API doc enhancements.
Affected #: 1 file
diff -r 841deccfb359c7722eeeb6f5101caa4b5925fb6e -r dbdc660f2a86cfe46ac9518793b128196dfe9788 lib/galaxy/webapps/galaxy/api/library_contents.py
--- a/lib/galaxy/webapps/galaxy/api/library_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/library_contents.py
@@ -29,12 +29,12 @@
.. note:: May be slow! Returns all content traversing recursively through all folders.
.. seealso:: :class:`galaxy.webapps.galaxy.api.FolderContentsController.index` for a non-recursive solution
- :param library_id: encoded id string of the library
- :type library_id: string
+ :param library_id: the encoded id of the library
+ :type library_id: str
:returns: list of dictionaries of the form:
* id: the encoded id of the library item
- * name: the 'libary path'
+ * name: the 'library path'
or relationship of the library item to the root
* type: 'file' or 'folder'
* url: the url to get detailed information on the library item
@@ -109,7 +109,7 @@
:param id: the encoded id of the library item to return
:type id: str
- :param library_id: encoded id string of the library that contains this item
+ :param library_id: the encoded id of the library that contains this item
:type library_id: str
:returns: detailed library item information
@@ -146,21 +146,34 @@
the HDA's encoded id in ``from_hda_id`` (and optionally ``ldda_message``).
:type library_id: str
- :param library_id: encoded id string of the library where to create the new item
+ :param library_id: the encoded id of the library where to create the new item
:type payload: dict
:param payload: dictionary structure containing:
- * folder_id: the parent folder of the new item
+ * folder_id: the encoded id of the parent folder of the new item
* create_type: the type of item to create ('file', 'folder' or 'collection')
- * from_hda_id: (optional) the id of an accessible HDA to copy into the
- library
+ * from_hda_id: (optional, only if create_type is 'file') the
+ encoded id of an accessible HDA to copy into the library
* ldda_message: (optional) the new message attribute of the LDDA created
* extended_metadata: (optional) dub-dictionary containing any extended
metadata to associate with the item
- * link_data_only: (optional) either 'copy_files' (default) or 'link_to_files'
* upload_option: (optional) one of 'upload_file' (default), 'upload_directory' or 'upload_paths'
- * server_dir: (optional) only if upload_option is 'upload_directory'
- * filesystem_paths: (optional) only if upload_option is 'upload_paths' and the user is an admin
+ * server_dir: (optional, only if upload_option is
+ 'upload_directory') relative path of the subdirectory of Galaxy
+ ``library_import_dir`` to upload. All and only the files (i.e.
+ no subdirectories) contained in the specified directory will be
+ uploaded.
+ * filesystem_paths: (optional, only if upload_option is
+ 'upload_paths' and the user is an admin) file paths on the
+ Galaxy server to upload to the library, one file per line
+ * link_data_only: (optional, only when upload_option is
+ 'upload_directory' or 'upload_paths') either 'copy_files'
+ (default) or 'link_to_files'. Setting to 'link_to_files'
+ symlinks instead of copying the files
+ * name: (optional, only if create_type is 'folder') name of the
+ folder to create
+ * description: (optional, only if create_type is 'folder')
+ description of the folder to create
:rtype: dict
:returns: a dictionary containing the id, name,
@@ -269,7 +282,7 @@
def _copy_hda_to_library_folder( self, trans, from_hda_id, library_id, folder_id, ldda_message='' ):
"""
- Copies hda ``from_hda_id`` to library folder ``library_folder_id`` optionally
+ Copies hda ``from_hda_id`` to library folder ``folder_id``, optionally
adding ``ldda_message`` to the new ldda's ``message``.
``library_contents.create`` will branch to this if called with 'from_hda_id'
@@ -322,7 +335,7 @@
:type id: str
:param id: the encoded id of the library item to return
:type library_id: str
- :param library_id: encoded id string of the library that contains this item
+ :param library_id: the encoded id of the library that contains this item
:type payload: dict
:param payload: dictionary structure containing::
'converted_dataset_id':
https://bitbucket.org/galaxy/galaxy-central/commits/d3dff45bbb05/
Changeset: d3dff45bbb05
User: dannon
Date: 2015-01-12 12:02:23+00:00
Summary: Merged in nsoranzo/galaxy-central (pull request #628)
PEP-8 fixes and API doc ehnancements to libraries API
Affected #: 2 files
diff -r eb61b02da1866c4a7da0f2fa357ce43e6c62b57c -r d3dff45bbb0554150da4491eb2d2031d11f90063 lib/galaxy/webapps/galaxy/api/libraries.py
--- a/lib/galaxy/webapps/galaxy/api/libraries.py
+++ b/lib/galaxy/webapps/galaxy/api/libraries.py
@@ -6,10 +6,7 @@
from galaxy.managers import libraries, folders, roles
from galaxy.web import _future_expose_api as expose_api
from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous
-from galaxy.model.orm import and_, not_, or_
from galaxy.web.base.controller import BaseAPIController
-from sqlalchemy.orm.exc import MultipleResultsFound
-from sqlalchemy.orm.exc import NoResultFound
import logging
log = logging.getLogger( __name__ )
@@ -48,7 +45,7 @@
def __decode_id( self, trans, encoded_id, object_name=None ):
"""
- Try to decode the id.
+ Try to decode the id.
:param object_name: Name of the object the id belongs to. (optional)
:type object_name: str
@@ -149,7 +146,7 @@
synopsis = payload.get( 'synopsis', None )
else:
raise exceptions.RequestParameterMissingException( "You did not specify any payload." )
- updated_library = self.library_manager.update( trans, library, name, description, synopsis )
+ updated_library = self.library_manager.update( trans, library, name, description, synopsis )
library_dict = self.library_manager.get_library_dict( trans, updated_library )
return library_dict
@@ -248,20 +245,20 @@
*POST /api/libraries/{encoded_library_id}/permissions
:param encoded_library_id: the encoded id of the library to set the permissions of
- :type encoded_library_id: an encoded id string
+ :type encoded_library_id: an encoded id string
:param action: (required) describes what action should be performed
available actions: remove_restrictions, set_permissions
- :type action: string
+ :type action: string
:param access_ids[]: list of Role.id defining roles that should have access permission on the library
- :type access_ids[]: string or list
+ :type access_ids[]: string or list
:param add_ids[]: list of Role.id defining roles that should have add item permission on the library
- :type add_ids[]: string or list
+ :type add_ids[]: string or list
:param manage_ids[]: list of Role.id defining roles that should have manage permission on the library
- :type manage_ids[]: string or list
+ :type manage_ids[]: string or list
:param modify_ids[]: list of Role.id defining roles that should have modify permission on the library
- :type modify_ids[]: string or list
+ :type modify_ids[]: string or list
:rtype: dictionary
:returns: dict of current roles for all available permission types
@@ -306,7 +303,7 @@
else:
invalid_access_roles_names.append( role_id )
if len( invalid_access_roles_names ) > 0:
- log.warning( "The following roles could not be added to the library access permission: " + str( invalid_access_roles_names ) )
+ log.warning( "The following roles could not be added to the library access permission: " + str( invalid_access_roles_names ) )
# ADD TO LIBRARY ROLES
valid_add_roles = []
@@ -319,8 +316,8 @@
else:
invalid_add_roles_names.append( role_id )
if len( invalid_add_roles_names ) > 0:
- log.warning( "The following roles could not be added to the add library item permission: " + str( invalid_add_roles_names ) )
-
+ log.warning( "The following roles could not be added to the add library item permission: " + str( invalid_add_roles_names ) )
+
# MANAGE LIBRARY ROLES
valid_manage_roles = []
invalid_manage_roles_names = []
@@ -332,8 +329,8 @@
else:
invalid_manage_roles_names.append( role_id )
if len( invalid_manage_roles_names ) > 0:
- log.warning( "The following roles could not be added to the manage library permission: " + str( invalid_manage_roles_names ) )
-
+ log.warning( "The following roles could not be added to the manage library permission: " + str( invalid_manage_roles_names ) )
+
# MODIFY LIBRARY ROLES
valid_modify_roles = []
invalid_modify_roles_names = []
@@ -345,7 +342,7 @@
else:
invalid_modify_roles_names.append( role_id )
if len( invalid_modify_roles_names ) > 0:
- log.warning( "The following roles could not be added to the modify library permission: " + str( invalid_modify_roles_names ) )
+ log.warning( "The following roles could not be added to the modify library permission: " + str( invalid_modify_roles_names ) )
permissions = { trans.app.security_agent.permitted_actions.LIBRARY_ACCESS : valid_access_roles }
permissions.update( { trans.app.security_agent.permitted_actions.LIBRARY_ADD : valid_add_roles } )
@@ -357,7 +354,7 @@
# Copy the permissions to the root folder
trans.app.security_agent.copy_library_permissions( trans, library, library.root_folder )
else:
- raise exceptions.RequestParameterInvalidException( 'The mandatory parameter "action" has an invalid value.'
+ raise exceptions.RequestParameterInvalidException( 'The mandatory parameter "action" has an invalid value.'
'Allowed values are: "remove_restrictions", set_permissions"' )
roles = self.library_manager.get_current_roles( trans, library )
return roles
@@ -369,18 +366,16 @@
POST /api/libraries/{encoded_library_id}/permissions
Updates the library permissions.
"""
- import galaxy.util
- params = galaxy.util.Params( payload )
+ params = util.Params( payload )
permissions = {}
for k, v in trans.app.model.Library.permitted_actions.items():
role_params = params.get( k + '_in', [] )
- in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( trans.security.decode_id( x ) ) for x in galaxy.util.listify( role_params ) ]
+ in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( trans.security.decode_id( x ) ) for x in util.listify( role_params ) ]
permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
trans.app.security_agent.set_all_library_permissions( trans, library, permissions )
trans.sa_session.refresh( library )
# Copy the permissions to the root folder
trans.app.security_agent.copy_library_permissions( trans, library, library.root_folder )
- message = "Permissions updated for library '%s'." % library.name
item = library.to_dict( view='element', value_mapper={ 'id' : trans.security.encode_id , 'root_folder_id' : trans.security.encode_id } )
return item
diff -r eb61b02da1866c4a7da0f2fa357ce43e6c62b57c -r d3dff45bbb0554150da4491eb2d2031d11f90063 lib/galaxy/webapps/galaxy/api/library_contents.py
--- a/lib/galaxy/webapps/galaxy/api/library_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/library_contents.py
@@ -29,12 +29,12 @@
.. note:: May be slow! Returns all content traversing recursively through all folders.
.. seealso:: :class:`galaxy.webapps.galaxy.api.FolderContentsController.index` for a non-recursive solution
- :param library_id: encoded id string of the library
- :type library_id: string
+ :param library_id: the encoded id of the library
+ :type library_id: str
:returns: list of dictionaries of the form:
* id: the encoded id of the library item
- * name: the 'libary path'
+ * name: the 'library path'
or relationship of the library item to the root
* type: 'file' or 'folder'
* url: the url to get detailed information on the library item
@@ -109,7 +109,7 @@
:param id: the encoded id of the library item to return
:type id: str
- :param library_id: encoded id string of the library that contains this item
+ :param library_id: the encoded id of the library that contains this item
:type library_id: str
:returns: detailed library item information
@@ -119,7 +119,7 @@
:func:`galaxy.model.LibraryDataset.to_dict` and
:attr:`galaxy.model.LibraryFolder.dict_element_visible_keys`
"""
- class_name, content_id = self.__decode_library_content_id( trans, id )
+ class_name, content_id = self.__decode_library_content_id( id )
if class_name == 'LibraryFolder':
content = self.get_library_folder( trans, content_id, check_ownership=False, check_accessible=True )
rval = content.to_dict( view='element', value_mapper={ 'id': trans.security.encode_id } )
@@ -146,27 +146,39 @@
the HDA's encoded id in ``from_hda_id`` (and optionally ``ldda_message``).
:type library_id: str
- :param library_id: encoded id string of the library where to create the new item
+ :param library_id: the encoded id of the library where to create the new item
:type payload: dict
:param payload: dictionary structure containing:
- * folder_id: the parent folder of the new item
+ * folder_id: the encoded id of the parent folder of the new item
* create_type: the type of item to create ('file', 'folder' or 'collection')
- * from_hda_id: (optional) the id of an accessible HDA to copy into the
- library
+ * from_hda_id: (optional, only if create_type is 'file') the
+ encoded id of an accessible HDA to copy into the library
* ldda_message: (optional) the new message attribute of the LDDA created
* extended_metadata: (optional) dub-dictionary containing any extended
metadata to associate with the item
- * link_data_only: (optional) either 'copy_files' (default) or 'link_to_files'
* upload_option: (optional) one of 'upload_file' (default), 'upload_directory' or 'upload_paths'
- * server_dir: (optional) only if upload_option is 'upload_directory'
- * filesystem_paths: (optional) only if upload_option is 'upload_paths' and the user is an admin
+ * server_dir: (optional, only if upload_option is
+ 'upload_directory') relative path of the subdirectory of Galaxy
+ ``library_import_dir`` to upload. All and only the files (i.e.
+ no subdirectories) contained in the specified directory will be
+ uploaded.
+ * filesystem_paths: (optional, only if upload_option is
+ 'upload_paths' and the user is an admin) file paths on the
+ Galaxy server to upload to the library, one file per line
+ * link_data_only: (optional, only when upload_option is
+ 'upload_directory' or 'upload_paths') either 'copy_files'
+ (default) or 'link_to_files'. Setting to 'link_to_files'
+ symlinks instead of copying the files
+ * name: (optional, only if create_type is 'folder') name of the
+ folder to create
+ * description: (optional, only if create_type is 'folder')
+ description of the folder to create
:rtype: dict
:returns: a dictionary containing the id, name,
and 'show' url of the new item
"""
- create_type = None
if 'create_type' not in payload:
trans.response.status = 400
return "Missing required 'create_type' parameter."
@@ -178,10 +190,10 @@
if 'folder_id' not in payload:
trans.response.status = 400
- return "Missing requred 'folder_id' parameter."
+ return "Missing required 'folder_id' parameter."
else:
folder_id = payload.pop( 'folder_id' )
- class_name, folder_id = self.__decode_library_content_id( trans, folder_id )
+ class_name, folder_id = self.__decode_library_content_id( folder_id )
try:
# security is checked in the downstream controller
parent = self.get_library_folder( trans, folder_id, check_ownership=False, check_accessible=False )
@@ -198,9 +210,7 @@
#check for extended metadata, store it and pop it out of the param
#otherwise sanitize_param will have a fit
- ex_meta_payload = None
- if 'extended_metadata' in payload:
- ex_meta_payload = payload.pop('extended_metadata')
+ ex_meta_payload = payload.pop('extended_metadata', None)
# Now create the desired content object, either file or folder.
if create_type == 'file':
@@ -272,7 +282,7 @@
def _copy_hda_to_library_folder( self, trans, from_hda_id, library_id, folder_id, ldda_message='' ):
"""
- Copies hda ``from_hda_id`` to library folder ``library_folder_id`` optionally
+ Copies hda ``from_hda_id`` to library folder ``folder_id``, optionally
adding ``ldda_message`` to the new ldda's ``message``.
``library_contents.create`` will branch to this if called with 'from_hda_id'
@@ -325,7 +335,7 @@
:type id: str
:param id: the encoded id of the library item to return
:type library_id: str
- :param library_id: encoded id string of the library that contains this item
+ :param library_id: the encoded id of the library that contains this item
:type payload: dict
:param payload: dictionary structure containing::
'converted_dataset_id':
@@ -344,7 +354,7 @@
trans.sa_session.add( assoc )
trans.sa_session.flush()
- def __decode_library_content_id( self, trans, content_id ):
+ def __decode_library_content_id( self, content_id ):
if len( content_id ) % 16 == 0:
return 'LibraryDataset', content_id
elif content_id.startswith( 'F' ):
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: Source the common startup script for run_tests.sh.
by commits-noreply@bitbucket.org 12 Jan '15
by commits-noreply@bitbucket.org 12 Jan '15
12 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/eb61b02da186/
Changeset: eb61b02da186
User: jmchilton
Date: 2015-01-12 02:43:13+00:00
Summary: Source the common startup script for run_tests.sh.
Fixes planemo #50.
Affected #: 1 file
diff -r ff4e9117b39ddaff106d1c44792eb6fbcc7c0256 -r eb61b02da1866c4a7da0f2fa357ce43e6c62b57c run_tests.sh
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -1,5 +1,7 @@
#!/bin/sh
+./scripts/common_startup.sh
+
# A good place to look for nose info: http://somethingaboutorange.com/mrl/projects/nose/
rm -f run_functional_tests.log
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: Tool Tests - Only set library import dir if it exists.
by commits-noreply@bitbucket.org 12 Jan '15
by commits-noreply@bitbucket.org 12 Jan '15
12 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ff4e9117b39d/
Changeset: ff4e9117b39d
User: jmchilton
Date: 2015-01-12 02:32:50+00:00
Summary: Tool Tests - Only set library import dir if it exists.
Fixes planemo #41 (https://github.com/galaxyproject/planemo/issues/41)
Affected #: 1 file
diff -r 796f3129e903e164e72ce9ec4db0158eb427ccac -r ff4e9117b39ddaff106d1c44792eb6fbcc7c0256 scripts/functional_tests.py
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -225,7 +225,11 @@
if not os.path.isabs( galaxy_test_file_dir ):
galaxy_test_file_dir = os.path.join( os.getcwd(), galaxy_test_file_dir )
library_import_dir = galaxy_test_file_dir
- user_library_import_dir = os.path.join( galaxy_test_file_dir, 'users' )
+ import_dir = os.path.join( galaxy_test_file_dir, 'users' )
+ if os.path.exists(import_dir):
+ user_library_import_dir = import_dir
+ else:
+ user_library_import_dir = None
ignore_files = ()
start_server = 'GALAXY_TEST_EXTERNAL' not in os.environ
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: Masthead: Lower icons by one pixel
by commits-noreply@bitbucket.org 11 Jan '15
by commits-noreply@bitbucket.org 11 Jan '15
11 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/796f3129e903/
Changeset: 796f3129e903
User: guerler
Date: 2015-01-11 18:16:00+00:00
Summary: Masthead: Lower icons by one pixel
Affected #: 2 files
diff -r 7833db9748f17c88f458976471e3aa64cb6e8d8b -r 796f3129e903e164e72ce9ec4db0158eb427ccac static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1742,7 +1742,7 @@
#masthead li.dropdown>a:hover .caret{border-top-color:gold;border-bottom-color:gold}
#masthead .navbar-brand{position:absolute;left:0;top:0;font-family:verdana;font-weight:bold;font-size:20px;line-height:1;color:white;padding:5px 20px 12px;margin-left:-15px;z-index:2000}#masthead .navbar-brand img{display:inline;width:26px;vertical-align:top}
#masthead .navbar-brand a{color:white;text-decoration:none}
-#masthead .iconbar{position:absolute;top:6px;right:110px;cursor:pointer;color:#999;overflow:hidden}#masthead .iconbar .symbol{float:left;margin:0px 10px;height:26px;font-size:11px}
+#masthead .iconbar{position:absolute;top:7px;right:110px;cursor:pointer;color:#999;overflow:hidden}#masthead .iconbar .symbol{float:left;margin:0px 10px;height:26px;font-size:11px}
#masthead .iconbar .symbol .number{font-weight:bold;font-size:10px;font-family:"Lucida Grande",verdana,arial,helvetica,sans-serif;position:relative;left:23px;top:-12px}
#masthead .iconbar .toggle{color:gold}
.quota-meter-container{position:absolute;top:0;right:0;height:32px}
diff -r 7833db9748f17c88f458976471e3aa64cb6e8d8b -r 796f3129e903e164e72ce9ec4db0158eb427ccac static/style/src/less/base.less
--- a/static/style/src/less/base.less
+++ b/static/style/src/less/base.less
@@ -425,7 +425,7 @@
.iconbar
{
position : absolute;
- top : 6px;
+ top : 7px;
right : 110px;
cursor : pointer;
color : @gray-light;
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: Upload: Show upload button only in analysis view
by commits-noreply@bitbucket.org 11 Jan '15
by commits-noreply@bitbucket.org 11 Jan '15
11 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/7833db9748f1/
Changeset: 7833db9748f1
User: guerler
Date: 2015-01-11 17:59:43+00:00
Summary: Upload: Show upload button only in analysis view
Affected #: 4 files
diff -r 41bad82393f1790013b09851afd6f8914500f7e2 -r 7833db9748f17c88f458976471e3aa64cb6e8d8b client/galaxy/scripts/mvc/upload/upload-view.js
--- a/client/galaxy/scripts/mvc/upload/upload-view.js
+++ b/client/galaxy/scripts/mvc/upload/upload-view.js
@@ -104,7 +104,7 @@
});
// define location
- $('#left .unified-panel-header-inner').append((new UploadButton.View(this.ui_button)).$el);
+ $('.with-upload-button').append((new UploadButton.View(this.ui_button)).$el);
// load extension
var self = this;
diff -r 41bad82393f1790013b09851afd6f8914500f7e2 -r 7833db9748f17c88f458976471e3aa64cb6e8d8b static/scripts/mvc/upload/upload-view.js
--- a/static/scripts/mvc/upload/upload-view.js
+++ b/static/scripts/mvc/upload/upload-view.js
@@ -104,7 +104,7 @@
});
// define location
- $('#left .unified-panel-header-inner').append((new UploadButton.View(this.ui_button)).$el);
+ $('.with-upload-button').append((new UploadButton.View(this.ui_button)).$el);
// load extension
var self = this;
diff -r 41bad82393f1790013b09851afd6f8914500f7e2 -r 7833db9748f17c88f458976471e3aa64cb6e8d8b static/scripts/packed/mvc/upload/upload-view.js
--- a/static/scripts/packed/mvc/upload/upload-view.js
+++ b/static/scripts/packed/mvc/upload/upload-view.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/upload/upload-button","mvc/upload/upload-model","mvc/upload/upload-row","mvc/upload/upload-ftp","mvc/ui/ui-popover","mvc/ui/ui-modal","utils/uploadbox"],function(f,e,c,b,g,d,a){return Backbone.View.extend({options:{nginx_upload_path:""},modal:null,ui_button:null,uploadbox:null,current_history:null,upload_size:0,list_extensions:[],list_genomes:[],auto:{id:"auto",text:"Auto-detect",description:"This system will try to detect the file type automatically. If your file is not detected properly as one of the known formats, it most likely means that it has some format problems (e.g., different number of columns on different rows). You can still coerce the system to set your data to the format you think it should be. You can also upload compressed files, which will automatically be decompressed."},collection:new c.Collection(),ftp:null,counter:{announce:0,success:0,error:0,running:0,reset:function(){this.announce=this.success=this.error=this.running=0}},initialize:function(i){var h=this;if(i){this.options=_.defaults(i,this.options)}this.ui_button=new e.Model({icon:"fa-upload",tooltip:"Download from URL or upload files from disk",label:"Load Data",onclick:function(j){if(j){j.preventDefault();h.show()}},onunload:function(){if(h.counter.running>0){return"Several uploads are still processing."}}});$("#left .unified-panel-header-inner").append((new e.View(this.ui_button)).$el);var h=this;f.get({url:galaxy_config.root+"api/datatypes?extension_only=False",success:function(j){for(key in j){h.list_extensions.push({id:j[key].extension,text:j[key].extension,description:j[key].description,description_url:j[key].description_url})}h.list_extensions.sort(function(l,k){return l.id>k.id?1:l.id<k.id?-1:0});if(!h.options.datatypes_disable_auto){h.list_extensions.unshift(h.auto)}}});f.get({url:galaxy_config.root+"api/genomes",success:function(j){for(key in j){h.list_genomes.push({id:j[key][1],text:j[key][0]})}h.list_genomes.sort(function(l,k){return l.id>k.id?1:l.id<k.id?-1:0})}});this.collection.on("remove",function(j){h._eventRemove(j)});this.collection.on("change:genome",function(k){var j=k.get("genome");h.collection.each(function(l){if(l.get("status")=="init"&&l.get("genome")=="?"){l.set("genome",j)}})})},show:function(){var h=this;if(!Galaxy.currHistoryPanel||!Galaxy.currHistoryPanel.model){window.setTimeout(function(){h.show()},500);return}if(!this.modal){var h=this;this.modal=new a.View({title:"Download data directly from web or upload files from your disk",body:this._template("upload-box","upload-info"),buttons:{"Choose local file":function(){h.uploadbox.select()},"Choose FTP file":function(){h._eventFtp()},"Paste/Fetch data":function(){h._eventCreate()},Start:function(){h._eventStart()},Pause:function(){h._eventStop()},Reset:function(){h._eventReset()},Close:function(){h.modal.hide()},},height:"400",width:"900",closing_events:true});this.setElement("#upload-box");var h=this;this.uploadbox=this.$el.uploadbox({announce:function(j,k,l){h._eventAnnounce(j,k,l)},initialize:function(j,k,l){return h._eventInitialize(j,k,l)},progress:function(j,k,l){h._eventProgress(j,k,l)},success:function(j,k,l){h._eventSuccess(j,k,l)},error:function(j,k,l){h._eventError(j,k,l)},complete:function(){h._eventComplete()}});var i=this.modal.getButton("Choose FTP file");this.ftp=new d.View({title:"FTP files",container:i})}this.modal.show();this._updateUser();this._updateScreen()},_eventRemove:function(i){var h=i.get("status");if(h=="success"){this.counter.success--}else{if(h=="error"){this.counter.error--}else{this.counter.announce--}}this._updateScreen();this.uploadbox.remove(i.id)},_eventAnnounce:function(h,i,k){this.counter.announce++;this._updateScreen();var j=new b(this,{id:h,file_name:i.name,file_size:i.size,file_mode:i.mode,file_path:i.path});this.collection.add(j.model);$(this.el).find("tbody:first").append(j.$el);j.render()},_eventInitialize:function(m,j,s){var k=this.collection.get(m);k.set("status","running");var o=k.get("file_name");var n=k.get("file_path");var h=k.get("file_mode");var p=k.get("extension");var r=k.get("genome");var q=k.get("url_paste");var l=k.get("space_to_tabs");var i=k.get("to_posix_lines");if(!q&&!(j.size>0)){return null}this.uploadbox.configure({url:this.options.nginx_upload_path});if(h=="local"){this.uploadbox.configure({paramname:"files_0|file_data"})}else{this.uploadbox.configure({paramname:null})}tool_input={};if(h=="new"){tool_input["files_0|url_paste"]=q}if(h=="ftp"){tool_input["files_0|ftp_files"]=n}tool_input.dbkey=r;tool_input.file_type=p;tool_input["files_0|type"]="upload_dataset";tool_input.space_to_tabs=l;tool_input.to_posix_lines=i;data={};data.history_id=this.current_history;data.tool_id="upload1";data.inputs=JSON.stringify(tool_input);return data},_eventProgress:function(i,j,h){var k=this.collection.get(i);k.set("percentage",h);this.ui_button.set("percentage",this._upload_percentage(h,j.size))},_eventSuccess:function(i,j,l){var k=this.collection.get(i);k.set("percentage",100);k.set("status","success");var h=k.get("file_size");this.ui_button.set("percentage",this._upload_percentage(100,h));this.upload_completed+=h*100;this.counter.announce--;this.counter.success++;this._updateScreen();Galaxy.currHistoryPanel.refreshContents()},_eventError:function(h,i,k){var j=this.collection.get(h);j.set("percentage",100);j.set("status","error");j.set("info",k);this.ui_button.set("percentage",this._upload_percentage(100,i.size));this.ui_button.set("status","danger");this.upload_completed+=i.size*100;this.counter.announce--;this.counter.error++;this._updateScreen()},_eventComplete:function(){this.collection.each(function(h){if(h.get("status")=="queued"){h.set("status","init")}});this.counter.running=0;this._updateScreen()},_eventFtp:function(){if(!this.ftp.visible){this.ftp.empty();this.ftp.append((new g(this)).$el);this.ftp.show()}else{this.ftp.hide()}},_eventCreate:function(){this.uploadbox.add([{name:"New File",size:0,mode:"new"}])},_eventStart:function(){if(this.counter.announce==0||this.counter.running>0){return}var h=this;this.upload_size=0;this.upload_completed=0;this.collection.each(function(i){if(i.get("status")=="init"){i.set("status","queued");h.upload_size+=i.get("file_size")}});this.ui_button.set("percentage",0);this.ui_button.set("status","success");this.counter.running=this.counter.announce;this._updateScreen();this.uploadbox.start()},_eventStop:function(){if(this.counter.running==0){return}this.ui_button.set("status","info");this.uploadbox.stop();$("#upload-info").html("Queue will pause after completing the current file...")},_eventReset:function(){if(this.counter.running==0){this.collection.reset();this.counter.reset();this._updateScreen();this.uploadbox.reset();this.ui_button.set("percentage",0)}},_updateUser:function(){this.current_user=Galaxy.currUser.get("id");this.current_history=null;if(this.current_user){this.current_history=Galaxy.currHistoryPanel.model.get("id")}},_updateScreen:function(){if(this.counter.announce==0){if(this.uploadbox.compatible()){message="You can Drag & Drop files into this box."}else{message="Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Some supported browsers are: Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+."}}else{if(this.counter.running==0){message="You added "+this.counter.announce+" file(s) to the queue. Add more files or click 'Start' to proceed."}else{message="Please wait..."+this.counter.announce+" out of "+this.counter.running+" remaining."}}$("#upload-info").html(message);if(this.counter.running==0&&this.counter.announce+this.counter.success+this.counter.error>0){this.modal.enableButton("Reset")}else{this.modal.disableButton("Reset")}if(this.counter.running==0&&this.counter.announce>0){this.modal.enableButton("Start")}else{this.modal.disableButton("Start")}if(this.counter.running>0){this.modal.enableButton("Pause")}else{this.modal.disableButton("Pause")}if(this.counter.running==0){this.modal.enableButton("Choose local file");this.modal.enableButton("Choose FTP file");this.modal.enableButton("Paste/Fetch data")}else{this.modal.disableButton("Choose local file");this.modal.disableButton("Choose FTP file");this.modal.disableButton("Paste/Fetch data")}if(this.current_user&&this.options.ftp_upload_dir&&this.options.ftp_upload_site){this.modal.showButton("Choose FTP file")}else{this.modal.hideButton("Choose FTP file")}if(this.counter.announce+this.counter.success+this.counter.error>0){$(this.el).find("#upload-table").show()}else{$(this.el).find("#upload-table").hide()}},_upload_percentage:function(h,i){return(this.upload_completed+(h*i))/this.upload_size},_template:function(i,h){return'<div id="'+i+'" class="upload-box"><table id="upload-table" class="table table-striped" style="display: none;"><thead><tr><th>Name</th><th>Size</th><th>Type</th><th>Genome</th><th>Settings</th><th>Status</th><th></th></tr></thead><tbody></tbody></table></div><h6 id="'+h+'" class="upload-info"></h6>'}})});
\ No newline at end of file
+define(["utils/utils","mvc/upload/upload-button","mvc/upload/upload-model","mvc/upload/upload-row","mvc/upload/upload-ftp","mvc/ui/ui-popover","mvc/ui/ui-modal","utils/uploadbox"],function(f,e,c,b,g,d,a){return Backbone.View.extend({options:{nginx_upload_path:""},modal:null,ui_button:null,uploadbox:null,current_history:null,upload_size:0,list_extensions:[],list_genomes:[],auto:{id:"auto",text:"Auto-detect",description:"This system will try to detect the file type automatically. If your file is not detected properly as one of the known formats, it most likely means that it has some format problems (e.g., different number of columns on different rows). You can still coerce the system to set your data to the format you think it should be. You can also upload compressed files, which will automatically be decompressed."},collection:new c.Collection(),ftp:null,counter:{announce:0,success:0,error:0,running:0,reset:function(){this.announce=this.success=this.error=this.running=0}},initialize:function(i){var h=this;if(i){this.options=_.defaults(i,this.options)}this.ui_button=new e.Model({icon:"fa-upload",tooltip:"Download from URL or upload files from disk",label:"Load Data",onclick:function(j){if(j){j.preventDefault();h.show()}},onunload:function(){if(h.counter.running>0){return"Several uploads are still processing."}}});$(".with-upload-button").append((new e.View(this.ui_button)).$el);var h=this;f.get({url:galaxy_config.root+"api/datatypes?extension_only=False",success:function(j){for(key in j){h.list_extensions.push({id:j[key].extension,text:j[key].extension,description:j[key].description,description_url:j[key].description_url})}h.list_extensions.sort(function(l,k){return l.id>k.id?1:l.id<k.id?-1:0});if(!h.options.datatypes_disable_auto){h.list_extensions.unshift(h.auto)}}});f.get({url:galaxy_config.root+"api/genomes",success:function(j){for(key in j){h.list_genomes.push({id:j[key][1],text:j[key][0]})}h.list_genomes.sort(function(l,k){return l.id>k.id?1:l.id<k.id?-1:0})}});this.collection.on("remove",function(j){h._eventRemove(j)});this.collection.on("change:genome",function(k){var j=k.get("genome");h.collection.each(function(l){if(l.get("status")=="init"&&l.get("genome")=="?"){l.set("genome",j)}})})},show:function(){var h=this;if(!Galaxy.currHistoryPanel||!Galaxy.currHistoryPanel.model){window.setTimeout(function(){h.show()},500);return}if(!this.modal){var h=this;this.modal=new a.View({title:"Download data directly from web or upload files from your disk",body:this._template("upload-box","upload-info"),buttons:{"Choose local file":function(){h.uploadbox.select()},"Choose FTP file":function(){h._eventFtp()},"Paste/Fetch data":function(){h._eventCreate()},Start:function(){h._eventStart()},Pause:function(){h._eventStop()},Reset:function(){h._eventReset()},Close:function(){h.modal.hide()},},height:"400",width:"900",closing_events:true});this.setElement("#upload-box");var h=this;this.uploadbox=this.$el.uploadbox({announce:function(j,k,l){h._eventAnnounce(j,k,l)},initialize:function(j,k,l){return h._eventInitialize(j,k,l)},progress:function(j,k,l){h._eventProgress(j,k,l)},success:function(j,k,l){h._eventSuccess(j,k,l)},error:function(j,k,l){h._eventError(j,k,l)},complete:function(){h._eventComplete()}});var i=this.modal.getButton("Choose FTP file");this.ftp=new d.View({title:"FTP files",container:i})}this.modal.show();this._updateUser();this._updateScreen()},_eventRemove:function(i){var h=i.get("status");if(h=="success"){this.counter.success--}else{if(h=="error"){this.counter.error--}else{this.counter.announce--}}this._updateScreen();this.uploadbox.remove(i.id)},_eventAnnounce:function(h,i,k){this.counter.announce++;this._updateScreen();var j=new b(this,{id:h,file_name:i.name,file_size:i.size,file_mode:i.mode,file_path:i.path});this.collection.add(j.model);$(this.el).find("tbody:first").append(j.$el);j.render()},_eventInitialize:function(m,j,s){var k=this.collection.get(m);k.set("status","running");var o=k.get("file_name");var n=k.get("file_path");var h=k.get("file_mode");var p=k.get("extension");var r=k.get("genome");var q=k.get("url_paste");var l=k.get("space_to_tabs");var i=k.get("to_posix_lines");if(!q&&!(j.size>0)){return null}this.uploadbox.configure({url:this.options.nginx_upload_path});if(h=="local"){this.uploadbox.configure({paramname:"files_0|file_data"})}else{this.uploadbox.configure({paramname:null})}tool_input={};if(h=="new"){tool_input["files_0|url_paste"]=q}if(h=="ftp"){tool_input["files_0|ftp_files"]=n}tool_input.dbkey=r;tool_input.file_type=p;tool_input["files_0|type"]="upload_dataset";tool_input.space_to_tabs=l;tool_input.to_posix_lines=i;data={};data.history_id=this.current_history;data.tool_id="upload1";data.inputs=JSON.stringify(tool_input);return data},_eventProgress:function(i,j,h){var k=this.collection.get(i);k.set("percentage",h);this.ui_button.set("percentage",this._upload_percentage(h,j.size))},_eventSuccess:function(i,j,l){var k=this.collection.get(i);k.set("percentage",100);k.set("status","success");var h=k.get("file_size");this.ui_button.set("percentage",this._upload_percentage(100,h));this.upload_completed+=h*100;this.counter.announce--;this.counter.success++;this._updateScreen();Galaxy.currHistoryPanel.refreshContents()},_eventError:function(h,i,k){var j=this.collection.get(h);j.set("percentage",100);j.set("status","error");j.set("info",k);this.ui_button.set("percentage",this._upload_percentage(100,i.size));this.ui_button.set("status","danger");this.upload_completed+=i.size*100;this.counter.announce--;this.counter.error++;this._updateScreen()},_eventComplete:function(){this.collection.each(function(h){if(h.get("status")=="queued"){h.set("status","init")}});this.counter.running=0;this._updateScreen()},_eventFtp:function(){if(!this.ftp.visible){this.ftp.empty();this.ftp.append((new g(this)).$el);this.ftp.show()}else{this.ftp.hide()}},_eventCreate:function(){this.uploadbox.add([{name:"New File",size:0,mode:"new"}])},_eventStart:function(){if(this.counter.announce==0||this.counter.running>0){return}var h=this;this.upload_size=0;this.upload_completed=0;this.collection.each(function(i){if(i.get("status")=="init"){i.set("status","queued");h.upload_size+=i.get("file_size")}});this.ui_button.set("percentage",0);this.ui_button.set("status","success");this.counter.running=this.counter.announce;this._updateScreen();this.uploadbox.start()},_eventStop:function(){if(this.counter.running==0){return}this.ui_button.set("status","info");this.uploadbox.stop();$("#upload-info").html("Queue will pause after completing the current file...")},_eventReset:function(){if(this.counter.running==0){this.collection.reset();this.counter.reset();this._updateScreen();this.uploadbox.reset();this.ui_button.set("percentage",0)}},_updateUser:function(){this.current_user=Galaxy.currUser.get("id");this.current_history=null;if(this.current_user){this.current_history=Galaxy.currHistoryPanel.model.get("id")}},_updateScreen:function(){if(this.counter.announce==0){if(this.uploadbox.compatible()){message="You can Drag & Drop files into this box."}else{message="Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Some supported browsers are: Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+."}}else{if(this.counter.running==0){message="You added "+this.counter.announce+" file(s) to the queue. Add more files or click 'Start' to proceed."}else{message="Please wait..."+this.counter.announce+" out of "+this.counter.running+" remaining."}}$("#upload-info").html(message);if(this.counter.running==0&&this.counter.announce+this.counter.success+this.counter.error>0){this.modal.enableButton("Reset")}else{this.modal.disableButton("Reset")}if(this.counter.running==0&&this.counter.announce>0){this.modal.enableButton("Start")}else{this.modal.disableButton("Start")}if(this.counter.running>0){this.modal.enableButton("Pause")}else{this.modal.disableButton("Pause")}if(this.counter.running==0){this.modal.enableButton("Choose local file");this.modal.enableButton("Choose FTP file");this.modal.enableButton("Paste/Fetch data")}else{this.modal.disableButton("Choose local file");this.modal.disableButton("Choose FTP file");this.modal.disableButton("Paste/Fetch data")}if(this.current_user&&this.options.ftp_upload_dir&&this.options.ftp_upload_site){this.modal.showButton("Choose FTP file")}else{this.modal.hideButton("Choose FTP file")}if(this.counter.announce+this.counter.success+this.counter.error>0){$(this.el).find("#upload-table").show()}else{$(this.el).find("#upload-table").hide()}},_upload_percentage:function(h,i){return(this.upload_completed+(h*i))/this.upload_size},_template:function(i,h){return'<div id="'+i+'" class="upload-box"><table id="upload-table" class="table table-striped" style="display: none;"><thead><tr><th>Name</th><th>Size</th><th>Type</th><th>Genome</th><th>Settings</th><th>Status</th><th></th></tr></thead><tbody></tbody></table></div><h6 id="'+h+'" class="upload-info"></h6>'}})});
\ No newline at end of file
diff -r 41bad82393f1790013b09851afd6f8914500f7e2 -r 7833db9748f17c88f458976471e3aa64cb6e8d8b templates/webapps/galaxy/root/index.mako
--- a/templates/webapps/galaxy/root/index.mako
+++ b/templates/webapps/galaxy/root/index.mako
@@ -58,7 +58,7 @@
<%def name="left_panel()"><div class="unified-panel-header" unselectable="on">
- <div class='unified-panel-header-inner'>
+ <div class='unified-panel-header-inner with-upload-button'>
${n_('Tools')}
</div></div>
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/Workflow: Add modules
by commits-noreply@bitbucket.org 11 Jan '15
by commits-noreply@bitbucket.org 11 Jan '15
11 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/41bad82393f1/
Changeset: 41bad82393f1
User: guerler
Date: 2015-01-11 17:08:10+00:00
Summary: ToolForm/Workflow: Add modules
Affected #: 6 files
diff -r d9b038019163bc378b72b675ddb4e1e902384b12 -r 41bad82393f1790013b09851afd6f8914500f7e2 client/galaxy/scripts/mvc/tools/tools-form-base.js
--- /dev/null
+++ b/client/galaxy/scripts/mvc/tools/tools-form-base.js
@@ -0,0 +1,315 @@
+/**
+ This is the main class of the tool form plugin. It is referenced as 'app' in all lower level modules.
+*/
+define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
+ 'mvc/citation/citation-model', 'mvc/citation/citation-view',
+ 'mvc/tools', 'mvc/tools/tools-template', 'mvc/tools/tools-content', 'mvc/tools/tools-section', 'mvc/tools/tools-tree'],
+ function(Utils, Deferred, Portlet, Ui, CitationModel, CitationView,
+ Tools, ToolTemplate, ToolContent, ToolSection, ToolTree) {
+
+ // create form view
+ return Backbone.View.extend({
+ // initialize
+ initialize: function(options) {
+ // log options
+ console.debug(options);
+
+ // link galaxy modal or create one
+ var galaxy = parent.Galaxy;
+ if (galaxy && galaxy.modal) {
+ this.modal = galaxy.modal;
+ } else {
+ this.modal = new Ui.Modal.View();
+ }
+
+ // check if the user is an admin
+ if (galaxy && galaxy.currUser) {
+ this.is_admin = galaxy.currUser.get('is_admin');
+ } else {
+ this.is_admin = false;
+ }
+
+ // link options
+ this.options = options;
+
+ // link container
+ this.container = this.options.container || 'body';
+
+ // create deferred processing queue handler
+ // this handler reduces the number of requests to the api by filtering redundant requests
+ this.deferred = new Deferred();
+
+ // set element
+ this.setElement('<div/>');
+
+ // add to main element
+ $(this.container).append(this.$el);
+
+ // build this form
+ this._buildForm();
+ },
+
+ /** Shows the final message (usually upon successful job submission)
+ */
+ reciept: function($el) {
+ $(this.container).empty();
+ $(this.container).append($el);
+ },
+
+ /** Highlight and scroll to input element (currently only used for error notifications)
+ */
+ highlight: function (input_id, message, silent) {
+ // get input field
+ var input_element = this.element_list[input_id];
+
+ // check input element
+ if (input_element) {
+ // mark error
+ input_element.error(message || 'Please verify this parameter.');
+
+ // scroll to first input element
+ if (!silent) {
+ $(this.container).animate({
+ scrollTop: input_element.$el.offset().top - 20
+ }, 500);
+ }
+ }
+ },
+
+ /** Main tool form build function. This function is called once a new model is available.
+ */
+ _buildForm: function() {
+ // link this
+ var self = this;
+
+ // reset events
+ this.off('refresh');
+ this.off('reset');
+
+ // reset field list, which contains the input field elements
+ this.field_list = {};
+
+ // reset sequential input definition list, which contains the input definitions as provided from the api
+ this.input_list = {};
+
+ // reset input element list, which contains the dom elements of each input element (includes also the input field)
+ this.element_list = {};
+
+ // creates a tree/json data structure from the input form
+ this.tree = new ToolTree(this);
+
+ // request history content and build form
+ this.content = new ToolContent(this);
+
+ // link model options
+ var options = this.options;
+
+ // create ui elements
+ this._renderForm(options);
+
+ // rebuild the underlying data structure
+ this.tree.finalize();
+
+ // show errors
+ if (!this.workflow && options.errors) {
+ var error_messages = this.tree.matchResponse(options.errors);
+ for (var input_id in error_messages) {
+ this.highlight(input_id, error_messages[input_id], true);
+ }
+ }
+
+ // add refresh listener
+ this.on('refresh', function() {
+ // by using/reseting the deferred ajax queue the number of redundant calls is reduced
+ self.deferred.reset();
+ self.deferred.execute(function(){self._updateModel()});
+ });
+
+ // add reset listener
+ this.on('reset', function() {
+ for (var i in this.element_list) {
+ this.element_list[i].reset();
+ }
+ });
+ },
+
+ /** Renders the UI elements required for the form
+ */
+ _renderForm: function(options) {
+ // link this
+ var self = this;
+
+ // create message view
+ this.message = new Ui.Message();
+
+ // button for version selection
+ var requirements_button = new Ui.ButtonIcon({
+ icon : 'fa-info-circle',
+ title : 'Requirements',
+ tooltip : 'Display tool requirements',
+ onclick : function() {
+ if (!this.visible) {
+ this.visible = true;
+ self.message.update({
+ persistent : true,
+ message : ToolTemplate.requirements(options),
+ status : 'info'
+ });
+ } else {
+ this.visible = false;
+ self.message.update({
+ message : ''
+ });
+ }
+ }
+ });
+ if (!options.requirements || options.requirements.length == 0) {
+ requirements_button.$el.hide();
+ }
+
+ // button for version selection
+ var versions_button = new Ui.ButtonMenu({
+ icon : 'fa-cubes',
+ title : 'Versions',
+ tooltip : 'Select another tool version'
+ });
+ if (options.versions && options.versions.length > 1) {
+ for (var i in options.versions) {
+ var version = options.versions[i];
+ if (version != options.version) {
+ versions_button.addMenu({
+ title : 'Switch to ' + version,
+ version : version,
+ icon : 'fa-cube',
+ onclick : function() {
+ // here we update the tool version (some tools encode the version also in the id)
+ options.id = options.id.replace(options.version, this.version);
+ options.version = this.version;
+
+ // rebuild the model and form
+ self.deferred.reset();
+ self.deferred.execute(function(){self._buildModel()});
+ }
+ });
+ }
+ }
+ } else {
+ versions_button.$el.hide();
+ }
+
+ // button menu
+ var menu_button = new Ui.ButtonMenu({
+ icon : 'fa-caret-down',
+ title : 'Options',
+ tooltip : 'View available options'
+ });
+
+ // configure button selection
+ if(options.biostar_url) {
+ // add question option
+ menu_button.addMenu({
+ icon : 'fa-question-circle',
+ title : 'Question?',
+ tooltip : 'Ask a question about this tool (Biostar)',
+ onclick : function() {
+ window.open(options.biostar_url + '/p/new/post/');
+ }
+ });
+
+ // create search button
+ menu_button.addMenu({
+ icon : 'fa-search',
+ title : 'Search',
+ tooltip : 'Search help for this tool (Biostar)',
+ onclick : function() {
+ window.open(options.biostar_url + '/t/' + options.id + '/');
+ }
+ });
+ };
+
+ // create share button
+ menu_button.addMenu({
+ icon : 'fa-share',
+ title : 'Share',
+ tooltip : 'Share this tool',
+ onclick : function() {
+ prompt('Copy to clipboard: Ctrl+C, Enter', window.location.origin + galaxy_config.root + 'root?tool_id=' + options.id);
+ }
+ });
+
+ // add admin operations
+ if (this.is_admin) {
+ // create download button
+ menu_button.addMenu({
+ icon : 'fa-download',
+ title : 'Download',
+ tooltip : 'Download this tool',
+ onclick : function() {
+ window.location.href = galaxy_config.root + 'api/tools/' + options.id + '/download';
+ }
+ });
+ }
+
+ // create tool form section
+ this.section = new ToolSection.View(self, {
+ inputs : options.inputs,
+ cls : 'ui-table-plain'
+ });
+
+ // switch to classic tool form mako if the form definition is incompatible
+ if (this.incompatible) {
+ this.$el.hide();
+ $('#tool-form-classic').show();
+ return;
+ }
+
+ // create portlet
+ this.portlet = new Portlet.View({
+ icon : 'fa-wrench',
+ title : '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Tool Version ' + options.version + ')',
+ cls : 'ui-portlet-slim',
+ operations: {
+ requirements : requirements_button,
+ menu : menu_button,
+ versions : versions_button
+ },
+ buttons : this.buttons
+ });
+
+ // append message
+ this.portlet.append(this.message.$el, true);
+
+ // append tool section
+ this.portlet.append(this.section.$el);
+
+ // start form
+ this.$el.empty();
+ this.$el.append(this.portlet.$el);
+
+ // append help
+ if (options.help != '') {
+ this.$el.append(ToolTemplate.help(options.help));
+ }
+
+ // append citations
+ if (options.citations) {
+ var $citations = $('<div/>');
+ var citations = new CitationModel.ToolCitationCollection();
+ citations.tool_id = options.id;
+ var citation_list_view = new CitationView.CitationListView({ el: $citations, collection: citations } );
+ citation_list_view.render();
+ citations.fetch();
+ this.$el.append($citations);
+ }
+
+ // show message if available in model
+ if (options.message) {
+ this.message.update({
+ persistent : true,
+ status : 'warning',
+ message : options.message
+ });
+ }
+ }
+ });
+});
diff -r d9b038019163bc378b72b675ddb4e1e902384b12 -r 41bad82393f1790013b09851afd6f8914500f7e2 client/galaxy/scripts/mvc/tools/tools-form-workflow.js
--- /dev/null
+++ b/client/galaxy/scripts/mvc/tools/tools-form-workflow.js
@@ -0,0 +1,66 @@
+/**
+ This is the main class of the tool form plugin. It is referenced as 'app' in all lower level modules.
+*/
+define(['utils/utils', 'mvc/tools/tools-form-base'],
+ function(Utils, ToolFormBase) {
+
+ // create form view
+ var View = ToolFormBase.extend({
+ initialize: function(options) {
+ this.workflow = true;
+ ToolFormBase.prototype.initialize.call(this, options);
+ },
+
+ /** Builds a new model through api call and recreates the entire form
+ */
+ _buildModel: function() {
+ },
+
+ /** Request a new model for an already created tool form and updates the form inputs
+ */
+ _updateModel: function() {
+ // create the request dictionary
+ var self = this;
+ var current_state = this.tree.finalize();
+
+ // log tool state
+ console.debug('tools-form-workflow::_refreshForm() - Refreshing states.');
+ console.debug(current_state);
+
+ // register process
+ 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;
+
+ // post job
+ Utils.request({
+ type : 'GET',
+ url : model_url,
+ data : current_state,
+ success : function(node) {
+ parent.update_node(node);
+
+ // process completed
+ self.deferred.done(process_id);
+
+ // log success
+ console.debug('tools-form::_refreshForm() - States refreshed.');
+ console.debug(node);
+ },
+ error : function(response) {
+ // process completed
+ self.deferred.done(process_id);
+
+ // log error
+ console.debug('tools-form::_refreshForm() - Refresh request failed.');
+ console.debug(response);
+ }
+ });
+ }
+ });
+
+ return {
+ View: View
+ };
+});
diff -r d9b038019163bc378b72b675ddb4e1e902384b12 -r 41bad82393f1790013b09851afd6f8914500f7e2 static/scripts/mvc/tools/tools-form-base.js
--- /dev/null
+++ b/static/scripts/mvc/tools/tools-form-base.js
@@ -0,0 +1,315 @@
+/**
+ This is the main class of the tool form plugin. It is referenced as 'app' in all lower level modules.
+*/
+define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
+ 'mvc/citation/citation-model', 'mvc/citation/citation-view',
+ 'mvc/tools', 'mvc/tools/tools-template', 'mvc/tools/tools-content', 'mvc/tools/tools-section', 'mvc/tools/tools-tree'],
+ function(Utils, Deferred, Portlet, Ui, CitationModel, CitationView,
+ Tools, ToolTemplate, ToolContent, ToolSection, ToolTree) {
+
+ // create form view
+ return Backbone.View.extend({
+ // initialize
+ initialize: function(options) {
+ // log options
+ console.debug(options);
+
+ // link galaxy modal or create one
+ var galaxy = parent.Galaxy;
+ if (galaxy && galaxy.modal) {
+ this.modal = galaxy.modal;
+ } else {
+ this.modal = new Ui.Modal.View();
+ }
+
+ // check if the user is an admin
+ if (galaxy && galaxy.currUser) {
+ this.is_admin = galaxy.currUser.get('is_admin');
+ } else {
+ this.is_admin = false;
+ }
+
+ // link options
+ this.options = options;
+
+ // link container
+ this.container = this.options.container || 'body';
+
+ // create deferred processing queue handler
+ // this handler reduces the number of requests to the api by filtering redundant requests
+ this.deferred = new Deferred();
+
+ // set element
+ this.setElement('<div/>');
+
+ // add to main element
+ $(this.container).append(this.$el);
+
+ // build this form
+ this._buildForm();
+ },
+
+ /** Shows the final message (usually upon successful job submission)
+ */
+ reciept: function($el) {
+ $(this.container).empty();
+ $(this.container).append($el);
+ },
+
+ /** Highlight and scroll to input element (currently only used for error notifications)
+ */
+ highlight: function (input_id, message, silent) {
+ // get input field
+ var input_element = this.element_list[input_id];
+
+ // check input element
+ if (input_element) {
+ // mark error
+ input_element.error(message || 'Please verify this parameter.');
+
+ // scroll to first input element
+ if (!silent) {
+ $(this.container).animate({
+ scrollTop: input_element.$el.offset().top - 20
+ }, 500);
+ }
+ }
+ },
+
+ /** Main tool form build function. This function is called once a new model is available.
+ */
+ _buildForm: function() {
+ // link this
+ var self = this;
+
+ // reset events
+ this.off('refresh');
+ this.off('reset');
+
+ // reset field list, which contains the input field elements
+ this.field_list = {};
+
+ // reset sequential input definition list, which contains the input definitions as provided from the api
+ this.input_list = {};
+
+ // reset input element list, which contains the dom elements of each input element (includes also the input field)
+ this.element_list = {};
+
+ // creates a tree/json data structure from the input form
+ this.tree = new ToolTree(this);
+
+ // request history content and build form
+ this.content = new ToolContent(this);
+
+ // link model options
+ var options = this.options;
+
+ // create ui elements
+ this._renderForm(options);
+
+ // rebuild the underlying data structure
+ this.tree.finalize();
+
+ // show errors
+ if (!this.workflow && options.errors) {
+ var error_messages = this.tree.matchResponse(options.errors);
+ for (var input_id in error_messages) {
+ this.highlight(input_id, error_messages[input_id], true);
+ }
+ }
+
+ // add refresh listener
+ this.on('refresh', function() {
+ // by using/reseting the deferred ajax queue the number of redundant calls is reduced
+ self.deferred.reset();
+ self.deferred.execute(function(){self._updateModel()});
+ });
+
+ // add reset listener
+ this.on('reset', function() {
+ for (var i in this.element_list) {
+ this.element_list[i].reset();
+ }
+ });
+ },
+
+ /** Renders the UI elements required for the form
+ */
+ _renderForm: function(options) {
+ // link this
+ var self = this;
+
+ // create message view
+ this.message = new Ui.Message();
+
+ // button for version selection
+ var requirements_button = new Ui.ButtonIcon({
+ icon : 'fa-info-circle',
+ title : 'Requirements',
+ tooltip : 'Display tool requirements',
+ onclick : function() {
+ if (!this.visible) {
+ this.visible = true;
+ self.message.update({
+ persistent : true,
+ message : ToolTemplate.requirements(options),
+ status : 'info'
+ });
+ } else {
+ this.visible = false;
+ self.message.update({
+ message : ''
+ });
+ }
+ }
+ });
+ if (!options.requirements || options.requirements.length == 0) {
+ requirements_button.$el.hide();
+ }
+
+ // button for version selection
+ var versions_button = new Ui.ButtonMenu({
+ icon : 'fa-cubes',
+ title : 'Versions',
+ tooltip : 'Select another tool version'
+ });
+ if (options.versions && options.versions.length > 1) {
+ for (var i in options.versions) {
+ var version = options.versions[i];
+ if (version != options.version) {
+ versions_button.addMenu({
+ title : 'Switch to ' + version,
+ version : version,
+ icon : 'fa-cube',
+ onclick : function() {
+ // here we update the tool version (some tools encode the version also in the id)
+ options.id = options.id.replace(options.version, this.version);
+ options.version = this.version;
+
+ // rebuild the model and form
+ self.deferred.reset();
+ self.deferred.execute(function(){self._buildModel()});
+ }
+ });
+ }
+ }
+ } else {
+ versions_button.$el.hide();
+ }
+
+ // button menu
+ var menu_button = new Ui.ButtonMenu({
+ icon : 'fa-caret-down',
+ title : 'Options',
+ tooltip : 'View available options'
+ });
+
+ // configure button selection
+ if(options.biostar_url) {
+ // add question option
+ menu_button.addMenu({
+ icon : 'fa-question-circle',
+ title : 'Question?',
+ tooltip : 'Ask a question about this tool (Biostar)',
+ onclick : function() {
+ window.open(options.biostar_url + '/p/new/post/');
+ }
+ });
+
+ // create search button
+ menu_button.addMenu({
+ icon : 'fa-search',
+ title : 'Search',
+ tooltip : 'Search help for this tool (Biostar)',
+ onclick : function() {
+ window.open(options.biostar_url + '/t/' + options.id + '/');
+ }
+ });
+ };
+
+ // create share button
+ menu_button.addMenu({
+ icon : 'fa-share',
+ title : 'Share',
+ tooltip : 'Share this tool',
+ onclick : function() {
+ prompt('Copy to clipboard: Ctrl+C, Enter', window.location.origin + galaxy_config.root + 'root?tool_id=' + options.id);
+ }
+ });
+
+ // add admin operations
+ if (this.is_admin) {
+ // create download button
+ menu_button.addMenu({
+ icon : 'fa-download',
+ title : 'Download',
+ tooltip : 'Download this tool',
+ onclick : function() {
+ window.location.href = galaxy_config.root + 'api/tools/' + options.id + '/download';
+ }
+ });
+ }
+
+ // create tool form section
+ this.section = new ToolSection.View(self, {
+ inputs : options.inputs,
+ cls : 'ui-table-plain'
+ });
+
+ // switch to classic tool form mako if the form definition is incompatible
+ if (this.incompatible) {
+ this.$el.hide();
+ $('#tool-form-classic').show();
+ return;
+ }
+
+ // create portlet
+ this.portlet = new Portlet.View({
+ icon : 'fa-wrench',
+ title : '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Tool Version ' + options.version + ')',
+ cls : 'ui-portlet-slim',
+ operations: {
+ requirements : requirements_button,
+ menu : menu_button,
+ versions : versions_button
+ },
+ buttons : this.buttons
+ });
+
+ // append message
+ this.portlet.append(this.message.$el, true);
+
+ // append tool section
+ this.portlet.append(this.section.$el);
+
+ // start form
+ this.$el.empty();
+ this.$el.append(this.portlet.$el);
+
+ // append help
+ if (options.help != '') {
+ this.$el.append(ToolTemplate.help(options.help));
+ }
+
+ // append citations
+ if (options.citations) {
+ var $citations = $('<div/>');
+ var citations = new CitationModel.ToolCitationCollection();
+ citations.tool_id = options.id;
+ var citation_list_view = new CitationView.CitationListView({ el: $citations, collection: citations } );
+ citation_list_view.render();
+ citations.fetch();
+ this.$el.append($citations);
+ }
+
+ // show message if available in model
+ if (options.message) {
+ this.message.update({
+ persistent : true,
+ status : 'warning',
+ message : options.message
+ });
+ }
+ }
+ });
+});
diff -r d9b038019163bc378b72b675ddb4e1e902384b12 -r 41bad82393f1790013b09851afd6f8914500f7e2 static/scripts/mvc/tools/tools-form-workflow.js
--- /dev/null
+++ b/static/scripts/mvc/tools/tools-form-workflow.js
@@ -0,0 +1,66 @@
+/**
+ This is the main class of the tool form plugin. It is referenced as 'app' in all lower level modules.
+*/
+define(['utils/utils', 'mvc/tools/tools-form-base'],
+ function(Utils, ToolFormBase) {
+
+ // create form view
+ var View = ToolFormBase.extend({
+ initialize: function(options) {
+ this.workflow = true;
+ ToolFormBase.prototype.initialize.call(this, options);
+ },
+
+ /** Builds a new model through api call and recreates the entire form
+ */
+ _buildModel: function() {
+ },
+
+ /** Request a new model for an already created tool form and updates the form inputs
+ */
+ _updateModel: function() {
+ // create the request dictionary
+ var self = this;
+ var current_state = this.tree.finalize();
+
+ // log tool state
+ console.debug('tools-form-workflow::_refreshForm() - Refreshing states.');
+ console.debug(current_state);
+
+ // register process
+ 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;
+
+ // post job
+ Utils.request({
+ type : 'GET',
+ url : model_url,
+ data : current_state,
+ success : function(node) {
+ parent.update_node(node);
+
+ // process completed
+ self.deferred.done(process_id);
+
+ // log success
+ console.debug('tools-form::_refreshForm() - States refreshed.');
+ console.debug(node);
+ },
+ error : function(response) {
+ // process completed
+ self.deferred.done(process_id);
+
+ // log error
+ console.debug('tools-form::_refreshForm() - Refresh request failed.');
+ console.debug(response);
+ }
+ });
+ }
+ });
+
+ return {
+ View: View
+ };
+});
diff -r d9b038019163bc378b72b675ddb4e1e902384b12 -r 41bad82393f1790013b09851afd6f8914500f7e2 static/scripts/packed/mvc/tools/tools-form-base.js
--- /dev/null
+++ b/static/scripts/packed/mvc/tools/tools-form-base.js
@@ -0,0 +1,1 @@
+define(["utils/utils","utils/deferred","mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-content","mvc/tools/tools-section","mvc/tools/tools-tree"],function(g,h,f,k,i,a,d,c,e,j,b){return Backbone.View.extend({initialize:function(l){console.debug(l);var m=parent.Galaxy;if(m&&m.modal){this.modal=m.modal}else{this.modal=new k.Modal.View()}if(m&&m.currUser){this.is_admin=m.currUser.get("is_admin")}else{this.is_admin=false}this.options=l;this.container=this.options.container||"body";this.deferred=new h();this.setElement("<div/>");$(this.container).append(this.$el);this._buildForm()},reciept:function(l){$(this.container).empty();$(this.container).append(l)},highlight:function(m,n,l){var o=this.element_list[m];if(o){o.error(n||"Please verify this parameter.");if(!l){$(this.container).animate({scrollTop:o.$el.offset().top-20},500)}}},_buildForm:function(){var l=this;this.off("refresh");this.off("reset");this.field_list={};this.input_list={};this.element_list={};this.tree=new b(this);this.content=new e(this);var n=this.options;this._renderForm(n);this.tree.finalize();if(!this.workflow&&n.errors){var o=this.tree.matchResponse(n.errors);for(var m in o){this.highlight(m,o[m],true)}}this.on("refresh",function(){l.deferred.reset();l.deferred.execute(function(){l._updateModel()})});this.on("reset",function(){for(var p in this.element_list){this.element_list[p].reset()}})},_renderForm:function(u){var t=this;this.message=new k.Message();var q=new k.ButtonIcon({icon:"fa-info-circle",title:"Requirements",tooltip:"Display tool requirements",onclick:function(){if(!this.visible){this.visible=true;t.message.update({persistent:true,message:c.requirements(u),status:"info"})}else{this.visible=false;t.message.update({message:""})}}});if(!u.requirements||u.requirements.length==0){q.$el.hide()}var m=new k.ButtonMenu({icon:"fa-cubes",title:"Versions",tooltip:"Select another tool version"});if(u.versions&&u.versions.length>1){for(var o in u.versions){var r=u.versions[o];if(r!=u.version){m.addMenu({title:"Switch to "+r,version:r,icon:"fa-cube",onclick:function(){u.id=u.id.replace(u.version,this.version);u.version=this.version;t.deferred.reset();t.deferred.execute(function(){t._buildModel()})}})}}}else{m.$el.hide()}var p=new k.ButtonMenu({icon:"fa-caret-down",title:"Options",tooltip:"View available options"});if(u.biostar_url){p.addMenu({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(u.biostar_url+"/p/new/post/")}});p.addMenu({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(u.biostar_url+"/t/"+u.id+"/")}})}p.addMenu({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",window.location.origin+galaxy_config.root+"root?tool_id="+u.id)}});if(this.is_admin){p.addMenu({icon:"fa-download",title:"Download",tooltip:"Download this tool",onclick:function(){window.location.href=galaxy_config.root+"api/tools/"+u.id+"/download"}})}this.section=new j.View(t,{inputs:u.inputs,cls:"ui-table-plain"});if(this.incompatible){this.$el.hide();$("#tool-form-classic").show();return}this.portlet=new f.View({icon:"fa-wrench",title:"<b>"+u.name+"</b> "+u.description+" (Galaxy Tool Version "+u.version+")",cls:"ui-portlet-slim",operations:{requirements:q,menu:p,versions:m},buttons:this.buttons});this.portlet.append(this.message.$el,true);this.portlet.append(this.section.$el);this.$el.empty();this.$el.append(this.portlet.$el);if(u.help!=""){this.$el.append(c.help(u.help))}if(u.citations){var s=$("<div/>");var l=new i.ToolCitationCollection();l.tool_id=u.id;var n=new a.CitationListView({el:s,collection:l});n.render();l.fetch();this.$el.append(s)}if(u.message){this.message.update({persistent:true,status:"warning",message:u.message})}}})});
\ No newline at end of file
diff -r d9b038019163bc378b72b675ddb4e1e902384b12 -r 41bad82393f1790013b09851afd6f8914500f7e2 static/scripts/packed/mvc/tools/tools-form-workflow.js
--- /dev/null
+++ b/static/scripts/packed/mvc/tools/tools-form-workflow.js
@@ -0,0 +1,1 @@
+define(["utils/utils","mvc/tools/tools-form-base"],function(b,a){var c=a.extend({initialize:function(d){this.workflow=true;a.prototype.initialize.call(this,d)},_buildModel:function(){},_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;b.request({type:"GET",url:f,data:e,success:function(h){parent.update_node(h);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
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/Workflow: Generalize/revise tool model building process, insert form into workflow editor
by commits-noreply@bitbucket.org 11 Jan '15
by commits-noreply@bitbucket.org 11 Jan '15
11 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d9b038019163/
Changeset: d9b038019163
User: guerler
Date: 2015-01-11 17:02:11+00:00
Summary: ToolForm/Workflow: Generalize/revise tool model building process, insert form into workflow editor
Affected #: 36 files
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 client/galaxy/scripts/galaxy.workflow_editor.canvas.js
--- a/client/galaxy/scripts/galaxy.workflow_editor.canvas.js
+++ b/client/galaxy/scripts/galaxy.workflow_editor.canvas.js
@@ -805,7 +805,7 @@
nodeView.addDataOutput( output );
} );
nodeView.render();
- workflow.node_changed( this );
+ workflow.node_changed( this, true);
},
update_field_data : function( data ) {
var node = this;
@@ -1094,9 +1094,9 @@
this.active_node = node;
}
},
- node_changed : function ( node ) {
+ node_changed : function ( node, force ) {
this.has_changes = true;
- if ( this.active_node == node ) {
+ if ( this.active_node == node && (!parent.__NEWTOOLFORM__ || force)) {
// Reactive with new form_html
this.check_changes_in_active_form(); //Force changes to be saved even on new connection (previously dumped)
parent.show_form_for_tool( node.form_html + node.tooltip, node );
@@ -1305,6 +1305,12 @@
return node;
}
+function update_node( data ) {
+ var node = workflow.active_node;
+ if (node) {
+ node.update_field_data(data, true);
+ }
+}
var ext_to_type = null;
var type_to_type = null;
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 client/galaxy/scripts/mvc/tools/tools-form.js
--- a/client/galaxy/scripts/mvc/tools/tools-form.js
+++ b/client/galaxy/scripts/mvc/tools/tools-form.js
@@ -1,79 +1,28 @@
/**
This is the main class of the tool form plugin. It is referenced as 'app' in all lower level modules.
*/
-define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
- 'mvc/citation/citation-model', 'mvc/citation/citation-view',
- 'mvc/tools', 'mvc/tools/tools-template', 'mvc/tools/tools-content', 'mvc/tools/tools-section', 'mvc/tools/tools-tree', 'mvc/tools/tools-jobs'],
- function(Utils, Deferred, Portlet, Ui, CitationModel, CitationView,
- Tools, ToolTemplate, ToolContent, ToolSection, ToolTree, ToolJobs) {
+define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools/tools-jobs'],
+ function(Utils, Ui, ToolFormBase, ToolJobs) {
// create form view
- var View = Backbone.View.extend({
- // base element
- container: 'body',
-
+ var View = ToolFormBase.extend({
// initialize
initialize: function(options) {
- // log options
- console.debug(options);
-
- // link galaxy modal or create one
- var galaxy = parent.Galaxy;
- if (galaxy && galaxy.modal) {
- this.modal = galaxy.modal;
- } else {
- this.modal = new Ui.Modal.View();
+ var self = this;
+ this.job_handler = new ToolJobs(this);
+ this.buttons = {
+ execute : new Ui.Button({
+ icon : 'fa-check',
+ tooltip : 'Execute: ' + options.name,
+ title : 'Execute',
+ cls : 'btn btn-primary',
+ floating : 'clear',
+ onclick : function() {
+ self.job_handler.submit();
+ }
+ })
}
-
- // check if the user is an admin
- if (galaxy && galaxy.currUser) {
- this.is_admin = galaxy.currUser.get('is_admin')
- } else {
- this.is_admin = false;
- }
-
- // link options
- this.options = options;
-
- // create deferred processing queue handler
- // this handler reduces the number of requests to the api by filtering redundant requests
- this.deferred = new Deferred();
-
- // set element
- this.setElement('<div/>');
-
- // add to main element
- $(this.container).append(this.$el);
-
- // build this form
- this._buildForm();
- },
-
- /** Shows the final message (usually upon successful job submission)
- */
- reciept: function($el) {
- $(this.container).empty();
- $(this.container).append($el);
- },
-
- /** Highlight and scroll to input element (currently only used for error notifications)
- */
- highlight: function (input_id, message, silent) {
- // get input field
- var input_element = this.element_list[input_id];
-
- // check input element
- if (input_element) {
- // mark error
- input_element.error(message || 'Please verify this parameter.');
-
- // scroll to first input element
- if (!silent) {
- $(this.container).animate({
- scrollTop: input_element.$el.offset().top - 20
- }, 500);
- }
- }
+ ToolFormBase.prototype.initialize.call(this, options);
},
/** Builds a new model through api call and recreates the entire form
@@ -250,256 +199,6 @@
console.debug(response);
}
});
- },
-
- /** Main tool form build function. This function is called once a new model is available.
- */
- _buildForm: function() {
- // link this
- var self = this;
-
- // reset events
- this.off('refresh');
- this.off('reset');
-
- // reset field list, which contains the input field elements
- this.field_list = {};
-
- // reset sequential input definition list, which contains the input definitions as provided from the api
- this.input_list = {};
-
- // reset input element list, which contains the dom elements of each input element (includes also the input field)
- this.element_list = {};
-
- // creates a tree/json data structure from the input form
- this.tree = new ToolTree(this);
-
- // creates the job handler
- this.job_handler = new ToolJobs(this);
-
- // request history content and build form
- this.content = new ToolContent(this);
-
- // link model options
- var options = this.options;
-
- // create ui elements
- this._renderForm(options);
-
- // rebuild the underlying data structure
- this.tree.finalize();
-
- // show errors
- if (options.errors) {
- var error_messages = this.tree.matchResponse(options.errors);
- for (var input_id in error_messages) {
- this.highlight(input_id, error_messages[input_id], true);
- }
- }
-
- // add refresh listener
- this.on('refresh', function() {
- // by using/reseting the deferred ajax queue the number of redundant calls is reduced
- self.deferred.reset();
- self.deferred.execute(function(){self._updateModel()});
- });
-
- // add reset listener
- this.on('reset', function() {
- for (var i in this.element_list) {
- this.element_list[i].reset();
- }
- });
- },
-
- /** Renders the UI elements required for the form
- */
- _renderForm: function(options) {
- // link this
- var self = this;
-
- // create message view
- this.message = new Ui.Message();
-
- // button for version selection
- var requirements_button = new Ui.ButtonIcon({
- icon : 'fa-info-circle',
- title : 'Requirements',
- tooltip : 'Display tool requirements',
- onclick : function() {
- if (!this.visible) {
- this.visible = true;
- self.message.update({
- persistent : true,
- message : ToolTemplate.requirements(options),
- status : 'info'
- });
- } else {
- this.visible = false;
- self.message.update({
- message : ''
- });
- }
- }
- });
- if (!options.requirements || options.requirements.length == 0) {
- requirements_button.$el.hide();
- }
-
- // button for version selection
- var versions_button = new Ui.ButtonMenu({
- icon : 'fa-cubes',
- title : 'Versions',
- tooltip : 'Select another tool version'
- });
- if (options.versions && options.versions.length > 1) {
- for (var i in options.versions) {
- var version = options.versions[i];
- if (version != options.version) {
- versions_button.addMenu({
- title : 'Switch to ' + version,
- version : version,
- icon : 'fa-cube',
- onclick : function() {
- // here we update the tool version (some tools encode the version also in the id)
- options.id = options.id.replace(options.version, this.version);
- options.version = this.version;
-
- // rebuild the model and form
- self.deferred.reset();
- self.deferred.execute(function(){self._buildModel()});
- }
- });
- }
- }
- } else {
- versions_button.$el.hide();
- }
-
- // button menu
- var menu_button = new Ui.ButtonMenu({
- icon : 'fa-caret-down',
- title : 'Options',
- tooltip : 'View available options'
- });
-
- // configure button selection
- if(options.biostar_url) {
- // add question option
- menu_button.addMenu({
- icon : 'fa-question-circle',
- title : 'Question?',
- tooltip : 'Ask a question about this tool (Biostar)',
- onclick : function() {
- window.open(options.biostar_url + '/p/new/post/');
- }
- });
-
- // create search button
- menu_button.addMenu({
- icon : 'fa-search',
- title : 'Search',
- tooltip : 'Search help for this tool (Biostar)',
- onclick : function() {
- window.open(options.biostar_url + '/t/' + options.id + '/');
- }
- });
- };
-
- // create share button
- menu_button.addMenu({
- icon : 'fa-share',
- title : 'Share',
- tooltip : 'Share this tool',
- onclick : function() {
- prompt('Copy to clipboard: Ctrl+C, Enter', window.location.origin + galaxy_config.root + 'root?tool_id=' + options.id);
- }
- });
-
- // add admin operations
- if (this.is_admin) {
- // create download button
- menu_button.addMenu({
- icon : 'fa-download',
- title : 'Download',
- tooltip : 'Download this tool',
- onclick : function() {
- window.location.href = galaxy_config.root + 'api/tools/' + options.id + '/download';
- }
- });
- }
-
- // create tool form section
- this.section = new ToolSection.View(self, {
- inputs : options.inputs,
- cls : 'ui-table-plain'
- });
-
- // switch to classic tool form mako if the form definition is incompatible
- if (this.incompatible) {
- this.$el.hide();
- $('#tool-form-classic').show();
- return;
- }
-
- // create portlet
- this.portlet = new Portlet.View({
- icon : 'fa-wrench',
- title : '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Tool Version ' + options.version + ')',
- cls : 'ui-portlet-slim',
- operations: {
- requirements : requirements_button,
- menu : menu_button,
- versions : versions_button
- },
- buttons: {
- execute : new Ui.Button({
- icon : 'fa-check',
- tooltip : 'Execute: ' + options.name,
- title : 'Execute',
- cls : 'btn btn-primary',
- floating : 'clear',
- onclick : function() {
- self.job_handler.submit();
- }
- })
- }
- });
-
- // append message
- this.portlet.append(this.message.$el, true);
-
- // append tool section
- this.portlet.append(this.section.$el);
-
- // start form
- this.$el.empty();
- this.$el.append(this.portlet.$el);
-
- // append help
- if (options.help != '') {
- this.$el.append(ToolTemplate.help(options.help));
- }
-
- // append citations
- if (options.citations) {
- var $citations = $('<div/>');
- var citations = new CitationModel.ToolCitationCollection();
- citations.tool_id = options.id;
- var citation_list_view = new CitationView.CitationListView({ el: $citations, collection: citations } );
- citation_list_view.render();
- citations.fetch();
- this.$el.append($citations);
- }
-
- // show message if available in model
- if (options.message) {
- this.message.update({
- persistent : true,
- status : 'warning',
- message : options.message
- });
- }
}
});
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 client/galaxy/scripts/mvc/tools/tools-jobs.js
--- a/client/galaxy/scripts/mvc/tools/tools-jobs.js
+++ b/client/galaxy/scripts/mvc/tools/tools-jobs.js
@@ -98,7 +98,7 @@
}
// validate non-optional fields
- if (!input_def.optional && input_field.validate && !input_field.validate()) {
+ if (!input_def.optional && input_value == null) {
this.app.highlight(input_id);
return false;
}
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 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
@@ -382,6 +382,11 @@
/** Data input field
*/
_fieldData : function(input_def) {
+ if (this.app.workflow) {
+ var extensions = Utils.textify(input_def.extensions.toString());
+ input_def.info = 'Data input \'' + input_def.name + '\' (' + extensions + ')';
+ return this._fieldHidden(input_def);
+ }
var self = this;
return new SelectContent.View(this.app, {
id : 'field-' + input_def.id,
@@ -398,6 +403,14 @@
/** Select/Checkbox/Radio options field
*/
_fieldSelect : function (input_def) {
+ // show text field in workflow
+ if (this.app.workflow && input_def.is_dynamic) {
+ if (!Utils.validate(input_def.value)) {
+ input_def.value = '';
+ }
+ return this._fieldText(input_def);
+ }
+
// configure options fields
var options = [];
for (var i in input_def.options) {
@@ -475,7 +488,8 @@
*/
_fieldHidden : function(input_def) {
return new Ui.Hidden({
- id : 'field-' + input_def.id
+ id : 'field-' + input_def.id,
+ info : input_def.info
});
},
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 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
@@ -36,14 +36,7 @@
this.list = {};
// error messages
- var extensions = options.extensions.toString();
- if (extensions) {
- extensions = extensions.replace(/,/g, ', ');
- var pos = extensions.lastIndexOf(', ');
- if (pos != -1) {
- extensions = extensions.substr(0, pos) + ' or ' + extensions.substr(pos+1);
- }
- }
+ var extensions = Utils.textify(options.extensions);
var hda_error = 'No dataset available.';
if (extensions) {
hda_error = 'No ' + extensions + ' dataset available.';
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 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
@@ -2,7 +2,7 @@
This class maps the tool form dom to an api compatible javascript dictionary.
*/
// dependencies
-define([], function() {
+define(['utils/utils'], function(Utils) {
// tool form tree
return Backbone.Model.extend({
@@ -120,7 +120,7 @@
// handle default value
if (!field.skip) {
- if (input.optional && field.validate && !field.validate()) {
+ if (field.validate && !field.validate(value)) {
value = null;
}
add (job_input_id, input.id, value);
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 client/galaxy/scripts/mvc/ui/ui-misc.js
--- a/client/galaxy/scripts/mvc/ui/ui-misc.js
+++ b/client/galaxy/scripts/mvc/ui/ui-misc.js
@@ -412,7 +412,7 @@
initialize : function(options) {
// configure options
this.options = options;
-
+
// create new element
this.setElement(this._template(this.options));
@@ -425,14 +425,20 @@
// value
value : function (new_val) {
if (new_val !== undefined) {
- this.$el.val(new_val);
+ this.$('hidden').val(new_val);
}
- return this.$el.val();
+ return this.$('hidden').val();
},
// element
_template: function(options) {
- return '<hidden id="' + options.id + '" value="' + options.value + '"/>';
+ var tmpl = '<div id="' + options.id + '" >';
+ if (options.info) {
+ tmpl += '<label>' + options.info + '</label>';
+ }
+ tmpl += '<hidden value="' + options.value + '"/>' +
+ '</div>';
+ return tmpl;
}
});
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 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
@@ -137,16 +137,7 @@
/** Validate the selected option/options
*/
validate: function() {
- var current = this.value();
- if (!(current instanceof Array)) {
- current = [current];
- }
- for (var i in current) {
- if ([null, 'null', undefined].indexOf(current[i]) > -1) {
- return false;
- }
- }
- return true;
+ return Utils.validate(this.value());
},
/** Wait message during request processing
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 client/galaxy/scripts/mvc/ui/ui-select-default.js
--- a/client/galaxy/scripts/mvc/ui/ui-select-default.js
+++ b/client/galaxy/scripts/mvc/ui/ui-select-default.js
@@ -96,16 +96,7 @@
/** Validate the current selection
*/
validate: function() {
- var current = this.value();
- if (!(current instanceof Array)) {
- current = [current];
- }
- for (var i in current) {
- if ([null, 'null', undefined].indexOf(current[i]) > -1) {
- return false;
- }
- }
- return true;
+ return Utils.validate(this.value());
},
/** Return the label/text of the current selection
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 client/galaxy/scripts/utils/utils.js
--- a/client/galaxy/scripts/utils/utils.js
+++ b/client/galaxy/scripts/utils/utils.js
@@ -15,6 +15,40 @@
};
/**
+ * Validate atomic values or list of values
+ * usually used for selectable options
+ * @param{String} value - Value or list to be validated
+ */
+function validate (value) {
+ if (!(value instanceof Array)) {
+ value = [value];
+ }
+ for (var i in value) {
+ if (['None', null, 'null', undefined, 'undefined'].indexOf(value[i]) > -1) {
+ return false;
+ }
+ }
+ return true;
+};
+
+/**
+ * Convert list to pretty string
+ * @param{String} lst - List of strings to be converted in human readable list sentence
+ */
+function textify(lst) {
+ var lst = lst.toString();
+ if (lst) {
+ lst = lst.replace(/,/g, ', ');
+ var pos = lst.lastIndexOf(', ');
+ if (pos != -1) {
+ lst = lst.substr(0, pos) + ' or ' + lst.substr(pos+1);
+ }
+ return lst;
+ }
+ return '';
+};
+
+/**
* Request handler for GET
* @param{String} url - Url request is made to
* @param{Function} success - Callback on success
@@ -212,7 +246,9 @@
time: time,
wrap: wrap,
request: request,
- sanitize: sanitize
+ sanitize: sanitize,
+ textify: textify,
+ validate: validate
};
});
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -33,7 +33,7 @@
from galaxy.tools.actions.data_source import DataSourceToolAction
from galaxy.tools.actions.data_manager import DataManagerToolAction
from galaxy.tools.deps import build_dependency_manager
-from galaxy.tools.parameters import check_param, params_from_strings, params_to_strings
+from galaxy.tools.parameters import params_to_incoming, check_param, params_from_strings, params_to_strings
from galaxy.tools.parameters import output_collect
from galaxy.tools.parameters.basic import (BaseURLToolParameter,
DataToolParameter, HiddenToolParameter, LibraryDatasetToolParameter,
@@ -2073,6 +2073,336 @@
return tool_dict
+ def to_json (self, trans, **kwd):
+ """
+ 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)
+
+ # load job details if provided
+ job = None
+ if job_id:
+ try:
+ job_id = trans.security.decode_id( job_id )
+ job = trans.sa_session.query( trans.app.model.Job ).get( job_id )
+ except Exception, exception:
+ trans.response.status = 500
+ log.error('Failed to retrieve job.')
+ return { 'error': 'Failed to retrieve job.' }
+ elif dataset_id:
+ try:
+ dataset_id = trans.security.decode_id( dataset_id )
+ data = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( dataset_id )
+ if not ( trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), data.dataset ) ):
+ trans.response.status = 500
+ log.error('User has no access to dataset.')
+ return { 'error': 'User has no access to dataset.' }
+ job = data.creating_job
+ if not job:
+ trans.response.status = 500
+ log.error('Creating job not found.')
+ return { 'error': 'Creating job not found.' }
+ except Exception, exception:
+ trans.response.status = 500
+ log.error('Failed to get job information.')
+ return { 'error': 'Failed to get job information.' }
+
+ # load job parameters into incoming
+ tool_message = ''
+ if job:
+ try:
+ job_params = job.get_param_values( trans.app, ignore_errors = True )
+ job_messages = self.check_and_update_param_values( job_params, trans, update_values=False )
+ tool_message = self._compare_tool_version(trans, job)
+ params_to_incoming( kwd, self.inputs, job_params, trans.app )
+ except Exception, exception:
+ trans.response.status = 500
+ return { 'error': str( exception ) }
+
+ # create parameter object
+ params = galaxy.util.Params( kwd, sanitize = False )
+
+ # convert value to jsonifiable value
+ def jsonify(v):
+ # check if value is numeric
+ isnumber = False
+ try:
+ float(v)
+ isnumber = True
+ except Exception:
+ pass
+
+ # fix hda parsing
+ if isinstance(v, trans.app.model.HistoryDatasetAssociation):
+ return {
+ 'id' : trans.security.encode_id(v.id),
+ 'src' : 'hda'
+ }
+ elif isinstance(v, bool):
+ if v is True:
+ return 'true'
+ else:
+ return 'false'
+ elif isinstance(v, basestring) or isnumber:
+ return v
+ else:
+ return None
+
+ # ensures that input dictionary is jsonifiable
+ def sanitize(dict):
+ # get current value
+ value = dict['value'] if 'value' in dict else None
+
+ # jsonify by type
+ if dict['type'] in ['data']:
+ if isinstance(value, list):
+ value = [ jsonify(v) for v in value ]
+ else:
+ value = [ jsonify(value) ]
+ value = { 'values': value }
+ elif isinstance(value, list):
+ value = [ jsonify(v) for v in value ]
+ else:
+ value = jsonify(value)
+
+ # update and return
+ dict['value'] = value
+ return dict
+
+ # initialize state using default parameters
+ def initialize_state(trans, inputs, state, context=None):
+ context = ExpressionContext(state, context)
+ for input in inputs.itervalues():
+ state[input.name] = input.get_initial_value(trans, context)
+
+ # check the current state of a value and update it if necessary
+ def check_state(trans, input, default_value, context):
+ value = default_value
+ error = 'State validation failed.'
+ try:
+ # resolves the inconsistent definition of boolean parameters (see base.py) without modifying shared code
+ if input.type == 'boolean' and isinstance(default_value, basestring):
+ value, error = [util.string_as_bool(default_value), None]
+ else:
+ value, error = check_param(trans, input, default_value, context)
+ except Exception, err:
+ log.error('Checking parameter failed. %s', str(err))
+ pass
+ return [value, error]
+
+ # populates state with incoming url parameters
+ def populate_state(trans, inputs, state, errors, incoming, prefix="", context=None ):
+ context = ExpressionContext(state, context)
+ for input in inputs.itervalues():
+ key = prefix + input.name
+ if input.type == 'repeat':
+ group_state = state[input.name]
+ rep_index = 0
+ del group_state[:]
+ while True:
+ rep_name = "%s_%d" % (key, rep_index)
+ if not any([incoming_key.startswith(rep_name) for incoming_key in incoming.keys()]):
+ break
+ if rep_index < input.max:
+ new_state = {}
+ new_state['__index__'] = rep_index
+ initialize_state(trans, input.inputs, new_state, context)
+ group_state.append(new_state)
+ populate_state(trans, input.inputs, new_state, errors, incoming, prefix=rep_name + "|", context=context)
+ rep_index += 1
+ elif input.type == 'conditional':
+ group_state = state[input.name]
+ group_prefix = "%s|" % ( key )
+ test_param_key = group_prefix + input.test_param.name
+ default_value = incoming.get(test_param_key, group_state.get(input.test_param.name, None))
+ value, error = check_state(trans, input.test_param, default_value, context)
+ if error:
+ errors[test_param_key] = error
+ else:
+ try:
+ current_case = input.get_current_case(value, trans)
+ group_state = state[input.name] = {}
+ initialize_state(trans, input.cases[current_case].inputs, group_state, context)
+ populate_state( trans, input.cases[current_case].inputs, group_state, errors, incoming, prefix=group_prefix, context=context)
+ group_state['__current_case__'] = current_case
+ except Exception, e:
+ errors[test_param_key] = 'The selected case is unavailable/invalid.'
+ pass
+ group_state[input.test_param.name] = value
+ else:
+ default_value = incoming.get(key, state.get(input.name, None))
+ value, error = check_state(trans, input, default_value, context)
+ if error:
+ errors[key] = error
+ state[input.name] = value
+
+ # builds tool model including all attributes
+ def iterate(group_inputs, inputs, state_inputs, other_values=None):
+ other_values = ExpressionContext( state_inputs, other_values )
+ for input_index, input in enumerate( inputs.itervalues() ):
+ # create model dictionary
+ tool_dict = input.to_dict(trans)
+ if tool_dict is None:
+ continue
+
+ # state for subsection/group
+ group_state = state_inputs[input.name]
+
+ # iterate and update values
+ if input.type == 'repeat':
+ group_cache = tool_dict['cache'] = {}
+ for i in range( len( group_state ) ):
+ group_cache[i] = {}
+ iterate( group_cache[i], input.inputs, group_state[i], other_values )
+ elif input.type == 'conditional':
+ if 'test_param' in tool_dict:
+ test_param = tool_dict['test_param']
+ test_param['value'] = jsonify(group_state[test_param['name']])
+ if '__current_case__' in group_state:
+ i = group_state['__current_case__']
+ iterate(tool_dict['cases'][i]['inputs'], input.cases[i].inputs, group_state, other_values)
+ else:
+ # create input dictionary, try to pass other_values if to_dict function supports it e.g. dynamic options
+ try:
+ tool_dict = input.to_dict(trans, other_values=other_values)
+ except Exception:
+ pass
+
+ # identify name
+ input_name = tool_dict.get('name')
+ if input_name:
+ # update input value from tool state
+ if input_name in state_inputs:
+ tool_dict['value'] = state_inputs[input_name]
+
+ # sanitize if value exists
+ tool_dict = sanitize(tool_dict)
+
+ # backup final input dictionary
+ group_inputs[input_index] = tool_dict
+
+ # sanatization for the final tool state
+ def sanitize_state(state):
+ keys = None
+ if isinstance(state, dict):
+ keys = state
+ elif isinstance(state, list):
+ keys = range( len(state) )
+ if keys:
+ for k in keys:
+ if isinstance(state[k], dict) or isinstance(state[k], list):
+ sanitize_state(state[k])
+ else:
+ state[k] = jsonify(state[k])
+
+ # do param translation here, used by datasource tools
+ if self.input_translator:
+ self.input_translator.translate( params )
+
+ # initialize and populate tool state
+ state_inputs = {}
+ state_errors = {}
+ initialize_state(trans, self.inputs, state_inputs)
+ populate_state(trans, self.inputs, state_inputs, state_errors, params.__dict__)
+
+ # create basic tool model
+ tool_model = self.to_dict(trans)
+ tool_model['inputs'] = {}
+
+ # build tool model and tool state
+ iterate(tool_model['inputs'], self.inputs, state_inputs, '')
+
+ # sanitize tool state
+ sanitize_state(state_inputs)
+
+ # load tool help
+ tool_help = ''
+ if self.help:
+ tool_help = self.help
+ tool_help = tool_help.render( static_path=url_for( '/static' ), host_url=url_for('/', qualified=True) )
+ if type( tool_help ) is not unicode:
+ tool_help = unicode( tool_help, 'utf-8')
+
+ # check if citations exist
+ tool_citations = False
+ if self.citations:
+ tool_citations = True
+
+ # get tool versions
+ tool_versions = []
+ tools = self.app.toolbox.get_loaded_tools_by_lineage(self.id)
+ for t in tools:
+ tool_versions.append(t.version)
+
+ ## add information with underlying requirements and their versions
+ tool_requirements = []
+ if self.requirements:
+ for requirement in self.requirements:
+ tool_requirements.append({
+ 'name' : requirement.name,
+ 'version' : requirement.version
+ })
+
+ # add additional properties
+ tool_model.update({
+ 'help' : tool_help,
+ 'citations' : tool_citations,
+ 'biostar_url' : trans.app.config.biostar_url,
+ 'message' : tool_message,
+ 'versions' : tool_versions,
+ 'requirements' : tool_requirements,
+ 'errors' : state_errors,
+ 'state_inputs' : state_inputs
+ })
+
+ # check for errors
+ if 'error' in tool_message:
+ return tool_message
+
+ # return enriched tool model
+ return tool_model
+
+ def _compare_tool_version( self, trans, job ):
+ """
+ Compares a tool version with the tool version from a job (from ToolRunner).
+ """
+ tool_id = job.tool_id
+ tool_version = job.tool_version
+ message = ''
+ try:
+ select_field, tools, tool = self.app.toolbox.get_tool_components( tool_id, tool_version=tool_version, get_loaded_tools_by_lineage=False, set_selected=True )
+ if tool is None:
+ trans.response.status = 500
+ return { 'error': 'This dataset was created by an obsolete tool (%s). Can\'t re-run.' % tool_id }
+ if ( self.id != tool_id and self.old_id != tool_id ) or self.version != tool_version:
+ if self.id == tool_id:
+ if tool_version == None:
+ # for some reason jobs don't always keep track of the tool version.
+ message = ''
+ else:
+ message = 'This job was initially run with tool version "%s", which is currently not available. ' % tool_version
+ if len( tools ) > 1:
+ message += 'You can re-run the job with the selected tool or choose another derivation of the tool.'
+ else:
+ message += 'You can re-run the job with this tool version, which is a derivation of the original tool.'
+ else:
+ if len( tools ) > 1:
+ message = 'This job was initially run with tool version "%s", which is currently not available. ' % tool_version
+ message += 'You can re-run the job with the selected tool or choose another derivation of the tool.'
+ else:
+ message = 'This job was initially run with tool id "%s", version "%s", which is ' % ( tool_id, tool_version )
+ message += 'currently not available. You can re-run the job with this tool, which is a derivation of the original tool.'
+ except Exception, error:
+ trans.response.status = 500
+ return { 'error': str (error) }
+
+ # can't rerun upload, external data sources, et cetera. workflow compatible will proxy this for now
+ #if not self.is_workflow_compatible:
+ # trans.response.status = 500
+ # return { 'error': 'The \'%s\' tool does currently not support re-running.' % self.name }
+ return message
+
def get_default_history_by_trans( self, trans, create=False ):
return trans.get_history( create=create )
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -11,7 +11,7 @@
from galaxy.visualization.genomes import GenomeRegion
from galaxy.util.json import dumps
from galaxy.visualization.data_providers.genome import *
-from galaxy.tools.parameters import params_to_incoming, check_param
+from galaxy.tools.parameters import check_param
from galaxy.tools.parameters import visit_input_values
from galaxy.tools.parameters.meta import expand_meta_parameters
from galaxy.managers.collections_util import dictify_dataset_collection_instance
@@ -85,7 +85,7 @@
if not tool:
trans.response.status = 500
return { 'error': 'Could not find tool with id \'%s\'' % tool_id }
- return self._build_dict(trans, tool, kwd)
+ return tool.to_json(trans, **kwd)
@_future_expose_api
@web.require_admin
@@ -491,308 +491,3 @@
dataset_dict[ 'id' ] = trans.security.encode_id( dataset_dict[ 'id' ] )
dataset_dict[ 'track_config' ] = self.get_new_track_config( trans, output_dataset )
return dataset_dict
-
- def _build_dict(self, trans, tool, kwd={}):
- """
- 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)
-
- # load job details if provided
- job = None
- if job_id:
- try:
- job_id = trans.security.decode_id( job_id )
- job = trans.sa_session.query( trans.app.model.Job ).get( job_id )
- except Exception, exception:
- trans.response.status = 500
- return { 'error': 'Failed to retrieve job.' }
- elif dataset_id:
- try:
- dataset_id = trans.security.decode_id( dataset_id )
- data = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( dataset_id )
- if not ( trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), data.dataset ) ):
- trans.response.status = 500
- return { 'error': 'User has no access to dataset.' }
- job = data.creating_job
- if not job:
- trans.response.status = 500
- return { 'error': 'Creating job not found.' }
- except Exception, exception:
- trans.response.status = 500
- return { 'error': 'Failed to get job information.' }
-
- # load job parameters into incoming
- tool_message = ''
- if job:
- try:
- job_params = job.get_param_values( trans.app, ignore_errors = True )
- job_messages = tool.check_and_update_param_values( job_params, trans, update_values=False )
- tool_message = self._compare_tool_version(trans, tool, job)
- params_to_incoming( kwd, tool.inputs, job_params, trans.app )
- except Exception, exception:
- trans.response.status = 500
- return { 'error': str( exception ) }
-
- # create parameter object
- params = galaxy.util.Params( kwd, sanitize = False )
-
- # convert value to jsonifiable value
- def convert(v):
- # check if value is numeric
- isnumber = False
- try:
- float(v)
- isnumber = True
- except Exception:
- pass
-
- # fix hda parsing
- if isinstance(v, HistoryDatasetAssociation):
- return {
- 'id' : trans.security.encode_id(v.id),
- 'src' : 'hda'
- }
- elif isinstance(v, bool):
- if v is True:
- return 'true'
- else:
- return 'false'
- elif isinstance(v, basestring) or isnumber:
- return v
- else:
- return None
-
- # ensures that input dictionary is jsonifiable
- def sanitize(dict):
- # get current value
- value = dict['value'] if 'value' in dict else None
-
- # identify lists
- if dict['type'] in ['data']:
- if isinstance(value, list):
- value = [ convert(v) for v in value ]
- else:
- value = [ convert(value) ]
- value = {
- 'batch' : dict['multiple'],
- 'values' : value
- }
- elif isinstance(value, list):
- value = [ convert(v) for v in value ]
- else:
- value = convert(value)
-
- # update and return
- dict['value'] = value
- return dict
-
- # initialize state using default parameters
- def initialize_state(trans, inputs, state, context=None):
- context = ExpressionContext(state, context)
- for input in inputs.itervalues():
- state[input.name] = input.get_initial_value(trans, context)
-
- # check the current state of a value and update it if necessary
- def check_state(trans, input, default_value, context):
- value = default_value
- error = 'State validation failed.'
- try:
- # resolves the inconsistent definition of boolean parameters (see base.py) without modifying shared code
- if input.type == 'boolean' and isinstance(default_value, basestring):
- value, error = [util.string_as_bool(default_value), None]
- else:
- value, error = check_param(trans, input, default_value, context)
- except Exception:
- log.error('Checking parameter %s failed.', input.name)
- pass
- return [value, error]
-
- # populates state with incoming url parameters
- def populate_state(trans, inputs, state, errors, incoming, prefix="", context=None ):
- context = ExpressionContext(state, context)
- for input in inputs.itervalues():
- key = prefix + input.name
- if input.type == 'repeat':
- group_state = state[input.name]
- rep_index = 0
- del group_state[:]
- while True:
- rep_name = "%s_%d" % (key, rep_index)
- if not any([incoming_key.startswith(rep_name) for incoming_key in incoming.keys()]):
- break
- if rep_index < input.max:
- new_state = {}
- new_state['__index__'] = rep_index
- initialize_state(trans, input.inputs, new_state, context)
- group_state.append(new_state)
- populate_state(trans, input.inputs, new_state, errors, incoming, prefix=rep_name + "|", context=context)
- rep_index += 1
- elif input.type == 'conditional':
- group_state = state[input.name]
- group_prefix = "%s|" % ( key )
- test_param_key = group_prefix + input.test_param.name
- default_value = incoming.get(test_param_key, group_state.get(input.test_param.name, None))
- value, error = check_state(trans, input.test_param, default_value, context)
- if error:
- errors[test_param_key] = error
- else:
- current_case = input.get_current_case(value, trans)
- group_state = state[input.name] = {}
- initialize_state(trans, input.cases[current_case].inputs, group_state, context)
- populate_state( trans, input.cases[current_case].inputs, group_state, errors, incoming, prefix=group_prefix, context=context)
- group_state['__current_case__'] = current_case
- group_state[input.test_param.name] = value
- else:
- default_value = incoming.get(key, state.get(input.name, None))
- value, error = check_state(trans, input, default_value, context)
- if error:
- errors[key] = error
- state[input.name] = value
-
- # builds tool model including all attributes
- def iterate(group_inputs, inputs, tool_state, other_values=None):
- other_values = ExpressionContext( tool_state, other_values )
- for input_index, input in enumerate( inputs.itervalues() ):
- # create model dictionary
- group_inputs[input_index] = input.to_dict(trans)
- if group_inputs[input_index] is None:
- continue
-
- # identify stat for subsection/group
- group_state = tool_state[input.name]
-
- # iterate and update values
- if input.type == 'repeat':
- group_cache = group_inputs[input_index]['cache'] = {}
- for i in range( len( group_state ) ):
- group_cache[i] = {}
- iterate( group_cache[i], input.inputs, group_state[i], other_values )
- elif input.type == 'conditional':
- try:
- test_param = group_inputs[input_index]['test_param']
- test_param['value'] = convert(group_state[test_param['name']])
- except Exception:
- pass
- i = group_state['__current_case__']
- iterate(group_inputs[input_index]['cases'][i]['inputs'], input.cases[i].inputs, group_state, other_values)
- else:
- # create input dictionary, try to pass other_values if to_dict function supports it e.g. dynamic options
- try:
- group_inputs[input_index] = input.to_dict(trans, other_values=other_values)
- except Exception:
- pass
-
- # update input value from tool state
- try:
- group_inputs[input_index]['value'] = tool_state[group_inputs[input_index]['name']]
- except Exception:
- pass
-
- # sanitize if value exists
- if group_inputs[input_index]['value']:
- group_inputs[input_index] = sanitize(group_inputs[input_index])
-
- # do param translation here, used by datasource tools
- if tool.input_translator:
- tool.input_translator.translate( params )
-
- # create tool state
- state_inputs = {}
- state_errors = {}
- initialize_state(trans, tool.inputs, state_inputs)
- populate_state(trans, tool.inputs, state_inputs, state_errors, params.__dict__)
-
- # create basic tool model
- tool_model = tool.to_dict(trans)
- tool_model['inputs'] = {}
-
- # build tool model
- iterate(tool_model['inputs'], tool.inputs, state_inputs, '')
-
- # load tool help
- tool_help = ''
- if tool.help:
- tool_help = tool.help
- tool_help = tool_help.render( static_path=web.url_for( '/static' ), host_url=web.url_for('/', qualified=True) )
- if type( tool_help ) is not unicode:
- tool_help = unicode( tool_help, 'utf-8')
-
- # check if citations exist
- tool_citations = False
- if tool.citations:
- tool_citations = True
-
- # get tool versions
- tool_versions = []
- tools = self.app.toolbox.get_loaded_tools_by_lineage(tool.id)
- for t in tools:
- tool_versions.append(t.version)
-
- ## add information with underlying requirements and their versions
- tool_requirements = []
- if tool.requirements:
- for requirement in tool.requirements:
- tool_requirements.append({
- 'name' : requirement.name,
- 'version' : requirement.version
- })
-
- # add additional properties
- tool_model.update({
- 'help' : tool_help,
- 'citations' : tool_citations,
- 'biostar_url' : trans.app.config.biostar_url,
- 'message' : tool_message,
- 'versions' : tool_versions,
- 'requirements' : tool_requirements,
- 'errors' : state_errors
- })
-
- # check for errors
- if 'error' in tool_message:
- return tool_message
-
- # return enriched tool model
- return tool_model
-
- def _compare_tool_version( self, trans, tool, job ):
- """
- Compares a tool version with the tool version from a job (from ToolRunner).
- """
- tool_id = job.tool_id
- tool_version = job.tool_version
- message = ''
- try:
- select_field, tools, tool = self.app.toolbox.get_tool_components( tool_id, tool_version=tool_version, get_loaded_tools_by_lineage=False, set_selected=True )
- if tool is None:
- trans.response.status = 500
- return { 'error': 'This dataset was created by an obsolete tool (%s). Can\'t re-run.' % tool_id }
- if ( tool.id != tool_id and tool.old_id != tool_id ) or tool.version != tool_version:
- if tool.id == tool_id:
- if tool_version == None:
- # for some reason jobs don't always keep track of the tool version.
- message = ''
- else:
- message = 'This job was initially run with tool version "%s", which is currently not available. ' % tool_version
- if len( tools ) > 1:
- message += 'You can re-run the job with the selected tool or choose another derivation of the tool.'
- else:
- message += 'You can re-run the job with this tool version, which is a derivation of the original tool.'
- else:
- if len( tools ) > 1:
- message = 'This job was initially run with tool version "%s", which is currently not available. ' % tool_version
- message += 'You can re-run the job with the selected tool or choose another derivation of the tool.'
- else:
- message = 'This job was initially run with tool id "%s", version "%s", which is ' % ( tool_id, tool_version )
- message += 'currently not available. You can re-run the job with this tool, which is a derivation of the original tool.'
- except Exception, error:
- trans.response.status = 500
- return { 'error': str (error) }
-
- # can't rerun upload, external data sources, et cetera. workflow compatible will proxy this for now
- if not tool.is_workflow_compatible:
- trans.response.status = 500
- return { 'error': 'The \'%s\' tool does currently not support re-running.' % tool.name }
- return message
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -4,6 +4,7 @@
import os
import sgmllib
import urllib2
+import copy
from sqlalchemy import and_
from tool_shed.util import common_util
@@ -609,16 +610,26 @@
is selected.
"""
+ tool_state = incoming.pop('tool_state', None)
trans.workflow_building_mode = True
module = module_factory.from_dict( trans, {
'type': type,
'tool_id': tool_id,
- 'tool_state': incoming.pop("tool_state")
+ 'tool_state': tool_state
} )
+
+ # create tool model and default tool state (if missing)
+ tool_model = None
+ if not tool_state:
+ tool_model = module.tool.to_json(trans, **incoming)
+ module.state.inputs = copy.deepcopy(tool_model['state_inputs'])
+
+ # update module state
module.update_state( incoming )
-
+
if type == 'tool':
return {
+ 'tool_model': tool_model,
'tool_state': module.get_state(),
'data_inputs': module.get_data_inputs(),
'data_outputs': module.get_data_outputs(),
@@ -653,6 +664,7 @@
'name': module.get_name(),
'tool_id': module.get_tool_id(),
'tool_state': module.get_state(),
+ 'tool_model': module.tool.to_json(trans),
'tooltip': module.get_tooltip( static_path=url_for( '/static' ) ),
'data_inputs': module.get_data_inputs(),
'data_outputs': module.get_data_outputs(),
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -18,7 +18,7 @@
from galaxy.web.framework import formbuilder
from galaxy.jobs.actions.post import ActionBox
from galaxy.model import PostJobAction
-from galaxy.tools.parameters import check_param, DataToolParameter, DummyDataset, RuntimeValue, visit_input_values
+from galaxy.tools.parameters import params_to_incoming, check_param, DataToolParameter, DummyDataset, RuntimeValue, visit_input_values
from galaxy.tools.parameters import DataCollectionToolParameter
from galaxy.tools.parameters.wrapped import make_dict_copy
from galaxy.tools.execute import execute
@@ -509,7 +509,8 @@
message = "%s: using version '%s' instead of version '%s' indicated in this workflow." % ( tool_id, d.get( 'tool_version', 'Unspecified' ), module.get_tool_version() )
log.debug(message)
module.version_changes.append(message)
- module.state.decode( d[ "tool_state" ], module.tool, module.trans.app, secure=secure )
+ if d[ "tool_state" ]:
+ module.state.decode( d[ "tool_state" ], module.tool, module.trans.app, secure=secure )
module.errors = d.get( "tool_errors", None )
module.post_job_actions = d.get( "post_job_actions", {} )
module.workflow_outputs = d.get( "workflow_outputs", [] )
@@ -687,7 +688,7 @@
def get_config_form( self ):
self.add_dummy_datasets()
- return self.trans.fill_template( "workflow/editor_tool_form.mako",
+ return self.trans.fill_template( "workflow/editor_tool_form.mako", module=self,
tool=self.tool, values=self.state.inputs, errors=( self.errors or {} ) )
def encode_runtime_state( self, trans, state ):
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 static/scripts/galaxy.workflow_editor.canvas.js
--- a/static/scripts/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/galaxy.workflow_editor.canvas.js
@@ -805,7 +805,7 @@
nodeView.addDataOutput( output );
} );
nodeView.render();
- workflow.node_changed( this );
+ workflow.node_changed( this, true);
},
update_field_data : function( data ) {
var node = this;
@@ -1094,9 +1094,9 @@
this.active_node = node;
}
},
- node_changed : function ( node ) {
+ node_changed : function ( node, force ) {
this.has_changes = true;
- if ( this.active_node == node ) {
+ if ( this.active_node == node && (!parent.__NEWTOOLFORM__ || force)) {
// Reactive with new form_html
this.check_changes_in_active_form(); //Force changes to be saved even on new connection (previously dumped)
parent.show_form_for_tool( node.form_html + node.tooltip, node );
@@ -1305,6 +1305,12 @@
return node;
}
+function update_node( data ) {
+ var node = workflow.active_node;
+ if (node) {
+ node.update_field_data(data, true);
+ }
+}
var ext_to_type = null;
var type_to_type = null;
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 static/scripts/mvc/tools/tools-form.js
--- a/static/scripts/mvc/tools/tools-form.js
+++ b/static/scripts/mvc/tools/tools-form.js
@@ -1,79 +1,28 @@
/**
This is the main class of the tool form plugin. It is referenced as 'app' in all lower level modules.
*/
-define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
- 'mvc/citation/citation-model', 'mvc/citation/citation-view',
- 'mvc/tools', 'mvc/tools/tools-template', 'mvc/tools/tools-content', 'mvc/tools/tools-section', 'mvc/tools/tools-tree', 'mvc/tools/tools-jobs'],
- function(Utils, Deferred, Portlet, Ui, CitationModel, CitationView,
- Tools, ToolTemplate, ToolContent, ToolSection, ToolTree, ToolJobs) {
+define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools/tools-jobs'],
+ function(Utils, Ui, ToolFormBase, ToolJobs) {
// create form view
- var View = Backbone.View.extend({
- // base element
- container: 'body',
-
+ var View = ToolFormBase.extend({
// initialize
initialize: function(options) {
- // log options
- console.debug(options);
-
- // link galaxy modal or create one
- var galaxy = parent.Galaxy;
- if (galaxy && galaxy.modal) {
- this.modal = galaxy.modal;
- } else {
- this.modal = new Ui.Modal.View();
+ var self = this;
+ this.job_handler = new ToolJobs(this);
+ this.buttons = {
+ execute : new Ui.Button({
+ icon : 'fa-check',
+ tooltip : 'Execute: ' + options.name,
+ title : 'Execute',
+ cls : 'btn btn-primary',
+ floating : 'clear',
+ onclick : function() {
+ self.job_handler.submit();
+ }
+ })
}
-
- // check if the user is an admin
- if (galaxy && galaxy.currUser) {
- this.is_admin = galaxy.currUser.get('is_admin')
- } else {
- this.is_admin = false;
- }
-
- // link options
- this.options = options;
-
- // create deferred processing queue handler
- // this handler reduces the number of requests to the api by filtering redundant requests
- this.deferred = new Deferred();
-
- // set element
- this.setElement('<div/>');
-
- // add to main element
- $(this.container).append(this.$el);
-
- // build this form
- this._buildForm();
- },
-
- /** Shows the final message (usually upon successful job submission)
- */
- reciept: function($el) {
- $(this.container).empty();
- $(this.container).append($el);
- },
-
- /** Highlight and scroll to input element (currently only used for error notifications)
- */
- highlight: function (input_id, message, silent) {
- // get input field
- var input_element = this.element_list[input_id];
-
- // check input element
- if (input_element) {
- // mark error
- input_element.error(message || 'Please verify this parameter.');
-
- // scroll to first input element
- if (!silent) {
- $(this.container).animate({
- scrollTop: input_element.$el.offset().top - 20
- }, 500);
- }
- }
+ ToolFormBase.prototype.initialize.call(this, options);
},
/** Builds a new model through api call and recreates the entire form
@@ -250,256 +199,6 @@
console.debug(response);
}
});
- },
-
- /** Main tool form build function. This function is called once a new model is available.
- */
- _buildForm: function() {
- // link this
- var self = this;
-
- // reset events
- this.off('refresh');
- this.off('reset');
-
- // reset field list, which contains the input field elements
- this.field_list = {};
-
- // reset sequential input definition list, which contains the input definitions as provided from the api
- this.input_list = {};
-
- // reset input element list, which contains the dom elements of each input element (includes also the input field)
- this.element_list = {};
-
- // creates a tree/json data structure from the input form
- this.tree = new ToolTree(this);
-
- // creates the job handler
- this.job_handler = new ToolJobs(this);
-
- // request history content and build form
- this.content = new ToolContent(this);
-
- // link model options
- var options = this.options;
-
- // create ui elements
- this._renderForm(options);
-
- // rebuild the underlying data structure
- this.tree.finalize();
-
- // show errors
- if (options.errors) {
- var error_messages = this.tree.matchResponse(options.errors);
- for (var input_id in error_messages) {
- this.highlight(input_id, error_messages[input_id], true);
- }
- }
-
- // add refresh listener
- this.on('refresh', function() {
- // by using/reseting the deferred ajax queue the number of redundant calls is reduced
- self.deferred.reset();
- self.deferred.execute(function(){self._updateModel()});
- });
-
- // add reset listener
- this.on('reset', function() {
- for (var i in this.element_list) {
- this.element_list[i].reset();
- }
- });
- },
-
- /** Renders the UI elements required for the form
- */
- _renderForm: function(options) {
- // link this
- var self = this;
-
- // create message view
- this.message = new Ui.Message();
-
- // button for version selection
- var requirements_button = new Ui.ButtonIcon({
- icon : 'fa-info-circle',
- title : 'Requirements',
- tooltip : 'Display tool requirements',
- onclick : function() {
- if (!this.visible) {
- this.visible = true;
- self.message.update({
- persistent : true,
- message : ToolTemplate.requirements(options),
- status : 'info'
- });
- } else {
- this.visible = false;
- self.message.update({
- message : ''
- });
- }
- }
- });
- if (!options.requirements || options.requirements.length == 0) {
- requirements_button.$el.hide();
- }
-
- // button for version selection
- var versions_button = new Ui.ButtonMenu({
- icon : 'fa-cubes',
- title : 'Versions',
- tooltip : 'Select another tool version'
- });
- if (options.versions && options.versions.length > 1) {
- for (var i in options.versions) {
- var version = options.versions[i];
- if (version != options.version) {
- versions_button.addMenu({
- title : 'Switch to ' + version,
- version : version,
- icon : 'fa-cube',
- onclick : function() {
- // here we update the tool version (some tools encode the version also in the id)
- options.id = options.id.replace(options.version, this.version);
- options.version = this.version;
-
- // rebuild the model and form
- self.deferred.reset();
- self.deferred.execute(function(){self._buildModel()});
- }
- });
- }
- }
- } else {
- versions_button.$el.hide();
- }
-
- // button menu
- var menu_button = new Ui.ButtonMenu({
- icon : 'fa-caret-down',
- title : 'Options',
- tooltip : 'View available options'
- });
-
- // configure button selection
- if(options.biostar_url) {
- // add question option
- menu_button.addMenu({
- icon : 'fa-question-circle',
- title : 'Question?',
- tooltip : 'Ask a question about this tool (Biostar)',
- onclick : function() {
- window.open(options.biostar_url + '/p/new/post/');
- }
- });
-
- // create search button
- menu_button.addMenu({
- icon : 'fa-search',
- title : 'Search',
- tooltip : 'Search help for this tool (Biostar)',
- onclick : function() {
- window.open(options.biostar_url + '/t/' + options.id + '/');
- }
- });
- };
-
- // create share button
- menu_button.addMenu({
- icon : 'fa-share',
- title : 'Share',
- tooltip : 'Share this tool',
- onclick : function() {
- prompt('Copy to clipboard: Ctrl+C, Enter', window.location.origin + galaxy_config.root + 'root?tool_id=' + options.id);
- }
- });
-
- // add admin operations
- if (this.is_admin) {
- // create download button
- menu_button.addMenu({
- icon : 'fa-download',
- title : 'Download',
- tooltip : 'Download this tool',
- onclick : function() {
- window.location.href = galaxy_config.root + 'api/tools/' + options.id + '/download';
- }
- });
- }
-
- // create tool form section
- this.section = new ToolSection.View(self, {
- inputs : options.inputs,
- cls : 'ui-table-plain'
- });
-
- // switch to classic tool form mako if the form definition is incompatible
- if (this.incompatible) {
- this.$el.hide();
- $('#tool-form-classic').show();
- return;
- }
-
- // create portlet
- this.portlet = new Portlet.View({
- icon : 'fa-wrench',
- title : '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Tool Version ' + options.version + ')',
- cls : 'ui-portlet-slim',
- operations: {
- requirements : requirements_button,
- menu : menu_button,
- versions : versions_button
- },
- buttons: {
- execute : new Ui.Button({
- icon : 'fa-check',
- tooltip : 'Execute: ' + options.name,
- title : 'Execute',
- cls : 'btn btn-primary',
- floating : 'clear',
- onclick : function() {
- self.job_handler.submit();
- }
- })
- }
- });
-
- // append message
- this.portlet.append(this.message.$el, true);
-
- // append tool section
- this.portlet.append(this.section.$el);
-
- // start form
- this.$el.empty();
- this.$el.append(this.portlet.$el);
-
- // append help
- if (options.help != '') {
- this.$el.append(ToolTemplate.help(options.help));
- }
-
- // append citations
- if (options.citations) {
- var $citations = $('<div/>');
- var citations = new CitationModel.ToolCitationCollection();
- citations.tool_id = options.id;
- var citation_list_view = new CitationView.CitationListView({ el: $citations, collection: citations } );
- citation_list_view.render();
- citations.fetch();
- this.$el.append($citations);
- }
-
- // show message if available in model
- if (options.message) {
- this.message.update({
- persistent : true,
- status : 'warning',
- message : options.message
- });
- }
}
});
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 static/scripts/mvc/tools/tools-jobs.js
--- a/static/scripts/mvc/tools/tools-jobs.js
+++ b/static/scripts/mvc/tools/tools-jobs.js
@@ -98,7 +98,7 @@
}
// validate non-optional fields
- if (!input_def.optional && input_field.validate && !input_field.validate()) {
+ if (!input_def.optional && input_value == null) {
this.app.highlight(input_id);
return false;
}
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 static/scripts/mvc/tools/tools-section.js
--- a/static/scripts/mvc/tools/tools-section.js
+++ b/static/scripts/mvc/tools/tools-section.js
@@ -382,6 +382,11 @@
/** Data input field
*/
_fieldData : function(input_def) {
+ if (this.app.workflow) {
+ var extensions = Utils.textify(input_def.extensions.toString());
+ input_def.info = 'Data input \'' + input_def.name + '\' (' + extensions + ')';
+ return this._fieldHidden(input_def);
+ }
var self = this;
return new SelectContent.View(this.app, {
id : 'field-' + input_def.id,
@@ -398,6 +403,14 @@
/** Select/Checkbox/Radio options field
*/
_fieldSelect : function (input_def) {
+ // show text field in workflow
+ if (this.app.workflow && input_def.is_dynamic) {
+ if (!Utils.validate(input_def.value)) {
+ input_def.value = '';
+ }
+ return this._fieldText(input_def);
+ }
+
// configure options fields
var options = [];
for (var i in input_def.options) {
@@ -475,7 +488,8 @@
*/
_fieldHidden : function(input_def) {
return new Ui.Hidden({
- id : 'field-' + input_def.id
+ id : 'field-' + input_def.id,
+ info : input_def.info
});
},
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 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
@@ -36,14 +36,7 @@
this.list = {};
// error messages
- var extensions = options.extensions.toString();
- if (extensions) {
- extensions = extensions.replace(/,/g, ', ');
- var pos = extensions.lastIndexOf(', ');
- if (pos != -1) {
- extensions = extensions.substr(0, pos) + ' or ' + extensions.substr(pos+1);
- }
- }
+ var extensions = Utils.textify(options.extensions);
var hda_error = 'No dataset available.';
if (extensions) {
hda_error = 'No ' + extensions + ' dataset available.';
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 static/scripts/mvc/tools/tools-tree.js
--- a/static/scripts/mvc/tools/tools-tree.js
+++ b/static/scripts/mvc/tools/tools-tree.js
@@ -2,7 +2,7 @@
This class maps the tool form dom to an api compatible javascript dictionary.
*/
// dependencies
-define([], function() {
+define(['utils/utils'], function(Utils) {
// tool form tree
return Backbone.Model.extend({
@@ -120,7 +120,7 @@
// handle default value
if (!field.skip) {
- if (input.optional && field.validate && !field.validate()) {
+ if (field.validate && !field.validate(value)) {
value = null;
}
add (job_input_id, input.id, value);
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 static/scripts/mvc/ui/ui-misc.js
--- a/static/scripts/mvc/ui/ui-misc.js
+++ b/static/scripts/mvc/ui/ui-misc.js
@@ -412,7 +412,7 @@
initialize : function(options) {
// configure options
this.options = options;
-
+
// create new element
this.setElement(this._template(this.options));
@@ -425,14 +425,20 @@
// value
value : function (new_val) {
if (new_val !== undefined) {
- this.$el.val(new_val);
+ this.$('hidden').val(new_val);
}
- return this.$el.val();
+ return this.$('hidden').val();
},
// element
_template: function(options) {
- return '<hidden id="' + options.id + '" value="' + options.value + '"/>';
+ var tmpl = '<div id="' + options.id + '" >';
+ if (options.info) {
+ tmpl += '<label>' + options.info + '</label>';
+ }
+ tmpl += '<hidden value="' + options.value + '"/>' +
+ '</div>';
+ return tmpl;
}
});
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 static/scripts/mvc/ui/ui-options.js
--- a/static/scripts/mvc/ui/ui-options.js
+++ b/static/scripts/mvc/ui/ui-options.js
@@ -137,16 +137,7 @@
/** Validate the selected option/options
*/
validate: function() {
- var current = this.value();
- if (!(current instanceof Array)) {
- current = [current];
- }
- for (var i in current) {
- if ([null, 'null', undefined].indexOf(current[i]) > -1) {
- return false;
- }
- }
- return true;
+ return Utils.validate(this.value());
},
/** Wait message during request processing
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 static/scripts/mvc/ui/ui-select-default.js
--- a/static/scripts/mvc/ui/ui-select-default.js
+++ b/static/scripts/mvc/ui/ui-select-default.js
@@ -96,16 +96,7 @@
/** Validate the current selection
*/
validate: function() {
- var current = this.value();
- if (!(current instanceof Array)) {
- current = [current];
- }
- for (var i in current) {
- if ([null, 'null', undefined].indexOf(current[i]) > -1) {
- return false;
- }
- }
- return true;
+ return Utils.validate(this.value());
},
/** Return the label/text of the current selection
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 static/scripts/packed/galaxy.workflow_editor.canvas.js
--- a/static/scripts/packed/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/packed/galaxy.workflow_editor.canvas.js
@@ -1,1 +1,1 @@
-function CollectionTypeDescription(a){this.collectionType=a;this.isCollection=true;this.rank=a.split(":").length}$.extend(CollectionTypeDescription.prototype,{append:function(a){if(a===NULL_COLLECTION_TYPE_DESCRIPTION){return this}if(a===ANY_COLLECTION_TYPE_DESCRIPTION){return otherCollectionType}return new CollectionTypeDescription(this.collectionType+":"+a.collectionType)},canMatch:function(a){if(a===NULL_COLLECTION_TYPE_DESCRIPTION){return false}if(a===ANY_COLLECTION_TYPE_DESCRIPTION){return true}return a.collectionType==this.collectionType},canMapOver:function(b){if(b===NULL_COLLECTION_TYPE_DESCRIPTION){return false}if(b===ANY_COLLECTION_TYPE_DESCRIPTION){return false}if(this.rank<=b.rank){return false}var a=b.collectionType;return this._endsWith(this.collectionType,a)},effectiveMapOver:function(a){var c=a.collectionType;var b=this.collectionType.substring(0,this.collectionType.length-c.length-1);return new CollectionTypeDescription(b)},equal:function(a){return a.collectionType==this.collectionType},toString:function(){return"CollectionType["+this.collectionType+"]"},_endsWith:function(b,a){return b.indexOf(a,b.length-a.length)!==-1}});NULL_COLLECTION_TYPE_DESCRIPTION={isCollection:false,canMatch:function(a){return false},canMapOver:function(a){return false},toString:function(){return"NullCollectionType[]"},append:function(a){return a},equal:function(a){return a===this}};ANY_COLLECTION_TYPE_DESCRIPTION={isCollection:true,canMatch:function(a){return NULL_COLLECTION_TYPE_DESCRIPTION!==a},canMapOver:function(a){return false},toString:function(){return"AnyCollectionType[]"},append:function(a){throw"Cannot append to ANY_COLLECTION_TYPE_DESCRIPTION"},equal:function(a){return a===this}};var TerminalMapping=Backbone.Model.extend({initialize:function(a){this.mapOver=a.mapOver||NULL_COLLECTION_TYPE_DESCRIPTION;this.terminal=a.terminal;this.terminal.terminalMapping=this},disableMapOver:function(){this.setMapOver(NULL_COLLECTION_TYPE_DESCRIPTION)},setMapOver:function(a){this.mapOver=a;this.trigger("change")}});var TerminalMappingView=Backbone.View.extend({tagName:"div",className:"fa-icon-button fa fa-folder-o",initialize:function(b){var a="Run tool in parallel over collection";this.$el.tooltip({delay:500,title:a});this.model.bind("change",_.bind(this.render,this))},render:function(){if(this.model.mapOver.isCollection){this.$el.show()}else{this.$el.hide()}},});var InputTerminalMappingView=TerminalMappingView.extend({events:{click:"onClick",mouseenter:"onMouseEnter",mouseleave:"onMouseLeave",},onMouseEnter:function(b){var a=this.model;if(!a.terminal.connected()&&a.mapOver.isCollection){this.$el.css("color","red")}},onMouseLeave:function(a){this.$el.css("color","black")},onClick:function(b){var a=this.model;if(!a.terminal.connected()&&a.mapOver.isCollection){a.terminal.resetMapping()}},});var InputTerminalMapping=TerminalMapping;var InputCollectionTerminalMapping=TerminalMapping;var OutputTerminalMapping=TerminalMapping;var OutputTerminalMappingView=TerminalMappingView;var InputCollectionTerminalMappingView=InputTerminalMappingView;var OutputCollectionTerminalMapping=TerminalMapping;var OutputCollectionTerminalMappingView=TerminalMappingView;var Terminal=Backbone.Model.extend({initialize:function(a){this.element=a.element;this.connectors=[]},connect:function(a){this.connectors.push(a);if(this.node){this.node.markChanged()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.markChanged();this.resetMappingIfNeeded()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})},destroyInvalidConnections:function(){_.each(this.connectors,function(a){a.destroyIfInvalid()})},setMapOver:function(a){if(this.multiple){return}if(!this.mapOver().equal(a)){this.terminalMapping.setMapOver(a);_.each(this.node.output_terminals,function(b){b.setMapOver(a)})}},mapOver:function(){if(!this.terminalMapping){return NULL_COLLECTION_TYPE_DESCRIPTION}else{return this.terminalMapping.mapOver}},isMappedOver:function(){return this.terminalMapping&&this.terminalMapping.mapOver.isCollection},resetMapping:function(){this.terminalMapping.disableMapOver()},resetMappingIfNeeded:function(){},});var OutputTerminal=Terminal.extend({initialize:function(a){Terminal.prototype.initialize.call(this,a);this.datatypes=a.datatypes},resetMappingIfNeeded:function(){if(!this.node.hasConnectedOutputTerminals()&&!this.node.hasConnectedMappedInputTerminals()){_.each(this.node.mappedInputTerminals(),function(b){b.resetMappingIfNeeded()})}var a=!this.node.hasMappedOverInputTerminals();if(a){this.resetMapping()}},resetMapping:function(){this.terminalMapping.disableMapOver();_.each(this.connectors,function(a){var b=a.handle2;if(b){b.resetMappingIfNeeded();a.destroyIfInvalid()}})}});var BaseInputTerminal=Terminal.extend({initialize:function(a){Terminal.prototype.initialize.call(this,a);this.update(a.input)},canAccept:function(a){if(this._inputFilled()){return false}else{return this.attachable(a)}},resetMappingIfNeeded:function(){var b=this.mapOver();if(!b.isCollection){return}var a=this.node.hasConnectedMappedInputTerminals()||(!this.node.hasConnectedOutputTerminals());if(a){this.resetMapping()}},resetMapping:function(){this.terminalMapping.disableMapOver();if(!this.node.hasMappedOverInputTerminals()){_.each(this.node.output_terminals,function(a){a.resetMapping()})}},connected:function(){return this.connectors.length!==0},_inputFilled:function(){var a;if(!this.connected()){a=false}else{if(this.multiple){if(this._collectionAttached()){inputsFilled=true}else{a=false}}else{a=true}}return a},_collectionAttached:function(){if(!this.connected()){return false}else{var a=this.connectors[0].handle1;if(!a){return false}else{if(a.isDataCollectionInput||a.isMappedOver()||a.datatypes.indexOf("input_collection")>0){return true}else{return false}}}},_mappingConstraints:function(){if(!this.node){return[]}var b=this.mapOver();if(b.isCollection){return[b]}var a=[];if(!this.node.hasConnectedOutputTerminals()){_.each(this.node.connectedMappedInputTerminals(),function(c){a.push(c.mapOver())})}else{a.push(_.first(_.values(this.node.output_terminals)).mapOver())}return a},_producesAcceptableDatatype:function(a){for(var c in this.datatypes){var f=new Array();f=f.concat(a.datatypes);if(a.node.post_job_actions){for(var d in a.node.post_job_actions){var g=a.node.post_job_actions[d];if(g.action_type=="ChangeDatatypeAction"&&(g.output_name==""||g.output_name==a.name)&&g.action_arguments){f.push(g.action_arguments.newtype)}}}for(var b in f){var h=f[b];if(h=="input"||h=="input_collection"||issubtype(f[b],this.datatypes[c])){return true}}}return false},_otherCollectionType:function(a){var c=NULL_COLLECTION_TYPE_DESCRIPTION;if(a.isDataCollectionInput){c=a.collectionType}else{var b=a.mapOver();if(b.isCollection){c=b}}return c},});var InputTerminal=BaseInputTerminal.extend({update:function(a){this.datatypes=a.extensions;this.multiple=a.multiple;this.collection=false},connect:function(a){BaseInputTerminal.prototype.connect.call(this,a);var b=a.handle1;if(!b){return}var c=this._otherCollectionType(b);if(c.isCollection){this.setMapOver(c)}},attachable:function(b){var d=this._otherCollectionType(b);var a=this.mapOver();if(d.isCollection){if(this.multiple){if(this.connected()&&!this._collectionAttached()){return false}if(d.rank==1){return this._producesAcceptableDatatype(b)}else{return false}}if(a.isCollection&&a.canMatch(d)){return this._producesAcceptableDatatype(b)}else{var c=this._mappingConstraints();if(c.every(_.bind(d.canMatch,d))){return this._producesAcceptableDatatype(b)}else{return false}}}else{if(a.isCollection){return false}}return this._producesAcceptableDatatype(b)}});var InputCollectionTerminal=BaseInputTerminal.extend({update:function(a){this.multiple=false;this.collection=true;this.datatypes=a.extensions;if(a.collection_type){this.collectionType=new CollectionTypeDescription(a.collection_type)}else{this.collectionType=ANY_COLLECTION_TYPE_DESCRIPTION}},connect:function(b){BaseInputTerminal.prototype.connect.call(this,b);var a=b.handle1;if(!a){return}var c=this._effectiveMapOver(a);this.setMapOver(c)},_effectiveMapOver:function(a){var b=this.collectionType;var c=this._otherCollectionType(a);if(!b.canMatch(c)){return c.effectiveMapOver(b)}else{return NULL_COLLECTION_TYPE_DESCRIPTION}},_effectiveCollectionType:function(){var b=this.collectionType;var a=this.mapOver();return a.append(b)},attachable:function(b){var g=this._otherCollectionType(b);if(g.isCollection){var f=this._effectiveCollectionType();var a=this.mapOver();if(f.canMatch(g)){return this._producesAcceptableDatatype(b)}else{if(a.isCollection){return false}else{if(g.canMapOver(this.collectionType)){var d=this._effectiveMapOver(b);if(!d.isCollection){return false}var c=this._mappingConstraints();if(c.every(d.canMatch)){return this._producesAcceptableDatatype(b)}}}}}return false}});var OutputCollectionTerminal=Terminal.extend({initialize:function(a){Terminal.prototype.initialize.call(this,a);this.datatypes=a.datatypes;this.collectionType=new CollectionTypeDescription(a.collection_type);this.isDataCollectionInput=true},update:function(a){var b=new CollectionTypeDescription(a.collection_type);if(b.collectionType!=this.collectionType.collectionType){_.each(this.connectors,function(c){c.destroy()})}this.collectionType=b}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a){this.connect(b,a)}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;if(this.handle1){this.handle1.connect(this)}this.handle2=a;if(this.handle2){this.handle2.connect(this)}},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},destroyIfInvalid:function(){if(this.handle1&&this.handle2&&!this.handle2.attachable(this.handle1)){this.destroy()}},redraw:function(){var f=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}f.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var v=function(c){return $(c).offset().left-f.offset().left};var p=function(c){return $(c).offset().top-f.offset().top};if(!this.handle1||!this.handle2){return}var o=v(this.handle1.element)+5;var n=p(this.handle1.element)+5;var x=v(this.handle2.element)+5;var u=p(this.handle2.element)+5;var k=100;var r=Math.min(o,x);var a=Math.max(o,x);var q=Math.min(n,u);var B=Math.max(n,u);var d=Math.min(Math.max(Math.abs(B-q)/2,100),300);var w=r-k;var A=q-k;var y=a-r+2*k;var s=B-q+2*k;this.canvas.style.left=w+"px";this.canvas.style.top=A+"px";this.canvas.setAttribute("width",y);this.canvas.setAttribute("height",s);o-=w;n-=A;x-=w;u-=A;var z=this.canvas.getContext("2d"),h=null,l=null;var g=1;if(this.handle1&&this.handle1.isMappedOver()){var h=[-6,-3,0,3,6];g=5}else{var h=[0]}if(this.handle2&&this.handle2.isMappedOver()){var l=[-6,-3,0,3,6];g=5}else{var l=[0]}var b=this;for(var t=0;t<g;t++){var m=5,j=7;if(h.length>1||l.length>1){m=1;j=3}b.draw_outlined_curve(o,n,x,u,d,m,j,h[t%h.length],l[t%l.length])}},draw_outlined_curve:function(j,i,l,k,a,b,f,g,d){var g=g||0;var d=d||0;var h=this.canvas.getContext("2d");h.lineCap="round";h.strokeStyle=this.outer_color;h.lineWidth=f;h.beginPath();h.moveTo(j,i+g);h.bezierCurveTo(j+a,i+g,l-a,k+d,l,k+d);h.stroke();h.strokeStyle=this.inner_color;h.lineWidth=b;h.beginPath();h.moveTo(j,i+g);h.bezierCurveTo(j+a,i+g,l-a,k+d,l,k+d);h.stroke()}});var Node=Backbone.Model.extend({initialize:function(a){this.element=a.element;this.input_terminals={};this.output_terminals={};this.tool_errors={}},connectedOutputTerminals:function(){return this._connectedTerminals(this.output_terminals)},_connectedTerminals:function(b){var a=[];$.each(b,function(c,d){if(d.connectors.length>0){a.push(d)}});return a},hasConnectedOutputTerminals:function(){var a=this.output_terminals;for(var b in a){if(a[b].connectors.length>0){return true}}return false},connectedMappedInputTerminals:function(){return this._connectedMappedTerminals(this.input_terminals)},hasConnectedMappedInputTerminals:function(){var c=this.input_terminals;for(var b in c){var a=c[b];if(a.connectors.length>0&&a.isMappedOver()){return true}}return false},_connectedMappedTerminals:function(b){var a=[];$.each(b,function(c,d){var f=d.mapOver();if(f.isCollection){if(d.connectors.length>0){a.push(d)}}});return a},mappedInputTerminals:function(){return this._mappedTerminals(this.input_terminals)},_mappedTerminals:function(b){var a=[];$.each(b,function(c,d){var f=d.mapOver();if(f.isCollection){a.push(d)}});return a},hasMappedOverInputTerminals:function(){var a=false;_.each(this.input_terminals,function(b){var c=b.mapOver();if(c.isCollection){a=true}});return a},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(b){if(b.type){this.type=b.type}this.name=b.name;this.form_html=b.form_html;this.tool_state=b.tool_state;this.tool_errors=b.tool_errors;this.tooltip=b.tooltip?b.tooltip:"";this.annotation=b.annotation;this.post_job_actions=b.post_job_actions?b.post_job_actions:{};this.label=b.label;this.uuid=b.uuid;this.workflow_outputs=b.workflow_outputs?b.workflow_outputs:[];var a=this;var c=new NodeView({el:this.element[0],node:a,});a.nodeView=c;$.each(b.data_inputs,function(f,d){c.addDataInput(d)});if((b.data_inputs.length>0)&&(b.data_outputs.length>0)){c.addRule()}$.each(b.data_outputs,function(f,d){c.addDataOutput(d)});c.render();workflow.node_changed(this)},update_field_data:function(d){var c=this;nodeView=c.nodeView;this.tool_state=d.tool_state;this.form_html=d.form_html;this.tool_errors=d.tool_errors;this.annotation=d.annotation;if("post_job_actions" in d){var f=$.parseJSON(d.post_job_actions);this.post_job_actions=f?f:{}}c.nodeView.renderToolErrors();var g=nodeView.$("div.inputs");var a=nodeView.newInputsDiv();var b={};_.each(d.data_inputs,function(h){var i=c.nodeView.addDataInput(h,a);b[h.name]=i});_.each(_.difference(_.values(nodeView.terminalViews),_.values(b)),function(h){h.el.terminal.destroy()});nodeView.terminalViews=b;if(d.data_outputs.length==1&&"collection_type" in d.data_outputs[0]){nodeView.updateDataOutput(d.data_outputs[0])}g.replaceWith(a);this.markChanged();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},markChanged:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false;this.active_form_has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},rectify_workflow_outputs:function(){var b=false;var a=false;$.each(this.nodes,function(c,d){if(d.workflow_outputs&&d.workflow_outputs.length>0){b=true}$.each(d.post_job_actions,function(g,f){if(f.action_type==="HideDatasetAction"){a=true}})});if(b!==false||a!==false){$.each(this.nodes,function(c,g){if(g.type==="tool"){var f=false;if(g.post_job_actions==null){g.post_job_actions={};f=true}var d=[];$.each(g.post_job_actions,function(i,h){if(h.action_type=="HideDatasetAction"){d.push(i)}});if(d.length>0){$.each(d,function(h,j){f=true;delete g.post_job_actions[j]})}if(b){$.each(g.output_terminals,function(i,j){var h=true;$.each(g.workflow_outputs,function(l,m){if(j.name===m){h=false}});if(h===true){f=true;var k={action_type:"HideDatasetAction",output_name:j.name,action_arguments:{}};g.post_job_actions["HideDatasetAction"+j.name]=null;g.post_job_actions["HideDatasetAction"+j.name]=k}})}if(workflow.active_node==g&&f===true){workflow.reload_active_node()}}})}},to_simple:function(){var a={};$.each(this.nodes,function(c,f){var g={};$.each(f.input_terminals,function(i,j){g[j.name]=null;var h=[];$.each(j.connectors,function(k,l){h[k]={id:l.handle1.node.id,output_name:l.handle1.name};g[j.name]=h})});var b={};if(f.post_job_actions){$.each(f.post_job_actions,function(j,h){var k={action_type:h.action_type,output_name:h.output_name,action_arguments:h.action_arguments};b[h.action_type+h.output_name]=null;b[h.action_type+h.output_name]=k})}if(!f.workflow_outputs){f.workflow_outputs=[]}var d={id:f.id,type:f.type,tool_id:f.tool_id,tool_state:f.tool_state,tool_errors:f.tool_errors,input_connections:g,position:$(f.element).position(),annotation:f.annotation,post_job_actions:f.post_job_actions,uuid:f.uuid,label:f.label,workflow_outputs:f.workflow_outputs};a[f.id]=d});return{steps:a}},from_simple:function(b){wf=this;var c=0;wf.name=b.name;var a=false;$.each(b.steps,function(g,f){var d=prebuild_node(f.type,f.name,f.tool_id);d.init_field_data(f);if(f.position){d.element.css({top:f.position.top,left:f.position.left})}d.id=f.id;wf.nodes[d.id]=d;c=Math.max(c,parseInt(g));if(!a&&d.type==="tool"){if(d.workflow_outputs.length>0){a=true}else{$.each(d.post_job_actions,function(i,h){if(h.action_type==="HideDatasetAction"){a=true}})}}});wf.id_counter=c+1;$.each(b.steps,function(g,f){var d=wf.nodes[g];$.each(f.input_connections,function(i,h){if(h){if(!$.isArray(h)){h=[h]}$.each(h,function(k,j){var m=wf.nodes[j.id];var n=new Connector();n.connect(m.output_terminals[j.output_name],d.input_terminals[i]);n.redraw()})}});if(a&&d.type==="tool"){$.each(d.output_terminals,function(h,i){if(d.post_job_actions["HideDatasetAction"+i.name]===undefined){d.workflow_outputs.push(i.name);callout=$(d.element).find(".callout."+i.name);callout.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png");workflow.has_changes=true}})}})},check_changes_in_active_form:function(){if(this.active_form_has_changes){this.has_changes=true;$("#right-content").find("form").submit();this.active_form_has_changes=false}},reload_active_node:function(){if(this.active_node){var a=this.active_node;this.clear_active_node();this.activate_node(a)}},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.check_changes_in_active_form();this.clear_active_node();parent.show_form_for_tool(a.form_html+a.tooltip,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){this.check_changes_in_active_form();parent.show_form_for_tool(a.form_html+a.tooltip,a)}},layout:function(){this.check_changes_in_active_form();this.has_changes=true;var i={};var b={};$.each(this.nodes,function(l,k){if(i[l]===undefined){i[l]=0}if(b[l]===undefined){b[l]=[]}});$.each(this.nodes,function(l,k){$.each(k.input_terminals,function(m,n){$.each(n.connectors,function(p,q){var o=q.handle1.node;i[k.id]+=1;b[o.id].push(k.id)})})});node_ids_by_level=[];while(true){level_parents=[];for(var a in i){if(i[a]==0){level_parents.push(a)}}if(level_parents.length==0){break}node_ids_by_level.push(level_parents);for(var f in level_parents){var j=level_parents[f];delete i[j];for(var g in b[j]){i[b[j][g]]-=1}}}if(i.length){return}var d=this.nodes;var h=80;v_pad=30;var c=h;$.each(node_ids_by_level,function(k,l){l.sort(function(p,o){return $(d[p].element).position().top-$(d[o].element).position().top});var m=0;var n=v_pad;$.each(l,function(o,r){var q=d[r];var p=$(q.element);$(p).css({top:n,left:c});m=Math.max(m,$(p).width());n+=$(p).height()+v_pad});c+=m+h});$.each(d,function(k,l){l.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(h,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var i=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var h=fix_delta(a.ymin,100);d=Math.max(d,f.left);h=Math.max(h,f.top);var c=f.left-d;var g=f.top-h;var b=round_up(a.xmax+100,100)+d;var j=round_up(a.ymax+100,100)+h;b=Math.max(b,-c+i.width());j=Math.max(j,-g+i.height());this.canvas_container.css({left:c,top:g,width:b,height:j});this.canvas_container.children().each(function(){var k=$(this).position();$(this).css("left",k.left+d);$(this).css("top",k.top+h)})}});function fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(l,j,r){var i=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node({element:i});g.type=l;if(l=="tool"){g.tool_id=r}var n=$("<div class='toolFormTitle unselectable'>"+j+"</div>");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("<div class='toolFormBody'></div>");var h="<div><img height='16' align='middle' src='"+galaxy_config.root+"static/images/loading_small_white_bg.gif'/> loading tool info...</div>";m.append(h);g.form_html=h;i.append(m);var k=$("<div class='buttons' style='float: right;'></div>");k.append($("<div>").addClass("fa-icon-button fa fa-times").click(function(b){g.destroy()}));i.appendTo("#canvas-container");var d=$("#canvas-container").position();var c=$("#canvas-container").parent();var a=i.width();var q=i.height();i.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(q/2)});k.prependTo(n);a+=(k.width()+10);i.css("width",a);$(i).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o,p){var f=$(this).offsetParent().offset(),b=p.offsetX-f.left,s=p.offsetY-f.top;$(this).css({left:b,top:s});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}function add_node(b,d,a){var c=prebuild_node(b,d,a);workflow.add_node(c);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview();workflow.activate_node(c);return c}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}var NodeView=Backbone.View.extend({initialize:function(a){this.node=a.node;this.output_width=Math.max(150,this.$el.width());this.tool_body=this.$el.find(".toolFormBody");this.tool_body.find("div").remove();this.newInputsDiv().appendTo(this.tool_body);this.terminalViews={};this.outputTerminlViews={}},render:function(){this.renderToolErrors();this.$el.css("width",Math.min(250,Math.max(this.$el.width(),this.output_width)))},renderToolErrors:function(){if(this.node.tool_errors){this.$el.addClass("tool-node-error")}else{this.$el.removeClass("tool-node-error")}},newInputsDiv:function(){return $("<div class='inputs'></div>")},updateMaxWidth:function(a){this.output_width=Math.max(this.output_width,a)},addRule:function(){this.tool_body.append($("<div class='rule'></div>"))},addDataInput:function(i,d){var j=true;if(!d){d=this.$(".inputs");j=false}var f=this.terminalViews[i.name];var h=(i.input_type=="dataset_collection")?InputCollectionTerminalView:InputTerminalView;if(f&&!(f instanceof h)){f.el.terminal.destroy();f=null}if(!f){f=new h({node:this.node,input:i})}else{var g=f.el.terminal;g.update(i);g.destroyInvalidConnections()}this.terminalViews[i.name]=f;var c=f.el;var b=new DataInputView({terminalElement:c,input:i,nodeView:this,skipResize:j});var a=b.$el;d.append(a.prepend(f.terminalElements()));return f},addDataOutput:function(a){var d=(a.collection_type)?OutputCollectionTerminalView:OutputTerminalView;var c=new d({node:this.node,output:a});var b=new DataOutputView({output:a,terminalElement:c.el,nodeView:this,});this.tool_body.append(b.$el.append(c.terminalElements()))},updateDataOutput:function(b){var a=this.node.output_terminals[b.name];a.update(b)}});var DataInputView=Backbone.View.extend({className:"form-row dataRow input-data-row",initialize:function(a){this.input=a.input;this.nodeView=a.nodeView;this.terminalElement=a.terminalElement;this.$el.attr("name",this.input.name).html(this.input.label);if(!a.skipResize){this.$el.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(this.el);this.nodeView.updateMaxWidth(this.$el.outerWidth());this.$el.css({position:"",left:"",top:"",display:""});this.$el.remove()}},});var OutputCalloutView=Backbone.View.extend({tagName:"div",initialize:function(b){this.label=b.label;this.node=b.node;this.output=b.output;var a=this;this.$el.attr("class","callout "+this.label).css({display:"none"}).append($("<div class='buttons'></div>").append($("<img/>").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png").click(function(){if($.inArray(a.output.name,a.node.workflow_outputs)!=-1){a.node.workflow_outputs.splice($.inArray(a.output.name,a.node.workflow_outputs),1);a.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{a.node.workflow_outputs.push(a.output.name);a.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}workflow.has_changes=true;canvas_manager.draw_overview()}))).tooltip({delay:500,title:"Mark dataset as a workflow output. All unmarked datasets will be hidden."});this.$el.css({top:"50%",margin:"-8px 0px 0px 0px",right:8});this.$el.show();this.resetImage()},resetImage:function(){if($.inArray(this.output.name,this.node.workflow_outputs)===-1){this.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{this.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}},hoverImage:function(){this.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-yellow.png")}});var DataOutputView=Backbone.View.extend({className:"form-row dataRow",initialize:function(c){this.output=c.output;this.terminalElement=c.terminalElement;this.nodeView=c.nodeView;var a=this.output;var b=a.name;var f=this.nodeView.node;var d=a.extensions.indexOf("input")>=0||a.extensions.indexOf("input_collection")>=0;if(!d){b=b+" ("+a.extensions.join(", ")+")"}this.$el.html(b);if(f.type=="tool"){var g=new OutputCalloutView({label:b,output:a,node:f,});this.$el.append(g.el);this.$el.hover(function(){g.hoverImage()},function(){g.resetImage()})}this.$el.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(this.el);this.nodeView.updateMaxWidth(this.$el.outerWidth()+17);this.$el.css({position:"",left:"",top:"",display:""}).detach()}});var TerminalView=Backbone.View.extend({setupMappingView:function(b){var c=new this.terminalMappingClass({terminal:b});var a=new this.terminalMappingViewClass({model:c});a.render();b.terminalMappingView=a;this.terminalMappingView=a},terminalElements:function(){if(this.terminalMappingView){return[this.terminalMappingView.el,this.el]}else{return[this.el]}}});var BaseInputTerminalView=TerminalView.extend({className:"terminal input-terminal",initialize:function(c){var f=c.node;var a=c.input;var b=a.name;var d=this.terminalForInput(a);if(!d.multiple){this.setupMappingView(d)}this.el.terminal=d;d.node=f;d.name=b;f.input_terminals[b]=d},events:{dropinit:"onDropInit",dropstart:"onDropStart",dropend:"onDropEnd",drop:"onDrop",hover:"onHover",},onDropInit:function(b,c){var a=this.el.terminal;return $(c.drag).hasClass("output-terminal")&&a.canAccept(c.drag.terminal)},onDropStart:function(a,b){if(b.proxy.terminal){b.proxy.terminal.connectors[0].inner_color="#BBFFBB"}},onDropEnd:function(a,b){if(b.proxy.terminal){b.proxy.terminal.connectors[0].inner_color="#FFFFFF"}},onDrop:function(b,c){var a=this.el.terminal;new Connector(c.drag.terminal,a).redraw()},onHover:function(){var c=this.el;var b=c.terminal;if(b.connectors.length>0){var a=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='button'></div>").append($("<div/>").addClass("fa-icon-button fa fa-times").click(function(){$.each(b.connectors,function(f,d){if(d){d.destroy()}});a.remove()}))).bind("mouseleave",function(){$(this).remove()});a.css({top:$(c).offset().top-2,left:$(c).offset().left-a.width(),"padding-right":$(c).width()}).show()}},});var InputTerminalView=BaseInputTerminalView.extend({terminalMappingClass:InputTerminalMapping,terminalMappingViewClass:InputTerminalMappingView,terminalForInput:function(a){return new InputTerminal({element:this.el,input:a})},});var InputCollectionTerminalView=BaseInputTerminalView.extend({terminalMappingClass:InputCollectionTerminalMapping,terminalMappingViewClass:InputCollectionTerminalMappingView,terminalForInput:function(a){return new InputCollectionTerminal({element:this.el,input:a})},});var BaseOutputTerminalView=TerminalView.extend({className:"terminal output-terminal",initialize:function(c){var f=c.node;var a=c.output;var b=a.name;var d=this.terminalForOutput(a);this.setupMappingView(d);this.el.terminal=d;d.node=f;d.name=b;f.output_terminals[b]=d},events:{drag:"onDrag",dragstart:"onDragStart",dragend:"onDragEnd",},onDrag:function(b,c){var a=function(){var f=$(c.proxy).offsetParent().offset(),d=c.offsetX-f.left,g=c.offsetY-f.top;$(c.proxy).css({left:d,top:g});c.proxy.terminal.redraw();canvas_manager.update_viewport_overlay()};a();$("#canvas-container").get(0).scroll_panel.test(b,a)},onDragStart:function(b,f){$(f.available).addClass("input-terminal-active");workflow.check_changes_in_active_form();var a=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);a.terminal=new OutputTerminal({element:a});var g=new Connector();g.dragging=true;g.connect(this.el.terminal,a.terminal);return a},onDragEnd:function(b,c){var a=c.proxy.terminal.connectors[0];if(a){a.destroy()}$(c.proxy).remove();$(c.available).removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()}});var OutputTerminalView=BaseOutputTerminalView.extend({terminalMappingClass:OutputTerminalMapping,terminalMappingViewClass:OutputTerminalMappingView,terminalForOutput:function(a){var c=a.extensions;var b=new OutputTerminal({element:this.el,datatypes:c});return b},});var OutputCollectionTerminalView=BaseOutputTerminalView.extend({terminalMappingClass:OutputCollectionTerminalMapping,terminalMappingViewClass:OutputCollectionTerminalMappingView,terminalForOutput:function(a){var c=a.collection_type;var b=new OutputCollectionTerminal({element:this.el,collection_type:c,datatypes:a.extensions});return b},});function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(v,d){clearTimeout(this.timeout);var k=v.pageX,j=v.pageY,l=$(this.panel),c=l.position(),b=l.width(),i=l.height(),w=l.parent(),s=w.width(),a=w.height(),r=w.offset(),p=r.left,m=r.top,A=p+w.width(),u=m+w.height(),B=-(b-(s/2)),z=-(i-(a/2)),g=(s/2),f=(a/2),h=false,q=5,o=23;if(k-q<p){if(c.left<g){var n=Math.min(o,g-c.left);l.css("left",c.left+n);h=true}}else{if(k+q>A){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-q<m){if(c.top<f){var n=Math.min(o,f-c.top);l.css("top",c.top+n);h=true}}else{if(j+q>u){if(c.top>z){var n=Math.min(o,c.top-B);l.css("top",(c.top-n)+"px");h=true}}}}}if(h){d();var l=this;this.timeout=setTimeout(function(){l.test(v,d)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(){var g=$(this).offset();var f=b.cc.position();c=f.top-g.top;d=f.left-g.left}).bind("drag",function(f,g){a(g.offsetX+d,g.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("drag",function(k,l){var h=b.cc.width(),n=b.cc.height(),m=b.oc.width(),j=b.oc.height(),f=$(this).offsetParent().offset(),i=l.offsetX-f.left,g=l.offsetY-f.top;a(-(i/m*h),-(g/j*n))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g,i){var j=$(this).offsetParent();var h=j.offset();var f=Math.max(j.width()-(i.offsetX-h.left),j.height()-(i.offsetY-h.top));$(this).css({width:f,height:f});b.draw_overview()});$("#overview-border div").bind("drag",function(){})},update_viewport_overlay:function(){var b=this.cc,f=this.cv,a=this.oc,c=this.ov,d=b.width(),j=b.height(),i=a.width(),g=a.height(),h=b.position();c.css({left:-(h.left/d*i),top:-(h.top/j*g),width:(f.width()/d*i)-2,height:(f.height()/j*g)-2})},draw_overview:function(){var j=$("#overview-canvas"),m=j.parent().parent().width(),i=j.get(0).getContext("2d"),d=$("#canvas-container").width(),l=$("#canvas-container").height();var g,a,k,f;var h=this.cv.width();var b=this.cv.height();if(d<h&&l<b){k=d/h*m;f=(m-k)/2;g=l/b*m;a=(m-g)/2}else{if(d<l){a=0;g=m;k=Math.ceil(g*d/l);f=(m-k)/2}else{k=m;f=0;g=Math.ceil(k*l/d);a=(m-g)/2}}j.parent().css({left:f,top:a,width:k,height:g});j.attr("width",k);j.attr("height",g);$.each(workflow.nodes,function(t,q){i.fillStyle="#D2C099";i.strokeStyle="#D8B365";i.lineWidth=1;var s=$(q.element),n=s.position(),c=n.left/d*k,r=n.top/l*g,o=s.width()/d*k,p=s.height()/l*g;if(q.tool_errors){i.fillStyle="#FFCCCC";i.strokeStyle="#AA6666"}else{if(q.workflow_outputs!=undefined&&q.workflow_outputs.length>0){i.fillStyle="#E8A92D";i.strokeStyle="#E8A92D"}}i.fillRect(c,r,o,p);i.strokeRect(c,r,o,p)});this.update_viewport_overlay()}});
\ No newline at end of file
+function CollectionTypeDescription(a){this.collectionType=a;this.isCollection=true;this.rank=a.split(":").length}$.extend(CollectionTypeDescription.prototype,{append:function(a){if(a===NULL_COLLECTION_TYPE_DESCRIPTION){return this}if(a===ANY_COLLECTION_TYPE_DESCRIPTION){return otherCollectionType}return new CollectionTypeDescription(this.collectionType+":"+a.collectionType)},canMatch:function(a){if(a===NULL_COLLECTION_TYPE_DESCRIPTION){return false}if(a===ANY_COLLECTION_TYPE_DESCRIPTION){return true}return a.collectionType==this.collectionType},canMapOver:function(b){if(b===NULL_COLLECTION_TYPE_DESCRIPTION){return false}if(b===ANY_COLLECTION_TYPE_DESCRIPTION){return false}if(this.rank<=b.rank){return false}var a=b.collectionType;return this._endsWith(this.collectionType,a)},effectiveMapOver:function(a){var c=a.collectionType;var b=this.collectionType.substring(0,this.collectionType.length-c.length-1);return new CollectionTypeDescription(b)},equal:function(a){return a.collectionType==this.collectionType},toString:function(){return"CollectionType["+this.collectionType+"]"},_endsWith:function(b,a){return b.indexOf(a,b.length-a.length)!==-1}});NULL_COLLECTION_TYPE_DESCRIPTION={isCollection:false,canMatch:function(a){return false},canMapOver:function(a){return false},toString:function(){return"NullCollectionType[]"},append:function(a){return a},equal:function(a){return a===this}};ANY_COLLECTION_TYPE_DESCRIPTION={isCollection:true,canMatch:function(a){return NULL_COLLECTION_TYPE_DESCRIPTION!==a},canMapOver:function(a){return false},toString:function(){return"AnyCollectionType[]"},append:function(a){throw"Cannot append to ANY_COLLECTION_TYPE_DESCRIPTION"},equal:function(a){return a===this}};var TerminalMapping=Backbone.Model.extend({initialize:function(a){this.mapOver=a.mapOver||NULL_COLLECTION_TYPE_DESCRIPTION;this.terminal=a.terminal;this.terminal.terminalMapping=this},disableMapOver:function(){this.setMapOver(NULL_COLLECTION_TYPE_DESCRIPTION)},setMapOver:function(a){this.mapOver=a;this.trigger("change")}});var TerminalMappingView=Backbone.View.extend({tagName:"div",className:"fa-icon-button fa fa-folder-o",initialize:function(b){var a="Run tool in parallel over collection";this.$el.tooltip({delay:500,title:a});this.model.bind("change",_.bind(this.render,this))},render:function(){if(this.model.mapOver.isCollection){this.$el.show()}else{this.$el.hide()}},});var InputTerminalMappingView=TerminalMappingView.extend({events:{click:"onClick",mouseenter:"onMouseEnter",mouseleave:"onMouseLeave",},onMouseEnter:function(b){var a=this.model;if(!a.terminal.connected()&&a.mapOver.isCollection){this.$el.css("color","red")}},onMouseLeave:function(a){this.$el.css("color","black")},onClick:function(b){var a=this.model;if(!a.terminal.connected()&&a.mapOver.isCollection){a.terminal.resetMapping()}},});var InputTerminalMapping=TerminalMapping;var InputCollectionTerminalMapping=TerminalMapping;var OutputTerminalMapping=TerminalMapping;var OutputTerminalMappingView=TerminalMappingView;var InputCollectionTerminalMappingView=InputTerminalMappingView;var OutputCollectionTerminalMapping=TerminalMapping;var OutputCollectionTerminalMappingView=TerminalMappingView;var Terminal=Backbone.Model.extend({initialize:function(a){this.element=a.element;this.connectors=[]},connect:function(a){this.connectors.push(a);if(this.node){this.node.markChanged()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.markChanged();this.resetMappingIfNeeded()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})},destroyInvalidConnections:function(){_.each(this.connectors,function(a){a.destroyIfInvalid()})},setMapOver:function(a){if(this.multiple){return}if(!this.mapOver().equal(a)){this.terminalMapping.setMapOver(a);_.each(this.node.output_terminals,function(b){b.setMapOver(a)})}},mapOver:function(){if(!this.terminalMapping){return NULL_COLLECTION_TYPE_DESCRIPTION}else{return this.terminalMapping.mapOver}},isMappedOver:function(){return this.terminalMapping&&this.terminalMapping.mapOver.isCollection},resetMapping:function(){this.terminalMapping.disableMapOver()},resetMappingIfNeeded:function(){},});var OutputTerminal=Terminal.extend({initialize:function(a){Terminal.prototype.initialize.call(this,a);this.datatypes=a.datatypes},resetMappingIfNeeded:function(){if(!this.node.hasConnectedOutputTerminals()&&!this.node.hasConnectedMappedInputTerminals()){_.each(this.node.mappedInputTerminals(),function(b){b.resetMappingIfNeeded()})}var a=!this.node.hasMappedOverInputTerminals();if(a){this.resetMapping()}},resetMapping:function(){this.terminalMapping.disableMapOver();_.each(this.connectors,function(a){var b=a.handle2;if(b){b.resetMappingIfNeeded();a.destroyIfInvalid()}})}});var BaseInputTerminal=Terminal.extend({initialize:function(a){Terminal.prototype.initialize.call(this,a);this.update(a.input)},canAccept:function(a){if(this._inputFilled()){return false}else{return this.attachable(a)}},resetMappingIfNeeded:function(){var b=this.mapOver();if(!b.isCollection){return}var a=this.node.hasConnectedMappedInputTerminals()||(!this.node.hasConnectedOutputTerminals());if(a){this.resetMapping()}},resetMapping:function(){this.terminalMapping.disableMapOver();if(!this.node.hasMappedOverInputTerminals()){_.each(this.node.output_terminals,function(a){a.resetMapping()})}},connected:function(){return this.connectors.length!==0},_inputFilled:function(){var a;if(!this.connected()){a=false}else{if(this.multiple){if(this._collectionAttached()){inputsFilled=true}else{a=false}}else{a=true}}return a},_collectionAttached:function(){if(!this.connected()){return false}else{var a=this.connectors[0].handle1;if(!a){return false}else{if(a.isDataCollectionInput||a.isMappedOver()||a.datatypes.indexOf("input_collection")>0){return true}else{return false}}}},_mappingConstraints:function(){if(!this.node){return[]}var b=this.mapOver();if(b.isCollection){return[b]}var a=[];if(!this.node.hasConnectedOutputTerminals()){_.each(this.node.connectedMappedInputTerminals(),function(c){a.push(c.mapOver())})}else{a.push(_.first(_.values(this.node.output_terminals)).mapOver())}return a},_producesAcceptableDatatype:function(a){for(var c in this.datatypes){var f=new Array();f=f.concat(a.datatypes);if(a.node.post_job_actions){for(var d in a.node.post_job_actions){var g=a.node.post_job_actions[d];if(g.action_type=="ChangeDatatypeAction"&&(g.output_name==""||g.output_name==a.name)&&g.action_arguments){f.push(g.action_arguments.newtype)}}}for(var b in f){var h=f[b];if(h=="input"||h=="input_collection"||issubtype(f[b],this.datatypes[c])){return true}}}return false},_otherCollectionType:function(a){var c=NULL_COLLECTION_TYPE_DESCRIPTION;if(a.isDataCollectionInput){c=a.collectionType}else{var b=a.mapOver();if(b.isCollection){c=b}}return c},});var InputTerminal=BaseInputTerminal.extend({update:function(a){this.datatypes=a.extensions;this.multiple=a.multiple;this.collection=false},connect:function(a){BaseInputTerminal.prototype.connect.call(this,a);var b=a.handle1;if(!b){return}var c=this._otherCollectionType(b);if(c.isCollection){this.setMapOver(c)}},attachable:function(b){var d=this._otherCollectionType(b);var a=this.mapOver();if(d.isCollection){if(this.multiple){if(this.connected()&&!this._collectionAttached()){return false}if(d.rank==1){return this._producesAcceptableDatatype(b)}else{return false}}if(a.isCollection&&a.canMatch(d)){return this._producesAcceptableDatatype(b)}else{var c=this._mappingConstraints();if(c.every(_.bind(d.canMatch,d))){return this._producesAcceptableDatatype(b)}else{return false}}}else{if(a.isCollection){return false}}return this._producesAcceptableDatatype(b)}});var InputCollectionTerminal=BaseInputTerminal.extend({update:function(a){this.multiple=false;this.collection=true;this.datatypes=a.extensions;if(a.collection_type){this.collectionType=new CollectionTypeDescription(a.collection_type)}else{this.collectionType=ANY_COLLECTION_TYPE_DESCRIPTION}},connect:function(b){BaseInputTerminal.prototype.connect.call(this,b);var a=b.handle1;if(!a){return}var c=this._effectiveMapOver(a);this.setMapOver(c)},_effectiveMapOver:function(a){var b=this.collectionType;var c=this._otherCollectionType(a);if(!b.canMatch(c)){return c.effectiveMapOver(b)}else{return NULL_COLLECTION_TYPE_DESCRIPTION}},_effectiveCollectionType:function(){var b=this.collectionType;var a=this.mapOver();return a.append(b)},attachable:function(b){var g=this._otherCollectionType(b);if(g.isCollection){var f=this._effectiveCollectionType();var a=this.mapOver();if(f.canMatch(g)){return this._producesAcceptableDatatype(b)}else{if(a.isCollection){return false}else{if(g.canMapOver(this.collectionType)){var d=this._effectiveMapOver(b);if(!d.isCollection){return false}var c=this._mappingConstraints();if(c.every(d.canMatch)){return this._producesAcceptableDatatype(b)}}}}}return false}});var OutputCollectionTerminal=Terminal.extend({initialize:function(a){Terminal.prototype.initialize.call(this,a);this.datatypes=a.datatypes;this.collectionType=new CollectionTypeDescription(a.collection_type);this.isDataCollectionInput=true},update:function(a){var b=new CollectionTypeDescription(a.collection_type);if(b.collectionType!=this.collectionType.collectionType){_.each(this.connectors,function(c){c.destroy()})}this.collectionType=b}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a){this.connect(b,a)}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;if(this.handle1){this.handle1.connect(this)}this.handle2=a;if(this.handle2){this.handle2.connect(this)}},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},destroyIfInvalid:function(){if(this.handle1&&this.handle2&&!this.handle2.attachable(this.handle1)){this.destroy()}},redraw:function(){var f=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}f.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var v=function(c){return $(c).offset().left-f.offset().left};var p=function(c){return $(c).offset().top-f.offset().top};if(!this.handle1||!this.handle2){return}var o=v(this.handle1.element)+5;var n=p(this.handle1.element)+5;var x=v(this.handle2.element)+5;var u=p(this.handle2.element)+5;var k=100;var r=Math.min(o,x);var a=Math.max(o,x);var q=Math.min(n,u);var B=Math.max(n,u);var d=Math.min(Math.max(Math.abs(B-q)/2,100),300);var w=r-k;var A=q-k;var y=a-r+2*k;var s=B-q+2*k;this.canvas.style.left=w+"px";this.canvas.style.top=A+"px";this.canvas.setAttribute("width",y);this.canvas.setAttribute("height",s);o-=w;n-=A;x-=w;u-=A;var z=this.canvas.getContext("2d"),h=null,l=null;var g=1;if(this.handle1&&this.handle1.isMappedOver()){var h=[-6,-3,0,3,6];g=5}else{var h=[0]}if(this.handle2&&this.handle2.isMappedOver()){var l=[-6,-3,0,3,6];g=5}else{var l=[0]}var b=this;for(var t=0;t<g;t++){var m=5,j=7;if(h.length>1||l.length>1){m=1;j=3}b.draw_outlined_curve(o,n,x,u,d,m,j,h[t%h.length],l[t%l.length])}},draw_outlined_curve:function(j,i,l,k,a,b,f,g,d){var g=g||0;var d=d||0;var h=this.canvas.getContext("2d");h.lineCap="round";h.strokeStyle=this.outer_color;h.lineWidth=f;h.beginPath();h.moveTo(j,i+g);h.bezierCurveTo(j+a,i+g,l-a,k+d,l,k+d);h.stroke();h.strokeStyle=this.inner_color;h.lineWidth=b;h.beginPath();h.moveTo(j,i+g);h.bezierCurveTo(j+a,i+g,l-a,k+d,l,k+d);h.stroke()}});var Node=Backbone.Model.extend({initialize:function(a){this.element=a.element;this.input_terminals={};this.output_terminals={};this.tool_errors={}},connectedOutputTerminals:function(){return this._connectedTerminals(this.output_terminals)},_connectedTerminals:function(b){var a=[];$.each(b,function(c,d){if(d.connectors.length>0){a.push(d)}});return a},hasConnectedOutputTerminals:function(){var a=this.output_terminals;for(var b in a){if(a[b].connectors.length>0){return true}}return false},connectedMappedInputTerminals:function(){return this._connectedMappedTerminals(this.input_terminals)},hasConnectedMappedInputTerminals:function(){var c=this.input_terminals;for(var b in c){var a=c[b];if(a.connectors.length>0&&a.isMappedOver()){return true}}return false},_connectedMappedTerminals:function(b){var a=[];$.each(b,function(c,d){var f=d.mapOver();if(f.isCollection){if(d.connectors.length>0){a.push(d)}}});return a},mappedInputTerminals:function(){return this._mappedTerminals(this.input_terminals)},_mappedTerminals:function(b){var a=[];$.each(b,function(c,d){var f=d.mapOver();if(f.isCollection){a.push(d)}});return a},hasMappedOverInputTerminals:function(){var a=false;_.each(this.input_terminals,function(b){var c=b.mapOver();if(c.isCollection){a=true}});return a},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(b){if(b.type){this.type=b.type}this.name=b.name;this.form_html=b.form_html;this.tool_state=b.tool_state;this.tool_errors=b.tool_errors;this.tooltip=b.tooltip?b.tooltip:"";this.annotation=b.annotation;this.post_job_actions=b.post_job_actions?b.post_job_actions:{};this.label=b.label;this.uuid=b.uuid;this.workflow_outputs=b.workflow_outputs?b.workflow_outputs:[];var a=this;var c=new NodeView({el:this.element[0],node:a,});a.nodeView=c;$.each(b.data_inputs,function(f,d){c.addDataInput(d)});if((b.data_inputs.length>0)&&(b.data_outputs.length>0)){c.addRule()}$.each(b.data_outputs,function(f,d){c.addDataOutput(d)});c.render();workflow.node_changed(this,true)},update_field_data:function(d){var c=this;nodeView=c.nodeView;this.tool_state=d.tool_state;this.form_html=d.form_html;this.tool_errors=d.tool_errors;this.annotation=d.annotation;if("post_job_actions" in d){var f=$.parseJSON(d.post_job_actions);this.post_job_actions=f?f:{}}c.nodeView.renderToolErrors();var g=nodeView.$("div.inputs");var a=nodeView.newInputsDiv();var b={};_.each(d.data_inputs,function(h){var i=c.nodeView.addDataInput(h,a);b[h.name]=i});_.each(_.difference(_.values(nodeView.terminalViews),_.values(b)),function(h){h.el.terminal.destroy()});nodeView.terminalViews=b;if(d.data_outputs.length==1&&"collection_type" in d.data_outputs[0]){nodeView.updateDataOutput(d.data_outputs[0])}g.replaceWith(a);this.markChanged();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},markChanged:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false;this.active_form_has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},rectify_workflow_outputs:function(){var b=false;var a=false;$.each(this.nodes,function(c,d){if(d.workflow_outputs&&d.workflow_outputs.length>0){b=true}$.each(d.post_job_actions,function(g,f){if(f.action_type==="HideDatasetAction"){a=true}})});if(b!==false||a!==false){$.each(this.nodes,function(c,g){if(g.type==="tool"){var f=false;if(g.post_job_actions==null){g.post_job_actions={};f=true}var d=[];$.each(g.post_job_actions,function(i,h){if(h.action_type=="HideDatasetAction"){d.push(i)}});if(d.length>0){$.each(d,function(h,j){f=true;delete g.post_job_actions[j]})}if(b){$.each(g.output_terminals,function(i,j){var h=true;$.each(g.workflow_outputs,function(l,m){if(j.name===m){h=false}});if(h===true){f=true;var k={action_type:"HideDatasetAction",output_name:j.name,action_arguments:{}};g.post_job_actions["HideDatasetAction"+j.name]=null;g.post_job_actions["HideDatasetAction"+j.name]=k}})}if(workflow.active_node==g&&f===true){workflow.reload_active_node()}}})}},to_simple:function(){var a={};$.each(this.nodes,function(c,f){var g={};$.each(f.input_terminals,function(i,j){g[j.name]=null;var h=[];$.each(j.connectors,function(k,l){h[k]={id:l.handle1.node.id,output_name:l.handle1.name};g[j.name]=h})});var b={};if(f.post_job_actions){$.each(f.post_job_actions,function(j,h){var k={action_type:h.action_type,output_name:h.output_name,action_arguments:h.action_arguments};b[h.action_type+h.output_name]=null;b[h.action_type+h.output_name]=k})}if(!f.workflow_outputs){f.workflow_outputs=[]}var d={id:f.id,type:f.type,tool_id:f.tool_id,tool_state:f.tool_state,tool_errors:f.tool_errors,input_connections:g,position:$(f.element).position(),annotation:f.annotation,post_job_actions:f.post_job_actions,uuid:f.uuid,label:f.label,workflow_outputs:f.workflow_outputs};a[f.id]=d});return{steps:a}},from_simple:function(b){wf=this;var c=0;wf.name=b.name;var a=false;$.each(b.steps,function(g,f){var d=prebuild_node(f.type,f.name,f.tool_id);d.init_field_data(f);if(f.position){d.element.css({top:f.position.top,left:f.position.left})}d.id=f.id;wf.nodes[d.id]=d;c=Math.max(c,parseInt(g));if(!a&&d.type==="tool"){if(d.workflow_outputs.length>0){a=true}else{$.each(d.post_job_actions,function(i,h){if(h.action_type==="HideDatasetAction"){a=true}})}}});wf.id_counter=c+1;$.each(b.steps,function(g,f){var d=wf.nodes[g];$.each(f.input_connections,function(i,h){if(h){if(!$.isArray(h)){h=[h]}$.each(h,function(k,j){var m=wf.nodes[j.id];var n=new Connector();n.connect(m.output_terminals[j.output_name],d.input_terminals[i]);n.redraw()})}});if(a&&d.type==="tool"){$.each(d.output_terminals,function(h,i){if(d.post_job_actions["HideDatasetAction"+i.name]===undefined){d.workflow_outputs.push(i.name);callout=$(d.element).find(".callout."+i.name);callout.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png");workflow.has_changes=true}})}})},check_changes_in_active_form:function(){if(this.active_form_has_changes){this.has_changes=true;$("#right-content").find("form").submit();this.active_form_has_changes=false}},reload_active_node:function(){if(this.active_node){var a=this.active_node;this.clear_active_node();this.activate_node(a)}},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.check_changes_in_active_form();this.clear_active_node();parent.show_form_for_tool(a.form_html+a.tooltip,a);a.make_active();this.active_node=a}},node_changed:function(a,b){this.has_changes=true;if(this.active_node==a&&(!parent.__NEWTOOLFORM__||b)){this.check_changes_in_active_form();parent.show_form_for_tool(a.form_html+a.tooltip,a)}},layout:function(){this.check_changes_in_active_form();this.has_changes=true;var i={};var b={};$.each(this.nodes,function(l,k){if(i[l]===undefined){i[l]=0}if(b[l]===undefined){b[l]=[]}});$.each(this.nodes,function(l,k){$.each(k.input_terminals,function(m,n){$.each(n.connectors,function(p,q){var o=q.handle1.node;i[k.id]+=1;b[o.id].push(k.id)})})});node_ids_by_level=[];while(true){level_parents=[];for(var a in i){if(i[a]==0){level_parents.push(a)}}if(level_parents.length==0){break}node_ids_by_level.push(level_parents);for(var f in level_parents){var j=level_parents[f];delete i[j];for(var g in b[j]){i[b[j][g]]-=1}}}if(i.length){return}var d=this.nodes;var h=80;v_pad=30;var c=h;$.each(node_ids_by_level,function(k,l){l.sort(function(p,o){return $(d[p].element).position().top-$(d[o].element).position().top});var m=0;var n=v_pad;$.each(l,function(o,r){var q=d[r];var p=$(q.element);$(p).css({top:n,left:c});m=Math.max(m,$(p).width());n+=$(p).height()+v_pad});c+=m+h});$.each(d,function(k,l){l.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(h,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var i=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var h=fix_delta(a.ymin,100);d=Math.max(d,f.left);h=Math.max(h,f.top);var c=f.left-d;var g=f.top-h;var b=round_up(a.xmax+100,100)+d;var j=round_up(a.ymax+100,100)+h;b=Math.max(b,-c+i.width());j=Math.max(j,-g+i.height());this.canvas_container.css({left:c,top:g,width:b,height:j});this.canvas_container.children().each(function(){var k=$(this).position();$(this).css("left",k.left+d);$(this).css("top",k.top+h)})}});function fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(l,j,r){var i=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node({element:i});g.type=l;if(l=="tool"){g.tool_id=r}var n=$("<div class='toolFormTitle unselectable'>"+j+"</div>");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("<div class='toolFormBody'></div>");var h="<div><img height='16' align='middle' src='"+galaxy_config.root+"static/images/loading_small_white_bg.gif'/> loading tool info...</div>";m.append(h);g.form_html=h;i.append(m);var k=$("<div class='buttons' style='float: right;'></div>");k.append($("<div>").addClass("fa-icon-button fa fa-times").click(function(b){g.destroy()}));i.appendTo("#canvas-container");var d=$("#canvas-container").position();var c=$("#canvas-container").parent();var a=i.width();var q=i.height();i.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(q/2)});k.prependTo(n);a+=(k.width()+10);i.css("width",a);$(i).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o,p){var f=$(this).offsetParent().offset(),b=p.offsetX-f.left,s=p.offsetY-f.top;$(this).css({left:b,top:s});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}function add_node(b,d,a){var c=prebuild_node(b,d,a);workflow.add_node(c);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview();workflow.activate_node(c);return c}function update_node(b){var a=workflow.active_node;if(a){a.update_field_data(b,true)}}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}var NodeView=Backbone.View.extend({initialize:function(a){this.node=a.node;this.output_width=Math.max(150,this.$el.width());this.tool_body=this.$el.find(".toolFormBody");this.tool_body.find("div").remove();this.newInputsDiv().appendTo(this.tool_body);this.terminalViews={};this.outputTerminlViews={}},render:function(){this.renderToolErrors();this.$el.css("width",Math.min(250,Math.max(this.$el.width(),this.output_width)))},renderToolErrors:function(){if(this.node.tool_errors){this.$el.addClass("tool-node-error")}else{this.$el.removeClass("tool-node-error")}},newInputsDiv:function(){return $("<div class='inputs'></div>")},updateMaxWidth:function(a){this.output_width=Math.max(this.output_width,a)},addRule:function(){this.tool_body.append($("<div class='rule'></div>"))},addDataInput:function(i,d){var j=true;if(!d){d=this.$(".inputs");j=false}var f=this.terminalViews[i.name];var h=(i.input_type=="dataset_collection")?InputCollectionTerminalView:InputTerminalView;if(f&&!(f instanceof h)){f.el.terminal.destroy();f=null}if(!f){f=new h({node:this.node,input:i})}else{var g=f.el.terminal;g.update(i);g.destroyInvalidConnections()}this.terminalViews[i.name]=f;var c=f.el;var b=new DataInputView({terminalElement:c,input:i,nodeView:this,skipResize:j});var a=b.$el;d.append(a.prepend(f.terminalElements()));return f},addDataOutput:function(a){var d=(a.collection_type)?OutputCollectionTerminalView:OutputTerminalView;var c=new d({node:this.node,output:a});var b=new DataOutputView({output:a,terminalElement:c.el,nodeView:this,});this.tool_body.append(b.$el.append(c.terminalElements()))},updateDataOutput:function(b){var a=this.node.output_terminals[b.name];a.update(b)}});var DataInputView=Backbone.View.extend({className:"form-row dataRow input-data-row",initialize:function(a){this.input=a.input;this.nodeView=a.nodeView;this.terminalElement=a.terminalElement;this.$el.attr("name",this.input.name).html(this.input.label);if(!a.skipResize){this.$el.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(this.el);this.nodeView.updateMaxWidth(this.$el.outerWidth());this.$el.css({position:"",left:"",top:"",display:""});this.$el.remove()}},});var OutputCalloutView=Backbone.View.extend({tagName:"div",initialize:function(b){this.label=b.label;this.node=b.node;this.output=b.output;var a=this;this.$el.attr("class","callout "+this.label).css({display:"none"}).append($("<div class='buttons'></div>").append($("<img/>").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png").click(function(){if($.inArray(a.output.name,a.node.workflow_outputs)!=-1){a.node.workflow_outputs.splice($.inArray(a.output.name,a.node.workflow_outputs),1);a.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{a.node.workflow_outputs.push(a.output.name);a.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}workflow.has_changes=true;canvas_manager.draw_overview()}))).tooltip({delay:500,title:"Mark dataset as a workflow output. All unmarked datasets will be hidden."});this.$el.css({top:"50%",margin:"-8px 0px 0px 0px",right:8});this.$el.show();this.resetImage()},resetImage:function(){if($.inArray(this.output.name,this.node.workflow_outputs)===-1){this.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{this.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}},hoverImage:function(){this.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-yellow.png")}});var DataOutputView=Backbone.View.extend({className:"form-row dataRow",initialize:function(c){this.output=c.output;this.terminalElement=c.terminalElement;this.nodeView=c.nodeView;var a=this.output;var b=a.name;var f=this.nodeView.node;var d=a.extensions.indexOf("input")>=0||a.extensions.indexOf("input_collection")>=0;if(!d){b=b+" ("+a.extensions.join(", ")+")"}this.$el.html(b);if(f.type=="tool"){var g=new OutputCalloutView({label:b,output:a,node:f,});this.$el.append(g.el);this.$el.hover(function(){g.hoverImage()},function(){g.resetImage()})}this.$el.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(this.el);this.nodeView.updateMaxWidth(this.$el.outerWidth()+17);this.$el.css({position:"",left:"",top:"",display:""}).detach()}});var TerminalView=Backbone.View.extend({setupMappingView:function(b){var c=new this.terminalMappingClass({terminal:b});var a=new this.terminalMappingViewClass({model:c});a.render();b.terminalMappingView=a;this.terminalMappingView=a},terminalElements:function(){if(this.terminalMappingView){return[this.terminalMappingView.el,this.el]}else{return[this.el]}}});var BaseInputTerminalView=TerminalView.extend({className:"terminal input-terminal",initialize:function(c){var f=c.node;var a=c.input;var b=a.name;var d=this.terminalForInput(a);if(!d.multiple){this.setupMappingView(d)}this.el.terminal=d;d.node=f;d.name=b;f.input_terminals[b]=d},events:{dropinit:"onDropInit",dropstart:"onDropStart",dropend:"onDropEnd",drop:"onDrop",hover:"onHover",},onDropInit:function(b,c){var a=this.el.terminal;return $(c.drag).hasClass("output-terminal")&&a.canAccept(c.drag.terminal)},onDropStart:function(a,b){if(b.proxy.terminal){b.proxy.terminal.connectors[0].inner_color="#BBFFBB"}},onDropEnd:function(a,b){if(b.proxy.terminal){b.proxy.terminal.connectors[0].inner_color="#FFFFFF"}},onDrop:function(b,c){var a=this.el.terminal;new Connector(c.drag.terminal,a).redraw()},onHover:function(){var c=this.el;var b=c.terminal;if(b.connectors.length>0){var a=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='button'></div>").append($("<div/>").addClass("fa-icon-button fa fa-times").click(function(){$.each(b.connectors,function(f,d){if(d){d.destroy()}});a.remove()}))).bind("mouseleave",function(){$(this).remove()});a.css({top:$(c).offset().top-2,left:$(c).offset().left-a.width(),"padding-right":$(c).width()}).show()}},});var InputTerminalView=BaseInputTerminalView.extend({terminalMappingClass:InputTerminalMapping,terminalMappingViewClass:InputTerminalMappingView,terminalForInput:function(a){return new InputTerminal({element:this.el,input:a})},});var InputCollectionTerminalView=BaseInputTerminalView.extend({terminalMappingClass:InputCollectionTerminalMapping,terminalMappingViewClass:InputCollectionTerminalMappingView,terminalForInput:function(a){return new InputCollectionTerminal({element:this.el,input:a})},});var BaseOutputTerminalView=TerminalView.extend({className:"terminal output-terminal",initialize:function(c){var f=c.node;var a=c.output;var b=a.name;var d=this.terminalForOutput(a);this.setupMappingView(d);this.el.terminal=d;d.node=f;d.name=b;f.output_terminals[b]=d},events:{drag:"onDrag",dragstart:"onDragStart",dragend:"onDragEnd",},onDrag:function(b,c){var a=function(){var f=$(c.proxy).offsetParent().offset(),d=c.offsetX-f.left,g=c.offsetY-f.top;$(c.proxy).css({left:d,top:g});c.proxy.terminal.redraw();canvas_manager.update_viewport_overlay()};a();$("#canvas-container").get(0).scroll_panel.test(b,a)},onDragStart:function(b,f){$(f.available).addClass("input-terminal-active");workflow.check_changes_in_active_form();var a=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);a.terminal=new OutputTerminal({element:a});var g=new Connector();g.dragging=true;g.connect(this.el.terminal,a.terminal);return a},onDragEnd:function(b,c){var a=c.proxy.terminal.connectors[0];if(a){a.destroy()}$(c.proxy).remove();$(c.available).removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()}});var OutputTerminalView=BaseOutputTerminalView.extend({terminalMappingClass:OutputTerminalMapping,terminalMappingViewClass:OutputTerminalMappingView,terminalForOutput:function(a){var c=a.extensions;var b=new OutputTerminal({element:this.el,datatypes:c});return b},});var OutputCollectionTerminalView=BaseOutputTerminalView.extend({terminalMappingClass:OutputCollectionTerminalMapping,terminalMappingViewClass:OutputCollectionTerminalMappingView,terminalForOutput:function(a){var c=a.collection_type;var b=new OutputCollectionTerminal({element:this.el,collection_type:c,datatypes:a.extensions});return b},});function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(v,d){clearTimeout(this.timeout);var k=v.pageX,j=v.pageY,l=$(this.panel),c=l.position(),b=l.width(),i=l.height(),w=l.parent(),s=w.width(),a=w.height(),r=w.offset(),p=r.left,m=r.top,A=p+w.width(),u=m+w.height(),B=-(b-(s/2)),z=-(i-(a/2)),g=(s/2),f=(a/2),h=false,q=5,o=23;if(k-q<p){if(c.left<g){var n=Math.min(o,g-c.left);l.css("left",c.left+n);h=true}}else{if(k+q>A){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-q<m){if(c.top<f){var n=Math.min(o,f-c.top);l.css("top",c.top+n);h=true}}else{if(j+q>u){if(c.top>z){var n=Math.min(o,c.top-B);l.css("top",(c.top-n)+"px");h=true}}}}}if(h){d();var l=this;this.timeout=setTimeout(function(){l.test(v,d)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(){var g=$(this).offset();var f=b.cc.position();c=f.top-g.top;d=f.left-g.left}).bind("drag",function(f,g){a(g.offsetX+d,g.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("drag",function(k,l){var h=b.cc.width(),n=b.cc.height(),m=b.oc.width(),j=b.oc.height(),f=$(this).offsetParent().offset(),i=l.offsetX-f.left,g=l.offsetY-f.top;a(-(i/m*h),-(g/j*n))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g,i){var j=$(this).offsetParent();var h=j.offset();var f=Math.max(j.width()-(i.offsetX-h.left),j.height()-(i.offsetY-h.top));$(this).css({width:f,height:f});b.draw_overview()});$("#overview-border div").bind("drag",function(){})},update_viewport_overlay:function(){var b=this.cc,f=this.cv,a=this.oc,c=this.ov,d=b.width(),j=b.height(),i=a.width(),g=a.height(),h=b.position();c.css({left:-(h.left/d*i),top:-(h.top/j*g),width:(f.width()/d*i)-2,height:(f.height()/j*g)-2})},draw_overview:function(){var j=$("#overview-canvas"),m=j.parent().parent().width(),i=j.get(0).getContext("2d"),d=$("#canvas-container").width(),l=$("#canvas-container").height();var g,a,k,f;var h=this.cv.width();var b=this.cv.height();if(d<h&&l<b){k=d/h*m;f=(m-k)/2;g=l/b*m;a=(m-g)/2}else{if(d<l){a=0;g=m;k=Math.ceil(g*d/l);f=(m-k)/2}else{k=m;f=0;g=Math.ceil(k*l/d);a=(m-g)/2}}j.parent().css({left:f,top:a,width:k,height:g});j.attr("width",k);j.attr("height",g);$.each(workflow.nodes,function(t,q){i.fillStyle="#D2C099";i.strokeStyle="#D8B365";i.lineWidth=1;var s=$(q.element),n=s.position(),c=n.left/d*k,r=n.top/l*g,o=s.width()/d*k,p=s.height()/l*g;if(q.tool_errors){i.fillStyle="#FFCCCC";i.strokeStyle="#AA6666"}else{if(q.workflow_outputs!=undefined&&q.workflow_outputs.length>0){i.fillStyle="#E8A92D";i.strokeStyle="#E8A92D"}}i.fillRect(c,r,o,p);i.strokeRect(c,r,o,p)});this.update_viewport_overlay()}});
\ No newline at end of file
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 static/scripts/packed/mvc/tools/tools-form.js
--- a/static/scripts/packed/mvc/tools/tools-form.js
+++ b/static/scripts/packed/mvc/tools/tools-form.js
@@ -1,1 +1,1 @@
-define(["utils/utils","utils/deferred","mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-content","mvc/tools/tools-section","mvc/tools/tools-tree","mvc/tools/tools-jobs"],function(i,j,h,m,k,a,e,d,f,l,c,g){var b=Backbone.View.extend({container:"body",initialize:function(n){console.debug(n);var o=parent.Galaxy;if(o&&o.modal){this.modal=o.modal}else{this.modal=new m.Modal.View()}if(o&&o.currUser){this.is_admin=o.currUser.get("is_admin")}else{this.is_admin=false}this.options=n;this.deferred=new j();this.setElement("<div/>");$(this.container).append(this.$el);this._buildForm()},reciept:function(n){$(this.container).empty();$(this.container).append(n)},highlight:function(o,p,n){var q=this.element_list[o];if(q){q.error(p||"Please verify this parameter.");if(!n){$(this.container).animate({scrollTop:q.$el.offset().top-20},500)}}},_buildModel:function(){var n=this;var o=galaxy_config.root+"api/tools/"+this.options.id+"/build?";if(this.options.job_id){o+="job_id="+this.options.job_id}else{if(this.options.dataset_id){o+="dataset_id="+this.options.dataset_id}else{o+="tool_version="+this.options.version+"&";var q=top.location.href;var r=q.indexOf("?");if(q.indexOf("tool_id=")!=-1&&r!==-1){o+=q.slice(r+1)}}}var p=this.deferred.register();i.request({type:"GET",url:o,success:function(s){n.options=s;n._buildForm();n.message.update({status:"success",message:"Now you are using '"+n.options.name+"' version "+n.options.version+".",persistent:false});n.deferred.done(p);console.debug("tools-form::initialize() - Initial tool model ready.");console.debug(s)},error:function(s){n.deferred.done(p);console.debug("tools-form::initialize() - Initial tool model request failed.");console.debug(s);var t=s.error||"Uncaught error.";n.modal.show({title:"Tool cannot be executed",body:t,buttons:{Close:function(){n.modal.hide()}}})}})},_updateModel:function(){var n=this;var o=this.tree.finalize({data:function(s){if(s.values.length>0&&s.values[0]&&s.values[0].src==="hda"){return n.content.get({id:s.values[0].id,src:"hda"}).id_uncoded}return null}});console.debug("tools-form::_refreshForm() - Refreshing states.");console.debug(o);function r(v){for(var t in n.input_list){var u=n.field_list[t];var s=n.input_list[t];if(s.is_dynamic&&u.wait&&u.unwait){if(v){u.wait()}else{u.unwait()}}}}r(true);var q=this.deferred.register();var p=galaxy_config.root+"api/tools/"+this.options.id+"/build?tool_version="+this.options.version;i.request({type:"GET",url:p,data:o,success:function(s){n.tree.matchModel(s,function(u,y){var t=n.input_list[u];if(t&&t.options){if(!_.isEqual(t.options,y.options)){t.options=y.options;var z=n.field_list[u];if(z.update){var x=[];if((["data","data_collection","drill_down"]).indexOf(t.type)!=-1){x=t.options}else{for(var w in y.options){var v=y.options[w];if(v.length>2){x.push({label:v[0],value:v[1]})}}}z.update(x);z.trigger("change");console.debug("Updating options for "+u)}}}});r(false);n.deferred.done(q);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(s)},error:function(s){n.deferred.done(q);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(s)}})},_buildForm:function(){var n=this;this.off("refresh");this.off("reset");this.field_list={};this.input_list={};this.element_list={};this.tree=new c(this);this.job_handler=new g(this);this.content=new f(this);var p=this.options;this._renderForm(p);this.tree.finalize();if(p.errors){var q=this.tree.matchResponse(p.errors);for(var o in q){this.highlight(o,q[o],true)}}this.on("refresh",function(){n.deferred.reset();n.deferred.execute(function(){n._updateModel()})});this.on("reset",function(){for(var r in this.element_list){this.element_list[r].reset()}})},_renderForm:function(w){var v=this;this.message=new m.Message();var s=new m.ButtonIcon({icon:"fa-info-circle",title:"Requirements",tooltip:"Display tool requirements",onclick:function(){if(!this.visible){this.visible=true;v.message.update({persistent:true,message:d.requirements(w),status:"info"})}else{this.visible=false;v.message.update({message:""})}}});if(!w.requirements||w.requirements.length==0){s.$el.hide()}var o=new m.ButtonMenu({icon:"fa-cubes",title:"Versions",tooltip:"Select another tool version"});if(w.versions&&w.versions.length>1){for(var q in w.versions){var t=w.versions[q];if(t!=w.version){o.addMenu({title:"Switch to "+t,version:t,icon:"fa-cube",onclick:function(){w.id=w.id.replace(w.version,this.version);w.version=this.version;v.deferred.reset();v.deferred.execute(function(){v._buildModel()})}})}}}else{o.$el.hide()}var r=new m.ButtonMenu({icon:"fa-caret-down",title:"Options",tooltip:"View available options"});if(w.biostar_url){r.addMenu({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(w.biostar_url+"/p/new/post/")}});r.addMenu({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(w.biostar_url+"/t/"+w.id+"/")}})}r.addMenu({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",window.location.origin+galaxy_config.root+"root?tool_id="+w.id)}});if(this.is_admin){r.addMenu({icon:"fa-download",title:"Download",tooltip:"Download this tool",onclick:function(){window.location.href=galaxy_config.root+"api/tools/"+w.id+"/download"}})}this.section=new l.View(v,{inputs:w.inputs,cls:"ui-table-plain"});if(this.incompatible){this.$el.hide();$("#tool-form-classic").show();return}this.portlet=new h.View({icon:"fa-wrench",title:"<b>"+w.name+"</b> "+w.description+" (Galaxy Tool Version "+w.version+")",cls:"ui-portlet-slim",operations:{requirements:s,menu:r,versions:o},buttons:{execute:new m.Button({icon:"fa-check",tooltip:"Execute: "+w.name,title:"Execute",cls:"btn btn-primary",floating:"clear",onclick:function(){v.job_handler.submit()}})}});this.portlet.append(this.message.$el,true);this.portlet.append(this.section.$el);this.$el.empty();this.$el.append(this.portlet.$el);if(w.help!=""){this.$el.append(d.help(w.help))}if(w.citations){var u=$("<div/>");var n=new k.ToolCitationCollection();n.tool_id=w.id;var p=new a.CitationListView({el:u,collection:n});p.render();n.fetch();this.$el.append(u)}if(w.message){this.message.update({persistent:true,status:"warning",message:w.message})}}});return{View:b}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-misc","mvc/tools/tools-form-base","mvc/tools/tools-jobs"],function(c,e,b,a){var d=b.extend({initialize:function(g){var f=this;this.job_handler=new a(this);this.buttons={execute:new e.Button({icon:"fa-check",tooltip:"Execute: "+g.name,title:"Execute",cls:"btn btn-primary",floating:"clear",onclick:function(){f.job_handler.submit()}})};b.prototype.initialize.call(this,g)},_buildModel:function(){var f=this;var g=galaxy_config.root+"api/tools/"+this.options.id+"/build?";if(this.options.job_id){g+="job_id="+this.options.job_id}else{if(this.options.dataset_id){g+="dataset_id="+this.options.dataset_id}else{g+="tool_version="+this.options.version+"&";var i=top.location.href;var j=i.indexOf("?");if(i.indexOf("tool_id=")!=-1&&j!==-1){g+=i.slice(j+1)}}}var h=this.deferred.register();c.request({type:"GET",url:g,success:function(k){f.options=k;f._buildForm();f.message.update({status:"success",message:"Now you are using '"+f.options.name+"' version "+f.options.version+".",persistent:false});f.deferred.done(h);console.debug("tools-form::initialize() - Initial tool model ready.");console.debug(k)},error:function(k){f.deferred.done(h);console.debug("tools-form::initialize() - Initial tool model request failed.");console.debug(k);var l=k.error||"Uncaught error.";f.modal.show({title:"Tool cannot be executed",body:l,buttons:{Close:function(){f.modal.hide()}}})}})},_updateModel:function(){var f=this;var g=this.tree.finalize({data:function(k){if(k.values.length>0&&k.values[0]&&k.values[0].src==="hda"){return f.content.get({id:k.values[0].id,src:"hda"}).id_uncoded}return null}});console.debug("tools-form::_refreshForm() - Refreshing states.");console.debug(g);function j(n){for(var l in f.input_list){var m=f.field_list[l];var k=f.input_list[l];if(k.is_dynamic&&m.wait&&m.unwait){if(n){m.wait()}else{m.unwait()}}}}j(true);var i=this.deferred.register();var h=galaxy_config.root+"api/tools/"+this.options.id+"/build?tool_version="+this.options.version;c.request({type:"GET",url:h,data:g,success:function(k){f.tree.matchModel(k,function(m,q){var l=f.input_list[m];if(l&&l.options){if(!_.isEqual(l.options,q.options)){l.options=q.options;var r=f.field_list[m];if(r.update){var p=[];if((["data","data_collection","drill_down"]).indexOf(l.type)!=-1){p=l.options}else{for(var o in q.options){var n=q.options[o];if(n.length>2){p.push({label:n[0],value:n[1]})}}}r.update(p);r.trigger("change");console.debug("Updating options for "+m)}}}});j(false);f.deferred.done(i);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(k)},error:function(k){f.deferred.done(i);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(k)}})}});return{View:d}});
\ No newline at end of file
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 static/scripts/packed/mvc/tools/tools-jobs.js
--- a/static/scripts/packed/mvc/tools/tools-jobs.js
+++ b/static/scripts/packed/mvc/tools/tools-jobs.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/tools/tools-template"],function(b,a){return Backbone.Model.extend({initialize:function(c){this.app=c},submit:function(){var c=this;var d={tool_id:this.app.options.id,tool_version:this.app.options.version,inputs:this.app.tree.finalize()};this.app.trigger("reset");if(!this._validation(d)){console.debug("tools-jobs::submit - Submission canceled. Validation failed.");return}console.debug(d);this.app.modal.show({title:"Please wait...",body:"progress",closing_events:true,buttons:{Close:function(){c.app.modal.hide()}}});b.request({type:"POST",url:galaxy_config.root+"api/tools",data:d,success:function(e){c.app.modal.hide();c.app.reciept(a.success(e));c._refreshHdas()},error:function(e,g){c.app.modal.hide();if(e&&e.message&&e.message.data){var h=c.app.tree.matchResponse(e.message.data);for(var f in h){c.app.highlight(f,h[f]);break}}else{console.debug(e);c.app.modal.show({title:"Job submission failed",body:a.error(d),buttons:{Close:function(){c.app.modal.hide()}}})}}})},_validation:function(h){var d=h.inputs;var m=-1;var i=null;for(var k in d){var f=d[k];var l=this.app.tree.match(k);var e=this.app.field_list[l];var j=this.app.input_list[l];if(!l||!j||!e){console.debug("tools-jobs::_validation - Retrieving input objects failed.");continue}if(!j.optional&&e.validate&&!e.validate()){this.app.highlight(l);return false}if(f&&f.batch){var g=f.values.length;var c=null;if(g>0){c=f.values[0]&&f.values[0].src}if(c){if(i===null){i=c}else{if(i!==c){this.app.highlight(l,"Please select either dataset or dataset list fields for all batch mode fields.");return false}}}if(m===-1){m=g}else{if(m!==g){this.app.highlight(l,"Please make sure that you select the same number of inputs for all batch mode fields. This field contains <b>"+g+"</b> selection(s) while a previous field contains <b>"+m+"</b>.");return false}}}}return true},_refreshHdas:function(){if(parent.Galaxy&&parent.Galaxy.currHistoryPanel){parent.Galaxy.currHistoryPanel.refreshContents()}}})});
\ No newline at end of file
+define(["utils/utils","mvc/tools/tools-template"],function(b,a){return Backbone.Model.extend({initialize:function(c){this.app=c},submit:function(){var c=this;var d={tool_id:this.app.options.id,tool_version:this.app.options.version,inputs:this.app.tree.finalize()};this.app.trigger("reset");if(!this._validation(d)){console.debug("tools-jobs::submit - Submission canceled. Validation failed.");return}console.debug(d);this.app.modal.show({title:"Please wait...",body:"progress",closing_events:true,buttons:{Close:function(){c.app.modal.hide()}}});b.request({type:"POST",url:galaxy_config.root+"api/tools",data:d,success:function(e){c.app.modal.hide();c.app.reciept(a.success(e));c._refreshHdas()},error:function(e,g){c.app.modal.hide();if(e&&e.message&&e.message.data){var h=c.app.tree.matchResponse(e.message.data);for(var f in h){c.app.highlight(f,h[f]);break}}else{console.debug(e);c.app.modal.show({title:"Job submission failed",body:a.error(d),buttons:{Close:function(){c.app.modal.hide()}}})}}})},_validation:function(h){var d=h.inputs;var m=-1;var i=null;for(var k in d){var f=d[k];var l=this.app.tree.match(k);var e=this.app.field_list[l];var j=this.app.input_list[l];if(!l||!j||!e){console.debug("tools-jobs::_validation - Retrieving input objects failed.");continue}if(!j.optional&&f==null){this.app.highlight(l);return false}if(f&&f.batch){var g=f.values.length;var c=null;if(g>0){c=f.values[0]&&f.values[0].src}if(c){if(i===null){i=c}else{if(i!==c){this.app.highlight(l,"Please select either dataset or dataset list fields for all batch mode fields.");return false}}}if(m===-1){m=g}else{if(m!==g){this.app.highlight(l,"Please make sure that you select the same number of inputs for all batch mode fields. This field contains <b>"+g+"</b> selection(s) while a previous field contains <b>"+m+"</b>.");return false}}}}return true},_refreshHdas:function(){if(parent.Galaxy&&parent.Galaxy.currHistoryPanel){parent.Galaxy.currHistoryPanel.refreshContents()}}})});
\ No newline at end of file
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 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/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=j.id=d.uuid();this.app.input_list[h.id]=h;var k=h.type;switch(k){case"conditional":this._addConditional(h);break;case"repeat":this._addRepeat(h);break;default:this._addRow(h)}},_addConditional:function(h){var j=this;h.test_param.id=h.id;var m=this._addRow(h.test_param);m.options.onchange=function(t){var p=j.app.tree.matchCase(h,t);for(var r in h.cases){var w=h.cases[r];var u=h.id+"-section-"+r;var o=j.table.get(u);var v=false;for(var q in w.inputs){var s=w.inputs[q].type;if(s&&s!=="hidden"){v=true;break}}if(r==p&&v){o.fadeIn("fast")}else{o.hide()}}j.app.trigger("refresh")};for(var l in h.cases){var k=h.id+"-section-"+l;var n=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});n.$el.addClass("ui-table-form-section");this.table.add(n.$el);this.table.append(k)}m.trigger("change")},_addRepeat:function(o){var r=this;var p=0;function m(i,t){var s=o.id+"-section-"+(p++);var u=null;if(t){u=function(){k.del(s);k.retitle(o.title);r.app.trigger("refresh")}}var v=new f(r.app,{inputs:i,cls:"ui-table-plain"});k.add({id:s,title:o.title,$el:v.$el,ondel:u});k.retitle(o.title)}var k=new c.View({title_new:o.title,max:o.max,onnew:function(){m(o.inputs,true);r.app.trigger("refresh")}});var h=o.min;var q=_.size(o.cache);for(var l=0;l<Math.max(q,h);l++){var n=null;if(l<q){n=o.cache[l]}else{n=o.inputs}m(n,l>=h)}var j=new e(this.app,{label:o.title,help:o.help,field:k});j.$el.addClass("ui-table-form-section");this.table.add(j.$el);this.table.append(o.id)},_addRow:function(h){var k=h.id;var i=this._createField(h);this.app.field_list[k]=i;var j=new e(this.app,{label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[k]=j;this.table.add(j.$el);this.table.append(k);return i},_createField:function(h){var i=null;switch(h.type){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_collection":i=this._fieldData(h);break;case"data_column":h.error_text="Missing columns in referenced dataset.";i=this._fieldSelect(h);break;case"hidden":i=this._fieldHidden(h);break;case"hidden_data":i=this._fieldHidden(h);break;case"integer":i=this._fieldSlider(h);break;case"float":i=this._fieldSlider(h);break;case"boolean":i=this._fieldBoolean(h);break;case"genomebuild":h.searchable=true;i=this._fieldSelect(h);break;case"drill_down":i=this._fieldDrilldown(h);break;case"baseurl":i=this._fieldHidden(h);break;default:this.app.incompatible=true;if(h.options){i=this._fieldSelect(h)}else{i=this._fieldText(h)}console.debug("tools-form::_addRow() : Auto matched field type ("+h.type+").")}if(h.value!==undefined){i.value(h.value)}return i},_fieldData:function(h){var i=this;return new a.View(this.app,{id:"field-"+h.id,extensions:h.extensions,multiple:h.multiple,type:h.type,data:h.options,onchange:function(){i.app.trigger("refresh")}})},_fieldSelect:function(h){var k=[];for(var l in h.options){var m=h.options[l];k.push({label:m[0],value:m[1]})}var n=g.Select;switch(h.display){case"checkboxes":n=g.Checkbox;break;case"radio":n=g.Radio;break}var j=this;return new n.View({id:"field-"+h.id,data:k,error_text:h.error_text||"No options available",multiple:h.multiple,searchable:h.searchable,onchange:function(){j.app.trigger("refresh")}})},_fieldDrilldown:function(h){var i=this;return new g.Drilldown.View({id:"field-"+h.id,data:h.options,display:h.display,onchange:function(){i.app.trigger("refresh")}})},_fieldText:function(h){var i=this;return new g.Input({id:"field-"+h.id,area:h.area,onchange:function(){i.app.trigger("refresh")}})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=j.id=d.uuid();this.app.input_list[h.id]=h;var k=h.type;switch(k){case"conditional":this._addConditional(h);break;case"repeat":this._addRepeat(h);break;default:this._addRow(h)}},_addConditional:function(h){var j=this;h.test_param.id=h.id;var m=this._addRow(h.test_param);m.options.onchange=function(t){var p=j.app.tree.matchCase(h,t);for(var r in h.cases){var w=h.cases[r];var u=h.id+"-section-"+r;var o=j.table.get(u);var v=false;for(var q in w.inputs){var s=w.inputs[q].type;if(s&&s!=="hidden"){v=true;break}}if(r==p&&v){o.fadeIn("fast")}else{o.hide()}}j.app.trigger("refresh")};for(var l in h.cases){var k=h.id+"-section-"+l;var n=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});n.$el.addClass("ui-table-form-section");this.table.add(n.$el);this.table.append(k)}m.trigger("change")},_addRepeat:function(o){var r=this;var p=0;function m(i,t){var s=o.id+"-section-"+(p++);var u=null;if(t){u=function(){k.del(s);k.retitle(o.title);r.app.trigger("refresh")}}var v=new f(r.app,{inputs:i,cls:"ui-table-plain"});k.add({id:s,title:o.title,$el:v.$el,ondel:u});k.retitle(o.title)}var k=new c.View({title_new:o.title,max:o.max,onnew:function(){m(o.inputs,true);r.app.trigger("refresh")}});var h=o.min;var q=_.size(o.cache);for(var l=0;l<Math.max(q,h);l++){var n=null;if(l<q){n=o.cache[l]}else{n=o.inputs}m(n,l>=h)}var j=new e(this.app,{label:o.title,help:o.help,field:k});j.$el.addClass("ui-table-form-section");this.table.add(j.$el);this.table.append(o.id)},_addRow:function(h){var k=h.id;var i=this._createField(h);this.app.field_list[k]=i;var j=new e(this.app,{label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[k]=j;this.table.add(j.$el);this.table.append(k);return i},_createField:function(h){var i=null;switch(h.type){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_collection":i=this._fieldData(h);break;case"data_column":h.error_text="Missing columns in referenced dataset.";i=this._fieldSelect(h);break;case"hidden":i=this._fieldHidden(h);break;case"hidden_data":i=this._fieldHidden(h);break;case"integer":i=this._fieldSlider(h);break;case"float":i=this._fieldSlider(h);break;case"boolean":i=this._fieldBoolean(h);break;case"genomebuild":h.searchable=true;i=this._fieldSelect(h);break;case"drill_down":i=this._fieldDrilldown(h);break;case"baseurl":i=this._fieldHidden(h);break;default:this.app.incompatible=true;if(h.options){i=this._fieldSelect(h)}else{i=this._fieldText(h)}console.debug("tools-form::_addRow() : Auto matched field type ("+h.type+").")}if(h.value!==undefined){i.value(h.value)}return i},_fieldData:function(h){if(this.app.workflow){var j=d.textify(h.extensions.toString());h.info="Data input '"+h.name+"' ("+j+")";return this._fieldHidden(h)}var i=this;return new a.View(this.app,{id:"field-"+h.id,extensions:h.extensions,multiple:h.multiple,type:h.type,data:h.options,onchange:function(){i.app.trigger("refresh")}})},_fieldSelect:function(h){if(this.app.workflow&&h.is_dynamic){if(!d.validate(h.value)){h.value=""}return this._fieldText(h)}var k=[];for(var l in h.options){var m=h.options[l];k.push({label:m[0],value:m[1]})}var n=g.Select;switch(h.display){case"checkboxes":n=g.Checkbox;break;case"radio":n=g.Radio;break}var j=this;return new n.View({id:"field-"+h.id,data:k,error_text:h.error_text||"No options available",multiple:h.multiple,searchable:h.searchable,onchange:function(){j.app.trigger("refresh")}})},_fieldDrilldown:function(h){var i=this;return new g.Drilldown.View({id:"field-"+h.id,data:h.options,display:h.display,onchange:function(){i.app.trigger("refresh")}})},_fieldText:function(h){var i=this;return new g.Input({id:"field-"+h.id,area:h.area,onchange:function(){i.app.trigger("refresh")}})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id,info:h.info})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}});
\ No newline at end of file
diff -r 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 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/>");this.list={};var m=[];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=o.extensions.toString();if(j){j=j.replace(/,/g,", ");var k=j.lastIndexOf(", ");if(k!=-1){j=j.substr(0,k)+" or "+j.substr(k+1)}}var h="No dataset available.";if(j){h="No "+j+" dataset available."}var l="No dataset list available.";if(j){l="No "+j+" dataset collection available."}if(this.mode=="single"){m.push({icon:"fa-file-o",label:"Single dataset",value:"single"});this.select_single=new e.Select.View({error_text:h,onchange:function(){n.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){m.push({icon:"fa-files-o",label:"Multiple datasets",value:"multiple"});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"){m.push({icon:"fa-folder-o",label:"Dataset collection",value:"collection"});this.select_collection=new e.Select.View({error_text:l,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:m,onchange:function(i){n.current=i;n.refresh();n.trigger("change")}});this.$batch=$(a.batchMode());if(_.size(this.list)>1){this.$el.append(c.wrap(this.button_type.$el))}for(var g in this.list){this.$el.append(this.list[g].field.$el)}this.$el.append(this.$batch);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(m){if(m&&m.values){try{var l=[];for(var h in m.values){l.push(m.values[h].id)}if(m&&m.values.length>0&&m.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])}}this.refresh();var g=this._select();if(!g.validate()){g.value(g.first())}}catch(k){console.debug("tools-select-content::value() - Skipped.")}}var j=this._select().value();if(!(j instanceof Array)){j=[j]}var f={batch:this.mode=="single"&&this.current!="single",values:[]};for(var h in j){f.values.push({id:j[h],src:this.list[this.current].type})}return f},validate:function(){return this._select().validate()},refresh:function(){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(l,g){this.app=l;this.options=g;var f=this;this.setElement("<div/>");this.list={};var j=[];if(g.type=="data_collection"){this.mode="collection"}else{if(g.multiple){this.mode="multiple"}else{this.mode="single"}}this.current=this.mode;this.list={};var k=c.textify(g.extensions);var n="No dataset available.";if(k){n="No "+k+" dataset available."}var m="No dataset list available.";if(k){m="No "+k+" dataset collection available."}if(this.mode=="single"){j.push({icon:"fa-file-o",label:"Single dataset",value:"single"});this.select_single=new e.Select.View({error_text:n,onchange:function(){f.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){j.push({icon:"fa-files-o",label:"Multiple datasets",value:"multiple"});this.select_multiple=new e.Select.View({multiple:true,error_text:n,onchange:function(){f.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"}}if(this.mode=="single"||this.mode=="collection"){j.push({icon:"fa-folder-o",label:"Dataset collection",value:"collection"});this.select_collection=new e.Select.View({error_text:m,onchange:function(){f.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"}}this.button_type=new e.RadioButton.View({value:this.current,data:j,onchange:function(i){f.current=i;f.refresh();f.trigger("change")}});this.$batch=$(a.batchMode());if(_.size(this.list)>1){this.$el.append(c.wrap(this.button_type.$el))}for(var h in this.list){this.$el.append(this.list[h].field.$el)}this.$el.append(this.$batch);this.update(g.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(g.onchange){g.onchange(f.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(m){if(m&&m.values){try{var l=[];for(var h in m.values){l.push(m.values[h].id)}if(m&&m.values.length>0&&m.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])}}this.refresh();var g=this._select();if(!g.validate()){g.value(g.first())}}catch(k){console.debug("tools-select-content::value() - Skipped.")}}var j=this._select().value();if(!(j instanceof Array)){j=[j]}var f={batch:this.mode=="single"&&this.current!="single",values:[]};for(var h in j){f.values.push({id:j[h],src:this.list[this.current].type})}return f},validate:function(){return this._select().validate()},refresh:function(){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 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 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([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},finalize:function(f){var a=this;this.map_dict={};if(!this.app.section){return{}}f=f||{};var e={};var d={};this._iterate(this.app.section.$el,d);function c(i,h,g){e[i]=g;a.map_dict[i]=h}function b(n,q){for(var l in q){var j=q[l];if(j.input){var s=j.input;var m=n;if(n!=""){m+="|"}m+=s.name;switch(s.type){case"repeat":var h="section-";var v=[];var p=null;for(var u in j){var o=u.indexOf(h);if(o!=-1){o+=h.length;v.push(parseInt(u.substr(o)));if(!p){p=u.substr(0,o)}}}v.sort(function(w,i){return w-i});var l=0;for(var k in v){b(m+"_"+l++,j[p+v[k]])}break;case"conditional":var t=a.app.field_list[s.id].value();if(f[s.test_param.type]){t=f[s.test_param.type](t)}c(m+"|"+s.test_param.name,s.id,t);var g=a.matchCase(s,t);if(g!=-1){b(m,q[s.id+"-section-"+g])}break;default:var r=a.app.field_list[s.id];var t=r.value();if(f[s.type]){t=f[s.type](t)}if(!r.skip){if(s.optional&&r.validate&&!r.validate()){t=null}c(m,s.id,t)}}}}}b("",d);return e},match:function(a){return this.map_dict&&this.map_dict[a]},matchCase:function(a,c){if(a.test_param.type=="boolean"){if(c=="true"){c=a.test_param.truevalue||"true"}else{c=a.test_param.falsevalue||"false"}}for(var b in a.cases){if(a.cases[b].value==c){return b}}return -1},matchModel:function(c,e){var a={};var b=this;function d(f,o){for(var l in o){var h=o[l];var m=h.name;if(f!=""){m=f+"|"+m}switch(h.type){case"repeat":for(var k in h.cache){d(m+"_"+k,h.cache[k])}break;case"conditional":var p=h.test_param&&h.test_param.value;var g=b.matchCase(h,p);if(g!=-1){d(m,h.cases[g].inputs)}break;default:var n=b.map_dict[m];if(n){e(n,h)}}}}d("",c.inputs);return a},matchResponse:function(c){var a={};var b=this;function d(k,h){if(typeof h==="string"){var f=b.map_dict[k];if(f){a[f]=h}}else{for(var g in h){var e=g;if(k!==""){var j="|";if(h instanceof Array){j="_"}e=k+j+e}d(e,h[g])}}}d("",c);return a},_iterate:function(c,d){var a=this;var b=$(c).children();b.each(function(){var g=this;var f=$(g).attr("id");if($(g).hasClass("section-row")){d[f]={};var e=a.app.input_list[f];if(e){d[f]={input:e}}a._iterate(g,d[f])}else{a._iterate(g,d)}})}})});
\ 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(o,r){for(var m in r){var k=r[m];if(k.input){var t=k.input;var n=o;if(o!=""){n+="|"}n+=t.name;switch(t.type){case"repeat":var j="section-";var w=[];var q=null;for(var v in k){var p=v.indexOf(j);if(p!=-1){p+=j.length;w.push(parseInt(v.substr(p)));if(!q){q=v.substr(0,p)}}}w.sort(function(x,i){return x-i});var m=0;for(var l in w){c(n+"_"+m++,k[q+w[l]])}break;case"conditional":var u=b.app.field_list[t.id].value();if(g[t.test_param.type]){u=g[t.test_param.type](u)}d(n+"|"+t.test_param.name,t.id,u);var h=b.matchCase(t,u);if(h!=-1){c(n,r[t.id+"-section-"+h])}break;default:var s=b.app.field_list[t.id];var u=s.value();if(g[t.type]){u=g[t.type](u)}if(!s.skip){if(s.validate&&!s.validate(u)){u=null}d(n,t.id,u)}}}}}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 5c33270710123171734e5c822dfbb430a4234e37 -r d9b038019163bc378b72b675ddb4e1e902384b12 static/scripts/packed/mvc/ui/ui-misc.js
--- a/static/scripts/packed/mvc/ui/ui-misc.js
+++ b/static/scripts/packed/mvc/ui/ui-misc.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-select-default","mvc/ui/ui-slider","mvc/ui/ui-options","mvc/ui/ui-drilldown","mvc/ui/ui-button-menu","mvc/ui/ui-modal"],function(k,b,e,o,l,q,m){var d=Backbone.View.extend({optionsDefault:{url:"",cls:""},initialize:function(r){this.options=k.merge(r,this.optionsDefault);this.setElement(this._template(this.options))},_template:function(r){return'<img class="ui-image '+r.cls+'" src="'+r.url+'"/>'}});var j=Backbone.View.extend({optionsDefault:{title:"",cls:""},initialize:function(r){this.options=k.merge(r,this.optionsDefault);this.setElement(this._template(this.options))},title:function(r){this.$el.html(r)},_template:function(r){return'<label class="ui-label '+r.cls+'">'+r.title+"</label>"},value:function(){return options.title}});var c=Backbone.View.extend({optionsDefault:{floating:"right",icon:"",tooltip:"",placement:"bottom",title:"",cls:""},initialize:function(r){this.options=k.merge(r,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).tooltip({title:r.tooltip,placement:"bottom"})},_template:function(r){return'<div><span class="fa '+r.icon+'" class="ui-icon"/> '+r.title+"</div>"}});var g=Backbone.View.extend({optionsDefault:{id:null,title:"",floating:"right",cls:"ui-button btn btn-default",icon:""},initialize:function(r){this.options=k.merge(r,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).on("click",function(){$(".tooltip").hide();if(r.onclick){r.onclick()}});$(this.el).tooltip({title:r.tooltip,placement:"bottom"})},_template:function(r){var s='<button id="'+r.id+'" type="submit" style="float: '+r.floating+';" type="button" class="'+r.cls+'">';if(r.icon){s+='<i class="icon fa '+r.icon+'"></i> '}s+=r.title+"</button>";return s}});var h=Backbone.View.extend({optionsDefault:{id:null,title:"",floating:"right",cls:"ui-button-icon",icon:"",tooltip:"",onclick:null},initialize:function(s){this.options=k.merge(s,this.optionsDefault);this.setElement(this._template(this.options));this.$button=this.$el.find(".button");var r=this;$(this.el).on("click",function(){$(".tooltip").hide();if(s.onclick&&!r.disabled){s.onclick()}});$(this.el).tooltip({title:s.tooltip,placement:"bottom"})},disable:function(){this.$button.addClass("disabled");this.disabled=true},enable:function(){this.$button.removeClass("disabled");this.disabled=false},_template:function(r){var s="";if(r.title){s="width: auto;"}var t='<div id="'+r.id+'" style="float: '+r.floating+"; "+s+'" class="'+r.cls+'">';if(r.title){t+='<div class="button"><i class="icon fa '+r.icon+'"/> <span class="title">'+r.title+"</span></div>"}else{t+='<i class="icon fa '+r.icon+'"/>'}t+="</div>";return t}});var f=Backbone.View.extend({optionsDefault:{title:"",cls:""},initialize:function(r){this.options=k.merge(r,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).on("click",r.onclick)},_template:function(r){return'<div><a href="javascript:void(0)" class="ui-anchor '+r.cls+'">'+r.title+"</a></div>"}});var n=Backbone.View.extend({optionsDefault:{message:null,status:"info",persistent:false},initialize:function(r){this.options=k.merge(r,this.optionsDefault);this.setElement("<div></div>");if(this.options.message){this.update(this.options)}},update:function(s){this.options=k.merge(s,this.optionsDefault);if(s.message!=""){this.$el.html(this._template(this.options));this.$el.find(".alert").append(s.message);this.$el.fadeIn();if(this.timeout){window.clearTimeout(this.timeout)}if(!s.persistent){var r=this;this.timeout=window.setTimeout(function(){if(r.$el.is(":visible")){r.$el.fadeOut()}else{r.$el.hide()}},3000)}}else{this.$el.fadeOut()}},_template:function(r){return'<div class="ui-message alert alert-'+r.status+'"/>'}});var a=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(s){this.options=k.merge(s,this.optionsDefault);this.setElement(this._template(this.options));var r=this;if(this.options.onclick){this.$el.on("submit",function(u){var t=r.$el.find("#search");r.options.onclick(t.val())})}},_template:function(r){return'<div class="ui-search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+r.searchword+'"><button type="submit" class="btn search-btn"><i class="fa fa-search"></i></button></form></div>'}});var i=Backbone.View.extend({optionsDefault:{type:"text",placeholder:"",disabled:false,visible:true,cls:"",area:false},initialize:function(s){this.options=k.merge(s,this.optionsDefault);this.setElement(this._template(this.options));if(this.options.value!==undefined){this.value(this.options.value)}if(this.options.disabled){this.$el.prop("disabled",true)}if(!this.options.visible){this.$el.hide()}var r=this;this.$el.on("input",function(){if(r.options.onchange){r.options.onchange(r.$el.val())}})},value:function(r){if(r!==undefined){this.$el.val(r)}return this.$el.val()},_template:function(r){if(r.area){return'<textarea id="'+r.id+'" class="ui-textarea '+r.cls+'"></textarea>'}else{return'<input id="'+r.id+'" type="'+r.type+'" value="'+r.value+'" placeholder="'+r.placeholder+'" class="ui-input '+r.cls+'">'}}});var p=Backbone.View.extend({initialize:function(r){this.options=r;this.setElement(this._template(this.options));if(this.options.value!==undefined){this.value(this.options.value)}},value:function(r){if(r!==undefined){this.$el.val(r)}return this.$el.val()},_template:function(r){return'<hidden id="'+r.id+'" value="'+r.value+'"/>'}});return{Anchor:f,Button:g,ButtonIcon:h,ButtonMenu:q,Icon:c,Image:d,Input:i,Label:j,Message:n,Modal:m,RadioButton:o.RadioButton,Checkbox:o.Checkbox,Radio:o.Radio,Searchbox:a,Select:b,Hidden:p,Slider:e,Drilldown:l}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-select-default","mvc/ui/ui-slider","mvc/ui/ui-options","mvc/ui/ui-drilldown","mvc/ui/ui-button-menu","mvc/ui/ui-modal"],function(k,b,e,o,l,q,m){var d=Backbone.View.extend({optionsDefault:{url:"",cls:""},initialize:function(r){this.options=k.merge(r,this.optionsDefault);this.setElement(this._template(this.options))},_template:function(r){return'<img class="ui-image '+r.cls+'" src="'+r.url+'"/>'}});var j=Backbone.View.extend({optionsDefault:{title:"",cls:""},initialize:function(r){this.options=k.merge(r,this.optionsDefault);this.setElement(this._template(this.options))},title:function(r){this.$el.html(r)},_template:function(r){return'<label class="ui-label '+r.cls+'">'+r.title+"</label>"},value:function(){return options.title}});var c=Backbone.View.extend({optionsDefault:{floating:"right",icon:"",tooltip:"",placement:"bottom",title:"",cls:""},initialize:function(r){this.options=k.merge(r,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).tooltip({title:r.tooltip,placement:"bottom"})},_template:function(r){return'<div><span class="fa '+r.icon+'" class="ui-icon"/> '+r.title+"</div>"}});var g=Backbone.View.extend({optionsDefault:{id:null,title:"",floating:"right",cls:"ui-button btn btn-default",icon:""},initialize:function(r){this.options=k.merge(r,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).on("click",function(){$(".tooltip").hide();if(r.onclick){r.onclick()}});$(this.el).tooltip({title:r.tooltip,placement:"bottom"})},_template:function(r){var s='<button id="'+r.id+'" type="submit" style="float: '+r.floating+';" type="button" class="'+r.cls+'">';if(r.icon){s+='<i class="icon fa '+r.icon+'"></i> '}s+=r.title+"</button>";return s}});var h=Backbone.View.extend({optionsDefault:{id:null,title:"",floating:"right",cls:"ui-button-icon",icon:"",tooltip:"",onclick:null},initialize:function(s){this.options=k.merge(s,this.optionsDefault);this.setElement(this._template(this.options));this.$button=this.$el.find(".button");var r=this;$(this.el).on("click",function(){$(".tooltip").hide();if(s.onclick&&!r.disabled){s.onclick()}});$(this.el).tooltip({title:s.tooltip,placement:"bottom"})},disable:function(){this.$button.addClass("disabled");this.disabled=true},enable:function(){this.$button.removeClass("disabled");this.disabled=false},_template:function(r){var s="";if(r.title){s="width: auto;"}var t='<div id="'+r.id+'" style="float: '+r.floating+"; "+s+'" class="'+r.cls+'">';if(r.title){t+='<div class="button"><i class="icon fa '+r.icon+'"/> <span class="title">'+r.title+"</span></div>"}else{t+='<i class="icon fa '+r.icon+'"/>'}t+="</div>";return t}});var f=Backbone.View.extend({optionsDefault:{title:"",cls:""},initialize:function(r){this.options=k.merge(r,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).on("click",r.onclick)},_template:function(r){return'<div><a href="javascript:void(0)" class="ui-anchor '+r.cls+'">'+r.title+"</a></div>"}});var n=Backbone.View.extend({optionsDefault:{message:null,status:"info",persistent:false},initialize:function(r){this.options=k.merge(r,this.optionsDefault);this.setElement("<div></div>");if(this.options.message){this.update(this.options)}},update:function(s){this.options=k.merge(s,this.optionsDefault);if(s.message!=""){this.$el.html(this._template(this.options));this.$el.find(".alert").append(s.message);this.$el.fadeIn();if(this.timeout){window.clearTimeout(this.timeout)}if(!s.persistent){var r=this;this.timeout=window.setTimeout(function(){if(r.$el.is(":visible")){r.$el.fadeOut()}else{r.$el.hide()}},3000)}}else{this.$el.fadeOut()}},_template:function(r){return'<div class="ui-message alert alert-'+r.status+'"/>'}});var a=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(s){this.options=k.merge(s,this.optionsDefault);this.setElement(this._template(this.options));var r=this;if(this.options.onclick){this.$el.on("submit",function(u){var t=r.$el.find("#search");r.options.onclick(t.val())})}},_template:function(r){return'<div class="ui-search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+r.searchword+'"><button type="submit" class="btn search-btn"><i class="fa fa-search"></i></button></form></div>'}});var i=Backbone.View.extend({optionsDefault:{type:"text",placeholder:"",disabled:false,visible:true,cls:"",area:false},initialize:function(s){this.options=k.merge(s,this.optionsDefault);this.setElement(this._template(this.options));if(this.options.value!==undefined){this.value(this.options.value)}if(this.options.disabled){this.$el.prop("disabled",true)}if(!this.options.visible){this.$el.hide()}var r=this;this.$el.on("input",function(){if(r.options.onchange){r.options.onchange(r.$el.val())}})},value:function(r){if(r!==undefined){this.$el.val(r)}return this.$el.val()},_template:function(r){if(r.area){return'<textarea id="'+r.id+'" class="ui-textarea '+r.cls+'"></textarea>'}else{return'<input id="'+r.id+'" type="'+r.type+'" value="'+r.value+'" placeholder="'+r.placeholder+'" class="ui-input '+r.cls+'">'}}});var p=Backbone.View.extend({initialize:function(r){this.options=r;this.setElement(this._template(this.options));if(this.options.value!==undefined){this.value(this.options.value)}},value:function(r){if(r!==undefined){this.$("hidden").val(r)}return this.$("hidden").val()},_template:function(s){var r='<div id="'+s.id+'" >';if(s.info){r+="<label>"+s.info+"</label>"}r+='<hidden value="'+s.value+'"/></div>';return r}});return{Anchor:f,Button:g,ButtonIcon:h,ButtonMenu:q,Icon:c,Image:d,Input:i,Label:j,Message:n,Modal:m,RadioButton:o.RadioButton,Checkbox:o.Checkbox,Radio:o.Radio,Searchbox:a,Select:b,Hidden:p,Slider:e,Drilldown:l}});
\ No newline at end of file
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
[galaxyproject/usegalaxy-playbook] 8e55f6: Swapped CoSSci out and PreSTIGE galaxy server in, ...
by GitHub 10 Jan '15
by GitHub 10 Jan '15
10 Jan '15
Branch: refs/heads/master
Home: https://github.com/galaxyproject/usegalaxy-playbook
Commit: 8e55f6015a13b536c9c1afe3e29114e01b5db1c9
https://github.com/galaxyproject/usegalaxy-playbook/commit/8e55f6015a13b536…
Author: Dave Clements <clements(a)Clements-Galaxy.local>
Date: 2015-01-10 (Sat, 10 Jan 2015)
Changed paths:
A files/galaxy/common/static/welcome_img/PreSTIGEGalaxy.png
M templates/galaxy/common/static/welcome.html.j2
Log Message:
-----------
Swapped CoSSci out and PreSTIGE galaxy server in, in landing page slide rotation.
Commit: 176e3a7ef6b5a89d28259879f931742e788b5419
https://github.com/galaxyproject/usegalaxy-playbook/commit/176e3a7ef6b5a89d…
Author: Dave Clements <clements(a)Clements-Galaxy.local>
Date: 2015-01-10 (Sat, 10 Jan 2015)
Changed paths:
M templates/galaxy/common/static/welcome.html.j2
Log Message:
-----------
Still struggling with Git add ... This change should have been in previous commit.
Compare: https://github.com/galaxyproject/usegalaxy-playbook/compare/2f879e75e725...…
1
0
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5c3327071012/
Changeset: 5c3327071012
User: dan
Date: 2015-01-09 19:58:19+00:00
Summary: merge
Affected #: 2 files
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
09 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/7fe5cbb6b66e/
Changeset: 7fe5cbb6b66e
Branch: next-stable
User: dan
Date: 2015-01-09 19:48:56+00:00
Summary: Add gemini.sqlite datatype.
Affected #: 3 files
diff -r 13f767186d5e281a9d647f8e497d6aca48d03417 -r 7fe5cbb6b66e0debec7775a88a8c553384784a00 config/datatypes_conf.xml.sample
--- a/config/datatypes_conf.xml.sample
+++ b/config/datatypes_conf.xml.sample
@@ -180,7 +180,8 @@
<datatype extension="taxonomy" type="galaxy.datatypes.tabular:Taxonomy" display_in_upload="true"/><datatype extension="tabular" type="galaxy.datatypes.tabular:Tabular" display_in_upload="true" description="Any data in tab delimited format (tabular)." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#Tabular_.28tab_delimited.29"/><datatype extension="twobit" type="galaxy.datatypes.binary:TwoBit" mimetype="application/octet-stream" display_in_upload="true"/>
- <datatype extension="sqlite" type="galaxy.datatypes.binary:SQlite" mimetype="application/octet-stream" display_in_upload="true"/>
+ <datatype extension="sqlite" type="galaxy.datatypes.binary:SQlite" mimetype="application/octet-stream" display_in_upload="true"/>
+ <datatype extension="gemini.sqlite" type="galaxy.datatypes.binary:GeminiSQLite" mimetype="application/octet-stream" display_in_upload="True" /><datatype extension="txt" type="galaxy.datatypes.data:Text" display_in_upload="true" description="Any text file." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#Plain_text"/><datatype extension="linecount" type="galaxy.datatypes.data:LineCount" display_in_upload="false"/><datatype extension="memexml" type="galaxy.datatypes.xml:MEMEXml" mimetype="application/xml" display_in_upload="true"/>
@@ -270,6 +271,7 @@
--><sniffer type="galaxy.datatypes.tabular:Vcf"/><sniffer type="galaxy.datatypes.binary:TwoBit"/>
+ <sniffer type="galaxy.datatypes.binary:GeminiSQLite"/><sniffer type="galaxy.datatypes.binary:SQlite"/><sniffer type="galaxy.datatypes.binary:Bam"/><sniffer type="galaxy.datatypes.binary:Sff"/>
diff -r 13f767186d5e281a9d647f8e497d6aca48d03417 -r 7fe5cbb6b66e0debec7775a88a8c553384784a00 lib/galaxy/datatypes/binary.py
--- a/lib/galaxy/datatypes/binary.py
+++ b/lib/galaxy/datatypes/binary.py
@@ -20,7 +20,7 @@
from bx.seq.twobit import TWOBIT_MAGIC_NUMBER, TWOBIT_MAGIC_NUMBER_SWAP, TWOBIT_MAGIC_SIZE
from galaxy.util import sqlite
-from galaxy.datatypes.metadata import MetadataElement,ListParameter,DictParameter
+from galaxy.datatypes.metadata import MetadataElement, MetadataParameter, ListParameter, DictParameter
from galaxy.datatypes import metadata
import dataproviders
@@ -630,8 +630,66 @@
return dataproviders.dataset.SQliteDataProvider( dataset_source, **settings )
+#Binary.register_sniffable_binary_format("sqlite", "sqlite", SQlite)
+
+
+class GeminiSQLite( SQlite ):
+ """Class describing a Gemini Sqlite database """
+ MetadataElement( name="gemini_version", default='0.10.0' , param=MetadataParameter, desc="Gemini Version",
+ readonly=True, visible=True, no_value='0.10.0' )
+ file_ext = "gemini.sqlite"
+
+ def set_meta( self, dataset, overwrite = True, **kwd ):
+ super( GeminiSQLite, self ).set_meta( dataset, overwrite = overwrite, **kwd )
+ try:
+ conn = sqlite.connect( dataset.file_name )
+ c = conn.cursor()
+ tables_query = "SELECT version FROM version"
+ result = c.execute( tables_query ).fetchall()
+ for version, in result:
+ dataset.metadata.gemini_version = version
+ # TODO: Can/should we detect even more attributes, such as use of PED file, what was input annotation type, etc.
+ except Exception, e:
+ log.warn( '%s, set_meta Exception: %s', self, e )
+
+ def sniff( self, filename ):
+ if super( GeminiSQLite, self ).sniff( filename ):
+ gemini_table_names = [ "gene_detailed", "gene_summary", "resources", "sample_genotype_counts", "sample_genotypes", "samples",
+ "variant_impacts", "variants", "version" ]
+ try:
+ conn = sqlite.connect( filename )
+ c = conn.cursor()
+ tables_query = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
+ result = c.execute( tables_query ).fetchall()
+ result = map( lambda x: x[0], result )
+ for table_name in gemini_table_names:
+ if table_name not in result:
+ return False
+ return True
+ except Exception, e:
+ log.warn( '%s, sniff Exception: %s', self, e )
+ return False
+
+ def set_peek( self, dataset, is_multi_byte=False ):
+ if not dataset.dataset.purged:
+ dataset.peek = "Gemini SQLite Database, version %s" % ( dataset.metadata.gemini_version or 'unknown' )
+ dataset.blurb = data.nice_size( dataset.get_size() )
+ else:
+ dataset.peek = 'file does not exist'
+ dataset.blurb = 'file purged from disk'
+
+ def display_peek( self, dataset ):
+ try:
+ return dataset.peek
+ except:
+ return "Gemini SQLite Database, version %s" % ( dataset.metadata.gemini_version or 'unknown' )
+
+Binary.register_sniffable_binary_format( "gemini.sqlite", "gemini.sqlite", GeminiSQLite )
+# FIXME: We need to register gemini.sqlite before sqlite, since register_sniffable_binary_format and is_sniffable_binary called in upload.py
+# ignores sniff order declared in datatypes_conf.xml
Binary.register_sniffable_binary_format("sqlite", "sqlite", SQlite)
+
class Xlsx(Binary):
"""Class for Excel 2007 (xlsx) files"""
file_ext="xlsx"
diff -r 13f767186d5e281a9d647f8e497d6aca48d03417 -r 7fe5cbb6b66e0debec7775a88a8c553384784a00 tools/data_source/upload.py
--- a/tools/data_source/upload.py
+++ b/tools/data_source/upload.py
@@ -113,6 +113,8 @@
ext = sniff.guess_ext( dataset.path, is_multi_byte=True )
# Is dataset content supported sniffable binary?
else:
+ # FIXME: This ignores the declared sniff order in datatype_conf.xml
+ # resulting in improper behavior
type_info = Binary.is_sniffable_binary( dataset.path )
if type_info:
data_type = type_info[0]
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
09 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/55553f94d810/
Changeset: 55553f94d810
User: dan
Date: 2015-01-09 19:48:56+00:00
Summary: Add gemini.sqlite datatype.
Affected #: 3 files
diff -r 63d901ca0e6e9cfa405bae41f7088e3fa6bf243f -r 55553f94d810f4ce3ff44a46b439690003d848cb config/datatypes_conf.xml.sample
--- a/config/datatypes_conf.xml.sample
+++ b/config/datatypes_conf.xml.sample
@@ -181,7 +181,8 @@
<datatype extension="taxonomy" type="galaxy.datatypes.tabular:Taxonomy" display_in_upload="true"/><datatype extension="tabular" type="galaxy.datatypes.tabular:Tabular" display_in_upload="true" description="Any data in tab delimited format (tabular)." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#Tabular_.28tab_delimited.29"/><datatype extension="twobit" type="galaxy.datatypes.binary:TwoBit" mimetype="application/octet-stream" display_in_upload="true"/>
- <datatype extension="sqlite" type="galaxy.datatypes.binary:SQlite" mimetype="application/octet-stream" display_in_upload="true"/>
+ <datatype extension="sqlite" type="galaxy.datatypes.binary:SQlite" mimetype="application/octet-stream" display_in_upload="true"/>
+ <datatype extension="gemini.sqlite" type="galaxy.datatypes.binary:GeminiSQLite" mimetype="application/octet-stream" display_in_upload="True" /><datatype extension="txt" type="galaxy.datatypes.data:Text" display_in_upload="true" description="Any text file." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#Plain_text"/><datatype extension="linecount" type="galaxy.datatypes.data:LineCount" display_in_upload="false"/><datatype extension="memexml" type="galaxy.datatypes.xml:MEMEXml" mimetype="application/xml" display_in_upload="true"/>
@@ -271,6 +272,7 @@
--><sniffer type="galaxy.datatypes.tabular:Vcf"/><sniffer type="galaxy.datatypes.binary:TwoBit"/>
+ <sniffer type="galaxy.datatypes.binary:GeminiSQLite"/><sniffer type="galaxy.datatypes.binary:SQlite"/><sniffer type="galaxy.datatypes.binary:Bam"/><sniffer type="galaxy.datatypes.binary:Sff"/>
diff -r 63d901ca0e6e9cfa405bae41f7088e3fa6bf243f -r 55553f94d810f4ce3ff44a46b439690003d848cb lib/galaxy/datatypes/binary.py
--- a/lib/galaxy/datatypes/binary.py
+++ b/lib/galaxy/datatypes/binary.py
@@ -20,7 +20,7 @@
from bx.seq.twobit import TWOBIT_MAGIC_NUMBER, TWOBIT_MAGIC_NUMBER_SWAP, TWOBIT_MAGIC_SIZE
from galaxy.util import sqlite
-from galaxy.datatypes.metadata import MetadataElement,ListParameter,DictParameter
+from galaxy.datatypes.metadata import MetadataElement, MetadataParameter, ListParameter, DictParameter
from galaxy.datatypes import metadata
import dataproviders
@@ -640,8 +640,66 @@
return dataproviders.dataset.SQliteDataDictProvider( dataset_source, **settings )
+#Binary.register_sniffable_binary_format("sqlite", "sqlite", SQlite)
+
+
+class GeminiSQLite( SQlite ):
+ """Class describing a Gemini Sqlite database """
+ MetadataElement( name="gemini_version", default='0.10.0' , param=MetadataParameter, desc="Gemini Version",
+ readonly=True, visible=True, no_value='0.10.0' )
+ file_ext = "gemini.sqlite"
+
+ def set_meta( self, dataset, overwrite = True, **kwd ):
+ super( GeminiSQLite, self ).set_meta( dataset, overwrite = overwrite, **kwd )
+ try:
+ conn = sqlite.connect( dataset.file_name )
+ c = conn.cursor()
+ tables_query = "SELECT version FROM version"
+ result = c.execute( tables_query ).fetchall()
+ for version, in result:
+ dataset.metadata.gemini_version = version
+ # TODO: Can/should we detect even more attributes, such as use of PED file, what was input annotation type, etc.
+ except Exception, e:
+ log.warn( '%s, set_meta Exception: %s', self, e )
+
+ def sniff( self, filename ):
+ if super( GeminiSQLite, self ).sniff( filename ):
+ gemini_table_names = [ "gene_detailed", "gene_summary", "resources", "sample_genotype_counts", "sample_genotypes", "samples",
+ "variant_impacts", "variants", "version" ]
+ try:
+ conn = sqlite.connect( filename )
+ c = conn.cursor()
+ tables_query = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
+ result = c.execute( tables_query ).fetchall()
+ result = map( lambda x: x[0], result )
+ for table_name in gemini_table_names:
+ if table_name not in result:
+ return False
+ return True
+ except Exception, e:
+ log.warn( '%s, sniff Exception: %s', self, e )
+ return False
+
+ def set_peek( self, dataset, is_multi_byte=False ):
+ if not dataset.dataset.purged:
+ dataset.peek = "Gemini SQLite Database, version %s" % ( dataset.metadata.gemini_version or 'unknown' )
+ dataset.blurb = data.nice_size( dataset.get_size() )
+ else:
+ dataset.peek = 'file does not exist'
+ dataset.blurb = 'file purged from disk'
+
+ def display_peek( self, dataset ):
+ try:
+ return dataset.peek
+ except:
+ return "Gemini SQLite Database, version %s" % ( dataset.metadata.gemini_version or 'unknown' )
+
+Binary.register_sniffable_binary_format( "gemini.sqlite", "gemini.sqlite", GeminiSQLite )
+# FIXME: We need to register gemini.sqlite before sqlite, since register_sniffable_binary_format and is_sniffable_binary called in upload.py
+# ignores sniff order declared in datatypes_conf.xml
Binary.register_sniffable_binary_format("sqlite", "sqlite", SQlite)
+
class Xlsx(Binary):
"""Class for Excel 2007 (xlsx) files"""
file_ext="xlsx"
diff -r 63d901ca0e6e9cfa405bae41f7088e3fa6bf243f -r 55553f94d810f4ce3ff44a46b439690003d848cb tools/data_source/upload.py
--- a/tools/data_source/upload.py
+++ b/tools/data_source/upload.py
@@ -113,6 +113,8 @@
ext = sniff.guess_ext( dataset.path, is_multi_byte=True )
# Is dataset content supported sniffable binary?
else:
+ # FIXME: This ignores the declared sniff order in datatype_conf.xml
+ # resulting in improper behavior
type_info = Binary.is_sniffable_binary( dataset.path )
if type_info:
data_type = type_info[0]
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
08 Jan '15
Branch: refs/heads/master
Home: https://github.com/galaxyproject/usegalaxy-playbook
Commit: 2f879e75e7258805ee919c0d043611e57cfd40a2
https://github.com/galaxyproject/usegalaxy-playbook/commit/2f879e75e7258805…
Author: Nate Coraor <nate(a)bx.psu.edu>
Date: 2015-01-08 (Thu, 08 Jan 2015)
Changed paths:
M templates/galaxy/usegalaxy.org/config/job_conf.xml.j2
Log Message:
-----------
Increase memory for join1.
1
0
[galaxyproject/usegalaxy-playbook] 1eff0f: Set the bigwig implicit converter to use more memo...
by GitHub 08 Jan '15
by GitHub 08 Jan '15
08 Jan '15
Branch: refs/heads/master
Home: https://github.com/galaxyproject/usegalaxy-playbook
Commit: 1eff0fac7c5826823f89852268218e3429658e1a
https://github.com/galaxyproject/usegalaxy-playbook/commit/1eff0fac7c582682…
Author: Nate Coraor <nate(a)bx.psu.edu>
Date: 2015-01-08 (Thu, 08 Jan 2015)
Changed paths:
M templates/galaxy/usegalaxy.org/config/job_conf.xml.j2
Log Message:
-----------
Set the bigwig implicit converter to use more memory.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/65cd7c0eee89/
Changeset: 65cd7c0eee89
User: jmchilton
Date: 2015-01-07 21:33:11+00:00
Summary: Update to brew_exts to latest platform-brew.
Affected #: 1 file
diff -r 8c57fc528cb7255ab11d20b03b5dd8509e3ea5a0 -r 65cd7c0eee89e2d32a3369b1eb88742f23034560 lib/galaxy/tools/deps/brew_exts.py
--- a/lib/galaxy/tools/deps/brew_exts.py
+++ b/lib/galaxy/tools/deps/brew_exts.py
@@ -28,6 +28,7 @@
import os
import re
import sys
+import string
import subprocess
WHITESPACE_PATTERN = re.compile("[\s]+")
@@ -43,6 +44,7 @@
CANNOT_DETERMINE_TAP_ERROR_MESSAGE = "Cannot determine tap of specified recipe - please use fully qualified recipe (e.g. homebrew/science/samtools)."
VERBOSE = False
RELAXED = False
+BREW_ARGS = []
class BrewContext(object):
@@ -104,6 +106,7 @@
def main():
global VERBOSE
global RELAXED
+ global BREW_ARGS
parser = argparse.ArgumentParser(description=DESCRIPTION)
parser.add_argument("--brew", help="Path to linuxbrew 'brew' executable to target")
actions = ["vinstall", "vuninstall", "vdeps", "vinfo", "env"]
@@ -114,11 +117,13 @@
parser.add_argument('version', metavar='version', help="Version for action (e.g. 0.1.19).")
parser.add_argument('--relaxed', action='store_true', help="Relaxed processing - for instance allow use of env on non-vinstall-ed recipes.")
parser.add_argument('--verbose', action='store_true', help="Verbose output")
+ parser.add_argument('restargs', nargs=argparse.REMAINDER)
args = parser.parse_args()
if args.verbose:
VERBOSE = True
if args.relaxed:
RELAXED = True
+ BREW_ARGS = args.restargs
if not action:
action = args.action
brew_context = BrewContext(args)
@@ -159,7 +164,7 @@
return self.message
-def versioned_install(recipe_context, package=None, version=None):
+def versioned_install(recipe_context, package=None, version=None, installed_deps=[]):
if package is None:
package = recipe_context.recipe
version = recipe_context.version
@@ -176,10 +181,15 @@
versioned = version_info[2]
if versioned:
dep_to_version[dep] = dep_version
+ if dep in installed_deps:
+ continue
versioned_install(recipe_context, dep, dep_version)
+ installed_deps.append(dep)
else:
# Install latest.
dep_to_version[dep] = None
+ if dep in installed_deps:
+ continue
unversioned_install(dep)
try:
for dep in deps:
@@ -198,7 +208,16 @@
}
deps_metadata.append(dep_metadata)
- brew_execute(["install", package])
+ cellar_root = recipe_context.brew_context.homebrew_cellar
+ cellar_path = recipe_context.cellar_path
+ env_actions = build_env_actions(deps_metadata, cellar_root, cellar_path, custom_only=True)
+ env = EnvAction.build_env(env_actions)
+ args = ["install"]
+ if VERBOSE:
+ args.append("--verbose")
+ args.extend(BREW_ARGS)
+ args.append(package)
+ brew_execute(args, env=env)
deps = brew_execute(["deps", package])
deps = [d.strip() for d in deps.split("\n") if d]
metadata = {
@@ -278,10 +297,10 @@
pass
-def brew_execute(args):
+def brew_execute(args, env=None):
os.environ["HOMEBREW_NO_EMOJI"] = "1" # simplify brew parsing.
cmds = ["brew"] + args
- return execute(cmds)
+ return execute(cmds, env=env)
def build_env_statements_from_recipe_context(recipe_context, **kwds):
@@ -290,11 +309,20 @@
return env_statements
-def build_env_statements(cellar_root, cellar_path, relaxed=None):
+def build_env_statements(cellar_root, cellar_path, relaxed=None, custom_only=False):
deps = load_versioned_deps(cellar_path, relaxed=relaxed)
+ actions = build_env_actions(deps, cellar_root, cellar_path, relaxed, custom_only)
+ env_statements = []
+ for action in actions:
+ env_statements.extend(action.to_statements())
+ return "\n".join(env_statements)
+
+
+def build_env_actions(deps, cellar_root, cellar_path, relaxed=None, custom_only=False):
path_appends = []
ld_path_appends = []
+ actions = []
def handle_keg(cellar_path):
bin_path = os.path.join(cellar_path, "bin")
@@ -303,6 +331,14 @@
lib_path = os.path.join(cellar_path, "lib")
if os.path.isdir(lib_path):
ld_path_appends.append(lib_path)
+ env_path = os.path.join(cellar_path, "platform_environment.json")
+ if os.path.exists(env_path):
+ with open(env_path, "r") as f:
+ env_metadata = json.load(f)
+ if "actions" in env_metadata:
+ def to_action(desc):
+ return EnvAction(cellar_path, desc)
+ actions.extend(map(to_action, env_metadata["actions"]))
for dep in deps:
package = dep['name']
@@ -311,14 +347,54 @@
handle_keg( dep_cellar_path )
handle_keg( cellar_path )
- env_statements = []
- if path_appends:
- env_statements.append("PATH=" + ":".join(path_appends) + ":$PATH")
- env_statements.append("export PATH")
- if ld_path_appends:
- env_statements.append("LD_LIBRARY_PATH=" + ":".join(ld_path_appends) + ":$LD_LIBRARY_PATH")
- env_statements.append("export LD_LIBRARY_PATH")
- return "\n".join(env_statements)
+ if not custom_only:
+ if path_appends:
+ actions.append(EnvAction(cellar_path, {"action": "prepend", "variable": "PATH", "value": ":".join(path_appends)}))
+ if ld_path_appends:
+ actions.append(EnvAction(cellar_path, {"action": "prepend", "variable": "LD_LIBRARY_PATH", "value": ":".join(path_appends)}))
+ return actions
+
+
+class EnvAction(object):
+
+ def __init__(self, keg_root, action_description):
+ self.variable = action_description["variable"]
+ self.action = action_description["action"]
+ self.value = string.Template(action_description["value"]).safe_substitute({
+ 'KEG_ROOT': keg_root,
+ })
+
+ @staticmethod
+ def build_env(env_actions):
+ new_env = os.environ.copy()
+ map(lambda env_action: env_action.modify_environ(new_env), env_actions)
+ return new_env
+
+ def modify_environ(self, environ):
+ if self.action == "set" or not environ.get(self.variable, ""):
+ environ[self.variable] = self.__eval("${value}")
+ elif self.action == "prepend":
+ environ[self.variable] = self.__eval("${value}:%s" % environ[self.variable])
+ else:
+ environ[self.variable] = self.__eval("%s:${value}" % environ[self.variable])
+
+ def __eval(self, template):
+ return string.Template(template).safe_substitute(
+ variable=self.variable,
+ value=self.value,
+ )
+
+ def to_statements(self):
+ if self.action == "set":
+ template = '''${variable}="${value}"'''
+ elif self.action == "prepend":
+ template = '''${variable}="${value}:$$${variable}"'''
+ else:
+ template = '''${variable}="$$${variable}:${value}"'''
+ return [
+ self.__eval(template),
+ "export %s" % self.variable
+ ]
@contextlib.contextmanager
@@ -350,8 +426,15 @@
return execute(cmds)
-def execute(cmds):
- p = subprocess.Popen(cmds, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+def execute(cmds, env=None):
+ subprocess_kwds = dict(
+ shell=False,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ if env:
+ subprocess_kwds["env"] = env
+ p = subprocess.Popen(cmds, **subprocess_kwds)
#log = p.stdout.read()
global VERBOSE
stdout, stderr = p.communicate()
@@ -363,7 +446,10 @@
def brew_deps(package):
- stdout = brew_execute(["deps", package])
+ args = ["deps"]
+ args.extend(BREW_ARGS)
+ args.append(package)
+ stdout = brew_execute(args)
return [p.strip() for p in stdout.split("\n") if p]
https://bitbucket.org/galaxy/galaxy-central/commits/63d901ca0e6e/
Changeset: 63d901ca0e6e
User: jmchilton
Date: 2015-01-07 21:33:11+00:00
Summary: Implement dependency resolver for Homebrew "tapped" tool shed packages (highly beta).
Homebrew/Linuxbrew can be configured the same way the more vanilla Homebrew resolver works (added in 6b7782f).
When this resolver is active, if the tool has been installed via the Tool Shed and the dependencies also installed it will use the database information to determine the dependent packages - otherwise it will just try to find the tool_dependencies.xml file on disk and recover the dependencies from that.
This is for dependencies installed via Platform Brew (https://github.com/jmchilton/platform-brew) and converted from Tool Shed repositories usiing the shed2tap WIP code (e.g. https://github.com/jmchilton/homebrew-toolshed)
Affected #: 7 files
diff -r 65cd7c0eee89e2d32a3369b1eb88742f23034560 -r 63d901ca0e6e9cfa405bae41f7088e3fa6bf243f lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1843,7 +1843,8 @@
"""Return a list of commands to be run to populate the current environment to include this tools requirements."""
return self.app.toolbox.dependency_manager.dependency_shell_commands(
self.requirements,
- installed_tool_dependencies=self.installed_tool_dependencies
+ installed_tool_dependencies=self.installed_tool_dependencies,
+ tool_dir=self.tool_dir,
)
@property
diff -r 65cd7c0eee89e2d32a3369b1eb88742f23034560 -r 63d901ca0e6e9cfa405bae41f7088e3fa6bf243f lib/galaxy/tools/deps/resolvers/brewed_tool_shed_packages.py
--- /dev/null
+++ b/lib/galaxy/tools/deps/resolvers/brewed_tool_shed_packages.py
@@ -0,0 +1,150 @@
+"""
+This dependency resolver resolves tool shed dependencies (those defined
+tool_dependencies.xml) installed using Platform Homebrew and converted
+via shed2tap (e.g. https://github.com/jmchilton/homebrew-toolshed)
+"""
+import logging
+import os
+from xml.etree import ElementTree as ET
+
+from .resolver_mixins import (
+ UsesHomebrewMixin,
+ UsesToolDependencyDirMixin,
+ UsesInstalledRepositoriesMixin,
+)
+from ..resolvers import DependencyResolver, INDETERMINATE_DEPENDENCY
+
+log = logging.getLogger(__name__)
+
+
+class HomebrewToolShedDependencyResolver(
+ DependencyResolver,
+ UsesHomebrewMixin,
+ UsesToolDependencyDirMixin,
+ UsesInstalledRepositoriesMixin,
+):
+ resolver_type = "tool_shed_tap"
+
+ def __init__(self, dependency_manager, **kwds):
+ self._init_homebrew(**kwds)
+ self._init_base_path(dependency_manager, **kwds)
+
+ def resolve(self, name, version, type, **kwds):
+ if type != "package":
+ return INDETERMINATE_DEPENDENCY
+
+ if version is None:
+ return INDETERMINATE_DEPENDENCY
+
+ return self._find_tool_dependencies(name, version, type, **kwds)
+
+ def _find_tool_dependencies(self, name, version, type, **kwds):
+ installed_tool_dependency = self._get_installed_dependency(name, type, version=version, **kwds)
+ if installed_tool_dependency:
+ return self._resolve_from_installed_tool_dependency(name, version, installed_tool_dependency)
+
+ if "tool_dir" in kwds:
+ tool_directory = os.path.abspath(kwds["tool_dir"])
+ tool_depenedencies_path = os.path.join(tool_directory, "tool_dependencies.xml")
+ if os.path.exists(tool_depenedencies_path):
+ return self._resolve_from_tool_dependencies_path(name, version, tool_depenedencies_path)
+
+ return INDETERMINATE_DEPENDENCY
+
+ def _resolve_from_installed_tool_dependency(self, name, version, installed_tool_dependency):
+ tool_shed_repository = installed_tool_dependency.tool_shed_repository
+ recipe_name = build_recipe_name(
+ package_name=name,
+ package_version=version,
+ repository_owner=tool_shed_repository.owner,
+ repository_name=tool_shed_repository.name,
+ )
+ return self._find_dep_default(recipe_name, None)
+
+ def _resolve_from_tool_dependencies_path(self, name, version, tool_dependencies_path):
+ try:
+ raw_dependencies = RawDependencies(tool_dependencies_path)
+ except Exception:
+ log.debug("Failed to parse dependencies in file %s" % tool_dependencies_path)
+ return INDETERMINATE_DEPENDENCY
+
+ raw_dependency = raw_dependencies.find(name, version)
+ if not raw_dependency:
+ return INDETERMINATE_DEPENDENCY
+
+ recipe_name = build_recipe_name(
+ package_name=name,
+ package_version=version,
+ repository_owner=raw_dependency.repository_owner,
+ repository_name=raw_dependency.repository_name
+ )
+ dep = self._find_dep_default(recipe_name, None)
+ return dep
+
+
+class RawDependencies(object):
+
+ def __init__(self, dependencies_file):
+ self.root = ET.parse(dependencies_file).getroot()
+ dependencies = []
+ package_els = self.root.findall("package") or []
+ for package_el in package_els:
+ repository_el = package_el.find("repository")
+ if repository_el is None:
+ continue
+ dependency = RawDependency(self, package_el, repository_el)
+ dependencies.append(dependency)
+ self.dependencies = dependencies
+
+ def find(self, package_name, package_version):
+ target_dependency = None
+
+ for dependency in self.dependencies:
+ if dependency.package_name == package_name and dependency.package_version == package_version:
+ target_dependency = dependency
+ break
+ return target_dependency
+
+
+class RawDependency(object):
+
+ def __init__(self, dependencies, package_el, repository_el):
+ self.dependencies = dependencies
+ self.package_el = package_el
+ self.repository_el = repository_el
+
+ def __repr__(self):
+ temp = "Dependency[package_name=%s,version=%s,dependent_package=%s]"
+ return temp % (
+ self.package_el.attrib["name"],
+ self.package_el.attrib["version"],
+ self.repository_el.attrib["name"]
+ )
+
+ @property
+ def repository_owner(self):
+ return self.repository_el.attrib["owner"]
+
+ @property
+ def repository_name(self):
+ return self.repository_el.attrib["name"]
+
+ @property
+ def package_name(self):
+ return self.package_el.attrib["name"]
+
+ @property
+ def package_version(self):
+ return self.package_el.attrib["version"]
+
+
+def build_recipe_name(package_name, package_version, repository_owner, repository_name):
+ # TODO: Consider baking package_name and package_version into name? (would be more "correct")
+ owner = repository_owner.replace("-", "")
+ name = repository_name
+ name = name.replace("_", "").replace("-", "")
+ base = "%s_%s" % (owner, name)
+ return base
+
+
+__all__ = [HomebrewToolShedDependencyResolver]
diff -r 65cd7c0eee89e2d32a3369b1eb88742f23034560 -r 63d901ca0e6e9cfa405bae41f7088e3fa6bf243f lib/galaxy/tools/deps/resolvers/galaxy_packages.py
--- a/lib/galaxy/tools/deps/resolvers/galaxy_packages.py
+++ b/lib/galaxy/tools/deps/resolvers/galaxy_packages.py
@@ -1,12 +1,13 @@
-from os.path import join, islink, realpath, basename, exists, abspath
+from os.path import join, islink, realpath, basename, exists
from ..resolvers import DependencyResolver, INDETERMINATE_DEPENDENCY, Dependency
+from .resolver_mixins import UsesToolDependencyDirMixin
import logging
log = logging.getLogger( __name__ )
-class GalaxyPackageDependencyResolver(DependencyResolver):
+class GalaxyPackageDependencyResolver(DependencyResolver, UsesToolDependencyDirMixin):
resolver_type = "galaxy_packages"
def __init__(self, dependency_manager, **kwds):
@@ -16,7 +17,7 @@
## resolver that will just grab 'default' version of exact version
## unavailable.
self.versionless = str(kwds.get('versionless', "false")).lower() == "true"
- self.base_path = abspath( kwds.get('base_path', dependency_manager.default_base_path) )
+ self._init_base_path( dependency_manager, **kwds )
def resolve( self, name, version, type, **kwds ):
"""
diff -r 65cd7c0eee89e2d32a3369b1eb88742f23034560 -r 63d901ca0e6e9cfa405bae41f7088e3fa6bf243f lib/galaxy/tools/deps/resolvers/homebrew.py
--- a/lib/galaxy/tools/deps/resolvers/homebrew.py
+++ b/lib/galaxy/tools/deps/resolvers/homebrew.py
@@ -12,20 +12,19 @@
incompatible changes coming.
"""
-import os
-from ..brew_exts import DEFAULT_HOMEBREW_ROOT, recipe_cellar_path, build_env_statements
-from ..resolvers import DependencyResolver, INDETERMINATE_DEPENDENCY, Dependency
+from .resolver_mixins import UsesHomebrewMixin
+from ..resolvers import DependencyResolver, INDETERMINATE_DEPENDENCY
# TODO: Implement prefer version linked...
PREFER_VERSION_LINKED = 'linked'
PREFER_VERSION_LATEST = 'latest'
-UNKNOWN_PREFER_VERSION_MESSAGE_TEMPLATE = "HomebrewDependencyResolver prefer_version must be latest %s"
+UNKNOWN_PREFER_VERSION_MESSAGE_TEMPLATE = "HomebrewDependencyResolver prefer_version must be %s"
UNKNOWN_PREFER_VERSION_MESSAGE = UNKNOWN_PREFER_VERSION_MESSAGE_TEMPLATE % (PREFER_VERSION_LATEST)
DEFAULT_PREFER_VERSION = PREFER_VERSION_LATEST
-class HomebrewDependencyResolver(DependencyResolver):
+class HomebrewDependencyResolver(DependencyResolver, UsesHomebrewMixin):
resolver_type = "homebrew"
def __init__(self, dependency_manager, **kwds):
@@ -38,11 +37,7 @@
if self.versionless and self.prefer_version not in [PREFER_VERSION_LATEST]:
raise Exception(UNKNOWN_PREFER_VERSION_MESSAGE)
- cellar_root = kwds.get('cellar', None)
- if cellar_root is None:
- cellar_root = os.path.join(DEFAULT_HOMEBREW_ROOT, "Cellar")
-
- self.cellar_root = cellar_root
+ self._init_homebrew(**kwds)
def resolve(self, name, version, type, **kwds):
if type != "package":
@@ -53,41 +48,6 @@
else:
return self._find_dep_versioned(name, version)
- def _find_dep_versioned(self, name, version):
- recipe_path = recipe_cellar_path(self.cellar_root, name, version)
- if not os.path.exists(recipe_path) or not os.path.isdir(recipe_path):
- return INDETERMINATE_DEPENDENCY
-
- commands = build_env_statements(self.cellar_root, recipe_path, relaxed=True)
- return HomebrewDependency(commands)
-
- def _find_dep_default(self, name, version):
- installed_versions = self._installed_versions(name)
- if not installed_versions:
- return INDETERMINATE_DEPENDENCY
-
- # Just grab newest installed version - may make sense some day to find
- # the linked version instead.
- default_version = sorted(installed_versions, reverse=True)[0]
- return self._find_dep_versioned(name, default_version)
-
- def _installed_versions(self, recipe):
- recipe_base_path = os.path.join(self.cellar_root, recipe)
- if not os.path.exists(recipe_base_path):
- return []
-
- names = os.listdir(recipe_base_path)
- return filter(lambda n: os.path.isdir(os.path.join(recipe_base_path, n)), names)
-
-
-class HomebrewDependency(Dependency):
-
- def __init__(self, commands):
- self.commands = commands
-
- def shell_commands(self, requirement):
- return self.commands.replace("\n", ";") + "\n"
-
def _string_as_bool( value ):
return str( value ).lower() == "true"
diff -r 65cd7c0eee89e2d32a3369b1eb88742f23034560 -r 63d901ca0e6e9cfa405bae41f7088e3fa6bf243f lib/galaxy/tools/deps/resolvers/resolver_mixins.py
--- /dev/null
+++ b/lib/galaxy/tools/deps/resolvers/resolver_mixins.py
@@ -0,0 +1,73 @@
+import os
+from ..brew_exts import DEFAULT_HOMEBREW_ROOT, recipe_cellar_path, build_env_statements
+from ..resolvers import INDETERMINATE_DEPENDENCY, Dependency
+
+
+class UsesHomebrewMixin:
+
+ def _init_homebrew(self, **kwds):
+ cellar_root = kwds.get('cellar', None)
+ if cellar_root is None:
+ cellar_root = os.path.join(DEFAULT_HOMEBREW_ROOT, "Cellar")
+
+ self.cellar_root = cellar_root
+
+ def _find_dep_versioned(self, name, version):
+ recipe_path = recipe_cellar_path(self.cellar_root, name, version)
+ if not os.path.exists(recipe_path) or not os.path.isdir(recipe_path):
+ return INDETERMINATE_DEPENDENCY
+
+ commands = build_env_statements(self.cellar_root, recipe_path, relaxed=True)
+ return HomebrewDependency(commands)
+
+ def _find_dep_default(self, name, version):
+ installed_versions = self._installed_versions(name)
+ if not installed_versions:
+ return INDETERMINATE_DEPENDENCY
+
+ # Just grab newest installed version - may make sense some day to find
+ # the linked version instead.
+ default_version = sorted(installed_versions, reverse=True)[0]
+ return self._find_dep_versioned(name, default_version)
+
+ def _installed_versions(self, recipe):
+ recipe_base_path = os.path.join(self.cellar_root, recipe)
+ if not os.path.exists(recipe_base_path):
+ return []
+
+ names = os.listdir(recipe_base_path)
+ return filter(lambda n: os.path.isdir(os.path.join(recipe_base_path, n)), names)
+
+
+class UsesToolDependencyDirMixin:
+
+ def _init_base_path(self, dependency_manager, **kwds):
+ self.base_path = os.path.abspath( kwds.get('base_path', dependency_manager.default_base_path) )
+
+
+class UsesInstalledRepositoriesMixin:
+
+ def _get_installed_dependency( self, name, type, version=None, **kwds ):
+ installed_tool_dependencies = kwds.get("installed_tool_dependencies", [])
+ for installed_tool_dependency in (installed_tool_dependencies or []):
+ name_and_type_equal = installed_tool_dependency.name == name and installed_tool_dependency.type == type
+ if version:
+ if name_and_type_equal and installed_tool_dependency.version == version:
+ return installed_tool_dependency
+ else:
+ if name_and_type_equal:
+ return installed_tool_dependency
+ return None
+
+
+class HomebrewDependency(Dependency):
+
+ def __init__(self, commands):
+ self.commands = commands
+
+ def shell_commands(self, requirement):
+ raw_commands = self.commands.replace("\n", ";")
+ return raw_commands
+
+ def __repr__(self):
+ return "PlatformBrewDependency[commands=%s]" % self.commands
diff -r 65cd7c0eee89e2d32a3369b1eb88742f23034560 -r 63d901ca0e6e9cfa405bae41f7088e3fa6bf243f lib/galaxy/tools/deps/resolvers/tool_shed_packages.py
--- a/lib/galaxy/tools/deps/resolvers/tool_shed_packages.py
+++ b/lib/galaxy/tools/deps/resolvers/tool_shed_packages.py
@@ -1,10 +1,11 @@
from os.path import abspath, join, exists
+from .resolver_mixins import UsesInstalledRepositoriesMixin
from .galaxy_packages import GalaxyPackageDependencyResolver, GalaxyPackageDependency
from ..resolvers import INDETERMINATE_DEPENDENCY
-class ToolShedPackageDependencyResolver(GalaxyPackageDependencyResolver):
+class ToolShedPackageDependencyResolver(GalaxyPackageDependencyResolver, UsesInstalledRepositoriesMixin):
resolver_type = "tool_shed_packages"
def __init__(self, dependency_manager, **kwds):
@@ -12,9 +13,8 @@
def _find_dep_versioned( self, name, version, type='package', **kwds ):
installed_tool_dependency = self._get_installed_dependency( name, type, version=version, **kwds )
- base_path = self.base_path
if installed_tool_dependency:
- path = self._get_package_installed_dependency_path( installed_tool_dependency, base_path, name, version )
+ path = self._get_package_installed_dependency_path( installed_tool_dependency, name, version )
return self._galaxy_package_dep(path, version)
else:
return INDETERMINATE_DEPENDENCY
@@ -29,26 +29,17 @@
return GalaxyPackageDependency(dependency.script, dependency.path, None)
return INDETERMINATE_DEPENDENCY
- def _get_installed_dependency( self, name, type, version=None, **kwds ):
- installed_tool_dependencies = kwds.get("installed_tool_dependencies", [])
- for installed_tool_dependency in (installed_tool_dependencies or []):
- name_and_type_equal = installed_tool_dependency.name == name and installed_tool_dependency.type == type
- if version:
- if name_and_type_equal and installed_tool_dependency.version == version:
- return installed_tool_dependency
- else:
- if name_and_type_equal:
- return installed_tool_dependency
- return None
-
- def _get_package_installed_dependency_path( self, installed_tool_dependency, base_path, name, version ):
+ def _get_package_installed_dependency_path( self, installed_tool_dependency, name, version ):
tool_shed_repository = installed_tool_dependency.tool_shed_repository
- return join( base_path,
- name,
- version,
- tool_shed_repository.owner,
- tool_shed_repository.name,
- tool_shed_repository.installed_changeset_revision )
+ base_path = self.base_path
+ return join(
+ base_path,
+ name,
+ version,
+ tool_shed_repository.owner,
+ tool_shed_repository.name,
+ tool_shed_repository.installed_changeset_revision
+ )
def _get_set_environment_installed_dependency_script_path( self, installed_tool_dependency, name ):
tool_shed_repository = installed_tool_dependency.tool_shed_repository
@@ -64,4 +55,5 @@
return GalaxyPackageDependency(script, path, None)
return INDETERMINATE_DEPENDENCY
+
__all__ = [ToolShedPackageDependencyResolver]
diff -r 65cd7c0eee89e2d32a3369b1eb88742f23034560 -r 63d901ca0e6e9cfa405bae41f7088e3fa6bf243f lib/galaxy/util/plugin_config.py
--- a/lib/galaxy/util/plugin_config.py
+++ b/lib/galaxy/util/plugin_config.py
@@ -24,7 +24,7 @@
for plugin_module in submodules( module ):
# FIXME: this is not how one is suppose to use __all__ why did you do
# this past John?
- for clazz in plugin_module.__all__:
+ for clazz in getattr( plugin_module, "__all__", [] ):
plugin_type = getattr( clazz, plugin_type_identifier, None )
if plugin_type:
plugin_dict[ plugin_type ] = clazz
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Clarify source of errors reported by anonymous users who don't provide a contact email address.
by commits-noreply@bitbucket.org 07 Jan '15
by commits-noreply@bitbucket.org 07 Jan '15
07 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8c57fc528cb7/
Changeset: 8c57fc528cb7
User: dannon
Date: 2015-01-07 19:10:42+00:00
Summary: Clarify source of errors reported by anonymous users who don't provide a contact email address.
Affected #: 1 file
diff -r 81e27001166b0e01b89eabc79d32b0adf72d5ef5 -r 8c57fc528cb7255ab11d20b03b5dd8509e3ea5a0 lib/galaxy/tools/errors.py
--- a/lib/galaxy/tools/errors.py
+++ b/lib/galaxy/tools/errors.py
@@ -86,7 +86,7 @@
if user and user.email != email:
email_str = "'%s' (providing preferred contact email '%s')" % (user.email, email)
else:
- email_str = "'%s'" % email
+ email_str = "'%s'" % (email or 'anonymously')
self.report = string.Template( error_report_template ) \
.safe_substitute( host=host,
dataset_id=hda.dataset_id,
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Use set_tags_from_list for PJA instead of apply_item_tags.
by commits-noreply@bitbucket.org 07 Jan '15
by commits-noreply@bitbucket.org 07 Jan '15
07 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/81e27001166b/
Changeset: 81e27001166b
User: dannon
Date: 2015-01-07 18:45:12+00:00
Summary: Use set_tags_from_list for PJA instead of apply_item_tags.
Affected #: 2 files
diff -r 53e839193da1f58b15834b07a61a3c131267795f -r 81e27001166b0e01b89eabc79d32b0adf72d5ef5 lib/galaxy/jobs/actions/post.py
--- a/lib/galaxy/jobs/actions/post.py
+++ b/lib/galaxy/jobs/actions/post.py
@@ -428,12 +428,11 @@
@classmethod
def execute(cls, app, sa_session, action, job, replacement_dict):
if action.action_arguments:
- tags = ','.join([t.strip() for t in action.action_arguments.get('tags', '').split(',')])
+ tags = [t.strip() for t in action.action_arguments.get('tags', '').split(',')]
if tags:
for dataset_assoc in job.output_datasets:
if action.output_name == '' or dataset_assoc.name == action.output_name:
- app.tag_handler.apply_item_tags( job.user, dataset_assoc.dataset,
- unicode(tags.encode('utf-8'), 'utf-8'))
+ app.tag_handler.set_tags_from_list( job.user, dataset_assoc.dataset, tags)
sa_session.flush()
@classmethod
diff -r 53e839193da1f58b15834b07a61a3c131267795f -r 81e27001166b0e01b89eabc79d32b0adf72d5ef5 lib/galaxy/managers/tags.py
--- a/lib/galaxy/managers/tags.py
+++ b/lib/galaxy/managers/tags.py
@@ -1,5 +1,5 @@
+import logging
import re
-import logging
from sqlalchemy.sql import select
from sqlalchemy.sql.expression import func
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
07 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/53e839193da1/
Changeset: 53e839193da1
User: dannon
Date: 2015-01-07 18:26:22+00:00
Summary: Tag manager PEP8.
Affected #: 1 file
diff -r 504fd0cce279c54003fb9c38ad9107ae9fea6ce6 -r 53e839193da1f58b15834b07a61a3c131267795f lib/galaxy/managers/tags.py
--- a/lib/galaxy/managers/tags.py
+++ b/lib/galaxy/managers/tags.py
@@ -7,7 +7,7 @@
log = logging.getLogger( __name__ )
-#Item-specific information needed to perform tagging.
+# Item-specific information needed to perform tagging.
class ItemTagAssocInfo( object ):
def __init__( self, item_class, tag_assoc_class, item_id_col ):
self.item_class = item_class
@@ -36,8 +36,8 @@
self.item_tag_assoc_info = {}
def set_tags_from_list( self, user, item, new_tags_list ):
- #precondition: item is already security checked against user
- #precondition: incoming tags is a list of sanitized/formatted strings
+ # precondition: item is already security checked against user
+ # precondition: incoming tags is a list of sanitized/formatted strings
self.delete_item_tags( user, item )
new_tags_str = ','.join( new_tags_list )
@@ -83,7 +83,7 @@
def get_tool_tags( self ):
result_set = self.app.model.context.execute( select( columns=[ self.app.model.ToolTagAssociation.table.c.tag_id ],
- from_obj=self.app.model.ToolTagAssociation.table ).distinct() )
+ from_obj=self.app.model.ToolTagAssociation.table ).distinct() )
tags = []
for row in result_set:
@@ -289,6 +289,7 @@
name_value_pair.append( None )
return name_value_pair
+
class GalaxyTagManager( TagManager ):
def __init__( self, app ):
from galaxy import model
@@ -313,5 +314,4 @@
class CommunityTagManager( TagManager):
def __init__( self, app ):
- from galaxy.webapps.tool_shed import model # ?huh?
TagManager.__init__( self, app )
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
4 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/dcc40b6cdb65/
Changeset: dcc40b6cdb65
User: dannon
Date: 2015-01-06 21:09:47+00:00
Summary: Initial commit of TagManager refactor.
Affected #: 5 files
diff -r d50ee9520583c225e48c577ab977f18fd6cb7d6a -r dcc40b6cdb65043fa0800c2852b60059b81bab91 lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -7,7 +7,7 @@
import galaxy.security
from galaxy.managers.collections import DatasetCollectionManager
import galaxy.quota
-from galaxy.tags.tag_handler import GalaxyTagHandler
+from galaxy.managers.tags import GalaxyTagManager
from galaxy.visualization.genomes import Genomes
from galaxy.visualization.data_providers.registry import DataProviderRegistry
from galaxy.visualization.registry import VisualizationsRegistry
@@ -58,7 +58,7 @@
# Security helper
self._configure_security()
# Tag handler
- self.tag_handler = GalaxyTagHandler()
+ self.tag_handler = GalaxyTagManager( self )
# Dataset Collection Plugins
self.dataset_collections_service = DatasetCollectionManager(self)
diff -r d50ee9520583c225e48c577ab977f18fd6cb7d6a -r dcc40b6cdb65043fa0800c2852b60059b81bab91 lib/galaxy/managers/collections.py
--- a/lib/galaxy/managers/collections.py
+++ b/lib/galaxy/managers/collections.py
@@ -36,7 +36,7 @@
self.security = app.security
self.hda_manager = hdas.HDAManager()
self.history_manager = histories.HistoryManager()
- self.tag_manager = tags.TagsManager( app )
+ self.tag_manager = tags.TagManager( app )
self.ldda_manager = lddas.LDDAManager( )
def create(
@@ -163,7 +163,7 @@
dataset_collection_instance.add_item_annotation( trans.sa_session, trans.get_user(), dataset_collection_instance, new_data[ 'annotation' ] )
changed[ 'annotation' ] = new_data[ 'annotation' ]
if 'tags' in new_data.keys() and trans.get_user():
- self.tag_manager.set_tags_from_list( trans, dataset_collection_instance, new_data[ 'tags' ], user=trans.user )
+ self.tag_manager.set_tags_from_list( trans.get_user(), dataset_collection_instance, new_data[ 'tags' ] )
if changed.keys():
trans.sa_session.flush()
diff -r d50ee9520583c225e48c577ab977f18fd6cb7d6a -r dcc40b6cdb65043fa0800c2852b60059b81bab91 lib/galaxy/managers/tags.py
--- a/lib/galaxy/managers/tags.py
+++ b/lib/galaxy/managers/tags.py
@@ -1,20 +1,317 @@
+import re
+import logging
+from sqlalchemy.sql import select
+from sqlalchemy.sql.expression import func
-class TagsManager( object ):
- """ Manages CRUD operations related to tagging objects.
+log = logging.getLogger( __name__ )
+
+
+#Item-specific information needed to perform tagging.
+class ItemTagAssocInfo( object ):
+ def __init__( self, item_class, tag_assoc_class, item_id_col ):
+ self.item_class = item_class
+ self.tag_assoc_class = tag_assoc_class
+ self.item_id_col = item_id_col
+
+
+class TagManager( object ):
+ """
+ Manages CRUD operations related to tagging objects.
"""
def __init__( self, app ):
self.app = app
- self.tag_handler = app.tag_handler
+ # Minimum tag length.
+ self.min_tag_len = 2
+ # Maximum tag length.
+ self.max_tag_len = 255
+ # Tag separator.
+ self.tag_separators = ',;'
+ # Hierarchy separator.
+ self.hierarchy_separator = '.'
+ # Key-value separator.
+ self.key_value_separators = "=:"
+ # Initialize with known classes - add to this in subclasses.
+ self.item_tag_assoc_info = {}
- def set_tags_from_list( self, trans, item, new_tags_list, user=None ):
+ def set_tags_from_list( self, user, item, new_tags_list ):
#precondition: item is already security checked against user
#precondition: incoming tags is a list of sanitized/formatted strings
- user = user or trans.user
- self.tag_handler.delete_item_tags( trans, user, item )
+ self.delete_item_tags( user, item )
new_tags_str = ','.join( new_tags_list )
- self.tag_handler.apply_item_tags( trans, user, item, unicode( new_tags_str.encode( 'utf-8' ), 'utf-8' ) )
- trans.sa_session.flush()
+ self.apply_item_tags( user, item, unicode( new_tags_str.encode( 'utf-8' ), 'utf-8' ) )
+ self.app.model.context.flush()
return item.tags
+
+ def get_tag_assoc_class( self, item_class ):
+ """Returns tag association class for item class."""
+ return self.item_tag_assoc_info[item_class.__name__].tag_assoc_class
+
+ def get_id_col_in_item_tag_assoc_table( self, item_class ):
+ """Returns item id column in class' item-tag association table."""
+ return self.item_tag_assoc_info[item_class.__name__].item_id_col
+
+ def get_community_tags( self, item=None, limit=None ):
+ """Returns community tags for an item."""
+ # Get item-tag association class.
+ item_class = item.__class__
+ item_tag_assoc_class = self.get_tag_assoc_class( item_class )
+ if not item_tag_assoc_class:
+ return []
+ # Build select statement.
+ cols_to_select = [ item_tag_assoc_class.table.c.tag_id, func.count( '*' ) ]
+ from_obj = item_tag_assoc_class.table.join( item_class.table ).join( self.app.model.Tag.table )
+ where_clause = ( self.get_id_col_in_item_tag_assoc_table( item_class ) == item.id )
+ order_by = [ func.count( "*" ).desc() ]
+ group_by = item_tag_assoc_class.table.c.tag_id
+ # Do query and get result set.
+ query = select( columns=cols_to_select,
+ from_obj=from_obj,
+ whereclause=where_clause,
+ group_by=group_by,
+ order_by=order_by,
+ limit=limit )
+ result_set = self.app.model.context.execute( query )
+ # Return community tags.
+ community_tags = []
+ for row in result_set:
+ tag_id = row[0]
+ community_tags.append( self.get_tag_by_id( tag_id ) )
+ return community_tags
+
+ def get_tool_tags( self ):
+ result_set = self.app.model.context.execute( select( columns=[ self.app.model.ToolTagAssociation.table.c.tag_id ],
+ from_obj=self.app.model.ToolTagAssociation.table ).distinct() )
+
+ tags = []
+ for row in result_set:
+ tag_id = row[0]
+ tags.append( self.get_tag_by_id( tag_id ) )
+ return tags
+
+ def remove_item_tag( self, user, item, tag_name ):
+ """Remove a tag from an item."""
+ # Get item tag association.
+ item_tag_assoc = self._get_item_tag_assoc( user, item, tag_name )
+ # Remove association.
+ if item_tag_assoc:
+ # Delete association.
+ self.app.model.context.delete( item_tag_assoc )
+ item.tags.remove( item_tag_assoc )
+ return True
+ return False
+
+ def delete_item_tags( self, user, item ):
+ """Delete tags from an item."""
+ # Delete item-tag associations.
+ for tag in item.tags:
+ self.app.model.context.delete( tag )
+ # Delete tags from item.
+ del item.tags[:]
+
+ def item_has_tag( self, user, item, tag ):
+ """Returns true if item is has a given tag."""
+ # Get tag name.
+ if isinstance( tag, basestring ):
+ tag_name = tag
+ elif isinstance( tag, self.app.model.Tag ):
+ tag_name = tag.name
+ # Check for an item-tag association to see if item has a given tag.
+ item_tag_assoc = self._get_item_tag_assoc( user, item, tag_name )
+ if item_tag_assoc:
+ return True
+ return False
+
+ def apply_item_tag( self, user, item, name, value=None ):
+ # Use lowercase name for searching/creating tag.
+ lc_name = name.lower()
+ # Get or create item-tag association.
+ item_tag_assoc = self._get_item_tag_assoc( user, item, lc_name )
+ if not item_tag_assoc:
+ # Create item-tag association.
+ # Create tag; if None, skip the tag (and log error).
+ tag = self._get_or_create_tag( lc_name )
+ if not tag:
+ log.warn( "Failed to create tag with name %s" % lc_name )
+ return
+ # Create tag association based on item class.
+ item_tag_assoc_class = self.get_tag_assoc_class( item.__class__ )
+ item_tag_assoc = item_tag_assoc_class()
+ # Add tag to association.
+ item.tags.append( item_tag_assoc )
+ item_tag_assoc.tag = tag
+ item_tag_assoc.user = user
+ # Apply attributes to item-tag association. Strip whitespace from user name and tag.
+ lc_value = None
+ if value:
+ lc_value = value.lower()
+ item_tag_assoc.user_tname = name
+ item_tag_assoc.user_value = value
+ item_tag_assoc.value = lc_value
+ return item_tag_assoc
+
+ def apply_item_tags( self, user, item, tags_str ):
+ """Apply tags to an item."""
+ # Parse tags.
+ parsed_tags = self.parse_tags( tags_str )
+ # Apply each tag.
+ for name, value in parsed_tags.items():
+ self.apply_item_tag( user, item, name, value )
+
+ def get_tags_str( self, tags ):
+ """Build a string from an item's tags."""
+ # Return empty string if there are no tags.
+ if not tags:
+ return ""
+ # Create string of tags.
+ tags_str_list = list()
+ for tag in tags:
+ tag_str = tag.user_tname
+ if tag.value is not None:
+ tag_str += ":" + tag.user_value
+ tags_str_list.append( tag_str )
+ return ", ".join( tags_str_list )
+
+ def get_tag_by_id( self, tag_id ):
+ """Get a Tag object from a tag id."""
+ return self.app.model.context.query( self.app.model.Tag ).filter_by( id=tag_id ).first()
+
+ def get_tag_by_name( self, tag_name ):
+ """Get a Tag object from a tag name (string)."""
+ if tag_name:
+ return self.app.model.context.query( self.app.model.Tag ).filter_by( name=tag_name.lower() ).first()
+ return None
+
+ def _create_tag( self, tag_str ):
+ """Create a Tag object from a tag string."""
+ tag_hierarchy = tag_str.split( self.hierarchy_separator )
+ tag_prefix = ""
+ parent_tag = None
+ for sub_tag in tag_hierarchy:
+ # Get or create subtag.
+ tag_name = tag_prefix + self._scrub_tag_name( sub_tag )
+ tag = self.app.model.context.query( self.app.model.Tag ).filter_by( name=tag_name).first()
+ if not tag:
+ tag = self.app.model.Tag( type=0, name=tag_name )
+ # Set tag parent.
+ tag.parent = parent_tag
+ # Update parent and tag prefix.
+ parent_tag = tag
+ tag_prefix = tag.name + self.hierarchy_separator
+ return tag
+
+ def _get_or_create_tag( self, tag_str ):
+ """Get or create a Tag object from a tag string."""
+ # Scrub tag; if tag is None after being scrubbed, return None.
+ scrubbed_tag_str = self._scrub_tag_name( tag_str )
+ if not scrubbed_tag_str:
+ return None
+ # Get item tag.
+ tag = self.get_tag_by_name( scrubbed_tag_str )
+ # Create tag if necessary.
+ if tag is None:
+ tag = self._create_tag( scrubbed_tag_str )
+ return tag
+
+ def _get_item_tag_assoc( self, user, item, tag_name ):
+ """
+ Return ItemTagAssociation object for a user, item, and tag string; returns None if there is
+ no such association.
+ """
+ scrubbed_tag_name = self._scrub_tag_name( tag_name )
+ for item_tag_assoc in item.tags:
+ if ( item_tag_assoc.user == user ) and ( item_tag_assoc.user_tname == scrubbed_tag_name ):
+ return item_tag_assoc
+ return None
+
+ def parse_tags( self, tag_str ):
+ """
+ Returns a list of raw (tag-name, value) pairs derived from a string; method scrubs tag names and values as well.
+ Return value is a dictionary where tag-names are keys.
+ """
+ # Gracefully handle None.
+ if not tag_str:
+ return dict()
+ # Split tags based on separators.
+ reg_exp = re.compile( '[' + self.tag_separators + ']' )
+ raw_tags = reg_exp.split( tag_str )
+ # Extract name-value pairs.
+ name_value_pairs = dict()
+ for raw_tag in raw_tags:
+ nv_pair = self._get_name_value_pair( raw_tag )
+ scrubbed_name = self._scrub_tag_name( nv_pair[0] )
+ scrubbed_value = self._scrub_tag_value( nv_pair[1] )
+ name_value_pairs[scrubbed_name] = scrubbed_value
+ return name_value_pairs
+
+ def _scrub_tag_value( self, value ):
+ """Scrub a tag value."""
+ # Gracefully handle None:
+ if not value:
+ return None
+ # Remove whitespace from value.
+ reg_exp = re.compile( '\s' )
+ scrubbed_value = re.sub( reg_exp, "", value )
+ return scrubbed_value
+
+ def _scrub_tag_name( self, name ):
+ """Scrub a tag name."""
+ # Gracefully handle None:
+ if not name:
+ return None
+ # Remove whitespace from name.
+ reg_exp = re.compile( '\s' )
+ scrubbed_name = re.sub( reg_exp, "", name )
+ # Ignore starting ':' char.
+ if scrubbed_name.startswith( self.hierarchy_separator ):
+ scrubbed_name = scrubbed_name[1:]
+ # If name is too short or too long, return None.
+ if len( scrubbed_name ) < self.min_tag_len or len( scrubbed_name ) > self.max_tag_len:
+ return None
+ return scrubbed_name
+
+ def _scrub_tag_name_list( self, tag_name_list ):
+ """Scrub a tag name list."""
+ scrubbed_tag_list = list()
+ for tag in tag_name_list:
+ scrubbed_tag_list.append( self._scrub_tag_name( tag ) )
+ return scrubbed_tag_list
+
+ def _get_name_value_pair( self, tag_str ):
+ """Get name, value pair from a tag string."""
+ # Use regular expression to parse name, value.
+ reg_exp = re.compile( "[" + self.key_value_separators + "]" )
+ name_value_pair = reg_exp.split( tag_str )
+ # Add empty slot if tag does not have value.
+ if len( name_value_pair ) < 2:
+ name_value_pair.append( None )
+ return name_value_pair
+
+class GalaxyTagManager( TagManager ):
+ def __init__( self, app ):
+ from galaxy import model
+ TagManager.__init__( self, app )
+ self.item_tag_assoc_info["History"] = ItemTagAssocInfo( model.History,
+ model.HistoryTagAssociation,
+ model.HistoryTagAssociation.table.c.history_id )
+ self.item_tag_assoc_info["HistoryDatasetAssociation"] = \
+ ItemTagAssocInfo( model.HistoryDatasetAssociation,
+ model.HistoryDatasetAssociationTagAssociation,
+ model.HistoryDatasetAssociationTagAssociation.table.c.history_dataset_association_id )
+ self.item_tag_assoc_info["Page"] = ItemTagAssocInfo( model.Page,
+ model.PageTagAssociation,
+ model.PageTagAssociation.table.c.page_id )
+ self.item_tag_assoc_info["StoredWorkflow"] = ItemTagAssocInfo( model.StoredWorkflow,
+ model.StoredWorkflowTagAssociation,
+ model.StoredWorkflowTagAssociation.table.c.stored_workflow_id )
+ self.item_tag_assoc_info["Visualization"] = ItemTagAssocInfo( model.Visualization,
+ model.VisualizationTagAssociation,
+ model.VisualizationTagAssociation.table.c.visualization_id )
+
+
+class CommunityTagManager( TagManager):
+ def __init__( self ):
+ from galaxy.webapps.tool_shed import model # ?huh?
+ TagManager.__init__( self )
diff -r d50ee9520583c225e48c577ab977f18fd6cb7d6a -r dcc40b6cdb65043fa0800c2852b60059b81bab91 lib/galaxy/tags/tag_handler.py
--- a/lib/galaxy/tags/tag_handler.py
+++ b/lib/galaxy/tags/tag_handler.py
@@ -1,301 +0,0 @@
-import re
-import logging
-from sqlalchemy.sql.expression import func
-from sqlalchemy.sql.expression import and_
-from sqlalchemy.sql import select
-
-log = logging.getLogger( __name__ )
-
-# Item-specific information needed to perform tagging.
-class ItemTagAssocInfo( object ):
- def __init__( self, item_class, tag_assoc_class, item_id_col ):
- self.item_class = item_class
- self.tag_assoc_class = tag_assoc_class
- self.item_id_col = item_id_col
-
-class TagHandler( object ):
- def __init__( self ):
- # Minimum tag length.
- self.min_tag_len = 2
- # Maximum tag length.
- self.max_tag_len = 255
- # Tag separator.
- self.tag_separators = ',;'
- # Hierarchy separator.
- self.hierarchy_separator = '.'
- # Key-value separator.
- self.key_value_separators = "=:"
- # Initialize with known classes - add to this in subclasses.
- self.item_tag_assoc_info = {}
-
- def get_tag_assoc_class( self, item_class ):
- """Returns tag association class for item class."""
- return self.item_tag_assoc_info[item_class.__name__].tag_assoc_class
-
- def get_id_col_in_item_tag_assoc_table( self, item_class ):
- """Returns item id column in class' item-tag association table."""
- return self.item_tag_assoc_info[item_class.__name__].item_id_col
-
- def get_community_tags( self, trans, item=None, limit=None ):
- """Returns community tags for an item."""
- # Get item-tag association class.
- item_class = item.__class__
- item_tag_assoc_class = self.get_tag_assoc_class( item_class )
- if not item_tag_assoc_class:
- return []
- # Build select statement.
- cols_to_select = [ item_tag_assoc_class.table.c.tag_id, func.count( '*' ) ]
- from_obj = item_tag_assoc_class.table.join( item_class.table ).join( trans.app.model.Tag.table )
- where_clause = ( self.get_id_col_in_item_tag_assoc_table( item_class ) == item.id )
- order_by = [ func.count( "*" ).desc() ]
- group_by = item_tag_assoc_class.table.c.tag_id
- # Do query and get result set.
- query = select( columns=cols_to_select,
- from_obj=from_obj,
- whereclause=where_clause,
- group_by=group_by,
- order_by=order_by,
- limit=limit )
- result_set = trans.sa_session.execute( query )
- # Return community tags.
- community_tags = []
- for row in result_set:
- tag_id = row[0]
- community_tags.append( self.get_tag_by_id( trans, tag_id ) )
- return community_tags
-
- def get_tool_tags( self, trans ):
- result_set = trans.sa_session.execute( select( columns=[ trans.app.model.ToolTagAssociation.table.c.tag_id ],
- from_obj=trans.app.model.ToolTagAssociation.table ).distinct() )
-
- tags = []
- for row in result_set:
- tag_id = row[0]
- tags.append( self.get_tag_by_id( trans, tag_id ) )
- return tags
-
- def remove_item_tag( self, trans, user, item, tag_name ):
- """Remove a tag from an item."""
- # Get item tag association.
- item_tag_assoc = self._get_item_tag_assoc( user, item, tag_name )
- # Remove association.
- if item_tag_assoc:
- # Delete association.
- trans.sa_session.delete( item_tag_assoc )
- item.tags.remove( item_tag_assoc )
- return True
- return False
-
- def delete_item_tags( self, trans, user, item ):
- """Delete tags from an item."""
- # Delete item-tag associations.
- for tag in item.tags:
- trans.sa_session.delete( tag )
- # Delete tags from item.
- del item.tags[:]
-
- def item_has_tag( self, trans, user, item, tag ):
- """Returns true if item is has a given tag."""
- # Get tag name.
- if isinstance( tag, basestring ):
- tag_name = tag
- elif isinstance( tag, trans.app.model.Tag ):
- tag_name = tag.name
- # Check for an item-tag association to see if item has a given tag.
- item_tag_assoc = self._get_item_tag_assoc( user, item, tag_name )
- if item_tag_assoc:
- return True
- return False
-
- def apply_item_tag( self, trans, user, item, name, value=None ):
- # Use lowercase name for searching/creating tag.
- lc_name = name.lower()
- # Get or create item-tag association.
- item_tag_assoc = self._get_item_tag_assoc( user, item, lc_name )
- if not item_tag_assoc:
- # Create item-tag association.
- # Create tag; if None, skip the tag (and log error).
- tag = self._get_or_create_tag( trans, lc_name )
- if not tag:
- log.warn( "Failed to create tag with name %s" % lc_name )
- return
- # Create tag association based on item class.
- item_tag_assoc_class = self.get_tag_assoc_class( item.__class__ )
- item_tag_assoc = item_tag_assoc_class()
- # Add tag to association.
- item.tags.append( item_tag_assoc )
- item_tag_assoc.tag = tag
- item_tag_assoc.user = user
- # Apply attributes to item-tag association. Strip whitespace from user name and tag.
- lc_value = None
- if value:
- lc_value = value.lower()
- item_tag_assoc.user_tname = name
- item_tag_assoc.user_value = value
- item_tag_assoc.value = lc_value
- return item_tag_assoc
-
- def apply_item_tags( self, trans, user, item, tags_str ):
- """Apply tags to an item."""
- # Parse tags.
- parsed_tags = self.parse_tags( tags_str )
- # Apply each tag.
- for name, value in parsed_tags.items():
- self.apply_item_tag( trans, user, item, name, value )
-
- def get_tags_str( self, tags ):
- """Build a string from an item's tags."""
- # Return empty string if there are no tags.
- if not tags:
- return ""
- # Create string of tags.
- tags_str_list = list()
- for tag in tags:
- tag_str = tag.user_tname
- if tag.value is not None:
- tag_str += ":" + tag.user_value
- tags_str_list.append( tag_str )
- return ", ".join( tags_str_list )
-
- def get_tag_by_id( self, trans, tag_id ):
- """Get a Tag object from a tag id."""
- return trans.sa_session.query( trans.app.model.Tag ).filter_by( id=tag_id ).first()
-
- def get_tag_by_name( self, trans, tag_name ):
- """Get a Tag object from a tag name (string)."""
- if tag_name:
- return trans.sa_session.query( trans.app.model.Tag ).filter_by( name=tag_name.lower() ).first()
- return None
-
- def _create_tag( self, trans, tag_str ):
- """Create a Tag object from a tag string."""
- tag_hierarchy = tag_str.split( self.hierarchy_separator )
- tag_prefix = ""
- parent_tag = None
- for sub_tag in tag_hierarchy:
- # Get or create subtag.
- tag_name = tag_prefix + self._scrub_tag_name( sub_tag )
- tag = trans.sa_session.query( trans.app.model.Tag ).filter_by( name=tag_name).first()
- if not tag:
- tag = trans.app.model.Tag( type=0, name=tag_name )
- # Set tag parent.
- tag.parent = parent_tag
- # Update parent and tag prefix.
- parent_tag = tag
- tag_prefix = tag.name + self.hierarchy_separator
- return tag
-
- def _get_or_create_tag( self, trans, tag_str ):
- """Get or create a Tag object from a tag string."""
- # Scrub tag; if tag is None after being scrubbed, return None.
- scrubbed_tag_str = self._scrub_tag_name( tag_str )
- if not scrubbed_tag_str:
- return None
- # Get item tag.
- tag = self.get_tag_by_name( trans, scrubbed_tag_str )
- # Create tag if necessary.
- if tag is None:
- tag = self._create_tag( trans, scrubbed_tag_str )
- return tag
-
- def _get_item_tag_assoc( self, user, item, tag_name ):
- """
- Return ItemTagAssociation object for a user, item, and tag string; returns None if there is
- no such association.
- """
- scrubbed_tag_name = self._scrub_tag_name( tag_name )
- for item_tag_assoc in item.tags:
- if ( item_tag_assoc.user == user ) and ( item_tag_assoc.user_tname == scrubbed_tag_name ):
- return item_tag_assoc
- return None
-
- def parse_tags( self, tag_str ):
- """
- Returns a list of raw (tag-name, value) pairs derived from a string; method scrubs tag names and values as well.
- Return value is a dictionary where tag-names are keys.
- """
- # Gracefully handle None.
- if not tag_str:
- return dict()
- # Split tags based on separators.
- reg_exp = re.compile( '[' + self.tag_separators + ']' )
- raw_tags = reg_exp.split( tag_str )
- # Extract name-value pairs.
- name_value_pairs = dict()
- for raw_tag in raw_tags:
- nv_pair = self._get_name_value_pair( raw_tag )
- scrubbed_name = self._scrub_tag_name( nv_pair[0] )
- scrubbed_value = self._scrub_tag_value( nv_pair[1] )
- name_value_pairs[scrubbed_name] = scrubbed_value
- return name_value_pairs
-
- def _scrub_tag_value( self, value ):
- """Scrub a tag value."""
- # Gracefully handle None:
- if not value:
- return None
- # Remove whitespace from value.
- reg_exp = re.compile( '\s' )
- scrubbed_value = re.sub( reg_exp, "", value )
- return scrubbed_value
-
- def _scrub_tag_name( self, name ):
- """Scrub a tag name."""
- # Gracefully handle None:
- if not name:
- return None
- # Remove whitespace from name.
- reg_exp = re.compile( '\s' )
- scrubbed_name = re.sub( reg_exp, "", name )
- # Ignore starting ':' char.
- if scrubbed_name.startswith( self.hierarchy_separator ):
- scrubbed_name = scrubbed_name[1:]
- # If name is too short or too long, return None.
- if len( scrubbed_name ) < self.min_tag_len or len( scrubbed_name ) > self.max_tag_len:
- return None
- return scrubbed_name
-
- def _scrub_tag_name_list( self, tag_name_list ):
- """Scrub a tag name list."""
- scrubbed_tag_list = list()
- for tag in tag_name_list:
- scrubbed_tag_list.append( self._scrub_tag_name( tag ) )
- return scrubbed_tag_list
-
- def _get_name_value_pair( self, tag_str ):
- """Get name, value pair from a tag string."""
- # Use regular expression to parse name, value.
- reg_exp = re.compile( "[" + self.key_value_separators + "]" )
- name_value_pair = reg_exp.split( tag_str )
- # Add empty slot if tag does not have value.
- if len( name_value_pair ) < 2:
- name_value_pair.append( None )
- return name_value_pair
-
-
-class GalaxyTagHandler( TagHandler ):
- def __init__( self ):
- from galaxy import model
- TagHandler.__init__( self )
- self.item_tag_assoc_info["History"] = ItemTagAssocInfo( model.History,
- model.HistoryTagAssociation,
- model.HistoryTagAssociation.table.c.history_id )
- self.item_tag_assoc_info["HistoryDatasetAssociation"] = \
- ItemTagAssocInfo( model.HistoryDatasetAssociation,
- model.HistoryDatasetAssociationTagAssociation,
- model.HistoryDatasetAssociationTagAssociation.table.c.history_dataset_association_id )
- self.item_tag_assoc_info["Page"] = ItemTagAssocInfo( model.Page,
- model.PageTagAssociation,
- model.PageTagAssociation.table.c.page_id )
- self.item_tag_assoc_info["StoredWorkflow"] = ItemTagAssocInfo( model.StoredWorkflow,
- model.StoredWorkflowTagAssociation,
- model.StoredWorkflowTagAssociation.table.c.stored_workflow_id )
- self.item_tag_assoc_info["Visualization"] = ItemTagAssocInfo( model.Visualization,
- model.VisualizationTagAssociation,
- model.VisualizationTagAssociation.table.c.visualization_id )
-
-
-class CommunityTagHandler( TagHandler ):
- def __init__( self ):
- from galaxy.webapps.tool_shed import model
- TagHandler.__init__( self )
diff -r d50ee9520583c225e48c577ab977f18fd6cb7d6a -r dcc40b6cdb65043fa0800c2852b60059b81bab91 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -2523,8 +2523,8 @@
def set_tags_from_list( self, trans, item, new_tags_list, user=None ):
# Method deprecated - try to use TagsHandler instead.
- tags_manager = tags.TagsManager( trans.app )
- return tags_manager.set_tags_from_list( trans, item, new_tags_list, user=user )
+ tags_manager = tags.GalaxyTagManager( trans.app )
+ return tags_manager.set_tags_from_list( user, item, new_tags_list )
def get_user_tags_used( self, trans, user=None ):
"""
https://bitbucket.org/galaxy/galaxy-central/commits/6bb0ddd5a4cc/
Changeset: 6bb0ddd5a4cc
User: dannon
Date: 2015-01-06 21:14:30+00:00
Summary: Update toolshed tag handler, but I don't think it's ever used.
Affected #: 2 files
diff -r dcc40b6cdb65043fa0800c2852b60059b81bab91 -r 6bb0ddd5a4cc1cba6e42fb838fabcfe818fc8ddb lib/galaxy/managers/tags.py
--- a/lib/galaxy/managers/tags.py
+++ b/lib/galaxy/managers/tags.py
@@ -312,6 +312,6 @@
class CommunityTagManager( TagManager):
- def __init__( self ):
+ def __init__( self, app ):
from galaxy.webapps.tool_shed import model # ?huh?
- TagManager.__init__( self )
+ TagManager.__init__( self, app )
diff -r dcc40b6cdb65043fa0800c2852b60059b81bab91 -r 6bb0ddd5a4cc1cba6e42fb838fabcfe818fc8ddb lib/galaxy/webapps/tool_shed/app.py
--- a/lib/galaxy/webapps/tool_shed/app.py
+++ b/lib/galaxy/webapps/tool_shed/app.py
@@ -8,7 +8,7 @@
from galaxy.openid.providers import OpenIDProviders
from galaxy.util.dbkeys import GenomeBuilds
from galaxy.web import security
-from galaxy.tags.tag_handler import CommunityTagHandler
+from galaxy.managers.tags import CommunityTagManager
from tool_shed.grids.repository_grid_filter_manager import RepositoryGridFilterManager
import tool_shed.repository_registry
import tool_shed.repository_types.registry
@@ -47,7 +47,7 @@
# Initialize the Tool SHed security helper.
self.security = security.SecurityHelper( id_secret=self.config.id_secret )
# initialize the Tool Shed tag handler.
- self.tag_handler = CommunityTagHandler()
+ self.tag_handler = CommunityTagManager( self )
# Initialize the Tool Shed tool data tables. Never pass a configuration file here
# because the Tool Shed should always have an empty dictionary!
self.tool_data_tables = galaxy.tools.data.ToolDataTableManager( self.config.tool_data_path )
https://bitbucket.org/galaxy/galaxy-central/commits/cb061e5ef947/
Changeset: cb061e5ef947
User: dannon
Date: 2015-01-06 23:27:54+00:00
Summary: Minor typo in comment.
Affected #: 1 file
diff -r 6bb0ddd5a4cc1cba6e42fb838fabcfe818fc8ddb -r cb061e5ef9475f61c30c90a0e9e3c9ad614cc728 lib/galaxy/webapps/tool_shed/app.py
--- a/lib/galaxy/webapps/tool_shed/app.py
+++ b/lib/galaxy/webapps/tool_shed/app.py
@@ -44,7 +44,7 @@
self.model = mapping.init( self.config.file_path,
db_url,
self.config.database_engine_options )
- # Initialize the Tool SHed security helper.
+ # Initialize the Tool Shed security helper.
self.security = security.SecurityHelper( id_secret=self.config.id_secret )
# initialize the Tool Shed tag handler.
self.tag_handler = CommunityTagManager( self )
https://bitbucket.org/galaxy/galaxy-central/commits/504fd0cce279/
Changeset: 504fd0cce279
User: dannon
Date: 2015-01-07 18:08:14+00:00
Summary: Add Tagging PJA.
Affected #: 1 file
diff -r cb061e5ef9475f61c30c90a0e9e3c9ad614cc728 -r 504fd0cce279c54003fb9c38ad9107ae9fea6ce6 lib/galaxy/jobs/actions/post.py
--- a/lib/galaxy/jobs/actions/post.py
+++ b/lib/galaxy/jobs/actions/post.py
@@ -1,5 +1,6 @@
"""
-Actions to be run at job completion. Currently only used in workflows.
+Actions to be run at job completion (or output hda creation, as in the case of
+immediate_actions listed below. Currently only used in workflows.
"""
import datetime
@@ -420,6 +421,43 @@
return "Delete parent datasets of this step created in this workflow that aren't flagged as outputs."
+class TagDatasetAction(DefaultJobAction):
+ name = "TagDatasetAction"
+ verbose_name = "Add tag to dataset"
+
+ @classmethod
+ def execute(cls, app, sa_session, action, job, replacement_dict):
+ if action.action_arguments:
+ tags = ','.join([t.strip() for t in action.action_arguments.get('tags', '').split(',')])
+ if tags:
+ for dataset_assoc in job.output_datasets:
+ if action.output_name == '' or dataset_assoc.name == action.output_name:
+ app.tag_handler.apply_item_tags( job.user, dataset_assoc.dataset,
+ unicode(tags.encode('utf-8'), 'utf-8'))
+ sa_session.flush()
+
+ @classmethod
+ def get_config_form(cls, trans):
+ form = """
+ if (pja.action_arguments && pja.action_arguments.tags){
+ p_str += "<label for='pja__"+pja.output_name+"__TagDatasetAction__tags'>Tags:</label>\
+ <input type='text' name='pja__"+pja.output_name+"__TagDatasetAction__tags' value=\\"" + pja.action_arguments.tags.replace(/"/g, """) + "\\"/>";
+ }
+ else{
+ p_str += "<label for='pja__"+pja.output_name+"__TagDatasetAction__tags'>Tags:</label>\
+ <input type='text' name='pja__"+pja.output_name+"__TagDatasetAction__tags' value=''/>";
+ }
+ """
+ return get_form_template(cls.name, cls.verbose_name, form, "This action will set tags for the dataset.")
+
+ @classmethod
+ def get_short_str(cls, pja):
+ if pja.action_arguments and pja.action_arguments.get('tags', ''):
+ return "Add tag(s) '%s' to '%s'." % (pja.action_arguments['tags'], pja.output_name)
+ else:
+ return "Tag addition action used without a tag specified. No tag will be added."
+
+
class ActionBox(object):
actions = { "RenameDatasetAction": RenameDatasetAction,
@@ -428,11 +466,13 @@
"ColumnSetAction": ColumnSetAction,
"EmailAction": EmailAction,
"DeleteIntermediatesAction": DeleteIntermediatesAction,
+ "TagDatasetAction": TagDatasetAction,
}
public_actions = ['RenameDatasetAction', 'ChangeDatatypeAction',
'ColumnSetAction', 'EmailAction',
- 'DeleteIntermediatesAction']
- immediate_actions = ['ChangeDatatypeAction', 'RenameDatasetAction']
+ 'DeleteIntermediatesAction', 'TagDatasetAction']
+ immediate_actions = ['ChangeDatatypeAction', 'RenameDatasetAction',
+ 'TagDatasetAction']
@classmethod
def get_short_str(cls, action):
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: Update tag latest_2014.10.06 for changeset ff6e36d7a238
by commits-noreply@bitbucket.org 06 Jan '15
by commits-noreply@bitbucket.org 06 Jan '15
06 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/c25df9f3d31e/
Changeset: c25df9f3d31e
Branch: stable
User: natefoo
Date: 2015-01-06 14:00:16+00:00
Summary: Update tag latest_2014.10.06 for changeset ff6e36d7a238
Affected #: 1 file
diff -r ff6e36d7a2388214fe7636c43d30838c07246907 -r c25df9f3d31effd9c4abdbbffd40381f23fc6dc8 .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -20,4 +20,4 @@
ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11
548ab24667d6206780237bd807f7d857a484c461 latest_2014.08.11
2092948937ac30ef82f71463a235c66d34987088 release_2014.10.06
-793d9cd5f9dec66ceafb36bc38f53453457056e6 latest_2014.10.06
+ff6e36d7a2388214fe7636c43d30838c07246907 latest_2014.10.06
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: martenson: Merged in jmchilton/galaxy-central-fork-1/stable (pull request #620)
by commits-noreply@bitbucket.org 05 Jan '15
by commits-noreply@bitbucket.org 05 Jan '15
05 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ff6e36d7a238/
Changeset: ff6e36d7a238
Branch: stable
User: martenson
Date: 2015-01-05 21:53:57+00:00
Summary: Merged in jmchilton/galaxy-central-fork-1/stable (pull request #620)
[STABLE] Don't choke on tool versions switches with significant parameter changes.
Affected #: 1 file
diff -r dff4071c13f9b2908556583227766c65fcfb8a29 -r ff6e36d7a2388214fe7636c43d30838c07246907 lib/galaxy/webapps/galaxy/controllers/tool_runner.py
--- a/lib/galaxy/webapps/galaxy/controllers/tool_runner.py
+++ b/lib/galaxy/webapps/galaxy/controllers/tool_runner.py
@@ -80,14 +80,28 @@
message=message,
status=status,
redirect=redirect ) )
- params = galaxy.util.Params( kwd, sanitize = False ) #Sanitize parameters when substituting into command line via input wrappers
- #do param translation here, used by datasource tools
- if tool.input_translator:
- tool.input_translator.translate( params )
+
+ def _validated_params_for( kwd ):
+ params = galaxy.util.Params( kwd, sanitize=False ) # Sanitize parameters when substituting into command line via input wrappers
+ #do param translation here, used by datasource tools
+ if tool.input_translator:
+ tool.input_translator.translate( params )
+ return params
+
+ params = _validated_params_for( kwd )
# We may be visiting Galaxy for the first time ( e.g., sending data from UCSC ),
# so make sure to create a new history if we've never had one before.
history = tool.get_default_history_by_trans( trans, create=True )
- template, vars = tool.handle_input( trans, params.__dict__ )
+ try:
+ template, vars = tool.handle_input( trans, params.__dict__ )
+ except KeyError:
+ # This error indicates (or at least can indicate) there was a
+ # problem with the stored tool_state - it is incompatible with
+ # this variant of the tool - possibly because the tool changed
+ # or because the tool version changed.
+ del kwd[ "tool_state" ]
+ params = _validated_params_for( kwd )
+ template, vars = tool.handle_input( trans, params.__dict__ )
if len( params ) > 0:
trans.log_event( "Tool params: %s" % ( str( params ) ), tool_id=tool_id )
add_frame = AddFrameData()
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/24c62137d466/
Changeset: 24c62137d466
Branch: stable
User: jmchilton
Date: 2014-12-18 14:47:08+00:00
Summary: Don't choke on tool versions switches with significant parameter changes.
Just regenerate the tool state from the supplied parameters instead - seems to still perserve parameters on the tool form that are common between the versions because they are coming in throuh kwd.
Affected #: 1 file
diff -r 7197e949d3ab990ceb76c193ebc940d90aa04cad -r 24c62137d46629f9200b43612485799cf39600d5 lib/galaxy/webapps/galaxy/controllers/tool_runner.py
--- a/lib/galaxy/webapps/galaxy/controllers/tool_runner.py
+++ b/lib/galaxy/webapps/galaxy/controllers/tool_runner.py
@@ -80,14 +80,28 @@
message=message,
status=status,
redirect=redirect ) )
- params = galaxy.util.Params( kwd, sanitize = False ) #Sanitize parameters when substituting into command line via input wrappers
- #do param translation here, used by datasource tools
- if tool.input_translator:
- tool.input_translator.translate( params )
+
+ def _validated_params_for( kwd ):
+ params = galaxy.util.Params( kwd, sanitize=False ) # Sanitize parameters when substituting into command line via input wrappers
+ #do param translation here, used by datasource tools
+ if tool.input_translator:
+ tool.input_translator.translate( params )
+ return params
+
+ params = _validated_params_for( kwd )
# We may be visiting Galaxy for the first time ( e.g., sending data from UCSC ),
# so make sure to create a new history if we've never had one before.
history = tool.get_default_history_by_trans( trans, create=True )
- template, vars = tool.handle_input( trans, params.__dict__ )
+ try:
+ template, vars = tool.handle_input( trans, params.__dict__ )
+ except KeyError:
+ # This error indicates (or at least can indicate) there was a
+ # problem with the stored tool_state - it is incompatible with
+ # this variant of the tool - possibly because the tool changed
+ # or because the tool version changed.
+ del kwd[ "tool_state" ]
+ params = _validated_params_for( kwd )
+ template, vars = tool.handle_input( trans, params.__dict__ )
if len( params ) > 0:
trans.log_event( "Tool params: %s" % ( str( params ) ), tool_id=tool_id )
add_frame = AddFrameData()
https://bitbucket.org/galaxy/galaxy-central/commits/ff6e36d7a238/
Changeset: ff6e36d7a238
Branch: stable
User: martenson
Date: 2015-01-05 21:53:57+00:00
Summary: Merged in jmchilton/galaxy-central-fork-1/stable (pull request #620)
[STABLE] Don't choke on tool versions switches with significant parameter changes.
Affected #: 1 file
diff -r dff4071c13f9b2908556583227766c65fcfb8a29 -r ff6e36d7a2388214fe7636c43d30838c07246907 lib/galaxy/webapps/galaxy/controllers/tool_runner.py
--- a/lib/galaxy/webapps/galaxy/controllers/tool_runner.py
+++ b/lib/galaxy/webapps/galaxy/controllers/tool_runner.py
@@ -80,14 +80,28 @@
message=message,
status=status,
redirect=redirect ) )
- params = galaxy.util.Params( kwd, sanitize = False ) #Sanitize parameters when substituting into command line via input wrappers
- #do param translation here, used by datasource tools
- if tool.input_translator:
- tool.input_translator.translate( params )
+
+ def _validated_params_for( kwd ):
+ params = galaxy.util.Params( kwd, sanitize=False ) # Sanitize parameters when substituting into command line via input wrappers
+ #do param translation here, used by datasource tools
+ if tool.input_translator:
+ tool.input_translator.translate( params )
+ return params
+
+ params = _validated_params_for( kwd )
# We may be visiting Galaxy for the first time ( e.g., sending data from UCSC ),
# so make sure to create a new history if we've never had one before.
history = tool.get_default_history_by_trans( trans, create=True )
- template, vars = tool.handle_input( trans, params.__dict__ )
+ try:
+ template, vars = tool.handle_input( trans, params.__dict__ )
+ except KeyError:
+ # This error indicates (or at least can indicate) there was a
+ # problem with the stored tool_state - it is incompatible with
+ # this variant of the tool - possibly because the tool changed
+ # or because the tool version changed.
+ del kwd[ "tool_state" ]
+ params = _validated_params_for( kwd )
+ template, vars = tool.handle_input( trans, params.__dict__ )
if len( params ) > 0:
trans.log_event( "Tool params: %s" % ( str( params ) ), tool_id=tool_id )
add_frame = AddFrameData()
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: Fix for Pull Request #614.
by commits-noreply@bitbucket.org 05 Jan '15
by commits-noreply@bitbucket.org 05 Jan '15
05 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d50ee9520583/
Changeset: d50ee9520583
User: jmchilton
Date: 2015-01-05 21:09:45+00:00
Summary: Fix for Pull Request #614.
Affected #: 1 file
diff -r 2aa2f508c50864b3d309d384137e53f5750aed2d -r d50ee9520583c225e48c577ab977f18fd6cb7d6a config/datatypes_conf.xml.sample
--- a/config/datatypes_conf.xml.sample
+++ b/config/datatypes_conf.xml.sample
@@ -299,7 +299,7 @@
<sniffer type="galaxy.datatypes.data:Newick"/><sniffer type="galaxy.datatypes.data:Nexus"/><sniffer type="galaxy.datatypes.text:Obo"/>
- <sniffer type="galaxy.datatypes.text.Arff"/>
+ <sniffer type="galaxy.datatypes.text:Arff"/><sniffer type="galaxy.datatypes.text:Ipynb"/><sniffer type="galaxy.datatypes.text:Json"/><sniffer type="galaxy.datatypes.images:Jpg"/>
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 jmchilton/galaxy-central-fork-1 (pull request #621)
by commits-noreply@bitbucket.org 05 Jan '15
by commits-noreply@bitbucket.org 05 Jan '15
05 Jan '15
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2aa2f508c508/
Changeset: 2aa2f508c508
User: jmchilton
Date: 2015-01-05 20:59:02+00:00
Summary: Merged in jmchilton/galaxy-central-fork-1 (pull request #621)
Workflow API: Replace preferred usage terminology in the API (s/usage/invocation)
Affected #: 2 files
diff -r 03955af117563248e950ec97d151c4a4615eaa58 -r 2aa2f508c50864b3d309d384137e53f5750aed2d lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -372,9 +372,9 @@
return item
@expose_api
- def workflow_request( self, trans, workflow_id, payload, **kwd ):
+ def invoke( self, trans, workflow_id, payload, **kwd ):
"""
- POST /api/workflows/{encoded_workflow_id}/usage
+ POST /api/workflows/{encoded_workflow_id}/invocations
Schedule the workflow specified by `workflow_id` to run.
"""
@@ -398,10 +398,11 @@
return self.encode_all_ids( trans, workflow_invocation.to_dict(), recursive=True )
@expose_api
- def workflow_usage(self, trans, workflow_id, **kwd):
+ def index_invocations(self, trans, workflow_id, **kwd):
"""
- GET /api/workflows/{workflow_id}/usage
- Get the list of the workflow usage
+ GET /api/workflows/{workflow_id}/invocations
+
+ Get the list of the workflow invocations
:param workflow_id: the workflow id (required)
:type workflow_id: str
@@ -416,53 +417,53 @@
return out
@expose_api
- def workflow_usage_contents(self, trans, workflow_id, usage_id, **kwd):
+ def show_invocation(self, trans, workflow_id, invocation_id, **kwd):
"""
- GET /api/workflows/{workflow_id}/usage/{usage_id}
- Get detailed description of workflow usage
+ GET /api/workflows/{workflow_id}/invocation/{invocation_id}
+ Get detailed description of workflow invocation
- :param workflow_id: the workflow id (required)
- :type workflow_id: str
+ :param workflow_id: the workflow id (required)
+ :type workflow_id: str
- :param usage_id: the usage id (required)
- :type usage_id: str
+ :param invocation_id: the invocation id (required)
+ :type invocation_id: str
:raises: exceptions.MessageException, exceptions.ObjectNotFound
"""
- decoded_workflow_invocation_id = self.__decode_id( trans, usage_id )
+ decoded_workflow_invocation_id = self.__decode_id( trans, invocation_id )
workflow_invocation = self.workflow_manager.get_invocation( trans, decoded_workflow_invocation_id )
if workflow_invocation:
return self.__encode_invocation( trans, workflow_invocation )
return None
@expose_api
- def cancel_workflow_invocation(self, trans, workflow_id, usage_id, **kwd):
+ def cancel_invocation(self, trans, workflow_id, invocation_id, **kwd):
"""
- DELETE /api/workflows/{workflow_id}/usage/{usage_id}
+ DELETE /api/workflows/{workflow_id}/invocation/{invocation_id}
Cancel the specified workflow invocation.
:param workflow_id: the workflow id (required)
:type workflow_id: str
- :param usage_id: the usage id (required)
- :type usage_id: str
+ :param invocation_id: the usage id (required)
+ :type invocation_id: str
:raises: exceptions.MessageException, exceptions.ObjectNotFound
"""
- decoded_workflow_invocation_id = self.__decode_id( trans, usage_id )
+ decoded_workflow_invocation_id = self.__decode_id( trans, invocation_id )
workflow_invocation = self.workflow_manager.cancel_invocation( trans, decoded_workflow_invocation_id )
return self.__encode_invocation( trans, workflow_invocation )
@expose_api
- def workflow_invocation_step(self, trans, workflow_id, usage_id, step_id, **kwd):
+ def invocation_step(self, trans, workflow_id, invocation_id, step_id, **kwd):
"""
- GET /api/workflows/{workflow_id}/usage/{usage_id}/steps/{step_id}
+ GET /api/workflows/{workflow_id}/invocation/{invocation_id}/steps/{step_id}
- :param workflow_id: the workflow id (required)
- :type workflow_id: str
+ :param workflow_id: the workflow id (required)
+ :type workflow_id: str
- :param usage_id: the usage id (required)
- :type usage_id: str
+ :param invocation_id: the invocation id (required)
+ :type invocation_id: str
:param step_id: encoded id of the WorkflowInvocationStep (required)
:type step_id: str
@@ -480,9 +481,9 @@
return self.__encode_invocation_step( trans, invocation_step )
@expose_api
- def workflow_invocation_step_update(self, trans, workflow_id, usage_id, step_id, payload, **kwd):
+ def update_invocation_step(self, trans, workflow_id, invocation_id, step_id, payload, **kwd):
"""
- PUT /api/workflows/{workflow_id}/usage/{usage_id}/steps/{step_id}
+ PUT /api/workflows/{workflow_id}/invocation/{invocation_id}/steps/{step_id}
Update state of running workflow step invocation - still very nebulous
but this would be for stuff like confirming paused steps can proceed
etc....
@@ -491,8 +492,8 @@
:param workflow_id: the workflow id (required)
:type workflow_id: str
- :param usage_id: the usage id (required)
- :type usage_id: str
+ :param invocation_id: the usage id (required)
+ :type invocation_id: str
:param step_id: encoded id of the WorkflowInvocationStep (required)
:type step_id: str
diff -r 03955af117563248e950ec97d151c4a4615eaa58 -r 2aa2f508c50864b3d309d384137e53f5750aed2d lib/galaxy/webapps/galaxy/buildapp.py
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -227,14 +227,62 @@
webapp.mapper.connect( 'workflow_dict', '/api/workflows/download/{workflow_id}', controller='workflows', action='workflow_dict', conditions=dict( method=['GET'] ) )
# Deprecated in favor of POST /api/workflows with shared_workflow_id in payload.
webapp.mapper.connect( 'import_shared_workflow_deprecated', '/api/workflows/import', controller='workflows', action='import_shared_workflow_deprecated', conditions=dict( method=['POST'] ) )
- webapp.mapper.connect( 'workflow_usage', '/api/workflows/{workflow_id}/usage', controller='workflows', action='workflow_usage', conditions=dict(method=['GET']))
- webapp.mapper.connect( 'workflow_usage_contents', '/api/workflows/{workflow_id}/usage/{usage_id}', controller='workflows', action='workflow_usage_contents', conditions=dict(method=['GET']))
- webapp.mapper.connect( 'cancel_workflow_invocation', '/api/workflows/{workflow_id}/usage/{usage_id}', controller='workflows', action='cancel_workflow_invocation', conditions=dict(method=['DELETE']))
- webapp.mapper.connect( 'workflow_invocation_step', '/api/workflows/{workflow_id}/usage/{usage_id}/steps/{step_id}', controller='workflows', action='workflow_invocation_step', conditions=dict(method=['GET']))
- webapp.mapper.connect( 'workflow_invocation_step_update', '/api/workflows/{workflow_id}/usage/{usage_id}/steps/{step_id}', controller='workflows', action='workflow_invocation_step_update', conditions=dict(method=['PUT']))
+ # API refers to usages and invocations - these mean the same thing but the
+ # usage routes should be considered deprecated.
+ invoke_names = {
+ "invocations": "",
+ "usage": "_deprecated",
+ }
+ for noun, suffix in invoke_names.iteritems():
+ name = "%s%s" % (noun, suffix)
+ webapp.mapper.connect(
+ 'list_workflow_%s' % name,
+ '/api/workflows/{workflow_id}/%s' % noun,
+ controller='workflows',
+ action='index_invocations',
+ conditions=dict(method=['GET'])
+ )
- webapp.mapper.connect( 'workflow_request', '/api/workflows/{workflow_id}/usage', controller='workflows', action='workflow_request', conditions=dict( method=['POST'] ) )
+ webapp.mapper.connect(
+ 'workflow_%s_contents' % name,
+ '/api/workflows/{workflow_id}/%s/{invocation_id}' % noun,
+ controller='workflows',
+ action='show_invocation',
+ conditions=dict(method=['GET'])
+ )
+
+ webapp.mapper.connect(
+ 'cancel_workflow_%s' % name,
+ '/api/workflows/{workflow_id}/%s/{invocation_id}' % noun,
+ controller='workflows',
+ action='cancel_invocation',
+ conditions=dict(method=['DELETE'])
+ )
+
+ webapp.mapper.connect(
+ 'workflow_%s_step' % name,
+ '/api/workflows/{workflow_id}/%s/{invocation_id}/steps/{step_id}' % noun,
+ controller='workflows',
+ action='invocation_step',
+ conditions=dict(method=['GET'])
+ )
+
+ webapp.mapper.connect(
+ 'workflow_%s_step_update' % name,
+ '/api/workflows/{workflow_id}/%s/{invocation_id}/steps/{step_id}' % noun,
+ controller='workflows',
+ action='update_invocation_step',
+ conditions=dict(method=['PUT'])
+ )
+
+ webapp.mapper.connect(
+ 'workflow_%s' % name,
+ '/api/workflows/{workflow_id}/%s' % noun,
+ controller='workflows',
+ action='invoke',
+ conditions=dict( method=['POST'] )
+ )
# ============================
# ===== AUTHENTICATE API =====
# ============================
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