"Input dataset" module now works for running. Many bug fixes to workflows

and tools. Moved some methods related to params out of the Tool class, sets
of inputs can also be used in other ways (e.g. for modules). More abstraction
needed here.
This commit is contained in:
James Taylor
2008-05-09 16:18:38 +00:00
parent bb3cd06be1
commit 8cfa45310e
8 changed files with 282 additions and 258 deletions
+46 -95
View File
@@ -142,7 +142,7 @@ class DefaultToolState( object ):
"""
# Convert parameters to a dictionary of strings, and save curent
# page in that dict
value = tool.params_to_strings( self.inputs, app )
value = params_to_strings( tool.inputs, self.inputs, app )
value["__page__"] = self.page
value = simplejson.dumps( value )
# Make it secure
@@ -161,7 +161,7 @@ class DefaultToolState( object ):
# Restore from string
values = json_fix( simplejson.loads( value ) )
self.page = values.pop( "__page__" )
self.inputs = tool.params_from_strings( values, app, ignore_errors=True )
self.inputs = params_from_strings( tool.inputs, values, app, ignore_errors=True )
class Tool:
"""
@@ -740,6 +740,7 @@ class Tool:
prefix = "%s|" % ( key )
# Deal with the 'test' element and see if it's value changed
test_param_key = prefix + input.test_param.name
test_param_error = None
if test_param_key not in incoming and update_only:
# Update only, keep previous value and state, but still
# recurse in case there are nested changes
@@ -751,7 +752,7 @@ class Tool:
# Get value of test param and determine current case
test_incoming = incoming.get( prefix + input.test_param.name, None )
value, test_param_error = \
self.check_param( trans, input.test_param, test_incoming, context )
check_param( trans, input.test_param, test_incoming, context )
current_case = input.get_current_case( value, trans )
if current_case != old_current_case:
# Current case has changed, throw away old state
@@ -786,74 +787,48 @@ class Tool:
# preserve the old error message.
if input.name in old_errors:
errors[ input.name ] = old_errors[ input.name ]
# SelectToolParameters and DataToolParameters whose options are dynamically
# generated based on the current value of a dependency parameter require special
# handling. When the dependency parameter's value is changed, the form is
# submitted ( due to the refresh_on_change behavior ). When this occurs, the
# "dependent" parameter's value has not been reset ( dynamically generated based
# on the new value of its dependency ) prior to reaching this point, so we need
# to regenerate it before it is validated in check_param().
incoming_value_generated = False
if not( 'runtool_btn' in incoming or 'URL' in incoming ):
# Form must have been refreshed, probably due to a refresh_on_change
try:
if input.is_dynamic:
dependencies = input.get_dependencies()
for dependency_name in dependencies:
dependency_value = changed_dependencies.get( dependency_name, None )
if dependency_value:
# We need to dynamically generate the current input based on
# the changed dependency parameter
changed_params = {}
changed_params[dependency_name] = dependency_value
changed_params[input.name] = input
incoming_value = input.get_initial_value( trans, changed_params )
incoming_value_generated = True
# Delete the dependency_param from chagned_dependencies since its
# dependent param has been generated based its new value.
del changed_dependencies[dependency_name]
break
except:
pass
if not incoming_value_generated:
incoming_value = incoming.get( key, None )
value, error = self.check_param( trans, input, incoming_value, context )
if input.dependent_params and state[ input.name ] != value:
# We need to keep track of changed dependency parametrs ( parameters
# that have dependent parameters whose options are dynamically generated )
changed_dependencies[ input.name ] = value
if error:
errors[ input.name ] = error
state[ input.name ] = value
else:
# SelectToolParameters and DataToolParameters whose options are dynamically
# generated based on the current value of a dependency parameter require special
# handling. When the dependency parameter's value is changed, the form is
# submitted ( due to the refresh_on_change behavior ). When this occurs, the
# "dependent" parameter's value has not been reset ( dynamically generated based
# on the new value of its dependency ) prior to reaching this point, so we need
# to regenerate it before it is validated in check_param().
incoming_value_generated = False
if not( 'runtool_btn' in incoming or 'URL' in incoming ):
# Form must have been refreshed, probably due to a refresh_on_change
try:
if input.is_dynamic:
dependencies = input.get_dependencies()
for dependency_name in dependencies:
dependency_value = changed_dependencies.get( dependency_name, None )
if dependency_value:
# We need to dynamically generate the current input based on
# the changed dependency parameter
changed_params = {}
changed_params[dependency_name] = dependency_value
changed_params[input.name] = input
incoming_value = input.get_initial_value( trans, changed_params )
incoming_value_generated = True
# Delete the dependency_param from chagned_dependencies since its
# dependent param has been generated based its new value.
del changed_dependencies[dependency_name]
break
except:
pass
if not incoming_value_generated:
incoming_value = incoming.get( key, None )
value, error = check_param( trans, input, incoming_value, context )
if input.dependent_params and state[ input.name ] != value:
# We need to keep track of changed dependency parametrs ( parameters
# that have dependent parameters whose options are dynamically generated )
changed_dependencies[ input.name ] = value
if error:
errors[ input.name ] = error
state[ input.name ] = value
return errors
def check_param( self, trans, param, incoming_value, param_values ):
"""
Check the value of a single parameter `param`. The value in
`incoming_value` is converted from its HTML encoding and validated.
The `param_values` argument contains the processed values of
previous parameters (this may actually be an ExpressionContext
when dealing with grouping scenarios).
"""
value = incoming_value
error = None
try:
if param.name == 'file_data':
pass
elif value is not None or isinstance(param, DataToolParameter):
# Convert value from HTML representation
value = param.from_html( value, trans, param_values )
# Allow the value to be converted if neccesary
filtered_value = param.filter_value( value, trans, param_values )
# Then do any further validation on the value
param.validate( filtered_value, trans.history )
elif value is None and isinstance( param, SelectToolParameter ):
# An empty select list or column list
param.validate( value, trans.history )
except ValueError, e:
error = str( e )
return value, error
def get_static_param_values( self, trans ):
"""
Returns a map of parameter names and values if the tool does not
@@ -880,34 +855,10 @@ class Tool:
return self.tool_action.execute( self, trans, incoming )
def params_to_strings( self, params, app ):
"""
Convert a dictionary of parameter values to a dictionary of strings
suitable for persisting. The `value_to_basic` method of each parameter
is called to convert its value to basic types, the result of which
is then json encoded (this allowing complex nested parameters and
such).
"""
rval = dict()
for key, value in params.iteritems():
if key in self.inputs:
value = self.inputs[ key ].value_to_basic( value, app )
rval[ key ] = str( simplejson.dumps( value ) )
return rval
return params_to_strings( self.inputs, params, app )
def params_from_strings( self, params, app, ignore_errors=False ):
"""
Convert a dictionary of strings as produced by `params_to_strings`
back into parameter values (decode the json representation and then
allow each parameter to convert the basic types into the parameters
preferred form).
"""
rval = dict()
for key, value in params.iteritems():
value = json_fix( simplejson.loads( value ) )
if key in self.inputs:
value = self.inputs[key].value_from_basic( value, app, ignore_errors )
rval[ key ] = value
return rval
return params_from_strings( self.inputs, params, app, ignore_errors )
def handle_unvalidated_param_values( self, input_values, app ):
"""
+59 -1
View File
@@ -2,4 +2,62 @@
Classes encapsulating Galaxy tool parameters.
"""
from basic import *
from basic import *
from galaxy.util.json import *
def check_param( trans, param, incoming_value, param_values ):
"""
Check the value of a single parameter `param`. The value in
`incoming_value` is converted from its HTML encoding and validated.
The `param_values` argument contains the processed values of
previous parameters (this may actually be an ExpressionContext
when dealing with grouping scenarios).
"""
value = incoming_value
error = None
try:
if param.name == 'file_data':
pass
elif value is not None or isinstance(param, DataToolParameter):
# Convert value from HTML representation
value = param.from_html( value, trans, param_values )
# Allow the value to be converted if neccesary
filtered_value = param.filter_value( value, trans, param_values )
# Then do any further validation on the value
param.validate( filtered_value, trans.history )
elif value is None and isinstance( param, SelectToolParameter ):
# An empty select list or column list
param.validate( value, trans.history )
except ValueError, e:
error = str( e )
return value, error
def params_to_strings( params, param_values, app ):
"""
Convert a dictionary of parameter values to a dictionary of strings
suitable for persisting. The `value_to_basic` method of each parameter
is called to convert its value to basic types, the result of which
is then json encoded (this allowing complex nested parameters and
such).
"""
rval = dict()
for key, value in param_values.iteritems():
if key in params:
value = params[ key ].value_to_basic( value, app )
rval[ key ] = str( to_json_string( value ) )
return rval
def params_from_strings( params, param_values, app, ignore_errors=False ):
"""
Convert a dictionary of strings as produced by `params_to_strings`
back into parameter values (decode the json representation and then
allow each parameter to convert the basic types into the parameters
preferred form).
"""
rval = dict()
for key, value in param_values.iteritems():
value = json_fix( from_json_string( value ) )
if key in params:
value = params[key].value_from_basic( value, app, ignore_errors )
rval[ key ] = value
return rval
+20
View File
@@ -0,0 +1,20 @@
__all__ = [ "to_json_string", "from_json_string", "json_fix"]
import pkg_resources
pkg_resources.require( "simplejson" )
import simplejson
to_json_string = simplejson.dumps
from_json_string = simplejson.loads
def json_fix( val ):
if isinstance( val, list ):
return [ json_fix( v ) for v in val ]
elif isinstance( val, dict ):
return dict( [ ( json_fix( k ), json_fix( v ) ) for ( k, v ) in val.iteritems() ] )
elif isinstance( val, unicode ):
return val.encode( "utf8" )
else:
return val
+109 -38
View File
@@ -2,11 +2,12 @@ from galaxy.web.base.controller import *
import simplejson
from galaxy.tools.parameters import DataToolParameter
from galaxy.tools.parameters import DataToolParameter, check_param
from galaxy.tools import DefaultToolState
from galaxy.tools.parameters.grouping import Repeat, Conditional
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
class WorkflowController( BaseController ):
@@ -60,7 +61,6 @@ class WorkflowController( BaseController ):
# Display the management page
return self.index( trans )
@web.expose
@web.require_login( "edit workflows" )
def editor( self, trans, id=None ):
@@ -131,9 +131,11 @@ class WorkflowController( BaseController ):
rval['name'] = module.name
rval['type'] = module.type
rval['tool_state'] = state = module.get_state()
rval['data_inputs'] = module.get_data_inputs( state )
rval['data_outputs'] = module.get_data_outputs( state )
rval['form_html'] = module.get_config_form_html( trans, 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
@web.json
@@ -184,9 +186,11 @@ class WorkflowController( BaseController ):
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( state )
step_dict['data_outputs'] = module.get_data_outputs( state )
step_dict['form_html'] = module.get_config_form_html( trans, 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() )
# Connections
input_conn_dict = {}
for conn in step.input_connections:
@@ -319,9 +323,12 @@ class WorkflowController( BaseController ):
if type( job_ids ) == str:
job_ids = [ job_ids ]
job_ids = [ int( id ) for id in job_ids ]
if type( dataset_ids ) == str:
dataset_ids = [ job_ids ]
dataset_ids = [ int( id ) for id in dataset_ids ]
if dataset_ids:
if type( dataset_ids ) == str:
dataset_ids = [ job_ids ]
dataset_ids = [ int( id ) for id in dataset_ids ]
else:
dataset_ids = []
# Find each job, for security we (implicately) check that they are
# associated witha job in the current history.
jobs, warnings = get_job_dict( trans )
@@ -335,7 +342,6 @@ class WorkflowController( BaseController ):
step.type = 'data_input'
hid_to_output_pair[ hid ] = ( step, 'output' )
steps.append( step )
print hid_to_output_pair
# Tool steps
for job_id in job_ids:
assert job_id in jobs_by_id, "Attempt to create workflow with job not connected to current history"
@@ -344,6 +350,7 @@ class WorkflowController( BaseController ):
param_values = job.get_param_values( trans.app )
associations = cleanup_param_values( tool.inputs, param_values )
step = model.WorkflowStep()
step.type = 'tool'
step.tool_id = job.tool_id
step.tool_inputs = tool.params_to_strings( param_values, trans.app )
# NOTE: We shouldn't need to do two passes here since only
@@ -363,7 +370,6 @@ class WorkflowController( BaseController ):
# Store created dataset hids
for assoc in job.output_datasets:
hid_to_output_pair[ assoc.dataset.hid ] = ( step, assoc.name )
print hid_to_output_pair
# Workflow to populate
workflow = model.Workflow()
workflow.name = workflow_name
@@ -418,54 +424,82 @@ class WorkflowController( BaseController ):
p = "%s|" % step.id
l = len(p)
step_args = dict( ( k[l:], v ) for ( k, v ) in kwargs.iteritems() if k.startswith( p ) )
if step.type == 'tool':
step_errors = None
if step.type == 'tool' or step.type is None:
# Get the tool
tool = trans.app.toolbox.tools_by_id[ step.tool_id ]
# Get the state
state = DefaultToolState()
state.decode( step_args.pop("tool_state"), tool, trans.app )
step.state = state
# Connections by input name
step.input_connections_by_name = dict( ( conn.input_name, conn ) for conn in step.input_connections )
# Get old errors
old_errors = state.inputs.pop( "__errors__", {} )
# Update the state
step_errors = tool.update_state( trans, tool.inputs, step.state.inputs, step_args,
update_only=True, old_errors=old_errors )
if step_errors:
errors[step.id] = state.inputs["__errors__"] = step_errors
else:
return error( "Modules not yet supported for running" )
module = step.module = WorkflowModule.from_workflow_step( 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:
errors[step.id] = state.inputs["__errors__"] = step_errors
# Connections by input name
step.input_connections_by_name = dict( ( conn.input_name, conn ) for conn in step.input_connections )
if not errors:
# Run each step, connecting outputs to inputs
outputs = {}
for step in workflow.steps:
tool = trans.app.toolbox.tools_by_id[ step.tool_id ]
inputs = step.state.inputs
# Connect up
for conn in step.input_connections:
inputs[ conn.input_name ] = outputs[ conn.output_step.id ][ conn.output_name ]
outputs[ step.id ] = tool.execute( trans, step.state.inputs )
if step.type == 'tool' or step.type is None:
tool = trans.app.toolbox.tools_by_id[ step.tool_id ]
input_values = step.state.inputs
# Connect up
# TODO: Generalize out visitor
def visitor( inputs, input_values, prefix ):
for input in inputs.itervalues():
if isinstance( input, Repeat ):
for i, d in enumerate( input_values[ input.name ] ):
index = d['__index__']
new_prefix = prefix + "%s_%d|" % ( input.name, index )
visitor( input.inputs, d, new_prefix)
elif isinstance( input, Conditional ):
values = input_values[ input.name ]
current = values["__current_case__"]
label_prefix = label_prefix
prefix = prefix + "|" + input.name
visitor( input.cases[current].inputs, values, prefix )
else:
if isinstance( input, DataToolParameter ):
prefixed_name = prefix + input.name
if prefixed_name in step.input_connections_by_name:
conn = step.input_connections_by_name[ prefixed_name ]
input_values[ input.name ] = outputs[ conn.output_step.id ][ conn.output_name ]
visitor( tool.inputs, input_values, "" )
# Execute it
outputs[ step.id ] = tool.execute( trans, step.state.inputs )
else:
outputs[ step.id ] = step.module.execute( trans, step.state )
return trans.fill_template( "workflow/run_complete.mako",
workflow=stored,
outputs=outputs )
else:
for step in workflow.steps:
if step.type == 'tool':
if step.type == 'tool' or step.type is None:
# Build a new tool state for the step
tool = trans.app.toolbox.tools_by_id[ step.tool_id ]
state = DefaultToolState()
state.inputs = tool.params_from_strings( step.tool_inputs, trans.app )
# Store state with the step
step.state = state
# Connections by input name
step.input_connections_by_name = dict( ( conn.input_name, conn ) for conn in step.input_connections )
# This should never actually happen since we don't allow
# running workflows with errors (yet?)
if step.tool_errors:
errors[step.id] = step.tool_errors
else:
return error( "Modules not yet supported for running" )
## Non-tool specific stuff?
step.module = WorkflowModule.from_workflow_step( 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 )
# Render the form
return trans.fill_template(
"workflow/run.mako",
@@ -475,29 +509,66 @@ class WorkflowController( BaseController ):
## ---- Workflow modules (to be factored out) ---------------------------------
from elementtree.ElementTree import Element
## TODO: 'Tool' should be a module rather than a special case
class InputDataModule( object ):
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, state ):
def from_workflow_step( cls, step ):
return cls()
def get_state( self ):
return None
def get_data_inputs( self, state ):
return []
def get_data_outputs( self, state ):
return [ dict( name='output', extension='input' ) ]
def get_config_form_html( self, trans, state ):
form = web.FormBuilder( title=self.name )
return trans.fill_template( "workflow/editor_generic_form.mako", form=form )
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 -------------------------------------------------------
@@ -257,7 +257,9 @@ $.extend( Node.prototype, {
},
init_field_data : function ( data ) {
var f = this.element;
this.type = data.type
if ( data.type ) {
this.type = data.type;
}
this.form_html = data.form_html;
this.tool_state = data.tool_state;
this.tool_errors = data.tool_errors;
@@ -281,7 +283,11 @@ $.extend( Node.prototype, {
$.each( data.data_outputs, function( i, output ) {
var t = $( "<div class='terminal output-terminal'></div>" );
node.enable_output_terminal( t, output.name, output.extension );
b.append( $("<div class='form-row dataRow'>" + output.name + "</div>" ).append( t ) );
var label = output.name
if ( output.extension != 'input' ) {
label = label + " (" + output.extension + ")";
}
b.append( $("<div class='form-row dataRow'>" + label + "</div>" ).append( t ) );
});
workflow.node_changed( this );
},
+16 -109
View File
@@ -7,8 +7,8 @@
<script type='text/javascript' src="/static/scripts/galaxy.panels.js"> </script>
<script type="text/javascript">
ensure_dd_helper();
var lp = make_left_panel( $("#left"), $("#center"), $("#left-border" ) );
var rp = make_right_panel( $("#right"), $("#center"), $("#right-border" ) );
make_left_panel( $("#left"), $("#center"), $("#left-border" ) );
make_right_panel( $("#right"), $("#center"), $("#right-border" ) );
## handle_minwidth_hint = rp.handle_minwidth_hint;
</script>
</%def>
@@ -20,6 +20,7 @@
<script type='text/javascript' src="/static/scripts/jquery.js"> </script>
<script type='text/javascript' src="/static/scripts/jquery.dimensions.js"> </script>
<script type='text/javascript' src="/static/scripts/jquery.ui.js"> </script>
<script type='text/javascript' src="/static/scripts/galaxy.ui.scrollPanel.js"> </script>
<script type='text/javascript' src="/static/scripts/jquery.hoverIntent.js"> </script>
<script type='text/javascript' src="/static/scripts/jquery.form.js"> </script>
<script type='text/javascript' src="/static/scripts/jquery.json.js"> </script>
@@ -73,7 +74,7 @@
// Load workflow definition
$.ajax( {
url: "${h.url_for( action='load_workflow' )}",
data: { id: "${trans.security.encode_id( workflow_id )}" },
data: { id: "${trans.security.encode_id( workflow_id )}", "_": "true" },
dataType: 'json',
success: function( data ) {
reset();
@@ -147,66 +148,6 @@
}
});
});
// Scrolling
$.ui.plugin.add("draggable", "scrollPanel", {
drag: function(e, ui) {
var o = ui.options,
i = ui.instance,
panel = o.panel,
panel_pos = panel.position(),
viewport = panel.parent();
moved = false;
nudge = 23;
// Legal panel range
var p_min_x = - ( panel.width() - viewport.width() ),
p_min_y = - ( panel.height() - viewport.height() ),
p_max_x = 0,
p_max_y = 0;
var min_vis_x = - panel_pos.left,
max_vis_x = min_vis_x + viewport.width(),
min_vis_y = - panel_pos.top,
max_vis_y = min_vis_y + viewport.height();
// Move it
if ( ( panel_pos.left < p_max_x ) && ( ui.position.left < min_vis_x ) ) {
var t = Math.min( nudge, p_max_x - panel_pos.left );
panel.css( "left", panel_pos.left + t );
moved = true;
ui.instance.offset.left += t;
ui.position.left = min_vis_x - t
}
if ( ( panel_pos.left > p_min_x ) && ( ( ui.position.left + ui.element.width() ) > max_vis_x ) ) {
var t = Math.min( nudge, panel_pos.left - p_min_x );
panel.css( "left", panel_pos.left - t );
moved = true;
ui.instance.offset.left -= t
ui.position.left = max_vis_x + t - ui.element.width();
}
if ( ( panel_pos.top < p_max_y ) && ( ui.position.top < min_vis_y ) ) {
var t = Math.min( nudge, p_max_y - panel_pos.top );
panel.css( "top", panel_pos.top + t );
moved = true;
ui.instance.offset.top += t;
ui.position.top = min_vis_y - t;
}
if ( ( panel_pos.top > p_min_y ) && ( ( ui.position.top + ui.element.height() ) > max_vis_y ) ) {
var t = Math.min( nudge, panel_pos.top - p_min_x );
panel.css( "top", panel_pos.top - t );
moved = true;
ui.instance.offset.top -= t
ui.position.top = max_vis_y + t - ui.element.height();
}
// Update offsets
if ( moved ) {
$.ui.ddmanager.prepareOffsets( ui.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.width() - ui.element.width() );
ui.position.top = Math.min( ui.position.top, panel.height() - ui.element.height() );
}
});
});
var workflow = null;
@@ -226,8 +167,10 @@
$("div.toolFormInCanvas").each( function() {
x = Math.min( x, $(this).position().left );
y = Math.min( x, $(this).position().left );
});
$("#canvas-container").css( { left: - x + 20, top: - y + 20 } );
});
x = Math.min( - x + 20, 0 );
y = Math.min( - y + 20, 0 );
$("#canvas-container").css( { left: x, top: y } );
}
}
@@ -238,7 +181,8 @@
workflow.activate_node( node );
$.ajax( {
url: "${h.url_for( action='get_tool_info' )}",
data: { tool_id: id, "_": "true" },
data: { tool_id: id, "_": "true" },
global: false,
dataType: "json",
success: function( data ) {
node.init_field_data( data );
@@ -292,6 +236,10 @@
beforeSubmit: function( data ) {
data.push( { name: 'tool_state', value: node.tool_state } );
data.push( { name: '_', value: "true" } );
$("#tool-form-save-button").each( function() {
this.value = "Saving...";
this.disabled = true;
});
}
}).each( function() {
form = this;
@@ -324,7 +272,8 @@
type: "POST",
data: {
id: "${trans.security.encode_id( workflow_id )}",
workflow_data: $.toJSON( workflow.to_simple() )
workflow_data: $.toJSON( workflow.to_simple() ),
"_": "true"
},
dataType: 'json',
success: function( data ) {
@@ -349,48 +298,6 @@
});
}
var load_workflow = function () {
var body = $("#load-dialog-form").clone();
var form = body.find( "form" ).ajaxForm( {
dataType: 'json',
success: function( data ) {
reset();
workflow.from_simple( data );
workflow.has_changes = false;
show_modal( "Workflow loaded", "Workflow loaded.", {
"Ok" : function () { hide_modal(); }
});
},
beforeSubmit: function( data ) {
show_modal( "Loading workflow", "progress" );
}
});
if ( workflow.has_changes ) {
body.prepend( "<div class='warningmark'>Your unsaved changes will be lost!</div>" );
}
show_modal( "Load workflow", body, {
"Cancel" : hide_modal,
"Load": function() { form.submit() }
} );
}
var clear_workflow = function () {
reset();
hide_modal();
}
var create_new_workflow_dialog = function () {
if ( workflow.has_changes ) {
show_modal( "Create new workflow",
"Your workflow has unsaved changes which will be lost", {
"Cancel" : hide_modal,
"Continue": clear_workflow
});
} else {
clear_workflow();
}
}
</script>
</%def>
+1 -1
View File
@@ -65,7 +65,7 @@
${do_inputs( inputs, values, errors, "" )}
%endfor
<div class="form-row">
<input type="submit" value="Save"></input>
<input type="submit" id="tool-form-save-button" value="Save"></input>
</div>
</form>
</div>
+23 -12
View File
@@ -31,10 +31,10 @@ from galaxy.tools.parameters import DataToolParameter
<div class="repeat-group-item">
<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 )}
<div class="form-row"><input type="submit" name="${step.id}|${prefix}${input.name}_${i}_remove" value="Remove ${input.title} ${i+1}" /></div>
</div>
## <div class="form-row"><input type="submit" name="${step.id}|${prefix}${input.name}_${i}_remove" value="Remove ${input.title} ${i+1}" /></div>
</div>
%endfor
<div class="form-row"><input type="submit" name="${step.id}|${prefix}${input.name}_add" value="Add new ${input.title}" /></div>
## <div class="form-row"><input type="submit" name="${step.id}|${prefix}${input.name}_add" value="Add new ${input.title}" /></div>
</div>
%elif input.type == "conditional":
<% group_values = values[input.name] %>
@@ -50,6 +50,7 @@ from galaxy.tools.parameters import DataToolParameter
</%def>
<%def name="row_for_param( param, value, error_dict, prefix, step )">
## -- ${param.name} -- ${step.state.inputs} --
%if error_dict.has_key( param.name ):
<% cls = "form-row form-row-error" %>
%else:
@@ -86,15 +87,25 @@ from galaxy.tools.parameters import DataToolParameter
## <input type="hidden" name="workflow_name" value="${workflow.name | h}" />
<input type="submit" value="Run workflow" />
%for i, step in enumerate( steps ):
<% tool = app.toolbox.tools_by_id[step.tool_id] %>
<input type="hidden" name="${step.id}|tool_state" value="${step.state.encode( tool, app )}">
<div class="toolForm">
<div class="toolFormTitle">Step ${int(step.order_index)+1}: ${tool.name}</div>
<div class="toolFormBody">
${do_inputs( tool.inputs, step.state.inputs, errors.get( step.id, dict() ), "", step )}
</div>
</div>
%if step.type == 'tool' or step.type is None:
<% tool = app.toolbox.tools_by_id[step.tool_id] %>
<input type="hidden" name="${step.id}|tool_state" value="${step.state.encode( tool, app )}">
<div class="toolForm">
<div class="toolFormTitle">Step ${int(step.order_index)+1}: ${tool.name}</div>
<div class="toolFormBody">
${do_inputs( tool.inputs, step.state.inputs, errors.get( step.id, dict() ), "", step )}
</div>
</div>
%else:
<% module = step.module %>
<input type="hidden" name="${step.id}|tool_state" value="${module.encode_runtime_state( t, step.state )}">
<div class="toolForm">
<div class="toolFormTitle">Step ${int(step.order_index)+1}: ${module.name}</div>
<div class="toolFormBody">
${do_inputs( module.get_runtime_inputs(), step.state.inputs, errors.get( step.id, dict() ), "", step )}
</div>
</div>
%endif
%endfor
</form>
</body>