Merge with cde78bdeaca823b011477498a4dfd1466d20c0c0

This commit is contained in:
Ramkrishna Chakrabarty
2010-06-11 10:20:24 -04:00
10 changed files with 460 additions and 21 deletions
+4
View File
@@ -0,0 +1,4 @@
"""
This package contains job action classes.
"""
+196
View File
@@ -0,0 +1,196 @@
import logging, threading, time
from Queue import Queue, Empty
from galaxy.util.json import from_json_string, to_json_string
from galaxy.web.form_builder import *
log = logging.getLogger( __name__ )
# DBTODO This still needs refactoring and general cleanup.
class DefaultJobAction(object):
name = "DefaultJobAction"
@classmethod
def execute(cls, job):
pass
@classmethod
def get_config_form(cls, trans):
return "<p>Default Job Action Config Form</p>"
@classmethod
def get_short_str(cls, pja):
if pja.action_arguments:
return "%s -> %s" % (pja.action_type, pja.action_arguments)
else:
return "%s" % pja.action_type
class ChangeDatatypeAction(DefaultJobAction):
name = "ChangeDatatypeAction"
@classmethod
def execute(cls, trans, action, job):
for dataset_assoc in job.output_datasets:
if action.output_name == '' or dataset_assoc.name == action.output_name:
trans.app.datatypes_registry.change_datatype( dataset_assoc.dataset, action.action_arguments['newtype'])
@classmethod
def get_config_form(cls, trans):
dt_list = ""
dtnames = [ dtype_name for dtype_name, dtype_value in trans.app.datatypes_registry.datatypes_by_extension.iteritems()]
dtnames.sort()
for dt_name in dtnames:
dt_list += """<option id='pja__"+pja.output_name+"__ChangeDatatypeAction__newtype__%s' value='%s'>%s</option>""" % (dt_name, dt_name, dt_name)
ps = """
if (pja.action_type == "ChangeDatatypeAction"){
p_str = "<div class='pjaForm toolForm'><span class='action_tag' style='display:none'>"+ pja.action_type + pja.output_name + "</span><div class='toolFormTitle'>" + pja.action_type + " <br/> on " + pja.output_name + "\
<div style='float: right;' class='buttons'><img src='../images/delete_icon.png'></div></div>\
<div class='toolFormBody'><label for='pja__"+pja.output_name+"__ChangeDatatypeAction__newtype'>New Datatype:</label><select id='pja__"+pja.output_name+"__ChangeDatatypeAction__newtype' name='pja__"+pja.output_name+"__ChangeDatatypeAction__newtype'>\
%s\
</select>";
if (pja.action_arguments != undefined && pja.action_arguments.newtype != undefined){
p_str += "<scrip" + "t type='text/javascript'>$('#pja__" + pja.output_name + "__ChangeDatatypeAction__newtype').val('" + pja.action_arguments.newtype + "');</scrip" + "t>"
}
p_str += "</div><div class='toolParamHelp'>This action will change the datatype of the output to the indicated value.</div></div>";
}
""" % dt_list
# Note the scrip + t hack above. Is there a better way?
return ps
class RenameDatasetAction(DefaultJobAction):
name = "RenameDatasetAction"
@classmethod
def execute(cls, trans, action, job):
for dataset_assoc in job.output_datasets:
if action.output_name == '' or dataset_assoc.name == action.output_name:
dataset_assoc.dataset.name = action.action_arguments['newname']
@classmethod
def get_config_form(cls, trans):
return """
if (pja.action_type == "RenameDatasetAction"){
p_str = "<div class='pjaForm toolForm'><span class='action_tag' style='display:none'>"+ pja.action_type + pja.output_name + "</span><div class='toolFormTitle'>"+ pja.action_type + " <br/> on " + pja.output_name + "\
<div style='float: right;' class='buttons'><img src='../images/delete_icon.png'></div></div><div class='toolFormBody'>";
if ((pja.action_arguments != undefined) && (pja.action_arguments.newname != undefined)){
p_str += "<label for='pja__"+pja.output_name+"__RenameDatasetAction__newname'>New output name:</label><input type='text' name='pja__"+pja.output_name+"__RenameDatasetAction__newname' value='"+pja.action_arguments.newname + "'/>";
}
else{
p_str += "<label for='pja__"+pja.output_name+"__RenameDatasetAction__newname'>New output name:</label><input type='text' name='pja__"+pja.output_name+"__RenameDatasetAction__newname' value='New Name'/>";
}
p_str += "</div><div class='toolParamHelp'>This action will rename the result dataset.</div></div>";
}
"""
class HideDatasetAction(DefaultJobAction):
name = "HideDatasetAction"
@classmethod
def execute(cls, trans, action, job):
for dataset_assoc in job.output_datasets:
if action.output_name == '' or dataset_assoc.name == action.output_name:
dataset_assoc.dataset.visible=False
@classmethod
def get_config_form(cls, trans):
return """
if (pja.action_type == "HideDatasetAction"){
p_str = "<div class='pjaForm toolForm'><span class='action_tag' style='display:none'>"+ pja.action_type + pja.output_name + "</span><div class='toolFormTitle'>"+ pja.action_type + " <br/> on " + pja.output_name + "\
<div style='float: right;' class='buttons'><img src='../images/delete_icon.png'></div></div><div class='toolFormBody'>";
p_str += "<label for='pja__"+pja.output_name+"__HideDatasetAction'>There are no additional options for this action.</label><input type='hidden' name='pja__"+pja.output_name+"__HideDatasetAction'/>";
p_str += "</div><div class='toolParamHelp'>This action will *hide* the result dataset from your history.</div></div>";
}
"""
class SetMetadataAction(DefaultJobAction):
name = "SetMetadataAction"
# DBTODO Setting of Metadata is currently broken and disabled. It should not be used (yet).
@classmethod
def execute(cls, trans, action, job):
for data in self.job.output_datasets:
data.set_metadata( action.action_arguments['newtype'] )
@classmethod
def get_config_form(cls, trans):
dt_list = ""
mdict = {}
for dtype_name, dtype_value in trans.app.datatypes_registry.datatypes_by_extension.iteritems():
for mn, mt in dtype_value.metadata_spec.items():
if mt.visible:
mdict[mt.desc] = mt.param.get_html(value= mn).replace('"', "'").strip().replace('\n','')
for k, v in mdict.items():
dt_list += "<p><strong>" + k + ":</strong><br/>" + v + "</p>"
return """
if (pja.action_type == "SetMetadataAction"){
p_str = "<div class='pjaForm toolForm'><span class='action_tag' style='display:none'>"+ pja.action_type + pja.output_name + "</span><div class='toolFormTitle'>"+ pja.action_type + " <br/> on " + pja.output_name + "\
<div style='float: right;' class='buttons'><img src='../images/delete_icon.png'></div></div>\
<div class='toolFormBody'>\
%s\
</div><div class='toolParamHelp'>This tool sets metadata in output.</div></div>";
}
""" % dt_list
ACTIONS = { "RenameDatasetAction" : RenameDatasetAction,
"HideDatasetAction" : HideDatasetAction,
"ChangeDatatypeAction": ChangeDatatypeAction,
# "SetMetadataAction" : SetMetadataAction,
}
class ActionBox(object):
@classmethod
def execute(cls, action, job):
if action.action_type in ACTIONS:
ACTIONS[action.action_type].execute(action, job, trans)
else:
return False
@classmethod
def get_short_str(cls, action):
if action.action_type in ACTIONS:
return ACTIONS[action.action_type].get_short_str(action)
else:
return "Unknown PostJobAction"
@classmethod
def handle_incoming(cls, incoming):
npd = {}
for key, val in incoming.iteritems():
if key.startswith('pja'):
sp = key.split('__')
# flag / output_name / pjatype / desc
if not sp[2] in npd:
npd[sp[2]] = {'action_type' : sp[2],
'output_name' : sp[1],
'action_arguments' : {}}
if len(sp) > 3:
if sp[3] == 'output_name':
npd[sp[2]]['output_name'] = val
else:
npd[sp[2]]['action_arguments'][sp[3]] = val
else:
# Not pja stuff.
pass
return to_json_string(npd)
@classmethod
def get_add_list(cls):
addlist = "<select id='new_pja_list' name='new_pja_list'>"
for action in ACTIONS:
addlist += "<option value='%s'>%s</option>" % (ACTIONS[action].name, ACTIONS[action].name)
addlist += "</select>"
return addlist
@classmethod
def get_forms(cls, trans):
forms = ""
for action in ACTIONS:
forms += ACTIONS[action].get_config_form(trans)
return forms
@classmethod
def execute(cls, trans, pja, job):
ACTIONS[pja.action_type].execute(trans, pja, job)
+9
View File
@@ -113,6 +113,8 @@ class Job( object ):
self.info = None
self.job_runner_name = None
self.job_runner_external_id = None
self.post_job_actions = None
def add_parameter( self, name, value ):
self.parameters.append( JobParameter( name, value ) )
def add_input_dataset( self, name, dataset ):
@@ -184,6 +186,13 @@ class JobToOutputLibraryDatasetAssociation( object ):
self.name = name
self.dataset = dataset
class PostJobAction( object ):
def __init__( self, action_type, workflow_step, output_name = None, action_arguments = None):
self.action_type = action_type
self.output_name = output_name
self.action_arguments = action_arguments
self.workflow_step = workflow_step
class JobExternalOutputMetadata( object ):
def __init__( self, job = None, dataset = None ):
self.job = job
+11 -1
View File
@@ -369,6 +369,13 @@ JobExternalOutputMetadata.table = Table( "job_external_output_metadata", metadat
Column( "filename_override_metadata", String( 255 ) ),
Column( "job_runner_external_pid", String( 255 ) ) )
PostJobAction.table = Table("post_job_action", metadata,
Column("id", Integer, primary_key=True),
Column("workflow_step_id", Integer, ForeignKey( "workflow_step.id" ), index=True, nullable=False),
Column("action_type", String(255), nullable=False),
Column("output_name", String(255), nullable=True),
Column("action_arguments", JSONType, nullable=True))
Event.table = Table( "event", metadata,
Column( "id", Integer, primary_key=True ),
Column( "create_time", DateTime, default=now ),
@@ -1237,6 +1244,9 @@ assign_mapper( context, JobExternalOutputMetadata, JobExternalOutputMetadata.tab
history_dataset_association = relation( HistoryDatasetAssociation, lazy = False ),
library_dataset_dataset_association = relation( LibraryDatasetDatasetAssociation, lazy = False ) ) )
assign_mapper( context, PostJobAction, PostJobAction.table,
properties=dict(workflow_step = relation( WorkflowStep, backref='post_job_actions', primaryjoin=(WorkflowStep.table.c.id == PostJobAction.table.c.workflow_step_id))))
assign_mapper( context, Job, Job.table,
properties=dict( galaxy_session=relation( GalaxySession ),
history=relation( History ),
@@ -1309,7 +1319,7 @@ assign_mapper( context, Workflow, Workflow.table,
assign_mapper( context, WorkflowStep, WorkflowStep.table,
properties=dict(
tags=relation(WorkflowStepTagAssociation, order_by=WorkflowStepTagAssociation.table.c.id, backref="workflow_steps"),
annotations=relation( WorkflowStepAnnotationAssociation, order_by=WorkflowStepAnnotationAssociation.table.c.id, backref="workflow_steps" ) )
annotations=relation( WorkflowStepAnnotationAssociation, order_by=WorkflowStepAnnotationAssociation.table.c.id, backref="workflow_steps" ) )
)
assign_mapper( context, WorkflowStepConnection, WorkflowStepConnection.table,
@@ -0,0 +1,49 @@
"""
Migration script to create tables for handling post-job actions.
"""
from sqlalchemy import *
from sqlalchemy.orm import *
from migrate import *
from migrate.changeset import *
import logging
logging.basicConfig( level=logging.DEBUG )
log = logging.getLogger( __name__ )
# Need our custom types, but don't import anything else from model
from galaxy.model.custom_types import *
import datetime
now = datetime.datetime.utcnow
metadata = MetaData( migrate_engine )
db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) )
PostJobAction_table = Table("post_job_action", metadata,
Column("id", Integer, primary_key=True),
Column("workflow_step_id", Integer, ForeignKey( "workflow_step.id" ), index=True, nullable=False),
Column("action_type", String(255), nullable=False),
Column("output_name", String(255), nullable=True),
Column("action_arguments", JSONType, nullable=True))
# PostJobActionAssociation_table = Table("post_job_action_association", metadata,
# Column("id", Integer, primary_key=True),
# Column("post_job_action_id", Integer, ForeignKey("post_job_action.id"), index=True, nullable=False),
# Column("job_id", Integer, ForeignKey("job.id"), index=True, nullable=False))
tables = [PostJobAction_table]#, PostJobActionAssociation_table]
def upgrade():
print __doc__
metadata.reflect()
for table in tables:
try:
table.create()
except:
log.warn( "Failed to create table '%s', ignoring (might result in wrong schema)" % table.name )
def downgrade():
metadata.reflect()
for table in tables:
table.drop()
+34 -12
View File
@@ -17,6 +17,7 @@ from galaxy.workflow.modules import *
from galaxy import model
from galaxy.model.mapping import desc
from galaxy.model.orm import *
from galaxy.jobs.actions.post import *
import urllib2
@@ -387,7 +388,6 @@ class WorkflowController( BaseController, Sharable, UsesStoredWorkflow, UsesAnno
else:
stored.importable = importable
trans.sa_session.flush()
return
@web.expose
@@ -514,6 +514,7 @@ class WorkflowController( BaseController, Sharable, UsesStoredWorkflow, UsesAnno
This is used for the form shown in the right pane when a node
is selected.
"""
trans.workflow_building_mode = True
module = module_factory.from_dict( trans, {
'type': type,
@@ -521,14 +522,26 @@ class WorkflowController( BaseController, Sharable, UsesStoredWorkflow, UsesAnno
'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(),
'tool_errors': module.get_errors(),
'form_html': module.get_config_form(),
'annotation': annotation
}
if type=='tool':
return {
'tool_state': module.get_state(),
'data_inputs': module.get_data_inputs(),
'data_outputs': module.get_data_outputs(),
'tool_errors': module.get_errors(),
'form_html': module.get_config_form(),
'annotation': annotation,
'post_job_actions': module.get_post_job_actions()
}
else:
return {
'tool_state': module.get_state(),
'data_inputs': module.get_data_inputs(),
'data_outputs': module.get_data_outputs(),
'tool_errors': module.get_errors(),
'form_html': module.get_config_form(),
'annotation': annotation
}
@web.json
def get_new_module_info( self, trans, type, **kwargs ):
@@ -552,7 +565,7 @@ class WorkflowController( BaseController, Sharable, UsesStoredWorkflow, UsesAnno
'form_html': module.get_config_form(),
'annotation': ""
}
@web.json
def load_workflow( self, trans, id ):
"""
@@ -613,6 +626,13 @@ class WorkflowController( BaseController, Sharable, UsesStoredWorkflow, UsesAnno
# Filter
# FIXME: this removes connection without displaying a message currently!
input_connections = [ conn for conn in input_connections if conn.input_name in data_input_names ]
# post_job_actions
pja_dict = {}
for pja in step.post_job_actions:
pja_dict[pja.action_type+pja.output_name] = dict(action_type = pja.action_type,
output_name = pja.output_name,
action_arguments = pja.action_arguments)
step_dict['post_job_actions'] = pja_dict
# Encode input connections as dictionary
input_conn_dict = {}
for conn in input_connections:
@@ -665,7 +685,7 @@ class WorkflowController( BaseController, Sharable, UsesStoredWorkflow, UsesAnno
annotation = step_dict[ 'annotation' ]
if annotation:
annotation = sanitize_html( annotation, 'utf-8', 'text/html' )
self.add_item_annotation( trans, step, annotation )
self.add_item_annotation( trans, step, annotation )
# Second pass to deal with connections between steps
for step in steps:
# Input connections
@@ -815,7 +835,7 @@ class WorkflowController( BaseController, Sharable, UsesStoredWorkflow, UsesAnno
annotation = step_dict[ 'annotation' ]
if annotation:
annotation = sanitize_html( annotation, 'utf-8', 'text/html' )
self.add_item_annotation( trans, step, annotation )
self.add_item_annotation( trans, step, annotation )
# Second pass to deal with connections between steps
for step in steps:
# Input connections
@@ -1044,6 +1064,8 @@ class WorkflowController( BaseController, Sharable, UsesStoredWorkflow, UsesAnno
# Execute it
job, out_data = tool.execute( trans, step.state.inputs )
outputs[ step.id ] = out_data
for pja in step.post_job_actions:
ActionBox.execute(trans, pja, job)
else:
job, out_data = step.module.execute( trans, step.state )
outputs[ step.id ] = out_data
+32 -1
View File
@@ -6,7 +6,8 @@ from galaxy.tools import DefaultToolState
from galaxy.tools.parameters.grouping import Repeat, Conditional
from galaxy.util.bunch import Bunch
from galaxy.util.json import from_json_string, to_json_string
from galaxy.jobs.actions.post import ActionBox
from galaxy.model import PostJobAction
class WorkflowModule( object ):
@@ -163,6 +164,7 @@ class ToolModule( WorkflowModule ):
self.trans = trans
self.tool_id = tool_id
self.tool = trans.app.toolbox.tools_by_id[ tool_id ]
self.post_job_actions = {}
self.state = None
self.errors = None
@@ -171,6 +173,7 @@ class ToolModule( WorkflowModule ):
module = Class( trans, tool_id )
module.state = module.tool.new_state( trans, all_pages=True )
return module
@classmethod
def from_dict( Class, trans, d, secure=True ):
tool_id = d['tool_id']
@@ -178,6 +181,10 @@ class ToolModule( WorkflowModule ):
module.state = DefaultToolState()
module.state.decode( d["tool_state"], module.tool, module.trans.app, secure=secure )
module.errors = d.get( "tool_errors", None )
if 'post_job_actions' in d and d["post_job_actions"] != []:
module.post_job_actions = d["post_job_actions"]
else:
module.post_job_actions = {}
return module
@classmethod
@@ -187,6 +194,11 @@ class ToolModule( WorkflowModule ):
module.state = DefaultToolState()
module.state.inputs = module.tool.params_from_strings( step.tool_inputs, trans.app, ignore_errors=True )
module.errors = step.tool_errors
# module.post_job_actions = step.post_job_actions
pjadict = {}
for pja in step.post_job_actions:
pjadict[pja.action_type] = pja
module.post_job_actions = pjadict
return module
def save_to_step( self, step ):
@@ -194,6 +206,17 @@ class ToolModule( WorkflowModule ):
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
for k, v in self.post_job_actions.iteritems():
# Must have action_type, step. output and a_args are optional.
if 'output_name' in v:
output_name = v['output_name']
else:
output_name = None
if 'action_arguments' in v:
action_arguments = v['action_arguments']
else:
action_arguments = None
n_p = PostJobAction(v['action_type'], step, output_name, action_arguments)
def get_name( self ):
return self.tool.name
@@ -221,15 +244,23 @@ class ToolModule( WorkflowModule ):
for name, ( format, metadata_source, parent ) in self.tool.outputs.iteritems():
data_outputs.append( dict( name=name, extension=format ) )
return data_outputs
def get_post_job_actions( self ):
return self.post_job_actions
def get_config_form( self ):
self.add_dummy_datasets()
return self.trans.fill_template( "workflow/editor_tool_form.mako",
tool=self.tool, values=self.state.inputs, errors=( self.errors or {} ) )
def update_state( self, incoming ):
# Build a callback that handles setting an input to be required at
# runtime. We still process all other parameters the user might have
# set. We also need to make sure all datasets have a dummy value
# for dependencies to see
self.post_job_actions = ActionBox.handle_incoming(incoming)
make_runtime_key = incoming.get( 'make_runtime', None )
make_buildtime_key = incoming.get( 'make_buildtime', None )
def item_callback( trans, key, input, value, error, old_value, context ):
@@ -273,6 +273,7 @@ $.extend( Node.prototype, {
this.tool_errors = data.tool_errors;
this.tooltip = data.tooltip ? data.tooltip : ""
this.annotation = data.annotation;
this.post_job_actions = data.post_job_actions;
if ( this.tool_errors ) {
f.addClass( "tool-node-error" );
@@ -309,6 +310,7 @@ $.extend( Node.prototype, {
this.form_html = data.form_html;
this.tool_errors = data.tool_errors;
this.annotation = data['annotation'];
this.post_job_actions = $.parseJSON(data.post_job_actions);
if ( this.tool_errors ) {
el.addClass( "tool-node-error" );
} else {
@@ -400,6 +402,19 @@ $.extend( Workflow.prototype, {
input_connections[ t.name ] = { id: c.handle1.node.id, output_name: c.handle1.name };
});
});
var post_job_actions = {};
if (node.post_job_actions){
$.each( node.post_job_actions, function ( i, act ) {
var pja = {
job_id : act.id,
action_type : act.action_type,
output_name : act.output_name,
action_arguments : act.action_arguments
}
post_job_actions[ act.type + act.output_name ] = null;
post_job_actions[ act.type + act.output_name ] = pja;
});
}
var node_data = {
id : node.id,
type : node.type,
@@ -408,7 +423,8 @@ $.extend( Workflow.prototype, {
tool_errors : node.tool_errors,
input_connections : input_connections,
position : $(node.element).position(),
annotation: node.annotation
annotation: node.annotation,
post_job_actions: node.post_job_actions
};
nodes[ node.id ] = node_data;
});
+84 -6
View File
@@ -128,7 +128,7 @@
show_modal( "Server error", message, { "Ignore error" : hide_modal } );
return false;
});
make_popupmenu( $("#workflow-options-button"), {
##"Create New" : create_new_workflow_dialog,
"Edit Attributes" : edit_workflow_attributes,
@@ -306,13 +306,63 @@
});
};
<%
from galaxy.jobs.actions.post import ActionBox
%>
// DBTODO Refactor to the post module.
// This function preloads how to display known pja's.
function display_pja(pja, node){
// DBTODO SANITIZE INPUTS. Way too easy to break the page right now with a change dataset name action.
p_str = '';
${ActionBox.get_forms(trans)};
$("#pja_container").append(p_str);
$("#pja_container>.toolForm:last>.toolFormTitle>.buttons").click(function (){
action_to_rem = $(this).closest(".toolForm", ".action_tag").children(".action_tag:first").text();
$(this).closest(".toolForm").remove();
delete workflow.active_node.post_job_actions[action_to_rem];
workflow.active_form_has_changes = true;
});
}
function display_pja_list(){
return "${ActionBox.get_add_list()}";
}
function display_file_list(node){
addlist = "<select id='node_data_list' name='node_data_list'>";
for (var out_terminal in node.output_terminals){
addlist += "<option value='" + out_terminal + "'>"+ out_terminal +"</option>";
}
addlist += "</select>";
return addlist;
}
function new_pja(action_type, target, node){
if (node.post_job_actions == undefined){
//New tool node, set up dict.
node.post_job_actions = {};
}
if (node.post_job_actions[action_type+target] == undefined){
var new_pja = new Object();
new_pja.action_type = action_type;
new_pja.output_name = target;
node.post_job_actions[action_type+target] = null;
node.post_job_actions[action_type+target] = new_pja;
display_pja(new_pja, node);
workflow.active_form_has_changes = true;
return true;
}else{
return false;
}
}
function show_form_for_tool( text, node ) {
$("#edit-attributes").hide();
$("#right-content").show().html( text );
// Add metadata form to tool.
if (node) {
$("#right-content").find(".toolForm").after( "<p><div class='metadataForm'> \
$("#right-content").find(".toolForm:first").after( "<p><div class='metadataForm'> \
<div class='metadataFormTitle'>Edit Step Attributes</div> \
<div class='form-row'> \
<label>Annotation / Notes:</label> \
@@ -323,7 +373,23 @@
</div> \
</div>" );
}
// Add step actions.
if (node && node.type=='tool'){
pjastr = "<p><div class='metadataForm'><div class='metadataFormTitle'>Edit Step Actions</div><div class='form-row'> \
<label>New Actions:</label><br/>" + display_pja_list() + display_file_list(node) + " <div class='action-button' style='border:1px solid black;display:inline;' id='add_pja'>Create</div>\
</div><div class='form-row'>\
<div style='margin-right: 10px;'><span id='pja_container'></span>";
pjastr += "<div class='toolParamHelp'>Add actions to this step; actions are applied when this workflow step completes.</div></div></div></div>";
$("#right-content").find(".toolForm").after( pjastr );
for (var key in node.post_job_actions){
if (key != "undefined"){ //To make sure we haven't just deleted it.
display_pja(node.post_job_actions[key], node);
}
}
$("#add_pja").click(function (){
new_pja($("#new_pja_list").val(),$("#node_data_list").val(), node);
});
}
$("#right-content").find( "form" ).ajaxForm( {
type: 'POST',
dataType: 'json',
@@ -355,7 +421,6 @@
$(this).remove();
make_popupmenu( b, options );
});
// Implements auto-saving based on whether the inputs change. We consider
// "changed" to be when a field is accessed and not necessarily modified
// because of an issue where "onchange" is not triggered when activating
@@ -612,6 +677,7 @@
.form-row {
}
div.toolFormInCanvas div.toolFormBody {
padding: 0;
}
@@ -630,7 +696,19 @@
position: absolute;
z-index: 10000;
}
.pjaForm {
margin-bottom:10px;
}
.pjaForm .toolFormBody{
padding:10px;
}
.pjaForm .toolParamHelp{
padding:5px;
}
.panel-header-button-group {
margin-right: 5px;
padding-right: 5px;
+24
View File
@@ -23,6 +23,7 @@
<%
from galaxy.tools.parameters import DataToolParameter, RuntimeValue
from galaxy.jobs.actions.post import ActionBox
%>
<%def name="do_inputs( inputs, values, errors, prefix, step, other_values = None )">
@@ -136,6 +137,23 @@ from galaxy.tools.parameters import DataToolParameter, RuntimeValue
<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 )}
% if step.post_job_actions:
<hr/>
<div class='form-row'>
% if len(step.post_job_actions) > 1:
<label>Actions:</label>
% else:
<label>Action:</label>
% endif
${', '.join([ActionBox.get_short_str(pja) for pja in step.post_job_actions])}
</div>
% endif
% if step.annotations:
<hr/>
<div class='form-row'>
<label>Annotation:</label> ${step.annotations[0].annotation}
</div>
% endif
</div>
</div>
%else:
@@ -145,6 +163,12 @@ from galaxy.tools.parameters import DataToolParameter, RuntimeValue
<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 )}
% if step.annotations:
<hr/>
<div class='form-row'>
<label>Annotation:</label> ${step.annotations[0].annotation}
</div>
% endif
</div>
</div>
%endif