Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Augment form module separation #4438

Merged
merged 18 commits into from Aug 18, 2017
Merged
Changes from 17 commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -10,7 +10,8 @@ function( Utils, Portlet, Ui, FormSection, FormData ) {
cls : 'ui-portlet-limited',
icon : null,
always_refresh : true,
status : 'warning'
status : 'warning',
onchange : function(){}
}).set( options );
this.setElement( '<div/>' );
this.render();
@@ -111,7 +112,7 @@ function( Utils, Portlet, Ui, FormSection, FormData ) {
var new_check = self.data.checksum();
if ( new_check != current_check ) {
current_check = new_check;
self.model.get( 'onchange' ) && self.model.get( 'onchange' )();
self.model.get( 'onchange' )();

This comment has been minimized.

Copy link
@dannon

dannon Aug 18, 2017

Member

Much cleaner, I like this. I feel bad about writing it the other way now ;)

}
}
});
@@ -8,13 +8,10 @@ define( [ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view
var self = this;
this.deferred = new Deferred();
FormBase.prototype.initialize.call( this, options );
if ( this.model.get( 'inputs' ) ) {
this._buildForm( this.model.attributes );
} else {
this.deferred.execute( function( process ) {
self._buildModel( process, self.model.attributes, true );
});
}

// optional model update
this._update( this.model.get( 'initialmodel' ) );

// listen to history panel
if ( this.model.get( 'listen_to_history' ) && parent.Galaxy && parent.Galaxy.currHistoryPanel ) {
this.listenTo( parent.Galaxy.currHistoryPanel.collection, 'change', function() {
@@ -25,6 +22,21 @@ define( [ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view
this.$el.on( 'remove', function() { self._destroy() } );
},

/** Allows tool form variation to update tool model */
_update: function( callback ) {
var self = this;
callback = callback || this.model.get( 'buildmodel' );
if ( callback ) {
this.deferred.reset();
this.deferred.execute( function( process ) {
callback( process, self );
process.then( function() { self._render() } );
});
} else {
this._render();
}
},

/** Wait for deferred build processes before removal */
_destroy: function() {
var self = this;
@@ -36,98 +48,29 @@ define( [ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view
},

/** Build form */
_buildForm: function( options ) {
_render: function() {
var self = this;
this.model.set( options );
var options = this.model.attributes;
this.model.set({
title : options.title || '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Version ' + options.version + ')',
operations : !this.model.get( 'hide_operations' ) && this._operations(),
title : options.fixed_title || '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Version ' + options.version + ')',
operations : !options.hide_operations && this._operations(),
onchange : function() {
self.deferred.reset();
self.deferred.execute( function ( process ) {
self.model.get( 'postchange' )( process, self );
});
}
});
this.model.get( 'customize' ) && this.model.get( 'customize' )( this );
this.render();
if ( !this.model.get( 'collapsible' ) ) {
this.$el.append( $( '<div/>' ).addClass( 'ui-margin-top-large' ).append( this._footer() ) );
}
},

/** Builds a new model through api call and recreates the entire form */
_buildModel: function( process, new_options, hide_message ) {
var self = this;
var options = this.model.attributes;
options.version = new_options.version;
options.id = new_options.id;

// build request url
var build_url = '';
var build_data = {};
var job_id = '';
// When re-running a job the job_id is found in the new_options object.
// When re-running a job and requesting a new tool_version,
// the job_id is in the options object.
if ( new_options.job_id ) {
job_id = new_options.job_id;
} else if (options.job_id) {
job_id = options.job_id;
}
if ( job_id ) {
build_url = Galaxy.root + 'api/jobs/' + job_id + '/build_for_rerun';
} else {
build_url = Galaxy.root + 'api/tools/' + options.id + '/build';
build_data = $.extend( {}, Galaxy.params );
build_data[ 'tool_id' ] && ( delete build_data[ 'tool_id' ] );
}
options.version && ( build_data[ 'tool_version' ] = options.version );

// get initial model
Utils.get({
url : build_url,
data : build_data,
success : function( data ) {
if( !data.display ) {
window.location = Galaxy.root;
return;
}
self._buildForm( data );
!hide_message && self.message.update({
status : 'success',
message : 'Now you are using \'' + options.name + '\' version ' + options.version + ', id \'' + options.id + '\'.',
persistent : false
});
Galaxy.emit.debug('tool-form-base::_buildModel()', 'Initial tool model ready.', data);
process.resolve();
},
error : function( response, status ) {
var error_message = ( response && response.err_msg ) || 'Uncaught error.';
if ( status == 401 ) {
window.location = Galaxy.root + 'user/login?' + $.param({ redirect : Galaxy.root + '?tool_id=' + options.id });
} else if ( self.$el.is( ':empty' ) ) {
self.$el.prepend( ( new Ui.Message({
message : error_message,
status : 'danger',
persistent : true,
large : true
}) ).$el );
} else {
Galaxy.modal && Galaxy.modal.show({
title : 'Tool request failed',
body : error_message,
buttons : {
'Close' : function() {
Galaxy.modal.hide();
}
}
});
}
Galaxy.emit.debug( 'tool-form-base::_buildModel()', 'Initial tool model request failed.', response );
process.reject();
}
this.show_message && this.message.update({
status : 'success',
message : 'Now you are using \'' + options.name + '\' version ' + options.version + ', id \'' + options.id + '\'.',
persistent : false
});
this.show_message = true;
},

/** Create tool operation menu */
@@ -151,19 +94,9 @@ define( [ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view
icon : 'fa-cube',
onclick : function() {
// here we update the tool version (some tools encode the version also in the id)
var id = options.id.replace( options.version, this.version );
var version = this.version;
// queue model request
self.deferred.reset();
self.deferred.execute( function( process ) {
if ( options.hasOwnProperty( "workflow" ) ) {
// this is needed for notifying the workflow editor form
options.version = version;
self.model.get( 'postchange' )( process, self );
} else {
self._buildModel( process, { id : id, version : version } );
};
});
self.model.set( 'id', options.id.replace( options.version, this.version ) );

This comment has been minimized.

Copy link
@mvdbeek

mvdbeek Aug 18, 2017

Member

Unfortunately I think this could break for tools that carry "version-like" numbers in their id, like if Bowtie2 version 2 was updated to version 3 (very hypothetical of course). The API is smart enough to ignore the version in the tool id if an explicit version is requested.

It seems that the id gets updated in another place anyway.

I think this get updated here https://github.com/guerler/galaxy/blob/5a913700221c3734364d70546abfa1b9342d8c1b/client/galaxy/scripts/mvc/tool/tool-form.js#L36 in the tool form or here https://github.com/guerler/galaxy/blob/5a913700221c3734364d70546abfa1b9342d8c1b/client/galaxy/scripts/mvc/workflow/workflow-forms.js#L62 in the workflow editor form.

This comment has been minimized.

Copy link
@guerler

guerler Aug 18, 2017

Author Contributor

Yeah, I am not a fan of having to replace the id in the string either. Although this PR does not change that. We introduced it because the tool version is encoded in the tool id / url of tool shed tools. You can see it in the top line of the replaced part.

This comment has been minimized.

Copy link
@mvdbeek

mvdbeek Aug 18, 2017

Member

Ah, didn't realize that was already here. In any case this isn't necessary anymore with #4119, would be good if we can remove that.

self.model.set( 'version', this.version );
self._update();
}
});
}
@@ -45,7 +45,7 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
}
step = Utils.merge( {
index : i,
title : _.escape( title ),
fixed_title : _.escape( title ),
icon : icon || '',
help : null,
citations : null,
@@ -304,7 +304,7 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
var is_simple_input = ([ 'data_input', 'data_collection_input' ]).indexOf( step.step_type ) != -1;
_.each( step.inputs, function( input ) { input.flavor = 'module'; input.hide_label = is_simple_input; } );
form = new Form( Utils.merge({
title : step.title,
title : step.fixed_title,
onchange : function() { _.each( self.links[ step.index ], function( link ) { self._refreshStep( link ) } ) },
inputs : step.inputs && step.inputs.length > 0 ? step.inputs : [ { type: 'hidden', name: 'No options available.', ignore: null } ]
}, step ) );
@@ -8,42 +8,64 @@ define([ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/ui/ui-modal', 'mvc/tool/tool-form
this.form = new ToolFormBase( Utils.merge({
listen_to_history : true,
always_refresh : false,
customize : function( form ) {
buildmodel: function( process, form ) {
var options = form.model.attributes;
// build execute button
options.buttons = {
execute: execute_btn = new Ui.Button({
icon : 'fa-check',
tooltip : 'Execute: ' + options.name + ' (' + options.version + ')',
title : 'Execute',
cls : 'btn btn-primary ui-clear-float',
wait_cls : 'btn btn-info ui-clear-float',
onclick : function() {
execute_btn.wait();
form.portlet.disable();
self.submit( options, function() {
execute_btn.unwait();
form.portlet.enable();
} );
}
})
}
// remap feature
if ( options.job_id && options.job_remap ) {
options.inputs.push({
label : 'Resume dependencies from this job',
name : 'rerun_remap_job_id',
type : 'select',
display : 'radio',
ignore : '__ignore__',
value : '__ignore__',
options : [ [ 'Yes', options.job_id ], [ 'No', '__ignore__' ] ],
help : 'The previous run of this tool failed and other tools were waiting for it to finish successfully. Use this option to resume those tools using the new output(s) of this tool run.'
});

// build request url
var build_url = '';
var build_data = {};
var job_id = options.job_id;
if ( job_id ) {
build_url = Galaxy.root + 'api/jobs/' + job_id + '/build_for_rerun';
} else {
build_url = Galaxy.root + 'api/tools/' + options.id + '/build';
build_data = $.extend( {}, Galaxy.params );
build_data[ 'tool_id' ] && ( delete build_data[ 'tool_id' ] );
}
options.version && ( build_data[ 'tool_version' ] = options.version );

// get initial model
Utils.get({
url : build_url,
data : build_data,
success : function( data ) {
if( !data.display ) {
window.location = Galaxy.root;
return;
}
form.model.set( data );
self._customize( form );
Galaxy.emit.debug('tool-form-base::_buildModel()', 'Initial tool model ready.', data);
process.resolve();
},
error : function( response, status ) {
var error_message = ( response && response.err_msg ) || 'Uncaught error.';
if ( status == 401 ) {

This comment has been minimized.

Copy link
@dannon

dannon Aug 18, 2017

Member

This is not new code, and it's not a problem with this PR, but is this something we can handle elsewhere (in a single place) down the road so we don't have to augment all these requests with login redirects?

window.location = Galaxy.root + 'user/login?' + $.param({ redirect : Galaxy.root + '?tool_id=' + options.id });
} else if ( form.$el.is( ':empty' ) ) {
form.$el.prepend( ( new Ui.Message({
message : error_message,
status : 'danger',
persistent : true,
large : true
}) ).$el );
} else {
Galaxy.modal && Galaxy.modal.show({
title : 'Tool request failed',
body : error_message,
buttons : {
'Close' : function() {
Galaxy.modal.hide();
}
}
});
}
Galaxy.emit.debug( 'tool-form-base::_buildModel()', 'Initial tool model request failed.', response );
process.reject();
}
});
},
postchange : function( process, form ) {
var self = this;
var current_state = {
tool_id : form.model.get( 'id' ),
tool_version : form.model.get( 'version' ),
@@ -73,6 +95,42 @@ define([ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/ui/ui-modal', 'mvc/tool/tool-form
this.$el.append( this.form.$el );
},

_customize: function( form ) {
var self = this;
var options = form.model.attributes;
// build execute button
options.buttons = {
execute: execute_btn = new Ui.Button({
icon : 'fa-check',
tooltip : 'Execute: ' + options.name + ' (' + options.version + ')',
title : 'Execute',
cls : 'btn btn-primary ui-clear-float',
wait_cls : 'btn btn-info ui-clear-float',
onclick : function() {
execute_btn.wait();
form.portlet.disable();
self.submit( options, function() {
execute_btn.unwait();
form.portlet.enable();
} );
}
})
}
// remap feature
if ( options.job_id && options.job_remap ) {
options.inputs.push({
label : 'Resume dependencies from this job',
name : 'rerun_remap_job_id',
type : 'select',
display : 'radio',
ignore : '__ignore__',
value : '__ignore__',
options : [ [ 'Yes', options.job_id ], [ 'No', '__ignore__' ] ],
help : 'The previous run of this tool failed and other tools were waiting for it to finish successfully. Use this option to resume those tools using the new output(s) of this tool run.'
});
}
},

/** Submit a regular job.
* @param{dict} options - Specifies tool id and version
* @param{function} callback - Called when request has completed
@@ -207,4 +265,4 @@ define([ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/ui/ui-modal', 'mvc/tool/tool-form
return {
View: View
};
});
});
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.