mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge.
This commit is contained in:
@@ -805,7 +805,7 @@ var Node = Backbone.Model.extend({
|
||||
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 @@ $.extend( Workflow.prototype, {
|
||||
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 @@ function add_node( type, title_text, tool_id ) {
|
||||
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;
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -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
|
||||
};
|
||||
});
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
})
|
||||
}
|
||||
ToolFormBase.prototype.initialize.call(this, options);
|
||||
},
|
||||
|
||||
/** Builds a new model through api call and recreates the entire form
|
||||
@@ -250,256 +199,6 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ return Backbone.Model.extend({
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -382,6 +382,11 @@ define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/tools/tools-rep
|
||||
/** 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 @@ define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/tools/tools-rep
|
||||
/** 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 @@ define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/tools/tools-rep
|
||||
*/
|
||||
_fieldHidden : function(input_def) {
|
||||
return new Ui.Hidden({
|
||||
id : 'field-' + input_def.id
|
||||
id : 'field-' + input_def.id,
|
||||
info : input_def.info
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -36,14 +36,7 @@ var View = Backbone.View.extend({
|
||||
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.';
|
||||
|
||||
@@ -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 @@ return Backbone.Model.extend({
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -412,7 +412,7 @@ var Hidden = Backbone.View.extend({
|
||||
initialize : function(options) {
|
||||
// configure options
|
||||
this.options = options;
|
||||
|
||||
|
||||
// create new element
|
||||
this.setElement(this._template(this.options));
|
||||
|
||||
@@ -425,14 +425,20 @@ var Hidden = Backbone.View.extend({
|
||||
// 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;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -137,16 +137,7 @@ var Base = Backbone.View.extend({
|
||||
/** 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
|
||||
|
||||
@@ -96,16 +96,7 @@ var View = Backbone.View.extend({
|
||||
/** 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
|
||||
|
||||
@@ -104,7 +104,7 @@ return Backbone.View.extend({
|
||||
});
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -14,6 +14,40 @@ function sanitize(content) {
|
||||
return $('<div/>').text(content).html();
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -212,7 +246,9 @@ return {
|
||||
time: time,
|
||||
wrap: wrap,
|
||||
request: request,
|
||||
sanitize: sanitize
|
||||
sanitize: sanitize,
|
||||
textify: textify,
|
||||
validate: validate
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -20,7 +20,7 @@ eggs.require( "bx-python" )
|
||||
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 @@ class SQlite ( Binary ):
|
||||
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"
|
||||
|
||||
@@ -33,7 +33,7 @@ from galaxy.tools.actions.upload import UploadToolAction
|
||||
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 @@ class Tool( object, Dictifiable ):
|
||||
"""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 @@ class Tool( object, Dictifiable ):
|
||||
|
||||
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 )
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import glob
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import string
|
||||
import subprocess
|
||||
|
||||
WHITESPACE_PATTERN = re.compile("[\s]+")
|
||||
@@ -43,6 +44,7 @@ NO_BREW_ERROR_MESSAGE = "Could not find brew on PATH, please place on path or pa
|
||||
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 @@ class RecipeContext(object):
|
||||
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 @@ def main():
|
||||
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 @@ class CommandLineException(Exception):
|
||||
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 @@ def versioned_install(recipe_context, package=None, version=None):
|
||||
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 @@ def versioned_install(recipe_context, package=None, version=None):
|
||||
}
|
||||
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 @@ def attempt_unlink(package):
|
||||
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 @@ def build_env_statements_from_recipe_context(recipe_context, **kwds):
|
||||
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 @@ def build_env_statements(cellar_root, cellar_path, relaxed=None):
|
||||
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 @@ def build_env_statements(cellar_root, cellar_path, relaxed=None):
|
||||
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 @@ def git_execute(args):
|
||||
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 execute(cmds):
|
||||
|
||||
|
||||
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]
|
||||
|
||||
|
||||
|
||||
@@ -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]
|
||||
@@ -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 @@ class GalaxyPackageDependencyResolver(DependencyResolver):
|
||||
## 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 ):
|
||||
"""
|
||||
|
||||
@@ -12,20 +12,19 @@ This is still an experimental module and there will almost certainly be backward
|
||||
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 @@ class HomebrewDependencyResolver(DependencyResolver):
|
||||
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 @@ class HomebrewDependencyResolver(DependencyResolver):
|
||||
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"
|
||||
|
||||
@@ -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
|
||||
@@ -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 @@ class ToolShedPackageDependencyResolver(GalaxyPackageDependencyResolver):
|
||||
|
||||
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 @@ class ToolShedPackageDependencyResolver(GalaxyPackageDependencyResolver):
|
||||
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 @@ class ToolShedPackageDependencyResolver(GalaxyPackageDependencyResolver):
|
||||
return GalaxyPackageDependency(script, path, None)
|
||||
return INDETERMINATE_DEPENDENCY
|
||||
|
||||
|
||||
__all__ = [ToolShedPackageDependencyResolver]
|
||||
|
||||
@@ -24,7 +24,7 @@ def plugins_dict(module, plugin_type_identifier):
|
||||
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
|
||||
|
||||
@@ -6,10 +6,7 @@ from galaxy import exceptions
|
||||
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 @@ class LibrariesController( BaseAPIController ):
|
||||
|
||||
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 @@ class LibrariesController( BaseAPIController ):
|
||||
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 @@ class LibrariesController( BaseAPIController ):
|
||||
*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 @@ class LibrariesController( BaseAPIController ):
|
||||
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 @@ class LibrariesController( BaseAPIController ):
|
||||
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 @@ class LibrariesController( BaseAPIController ):
|
||||
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 @@ class LibrariesController( BaseAPIController ):
|
||||
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 @@ class LibrariesController( BaseAPIController ):
|
||||
# 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 @@ class LibrariesController( BaseAPIController ):
|
||||
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
|
||||
|
||||
|
||||
@@ -29,12 +29,12 @@ class LibraryContentsController( BaseAPIController, UsesLibraryMixin, UsesLibrar
|
||||
.. 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 @@ class LibraryContentsController( BaseAPIController, UsesLibraryMixin, UsesLibrar
|
||||
: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 @@ class LibraryContentsController( BaseAPIController, UsesLibraryMixin, UsesLibrar
|
||||
: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 @@ class LibraryContentsController( BaseAPIController, UsesLibraryMixin, UsesLibrar
|
||||
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 @@ class LibraryContentsController( BaseAPIController, UsesLibraryMixin, UsesLibrar
|
||||
|
||||
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 @@ class LibraryContentsController( BaseAPIController, UsesLibraryMixin, UsesLibrar
|
||||
|
||||
#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 @@ class LibraryContentsController( BaseAPIController, UsesLibraryMixin, UsesLibrar
|
||||
|
||||
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 @@ class LibraryContentsController( BaseAPIController, UsesLibraryMixin, UsesLibrar
|
||||
: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 @@ class LibraryContentsController( BaseAPIController, UsesLibraryMixin, UsesLibrar
|
||||
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' ):
|
||||
|
||||
@@ -11,7 +11,7 @@ from galaxy.web.base.controller import UsesHistoryMixin
|
||||
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 @@ class ToolsController( BaseAPIController, UsesVisualizationMixin, UsesHistoryMix
|
||||
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 @@ class ToolsController( BaseAPIController, UsesVisualizationMixin, UsesHistoryMix
|
||||
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
|
||||
|
||||
@@ -4,6 +4,7 @@ import json
|
||||
import os
|
||||
import sgmllib
|
||||
import urllib2
|
||||
import copy
|
||||
|
||||
from sqlalchemy import and_
|
||||
from tool_shed.util import common_util
|
||||
@@ -609,16 +610,26 @@ class WorkflowController( BaseUIController, SharableMixin, UsesStoredWorkflowMix
|
||||
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 @@ class WorkflowController( BaseUIController, SharableMixin, UsesStoredWorkflowMix
|
||||
'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(),
|
||||
|
||||
@@ -18,7 +18,7 @@ from galaxy.dataset_collections import matching
|
||||
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 @@ class ToolModule( WorkflowModule ):
|
||||
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 @@ class ToolModule( WorkflowModule ):
|
||||
|
||||
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 ):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -225,7 +225,11 @@ def main():
|
||||
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
|
||||
|
||||
@@ -805,7 +805,7 @@ var Node = Backbone.Model.extend({
|
||||
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 @@ $.extend( Workflow.prototype, {
|
||||
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 @@ function add_node( type, title_text, tool_id ) {
|
||||
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;
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -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
|
||||
};
|
||||
});
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
})
|
||||
}
|
||||
ToolFormBase.prototype.initialize.call(this, options);
|
||||
},
|
||||
|
||||
/** Builds a new model through api call and recreates the entire form
|
||||
@@ -250,256 +199,6 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ return Backbone.Model.extend({
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -382,6 +382,11 @@ define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/tools/tools-rep
|
||||
/** 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 @@ define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/tools/tools-rep
|
||||
/** 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 @@ define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/tools/tools-rep
|
||||
*/
|
||||
_fieldHidden : function(input_def) {
|
||||
return new Ui.Hidden({
|
||||
id : 'field-' + input_def.id
|
||||
id : 'field-' + input_def.id,
|
||||
info : input_def.info
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -36,14 +36,7 @@ var View = Backbone.View.extend({
|
||||
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.';
|
||||
|
||||
@@ -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 @@ return Backbone.Model.extend({
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -412,7 +412,7 @@ var Hidden = Backbone.View.extend({
|
||||
initialize : function(options) {
|
||||
// configure options
|
||||
this.options = options;
|
||||
|
||||
|
||||
// create new element
|
||||
this.setElement(this._template(this.options));
|
||||
|
||||
@@ -425,14 +425,20 @@ var Hidden = Backbone.View.extend({
|
||||
// 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;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -137,16 +137,7 @@ var Base = Backbone.View.extend({
|
||||
/** 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
|
||||
|
||||
@@ -96,16 +96,7 @@ var View = Backbone.View.extend({
|
||||
/** 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
|
||||
|
||||
@@ -104,7 +104,7 @@ return Backbone.View.extend({
|
||||
});
|
||||
|
||||
// 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;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +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})}}})});
|
||||
@@ -0,0 +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}});
|
||||
File diff suppressed because one or more lines are too long
@@ -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()}}})});
|
||||
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()}}})});
|
||||
@@ -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}});
|
||||
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}});
|
||||
@@ -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}});
|
||||
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}});
|
||||
@@ -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)}})}})});
|
||||
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)}})}})});
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
define(["utils/utils"],function(b){var a=Backbone.View.extend({initialize:function(g){this.optionsDefault={visible:true,data:[],id:b.uuid(),error_text:"No data available.",wait_text:"Please wait..."};this.options=b.merge(g,this.optionsDefault);this.setElement("<div/>");this.$message=$("<div/>");this.$options=$(this._template(g));this.$el.append(this.$message);this.$el.append(this.$options);if(!this.options.visible){this.$el.hide()}this.update(this.options.data);if(this.options.value!==undefined){this.value(this.options.value)}var f=this;this.on("change",function(){f._change()})},update:function(g){var j=this._getValue();this.$options.empty();if(this._templateOptions){this.$options.append(this._templateOptions(g))}else{for(var h in g){var i=$(this._templateOption(g[h]));i.addClass("ui-option");this.$options.append(i)}}var f=this;this.$el.find("input").on("change",function(){f.value(f._getValue());f._change()});this._refresh();this.value(j)},value:function(g){if(g!==undefined){if(!(g instanceof Array)){g=[g]}this.$el.find("input").prop("checked",false);for(var f in g){this.$el.find('input[value="'+g[f]+'"]').first().prop("checked",true)}}return this._getValue()},exists:function(g){if(g!==undefined){if(!(g instanceof Array)){g=[g]}for(var f in g){if(this.$el.find('input[value="'+g[f]+'"]').length>0){return true}}}return false},first:function(){var f=this.$el.find("input");if(f.length>0){return f.val()}else{return undefined}},validate:function(){var g=this.value();if(!(g instanceof Array)){g=[g]}for(var f in g){if([null,"null",undefined].indexOf(g[f])>-1){return false}}return true},wait:function(){if(this._size()==0){this._messageShow(this.options.wait_text,"info");this.$options.hide()}},unwait:function(){this._messageHide();this._refresh()},_change:function(){if(this.options.onchange){this.options.onchange(this._getValue())}},_refresh:function(){if(this._size()==0){this._messageShow(this.options.error_text,"danger");this.$options.hide()}else{this._messageHide();this.$options.css("display","inline-block")}},_getValue:function(){var g=this.$el.find(":checked");if(g.length==0){return"null"}if(this.options.multiple){var f=[];g.each(function(){f.push($(this).val())});return f}else{return g.val()}},_size:function(){return this.$el.find(".ui-option").length},_messageShow:function(g,f){this.$message.show();this.$message.removeClass();this.$message.addClass("ui-message alert alert-"+f);this.$message.html(g)},_messageHide:function(){this.$message.hide()},_template:function(){return'<div class="ui-options"/>'}});var d={};d.View=a.extend({initialize:function(f){a.prototype.initialize.call(this,f)},_templateOption:function(f){return'<div><input type="radio" name="'+this.options.id+'" value="'+f.value+'"/>'+f.label+"<br></div>"}});var c={};c.View=a.extend({initialize:function(f){f.multiple=true;a.prototype.initialize.call(this,f)},_templateOption:function(f){return'<div><input type="checkbox" name="'+this.options.id+'" value="'+f.value+'"/>'+f.label+"<br></div>"}});var e={};e.View=a.extend({initialize:function(f){a.prototype.initialize.call(this,f)},value:function(f){if(f!==undefined){this.$el.find("input").prop("checked",false);this.$el.find("label").removeClass("active");this.$el.find('[value="'+f+'"]').prop("checked",true).closest("label").addClass("active")}return this._getValue()},_templateOption:function(g){var f='<label class="btn btn-default">';if(g.icon){f+='<i class="fa '+g.icon+'"/>'}f+='<input type="radio" name="'+this.options.id+'" value="'+g.value+'">'+g.label+"</label>";return f},_template:function(){return'<div class="btn-group ui-radiobutton" data-toggle="buttons"/>'}});return{Base:a,Radio:d,RadioButton:e,Checkbox:c}});
|
||||
define(["utils/utils"],function(b){var a=Backbone.View.extend({initialize:function(g){this.optionsDefault={visible:true,data:[],id:b.uuid(),error_text:"No data available.",wait_text:"Please wait..."};this.options=b.merge(g,this.optionsDefault);this.setElement("<div/>");this.$message=$("<div/>");this.$options=$(this._template(g));this.$el.append(this.$message);this.$el.append(this.$options);if(!this.options.visible){this.$el.hide()}this.update(this.options.data);if(this.options.value!==undefined){this.value(this.options.value)}var f=this;this.on("change",function(){f._change()})},update:function(g){var j=this._getValue();this.$options.empty();if(this._templateOptions){this.$options.append(this._templateOptions(g))}else{for(var h in g){var i=$(this._templateOption(g[h]));i.addClass("ui-option");this.$options.append(i)}}var f=this;this.$el.find("input").on("change",function(){f.value(f._getValue());f._change()});this._refresh();this.value(j)},value:function(g){if(g!==undefined){if(!(g instanceof Array)){g=[g]}this.$el.find("input").prop("checked",false);for(var f in g){this.$el.find('input[value="'+g[f]+'"]').first().prop("checked",true)}}return this._getValue()},exists:function(g){if(g!==undefined){if(!(g instanceof Array)){g=[g]}for(var f in g){if(this.$el.find('input[value="'+g[f]+'"]').length>0){return true}}}return false},first:function(){var f=this.$el.find("input");if(f.length>0){return f.val()}else{return undefined}},validate:function(){return b.validate(this.value())},wait:function(){if(this._size()==0){this._messageShow(this.options.wait_text,"info");this.$options.hide()}},unwait:function(){this._messageHide();this._refresh()},_change:function(){if(this.options.onchange){this.options.onchange(this._getValue())}},_refresh:function(){if(this._size()==0){this._messageShow(this.options.error_text,"danger");this.$options.hide()}else{this._messageHide();this.$options.css("display","inline-block")}},_getValue:function(){var g=this.$el.find(":checked");if(g.length==0){return"null"}if(this.options.multiple){var f=[];g.each(function(){f.push($(this).val())});return f}else{return g.val()}},_size:function(){return this.$el.find(".ui-option").length},_messageShow:function(g,f){this.$message.show();this.$message.removeClass();this.$message.addClass("ui-message alert alert-"+f);this.$message.html(g)},_messageHide:function(){this.$message.hide()},_template:function(){return'<div class="ui-options"/>'}});var d={};d.View=a.extend({initialize:function(f){a.prototype.initialize.call(this,f)},_templateOption:function(f){return'<div><input type="radio" name="'+this.options.id+'" value="'+f.value+'"/>'+f.label+"<br></div>"}});var c={};c.View=a.extend({initialize:function(f){f.multiple=true;a.prototype.initialize.call(this,f)},_templateOption:function(f){return'<div><input type="checkbox" name="'+this.options.id+'" value="'+f.value+'"/>'+f.label+"<br></div>"}});var e={};e.View=a.extend({initialize:function(f){a.prototype.initialize.call(this,f)},value:function(f){if(f!==undefined){this.$el.find("input").prop("checked",false);this.$el.find("label").removeClass("active");this.$el.find('[value="'+f+'"]').prop("checked",true).closest("label").addClass("active")}return this._getValue()},_templateOption:function(g){var f='<label class="btn btn-default">';if(g.icon){f+='<i class="fa '+g.icon+'"/>'}f+='<input type="radio" name="'+this.options.id+'" value="'+g.value+'">'+g.label+"</label>";return f},_template:function(){return'<div class="btn-group ui-radiobutton" data-toggle="buttons"/>'}});return{Base:a,Radio:d,RadioButton:e,Checkbox:c}});
|
||||
@@ -1 +1 @@
|
||||
define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{id:"",cls:"",error_text:"No data available",visible:true,wait:false,multiple:false,searchable:false},initialize:function(d){this.options=a.merge(d,this.optionsDefault);this.setElement(this._template(this.options));this.$select=this.$el.find(".select");this.$icon=this.$el.find(".icon");this.$button=this.$el.find(".button");if(this.options.multiple){this.$select.prop("multiple",true);this.$select.addClass("ui-select-multiple");this.$icon.remove()}else{this.$el.addClass("ui-select")}this.update(this.options.data);if(this.options.value!==undefined){this.value(this.options.value)}if(!this.options.visible){this.hide()}if(this.options.wait){this.wait()}else{this.show()}var c=this;this.$select.on("change",function(){c._change()});this.on("change",function(){c._change()})},value:function(c){if(c!==undefined){this.$select.val(c);if(this.$select.select2){this.$select.select2("val",c)}}return this.$select.val()},first:function(){var c=this.$select.find("option");if(c.length>0){return c.val()}else{return undefined}},validate:function(){var d=this.value();if(!(d instanceof Array)){d=[d]}for(var c in d){if([null,"null",undefined].indexOf(d[c])>-1){return false}}return true},text:function(){return this.$select.find("option:selected").text()},show:function(){this.unwait();this.$select.show();this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass();this.$icon.addClass("fa fa-spinner fa-spin")},unwait:function(){this.$icon.removeClass();this.$icon.addClass("fa fa-caret-down")},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",false)},disable:function(){this.$select.prop("disabled",true)},add:function(c){this.$select.append(this._templateOption(c));this._refresh()},del:function(c){this.$select.find("option[value="+c+"]").remove();this.$select.trigger("change");this._refresh()},update:function(c){var e=this.$select.val();this.$select.find("option").remove();for(var d in c){this.$select.append(this._templateOption(c[d]))}this._refresh();this.$select.val(e);if(!this.$select.val()){this.$select.val(this.first())}if(this.options.searchable){this.$button.hide();this.$select.select2("destroy");this.$select.select2()}},setOnChange:function(c){this.options.onchange=c},exists:function(c){return this.$select.find('option[value="'+c+'"]').length>0},_change:function(){if(this.options.onchange){this.options.onchange(this.$select.val())}},_refresh:function(){this.$select.find("option[value=null]").remove();var c=this.$select.find("option").length;if(c==0){this.disable();this.$select.append(this._templateOption({value:"null",label:this.options.error_text}))}else{this.enable()}},_templateOption:function(c){return'<option value="'+c.value+'">'+c.label+"</option>"},_template:function(c){return'<div id="'+c.id+'"><select id="select" class="select '+c.cls+" "+c.id+'"></select><div class="button"><i class="icon"/></div></div>'}});return{View:b}});
|
||||
define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{id:"",cls:"",error_text:"No data available",visible:true,wait:false,multiple:false,searchable:false},initialize:function(d){this.options=a.merge(d,this.optionsDefault);this.setElement(this._template(this.options));this.$select=this.$el.find(".select");this.$icon=this.$el.find(".icon");this.$button=this.$el.find(".button");if(this.options.multiple){this.$select.prop("multiple",true);this.$select.addClass("ui-select-multiple");this.$icon.remove()}else{this.$el.addClass("ui-select")}this.update(this.options.data);if(this.options.value!==undefined){this.value(this.options.value)}if(!this.options.visible){this.hide()}if(this.options.wait){this.wait()}else{this.show()}var c=this;this.$select.on("change",function(){c._change()});this.on("change",function(){c._change()})},value:function(c){if(c!==undefined){this.$select.val(c);if(this.$select.select2){this.$select.select2("val",c)}}return this.$select.val()},first:function(){var c=this.$select.find("option");if(c.length>0){return c.val()}else{return undefined}},validate:function(){return a.validate(this.value())},text:function(){return this.$select.find("option:selected").text()},show:function(){this.unwait();this.$select.show();this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass();this.$icon.addClass("fa fa-spinner fa-spin")},unwait:function(){this.$icon.removeClass();this.$icon.addClass("fa fa-caret-down")},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",false)},disable:function(){this.$select.prop("disabled",true)},add:function(c){this.$select.append(this._templateOption(c));this._refresh()},del:function(c){this.$select.find("option[value="+c+"]").remove();this.$select.trigger("change");this._refresh()},update:function(c){var e=this.$select.val();this.$select.find("option").remove();for(var d in c){this.$select.append(this._templateOption(c[d]))}this._refresh();this.$select.val(e);if(!this.$select.val()){this.$select.val(this.first())}if(this.options.searchable){this.$button.hide();this.$select.select2("destroy");this.$select.select2()}},setOnChange:function(c){this.options.onchange=c},exists:function(c){return this.$select.find('option[value="'+c+'"]').length>0},_change:function(){if(this.options.onchange){this.options.onchange(this.$select.val())}},_refresh:function(){this.$select.find("option[value=null]").remove();var c=this.$select.find("option").length;if(c==0){this.disable();this.$select.append(this._templateOption({value:"null",label:this.options.error_text}))}else{this.enable()}},_templateOption:function(c){return'<option value="'+c.value+'">'+c.label+"</option>"},_template:function(c){return'<div id="'+c.id+'"><select id="select" class="select '+c.cls+" "+c.id+'"></select><div class="button"><i class="icon"/></div></div>'}});return{View:b}});
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
define(["libs/underscore"],function(k){function d(l){return $("<div/>").text(l).html()}function e(l){top.__utils__get__=top.__utils__get__||{};if(l.cache&&top.__utils__get__[l.url]){l.success&&l.success(top.__utils__get__[l.url]);console.debug("utils.js::get() - Fetching from cache ["+l.url+"].")}else{h({url:l.url,data:l.data,success:function(m){top.__utils__get__[l.url]=m;l.success&&l.success(m)},error:function(m){l.error&&l.error(m)}})}}function h(m){var l={contentType:"application/json",type:m.type||"GET",data:m.data||{},url:m.url};if(l.type=="GET"||l.type=="DELETE"){if(l.url.indexOf("?")==-1){l.url+="?"}else{l.url+="&"}l.url=l.url+$.param(l.data);l.data=null}else{l.dataType="json";l.url=l.url;l.data=JSON.stringify(l.data)}$.ajax(l).done(function(n){if(typeof n==="string"){try{n=n.replace("Infinity,",'"Infinity",');n=jQuery.parseJSON(n)}catch(o){console.debug(o)}}m.success&&m.success(n)}).fail(function(o){var n=null;try{n=jQuery.parseJSON(o.responseText)}catch(p){n=o.responseText}m.error&&m.error(n,o)})}function i(o,l){var m=$('<div class="'+o+'"></div>');m.appendTo(":eq(0)");var n=m.css(l);m.remove();return n}function g(l){if(!$('link[href^="'+l+'"]').length){$('<link href="'+galaxy_config.root+l+'" rel="stylesheet">').appendTo("head")}}function j(l,m){if(l){return k.defaults(l,m)}else{return m}}function b(m,o){var n="";if(m>=100000000000){m=m/100000000000;n="TB"}else{if(m>=100000000){m=m/100000000;n="GB"}else{if(m>=100000){m=m/100000;n="MB"}else{if(m>=100){m=m/100;n="KB"}else{if(m>0){m=m*10;n="b"}else{return"<strong>-</strong>"}}}}}var l=(Math.round(m)/10);if(o){return l+" "+n}else{return"<strong>"+l+"</strong> "+n}}function a(){return"x"+Math.random().toString(36).substring(2,9)}function c(l){var m=$("<p></p>");m.append(l);return m}function f(){var n=new Date();var l=(n.getHours()<10?"0":"")+n.getHours();var m=(n.getMinutes()<10?"0":"")+n.getMinutes();var o=n.getDate()+"/"+(n.getMonth()+1)+"/"+n.getFullYear()+", "+l+":"+m;return o}return{cssLoadFile:g,cssGetAttribute:i,get:e,merge:j,bytesToString:b,uuid:a,time:f,wrap:c,request:h,sanitize:d}});
|
||||
define(["libs/underscore"],function(m){function d(n){return $("<div/>").text(n).html()}function l(o){if(!(o instanceof Array)){o=[o]}for(var n in o){if(["None",null,"null",undefined,"undefined"].indexOf(o[n])>-1){return false}}return true}function h(n){var n=n.toString();if(n){n=n.replace(/,/g,", ");var o=n.lastIndexOf(", ");if(o!=-1){n=n.substr(0,o)+" or "+n.substr(o+1)}return n}return""}function e(n){top.__utils__get__=top.__utils__get__||{};if(n.cache&&top.__utils__get__[n.url]){n.success&&n.success(top.__utils__get__[n.url]);console.debug("utils.js::get() - Fetching from cache ["+n.url+"].")}else{i({url:n.url,data:n.data,success:function(o){top.__utils__get__[n.url]=o;n.success&&n.success(o)},error:function(o){n.error&&n.error(o)}})}}function i(o){var n={contentType:"application/json",type:o.type||"GET",data:o.data||{},url:o.url};if(n.type=="GET"||n.type=="DELETE"){if(n.url.indexOf("?")==-1){n.url+="?"}else{n.url+="&"}n.url=n.url+$.param(n.data);n.data=null}else{n.dataType="json";n.url=n.url;n.data=JSON.stringify(n.data)}$.ajax(n).done(function(p){if(typeof p==="string"){try{p=p.replace("Infinity,",'"Infinity",');p=jQuery.parseJSON(p)}catch(q){console.debug(q)}}o.success&&o.success(p)}).fail(function(q){var p=null;try{p=jQuery.parseJSON(q.responseText)}catch(r){p=q.responseText}o.error&&o.error(p,q)})}function j(q,n){var o=$('<div class="'+q+'"></div>');o.appendTo(":eq(0)");var p=o.css(n);o.remove();return p}function g(n){if(!$('link[href^="'+n+'"]').length){$('<link href="'+galaxy_config.root+n+'" rel="stylesheet">').appendTo("head")}}function k(n,o){if(n){return m.defaults(n,o)}else{return o}}function b(o,q){var p="";if(o>=100000000000){o=o/100000000000;p="TB"}else{if(o>=100000000){o=o/100000000;p="GB"}else{if(o>=100000){o=o/100000;p="MB"}else{if(o>=100){o=o/100;p="KB"}else{if(o>0){o=o*10;p="b"}else{return"<strong>-</strong>"}}}}}var n=(Math.round(o)/10);if(q){return n+" "+p}else{return"<strong>"+n+"</strong> "+p}}function a(){return"x"+Math.random().toString(36).substring(2,9)}function c(n){var o=$("<p></p>");o.append(n);return o}function f(){var p=new Date();var n=(p.getHours()<10?"0":"")+p.getHours();var o=(p.getMinutes()<10?"0":"")+p.getMinutes();var q=p.getDate()+"/"+(p.getMonth()+1)+"/"+p.getFullYear()+", "+n+":"+o;return q}return{cssLoadFile:g,cssGetAttribute:j,get:e,merge:k,bytesToString:b,uuid:a,time:f,wrap:c,request:i,sanitize:d,textify:h,validate:l}});
|
||||
@@ -14,6 +14,40 @@ function sanitize(content) {
|
||||
return $('<div/>').text(content).html();
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -212,7 +246,9 @@ return {
|
||||
time: time,
|
||||
wrap: wrap,
|
||||
request: request,
|
||||
sanitize: sanitize
|
||||
sanitize: sanitize,
|
||||
textify: textify,
|
||||
validate: validate
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
@@ -1742,7 +1742,7 @@ div.unified-panel-body{position:absolute;top:30px;bottom:0;width:100%}
|
||||
#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}
|
||||
|
||||
@@ -425,7 +425,7 @@ div.unified-panel-body {
|
||||
.iconbar
|
||||
{
|
||||
position : absolute;
|
||||
top : 6px;
|
||||
top : 7px;
|
||||
right : 110px;
|
||||
cursor : pointer;
|
||||
color : @gray-light;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -8,12 +8,10 @@ ${h.css('base', 'jquery-ui/smoothness/jquery-ui')}
|
||||
<%
|
||||
## TEMPORARY: create tool dictionary in mako while both tool forms are in use.
|
||||
## This avoids making two separate requests since the classic form requires the mako anyway.
|
||||
from galaxy.webapps.galaxy.api.tools import ToolsController
|
||||
controller = ToolsController(trans.app)
|
||||
params = dict(trans.request.params)
|
||||
if 'id' in params:
|
||||
params['dataset_id'] = params['id']
|
||||
self.form_config = controller._build_dict(trans, tool, params)
|
||||
self.form_config = tool.to_json(trans, **params)
|
||||
self.form_config.update({
|
||||
'id' : tool.id,
|
||||
'job_id' : trans.security.encode_id( job.id ) if job else None,
|
||||
|
||||
@@ -1,127 +1,161 @@
|
||||
<%
|
||||
from galaxy.tools.parameters import DataToolParameter, RuntimeValue
|
||||
from galaxy.tools.parameters import DataCollectionToolParameter
|
||||
from galaxy.util.expressions import ExpressionContext
|
||||
%>
|
||||
## TEMPORARY SWITCH FOR THE NEW TOOL FORM
|
||||
%if False:
|
||||
${h.js("libs/bibtex", "libs/jquery/jquery-ui")}
|
||||
${h.css('jquery-ui/smoothness/jquery-ui')}
|
||||
<%
|
||||
## TEMPORARY: create tool dictionary in mako while both tool forms are in use.
|
||||
## This avoids making two separate requests since the classic form requires the mako anyway.
|
||||
from galaxy.tools.parameters import params_to_incoming
|
||||
incoming = {}
|
||||
params_to_incoming( incoming, tool.inputs, module.state.inputs, trans.app )
|
||||
self.form_config = tool.to_json(trans, **incoming)
|
||||
self.form_config.update({
|
||||
'id' : tool.id,
|
||||
'job_id' : trans.security.encode_id( job.id ) if job else None,
|
||||
'history_id' : trans.security.encode_id( trans.history.id ),
|
||||
'workflow' : True,
|
||||
'container' : '#right-content'
|
||||
})
|
||||
%>
|
||||
<script>
|
||||
parent.__NEWTOOLFORM__ = true;
|
||||
require(['mvc/tools/tools-form-workflow'], function(ToolsForm){
|
||||
$(function(){
|
||||
var form = new ToolsForm.View(${ h.dumps(self.form_config) });
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<form method="post" action="${h.url_for(controller='workflow', action='editor_form_post' )}">
|
||||
<div class="toolForm">
|
||||
<input type="hidden" name="tool_id" value="${tool.id}" />
|
||||
</div>
|
||||
</form>
|
||||
%else:
|
||||
<%
|
||||
from galaxy.tools.parameters import DataToolParameter, RuntimeValue
|
||||
from galaxy.tools.parameters import DataCollectionToolParameter
|
||||
from galaxy.util.expressions import ExpressionContext
|
||||
%>
|
||||
|
||||
<%def name="do_inputs( inputs, values, errors, prefix, ctx=None )">
|
||||
<% ctx = ExpressionContext( values, ctx ) %>
|
||||
%for input_index, input in enumerate( inputs.itervalues() ):
|
||||
%if input.type == "repeat":
|
||||
<div class="repeat-group form-row">
|
||||
<label>${input.title_plural}:</label>
|
||||
<% repeat_values = values[input.name] %>
|
||||
%for i in range( len( repeat_values ) ):
|
||||
<%
|
||||
if input.name in errors:
|
||||
rep_errors = errors[input.name][i]
|
||||
else:
|
||||
rep_errors = dict()
|
||||
index = repeat_values[i]['__index__']
|
||||
%>
|
||||
<div class="repeat-group-item">
|
||||
<div class="form-title-row"><label>${input.title} ${i + 1}</label></div>
|
||||
${do_inputs( input.inputs, repeat_values[ i ], rep_errors, prefix + input.name + "_" + str(index) + "|", ctx )}
|
||||
<div class="form-row"><input type="submit" name="${prefix}${input.name}_${index}_remove" value="Remove ${input.title} ${i+1}"></div>
|
||||
</div>
|
||||
%endfor
|
||||
<div class="form-row"><input type="submit" name="${prefix}${input.name}_add" value="Add new ${input.title}"></div>
|
||||
</div>
|
||||
%elif input.type == "conditional":
|
||||
%if input.is_job_resource_conditional:
|
||||
<% continue %>
|
||||
%endif
|
||||
<% group_values = values[input.name] %>
|
||||
<% current_case = group_values['__current_case__'] %>
|
||||
<% group_prefix = prefix + input.name + "|" %>
|
||||
<% group_errors = errors.get( input.name, {} ) %>
|
||||
${row_for_param( input.test_param, group_values[ input.test_param.name ], group_errors, group_prefix, ctx, allow_runtime=False )}
|
||||
${do_inputs( input.cases[ current_case ].inputs, group_values, group_errors, group_prefix, ctx )}
|
||||
%else:
|
||||
%if input.name in values:
|
||||
${row_for_param( input, values[ input.name ], errors, prefix, ctx )}
|
||||
%else:
|
||||
<% errors[ input.name ] = 'Value not stored, displaying default' %>
|
||||
${row_for_param( input, input.get_initial_value( trans, values ), errors, prefix, ctx )}
|
||||
%endif
|
||||
%endif
|
||||
%endfor
|
||||
</%def>
|
||||
|
||||
<%def name="row_for_param( param, value, error_dict, prefix, ctx, allow_runtime=True )">
|
||||
%if error_dict.has_key( param.name ):
|
||||
<% cls = "form-row form-row-error" %>
|
||||
%else:
|
||||
<% cls = "form-row" %>
|
||||
%endif
|
||||
<div class="${cls}" id="row-${prefix}${param.name}">
|
||||
## Data parameters are very special since their value / runtime state
|
||||
## comes from connectors
|
||||
%if type( param ) is DataToolParameter:
|
||||
<label>
|
||||
${param.get_label()}
|
||||
</label>
|
||||
<div>
|
||||
Data input '${param.name}' (${" or ".join( param.extensions )})
|
||||
</div>
|
||||
%elif type( param ) is DataCollectionToolParameter:
|
||||
<label>
|
||||
${param.get_label()}
|
||||
</label>
|
||||
<div>
|
||||
Data collection input '${param.name}'
|
||||
</div>
|
||||
<%def name="do_inputs( inputs, values, errors, prefix, ctx=None )">
|
||||
<% ctx = ExpressionContext( values, ctx ) %>
|
||||
%for input_index, input in enumerate( inputs.itervalues() ):
|
||||
%if input.type == "repeat":
|
||||
<div class="repeat-group form-row">
|
||||
<label>${input.title_plural}:</label>
|
||||
<% repeat_values = values[input.name] %>
|
||||
%for i in range( len( repeat_values ) ):
|
||||
<%
|
||||
if input.name in errors:
|
||||
rep_errors = errors[input.name][i]
|
||||
else:
|
||||
rep_errors = dict()
|
||||
index = repeat_values[i]['__index__']
|
||||
%>
|
||||
<div class="repeat-group-item">
|
||||
<div class="form-title-row"><label>${input.title} ${i + 1}</label></div>
|
||||
${do_inputs( input.inputs, repeat_values[ i ], rep_errors, prefix + input.name + "_" + str(index) + "|", ctx )}
|
||||
<div class="form-row"><input type="submit" name="${prefix}${input.name}_${index}_remove" value="Remove ${input.title} ${i+1}"></div>
|
||||
</div>
|
||||
%endfor
|
||||
<div class="form-row"><input type="submit" name="${prefix}${input.name}_add" value="Add new ${input.title}"></div>
|
||||
</div>
|
||||
%elif input.type == "conditional":
|
||||
%if input.is_job_resource_conditional:
|
||||
<% continue %>
|
||||
%endif
|
||||
<% group_values = values[input.name] %>
|
||||
<% current_case = group_values['__current_case__'] %>
|
||||
<% group_prefix = prefix + input.name + "|" %>
|
||||
<% group_errors = errors.get( input.name, {} ) %>
|
||||
${row_for_param( input.test_param, group_values[ input.test_param.name ], group_errors, group_prefix, ctx, allow_runtime=False )}
|
||||
${do_inputs( input.cases[ current_case ].inputs, group_values, group_errors, group_prefix, ctx )}
|
||||
%else:
|
||||
%if isinstance( value, RuntimeValue ):
|
||||
%if input.name in values:
|
||||
${row_for_param( input, values[ input.name ], errors, prefix, ctx )}
|
||||
%else:
|
||||
<% errors[ input.name ] = 'Value not stored, displaying default' %>
|
||||
${row_for_param( input, input.get_initial_value( trans, values ), errors, prefix, ctx )}
|
||||
%endif
|
||||
%endif
|
||||
%endfor
|
||||
</%def>
|
||||
|
||||
<%def name="row_for_param( param, value, error_dict, prefix, ctx, allow_runtime=True )">
|
||||
%if error_dict.has_key( param.name ):
|
||||
<% cls = "form-row form-row-error" %>
|
||||
%else:
|
||||
<% cls = "form-row" %>
|
||||
%endif
|
||||
<div class="${cls}" id="row-${prefix}${param.name}">
|
||||
## Data parameters are very special since their value / runtime state
|
||||
## comes from connectors
|
||||
%if type( param ) is DataToolParameter:
|
||||
<label>
|
||||
${param.get_label()}:
|
||||
<span class="popupmenu">
|
||||
<button type="submit" name="make_buildtime" value="${prefix}${param.name}">Set in advance</button>
|
||||
</span>
|
||||
${param.get_label()}
|
||||
</label>
|
||||
<div>
|
||||
<i>To be set at runtime</i>
|
||||
Data input '${param.name}' (${" or ".join( param.extensions )})
|
||||
</div>
|
||||
%elif type( param ) is DataCollectionToolParameter:
|
||||
<label>
|
||||
${param.get_label()}
|
||||
</label>
|
||||
<div>
|
||||
Data collection input '${param.name}'
|
||||
</div>
|
||||
%else:
|
||||
<label>
|
||||
${param.get_label()}:
|
||||
%if allow_runtime:
|
||||
%if isinstance( value, RuntimeValue ):
|
||||
<label>
|
||||
${param.get_label()}:
|
||||
<span class="popupmenu">
|
||||
<button type="submit" name="make_runtime" value="${prefix}${param.name}">Set at runtime</button>
|
||||
<button type="submit" name="make_buildtime" value="${prefix}${param.name}">Set in advance</button>
|
||||
</span>
|
||||
%endif
|
||||
</label>
|
||||
<div>
|
||||
${param.get_html_field( trans, value, ctx ).get_html( prefix )}
|
||||
</div>
|
||||
%endif
|
||||
%if error_dict.has_key( param.name ):
|
||||
<div style="color: red; font-weight: bold; padding-top: 1px; padding-bottom: 3px;">
|
||||
<div style="width: 300px;"><img style="vertical-align: middle;" src="${h.url_for('/static/style/error_small.png')}"> <span style="vertical-align: middle;">${error_dict[param.name]}</span></div>
|
||||
</div>
|
||||
%endif
|
||||
%endif
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
</%def>
|
||||
|
||||
<form method="post" action="${h.url_for(controller='workflow', action='editor_form_post' )}">
|
||||
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Tool: ${tool.name}</div>
|
||||
%if tool.version:
|
||||
<div class="form-row"><div class='titleRow'>Version: ${tool.version}</div></div>
|
||||
%endif
|
||||
<div class="toolFormBody">
|
||||
<input type="hidden" name="tool_id" value="${tool.id}" />
|
||||
%for i, inputs in enumerate( tool.inputs_by_page ):
|
||||
%if tool.has_multiple_pages:
|
||||
<div class='titleRow'>Page ${i+1}</div>
|
||||
</label>
|
||||
<div>
|
||||
<i>To be set at runtime</i>
|
||||
</div>
|
||||
%else:
|
||||
<label>
|
||||
${param.get_label()}:
|
||||
%if allow_runtime:
|
||||
<span class="popupmenu">
|
||||
<button type="submit" name="make_runtime" value="${prefix}${param.name}">Set at runtime</button>
|
||||
</span>
|
||||
%endif
|
||||
</label>
|
||||
<div>
|
||||
${param.get_html_field( trans, value, ctx ).get_html( prefix )}
|
||||
</div>
|
||||
%endif
|
||||
${do_inputs( inputs, values, errors, "" )}
|
||||
%endfor
|
||||
%if error_dict.has_key( param.name ):
|
||||
<div style="color: red; font-weight: bold; padding-top: 1px; padding-bottom: 3px;">
|
||||
<div style="width: 300px;"><img style="vertical-align: middle;" src="${h.url_for('/static/style/error_small.png')}"> <span style="vertical-align: middle;">${error_dict[param.name]}</span></div>
|
||||
</div>
|
||||
%endif
|
||||
%endif
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</%def>
|
||||
|
||||
</form>
|
||||
<form method="post" action="${h.url_for(controller='workflow', action='editor_form_post' )}">
|
||||
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Tool: ${tool.name}</div>
|
||||
%if tool.version:
|
||||
<div class="form-row"><div class='titleRow'>Version: ${tool.version}</div></div>
|
||||
%endif
|
||||
<div class="toolFormBody">
|
||||
<input type="hidden" name="tool_id" value="${tool.id}" />
|
||||
%for i, inputs in enumerate( tool.inputs_by_page ):
|
||||
%if tool.has_multiple_pages:
|
||||
<div class='titleRow'>Page ${i+1}</div>
|
||||
%endif
|
||||
${do_inputs( inputs, values, errors, "" )}
|
||||
%endfor
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
%endif
|
||||
@@ -113,6 +113,8 @@ def add_file( dataset, registry, json_file, output_path ):
|
||||
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]
|
||||
|
||||
Reference in New Issue
Block a user