1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/3b4784d5fc0d/ Changeset: 3b4784d5fc0d User: guerler Date: 2014-10-23 13:50:31+00:00 Summary: ToolForm: Add support for dynamic parameters, add tool version check Affected #: 14 files diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c client/galaxy/scripts/mvc/tools/tools-form.js --- a/client/galaxy/scripts/mvc/tools/tools-form.js +++ b/client/galaxy/scripts/mvc/tools/tools-form.js @@ -42,24 +42,11 @@ // creates the job handler this.job_handler = new ToolJobs(this); - // 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 = {}; - - // for now the initial tool model is parsed through the mako - this.model = this.options; - this.inputs = this.options.inputs; - // request history content and build form this.content = new ToolContent({ history_id : self.options.history_id, success : function() { - self._buildForm(); + self._buildForm(self.options); } }); }, @@ -137,7 +124,7 @@ }, // refresh form data - _refreshForm: function() { + rebuild: function() { // link this var self = this; @@ -161,6 +148,10 @@ url : galaxy_config.root + 'api/tools/' + this.options.id + '/build', data : current_state, success : function(response) { + // rebuild form + self._rebuildForm(response); + + // log success console.debug('tools-form::_refreshForm() - Refreshed inputs/states.'); console.debug(response); }, @@ -171,11 +162,55 @@ }); }, + // rebuild the form elements + _rebuildForm: function(new_model) { + var self = this; + this.tree.matchModel(new_model, function(input_id, node) { + var input = self.input_list[input_id]; + if (input && input.options) { + if (JSON.stringify(input.options) != JSON.stringify(node.options)) { + // backup new options + input.options = node.options; + + // get/update field (currently only done for select fields) + var field = self.field_list[input_id]; + if (field.update && input.type == 'select') { + var new_options = []; + for (var i in node.options) { + var opt = node.options[i]; + if (opt.length > 2) { + new_options.push({ + 'label': opt[0], + 'value': opt[1] + }); + } + } + field.update(new_options); + console.debug('Updating options for ' + input_id); + } + } + } + }); + }, + // builds the tool form - _buildForm: function() { + _buildForm: function(options) { // link this var self = this; + // 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 = {}; + + // for now the initial tool model is parsed through the mako + this.model = options; + this.inputs = options.inputs; + // button menu var menu = new Ui.ButtonMenu({ icon : 'fa-gear', @@ -183,7 +218,7 @@ }); // configure button selection - if(this.options.biostar_url) { + if(options.biostar_url) { // add question option menu.addMenu({ icon : 'fa-question-circle', @@ -256,29 +291,30 @@ cls : 'btn btn-primary', floating : 'clear', onclick : function() { - //self._refreshForm(); + //self.rebuild(); self.job_handler.submit(); } }) } }); - // append form + // start form + this.$el.empty(); this.$el.append(this.portlet.$el); // append help - if (this.options.help != '') { - this.$el.append(ToolTemplate.help(this.options.help)); + if (options.help != '') { + this.$el.append(ToolTemplate.help(options.help)); } // append citations - if (this.options.citations) { + if (options.citations) { // append html this.$el.append(ToolTemplate.citations()); // fetch citations var citations = new CitationModel.ToolCitationCollection(); - citations.tool_id = this.options.id; + citations.tool_id = options.id; var citation_list_view = new CitationView.CitationListView({ collection: citations } ); citation_list_view.render(); citations.fetch(); diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c client/galaxy/scripts/mvc/tools/tools-section.js --- a/client/galaxy/scripts/mvc/tools/tools-section.js +++ b/client/galaxy/scripts/mvc/tools/tools-section.js @@ -50,7 +50,7 @@ var input_def = jQuery.extend(true, {}, input); // create unique id - input_def.id = Utils.uuid(); + input_def.id = input.id = Utils.uuid(); // add to sequential list of inputs this.app.input_list[input_def.id] = input_def; @@ -208,7 +208,7 @@ _addRow: function(field_type, input_def) { // get id var id = input_def.id; - + // field wrapper var field = null; @@ -283,6 +283,11 @@ console.debug('tools-form::_addRow() : Auto matched field type (' + field_type + ').'); } + // deactivate dynamic fields + if (input_def.is_dynamic) { + this.app.incompatible = true; + } + // set field value if (input_def.value !== undefined) { field.value(input_def.value); @@ -380,6 +385,11 @@ extensions : input_def.extensions, multiple : input_def.multiple, onchange : function(dict) { + // rebuild the form + if (self.app.is_dynamic) { + self.app.rebuild(); + } + // pick the first content only (todo: maybe collect multiple meta information) var content_def = dict.values[0]; var content_id = content_def.id; @@ -485,7 +495,7 @@ _fieldSelect : function (input_def) { // check compatibility if (input_def.is_dynamic) { - this.app.incompatible = true; + this.app.is_dynamic = true; } // configure options fields diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c client/galaxy/scripts/mvc/tools/tools-template.js --- a/client/galaxy/scripts/mvc/tools/tools-template.js +++ b/client/galaxy/scripts/mvc/tools/tools-template.js @@ -30,7 +30,7 @@ if (njobs == 1) { njobs_text = '1 job has'; } else { - njobs_text = njobs + ' jobs have been'; + njobs_text = njobs + ' jobs have'; } // create template string diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c client/galaxy/scripts/mvc/tools/tools-tree.js --- a/client/galaxy/scripts/mvc/tools/tools-tree.js +++ b/client/galaxy/scripts/mvc/tools/tools-tree.js @@ -146,7 +146,48 @@ return this.job_ids && this.job_ids[job_input_id]; }, - /** Matches identifier from api response to input element + /** Matches identifier from api model to input elements + */ + matchModel: function(model, callback) { + // final result dictionary + var result = {}; + + // link this + var self = this; + + // search throughout response + function search (id, head) { + for (var i in head) { + var node = head[i]; + var index = node.name; + if (id != '') { + index = id + '|' + index; + } + if (node.type == 'repeat') { + for (var j in node.cache) { + search (index + '_' + j, node.cache[j]); + } + } else { + if (node.type == 'conditional') { + search (index, node.inputs); + } else { + var input_id = self.app.tree.job_ids[index]; + if (input_id) { + callback(input_id, node); + } + } + } + } + } + + // match all ids and return messages + search('', model.inputs); + + // return matched results + return result; + }, + + /** Matches identifier from api response to input elements */ matchResponse: function(response) { // final result dictionary diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c lib/galaxy/webapps/galaxy/api/history_contents.py --- a/lib/galaxy/webapps/galaxy/api/history_contents.py +++ b/lib/galaxy/webapps/galaxy/api/history_contents.py @@ -131,6 +131,7 @@ """ api_type = "file" encoded_id = trans.security.encode_id( hda.id ) + # TODO: handle failed_metadata here as well return { 'id' : encoded_id, diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c lib/galaxy/webapps/galaxy/api/tools.py --- a/lib/galaxy/webapps/galaxy/api/tools.py +++ b/lib/galaxy/webapps/galaxy/api/tools.py @@ -510,16 +510,18 @@ trans.response.status = 500 return { 'error': 'Failed to get job information.' } - # check if job was identified + # 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 ) @@ -644,8 +646,52 @@ tool_model.update({ 'help' : tool_help, 'citations' : tool_citations, - 'biostar_url' : trans.app.config.biostar_url + 'biostar_url' : trans.app.config.biostar_url, + 'message' : tool_message }) # return enriched tool model return tool_model + + def _get_tool_components( self, trans, tool_id, tool_version=None, get_loaded_tools_by_lineage=False, set_selected=False ): + return self.get_toolbox().get_tool_components( tool_id, tool_version, get_loaded_tools_by_lineage, set_selected ) + + def _compare_tool_version( self, trans, tool, job ): + """ + Compares a tool version with the tool version from a job (from ToolRunne. + """ + id = job.tool_id + version = job.tool_version + message = '' + try: + select_field, tools, tool = self._get_tool_components( trans, id, tool_version=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.' % id } + if ( tool.id != id and tool.old_id != id ) or tool.version != version: + if tool.id == id: + if 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. ' % 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. ' % 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 ' % ( id, version ) + message += 'currently not available. You can re-run the job with this tool, which is a derivation of the original tool.' + except Exception, error: + trans.response.status = 500 + return { 'error': str (error) } + + # can't rerun upload, external data sources, et cetera. workflow compatible will proxy this for now + if not tool.is_workflow_compatible: + trans.response.status = 500 + return { 'error': 'The \'%s\' tool does currently not support re-running.' % tool.name } + return message diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c static/scripts/mvc/tools/tools-form.js --- a/static/scripts/mvc/tools/tools-form.js +++ b/static/scripts/mvc/tools/tools-form.js @@ -42,24 +42,11 @@ // creates the job handler this.job_handler = new ToolJobs(this); - // 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 = {}; - - // for now the initial tool model is parsed through the mako - this.model = this.options; - this.inputs = this.options.inputs; - // request history content and build form this.content = new ToolContent({ history_id : self.options.history_id, success : function() { - self._buildForm(); + self._buildForm(self.options); } }); }, @@ -137,7 +124,7 @@ }, // refresh form data - _refreshForm: function() { + rebuild: function() { // link this var self = this; @@ -161,6 +148,10 @@ url : galaxy_config.root + 'api/tools/' + this.options.id + '/build', data : current_state, success : function(response) { + // rebuild form + self._rebuildForm(response); + + // log success console.debug('tools-form::_refreshForm() - Refreshed inputs/states.'); console.debug(response); }, @@ -171,11 +162,55 @@ }); }, + // rebuild the form elements + _rebuildForm: function(new_model) { + var self = this; + this.tree.matchModel(new_model, function(input_id, node) { + var input = self.input_list[input_id]; + if (input && input.options) { + if (JSON.stringify(input.options) != JSON.stringify(node.options)) { + // backup new options + input.options = node.options; + + // get/update field (currently only done for select fields) + var field = self.field_list[input_id]; + if (field.update && input.type == 'select') { + var new_options = []; + for (var i in node.options) { + var opt = node.options[i]; + if (opt.length > 2) { + new_options.push({ + 'label': opt[0], + 'value': opt[1] + }); + } + } + field.update(new_options); + console.debug('Updating options for ' + input_id); + } + } + } + }); + }, + // builds the tool form - _buildForm: function() { + _buildForm: function(options) { // link this var self = this; + // 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 = {}; + + // for now the initial tool model is parsed through the mako + this.model = options; + this.inputs = options.inputs; + // button menu var menu = new Ui.ButtonMenu({ icon : 'fa-gear', @@ -183,7 +218,7 @@ }); // configure button selection - if(this.options.biostar_url) { + if(options.biostar_url) { // add question option menu.addMenu({ icon : 'fa-question-circle', @@ -256,29 +291,30 @@ cls : 'btn btn-primary', floating : 'clear', onclick : function() { - //self._refreshForm(); + //self.rebuild(); self.job_handler.submit(); } }) } }); - // append form + // start form + this.$el.empty(); this.$el.append(this.portlet.$el); // append help - if (this.options.help != '') { - this.$el.append(ToolTemplate.help(this.options.help)); + if (options.help != '') { + this.$el.append(ToolTemplate.help(options.help)); } // append citations - if (this.options.citations) { + if (options.citations) { // append html this.$el.append(ToolTemplate.citations()); // fetch citations var citations = new CitationModel.ToolCitationCollection(); - citations.tool_id = this.options.id; + citations.tool_id = options.id; var citation_list_view = new CitationView.CitationListView({ collection: citations } ); citation_list_view.render(); citations.fetch(); diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c static/scripts/mvc/tools/tools-section.js --- a/static/scripts/mvc/tools/tools-section.js +++ b/static/scripts/mvc/tools/tools-section.js @@ -50,7 +50,7 @@ var input_def = jQuery.extend(true, {}, input); // create unique id - input_def.id = Utils.uuid(); + input_def.id = input.id = Utils.uuid(); // add to sequential list of inputs this.app.input_list[input_def.id] = input_def; @@ -208,7 +208,7 @@ _addRow: function(field_type, input_def) { // get id var id = input_def.id; - + // field wrapper var field = null; @@ -380,6 +380,11 @@ extensions : input_def.extensions, multiple : input_def.multiple, onchange : function(dict) { + // rebuild the form + if (self.app.is_dynamic) { + self.app.rebuild(); + } + // pick the first content only (todo: maybe collect multiple meta information) var content_def = dict.values[0]; var content_id = content_def.id; @@ -485,7 +490,7 @@ _fieldSelect : function (input_def) { // check compatibility if (input_def.is_dynamic) { - this.app.incompatible = true; + this.app.is_dynamic = true; } // configure options fields diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c static/scripts/mvc/tools/tools-template.js --- a/static/scripts/mvc/tools/tools-template.js +++ b/static/scripts/mvc/tools/tools-template.js @@ -30,7 +30,7 @@ if (njobs == 1) { njobs_text = '1 job has'; } else { - njobs_text = njobs + ' jobs have been'; + njobs_text = njobs + ' jobs have'; } // create template string diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c static/scripts/mvc/tools/tools-tree.js --- a/static/scripts/mvc/tools/tools-tree.js +++ b/static/scripts/mvc/tools/tools-tree.js @@ -146,7 +146,48 @@ return this.job_ids && this.job_ids[job_input_id]; }, - /** Matches identifier from api response to input element + /** Matches identifier from api model to input elements + */ + matchModel: function(model, callback) { + // final result dictionary + var result = {}; + + // link this + var self = this; + + // search throughout response + function search (id, head) { + for (var i in head) { + var node = head[i]; + var index = node.name; + if (id != '') { + index = id + '|' + index; + } + if (node.type == 'repeat') { + for (var j in node.cache) { + search (index + '_' + j, node.cache[j]); + } + } else { + if (node.type == 'conditional') { + search (index, node.inputs); + } else { + var input_id = self.app.tree.job_ids[index]; + if (input_id) { + callback(input_id, node); + } + } + } + } + } + + // match all ids and return messages + search('', model.inputs); + + // return matched results + return result; + }, + + /** Matches identifier from api response to input elements */ matchResponse: function(response) { // final result dictionary diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c static/scripts/packed/mvc/tools/tools-form.js --- a/static/scripts/packed/mvc/tools/tools-form.js +++ b/static/scripts/packed/mvc/tools/tools-form.js @@ -1,1 +1,1 @@ -define(["utils/utils","mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-content","mvc/tools/tools-section","mvc/tools/tools-tree","mvc/tools/tools-jobs"],function(i,h,l,j,a,e,d,f,k,c,g){var b=Backbone.View.extend({container:"body",initialize:function(n){console.debug(n);var m=this;if(parent.Galaxy&&parent.Galaxy.modal){this.modal=parent.Galaxy.modal}else{this.modal=new l.Modal.View()}this.options=n;this.setElement("<div/>");$(this.container).append(this.$el);this.tree=new c(this);this.job_handler=new g(this);this.field_list={};this.input_list={};this.element_list={};this.model=this.options;this.inputs=this.options.inputs;this.content=new f({history_id:m.options.history_id,success:function(){m._buildForm()}})},message:function(m){$(this.container).empty();$(this.container).append(m)},reset:function(){for(var m in this.element_list){this.element_list[m].reset()}},refresh:function(){this.tree.refresh();for(var m in this.field_list){this.field_list[m].trigger("change")}console.debug("tools-form::refresh() - Recreated data structure. Refresh.")},_buildModel:function(){var m=this;var n=galaxy_config.root+"api/tools/"+this.options.id+"/build?";if(this.options.job_id){n+="job_id="+this.options.job_id}else{if(this.options.dataset_id){n+="dataset_id="+this.options.dataset_id}else{var o=top.location.href;var p=o.indexOf("?");if(o.indexOf("tool_id=")!=-1&&p!==-1){n+=o.slice(p+1)}}}i.request({type:"GET",url:n,success:function(q){m.options=$.extend(m.options,q);m.model=q;m.inputs=q.inputs;console.debug("tools-form::initialize() - Initial tool model ready.");console.debug(q);m._buildForm()},error:function(q){console.debug("tools-form::initialize() - Initial tool model request failed.");console.debug(q)}})},_refreshForm:function(){var m=this;var n=this.tree.finalize({data:function(o){if(o.values.length>0&&o.values[0]&&o.values[0].src==="hda"){return m.content.get({id:o.values[0].id}).dataset_id}return null}});console.debug("tools-form::_refreshForm() - Refreshing inputs/states.");console.debug(n);i.request({type:"GET",url:galaxy_config.root+"api/tools/"+this.options.id+"/build",data:n,success:function(o){console.debug("tools-form::_refreshForm() - Refreshed inputs/states.");console.debug(o)},error:function(o){console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(o)}})},_buildForm:function(){var n=this;var p=new l.ButtonMenu({icon:"fa-gear",tooltip:"Click to see a list of options."});if(this.options.biostar_url){p.addMenu({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(n.options.biostar_url+"/p/new/post/")}});p.addMenu({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(n.options.biostar_url+"/t/"+n.options.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="+n.options.id)}});if(Galaxy.currUser.get("is_admin")){p.addMenu({icon:"fa-download",title:"Download",tooltip:"Download this tool",onclick:function(){window.location.href=galaxy_config.root+"api/tools/"+n.options.id+"/download"}})}this.section=new k.View(n,{inputs:this.inputs,cls:"ui-table-plain"});if(this.incompatible){this.$el.hide();$("#tool-form-classic").show();return}this.portlet=new h.View({icon:"fa-wrench",title:"<b>"+this.model.name+"</b> "+this.model.description,operations:{menu:p},buttons:{execute:new l.Button({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",cls:"btn btn-primary",floating:"clear",onclick:function(){n.job_handler.submit()}})}});this.$el.append(this.portlet.$el);if(this.options.help!=""){this.$el.append(d.help(this.options.help))}if(this.options.citations){this.$el.append(d.citations());var m=new j.ToolCitationCollection();m.tool_id=this.options.id;var o=new a.CitationListView({collection:m});o.render();m.fetch()}this.portlet.append(this.section.$el);this.refresh()}});return{View:b}}); \ No newline at end of file +define(["utils/utils","mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-content","mvc/tools/tools-section","mvc/tools/tools-tree","mvc/tools/tools-jobs"],function(i,h,l,j,a,e,d,f,k,c,g){var b=Backbone.View.extend({container:"body",initialize:function(n){console.debug(n);var m=this;if(parent.Galaxy&&parent.Galaxy.modal){this.modal=parent.Galaxy.modal}else{this.modal=new l.Modal.View()}this.options=n;this.setElement("<div/>");$(this.container).append(this.$el);this.tree=new c(this);this.job_handler=new g(this);this.content=new f({history_id:m.options.history_id,success:function(){m._buildForm(m.options)}})},message:function(m){$(this.container).empty();$(this.container).append(m)},reset:function(){for(var m in this.element_list){this.element_list[m].reset()}},refresh:function(){this.tree.refresh();for(var m in this.field_list){this.field_list[m].trigger("change")}console.debug("tools-form::refresh() - Recreated data structure. Refresh.")},_buildModel:function(){var m=this;var n=galaxy_config.root+"api/tools/"+this.options.id+"/build?";if(this.options.job_id){n+="job_id="+this.options.job_id}else{if(this.options.dataset_id){n+="dataset_id="+this.options.dataset_id}else{var o=top.location.href;var p=o.indexOf("?");if(o.indexOf("tool_id=")!=-1&&p!==-1){n+=o.slice(p+1)}}}i.request({type:"GET",url:n,success:function(q){m.options=$.extend(m.options,q);m.model=q;m.inputs=q.inputs;console.debug("tools-form::initialize() - Initial tool model ready.");console.debug(q);m._buildForm()},error:function(q){console.debug("tools-form::initialize() - Initial tool model request failed.");console.debug(q)}})},rebuild:function(){var m=this;var n=this.tree.finalize({data:function(o){if(o.values.length>0&&o.values[0]&&o.values[0].src==="hda"){return m.content.get({id:o.values[0].id}).dataset_id}return null}});console.debug("tools-form::_refreshForm() - Refreshing inputs/states.");console.debug(n);i.request({type:"GET",url:galaxy_config.root+"api/tools/"+this.options.id+"/build",data:n,success:function(o){m._rebuildForm(o);console.debug("tools-form::_refreshForm() - Refreshed inputs/states.");console.debug(o)},error:function(o){console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(o)}})},_rebuildForm:function(m){var n=this;this.tree.matchModel(m,function(p,t){var o=n.input_list[p];if(o&&o.options){if(JSON.stringify(o.options)!=JSON.stringify(t.options)){o.options=t.options;var u=n.field_list[p];if(u.update&&o.type=="select"){var s=[];for(var r in t.options){var q=t.options[r];if(q.length>2){s.push({label:q[0],value:q[1]})}}u.update(s);console.debug("Updating options for "+p)}}}})},_buildForm:function(o){var n=this;this.field_list={};this.input_list={};this.element_list={};this.model=o;this.inputs=o.inputs;var q=new l.ButtonMenu({icon:"fa-gear",tooltip:"Click to see a list of options."});if(o.biostar_url){q.addMenu({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(n.options.biostar_url+"/p/new/post/")}});q.addMenu({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(n.options.biostar_url+"/t/"+n.options.id+"/")}})}q.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="+n.options.id)}});if(Galaxy.currUser.get("is_admin")){q.addMenu({icon:"fa-download",title:"Download",tooltip:"Download this tool",onclick:function(){window.location.href=galaxy_config.root+"api/tools/"+n.options.id+"/download"}})}this.section=new k.View(n,{inputs:this.inputs,cls:"ui-table-plain"});if(this.incompatible){this.$el.hide();$("#tool-form-classic").show();return}this.portlet=new h.View({icon:"fa-wrench",title:"<b>"+this.model.name+"</b> "+this.model.description,operations:{menu:q},buttons:{execute:new l.Button({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",cls:"btn btn-primary",floating:"clear",onclick:function(){n.job_handler.submit()}})}});this.$el.empty();this.$el.append(this.portlet.$el);if(o.help!=""){this.$el.append(d.help(o.help))}if(o.citations){this.$el.append(d.citations());var m=new j.ToolCitationCollection();m.tool_id=o.id;var p=new a.CitationListView({collection:m});p.render();m.fetch()}this.portlet.append(this.section.$el);this.refresh()}});return{View:b}}); \ No newline at end of file diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c static/scripts/packed/mvc/tools/tools-section.js --- a/static/scripts/packed/mvc/tools/tools-section.js +++ b/static/scripts/packed/mvc/tools/tools-section.js @@ -1,1 +1,1 @@ -define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=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(k,h)}},_addConditional:function(h){h.label=h.test_param.label;h.value=h.test_param.value;var j=this._addRow("conditional",h);for(var l in h.cases){var k=h.id+"-section-"+l;var m=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});m.$el.addClass("ui-table-form-section");this.table.add(m.$el);this.table.append(k)}},_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.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.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({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(j,h){var l=h.id;var i=null;switch(j){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_column":h.is_dynamic=false;i=this._fieldSelect(h);break;case"conditional":i=this._fieldConditional(h);break;case"hidden":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":i=this._fieldSelect(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 ("+j+").")}if(h.value!==undefined){i.value(h.value)}this.app.field_list[l]=i;var k=new e({label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[l]=k;this.table.add(k.$el);this.table.append(l);return this.table.get(l)},_fieldConditional:function(h){var j=this;var k=[];for(var l in h.test_param.options){var m=h.test_param.options[l];k.push({label:m[0],value:m[1]})}return new g.Select.View({id:"field-"+h.id,data:k,onchange:function(u){for(var s in h.cases){var o=h.cases[s];var r=h.id+"-section-"+s;var n=j.table.get(r);var q=false;for(var p in o.inputs){var t=o.inputs[p].type;if(t&&t!=="hidden"){q=true;break}}if(o.value==u&&q){n.fadeIn("fast")}else{n.hide()}}}})},_fieldData:function(h){var i=this;var j=h.id;return new a.View(this.app,{id:"field-"+j,extensions:h.extensions,multiple:h.multiple,onchange:function(q){var o=q.values[0];var m=o.id;var p=o.src;var l=i.app.tree.references(j,"data_column");if(l.length<=0){console.debug("tool-form::field_data() - Data column parameters unavailable.");return}for(var n in l){var k=i.app.field_list[l[n]];k.wait&&k.wait()}i.app.content.getDetails({id:m,src:p,success:function(y){var B=null;if(y){console.debug("tool-form::field_data() - Selected content "+m+".");if(p=="hdca"&&y.elements&&y.elements.length>0){y=y.elements[0].object}B=y.metadata_column_types;if(!B){console.debug("tool-form::field_data() - FAILED: Could not find metadata for content "+m+".")}}else{console.debug("tool-form::field_data() - FAILED: Could not find content "+m+".")}for(var u in l){var w=i.app.input_list[l[u]];var x=i.app.field_list[l[u]];if(!w||!x){console.debug("tool-form::field_data() - FAILED: Column not found.")}var t=w.numerical;var s=[];for(var A in B){var z=B[A];var r=(parseInt(A)+1);var v="Text";if(z=="int"||z=="float"){v="Number"}if(z=="int"||z=="float"||!t){s.push({label:"Column: "+r+" ["+v+"]",value:r})}}if(x){x.update(s);if(!x.exists(x.value())){x.value(x.first())}x.show()}}}})}})},_fieldSelect:function(h){if(h.is_dynamic){this.app.incompatible=true}var j=[];for(var k in h.options){var l=h.options[k];j.push({label:l[0],value:l[1]})}var m=g.Select;switch(h.display){case"checkboxes":m=g.Checkbox;break;case"radio":m=g.Radio;break}return new m.View({id:"field-"+h.id,data:j,multiple:h.multiple})},_fieldText:function(h){return new g.Input({id:"field-"+h.id,area:h.area})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}}); \ No newline at end of file +define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=j.id=d.uuid();this.app.input_list[h.id]=h;var k=h.type;switch(k){case"conditional":this._addConditional(h);break;case"repeat":this._addRepeat(h);break;default:this._addRow(k,h)}},_addConditional:function(h){h.label=h.test_param.label;h.value=h.test_param.value;var j=this._addRow("conditional",h);for(var l in h.cases){var k=h.id+"-section-"+l;var m=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});m.$el.addClass("ui-table-form-section");this.table.add(m.$el);this.table.append(k)}},_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.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.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({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(j,h){var l=h.id;var i=null;switch(j){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_column":h.is_dynamic=false;i=this._fieldSelect(h);break;case"conditional":i=this._fieldConditional(h);break;case"hidden":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":i=this._fieldSelect(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 ("+j+").")}if(h.value!==undefined){i.value(h.value)}this.app.field_list[l]=i;var k=new e({label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[l]=k;this.table.add(k.$el);this.table.append(l);return this.table.get(l)},_fieldConditional:function(h){var j=this;var k=[];for(var l in h.test_param.options){var m=h.test_param.options[l];k.push({label:m[0],value:m[1]})}return new g.Select.View({id:"field-"+h.id,data:k,onchange:function(u){for(var s in h.cases){var o=h.cases[s];var r=h.id+"-section-"+s;var n=j.table.get(r);var q=false;for(var p in o.inputs){var t=o.inputs[p].type;if(t&&t!=="hidden"){q=true;break}}if(o.value==u&&q){n.fadeIn("fast")}else{n.hide()}}}})},_fieldData:function(h){var i=this;var j=h.id;return new a.View(this.app,{id:"field-"+j,extensions:h.extensions,multiple:h.multiple,onchange:function(q){if(i.app.is_dynamic){i.app.rebuild()}var o=q.values[0];var m=o.id;var p=o.src;var l=i.app.tree.references(j,"data_column");if(l.length<=0){console.debug("tool-form::field_data() - Data column parameters unavailable.");return}for(var n in l){var k=i.app.field_list[l[n]];k.wait&&k.wait()}i.app.content.getDetails({id:m,src:p,success:function(y){var B=null;if(y){console.debug("tool-form::field_data() - Selected content "+m+".");if(p=="hdca"&&y.elements&&y.elements.length>0){y=y.elements[0].object}B=y.metadata_column_types;if(!B){console.debug("tool-form::field_data() - FAILED: Could not find metadata for content "+m+".")}}else{console.debug("tool-form::field_data() - FAILED: Could not find content "+m+".")}for(var u in l){var w=i.app.input_list[l[u]];var x=i.app.field_list[l[u]];if(!w||!x){console.debug("tool-form::field_data() - FAILED: Column not found.")}var t=w.numerical;var s=[];for(var A in B){var z=B[A];var r=(parseInt(A)+1);var v="Text";if(z=="int"||z=="float"){v="Number"}if(z=="int"||z=="float"||!t){s.push({label:"Column: "+r+" ["+v+"]",value:r})}}if(x){x.update(s);if(!x.exists(x.value())){x.value(x.first())}x.show()}}}})}})},_fieldSelect:function(h){if(h.is_dynamic){this.app.is_dynamic=true}var j=[];for(var k in h.options){var l=h.options[k];j.push({label:l[0],value:l[1]})}var m=g.Select;switch(h.display){case"checkboxes":m=g.Checkbox;break;case"radio":m=g.Radio;break}return new m.View({id:"field-"+h.id,data:j,multiple:h.multiple})},_fieldText:function(h){return new g.Input({id:"field-"+h.id,area:h.area})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}}); \ No newline at end of file diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c static/scripts/packed/mvc/tools/tools-template.js --- a/static/scripts/packed/mvc/tools/tools-template.js +++ b/static/scripts/packed/mvc/tools/tools-template.js @@ -1,1 +1,1 @@ -define([],function(){return{help:function(a){return'<div class="toolHelp"><div class="toolHelpBody">'+a+"</div></div>"},citations:function(){return'<div id="citations"></div>'},success:function(c){if(!c.jobs||!c.jobs.length){console.debug("tools-template::success() - Failed jobs.");return}var a=c.jobs.length;var d="";if(a==1){d="1 job has"}else{d=a+" jobs have been"}var b='<div class="donemessagelarge"><p>'+d+" been successfully added to the queue - resulting in the following datasets:</p>";for(var e in c.outputs){b+='<p style="padding: 10px 20px;"><b>'+(parseInt(e)+1)+": "+c.outputs[e].name+"</b></p>"}b+="<p>You can check the status of queued jobs and view the resulting data by refreshing the History pane. When the job has been run the status will change from 'running' to 'finished' if completed successfully or 'error' if problems were encountered.</p></div>";return b},error:function(a){return'<div><p>The server could not complete the request. Please contact the Galaxy Team if this error persists.</p><textarea class="ui-textarea" disabled style="color: black;" rows="6">'+JSON.stringify(a,undefined,4)+"</textarea></div>"},batchMode:function(){return'<div class="ui-table-form-info"><i class="fa fa-sitemap" style="font-size: 1.2em; padding: 2px 5px;"/>This is a batch mode input field. A separate job will be triggered for each dataset.';"</div>"}}}); \ No newline at end of file +define([],function(){return{help:function(a){return'<div class="toolHelp"><div class="toolHelpBody">'+a+"</div></div>"},citations:function(){return'<div id="citations"></div>'},success:function(c){if(!c.jobs||!c.jobs.length){console.debug("tools-template::success() - Failed jobs.");return}var a=c.jobs.length;var d="";if(a==1){d="1 job has"}else{d=a+" jobs have"}var b='<div class="donemessagelarge"><p>'+d+" been successfully added to the queue - resulting in the following datasets:</p>";for(var e in c.outputs){b+='<p style="padding: 10px 20px;"><b>'+(parseInt(e)+1)+": "+c.outputs[e].name+"</b></p>"}b+="<p>You can check the status of queued jobs and view the resulting data by refreshing the History pane. When the job has been run the status will change from 'running' to 'finished' if completed successfully or 'error' if problems were encountered.</p></div>";return b},error:function(a){return'<div><p>The server could not complete the request. Please contact the Galaxy Team if this error persists.</p><textarea class="ui-textarea" disabled style="color: black;" rows="6">'+JSON.stringify(a,undefined,4)+"</textarea></div>"},batchMode:function(){return'<div class="ui-table-form-info"><i class="fa fa-sitemap" style="font-size: 1.2em; padding: 2px 5px;"/>This is a batch mode input field. A separate job will be triggered for each dataset.';"</div>"}}}); \ No newline at end of file diff -r 0d9ac8314a78087f68f84c66e861dffb9a1ea203 -r 3b4784d5fc0d3687a51a64d10765edf54e6ed62c static/scripts/packed/mvc/tools/tools-tree.js --- a/static/scripts/packed/mvc/tools/tools-tree.js +++ b/static/scripts/packed/mvc/tools/tools-tree.js @@ -1,1 +1,1 @@ -define([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},refresh:function(){this.dict={};this.xml=$("<div/>");if(!this.app.section){return{}}this._iterate(this.app.section.$el,this.dict,this.xml)},finalize:function(d){d=d||{};var a=this;this.job_def={};this.job_ids={};function c(g,f,e){a.job_def[g]=e;a.job_ids[g]=f}function b(k,n){for(var h in n){var f=n[h];if(f.input){var p=f.input;var j=k;if(k!=""){j+="|"}j+=p.name;switch(p.type){case"repeat":var e="section-";var s=[];var m=null;for(var r in f){var l=r.indexOf(e);if(l!=-1){l+=e.length;s.push(parseInt(r.substr(l)));if(!m){m=r.substr(0,l)}}}s.sort(function(t,i){return t-i});var h=0;for(var g in s){b(j+"_"+h++,f[m+s[g]])}break;case"conditional":var q=a.app.field_list[p.id].value();c(j+"|"+p.test_param.name,p.id,q);for(var g in p.cases){if(p.cases[g].value==q){b(j,n[p.id+"-section-"+g]);break}}break;default:var o=a.app.field_list[p.id];var q=o.value();if(d[p.type]){q=d[p.type](q)}if(!o.skip){c(j,p.id,q)}}}}}b("",this.dict);return this.job_def},match:function(a){return this.job_ids&&this.job_ids[a]},matchResponse:function(c){var a={};var b=this;function d(j,h){if(typeof h==="string"){var f=b.app.tree.job_ids[j];if(f){a[f]=h}}else{for(var g in h){var e=g;if(j!==""){e=j+"|"+e}d(e,h[g])}}}d("",c);return a},references:function(c,e){var g=[];var b=this;function d(h,j){var i=$(j).children();var l=[];var k=false;i.each(function(){var o=this;var n=$(o).attr("id");if(n!==c){var m=b.app.input_list[n];if(m){if(m.name==h){k=true;return false}if(m.data_ref==h&&m.type==e){l.push(n)}}}});if(!k){g=g.concat(l);i.each(function(){d(h,this)})}}var f=this.xml.find("#"+c);if(f.length>0){var a=this.app.input_list[c];if(a){d(a.name,f.parent())}}return g},_iterate:function(d,e,b){var a=this;var c=$(d).children();c.each(function(){var i=this;var h=$(i).attr("id");if($(i).hasClass("section-row")){e[h]={};var f=a.app.input_list[h];if(f){e[h]={input:f}}var g=$('<div id="'+h+'"/>');b.append(g);a._iterate(i,e[h],g)}else{a._iterate(i,e,b)}})}})}); \ No newline at end of file +define([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},refresh:function(){this.dict={};this.xml=$("<div/>");if(!this.app.section){return{}}this._iterate(this.app.section.$el,this.dict,this.xml)},finalize:function(d){d=d||{};var a=this;this.job_def={};this.job_ids={};function c(g,f,e){a.job_def[g]=e;a.job_ids[g]=f}function b(k,n){for(var h in n){var f=n[h];if(f.input){var p=f.input;var j=k;if(k!=""){j+="|"}j+=p.name;switch(p.type){case"repeat":var e="section-";var s=[];var m=null;for(var r in f){var l=r.indexOf(e);if(l!=-1){l+=e.length;s.push(parseInt(r.substr(l)));if(!m){m=r.substr(0,l)}}}s.sort(function(t,i){return t-i});var h=0;for(var g in s){b(j+"_"+h++,f[m+s[g]])}break;case"conditional":var q=a.app.field_list[p.id].value();c(j+"|"+p.test_param.name,p.id,q);for(var g in p.cases){if(p.cases[g].value==q){b(j,n[p.id+"-section-"+g]);break}}break;default:var o=a.app.field_list[p.id];var q=o.value();if(d[p.type]){q=d[p.type](q)}if(!o.skip){c(j,p.id,q)}}}}}b("",this.dict);return this.job_def},match:function(a){return this.job_ids&&this.job_ids[a]},matchModel:function(c,e){var a={};var b=this;function d(n,l){for(var k in l){var m=l[k];var h=m.name;if(n!=""){h=n+"|"+h}if(m.type=="repeat"){for(var g in m.cache){d(h+"_"+g,m.cache[g])}}else{if(m.type=="conditional"){d(h,m.inputs)}else{var f=b.app.tree.job_ids[h];if(f){e(f,m)}}}}}d("",c.inputs);return a},matchResponse:function(c){var a={};var b=this;function d(j,h){if(typeof h==="string"){var f=b.app.tree.job_ids[j];if(f){a[f]=h}}else{for(var g in h){var e=g;if(j!==""){e=j+"|"+e}d(e,h[g])}}}d("",c);return a},references:function(c,e){var g=[];var b=this;function d(h,j){var i=$(j).children();var l=[];var k=false;i.each(function(){var o=this;var n=$(o).attr("id");if(n!==c){var m=b.app.input_list[n];if(m){if(m.name==h){k=true;return false}if(m.data_ref==h&&m.type==e){l.push(n)}}}});if(!k){g=g.concat(l);i.each(function(){d(h,this)})}}var f=this.xml.find("#"+c);if(f.length>0){var a=this.app.input_list[c];if(a){d(a.name,f.parent())}}return g},_iterate:function(d,e,b){var a=this;var c=$(d).children();c.each(function(){var i=this;var h=$(i).attr("id");if($(i).hasClass("section-row")){e[h]={};var f=a.app.input_list[h];if(f){e[h]={input:f}}var g=$('<div id="'+h+'"/>');b.append(g);a._iterate(i,e[h],g)}else{a._iterate(i,e,b)}})}})}); \ No newline at end of file Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.