Workflow: create a new python module for 'WorkflowModules'. Tools are now another type of module, which removes a lot of special cases in the controller. Fixed some problems with validation and parameter groups.

This commit is contained in:
James Taylor
2008-06-27 00:22:02 +00:00
parent a662635a38
commit 69c4444de2
7 changed files with 346 additions and 234 deletions
+54 -207
View File
@@ -9,6 +9,7 @@ from galaxy.datatypes.data import Data
from galaxy.util.odict import odict
from galaxy.util.bunch import Bunch
from galaxy.util.topsort import topsort, topsort_levels, CycleError
from galaxy.workflow.modules import *
class WorkflowController( BaseController ):
beta = True
@@ -31,7 +32,7 @@ class WorkflowController( BaseController ):
"""
user = trans.get_user()
if not workflow_name:
return error( "Must provide a name for the new workflow" )
error( "Must provide a name for the new workflow" )
# Create the new stored workflow
stored_workflow = model.StoredWorkflow()
stored_workflow.name = workflow_name
@@ -70,13 +71,12 @@ class WorkflowController( BaseController ):
rendered by `editor_canvas`.
"""
if not id:
return trans.show_error_message( "Invalid workflow id" )
error( "Invalid workflow id" )
id = trans.security.decode_id( id )
return trans.fill_template( "workflow/editor.mako",
workflow_id=id )
return trans.fill_template( "workflow/editor.mako", workflow_id=id )
@web.json
def editor_tool_form( self, trans, tool_id=None, **incoming ):
def editor_tool_form( self, trans, type='tool', tool_id=None, **incoming ):
"""
Accepts a tool state and incoming values, and generates a new tool
form and some additional information, packed into a json dictionary.
@@ -84,59 +84,39 @@ class WorkflowController( BaseController ):
is selected.
"""
trans.workflow_building_mode = True
tool = trans.app.toolbox.tools_by_id[tool_id]
state = DefaultToolState()
state.decode( incoming.pop("tool_state"), tool, trans.app )
errors = tool.update_state( trans, tool.inputs, state.inputs, incoming )
rval = {}
rval['form_html'] = trans.fill_template( "workflow/editor_tool_form.mako",
tool=tool, as_html=as_html, values=state.inputs, errors=errors )
if errors:
rval['tool_errors'] = errors
else:
rval['tool_errors'] = None
# Updated data_inputs
rval['data_inputs'] = get_data_inputs( tool.inputs, state.inputs )
rval['state'] = state.encode( tool, trans.app )
return rval
module = module_factory.from_dict( trans, {
'type': type,
'tool_id': tool_id,
'tool_state': incoming.pop("tool_state")
} )
module.update_state( incoming )
return {
'tool_state': module.get_state(),
'data_inputs': module.get_data_inputs(),
'data_outputs': module.get_data_outputs(),
'form_html': module.get_config_form()
}
@web.json
def get_tool_info( self, trans, tool_id ):
def get_new_module_info( self, trans, type, **kwargs ):
"""
Generate a json dictionary containing info about the tool specified by
`tool_id`. Info includes data inputs and outputs, html representation
Get the info for a new instance of a module initialized with default
paramters (any keyword arguments will be passed along to the module).
Result includes data inputs and outputs, html representation
of the initial form, and the initial tool state (with default values).
This is called asynchronously whenever a new node is added.
"""
trans.workflow_building_mode = True
tool = trans.app.toolbox.tools_by_id[tool_id]
rval = {}
rval['name'] = tool.name
rval['tool_id'] = tool.id
data_outputs = []
for name, ( format, metadata_source, parent ) in tool.outputs.iteritems():
data_outputs.append( dict( name=name, extension=format ) )
rval['data_outputs'] = data_outputs
state = tool.new_state( trans, all_pages=True )
rval['form_html'] = trans.fill_template( "workflow/editor_tool_form.mako",
tool=tool, as_html=as_html, values=state.inputs, errors={} )
rval['tool_state'] = state.encode( tool, trans.app )
rval['data_inputs'] = get_data_inputs( tool.inputs, state.inputs )
return rval
@web.json
def get_module_info( self, trans, type ):
module = module_types[type]()
rval = {}
rval['name'] = module.name
rval['type'] = module.type
rval['tool_state'] = state = module.get_state()
rval['data_inputs'] = module.get_data_inputs()
rval['data_outputs'] = module.get_data_outputs()
rval['form_html'] = trans.fill_template(
"workflow/editor_generic_form.mako",
form = module.get_config_form() )
return rval
module = module_factory.new( trans, type, **kwargs )
return {
'type': module.type,
'name': module.get_name(),
'tool_id': module.get_tool_id(),
'tool_state': module.get_state(),
'data_inputs': module.get_data_inputs(),
'data_outputs': module.get_data_outputs(),
'form_html': module.get_config_form()
}
@web.json
def load_workflow( self, trans, id ):
@@ -158,39 +138,18 @@ class WorkflowController( BaseController ):
data['steps'] = {}
# For each step, rebuild the form and encode the state
for step in workflow.steps:
step_dict = {}
step_dict['id'] = step.order_index
step_dict['type'] = step_type = ( step.type or "tool" )
if step_type == 'tool':
step_dict['tool_id'] = tool_id = step.tool_id
# Load tool
tool = trans.app.toolbox.tools_by_id[tool_id]
# Build a state from the tool_inputs dict
state = DefaultToolState()
state.inputs = tool.params_from_strings( step.tool_inputs, trans.app, ignore_errors=True )
step_dict['tool_state'] = state.encode( tool, trans.app )
# Error messages for the tool
step_dict['tool_errors'] = ( step.tool_errors or None )
# Input and output specs
step_dict['data_inputs'] = get_data_inputs( tool.inputs, state.inputs )
data_outputs = []
for name, ( format, metadata_source, parent ) in tool.outputs.iteritems():
data_outputs.append( dict( name=name, extension=format ) )
step_dict['data_outputs'] = data_outputs
# Build the tool form html
errors = step.tool_errors
step_dict['form_html'] = trans.fill_template( "workflow/editor_tool_form.mako",
tool=tool, as_html=as_html, values=state.inputs, errors=( step.tool_errors or {} ) )
step_dict['name'] = tool.name
else:
module = module_types[step.type].from_workflow_step( step )
step_dict['name'] = module.name
step_dict['tool_state'] = state = module.get_state()
step_dict['data_inputs'] = module.get_data_inputs()
step_dict['data_outputs'] = module.get_data_outputs()
step_dict['form_html'] = trans.fill_template(
"workflow/editor_generic_form.mako",
form = module.get_config_form() )
module = module_factory.from_workflow_step( trans, step )
step_dict = {
'id': step.order_index,
'type': module.type,
'tool_id': module.get_tool_id(),
'name': module.get_name(),
'tool_state': module.get_state(),
'tool_errors': module.get_errors(),
'data_inputs': module.get_data_inputs(),
'data_outputs': module.get_data_outputs(),
'form_html': module.get_config_form()
}
# Connections
input_conn_dict = {}
for conn in step.input_connections:
@@ -229,25 +188,14 @@ class WorkflowController( BaseController ):
for key, step_dict in data['steps'].iteritems():
# Create the model class for the step
step = model.WorkflowStep()
step.type = step_type = step_dict['type']
steps.append( step )
steps_by_external_id[ step_dict['id' ] ] = step
# FIXME: Position should be handled inside module
step.position = step_dict['position']
if step_type == 'tool':
step.tool_id = step_dict['tool_id']
# Decode the tool state from the step dict
tool = trans.app.toolbox.tools_by_id[ step_dict['tool_id'] ]
state = DefaultToolState()
state.decode( step_dict['tool_state'], tool, trans.app )
# Convert back to strings for database
tool_inputs = tool.params_to_strings( state.inputs, trans.app )
step.tool_inputs = tool_inputs
step.tool_errors = step_dict.get( 'tool_errors', None )
if step.tool_errors:
workflow.has_errors = True
else:
module = module_types[step_type].from_state( step_dict['tool_state'] )
module.save_to_step( step )
module = module_factory.from_dict( trans, step_dict )
module.save_to_step( step )
if step.tool_errors:
workflow.has_errors = True
# Stick this in the step temporarily
step.temp_input_connections = step_dict['input_connections']
# Second pass to deal with connections between steps
@@ -405,15 +353,12 @@ class WorkflowController( BaseController ):
workflow = stored.latest_workflow
# It is possible for a workflow to have 0 steps
if len( workflow.steps ) == 0:
return trans.show_error_message(
"Workflow cannot be run because it does not have any steps" )
error( "Workflow cannot be run because it does not have any steps" )
#workflow = Workflow.from_simple( simplejson.loads( stored.encoded_value ), trans.app )
if workflow.has_cycles:
return trans.show_error_message(
"Workflow cannot be run because it contains cycles" )
error( "Workflow cannot be run because it contains cycles" )
if workflow.has_errors:
return trans.show_error_message(
"Workflow cannot be run because of validation errors in some steps" )
error( "Workflow cannot be run because of validation errors in some steps" )
# Build the state for each step
errors = {}
if kwargs:
@@ -438,7 +383,7 @@ class WorkflowController( BaseController ):
step_errors = tool.update_state( trans, tool.inputs, step.state.inputs, step_args,
update_only=True, old_errors=old_errors )
else:
module = step.module = WorkflowModule.from_workflow_step( step )
module = step.module = module_factory.from_workflow_step( trans, step )
state = step.state = module.decode_runtime_state( trans, step_args.pop( "tool_state" ) )
step_errors = module.update_runtime_state( trans, state, step_args )
if step_errors:
@@ -495,7 +440,7 @@ class WorkflowController( BaseController ):
errors[step.id] = step.tool_errors
else:
## Non-tool specific stuff?
step.module = WorkflowModule.from_workflow_step( step )
step.module = module_factory.from_workflow_step( trans, step )
step.state = step.module.get_runtime_state()
# Connections by input name
step.input_connections_by_name = dict( ( conn.input_name, conn ) for conn in step.input_connections )
@@ -505,70 +450,6 @@ class WorkflowController( BaseController ):
steps=workflow.steps,
workflow=stored,
errors=errors )
## ---- Workflow modules (to be factored out) ---------------------------------
from elementtree.ElementTree import Element
## TODO: 'Tool' should be a module rather than a special case
class WorkflowModule( object ):
@classmethod
def from_workflow_step( cls, step ):
assert step.type in module_types, "Unknown module type"
return module_types[ step.type ].from_workflow_step( step )
class InputDataModule( WorkflowModule ):
type = "data_input"
name = "Input dataset"
_inputs = {
'input' : DataToolParameter( None, Element( "param", name="input", label="Input Dataset", type="data", format="data" ) )
}
@classmethod
def from_state( cls, state ):
return cls()
@classmethod
def from_workflow_step( cls, step ):
return cls()
def get_state( self ):
return None
def save_to_step( self, step ):
pass
def get_data_inputs( self ):
return []
def get_data_outputs( self ):
return [ dict( name='output', extension='input' ) ]
def get_config_form( self ):
return web.FormBuilder( title=self.name )
def get_runtime_inputs( self ):
return self._inputs
def get_runtime_state( self ):
state = DefaultToolState()
state.inputs = dict( input=None )
return state
def encode_runtime_state( self, trans, state ):
fake_tool = Bunch( inputs = self.get_runtime_inputs() )
return state.encode( fake_tool, trans.app )
def decode_runtime_state( self, trans, string ):
fake_tool = Bunch( inputs = self.get_runtime_inputs() )
state = DefaultToolState()
state.decode( string, fake_tool, trans.app )
return state
def update_runtime_state( self, trans, state, values ):
errors = {}
for name, param in self._inputs.iteritems():
value, error = check_param( trans, param, values[name], values )
state.inputs[ name ] = value
if error:
errors[ name ] = error
return errors
def execute( self, trans, state ):
return dict( output=state.inputs['input'])
module_types = dict( data_input=InputDataModule )
## ---- Utility methods -------------------------------------------------------
@@ -589,12 +470,6 @@ def get_stored_workflow( trans, id ):
error( "Workflow is not owned by current user" )
# Looks good
return stored
def as_html( param, value, trans, prefix ):
if type( param ) is DataToolParameter:
return "Data input '" + param.name + "' (" + ( " or ".join( param.extensions ) ) + ")"
else:
return param.get_html_field( trans, value ).get_html( prefix )
def attach_ordered_steps( workflow, steps ):
ordered_steps = order_workflow_steps( steps )
@@ -700,32 +575,4 @@ def cleanup_param_values( inputs, values ):
prefix = "%s|" % ( key )
cleanup( prefix, input.cases[current_case].inputs, group_values )
cleanup( "", inputs, values )
return associations
def get_data_inputs( inputs, input_values ):
"""
For a set of input definitions and a tool state, find all of the dataset
inputs
"""
data_inputs = []
def visitor( inputs, input_values, name_prefix, label_prefix ):
for input in inputs.itervalues():
if isinstance( input, Repeat ):
for i, d in enumerate( input_values[ input.name ] ):
index = d['__index__']
new_name_prefix = name_prefix + "%s_%d|" % ( input.name, index )
new_label_prefix = label_prefix + "%s %d > " % ( input.title, i + 1 )
visitor( input.inputs, d, new_name_prefix, new_label_prefix )
elif isinstance( input, Conditional ):
values = input_values[ input.name ]
current = values["__current_case__"]
label_prefix = label_prefix
name_prefix = name_prefix + "|" + input.name
visitor( input.cases[current].inputs, values, name_prefix, label_prefix )
else:
if isinstance( input, DataToolParameter ):
data_inputs.append( dict( name=name_prefix+input.name, label=label_prefix+input.label, extensions=input.extensions ) )
visitor( inputs, input_values, "", "" )
return data_inputs
return associations
View File
+232
View File
@@ -0,0 +1,232 @@
from elementtree.ElementTree import Element
from galaxy import web
from galaxy.tools.parameters import DataToolParameter, check_param
from galaxy.tools import DefaultToolState
from galaxy.tools.parameters.grouping import Repeat, Conditional
from galaxy.util.bunch import Bunch
class WorkflowModule( object ):
def __init__( self, trans ):
self.trans = trans
## ---- Creating modules from various representations ---------------------
@classmethod
def new( Class, trans, tool_id=None ):
"""
Create a new instance of the module with default state
"""
return Class( trans )
@classmethod
def from_dict( Class, trans, d ):
"""
Create a new instance of the module initialized from values in the
dictionary `d`.
"""
return Class( trans )
@classmethod
def from_workflow_step( Class, trans, step ):
return Class( trans )
## ---- Saving in various forms ------------------------------------------
def save_to_step( self, step ):
step.type = self.type
## ---- General attributes -----------------------------------------------
def get_type( self ):
return self.type
def get_name( self ):
return self.name
def get_tool_id( self ):
return None
## ---- Configuration time -----------------------------------------------
def get_state( self ):
return None
def get_errors( self ):
return None
def get_data_inputs( self ):
return []
def get_data_outputs( self ):
return []
def update_state( self ):
pass
def get_config_form( self ):
raise TypeError( "Abstract method" )
## ---- Run time ---------------------------------------------------------
def get_runtime_inputs( self ):
raise TypeError( "Abstract method" )
def get_runtime_state( self ):
raise TypeError( "Abstract method" )
def encode_runtime_state( self, trans, state ):
raise TypeError( "Abstract method" )
def decode_runtime_state( self, trans, string ):
raise TypeError( "Abstract method" )
def update_runtime_state( self, trans, state, values ):
raise TypeError( "Abstract method" )
def execute( self, trans, state ):
raise TypeError( "Abstract method" )
class InputDataModule( WorkflowModule ):
type = "data_input"
name = "Input dataset"
_runtime_inputs = {
'input' : DataToolParameter( None, Element( "param", name="input", label="Input Dataset", type="data", format="data" ) )
}
def get_data_inputs( self ):
return []
def get_data_outputs( self ):
return [ dict( name='output', extension='input' ) ]
def get_config_form( self ):
return self.trans.fill_template( "workflow/editor_generic_form.mako",
form = web.FormBuilder( title=self.name ) )
def get_runtime_inputs( self ):
return self._runtime_inputs
def get_runtime_state( self ):
state = DefaultToolState()
state.inputs = dict( input=None )
return state
def encode_runtime_state( self, trans, state ):
fake_tool = Bunch( inputs = self.get_runtime_inputs() )
return state.encode( fake_tool, trans.app )
def decode_runtime_state( self, trans, string ):
fake_tool = Bunch( inputs = self.get_runtime_inputs() )
state = DefaultToolState()
state.decode( string, fake_tool, trans.app )
return state
def update_runtime_state( self, trans, state, values ):
errors = {}
for name, param in self._runtime_inputs.iteritems():
value, error = check_param( trans, param, values.get( name, None ), values )
state.inputs[ name ] = value
if error:
errors[ name ] = error
return errors
def execute( self, trans, state ):
return dict( output=state.inputs['input'])
class ToolModule( object ):
type = "tool"
def __init__( self, trans, tool_id ):
self.trans = trans
self.tool_id = tool_id
self.tool = trans.app.toolbox.tools_by_id[ tool_id ]
self.state = None
self.errors = None
@classmethod
def new( Class, trans, tool_id=None ):
module = Class( trans, tool_id )
module.state = module.tool.new_state( trans, all_pages=True )
return module
@classmethod
def from_dict( Class, trans, d ):
tool_id = d['tool_id']
module = Class( trans, tool_id )
module.state = DefaultToolState()
module.state.decode( d["tool_state"], module.tool, module.trans.app )
module.errors = d.get( "tool_errors", None )
return module
@classmethod
def from_workflow_step( Class, trans, step ):
tool_id = step.tool_id
module = Class( trans, tool_id )
module.state = DefaultToolState()
print step.tool_inputs
module.state.inputs = module.tool.params_from_strings( step.tool_inputs, trans.app )
module.errors = step.tool_errors
return module
def save_to_step( self, step ):
step.type = self.type
step.tool_id = self.tool_id
step.tool_inputs = self.tool.params_to_strings( self.state.inputs, self.trans.app )
step.tool_errors = self.errors
def get_name( self ):
return self.tool.name
def get_tool_id( self ):
return self.tool_id
def get_state( self ):
return self.state.encode( self.tool, self.trans.app )
def get_errors( self ):
return self.errors
def get_data_inputs( self ):
data_inputs = []
def visitor( inputs, input_values, name_prefix, label_prefix ):
for input in inputs.itervalues():
if isinstance( input, Repeat ):
for i, d in enumerate( input_values[ input.name ] ):
index = d['__index__']
new_name_prefix = name_prefix + "%s_%d|" % ( input.name, index )
new_label_prefix = label_prefix + "%s %d > " % ( input.title, i + 1 )
visitor( input.inputs, d, new_name_prefix, new_label_prefix )
elif isinstance( input, Conditional ):
values = input_values[ input.name ]
current = values["__current_case__"]
label_prefix = label_prefix
name_prefix = name_prefix + "|" + input.name
visitor( input.cases[current].inputs, values, name_prefix, label_prefix )
else:
if isinstance( input, DataToolParameter ):
data_inputs.append( dict( name=name_prefix+input.name, label=label_prefix+input.label, extensions=input.extensions ) )
visitor( self.tool.inputs, self.state.inputs, "", "" )
return data_inputs
def get_data_outputs( self ):
data_outputs = []
for name, ( format, metadata_source, parent ) in self.tool.outputs.iteritems():
data_outputs.append( dict( name=name, extension=format ) )
return data_outputs
def get_config_form( self ):
def as_html( param, value, trans, prefix ):
if type( param ) is DataToolParameter:
return "Data input '" + param.name + "' (" + ( " or ".join( param.extensions ) ) + ")"
else:
return param.get_html_field( trans, value ).get_html( prefix )
return self.trans.fill_template( "workflow/editor_tool_form.mako",
tool=self.tool, as_html=as_html, values=self.state.inputs, errors=( self.errors or {} ) )
def update_state( self, incoming ):
errors = self.tool.update_state( self.trans, self.tool.inputs, self.state.inputs, incoming )
self.errors = errors or None
class WorkflowModuleFactory( object ):
def __init__( self, module_types ):
self.module_types = module_types
def new( self, trans, type, tool_id=None ):
"""
Return module for type and (optional) tool_id intialized with
new / default state.
"""
assert type in self.module_types
return self.module_types[type].new( trans, tool_id )
def from_dict( self, trans, d ):
"""
Return module initialized from the data in dictionary `d`.
"""
type = d['type']
assert type in self.module_types
return self.module_types[type].from_dict( trans, d )
def from_workflow_step( self, trans, step ):
"""
Return module initializd from the WorkflowStep object `step`.
"""
type = step.type
return self.module_types[type].from_workflow_step( trans, step )
module_factory = WorkflowModuleFactory( dict( data_input=InputDataModule, tool=ToolModule ) )
+4 -4
View File
@@ -66,15 +66,15 @@ $.ui.plugin.add("draggable", "scrollPanel", {
ui.position.top += amount_moved;
moved = true;
}
// Update offsets
if ( moved ) {
$.ui.ddmanager.prepareOffsets( instance, e );
}
// Still contain in panel
ui.position.left = Math.max( ui.position.left, 0 );
ui.position.top = Math.max( ui.position.top, 0 );
ui.position.left = Math.min( ui.position.left, panel_w - element_w );
ui.position.top = Math.min( ui.position.top, panel_h - element_h );
// Update offsets
if ( moved ) {
$.ui.ddmanager.prepareOffsets( instance, e );
}
// Keep moving even if mouse doesn't move
if ( moved ) {
instance.old_e = e;
@@ -295,9 +295,9 @@ $.extend( Node.prototype, {
update_field_data : function( data ) {
var el = $(this.element),
node = this;
this.tool_state = data.state;
this.tool_state = data.tool_state;
this.form_html = data.form_html;
this.tool_errors = data.tool_errors;
this.tool_errors = data.tool_errors;
if ( this.tool_errors ) {
el.addClass( "tool-node-error" );
} else {
@@ -493,27 +493,28 @@ function prebuild_node( type, title_text, tool_id ) {
scrollSpeed: 20,
// containment: $("#shim"),
// grow: true,
click: function( _, ui ) {
click: function( e, ui ) {
var element = $(this).data("draggable").element.get(0);
(function(p) { p.removeChild( element ); p.appendChild( element ) })(element.parentNode)
workflow.activate_node( node );
},
start: function() {
start: function( e, ui ) {
workflow.activate_node( node );
$(this).css( 'z-index', '1000' );
},
drag: function() {
drag: function( e, ui ) {
$(this).find( ".terminal" ).each( function() {
this.terminal.redraw();
})
},
stop: function( _, ui ) {
stop: function( e, ui ) {
var element = $(this).data("draggable").element.get(0);
(function(p) { p.removeChild( element ); p.appendChild( element ) })(element.parentNode)
$(this).css( 'z-index', '100' );
$(this).find( ".terminal" ).each( function() {
this.terminal.redraw();
});
workflow.node_changed( this );
}
});
return node;
+47 -16
View File
@@ -28,7 +28,7 @@
$(".dialog-box-container" ).fadeOut( function() { $("#overlay").hide(); } );
};
function show_modal( title, body, buttons ) {
function show_modal( title, body, buttons, extra_buttons ) {
$( ".dialog-box" ).find( ".title" ).html( title );
var b = $( ".dialog-box" ).find( ".buttons" ).html( "" );
if ( buttons ) {
@@ -40,6 +40,16 @@
} else {
b.hide();
}
var b = $( ".dialog-box" ).find( ".extra_buttons" ).html( "" );
if ( extra_buttons ) {
$.each( extra_buttons, function( name, value ) {
b.append( $( '<button/>' ).text( name ).click( value ) );
b.append( " " );
});
b.show();
} else {
b.hide();
}
if ( body == "progress" ) {
body = $( "<img src='${h.url_for('/static/images/yui/rel_interstitial_loading.gif')}'/>" );
}
@@ -100,8 +110,8 @@
## "<b>Load</b> a stored workflow" : load_workflow
## });
$("#save-button").click( save_current_workflow );
$("#close-button").click( close_editor );
$("#save-button").click( function() { save_current_workflow(); } );
$("#close-button").click( function() { close_editor(); } );
// Unload handler
window.onbeforeunload = function() {
@@ -162,7 +172,7 @@
var x = 5000, y = 5000;
$("div.toolFormInCanvas").each( function() {
x = Math.min( x, $(this).position().left );
y = Math.min( x, $(this).position().left );
y = Math.min( y, $(this).position().top );
});
x = Math.min( - x + 20, 0 );
y = Math.min( - y + 20, 0 );
@@ -176,8 +186,8 @@
workflow.add_node( node );
workflow.activate_node( node );
$.ajax( {
url: "${h.url_for( action='get_tool_info' )}",
data: { tool_id: id, "_": "true" },
url: "${h.url_for( action='get_new_module_info' )}",
data: { type: "tool", tool_id: id, "_": "true" },
global: false,
dataType: "json",
success: function( data ) {
@@ -198,7 +208,7 @@
workflow.add_node( node );
workflow.activate_node( node );
$.ajax( {
url: "${h.url_for( action='get_module_info' )}",
url: "${h.url_for( action='get_new_module_info' )}",
data: { type: type, "_": "true" },
dataType: "json",
success: function( data ) {
@@ -226,7 +236,7 @@
$("#right-content").find( "form" ).ajaxForm( {
type: 'POST',
dataType: 'json',
success: function( data ) {
success: function( data ) {
node.update_field_data( data );
},
beforeSubmit: function( data ) {
@@ -247,21 +257,26 @@
var close_editor = function() {
if ( workflow && workflow.has_changes ) {
do_close = function() {
window.onbeforeunload = undefined;
window.document.location = "${h.url_for( controller='root' )}"
};
show_modal( "Close workflow editor",
"There are unsaved changes to your workflow which will be lost.",
{
"Cancel" : hide_modal,
"Close": function() {
window.onbeforeunload = undefined;
window.document.location = "${h.url_for( controller='root' )}"
"Save Changes" : function() {
save_current_workflow( do_close );
}
}, {
"Don't Save": do_close,
} );
} else {
window.document.location = "${h.url_for( controller='root' )}"
}
}
var save_current_workflow = function () {
var save_current_workflow = function ( success_callback ) {
show_modal( "Saving workflow", "progress" );
$.ajax( {
url: "${h.url_for( action='save_workflow' )}",
@@ -287,13 +302,22 @@
workflow.name = data.name;
workflow.has_changes = false;
workflow.stored = true;
show_modal( "Workflow saved", body, {
"Ok" : function () { hide_modal(); }
});
if ( success_callback ) {
success_callback();
}
hide_modal();
}
});
}
## var update_canvas_map = function() {
## var c = $("#canvas-map-canvas").get(0).getContext("2d");
## var cp = $("#canvas-container").position();
## c.clearRect( 0, 0, 100, 100 );
## c.strokeStyle = "rgb(200,0,0)";
## c.strokeRect ( -cp.left / 50, -cp.top / 50, $("#canvas-viewport").width() / 50, $("#canvas-viewport").height() / 50 );
## }
</script>
</%def>
@@ -485,7 +509,11 @@
<div class="unified-panel-header-inner"><span class='title'>Loading workflow editor...</span></div>
</div>
<div class="body" style="max-height: 500px; overflow: auto;"><img src="${h.url_for('/static/images/yui/rel_interstitial_loading.gif')}" /></div>
<div class="buttons" style="display: none;"></div>
<div>
<div class="buttons" style="display: none; float: right;"></div>
<div class="extra_buttons" style="display: none; padding: 5px;"></div>
<div style="clear: both;"></div>
</div>
</div>
<div class="dialog-box-underlay"></div>
</div>
@@ -576,6 +604,9 @@
<div class="unified-panel-body">
<div id="canvas-viewport" style="width: 100%; height: 100%; position: absolute; overflow: hidden;">
<div id="canvas-container" style="height: 5000px; width: 5000px; background: white url(${h.url_for('/static/images/light_gray_grid.gif')}) repeat;"></div>
## <div id="canvas-map" style="height: 100px; width: 100px; border: solid red 1px; background: white; position: absolute; right: 0; bottom: 0;">
## <canvas width="100" height="100" style="width: 100%; height: 100%" id="canvas-map-canvas"></canvas>
## </div>
</div>
</div>
+2 -1
View File
@@ -32,8 +32,9 @@ from galaxy.tools.parameters import DataToolParameter
<% rep_errors = dict() %>
%endif
<div class="repeat-group-item">
<% index = repeat_values[i]['__index__'] %>
<div class="form-title-row"><b>${input.title} ${i + 1}</b></div>
${do_inputs( input.inputs, repeat_values[ i ], rep_errors, prefix + input.name + "_" + str(i) + "|", step, other_values )}
${do_inputs( input.inputs, repeat_values[ i ], rep_errors, prefix + input.name + "_" + str(index) + "|", step, other_values )}
## <div class="form-row"><input type="submit" name="${step.id}|${prefix}${input.name}_${i}_remove" value="Remove ${input.title} ${i+1}" /></div>
</div>
%endfor