Skip to content

Commit

Permalink
Revise label handling and duplicate check, move save controller to ap…
Browse files Browse the repository at this point in the history
…i for proper error response
  • Loading branch information
guerler committed Jan 11, 2017
1 parent 20c2707 commit e571fce
Show file tree
Hide file tree
Showing 16 changed files with 96 additions and 160 deletions.
8 changes: 4 additions & 4 deletions client/galaxy/scripts/mvc/tool/tool-form-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,18 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view',
Utils.get({
url : build_url,
data : build_data,
success : function( new_model ) {
if( !new_model.display ) {
success : function( data ) {
if( !data.display ) {
window.location = Galaxy.root;
return;
}
self._buildForm( new_model );
self._buildForm( data );
!hide_message && self.message.update({
status : 'success',
message : 'Now you are using \'' + self.options.name + '\' version ' + self.options.version + ', id \'' + self.options.id + '\'.',
persistent : false
});
Galaxy.emit.debug('tool-form-base::_buildModel()', 'Initial tool model ready.', new_model);
Galaxy.emit.debug('tool-form-base::_buildModel()', 'Initial tool model ready.', data);
process.resolve();
},
error : function( response, status ) {
Expand Down
38 changes: 0 additions & 38 deletions client/galaxy/scripts/mvc/workflow/workflow-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,9 @@ function( Connector, Toastr ) {
this.name = null;
this.has_changes = false;
this.active_form_has_changes = false;
this.nodeLabels = {};
this.workflowOutputLabels = {};
}
$.extend( Workflow.prototype, {
canLabelNodeWith: function( label ) {
if( label ) {
return ! (label in this.nodeLabels);
} else {
// empty labels are non-exclusive, so allow this one.
return true;
}
},
registerNodeLabel: function( label ) {
if( label ) {
this.nodeLabels[label] = true;
}
},
unregisterNodeLabel: function( label ) {
if( label ) {
delete this.nodeLabels[label];
}
},
updateNodeLabel: function( fromLabel, toLabel ) {
if( fromLabel ) {
this.unregisterNodeLabel( fromLabel );
}
if( ! this.canLabelNodeWith( toLabel ) ) {
Toastr.warning("Workflow contains duplicate node labels " + toLabel + ". This must be fixed before it can be saved.");
}
if( toLabel ) {
this.registerNodeLabel( toLabel );
}
},
attemptUpdateNodeLabel: function( node, label ) {
if( this.canLabelNodeWith( label ) ) {
node.setLabel( label );
return true;
} else {
return false;
}
},
canLabelOutputWith: function( label ) {
if( label ) {
return ! (label in this.workflowOutputLabels);
Expand Down
12 changes: 3 additions & 9 deletions client/galaxy/scripts/mvc/workflow/workflow-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,6 @@ define(['mvc/workflow/workflow-view-node'], function( NodeView ) {
// Remove active class
$(element).removeClass( "toolForm-active" );
},
setLabel: function(label) {
this.app.workflow.updateNodeLabel(this.label, label);
this.label = label || null;
},
init_field_data : function ( data ) {
if ( data.type ) {
this.type = data.type;
Expand All @@ -163,17 +159,15 @@ define(['mvc/workflow/workflow-view-node'], function( NodeView ) {
this.tooltip = data.tooltip ? data.tooltip : "";
this.annotation = data.annotation;
this.post_job_actions = data.post_job_actions ? data.post_job_actions : {};
this.setLabel(data.label);
this.label = data.label;
this.uuid = data.uuid;
this.workflow_outputs = data.workflow_outputs ? data.workflow_outputs : [];

var node = this;
var nodeView = new NodeView({
el: this.element[ 0 ],
node: node,
});
node.nodeView = nodeView;

$.each( data.data_inputs, function( i, input ) {
nodeView.addDataInput( input );
});
Expand All @@ -188,12 +182,12 @@ define(['mvc/workflow/workflow-view-node'], function( NodeView ) {
},
update_field_data : function( data ) {
var node = this;
nodeView = node.nodeView;
var nodeView = node.nodeView;
this.tool_state = data.tool_state;
this.config_form = data.config_form;
this.errors = data.errors;
this.annotation = data['annotation'];
this.setLabel(data.label);
this.label = data.label;
if( "post_job_actions" in data ) {
// Won't be present in response for data inputs
var pja_in = data.post_job_actions;
Expand Down
112 changes: 46 additions & 66 deletions client/galaxy/scripts/mvc/workflow/workflow-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ define([
var self = Globals.app = this;
this.options = options;
this.urls = options && options.urls || {};
this.active_ajax_call = false;
var close_editor = function() {
self.workflow.check_changes_in_active_form();
if ( workflow && self.workflow.has_changes ) {
Expand Down Expand Up @@ -95,56 +94,37 @@ define([
return;
}
self.workflow.rectify_workflow_outputs();
var savefn = function(callback) {
$.ajax( {
url: self.urls.save_workflow,
type: "POST",
data: {
id: self.options.id,
workflow_data: function() { return JSON.stringify( self.workflow.to_simple() ); },
"_": "true"
},
dataType: 'json',
success: function( data ) {
var body = $("<div></div>").text( data.message );
if ( data.errors ) {
body.addClass( "warningmark" );
var errlist = $( "<ul/>" );
$.each( data.errors, function( i, v ) {
$("<li></li>").text( v ).appendTo( errlist );
});
body.append( errlist );
} else {
body.addClass( "donemark" );
}
self.workflow.name = data.name;
self.workflow.has_changes = false;
self.workflow.stored = true;
self.showWorkflowParameters();
if ( data.errors ) {
window.show_modal( "Saving workflow", body, { "Ok" : hide_modal } );
} else {
if (callback) {
callback();
}
hide_modal();
}
Utils.request( {
url: Galaxy.root + 'api/workflows/' + self.options.id + '/save',
type: "POST",
data: self.workflow.to_simple(),
success: function( data ) {
var body = $( "<div/>" ).text( data.message );
if ( data.errors ) {
body.addClass( "warningmark" );
var errlist = $( "<ul/>" );
$.each( data.errors, function( i, v ) {
$( "<li/>" ).text( v ).appendTo( errlist );
});
body.append( errlist );
} else {
body.addClass( "donemark" );
}
});
};

// We bind to ajaxStop because of auto-saving, since the form submission ajax
// call needs to be completed so that the new data is saved
if (self.active_ajax_call) {
$(document).bind('ajaxStop.save_workflow', function() {
$(document).unbind('ajaxStop.save_workflow');
savefn();
$(document).unbind('ajaxStop.save_workflow'); // IE7 needs it here
self.active_ajax_call = false;
});
} else {
savefn(success_callback);
}
self.workflow.name = data.name;
self.workflow.has_changes = false;
self.workflow.stored = true;
self.showWorkflowParameters();
if ( data.errors ) {
window.show_modal( "Saving workflow", body, { "Ok" : hide_modal } );
} else {
success_callback && success_callback();
hide_modal();
}
},
error: function( response ) {
window.show_modal( "Saving workflow failed.", response.err_msg, { "Ok" : hide_modal } );
}
});
};

// Init searching.
Expand Down Expand Up @@ -273,21 +253,6 @@ define([
}
});

// For autosave purposes
$(document).ajaxStart( function() {
self.active_ajax_call = true;
$(document).bind( "ajaxStop.global", function() {
self.active_ajax_call = false;
});
});

$(document).ajaxError( function ( e, x ) {
// console.log( e, x );
var message = x.responseText || x.statusText || "Could not connect to server";
window.show_modal( "Server error", message, { "Ignore error" : hide_modal } );
return false;
});

window.make_popupmenu && make_popupmenu( $("#workflow-options-button"), {
"Save" : save_current_workflow,
"Save As": workflow_save_as,
Expand Down Expand Up @@ -690,6 +655,7 @@ define([
},

showForm: function ( content, node ) {
var self = this;
var cls = 'right-content';
var id = cls + '-' + node.id;
var $container = $( '#' + cls );
Expand All @@ -711,7 +677,21 @@ define([
name : '__label',
label : 'Label',
value : node.label,
help : 'Add a step label.'
help : 'Add a step label.',
onchange: function( new_label ) {
var duplicate = false;
for ( var i in self.workflow.nodes ) {
var n = self.workflow.nodes[ i ];
if ( n.label && n.label == new_label && n.id != node.id ) {
duplicate = true;
break;
}
}
var input_id = form.data.match( '__label' );
var input_element = form.element_list[ input_id ];
input_element.model.set( 'error_text', duplicate && 'Duplicate label. Please fix this before saving the workflow.' );
form.trigger( 'change' );
}
});
content.inputs.push({
type : 'text',
Expand Down
33 changes: 33 additions & 0 deletions lib/galaxy/webapps/galaxy/api/workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,39 @@ def import_new_workflow_deprecated(self, trans, payload, **kwd):
"""
return self.__api_import_new_workflow( trans, payload, **kwd )

@expose_api
def save( self, trans, id, payload, **kwd ):
"""
POST /api/workflows/id/save
Save the workflow described by `workflow_data` with id `id`.
"""
print payload
# Get the stored workflow
stored = self.__get_stored_workflow( trans, id )
try:
workflow, errors = self.workflow_contents_manager.update_workflow_from_dict(
trans,
stored,
payload,
)
except workflows.MissingToolsException as e:
return dict(
name=e.workflow.name,
message="This workflow includes missing or invalid tools. It cannot be saved until the following steps are removed or the missing tools are enabled.",
errors=e.errors,
)
if workflow.has_errors:
errors.append( "Some steps in this workflow have validation errors." )
if workflow.has_cycles:
errors.append( "This workflow contains cycles." )
if errors:
rval = dict( message="Workflow saved, but will not be runnable due to the following errors.",
errors=errors )
else:
rval = dict( message="Workflow saved." )
rval['name'] = workflow.name
return rval

@expose_api
def update( self, trans, id, payload, **kwds ):
"""
Expand Down
1 change: 1 addition & 0 deletions lib/galaxy/webapps/galaxy/buildapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ def populate_api_routes( webapp, app ):
webapp.mapper.connect( '/api/genomes/{id}/sequences', controller='genomes', action='sequences' )
webapp.mapper.resource( 'visualization', 'visualizations', path_prefix='/api' )
webapp.mapper.connect( '/api/workflows/build_module', action='build_module', controller="workflows" )
webapp.mapper.connect( '/api/workflows/{id}/save', action='save', controller="workflows" )
webapp.mapper.resource( 'workflow', 'workflows', path_prefix='/api' )
webapp.mapper.resource_with_deleted( 'history', 'histories', path_prefix='/api' )
webapp.mapper.connect( '/api/histories/{history_id}/citations', action='citations', controller="histories" )
Expand Down
34 changes: 0 additions & 34 deletions lib/galaxy/webapps/galaxy/controllers/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -684,40 +684,6 @@ def load_workflow( self, trans, id ):
workflow_contents_manager = workflows.WorkflowContentsManager(trans.app)
return workflow_contents_manager.workflow_to_dict( trans, stored, style="editor" )

@web.json
def save_workflow( self, trans, id, workflow_data ):
"""
Save the workflow described by `workflow_data` with id `id`.
"""
# Get the stored workflow
stored = self.get_stored_workflow( trans, id )
workflow_contents_manager = workflows.WorkflowContentsManager(trans.app)
try:
workflow, errors = workflow_contents_manager.update_workflow_from_dict(
trans,
stored,
workflow_data,
)
except workflows.MissingToolsException as e:
return dict(
name=e.workflow.name,
message="This workflow includes missing or invalid tools. "
"It cannot be saved until the following steps are removed or the missing tools are enabled.",
errors=e.errors,
)

if workflow.has_errors:
errors.append( "Some steps in this workflow have validation errors" )
if workflow.has_cycles:
errors.append( "This workflow contains cycles" )
if errors:
rval = dict( message="Workflow saved, but will not be runnable due to the following errors",
errors=errors )
else:
rval = dict( message="Workflow saved" )
rval['name'] = workflow.name
return rval

@web.expose
@web.require_login( "use workflows" )
def export_to_myexp( self, trans, id, myexp_username, myexp_password ):
Expand Down

0 comments on commit e571fce

Please sign in to comment.