mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-10-24 12:13:33 +08:00
598 lines
21 KiB
Mako
598 lines
21 KiB
Mako
<%inherit file="/base_panels.mako"/>
|
|
|
|
<%def name="init()">
|
|
<%
|
|
self.active_view="workflow"
|
|
self.message_box_visible=True
|
|
self.message_box_class="warning"
|
|
%>
|
|
</%def>
|
|
|
|
<%def name="message_box_content()">
|
|
Workflow support is currently in <b><i>beta</i></b> testing.
|
|
Workflows may not work with all tools, may fail unexpectedly, and may
|
|
not be compatible with future updates to <b>Galaxy</b>.
|
|
</%def>
|
|
|
|
<%def name="late_javascripts()">
|
|
<script type='text/javascript' src="/static/scripts/galaxy.panels.js"> </script>
|
|
<script type="text/javascript">
|
|
ensure_dd_helper();
|
|
make_left_panel( $("#left"), $("#center"), $("#left-border" ) );
|
|
make_right_panel( $("#right"), $("#center"), $("#right-border" ) );
|
|
## handle_minwidth_hint = rp.handle_minwidth_hint;
|
|
</script>
|
|
</%def>
|
|
|
|
<%def name="javascripts()">
|
|
|
|
${parent.javascripts()}
|
|
|
|
<!--[if IE]>
|
|
<script type='text/javascript' src="/static/scripts/excanvas.js"> </script>
|
|
<![endif]-->
|
|
<script type='text/javascript' src="/static/scripts/jquery.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>
|
|
|
|
<script type='text/javascript' src="/static/scripts/galaxy.workflow_editor.canvas.js"> </script>
|
|
|
|
<!--[if lt IE 7]>
|
|
<script type='text/javascript'>
|
|
window.lt_ie_7 = true;
|
|
</script>
|
|
<![endif]-->
|
|
|
|
<script type='text/javascript'>
|
|
$( function() {
|
|
if ( window.lt_ie_7 ) {
|
|
show_modal(
|
|
"Browser not supported",
|
|
"Sorry, the workflow editor is not supported for IE6 and below."
|
|
);
|
|
return;
|
|
}
|
|
// Initialize workflow state
|
|
reset();
|
|
// Load the datatype info
|
|
$.ajax( {
|
|
url: "${h.url_for( action='get_datatypes' )}",
|
|
dataType: "json",
|
|
cache: false,
|
|
success: function( data ) {
|
|
populate_datatype_info( data );
|
|
// Load workflow definition
|
|
$.ajax( {
|
|
url: "${h.url_for( action='load_workflow' )}",
|
|
data: { id: "${trans.security.encode_id( workflow_id )}", "_": "true" },
|
|
dataType: 'json',
|
|
cache: false,
|
|
success: function( data ) {
|
|
reset();
|
|
workflow.from_simple( data );
|
|
workflow.has_changes = false;
|
|
scroll_to_nodes();
|
|
hide_modal();
|
|
},
|
|
beforeSubmit: function( data ) {
|
|
show_modal( "Loading workflow", "progress" );
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
$(document).ajaxError( function ( e, x ) {
|
|
show_modal( "Server error", x.responseText, { "Ignore error" : hide_modal } );
|
|
return false;
|
|
});
|
|
|
|
## make_popupmenu( "#optionsbutton", {
|
|
## "Create <b>new</b> workflow" : create_new_workflow_dialog,
|
|
## "<b>Save</b> current workflow" : save_current_workflow,
|
|
## "<b>Load</b> a stored workflow" : load_workflow
|
|
## });
|
|
|
|
$("#save-button").click( function() { save_current_workflow(); } );
|
|
$("#close-button").click( function() { close_editor(); } );
|
|
|
|
// Unload handler
|
|
window.onbeforeunload = function() {
|
|
if ( workflow && workflow.has_changes ) {
|
|
return "There are unsaved changes to your workflow which will be lost.";
|
|
}
|
|
}
|
|
|
|
// Drag/scroll canvas
|
|
$("#canvas-container").draggable({
|
|
drag: function( _, ui ) {
|
|
x = ui.position.left;
|
|
y = ui.position.top;
|
|
// Limit range
|
|
x = Math.min( x, 0 );
|
|
y = Math.min( y, 0 );
|
|
x = Math.max( x, - ( $(this).width() - $(this).parent().width() ) )
|
|
y = Math.max( y, - ( $(this).width() - $(this).parent().width() ) )
|
|
// Constrain position
|
|
ui.position.left = x;
|
|
ui.position.top = y;
|
|
}
|
|
});
|
|
|
|
// Tool menu
|
|
$( "div.toolSectionBody" ).hide();
|
|
$( "div.toolSectionTitle > span" ).wrap( "<a href='#'></a>" );
|
|
var last_expanded = null;
|
|
$( "div.toolSectionTitle" ).each( function() {
|
|
var body = $(this).next( "div.toolSectionBody" );
|
|
$(this).click( function() {
|
|
if ( body.is( ":hidden" ) ) {
|
|
if ( last_expanded ) last_expanded.slideUp( "fast" );
|
|
last_expanded = body;
|
|
body.slideDown( "fast" );
|
|
}
|
|
else {
|
|
body.slideUp( "fast" );
|
|
last_expanded = null;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
var workflow = null;
|
|
|
|
// Global state for the whole workflow
|
|
function reset() {
|
|
if ( workflow ) {
|
|
workflow.remove_all();
|
|
}
|
|
workflow = new Workflow();
|
|
}
|
|
|
|
function scroll_to_nodes() {
|
|
// Scroll to the top left node
|
|
if ( $("div.toolFormInCanvas").length > 0 ) {
|
|
var x = 5000, y = 5000;
|
|
$("div.toolFormInCanvas").each( function() {
|
|
x = 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 );
|
|
$("#canvas-container").css( { left: x, top: y } );
|
|
}
|
|
}
|
|
|
|
// Add a new step to the workflow by tool id
|
|
function add_node_for_tool( id, title ) {
|
|
node = prebuild_node( 'tool', title, id );
|
|
workflow.add_node( node );
|
|
workflow.activate_node( node );
|
|
$.ajax( {
|
|
url: "${h.url_for( action='get_new_module_info' )}",
|
|
data: { type: "tool", tool_id: id, "_": "true" },
|
|
global: false,
|
|
dataType: "json",
|
|
success: function( data ) {
|
|
node.init_field_data( data );
|
|
},
|
|
error: function( x, e ) {
|
|
var m = "error loading field data"
|
|
if ( x.status == 0 ) {
|
|
m += ", server unavailable"
|
|
}
|
|
node.error( m );
|
|
}
|
|
});
|
|
};
|
|
|
|
function add_node_for_module( type, title ) {
|
|
node = prebuild_node( type, title );
|
|
workflow.add_node( node );
|
|
workflow.activate_node( node );
|
|
$.ajax( {
|
|
url: "${h.url_for( action='get_new_module_info' )}",
|
|
data: { type: type, "_": "true" },
|
|
dataType: "json",
|
|
success: function( data ) {
|
|
node.init_field_data( data );
|
|
},
|
|
error: function( x, e ) {
|
|
var m = "error loading field data"
|
|
if ( x.status == 0 ) {
|
|
m += ", server unavailable"
|
|
}
|
|
node.error( m );
|
|
}
|
|
});
|
|
};
|
|
|
|
function show_form_for_tool( text, node ) {
|
|
// $("#overlay, #modalwrapper" ).show();
|
|
//$("#modal iframe").attr( 'src', "${h.url_for( action='tool_form' )}?tool_id=" + tool_id ).load( function () {
|
|
// $("#modalloadwrapper").hide();
|
|
//});
|
|
// $("#right-content").load( "${h.url_for( action='tool_form' )}", { tool_id: tool_id }, function () {
|
|
//
|
|
// });
|
|
$("#right-content").html( text );
|
|
$("#right-content").find( "form" ).ajaxForm( {
|
|
type: 'POST',
|
|
dataType: 'json',
|
|
success: function( data ) {
|
|
node.update_field_data( data );
|
|
},
|
|
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;
|
|
$(this).find( "select[refresh_on_change='true']").change( function() {
|
|
$(form).submit();
|
|
});
|
|
});
|
|
}
|
|
|
|
var close_editor = function() {
|
|
<% next_url = h.url_for( controller='workflow', action='index' ) %>
|
|
if ( workflow && workflow.has_changes ) {
|
|
do_close = function() {
|
|
window.onbeforeunload = undefined;
|
|
window.document.location = "${next_url}"
|
|
};
|
|
show_modal( "Close workflow editor",
|
|
"There are unsaved changes to your workflow which will be lost.",
|
|
{
|
|
"Cancel" : hide_modal,
|
|
"Save Changes" : function() {
|
|
save_current_workflow( do_close );
|
|
}
|
|
}, {
|
|
"Don't Save": do_close
|
|
} );
|
|
} else {
|
|
window.document.location = "${next_url}"
|
|
}
|
|
}
|
|
|
|
var save_current_workflow = function ( success_callback ) {
|
|
show_modal( "Saving workflow", "progress" );
|
|
$.ajax( {
|
|
url: "${h.url_for( action='save_workflow' )}",
|
|
type: "POST",
|
|
data: {
|
|
id: "${trans.security.encode_id( workflow_id )}",
|
|
workflow_data: $.toJSON( 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" );
|
|
}
|
|
workflow.name = data.name;
|
|
workflow.has_changes = false;
|
|
workflow.stored = true;
|
|
if ( success_callback ) {
|
|
success_callback();
|
|
}
|
|
if ( data.errors ) {
|
|
show_modal( "Saving workflow", body, { "Ok" : hide_modal } );
|
|
} else {
|
|
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>
|
|
|
|
<%def name="stylesheets()">
|
|
|
|
## Include "base.css" for styling tool menu and forms (details)
|
|
<link href="${h.url_for('/static/style/base.css')}" rel="stylesheet" type="text/css" />
|
|
|
|
## But make sure styles for the layout take precedence
|
|
${parent.stylesheets()}
|
|
|
|
<style type="text/css">
|
|
body { margin: 0; padding: 0; overflow: hidden; }
|
|
|
|
/* Wider right panel */
|
|
#center { right: 309px; }
|
|
#right-border { right: 300px; }
|
|
#right { width: 300px; }
|
|
## /* Relative masthead size */
|
|
## #masthead { height: 2.5em; }
|
|
## #masthead div.title { font-size: 1.8em; }
|
|
## #left, #left-border, #center, #right-border, #right {
|
|
## top: 2.5em;
|
|
## margin-top: 7px;
|
|
## }
|
|
|
|
#left {
|
|
background: #C1C9E5 url(${h.url_for('/static/style/menu_bg.png')}) top repeat-x;
|
|
}
|
|
|
|
div.toolMenu {
|
|
margin: 5px;
|
|
margin-left: 10px;
|
|
margin-right: 10px;
|
|
}
|
|
div.toolSectionPad {
|
|
margin: 0;
|
|
padding: 0;
|
|
height: 5px;
|
|
font-size: 0px;
|
|
}
|
|
div.toolSectionDetailsInner {
|
|
margin-left: 5px;
|
|
margin-right: 5px;
|
|
}
|
|
div.toolSectionTitle {
|
|
padding-bottom: 0px;
|
|
font-weight: bold;
|
|
}
|
|
div.toolMenuGroupHeader {
|
|
font-weight: bold;
|
|
padding-top: 0.5em;
|
|
padding-bottom: 0.5em;
|
|
color: #333;
|
|
font-style: italic;
|
|
border-bottom: dotted #333 1px;
|
|
margin-bottom: 0.5em;
|
|
}
|
|
|
|
div.toolTitle {
|
|
padding-top: 5px;
|
|
padding-bottom: 5px;
|
|
margin-left: 16px;
|
|
margin-right: 10px;
|
|
display: list-item;
|
|
list-style: square outside;
|
|
}
|
|
div.toolTitleDisabled {
|
|
padding-top: 5px;
|
|
padding-bottom: 5px;
|
|
margin-left: 16px;
|
|
margin-right: 10px;
|
|
display: list-item;
|
|
list-style: square outside;
|
|
font-style: italic;
|
|
color: gray;
|
|
}
|
|
div.toolFormRow {
|
|
position: relative;
|
|
}
|
|
|
|
|
|
#right-content {
|
|
margin: 5px;
|
|
}
|
|
|
|
canvas { position: absolute; z-index: 10; }
|
|
canvas.dragging { position: absolute; z-index: 1000; }
|
|
.input-terminal { width: 12px; height: 12px; background: url(${h.url_for('/static/style/workflow_circle_open.png')}); position: absolute; top: 0; left: -16px; z-index: 1500; }
|
|
.output-terminal { width: 12px; height: 12px; background: url(${h.url_for('/static/style/workflow_circle_open.png')}); position: absolute; top: 0; right: -16px; z-index: 1500; }
|
|
.drag-terminal { width: 12px; height: 12px; background: url(${h.url_for('/static/style/workflow_circle_drag.png')}); position: absolute; z-index: 1500; }
|
|
.input-terminal-active { background: url(${h.url_for('/static/style/workflow_circle_green.png')}); }
|
|
## .input-terminal-hover { background: yellow; border: solid black 1px; }
|
|
.unselectable { -moz-user-select: none; -khtml-user-select: none; user-select: none; }
|
|
img { border: 0; }
|
|
|
|
div.buttons img {
|
|
width: 16px; height: 16px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
## Extra styles for the representation of a tool on the canvas (looks like
|
|
## a tiny tool form)
|
|
div.toolFormInCanvas {
|
|
z-index: 100;
|
|
position: absolute;
|
|
min-width: 130px;
|
|
margin: 6px;
|
|
}
|
|
|
|
div.toolForm-active {
|
|
z-index: 1001;
|
|
border: solid #8080FF 4px;
|
|
margin: 3px;
|
|
}
|
|
|
|
div.toolFormTitle {
|
|
cursor: move;
|
|
min-height: 16px;
|
|
}
|
|
|
|
div.titleRow {
|
|
font-weight: bold;
|
|
border-bottom: dotted gray 1px;
|
|
margin-bottom: 0.5em;
|
|
padding-bottom: 0.25em;
|
|
}
|
|
div.form-row {
|
|
position: relative;
|
|
margin-top: 0.5em;
|
|
margin-bottom: 0.5em;
|
|
}
|
|
|
|
div.tool-node-error div.toolFormTitle {
|
|
background: #FFCCCC;
|
|
border-color: #AA6666;
|
|
}
|
|
div.tool-node-error {
|
|
border-color: #AA6666;
|
|
}
|
|
|
|
#canvas-area {
|
|
position: absolute;
|
|
top: 0; left: 305px; bottom: 0; right: 0;
|
|
border: solid red 1px;
|
|
overflow: none;
|
|
}
|
|
|
|
.form-row {
|
|
|
|
}
|
|
.form-row-body {
|
|
|
|
}
|
|
.form-row-clear {
|
|
clear: both;
|
|
}
|
|
|
|
div.rule {
|
|
height: 0;
|
|
border: none;
|
|
border-bottom: dotted black 1px;
|
|
}
|
|
|
|
.callout {
|
|
position: absolute;
|
|
z-index: 10000;
|
|
}
|
|
|
|
</style>
|
|
</%def>
|
|
|
|
<div id="overlay">
|
|
## Need a table here for centering in IE6
|
|
<table class="dialog-box-container" border="0" cellpadding="0" cellspacing="0"><tr><td>
|
|
<div class="dialog-box-wrapper">
|
|
<div class="dialog-box">
|
|
<div class="unified-panel-header">
|
|
<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>
|
|
<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>
|
|
</td></tr></table>
|
|
</div>
|
|
|
|
<%def name="left_panel()">
|
|
<div class="unified-panel-header" unselectable="on">
|
|
<div class="unified-panel-header-inner">
|
|
Tools
|
|
</div>
|
|
</div>
|
|
|
|
<div class="unified-panel-body" style="overflow: auto;">
|
|
<div class="toolMenu">
|
|
<div class="toolSectionList">
|
|
%for i, section in enumerate( app.toolbox.sections ):
|
|
%if i > 0:
|
|
<div class="toolSectionPad"></div>
|
|
%endif
|
|
<div class="toolSectionTitle" id="title_${section.id}">
|
|
<span>${section.name}</span>
|
|
</div>
|
|
<div id="${section.id}" class="toolSectionBody">
|
|
<div class="toolSectionBg">
|
|
%for tool in section.tools:
|
|
%if not tool.hidden:
|
|
%if tool.is_workflow_compatible:
|
|
<div class="toolTitle ">
|
|
%if "[[" in tool.description and "]]" in tool.description:
|
|
${tool.description.replace( '[[', '<a id="link-${tool.id}" href="javascript:add_node_for_tool( ${tool.id} )">' % tool.id ).replace( "]]", "</a>" )}
|
|
%elif tool.name:
|
|
<a id="link-${tool.id}" href="#" onclick="add_node_for_tool( '${tool.id}', '${tool.name}' )">${tool.name}</a> ${tool.description}
|
|
%else:
|
|
<a id="link-${tool.id}" href="#" onclick="add_node_for_tool( '${tool.id}', '${tool.name}' )">${tool.description}</a>
|
|
%endif
|
|
</div>
|
|
%else:
|
|
<div class="toolTitleDisabled">
|
|
%if "[[" in tool.description and "]]" in tool.description:
|
|
${tool.description.replace( '[[', '' % tool.id ).replace( "]]", "" )}
|
|
%elif tool.name:
|
|
${tool.name} ${tool.description}
|
|
%else:
|
|
${tool.description}
|
|
%endif
|
|
</div>
|
|
%endif
|
|
%endif
|
|
%endfor
|
|
</div>
|
|
</div>
|
|
%endfor
|
|
</div>
|
|
<div> </div>
|
|
<div class="toolMenuGroupHeader">Workflow control</div>
|
|
<div class="toolSectionTitle" id="title___workflow__input__">
|
|
<span>Inputs</span>
|
|
</div>
|
|
<div id="__workflow__input__" class="toolSectionBody">
|
|
<div class="toolSectionBg">
|
|
<div class="toolTitle">
|
|
<a href="#" onclick="add_node_for_module( 'data_input', 'Input Dataset' )">Input dataset</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</%def>
|
|
|
|
<%def name="center_panel()">
|
|
|
|
<div class="unified-panel-header" unselectable="on">
|
|
<div class="unified-panel-header-inner" style="float: right">
|
|
<a id="save-button" class="panel-header-button">Save</a>
|
|
<a id="close-button" class="panel-header-button">Close</a>
|
|
</div>
|
|
<div class="unified-panel-header-inner">
|
|
Workflow canvas
|
|
</div>
|
|
</div>
|
|
|
|
<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>
|
|
|
|
</%def>
|
|
|
|
<%def name="right_panel()">
|
|
<div class="unified-panel-header" unselectable="on">
|
|
<div class="unified-panel-header-inner">
|
|
Details
|
|
</div>
|
|
</div>
|
|
<div class="unified-panel-body" style="overflow: auto;">
|
|
<div id="right-content"></div>
|
|
</div>
|
|
</%def> |