galaxy-dev
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- 10007 discussions
15 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/14fd033f08eb
changeset: 2476:14fd033f08eb
user: James Taylor <james(a)jamestaylor.org>
date: Fri Jul 10 16:21:19 2009 -0400
description:
IE compatibility fixes in workflow editor javascript (groan)
2 file(s) affected in this change:
static/scripts/galaxy.workflow_editor.canvas.js
static/scripts/packed/galaxy.workflow_editor.canvas.js
diffs (474 lines):
diff -r 0b5d64cde142 -r 14fd033f08eb static/scripts/galaxy.workflow_editor.canvas.js
--- a/static/scripts/galaxy.workflow_editor.canvas.js Fri Jul 10 16:15:32 2009 -0400
+++ b/static/scripts/galaxy.workflow_editor.canvas.js Fri Jul 10 16:21:19 2009 -0400
@@ -2,7 +2,7 @@
this.element = element;
this.connectors = [];
}
-Terminal.prototype = {
+$.extend( Terminal.prototype, {
connect: function ( connector ) {
this.connectors.push( connector );
if ( this.node ) {
@@ -25,26 +25,26 @@
c.destroy();
});
}
-}
+});
function OutputTerminal( element, datatype ) {
Terminal.call( this, element );
this.datatype = datatype;
}
-OutputTerminal.prototype = new Terminal;
+OutputTerminal.prototype = new Terminal();
function InputTerminal( element, datatypes ) {
Terminal.call( this, element );
this.datatypes = datatypes;
}
-InputTerminal.prototype = new Terminal;
+InputTerminal.prototype = new Terminal();
$.extend( InputTerminal.prototype, {
can_accept: function ( other ) {
if ( this.connectors.length < 1 ) {
- for ( t in this.datatypes ) {
+ for ( var t in this.datatypes ) {
// FIXME: No idea what to do about this case
if ( other.datatype == "input" ) { return true; }
if ( issubtype( other.datatype, this.datatypes[t] ) ) {
@@ -60,7 +60,7 @@
this.canvas = null;
this.dragging = false;
this.inner_color = "#FFFFFF";
- this.outer_color = "#D8B365"
+ this.outer_color = "#D8B365";
if ( handle1 && handle2 ) {
this.connect( handle1, handle2 );
}
@@ -90,10 +90,16 @@
G_vmlCanvasManager.initElement( this.canvas );
}
canvas_container.append( $(this.canvas) );
- if ( this.dragging ) { this.canvas.style.zIndex = "300" }
+ if ( this.dragging ) {
+ this.canvas.style.zIndex = "300";
+ }
}
- var relativeLeft = function( e ) { return $(e).offset().left - canvas_container.offset().left }
- var relativeTop = function( e ) { return $(e).offset().top - canvas_container.offset().top }
+ var relativeLeft = function( e ) {
+ return $(e).offset().left - canvas_container.offset().left;
+ };
+ var relativeTop = function( e ) {
+ return $(e).offset().top - canvas_container.offset().top;
+ };
// Find the position of each handle
var start_x = relativeLeft( this.handle1.element ) + 5;
var start_y = relativeTop( this.handle1.element ) + 5;
@@ -157,7 +163,7 @@
}).bind( "dropend", function ( e ) {
e.dragProxy.terminal.connectors[0].inner_color = "#FFFFFF";
}).bind( "drop", function( e ) {
- new Connector( e.dragTarget.terminal, e.dropTarget.terminal ).redraw();
+ ( new Connector( e.dragTarget.terminal, e.dropTarget.terminal ) ).redraw();
}).bind( "hover", function() {
// If connected, create a popup to allow disconnection
if ( terminal.connectors.length > 0 ) {
@@ -168,22 +174,24 @@
.append(
$("<div class='buttons'></div>").append(
$("<img src='../images/delete_icon.png' />").click( function() {
- $.each( terminal.connectors, function( _, x ) { x.destroy() } );
+ $.each( terminal.connectors, function( _, x ) {
+ x.destroy();
+ });
t.remove();
})))
.bind( "mouseleave", function() {
$(this).remove();
});
// Position it and show
- t.css( {
+ t.css({
top: $(this).offset().top - 2,
left: $(this).offset().left - t.width(),
- 'padding-right': $(this).width() }
- ).show();
+ 'padding-right': $(this).width()
+ }).show();
}
});
node.input_terminals[name] = terminal;
- })
+ });
},
enable_output_terminal : function( elements, name, type ) {
var node = this;
@@ -213,7 +221,7 @@
e.dragProxy.terminal.redraw();
// FIXME: global
canvas_manager.update_viewport_overlay();
- }
+ };
onmove();
$("#canvas-container").get(0).scroll_panel.test( e, onmove );
}).bind( "dragend", function ( e ) {
@@ -226,8 +234,12 @@
});
},
redraw : function () {
- $.each( this.input_terminals, function( _, t ) { t.redraw() } );
- $.each( this.output_terminals, function( _, t ) { t.redraw() } );
+ $.each( this.input_terminals, function( _, t ) {
+ t.redraw();
+ });
+ $.each( this.output_terminals, function( _, t ) {
+ t.redraw();
+ });
},
destroy : function () {
$.each( this.input_terminals, function( k, t ) {
@@ -246,7 +258,7 @@
// Keep inactive nodes stacked from most to least recently active
// by moving element to the end of parent's node list
var element = this.element.get(0);
- (function(p) { p.removeChild( element ); p.appendChild( element ) })(element.parentNode);
+ (function(p) { p.removeChild( element ); p.appendChild( element ); })(element.parentNode);
// Remove active class
$(element).removeClass( "toolForm-active" );
},
@@ -279,7 +291,7 @@
$.each( data.data_outputs, function( i, output ) {
var t = $( "<div class='terminal output-terminal'></div>" );
node.enable_output_terminal( t, output.name, output.extension );
- var label = output.name
+ var label = output.name;
if ( output.extension != 'input' ) {
label = label + " (" + output.extension + ")";
}
@@ -301,7 +313,7 @@
// Update input rows
var old_body = el.find( "div.inputs" );
var new_body = $("<div class='inputs'></div>");
- var old = old_body.find( "div.input-data-row")
+ var old = old_body.find( "div.input-data-row");
$.each( data.data_inputs, function( i, input ) {
var t = $("<div class='terminal input-terminal'></div>");
node.enable_input_terminal( t, input.name, input.extensions );
@@ -323,7 +335,7 @@
// Cleanup any leftover terminals
old_body.find( "div.input-data-row > .terminal" ).each( function() {
this.terminal.destroy();
- })
+ });
// If active, reactivate with new form_html
this.changed();
this.redraw();
@@ -344,7 +356,7 @@
function Workflow( canvas_container ) {
this.canvas_container = canvas_container;
this.id_counter = 0;
- this.nodes = {}
+ this.nodes = {};
this.name = null;
this.has_changes = false;
}
@@ -372,9 +384,9 @@
});
},
to_simple : function () {
- var nodes = {}
+ var nodes = {};
$.each( this.nodes, function ( i, node ) {
- var input_connections = {}
+ var input_connections = {};
$.each( node.input_terminals, function ( k, t ) {
input_connections[ t.name ] = null;
// There should only be 0 or 1 connectors, so this is
@@ -391,10 +403,10 @@
tool_errors : node.tool_errors,
input_connections : input_connections,
position : $(node.element).position()
- }
+ };
nodes[ node.id ] = node_data;
- })
- return { steps: nodes }
+ });
+ return { steps: nodes };
},
from_simple : function ( data ) {
wf = this;
@@ -409,7 +421,7 @@
}
node.id = step.id;
wf.nodes[ node.id ] = node;
- max_id = Math.max( max_id, parseInt( id ) )
+ max_id = Math.max( max_id, parseInt( id ) );
});
wf.id_counter = max_id + 1;
// Second pass, connections
@@ -423,7 +435,7 @@
node.input_terminals[ k ] );
c.redraw();
}
- })
+ });
});
},
clear_active_node : function() {
@@ -471,31 +483,32 @@
});
});
// Assemble order, tracking levels
- node_ids_by_level = []
+ node_ids_by_level = [];
while ( true ) {
// Everything without a predecessor
- level_parents = []
- $.each( n_pred, function( k, v ) {
- if ( v == 0 ) {
- level_parents.push( k );
+ level_parents = [];
+ for ( var pred_k in n_pred ) {
+ if ( n_pred[ pred_k ] == 0 ) {
+ level_parents.push( pred_k );
}
- });
+ }
if ( level_parents.length == 0 ) {
break;
}
- node_ids_by_level.push( level_parents )
+ node_ids_by_level.push( level_parents );
// Remove the parents from this level, and decrement the number
// of predecessors for each successor
- $.each( level_parents, function( k, v ) {
+ for ( var k in level_parents ) {
+ var v = level_parents[k];
delete n_pred[v];
- $.each( successors[v], function( sk, sv ) {
- n_pred[sv] -= 1;
- });
- });
+ for ( var sk in successors[v] ) {
+ n_pred[ sucessors[v][sk] ] -= 1;
+ }
+ }
}
if ( n_pred.length ) {
// ERROR: CYCLE! Currently we do nothing
- return
+ return;
}
// Layout each level
var all_nodes = this.nodes;
@@ -505,7 +518,7 @@
// We keep nodes in the same order in a level to give the user
// some control over ordering
ids.sort( function( a, b ) {
- return $(all_nodes[a].element).position().top - $(all_nodes[b].element).position().top
+ return $(all_nodes[a].element).position().top - $(all_nodes[b].element).position().top;
});
// Position each node
var max_width = 0;
@@ -520,7 +533,7 @@
left += max_width + h_pad;
});
// Need to redraw all connectors
- $.each( all_nodes, function( _, node ) { node.redraw() } );
+ $.each( all_nodes, function( _, node ) { node.redraw(); } );
},
bounds_for_all_nodes: function() {
var xmin = Infinity, xmax = -Infinity,
@@ -528,7 +541,7 @@
p;
$.each( this.nodes, function( id, node ) {
e = $(node.element);
- p = e.position()
+ p = e.position();
xmin = Math.min( xmin, p.left );
xmax = Math.max( xmax, p.left + e.width() );
ymin = Math.min( ymin, p.top );
@@ -559,11 +572,11 @@
left: left,
top: top,
width: width,
- height: height,
+ height: height
});
// Move elements back if needed
this.canvas_container.children().each( function() {
- var p = $(this).position()
+ var p = $(this).position();
$(this).css( "left", p.left + xmin_delta );
$(this).css( "top", p.top + ymin_delta );
});
@@ -585,26 +598,26 @@
function prebuild_node( type, title_text, tool_id ) {
var f = $("<div class='toolForm toolFormInCanvas'></div>");
var node = new Node( f );
- node.type = type
+ node.type = type;
if ( type == 'tool' ) {
node.tool_id = tool_id;
}
- var title = $("<div class='toolFormTitle unselectable'>" + title_text + "</div>" )
+ var title = $("<div class='toolFormTitle unselectable'>" + title_text + "</div>" );
f.append( title );
f.css( "left", $(window).scrollLeft() + 20 ); f.css( "top", $(window).scrollTop() + 20 );
- var b = $("<div class='toolFormBody'></div>")
+ var b = $("<div class='toolFormBody'></div>");
var tmp = "<div><img height='16' align='middle' src='../images/loading_small_white_bg.gif'/> loading tool info...</div>";
b.append( tmp );
node.form_html = tmp;
- f.append( b )
+ f.append( b );
// Fix width to computed width
// Now add floats
var buttons = $("<div class='buttons' style='float: right;'></div>");
buttons.append( $("<img src='../images/delete_icon.png' />").click( function( e ) {
node.destroy();
} ).hover(
- function() { $(this).attr( 'src', "../images/delete_icon_dark.png" ) },
- function() { $(this).attr( 'src', "../images/delete_icon.png" ) }
+ function() { $(this).attr( 'src', "../images/delete_icon_dark.png" ); },
+ function() { $(this).attr( 'src', "../images/delete_icon.png" ); }
) );
// Place inside container
f.appendTo( "#canvas-container" );
@@ -647,12 +660,12 @@
child = ext_to_type[child];
parent = ext_to_type[parent];
return ( type_to_type[child] ) && ( parent in type_to_type[child] );
-};
+}
function populate_datatype_info( data ) {
ext_to_type = data.ext_to_class_name;
type_to_type = data.class_to_classes;
-};
+}
// FIXME: merge scroll panel into CanvasManager, clean up hardcoded stuff.
@@ -663,14 +676,14 @@
test: function( e, onmove ) {
clearTimeout( this.timeout );
var x = e.pageX,
- y = e.pageY;
+ y = e.pageY,
// Panel size and position
panel = $(this.panel),
panel_pos = panel.position(),
panel_w = panel.width(),
- panel_h = panel.height()
+ panel_h = panel.height(),
// Viewport size and offset
- viewport = panel.parent();
+ viewport = panel.parent(),
viewport_w = viewport.width(),
viewport_h = viewport.height(),
viewport_offset = viewport.offset(),
@@ -747,7 +760,7 @@
top: y
});
self.update_viewport_overlay();
- }
+ };
// Dragging within canvas background
this.cc.each( function() {
this.scroll_panel = new ScrollPanel( this );
@@ -766,13 +779,13 @@
});
// Dragging for overview pane
this.ov.bind( "drag", function( e ) {
- var in_w = self.cc.width();
- var in_h = self.cc.height()
- var o_w = self.oc.width();
- var o_h = self.oc.height();
- var p = $(this).offsetParent().offset();
- var new_x_offset = e.offsetX - p.left;
- var new_y_offset = e.offsetY - p.top;
+ var in_w = self.cc.width(),
+ in_h = self.cc.height(),
+ o_w = self.oc.width(),
+ o_h = self.oc.height(),
+ p = $(this).offsetParent().offset(),
+ new_x_offset = e.offsetX - p.left,
+ new_y_offset = e.offsetY - p.top;
move( - ( new_x_offset / o_w * in_w ),
- ( new_y_offset / o_h * in_h ) );
}).bind( "dragend", function() {
@@ -794,15 +807,15 @@
},
update_viewport_overlay: function() {
- var cc = this.cc;
- var cv = this.cv;
- var oc = this.oc;
- var ov = this.ov;
- var in_w = cc.width();
- var in_h = cc.height()
- var o_w = oc.width();
- var o_h = oc.height();
- var cc_pos = cc.position()
+ var cc = this.cc,
+ cv = this.cv,
+ oc = this.oc,
+ ov = this.ov,
+ in_w = cc.width(),
+ in_h = cc.height(),
+ o_w = oc.width(),
+ o_h = oc.height(),
+ cc_pos = cc.position();
ov.css( {
left: - ( cc_pos.left / in_w * o_w ),
top: - ( cc_pos.top / in_h * o_h ),
@@ -812,11 +825,11 @@
});
},
draw_overview: function() {
- var canvas_el = $("#overview-canvas");
- var size = canvas_el.parent().parent().width()
- var c = canvas_el.get(0).getContext("2d");
- var in_w = $("#canvas-container").width();
- var in_h = $("#canvas-container").height()
+ var canvas_el = $("#overview-canvas"),
+ size = canvas_el.parent().parent().width(),
+ c = canvas_el.get(0).getContext("2d"),
+ in_w = $("#canvas-container").width(),
+ in_h = $("#canvas-container").height();
var o_h, shift_h, o_w, shift_w;
// Fit canvas into overview area
var cv_w = this.cv.width();
@@ -853,7 +866,7 @@
c.strokeStyle = "#D8B365";
c.lineWidth = 1;
$.each( workflow.nodes, function( id, node ) {
- var node_element = $(node.element);
+ var node_element = $(node.element),
position = node_element.position(),
x = position.left / in_w * o_w,
y = position.top / in_h * o_h,
@@ -864,4 +877,4 @@
});
this.update_viewport_overlay();
}
-})
\ No newline at end of file
+});
\ No newline at end of file
diff -r 0b5d64cde142 -r 14fd033f08eb static/scripts/packed/galaxy.workflow_editor.canvas.js
--- a/static/scripts/packed/galaxy.workflow_editor.canvas.js Fri Jul 10 16:15:32 2009 -0400
+++ b/static/scripts/packed/galaxy.workflow_editor.canvas.js Fri Jul 10 16:21:19 2009 -0400
@@ -1,1 +1,1 @@
-function Terminal(a){this.element=a;this.connectors=[]}Terminal.prototype={connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}};function OutputTerminal(a,b){Terminal.call(this,a);this.datatype=b}OutputTerminal.prototype=new Terminal;function InputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}InputTerminal.prototype=new Terminal;$.extend(InputTerminal.prototype,{can_accept:function(a){if(this.connectors.length<1){for(t in this.datatypes){if(a.datatype=="input"){return true}if(issubtype(a.datatype,this.datatypes[t])){return true}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a){this.connect(b,a)
}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;this.handle1.connect(this);this.handle2=a;this.handle2.connect(this)},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var o=function(c){return $(c).offset().left-d.offset().left};var j=function(c){return $(c).offset().top-d.offset().top};var i=o(this.handle1.element)+5;var g=j(this.handle1.element)+5;var q=o(this.handle2.element)+5;var n=j(this.handle2.element)+5;var f=100;var l=Math.min(i,q);var a=Math.max(i,q);var k=Math.min(g,n);var v=Math.max(g,n);var b=Math.min(Math.max(Math.abs(v-k)/2,100),300);var p=l-f;var u=k-f;var r=a-l+2*f;var m=v-k+2*f;this.canvas.style.
left=p+"px";this.canvas.style.top=u+"px";this.canvas.setAttribute("width",r);this.canvas.setAttribute("height",m);i-=p;g-=u;q-=p;n-=u;var s=this.canvas.getContext("2d");s.lineCap="round";s.strokeStyle=this.outer_color;s.lineWidth=7;s.beginPath();s.moveTo(i,g);s.bezierCurveTo(i+b,g,q-b,n,q,n);s.stroke();s.strokeStyle=this.inner_color;s.lineWidth=5;s.beginPath();s.moveTo(i,g);s.bezierCurveTo(i+b,g,q-b,n,q,n);s.stroke()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{enable_input_terminal:function(d,a,b){var c=this;$(d).each(function(){var f=this.terminal=new InputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dropstart",function(g){g.dragProxy.terminal.connectors[0].inner_color="#BBFFBB"}).bind("dropend",function(g){g.dragProxy.terminal.connectors[0].inner_color="#FFFFFF"}).bind("drop",function(g){new Connector(g.dragTarget.terminal,g.dropTarget.terminal).redraw()}).bind("hover",function(){if(f.
connectors.length>0){var g=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='buttons'></div>").append($("<img src='../images/delete_icon.png' />").click(function(){$.each(f.connectors,function(j,i){i.destroy()});g.remove()}))).bind("mouseleave",function(){$(this).remove()});g.css({top:$(this).offset().top-2,left:$(this).offset().left-g.width(),"padding-right":$(this).width()}).show()}});c.input_terminals[a]=f})},enable_output_terminal:function(d,a,b){var c=this;$(d).each(function(){var g=this;var f=this.terminal=new OutputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dragstart",function(j){var i=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);i.terminal=new OutputTerminal(i);var k=new Connector();k.dragging=true;k.connect(this.terminal,i.terminal);$.dropManage({filter:function(l){return this.terminal.can_accept(f)}}).addClass("input-terminal-active");return i}).bind("drag",
function(j){var i=function(){var l=$(j.dragProxy).offsetParent().offset(),k=j.offsetX-l.left,m=j.offsetY-l.top;$(j.dragProxy).css({left:k,top:m});j.dragProxy.terminal.redraw();canvas_manager.update_viewport_overlay()};i();$("#canvas-container").get(0).scroll_panel.test(j,i)}).bind("dragend",function(i){i.dragProxy.terminal.connectors[0].destroy();$(i.dragProxy).remove();$.dropManage().removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()});c.output_terminals[a]=f})},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b.appendChild(a)})(a.
parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(g){var d=this.element;if(g.type){this.type=g.type}this.name=g.name;this.form_html=g.form_html;this.tool_state=g.tool_state;this.tool_errors=g.tool_errors;if(this.tool_errors){d.addClass("tool-node-error")}else{d.removeClass("tool-node-error")}var c=this;var a=d.find(".toolFormBody");a.find("div").remove();var i=$("<div class='inputs'></div>").appendTo(a);$.each(g.data_inputs,function(j,b){var f=$("<div class='terminal input-terminal'></div>");c.enable_input_terminal(f,b.name,b.extensions);i.append($("<div class='form-row dataRow input-data-row' name='"+b.name+"'>"+b.label+"</div>").prepend(f))});if((g.data_inputs.length>0)&&(g.data_outputs.length>0)){a.append($("<div class='rule'></div>"))}$.each(g.data_outputs,function(k,b){var j=$("<div class='terminal output-terminal'></div>");c.enable_output_terminal(j,b.name,b.extension);var f=b.name;if(b.extension!="input"){f=f+" ("+b.extension+")"}a.append($("<d
iv class='form-row dataRow'>"+f+"</div>").append(j))});workflow.node_changed(this)},update_field_data:function(f){var c=$(this.element),d=this;this.tool_state=f.tool_state;this.form_html=f.form_html;this.tool_errors=f.tool_errors;if(this.tool_errors){c.addClass("tool-node-error")}else{c.removeClass("tool-node-error")}var g=c.find("div.inputs");var b=$("<div class='inputs'></div>");var a=g.find("div.input-data-row");$.each(f.data_inputs,function(l,j){var k=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(k,j.name,j.extensions);g.find("div[name="+j.name+"]").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){k[0].terminal.connectors[0]=i;i.handle2=k[0].terminal}});$(this).remove()});b.append($("<div class='form-row dataRow input-data-row' name='"+j.name+"'>"+j.label+"</div>").prepend(k))});g.replaceWith(b);g.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.changed(
);this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},changed:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},to_simple:function(){var a={};$.each(this.nodes,function(b,d){var f={};$.each(d.input_terminals,function(g,i){f[i.name]=null;$.each(i.connectors,function(j,k){f[i.name]={id:k.handle1.node.id,output
_name:k.handle1.name}})});var c={id:d.id,type:d.type,tool_id:d.tool_id,tool_state:d.tool_state,tool_errors:d.tool_errors,input_connections:f,position:$(d.element).position()};a[d.id]=c});return{steps:a}},from_simple:function(a){wf=this;var b=0;wf.name=a.name;$.each(a.steps,function(f,d){var c=prebuild_node("tool",d.name,d.tool_id);c.init_field_data(d);if(d.position){c.element.css({top:d.position.top,left:d.position.left})}c.id=d.id;wf.nodes[c.id]=c;b=Math.max(b,parseInt(f))});wf.id_counter=b+1;$.each(a.steps,function(f,d){var c=wf.nodes[f];$.each(d.input_connections,function(i,g){if(g){var j=wf.nodes[g.id];var l=new Connector();l.connect(j.output_terminals[g.output_name],c.input_terminals[i]);l.redraw()}})})},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.clear_active_node();parent.show_form_for_tool(a.form
_html,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){parent.show_form_for_tool(a.form_html,a)}},layout:function(){var a={};var b={};$.each(this.nodes,function(i,g){if(a[i]===undefined){a[i]=0}if(b[i]===undefined){b[i]=[]}});$.each(this.nodes,function(i,g){$.each(g.input_terminals,function(k,l){$.each(l.connectors,function(m,n){var j=n.handle1.node;a[g.id]+=1;b[j.id].push(g.id)})})});node_ids_by_level=[];while(true){level_parents=[];$.each(a,function(i,g){if(g==0){level_parents.push(i)}});if(level_parents.length==0){break}node_ids_by_level.push(level_parents);$.each(level_parents,function(i,g){delete a[g];$.each(b[g],function(k,j){a[j]-=1})})}if(a.length){return}var d=this.nodes;var c=80;v_pad=30;var f=c;$.each(node_ids_by_level,function(g,j){j.sort(function(m,i){return $(d[m].element).position().top-$(d[i].element).position().top});var k=0;var l=v_pad;$.each(j,function(i,o){var n=d[o];var m=$(n.element);$(m).css
({top:l,left:f});k=Math.max(k,$(m).width());l+=$(m).height()+v_pad});f+=k+c});$.each(d,function(g,i){i.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(i,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var j=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var i=fix_delta(a.ymin,100);d=Math.max(d,f.left);i=Math.max(i,f.top);var c=f.left-d;var g=f.top-i;var b=round_up(a.xmax+100,100)+d;var k=round_up(a.ymax+100,100)+i;b=Math.max(b,-c+j.width());k=Math.max(k,-g+j.height());this.canvas_container.css({left:c,top:g,width:b,height:k,});this.canvas_container.children().each(function(){var l=$(this).position();$(this).css("left",l.left+d);$(this).css("top",l.top+i)})}});func
tion fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(m,k,s){var j=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node(j);g.type=m;if(m=="tool"){g.tool_id=s}var q=$("<div class='toolFormTitle unselectable'>"+k+"</div>");j.append(q);j.css("left",$(window).scrollLeft()+20);j.css("top",$(window).scrollTop()+20);var n=$("<div class='toolFormBody'></div>");var i="<div><img height='16' align='middle' src='../images/loading_small_white_bg.gif'/> loading tool info...</div>";n.append(i);g.form_html=i;j.append(n);var l=$("<div class='buttons' style='float: right;'></div>");l.append($("<img src='../images/delete_icon.png' />").click(function(b){g.destroy()}).hover(function(){$(this).attr("src","../images/delete_icon_dark.png")},function(){$(this).attr("src","../images/delete_icon.png")}));j.appendTo("#canvas-container");var d=$("#canvas-container").position(
);var c=$("#canvas-container").parent();var a=j.width();var r=j.height();j.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(r/2)});l.prependTo(q);a+=(l.width()+10);j.css("width",a);$(j).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o){var f=$(this).offsetParent().offset(),b=o.offsetX-f.left,p=o.offsetY-f.top;$(this).css({left:b,top:p});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(f,c){clearTim
eout(this.timeout);var a=f.pageX,g=f.pageY;b=$(this.panel),panel_pos=b.position(),panel_w=b.width(),panel_h=b.height();viewport=b.parent();viewport_w=viewport.width(),viewport_h=viewport.height(),viewport_offset=viewport.offset(),min_x=viewport_offset.left,min_y=viewport_offset.top,max_x=min_x+viewport.width(),max_y=min_y+viewport.height(),p_min_x=-(panel_w-(viewport_w/2)),p_min_y=-(panel_h-(viewport_h/2)),p_max_x=(viewport_w/2),p_max_y=(viewport_h/2),moved=false,close_dist=5,nudge=23;if(a-close_dist<min_x){if(panel_pos.left<p_max_x){var d=Math.min(nudge,p_max_x-panel_pos.left);b.css("left",panel_pos.left+d);moved=true}}else{if(a+close_dist>max_x){if(panel_pos.left>p_min_x){var d=Math.min(nudge,panel_pos.left-p_min_x);b.css("left",panel_pos.left-d);moved=true}}else{if(g-close_dist<min_y){if(panel_pos.top<p_max_y){var d=Math.min(nudge,p_max_y-panel_pos.top);b.css("top",panel_pos.top+d);moved=true}}else{if(g+close_dist>max_y){if(panel_pos.top>p_min_y){var d=Math.min(nudge,pane
l_pos.top-p_min_x);b.css("top",(panel_pos.top-d)+"px");moved=true}}}}}if(moved){c();var b=this;this.timeout=setTimeout(function(){b.test(f,c)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(g){var i=$(this).offset();var f=b.cc.position();c=f.top-i.top;d=f.left-i.left}).bind("drag",function(f){a(f.offsetX+d,f.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("dra
g",function(l){var k=b.cc.width();var g=b.cc.height();var f=b.oc.width();var i=b.oc.height();var j=$(this).offsetParent().offset();var n=l.offsetX-j.left;var m=l.offsetY-j.top;a(-(n/f*k),-(m/i*g))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g){var j=$(this).offsetParent();var i=j.offset();var f=Math.max(j.width()-(g.offsetX-i.left),j.height()-(g.offsetY-i.top));$(this).css({width:f,height:f});b.draw_overview()})},update_viewport_overlay:function(){var b=this.cc;var f=this.cv;var a=this.oc;var c=this.ov;var d=b.width();var k=b.height();var j=a.width();var g=a.height();var i=b.position();c.css({left:-(i.left/d*j),top:-(i.top/k*g),width:(f.width()/d*j)-2,height:(f.height()/k*g)-2})},draw_overview:function(){var k=$("#overview-canvas");var n=k.parent().parent().width();var j=k.get(0).getContext("2d");var d=$("#canvas-container").width();var m=$("#canvas-container").height();var g,a,l,f;var i=this.cv.wi
dth();var b=this.cv.height();if(d<i&&m<b){l=d/i*n;f=(n-l)/2;g=m/b*n;a=(n-g)/2}else{if(d<m){a=0;g=n;l=Math.ceil(g*d/m);f=(n-l)/2}else{l=n;f=0;g=Math.ceil(l*m/d);a=(n-g)/2}}k.parent().css({left:f,top:a,width:l,height:g});k.attr("width",l);k.attr("height",g);j.fillStyle="#D2C099";j.strokeStyle="#D8B365";j.lineWidth=1;$.each(workflow.nodes,function(p,c){var o=$(c.element);position=o.position(),x=position.left/d*l,y=position.top/m*g,w=o.width()/d*l,h=o.height()/m*g;j.fillRect(x,y,w,h);j.strokeRect(x,y,w,h)});this.update_viewport_overlay()}});
\ No newline at end of file
+function Terminal(a){this.element=a;this.connectors=[]}$.extend(Terminal.prototype,{connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}});function OutputTerminal(a,b){Terminal.call(this,a);this.datatype=b}OutputTerminal.prototype=new Terminal();function InputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}InputTerminal.prototype=new Terminal();$.extend(InputTerminal.prototype,{can_accept:function(a){if(this.connectors.length<1){for(var b in this.datatypes){if(a.datatype=="input"){return true}if(issubtype(a.datatype,this.datatypes[b])){return true}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a)
{this.connect(b,a)}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;this.handle1.connect(this);this.handle2=a;this.handle2.connect(this)},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var n=function(c){return $(c).offset().left-d.offset().left};var i=function(c){return $(c).offset().top-d.offset().top};var h=n(this.handle1.element)+5;var g=i(this.handle1.element)+5;var p=n(this.handle2.element)+5;var m=i(this.handle2.element)+5;var f=100;var k=Math.min(h,p);var a=Math.max(h,p);var j=Math.min(g,m);var t=Math.max(g,m);var b=Math.min(Math.max(Math.abs(t-j)/2,100),300);var o=k-f;var s=j-f;var q=a-k+2*f;var l=t-j+2*f;
this.canvas.style.left=o+"px";this.canvas.style.top=s+"px";this.canvas.setAttribute("width",q);this.canvas.setAttribute("height",l);h-=o;g-=s;p-=o;m-=s;var r=this.canvas.getContext("2d");r.lineCap="round";r.strokeStyle=this.outer_color;r.lineWidth=7;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke();r.strokeStyle=this.inner_color;r.lineWidth=5;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{enable_input_terminal:function(d,a,b){var c=this;$(d).each(function(){var f=this.terminal=new InputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dropstart",function(g){g.dragProxy.terminal.connectors[0].inner_color="#BBFFBB"}).bind("dropend",function(g){g.dragProxy.terminal.connectors[0].inner_color="#FFFFFF"}).bind("drop",function(g){(new Connector(g.dragTarget.terminal,g.dropTarget.terminal)).redraw()}).bind("hov
er",function(){if(f.connectors.length>0){var g=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='buttons'></div>").append($("<img src='../images/delete_icon.png' />").click(function(){$.each(f.connectors,function(i,h){h.destroy()});g.remove()}))).bind("mouseleave",function(){$(this).remove()});g.css({top:$(this).offset().top-2,left:$(this).offset().left-g.width(),"padding-right":$(this).width()}).show()}});c.input_terminals[a]=f})},enable_output_terminal:function(d,a,b){var c=this;$(d).each(function(){var g=this;var f=this.terminal=new OutputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dragstart",function(j){var i=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);i.terminal=new OutputTerminal(i);var k=new Connector();k.dragging=true;k.connect(this.terminal,i.terminal);$.dropManage({filter:function(h){return this.terminal.can_accept(f)}}).addClass("input-terminal-active");ret
urn i}).bind("drag",function(i){var h=function(){var k=$(i.dragProxy).offsetParent().offset(),j=i.offsetX-k.left,l=i.offsetY-k.top;$(i.dragProxy).css({left:j,top:l});i.dragProxy.terminal.redraw();canvas_manager.update_viewport_overlay()};h();$("#canvas-container").get(0).scroll_panel.test(i,h)}).bind("dragend",function(h){h.dragProxy.terminal.connectors[0].destroy();$(h.dragProxy).remove();$.dropManage().removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()});c.output_terminals[a]=f})},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b
.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(g){var d=this.element;if(g.type){this.type=g.type}this.name=g.name;this.form_html=g.form_html;this.tool_state=g.tool_state;this.tool_errors=g.tool_errors;if(this.tool_errors){d.addClass("tool-node-error")}else{d.removeClass("tool-node-error")}var c=this;var a=d.find(".toolFormBody");a.find("div").remove();var h=$("<div class='inputs'></div>").appendTo(a);$.each(g.data_inputs,function(j,b){var f=$("<div class='terminal input-terminal'></div>");c.enable_input_terminal(f,b.name,b.extensions);h.append($("<div class='form-row dataRow input-data-row' name='"+b.name+"'>"+b.label+"</div>").prepend(f))});if((g.data_inputs.length>0)&&(g.data_outputs.length>0)){a.append($("<div class='rule'></div>"))}$.each(g.data_outputs,function(k,b){var j=$("<div class='terminal output-terminal'></div>");c.enable_output_terminal(j,b.name,b.extension);var f=b.name;if(b.extension!="input"){f=f+" ("+b.extensio
n+")"}a.append($("<div class='form-row dataRow'>"+f+"</div>").append(j))});workflow.node_changed(this)},update_field_data:function(f){var c=$(this.element),d=this;this.tool_state=f.tool_state;this.form_html=f.form_html;this.tool_errors=f.tool_errors;if(this.tool_errors){c.addClass("tool-node-error")}else{c.removeClass("tool-node-error")}var g=c.find("div.inputs");var b=$("<div class='inputs'></div>");var a=g.find("div.input-data-row");$.each(f.data_inputs,function(k,h){var j=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(j,h.name,h.extensions);g.find("div[name="+h.name+"]").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){j[0].terminal.connectors[0]=i;i.handle2=j[0].terminal}});$(this).remove()});b.append($("<div class='form-row dataRow input-data-row' name='"+h.name+"'>"+h.label+"</div>").prepend(j))});g.replaceWith(b);g.find("div.input-data-row > .terminal").each(function(){this.terminal.destr
oy()});this.changed();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},changed:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},to_simple:function(){var a={};$.each(this.nodes,function(b,d){var f={};$.each(d.input_terminals,function(g,h){f[h.name]=null;$.each(h.connectors,function(j,k){f[h.name]={id:k.ha
ndle1.node.id,output_name:k.handle1.name}})});var c={id:d.id,type:d.type,tool_id:d.tool_id,tool_state:d.tool_state,tool_errors:d.tool_errors,input_connections:f,position:$(d.element).position()};a[d.id]=c});return{steps:a}},from_simple:function(a){wf=this;var b=0;wf.name=a.name;$.each(a.steps,function(f,d){var c=prebuild_node("tool",d.name,d.tool_id);c.init_field_data(d);if(d.position){c.element.css({top:d.position.top,left:d.position.left})}c.id=d.id;wf.nodes[c.id]=c;b=Math.max(b,parseInt(f))});wf.id_counter=b+1;$.each(a.steps,function(f,d){var c=wf.nodes[f];$.each(d.input_connections,function(h,g){if(g){var i=wf.nodes[g.id];var j=new Connector();j.connect(i.output_terminals[g.output_name],c.input_terminals[h]);j.redraw()}})})},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.clear_active_node();parent.show_
form_for_tool(a.form_html,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){parent.show_form_for_tool(a.form_html,a)}},layout:function(){var i={};var b={};$.each(this.nodes,function(l,k){if(i[l]===undefined){i[l]=0}if(b[l]===undefined){b[l]=[]}});$.each(this.nodes,function(l,k){$.each(k.input_terminals,function(m,n){$.each(n.connectors,function(p,q){var o=q.handle1.node;i[k.id]+=1;b[o.id].push(k.id)})})});node_ids_by_level=[];while(true){level_parents=[];for(var a in i){if(i[a]==0){level_parents.push(a)}}if(level_parents.length==0){break}node_ids_by_level.push(level_parents);for(var f in level_parents){var j=level_parents[f];delete i[j];for(var g in b[j]){i[sucessors[j][g]]-=1}}}if(i.length){return}var d=this.nodes;var h=80;v_pad=30;var c=h;$.each(node_ids_by_level,function(k,l){l.sort(function(p,o){return $(d[p].element).position().top-$(d[o].element).position().top});var m=0;var n=v_pad;$.each(l,function(o,r){var
q=d[r];var p=$(q.element);$(p).css({top:n,left:c});m=Math.max(m,$(p).width());n+=$(p).height()+v_pad});c+=m+h});$.each(d,function(k,l){l.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(h,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var i=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var h=fix_delta(a.ymin,100);d=Math.max(d,f.left);h=Math.max(h,f.top);var c=f.left-d;var g=f.top-h;var b=round_up(a.xmax+100,100)+d;var j=round_up(a.ymax+100,100)+h;b=Math.max(b,-c+i.width());j=Math.max(j,-g+i.height());this.canvas_container.css({left:c,top:g,width:b,height:j});this.canvas_container.children().each(function(){var k=$(this).position();$(this).css("left",k.left+d);$(
this).css("top",k.top+h)})}});function fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(l,j,r){var i=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node(i);g.type=l;if(l=="tool"){g.tool_id=r}var n=$("<div class='toolFormTitle unselectable'>"+j+"</div>");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("<div class='toolFormBody'></div>");var h="<div><img height='16' align='middle' src='../images/loading_small_white_bg.gif'/> loading tool info...</div>";m.append(h);g.form_html=h;i.append(m);var k=$("<div class='buttons' style='float: right;'></div>");k.append($("<img src='../images/delete_icon.png' />").click(function(b){g.destroy()}).hover(function(){$(this).attr("src","../images/delete_icon_dark.png")},function(){$(this).attr("src","../images/delete_icon.png")}));i.appendTo("#canvas-container");var
d=$("#canvas-container").position();var c=$("#canvas-container").parent();var a=i.width();var q=i.height();i.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(q/2)});k.prependTo(n);a+=(k.width()+10);i.css("width",a);$(i).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o){var f=$(this).offsetParent().offset(),b=o.offsetX-f.left,p=o.offsetY-f.top;$(this).css({left:b,top:p});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prot
otype,{test:function(v,d){clearTimeout(this.timeout);var k=v.pageX,j=v.pageY,l=$(this.panel),c=l.position(),b=l.width(),i=l.height(),w=l.parent(),s=w.width(),a=w.height(),r=w.offset(),p=r.left,m=r.top,A=p+w.width(),u=m+w.height(),B=-(b-(s/2)),z=-(i-(a/2)),g=(s/2),f=(a/2),h=false,q=5,o=23;if(k-q<p){if(c.left<g){var n=Math.min(o,g-c.left);l.css("left",c.left+n);h=true}}else{if(k+q>A){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-q<m){if(c.top<f){var n=Math.min(o,f-c.top);l.css("top",c.top+n);h=true}}else{if(j+q>u){if(c.top>z){var n=Math.min(o,c.top-B);l.css("top",(c.top-n)+"px");h=true}}}}}if(h){d();var l=this;this.timeout=setTimeout(function(){l.test(v,d)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;
var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(g){var h=$(this).offset();var f=b.cc.position();c=f.top-h.top;d=f.left-h.left}).bind("drag",function(f){a(f.offsetX+d,f.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("drag",function(k){var j=b.cc.width(),g=b.cc.height(),f=b.oc.width(),h=b.oc.height(),i=$(this).offsetParent().offset(),m=k.offsetX-i.left,l=k.offsetY-i.top;a(-(m/f*j),-(l/h*g))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g){var i=$(this).offsetParent();var h=i.offset();var f=Math.max(i.width()-(g.offsetX-h.left),i.height()-(g.offsetY-h.top));$(this).css({wi
dth:f,height:f});b.draw_overview()})},update_viewport_overlay:function(){var b=this.cc,f=this.cv,a=this.oc,c=this.ov,d=b.width(),j=b.height(),i=a.width(),g=a.height(),h=b.position();c.css({left:-(h.left/d*i),top:-(h.top/j*g),width:(f.width()/d*i)-2,height:(f.height()/j*g)-2})},draw_overview:function(){var j=$("#overview-canvas"),m=j.parent().parent().width(),i=j.get(0).getContext("2d"),d=$("#canvas-container").width(),l=$("#canvas-container").height();var g,a,k,f;var h=this.cv.width();var b=this.cv.height();if(d<h&&l<b){k=d/h*m;f=(m-k)/2;g=l/b*m;a=(m-g)/2}else{if(d<l){a=0;g=m;k=Math.ceil(g*d/l);f=(m-k)/2}else{k=m;f=0;g=Math.ceil(k*l/d);a=(m-g)/2}}j.parent().css({left:f,top:a,width:k,height:g});j.attr("width",k);j.attr("height",g);i.fillStyle="#D2C099";i.strokeStyle="#D8B365";i.lineWidth=1;$.each(workflow.nodes,function(t,q){var s=$(q.element),n=s.position(),c=n.left/d*k,r=n.top/l*g,o=s.width()/d*k,p=s.height()/l*g;i.fillRect(c,r,o,p);i.strokeRect(c,r,o,p)});this.update_viewp
ort_overlay()}});
\ No newline at end of file
1
0
15 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/249f0037dea2
changeset: 2472:249f0037dea2
user: rc
date: Fri Jul 10 13:52:20 2009 -0400
description:
Fixed form_definition foreign key so that the unittest will pass. Nothing needed for migration script
1 file(s) affected in this change:
lib/galaxy/model/mapping.py
diffs (17 lines):
diff -r b46f27137744 -r 249f0037dea2 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py Fri Jul 10 11:37:28 2009 -0400
+++ b/lib/galaxy/model/mapping.py Fri Jul 10 13:52:20 2009 -0400
@@ -535,7 +535,12 @@
Column( "update_time", DateTime, default=now, onupdate=now ),
Column( "name", TrimmedString( 255 ), nullable=False ),
Column( "desc", TEXT ),
- Column( "form_definition_current_id", Integer, ForeignKey( "form_definition_current.id" ), index=True ),
+ Column( "form_definition_current_id",
+ Integer,
+ ForeignKey( "form_definition_current.id",
+ name='for_def_form_def_current_id_fk',
+ use_alter=True),
+ index=True ),
Column( "fields", JSONType()))
RequestType.table = Table('request_type', metadata,
1
0
15 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/615a0bcf870b
changeset: 2474:615a0bcf870b
user: rc
date: Fri Jul 10 15:24:01 2009 -0400
description:
Fixed another bug in saving special characters in forms
1 file(s) affected in this change:
lib/galaxy/web/controllers/forms.py
diffs (25 lines):
diff -r f7bdfd409b7d -r 615a0bcf870b lib/galaxy/web/controllers/forms.py
--- a/lib/galaxy/web/controllers/forms.py Fri Jul 10 14:50:17 2009 -0400
+++ b/lib/galaxy/web/controllers/forms.py Fri Jul 10 15:24:01 2009 -0400
@@ -152,7 +152,7 @@
def __get_field(self, params, index):
name = util.restore_text( params.get( 'field_name_%i' % index, None ) )
helptext = util.restore_text( params.get( 'field_helptext_%i' % index, None ) )
- required = util.restore_text( params.get( 'field_required_%i' % index, False ) )
+ required = params.get( 'field_required_%i' % index, False )
field_type = util.restore_text( params.get( 'field_type_%i' % index, None ) )
if field_type == 'SelectField':
selectlist = self.__get_selectbox_options(params, index)
@@ -172,10 +172,10 @@
ctr=0
sb_options = []
while True:
- option = util.restore_text( params.get( 'field_'+str(index)+'_option_'+str(ctr), None ) )
+ option = params.get( 'field_'+str(index)+'_option_'+str(ctr), None )
ctr = ctr+1
if option:
- sb_options.append(option)
+ sb_options.append(util.restore_text(option))
else:
return sb_options
def __get_saved_form(self, fd):
1
0
15 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/f7bdfd409b7d
changeset: 2473:f7bdfd409b7d
user: rc
date: Fri Jul 10 14:50:17 2009 -0400
description:
Fixed a bug in form editing where some characters where not appearing correctly when the form is saved.
3 file(s) affected in this change:
lib/galaxy/web/controllers/admin.py
lib/galaxy/web/controllers/forms.py
lib/galaxy/web/controllers/requests.py
diffs (98 lines):
diff -r 249f0037dea2 -r f7bdfd409b7d lib/galaxy/web/controllers/admin.py
--- a/lib/galaxy/web/controllers/admin.py Fri Jul 10 13:52:20 2009 -0400
+++ b/lib/galaxy/web/controllers/admin.py Fri Jul 10 14:50:17 2009 -0400
@@ -2188,10 +2188,10 @@
msg=msg,
messagetype=messagetype )
def _save_request_type(self, trans, params, request_type_id):
- num_states = int( params.get( 'num_states', 0 ) )
+ num_states = int( util.restore_text( params.get( 'num_states', 0 ) ))
proceed = True
for i in range( num_states ):
- if not params.get( 'new_element_name_%i' % i, None ):
+ if not util.restore_text( params.get( 'new_element_name_%i' % i, None ) ):
proceed = False
break
if not proceed:
@@ -2212,8 +2212,8 @@
ss.delete()
ss.flush()
for i in range( num_states ):
- name = params.get( 'new_element_name_%i' % i, None )
- desc = params.get( 'new_element_description_%i' % i, None )
+ name = util.restore_text( params.get( 'new_element_name_%i' % i, None ))
+ desc = util.restore_text( params.get( 'new_element_description_%i' % i, None ))
ss = trans.app.model.SampleState(name, desc, rt.id)
ss.flush()
msg = "The new sample type named '%s' with %s state(s) has been created" % (rt.name, num_states)
diff -r 249f0037dea2 -r f7bdfd409b7d lib/galaxy/web/controllers/forms.py
--- a/lib/galaxy/web/controllers/forms.py Fri Jul 10 13:52:20 2009 -0400
+++ b/lib/galaxy/web/controllers/forms.py Fri Jul 10 14:50:17 2009 -0400
@@ -150,10 +150,10 @@
'selectlist': '' }
self.current_form['fields'].append(empty_field)
def __get_field(self, params, index):
- name = params.get( 'field_name_%i' % index, None )
- helptext = params.get( 'field_helptext_%i' % index, None )
- required = params.get( 'field_required_%i' % index, False )
- field_type = params.get( 'field_type_%i' % index, None )
+ name = util.restore_text( params.get( 'field_name_%i' % index, None ) )
+ helptext = util.restore_text( params.get( 'field_helptext_%i' % index, None ) )
+ required = util.restore_text( params.get( 'field_required_%i' % index, False ) )
+ field_type = util.restore_text( params.get( 'field_type_%i' % index, None ) )
if field_type == 'SelectField':
selectlist = self.__get_selectbox_options(params, index)
else:
@@ -172,7 +172,7 @@
ctr=0
sb_options = []
while True:
- option = params.get( 'field_'+str(index)+'_option_'+str(ctr), None )
+ option = util.restore_text( params.get( 'field_'+str(index)+'_option_'+str(ctr), None ) )
ctr = ctr+1
if option:
sb_options.append(option)
@@ -194,7 +194,7 @@
return None, 'Form name must be filled.'
# fields
for i in range( len(self.current_form['fields']) ):
- if not params.get( 'field_name_%i' % i, None ):
+ if not util.restore_text(params.get( 'field_name_%i' % i, None )):
return None, "All the field label(s) must be completed."
return True, ''
def __get_form(self, params):
diff -r 249f0037dea2 -r f7bdfd409b7d lib/galaxy/web/controllers/requests.py
--- a/lib/galaxy/web/controllers/requests.py Fri Jul 10 13:52:20 2009 -0400
+++ b/lib/galaxy/web/controllers/requests.py Fri Jul 10 14:50:17 2009 -0400
@@ -212,12 +212,12 @@
request = trans.app.model.Request.get(request_id)
form_values = trans.app.model.FormValues.get(request.form_values_id)
request_form = trans.app.model.FormDefinition.get(form_values.request_form_id)
- name = params.get('name', '')
- desc = params.get('desc', '')
- library_id = params.get('library', '')
+ name = util.restore_text(params.get('name', ''))
+ desc = util.restore_text(params.get('desc', ''))
+ library_id = util.restore_text(params.get('library', ''))
values = {}
for field in request_form.fields:
- values[field['label']] = params.get(field['label'], '')
+ values[field['label']] = util.restore_text(params.get(field['label'], ''))
if not request_id:
form_values = trans.app.model.FormValues(request_form_id, values)
form_values.flush()
@@ -348,11 +348,11 @@
sample = trans.app.model.Sample.get(sample_id)
form_data = trans.app.model.FormData.get(sample.form_data_id)
form = trans.app.model.FormDefinition.get(form_data.form_definition_id)
- name = params.get('name', '')
- desc = params.get('desc', '')
+ name = util.restore_text(params.get('name', ''))
+ desc = util.restore_text(params.get('desc', ''))
values = {}
for field in sample_form.fields:
- values[field['label']] = params.get(field['label'], '')
+ values[field['label']] = util.restore_text(params.get(field['label'], ''))
if not sample_id:
form_values = trans.app.model.FormValues(sample_form.id, values)
form_values.flush()
1
0
15 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/b46f27137744
changeset: 2471:b46f27137744
user: rc
date: Fri Jul 10 11:37:28 2009 -0400
description:
First pass of the new Galaxy forms components including requests which based on form definitions and samples.
40 file(s) affected in this change:
lib/galaxy/model/__init__.py
lib/galaxy/model/mapping.py
lib/galaxy/model/migrate/versions/0008_galaxy_forms.py
lib/galaxy/web/controllers/admin.py
lib/galaxy/web/controllers/forms.py
lib/galaxy/web/controllers/requests.py
lib/galaxy/web/controllers/requests_admin.py
lib/galaxy/web/form_builder.py
lib/galaxy/web/framework/__init__.py
run_functional_tests.sh
templates/admin/forms/create_form.mako
templates/admin/forms/edit_form.mako
templates/admin/forms/manage_forms.mako
templates/admin/forms/show_form_read_only.mako
templates/admin/index.mako
templates/admin/requests/add_states.mako
templates/admin/requests/create_request_type.mako
templates/admin/requests/edit_request_type.mako
templates/admin/requests/grid.mako
templates/admin/requests/manage_request_types.mako
templates/admin/requests/view_request.mako
templates/admin/samples/change_state.mako
templates/admin/samples/edit_sample.mako
templates/admin/samples/events.mako
templates/admin/samples/grid.mako
templates/admin/samples/view_sample.mako
templates/base.mako
templates/base_panels.mako
templates/requests/grid.mako
templates/requests/index.mako
templates/requests/new_request.mako
templates/requests/select_request_type.mako
templates/requests/view_request.mako
templates/sample/browse_samples.mako
templates/sample/edit_sample.mako
templates/sample/grid.mako
templates/sample/index.mako
templates/sample/new_sample.mako
templates/sample/sample_events.mako
templates/sample/view_sample.mako
diffs (truncated from 3714 to 3000 lines):
diff -r 267db48a2371 -r b46f27137744 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py Thu Jul 09 15:49:26 2009 -0400
+++ b/lib/galaxy/model/__init__.py Fri Jul 10 11:37:28 2009 -0400
@@ -14,6 +14,7 @@
import galaxy.datatypes.registry
from galaxy.datatypes.metadata import MetadataCollection
from galaxy.security import RBACAgent, get_permitted_actions
+
import logging
log = logging.getLogger( __name__ )
@@ -1095,6 +1096,58 @@
raise
# Return filename inside hashed directory
return os.path.abspath( os.path.join( path, "metadata_%d.dat" % self.id ) )
+
+
+class FormDefinition( object ):
+ def __init__(self, name=None, desc=None, fields=[], current_form_id=None):
+ self.name = name
+ self.desc = desc
+ self.fields = fields
+ self.form_definition_current_id = current_form_id
+
+class FormDefinitionCurrent( object ):
+ def __init__(self, form_definition_id=None):
+ self.latest_form_id = form_definition_id
+
+class FormValues( object ):
+ def __init__(self, form_def_id=None, content=None):
+ self.form_definition_id = form_def_id
+ self.content = content
+
+class Request( object ):
+ def __init__(self, name=None, desc=None, request_type_id=None, user_id=None, form_values_id=None, library_id=None):
+ self.name = name
+ self.desc = desc
+ self.request_type_id = request_type_id
+ self.form_values_id = form_values_id
+ self.user_id = user_id
+ self.library_id = library_id
+
+class RequestType( object ):
+ def __init__(self, request_form_id=None, sample_form_id=None):
+ self.request_form_id = request_form_id
+ self.sample_form_id = sample_form_id
+
+class Sample( object ):
+ def __init__(self, name=None, desc=None, request_id=None, form_values_id=None):
+ self.name = name
+ self.desc = desc
+ self.request_id = request_id
+ self.form_values_id = form_values_id
+
+class SampleState( object ):
+ def __init__(self, name=None, desc=None, request_type_id=None):
+ self.name = name
+ self.desc = desc
+ self.request_type_id = request_type_id
+
+class SampleEvent( object ):
+ def __init__(self, sample_id=None, sample_state_id=None, comment=''):
+ self.sample_id = sample_id
+ self.sample_state_id = sample_state_id
+ self.comment = comment
+
+
## ---- Utility methods -------------------------------------------------------
diff -r 267db48a2371 -r b46f27137744 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py Thu Jul 09 15:49:26 2009 -0400
+++ b/lib/galaxy/model/mapping.py Fri Jul 10 11:37:28 2009 -0400
@@ -520,8 +520,114 @@
Column( "deleted", Boolean, index=True, default=False ),
Column( "purged", Boolean, index=True, default=False ) )
+
+FormDefinitionCurrent.table = Table('form_definition_current', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "latest_form_id", Integer, ForeignKey( "form_definition.id" ), index=True ),
+ Column( "deleted", Boolean, index=True, default=False ))
+
+# new table to store all the forms which is created by the admin
+FormDefinition.table = Table('form_definition', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "name", TrimmedString( 255 ), nullable=False ),
+ Column( "desc", TEXT ),
+ Column( "form_definition_current_id", Integer, ForeignKey( "form_definition_current.id" ), index=True ),
+ Column( "fields", JSONType()))
+
+RequestType.table = Table('request_type', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "name", TrimmedString( 255 ), nullable=False ),
+ Column( "desc", TEXT ),
+ Column( "request_form_id", Integer, ForeignKey( "form_definition.id" ), index=True ),
+ Column( "sample_form_id", Integer, ForeignKey( "form_definition.id" ), index=True ) )
+
+FormValues.table = Table('form_values', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "form_definition_id", Integer, ForeignKey( "form_definition.id" ), index=True ),
+ Column( "content", JSONType()) )
+
+Request.table = Table('request', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "name", TrimmedString( 255 ), nullable=False ),
+ Column( "desc", TEXT ),
+ Column( "form_values_id", Integer, ForeignKey( "form_values.id" ), index=True ),
+ Column( "request_type_id", Integer, ForeignKey( "request_type.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "library_id", Integer, ForeignKey( "library.id" ), index=True ),
+ Column( "deleted", Boolean, index=True, default=False ) )
+
+Sample.table = Table('sample', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "name", TrimmedString( 255 ), nullable=False ),
+ Column( "desc", TEXT ),
+ Column( "form_values_id", Integer, ForeignKey( "form_values.id" ), index=True ),
+ Column( "request_id", Integer, ForeignKey( "request.id" ), index=True ),
+ Column( "deleted", Boolean, index=True, default=False ) )
+
+# new table to store all the possible sample states and the sample type it
+# belongs to
+SampleState.table = Table('sample_state', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "name", TrimmedString( 255 ), nullable=False ),
+ Column( "desc", TEXT ),
+ Column( "request_type_id", Integer, ForeignKey( "request_type.id" ), index=True ) )
+
+SampleEvent.table = Table('sample_event', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "sample_id", Integer, ForeignKey( "sample.id" ), index=True ),
+ Column( "sample_state_id", Integer, ForeignKey( "sample_state.id" ), index=True ),
+ Column( "comment", TEXT ) )
+
+
+
# With the tables defined we can define the mappers and setup the
# relationships between the model objects.
+
+assign_mapper( context, Sample, Sample.table,
+ properties=dict( events=relation( SampleEvent, backref="sample",
+ order_by=desc(SampleEvent.table.c.update_time) ),
+ ) )
+
+assign_mapper( context, FormValues, FormValues.table, properties=None)
+
+assign_mapper( context, Request, Request.table, properties=None)
+
+assign_mapper( context, RequestType, RequestType.table,
+ properties=dict( states=relation( SampleState, backref="request_type",
+ order_by=desc(SampleState.table.c.update_time) ),
+ ) )
+
+assign_mapper( context, FormDefinition, FormDefinition.table, properties=None)
+
+assign_mapper( context, FormDefinitionCurrent, FormDefinitionCurrent.table,
+ properties=dict( forms=relation( FormDefinition, backref='form_definition_current',
+ cascade="all, delete-orphan",
+ primaryjoin=( FormDefinitionCurrent.table.c.id == FormDefinition.table.c.form_definition_current_id ) ),
+ latest_form=relation( FormDefinition, post_update=True,
+ primaryjoin=( FormDefinitionCurrent.table.c.latest_form_id == FormDefinition.table.c.id ) )
+ ) )
+
+assign_mapper( context, SampleEvent, SampleEvent.table, properties=None)
+
+assign_mapper( context, SampleState, SampleState.table,
+ properties=None #dict( sample=relation( Sample, backref="sample" ),
+ )# )
assign_mapper( context, ValidationError, ValidationError.table )
@@ -590,6 +696,8 @@
assign_mapper( context, User, User.table,
properties=dict( histories=relation( History, backref="user",
order_by=desc(History.table.c.update_time) ),
+ requests=relation( Request, backref="user",
+ order_by=desc(Request.table.c.update_time) ),
active_histories=relation( History, primaryjoin=( ( History.table.c.user_id == User.table.c.id ) & ( not_( History.table.c.deleted ) ) ), order_by=desc( History.table.c.update_time ) ),
galaxy_sessions=relation( GalaxySession, order_by=desc( GalaxySession.table.c.update_time ) ),
stored_workflow_menu_entries=relation( StoredWorkflowMenuEntry, backref="user",
diff -r 267db48a2371 -r b46f27137744 lib/galaxy/model/migrate/versions/0008_galaxy_forms.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/model/migrate/versions/0008_galaxy_forms.py Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,189 @@
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from sqlalchemy.exceptions import *
+from migrate import *
+from migrate.changeset import *
+
+import datetime
+now = datetime.datetime.utcnow
+
+import sys, logging
+log = logging.getLogger( __name__ )
+log.setLevel(logging.DEBUG)
+handler = logging.StreamHandler( sys.stdout )
+format = "%(name)s %(levelname)s %(asctime)s %(message)s"
+formatter = logging.Formatter( format )
+handler.setFormatter( formatter )
+log.addHandler( handler )
+
+# Need our custom types, but don't import anything else from model
+from galaxy.model.custom_types import *
+
+metadata = MetaData( migrate_engine )
+db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, transactional=False ) )
+
+
+FormDefinitionCurrent_table = Table('form_definition_current', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "latest_form_id", Integer,
+ #ForeignKey( "form_definition.id", use_alter=True, name='form_definition_current_latest_form_id_fk'),
+ index=True ),
+ Column( "deleted", Boolean, index=True, default=False ))
+FormDefinition_table = Table('form_definition', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "name", TrimmedString( 255 ), nullable=False ),
+ Column( "desc", TEXT ),
+ Column( "form_definition_current_id", Integer, ForeignKey( "form_definition_current.id" ), index=True, nullable=False ),
+ Column( "fields", JSONType()) )
+
+FormValues_table = Table('form_values', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "form_definition_id", Integer, ForeignKey( "form_definition.id" ), index=True ),
+ Column( "content", JSONType()) )
+
+RequestType_table = Table('request_type', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "name", TrimmedString( 255 ), nullable=False ),
+ Column( "desc", TEXT ),
+ Column( "request_form_id", Integer, ForeignKey( "form_definition.id" ), index=True ),
+ Column( "sample_form_id", Integer, ForeignKey( "form_definition.id" ), index=True ) )
+# request table
+Request_table = Table('request', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "name", TrimmedString( 255 ), nullable=False ),
+ Column( "desc", TEXT ),
+ Column( "form_values_id", Integer, ForeignKey( "form_values.id" ), index=True ),
+ Column( "request_type_id", Integer, ForeignKey( "request_type.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "library_id", Integer, ForeignKey( "library.id" ), index=True ),
+ Column( "deleted", Boolean, index=True, default=False ) )
+
+Sample_table = Table('sample', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "name", TrimmedString( 255 ), nullable=False ),
+ Column( "desc", TEXT ),
+ Column( "form_values_id", Integer, ForeignKey( "form_values.id" ), index=True ),
+ Column( "request_id", Integer, ForeignKey( "request.id" ), index=True ),
+ Column( "deleted", Boolean, index=True, default=False ) )
+
+SampleState_table = Table('sample_state', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "name", TrimmedString( 255 ), nullable=False ),
+ Column( "desc", TEXT ),
+ Column( "request_type_id", Integer, ForeignKey( "request_type.id" ), index=True ) )
+
+SampleEvent_table = Table('sample_event', metadata,
+ Column( "id", Integer, primary_key=True),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "sample_id", Integer, ForeignKey( "sample.id" ), index=True ),
+ Column( "sample_state_id", Integer, ForeignKey( "sample_state.id" ), index=True ),
+ Column( "comment", TEXT ) )
+
+
+
+
+def upgrade():
+ # Load existing tables
+ metadata.reflect()
+
+ # Add all of the new tables above
+# metadata.create_all()
+ try:
+ FormDefinitionCurrent_table.create()
+ except Exception, e:
+ log.debug( "Creating form_definition_current table failed: %s" % str( e ) )
+ try:
+ FormDefinition_table.create()
+ except Exception, e:
+ log.debug( "Creating form_definition table failed: %s" % str( e ) )
+ # Add 1 foreign key constraint to the form_definition_current table
+ if FormDefinitionCurrent_table and FormDefinition_table:
+ try:
+ cons = ForeignKeyConstraint( [FormDefinitionCurrent_table.c.latest_form_id],
+ [FormDefinition_table.c.id],
+ name='form_definition_current_latest_form_id_fk' )
+ # Create the constraint
+ cons.create()
+ except Exception, e:
+ log.debug( "Adding foreign key constraint 'form_definition_current_latest_form_id_fk' to table 'form_definition_current' failed: %s" % ( str( e ) ) )
+ try:
+ FormValues_table.create()
+ except Exception, e:
+ log.debug( "Creating form_values table failed: %s" % str( e ) )
+ try:
+ RequestType_table.create()
+ except Exception, e:
+ log.debug( "Creating request_type table failed: %s" % str( e ) )
+ try:
+ Request_table.create()
+ except Exception, e:
+ log.debug( "Creating request table failed: %s" % str( e ) )
+ try:
+ Sample_table.create()
+ except Exception, e:
+ log.debug( "Creating sample table failed: %s" % str( e ) )
+ try:
+ SampleState_table.create()
+ except Exception, e:
+ log.debug( "Creating sample_state table failed: %s" % str( e ) )
+ try:
+ SampleEvent_table.create()
+ except Exception, e:
+ log.debug( "Creating sample_event table failed: %s" % str( e ) )
+
+
+
+def downgrade():
+ # Load existing tables
+ metadata.reflect()
+ try:
+ FormDefinition_table.drop()
+ except Exception, e:
+ log.debug( "Dropping form_definition table failed: %s" % str( e ) )
+ try:
+ FormDefinitionCurrent_table.drop()
+ except Exception, e:
+ log.debug( "Dropping form_definition_current table failed: %s" % str( e ) )
+ try:
+ FormValues_table.drop()
+ except Exception, e:
+ log.debug( "Dropping form_values table failed: %s" % str( e ) )
+ try:
+ Request_table.drop()
+ except Exception, e:
+ log.debug( "Dropping request table failed: %s" % str( e ) )
+ try:
+ RequestType_table.drop()
+ except Exception, e:
+ log.debug( "Dropping request_type table failed: %s" % str( e ) )
+ try:
+ Sample_table.drop()
+ except Exception, e:
+ log.debug( "Dropping sample table failed: %s" % str( e ) )
+ try:
+ SampleState_table.drop()
+ except Exception, e:
+ log.debug( "Dropping sample_state table failed: %s" % str( e ) )
+ try:
+ SampleEvent_table.drop()
+ except Exception, e:
+ log.debug( "Dropping sample_event table failed: %s" % str( e ) )
+
+
+
+
diff -r 267db48a2371 -r b46f27137744 lib/galaxy/web/controllers/admin.py
--- a/lib/galaxy/web/controllers/admin.py Thu Jul 09 15:49:26 2009 -0400
+++ b/lib/galaxy/web/controllers/admin.py Fri Jul 10 11:37:28 2009 -0400
@@ -3,6 +3,7 @@
from galaxy import util, datatypes
from galaxy.web.base.controller import *
from galaxy.model.orm import *
+import sys
import logging
log = logging.getLogger( __name__ )
@@ -2097,4 +2098,123 @@
else:
last_updated[job.id] = '%s minutes' % int( delta.seconds / 60 )
return trans.fill_template( '/admin/jobs.mako', jobs = jobs, last_updated = last_updated, cutoff = cutoff, msg = msg, messagetype = messagetype )
-
+
+ def _get_all_forms(self, trans, all_versions=False):
+ '''
+ This method returns all the latest forms from the
+ form_definition_current table if all_versions is set to True. Otherwise
+ this method return all the versions of all the forms from form_definition
+ table
+ '''
+ if all_versions:
+ return trans.app.model.FormDefinition.query().all()
+ else:
+ fdc_list = trans.app.model.FormDefinitionCurrent.query().all()
+ return [fdc.latest_form for fdc in fdc_list]
+ @web.expose
+ @web.require_admin
+ def manage_request_types( self, trans, **kwd ):
+ params = util.Params( kwd )
+ msg = util.restore_text( params.get( 'msg', '' ) )
+ messagetype = params.get( 'messagetype', 'done' )
+ forms = self._get_all_forms(trans, all_versions=True)
+ return trans.fill_template( '/admin/requests/manage_request_types.mako',
+ request_types=trans.app.model.RequestType.query().all(),
+ forms=forms,
+ deleted=False,
+ show_deleted=False,
+ msg=msg,
+ messagetype=messagetype )
+ @web.expose
+ @web.require_admin
+ def request_type( self, trans, **kwd ):
+ params = util.Params( kwd )
+ msg = util.restore_text( params.get( 'msg', '' ) )
+ messagetype = params.get( 'messagetype', 'done' )
+ if params.get('create', False) == 'True':
+ return trans.fill_template( '/admin/requests/create_request_type.mako',
+ forms=self._get_all_forms(trans, all_versions=False),
+ msg=msg,
+ messagetype=messagetype)
+ elif params.get('add_states', False) == 'True':
+ return trans.fill_template( '/admin/requests/add_states.mako',
+ sample_type_name=util.restore_text( params.name ),
+ desc=util.restore_text( params.description ),
+ num_states=int(util.restore_text( params.num_states )),
+ request_form_id=int(util.restore_text( params.request_form_id )),
+ sample_form_id=int(util.restore_text( params.sample_form_id )),
+ msg=msg,
+ messagetype=messagetype)
+ elif params.get('save_new', False) == 'True':
+ st, msg = self._save_request_type(trans, params, None)
+ if not st:
+ return trans.fill_template( '/admin/requests/create_request_type.mako',
+ forms=self._get_all_forms(trans, all_versions=False),
+ msg=msg,
+ messagetype='error')
+ return trans.fill_template( '/admin/requests/manage_request_types.mako',
+ request_types=trans.app.model.RequestType.query().all(),
+ forms=self._get_all_forms(trans, all_versions=True),
+ deleted=False,
+ show_deleted=False,
+ msg=msg,
+ messagetype=messagetype )
+ elif params.get('edit', False) == 'True':
+ rt = trans.app.model.RequestType.get(int(util.restore_text( params.id )))
+ ss_list = trans.app.model.SampleState.filter(trans.app.model.SampleState.table.c.request_type_id == rt.id).all()
+ return trans.fill_template( '/admin/requests/edit_request_type.mako',
+ request_type=rt,
+ forms=self._get_all_forms(trans, all_versions=False),
+ states_list=ss_list,
+ deleted=False,
+ show_deleted=False,
+ msg=msg,
+ messagetype=messagetype )
+ elif params.get('save_changes', False) == 'True':
+ st = trans.app.model.SampleType.get(int(util.restore_text( params.id )))
+ st, msg = self._save_sample_type(trans, params, st.id)
+ if st:
+ msg = "The sample type '%s' has been updated with the changes." % st.name
+ messagetype = 'done'
+ else:
+ messagetype = 'error'
+ ss_list = trans.app.model.SampleState.filter(trans.app.model.SampleState.table.c.sample_type_id == st.id).all()
+ return trans.fill_template( '/admin/samples/edit_sample_type.mako',
+ sample_type=st,
+ forms=self._get_all_forms(trans, all_versions=False),
+ states_list=ss_list,
+ deleted=False,
+ show_deleted=False,
+ msg=msg,
+ messagetype=messagetype )
+ def _save_request_type(self, trans, params, request_type_id):
+ num_states = int( params.get( 'num_states', 0 ) )
+ proceed = True
+ for i in range( num_states ):
+ if not params.get( 'new_element_name_%i' % i, None ):
+ proceed = False
+ break
+ if not proceed:
+ msg = "All the state name(s) must be completed."
+ return None, msg
+ if not request_type_id: # create a new sample type to save
+ rt = trans.app.model.RequestType()
+ else: # use the existing sample type to save changes
+ rt = trans.app.model.RequestType.get(request_type_id)
+ rt.name = util.restore_text( params.name )
+ rt.desc = util.restore_text( params.description ) or ""
+ rt.request_form_id = int(util.restore_text( params.request_form_id ))
+ rt.sample_form_id = int(util.restore_text( params.sample_form_id ))
+ rt.flush()
+ # set sample states
+ ss_list = trans.app.model.SampleState.filter(trans.app.model.SampleState.table.c.request_type_id == rt.id).all()
+ for ss in ss_list:
+ ss.delete()
+ ss.flush()
+ for i in range( num_states ):
+ name = params.get( 'new_element_name_%i' % i, None )
+ desc = params.get( 'new_element_description_%i' % i, None )
+ ss = trans.app.model.SampleState(name, desc, rt.id)
+ ss.flush()
+ msg = "The new sample type named '%s' with %s state(s) has been created" % (rt.name, num_states)
+ return rt, msg
diff -r 267db48a2371 -r b46f27137744 lib/galaxy/web/controllers/forms.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/web/controllers/forms.py Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,323 @@
+from galaxy.web.base.controller import *
+from galaxy.model.orm import *
+from galaxy.datatypes import sniff
+from galaxy import util
+import logging, os, sys
+from galaxy.web.form_builder import *
+from galaxy.tools.parameters.basic import parameter_types
+from elementtree.ElementTree import XML, Element
+from galaxy.util.odict import odict
+import copy
+
+log = logging.getLogger( __name__ )
+
+
+class Forms( BaseController ):
+ @web.expose
+ @web.require_admin
+ def index( self, trans, **kwd ):
+ params = util.Params( kwd )
+ msg = util.restore_text( params.get( 'msg', '' ) )
+ messagetype = params.get( 'messagetype', 'done' )
+ return trans.fill_template( "/sample/index.mako",
+ default_action=params.get( 'default_action', None ),
+ msg=msg,
+ messagetype=messagetype )
+ @web.expose
+ @web.require_admin
+ def manage( self, trans, **kwd ):
+ params = util.Params( kwd )
+ msg = util.restore_text( params.get( 'msg', '' ) )
+ messagetype = params.get( 'messagetype', 'done' )
+ return self._show_forms_list(trans, msg, messagetype)
+ def _show_forms_list(self, trans, msg, messagetype):
+ fdc_list = trans.app.model.FormDefinitionCurrent.query().all()
+ return trans.fill_template( '/admin/forms/manage_forms.mako',
+ fdc_list=fdc_list,
+ deleted=False,
+ show_deleted=False,
+ msg=msg,
+ messagetype=messagetype )
+ def _get_all_forms(self, trans, all_versions=False):
+ '''
+ This method returns all the latest forms from the
+ form_definition_current table if all_versions is set to True. Otherwise
+ this method return all the versions of all the forms from form_definition
+ table
+ '''
+ if all_versions:
+ return trans.app.model.FormDefinition.query().all()
+ else:
+ fdc_list = trans.app.model.FormDefinitionCurrent.query().all()
+ return [fdc.latest_form for fdc in fdc_list]
+ @web.expose
+ @web.require_admin
+ def new( self, trans, **kwd ):
+ params = util.Params( kwd )
+ msg = util.restore_text( params.get( 'msg', '' ) )
+ messagetype = params.get( 'messagetype', 'done' )
+ if params.get('new', False) and not params.get('create_form', False):
+ self.current_form = {}
+ self.current_form['name'] = 'New Form'
+ self.current_form['desc'] = ''
+ self.current_form['fields'] = []
+ inputs = [ ( 'Name', TextField('name', 40,self.current_form['name'] ) ),
+ ( 'Description', TextField('description', 40, self.current_form['desc']) ) ]
+ return trans.fill_template( '/admin/forms/create_form.mako',
+ inputs=inputs,
+ msg=msg,
+ messagetype=messagetype )
+ elif params.get('create_form', False) == 'True':
+ if 'submitted' in params.new:
+ self.num_add_fields = 0
+ fd, msg = self.__save_form(trans, params)
+ self.__get_saved_form(fd)
+ return self._show_forms_list(trans, msg, messagetype)
+ @web.expose
+ @web.require_admin
+ def edit( self, trans, **kwd ):
+ '''
+ This callback method is for handling all the editing functions like:
+ remaning fields, adding/deleting fields, changing fields attributes
+ '''
+ params = util.Params( kwd )
+ msg = util.restore_text( params.get( 'msg', '' ) )
+ messagetype = params.get( 'messagetype', 'done' )
+ fd = trans.app.model.FormDefinition.get(int(util.restore_text( params.form_id )))
+ # SHOW THE FORM FOR EDITING.
+ if params.get('show_form', False) == 'True':
+ self.__get_saved_form(fd)
+ # the following two dicts store the unsaved select box options
+ self.del_options = {}
+ self.add_options = {}
+ return self.__show(trans, params, fd)
+ # DELETE FIELD
+ elif params.get('remove_button', False):
+ self.__update_current_form(params)
+ index = int(params.get('remove_button', None).split(' ')[2])-1
+ self.__remove_field(index)
+ return self.__show(trans, params, fd)
+ # SAVE CHANGES
+ elif params.get('save_changes_button', False) == 'Save':
+ self.__update_current_form(params)
+ fd_new, msg = self.__save_form(trans, params, fd.form_definition_current.id)
+ if not fd_new:
+ return self.__show(trans, params, fd, msg, 'error')
+ else:
+ fd = fd_new
+ msg = "The form '%s' has been updated with the changes." % fd.name
+ return self.__show(trans, params, fd, msg)
+ #ADD A FIELD
+ elif params.get('add_field_button', False) == 'Add field':
+ self.__update_current_form(params)
+ self.__add_field()
+ # show the form again with one empty field
+ return self.__show(trans, params, fd)
+ # SHOW FORM READ ONLY
+ elif params.get('read_only', False):
+ return trans.fill_template( '/admin/forms/show_form_read_only.mako',
+ form=fd,
+ msg=msg,
+ messagetype=messagetype )
+ # REFRESH PAGE, SelectField is selected/deselected as the type of a field
+ elif params.get('refresh', False) == 'true':
+ self.__update_current_form(params)
+ return self.__show(trans, params, fd)
+ # REMOVE SelectField OPTION
+ elif params.get('select_box_options', False) == 'remove':
+ #self.__update_current_form(params)
+ index = int(params.get( 'field_index', None ))
+ option = int(params.get( 'option_index', None ))
+ del self.current_form['fields'][index]['selectlist'][option]
+ return self.__show(trans, params, fd)
+ # ADD SelectField OPTION
+ elif params.get('select_box_options', False) == 'add':
+ #self.__update_current_form(params)
+ index = int(params.get( 'field_index', None ))
+ self.current_form['fields'][index]['selectlist'].append('')
+ return self.__show(trans, params, fd)
+ def __remove_field(self, index):
+ del self.current_form['fields'][index]
+ def __add_field(self):
+ '''
+ add an empty field to the fields list
+ '''
+ empty_field = { 'label': '',
+ 'helptext': '',
+ 'visible': True,
+ 'required': False,
+ 'type': BaseField.form_field_types()[0],
+ 'selectlist': '' }
+ self.current_form['fields'].append(empty_field)
+ def __get_field(self, params, index):
+ name = params.get( 'field_name_%i' % index, None )
+ helptext = params.get( 'field_helptext_%i' % index, None )
+ required = params.get( 'field_required_%i' % index, False )
+ field_type = params.get( 'field_type_%i' % index, None )
+ if field_type == 'SelectField':
+ selectlist = self.__get_selectbox_options(params, index)
+ else:
+ selectlist = None
+ return {'label': name,
+ 'helptext': helptext,
+ 'visible': True,
+ 'required': required,
+ 'type': field_type,
+ 'selectlist': selectlist }
+ def __get_selectbox_options(self, params, index):
+ '''
+ This method gets all the options entered by the user for field when
+ the fieldtype is SelectField
+ '''
+ ctr=0
+ sb_options = []
+ while True:
+ option = params.get( 'field_'+str(index)+'_option_'+str(ctr), None )
+ ctr = ctr+1
+ if option:
+ sb_options.append(option)
+ else:
+ return sb_options
+ def __get_saved_form(self, fd):
+ self.current_form = {}
+ self.current_form['name'] = fd.name
+ self.current_form['desc'] = fd.desc
+ self.current_form['fields'] = list(copy.deepcopy(fd.fields))
+ def __validate_form(self, params):
+ '''
+ This method checks the following text inputs are filled out by the user
+ - the name of form
+ - name of all the fields
+ '''
+ # form name
+ if not util.restore_text( params.name ):
+ return None, 'Form name must be filled.'
+ # fields
+ for i in range( len(self.current_form['fields']) ):
+ if not params.get( 'field_name_%i' % i, None ):
+ return None, "All the field label(s) must be completed."
+ return True, ''
+ def __get_form(self, params):
+ name = util.restore_text( params.name )
+ desc = util.restore_text( params.description ) or ""
+ # set form fields
+ fields = []
+ for i in range( len(self.current_form['fields']) ):
+ fields.append(self.__get_field(params, i))
+ fields = fields
+ return name, desc, fields
+ def __update_current_form(self, params):
+ name, desc, fields = self.__get_form(params)
+ self.current_form = {}
+ self.current_form['name'] = name
+ self.current_form['desc'] = desc
+ self.current_form['fields'] = fields
+
+ def __save_form(self, trans, params, fdc_id=None):
+ '''
+ This method saves the current form
+ '''
+ # check the form for invalid inputs
+ flag, msg = self.__validate_form(params)
+ if not flag:
+ return None, msg
+ fd = trans.app.model.FormDefinition()
+ fd.name, fd.desc, fd.fields = self.__get_form(params)
+ if fdc_id: # save changes to the existing form
+ # change the pointer in the form_definition_current table to point
+ # to this new record
+ fdc = trans.app.model.FormDefinitionCurrent.get(fdc_id)
+ else: # create a new form
+ fdc = trans.app.model.FormDefinitionCurrent()
+ # create corresponding row in the form_definition_current table
+ fd.form_definition_current = fdc
+ fdc.latest_form = fd
+ trans.sa_session.save_or_update( fdc )
+ trans.sa_session.flush()
+ msg = "The new form named '%s' has been created. " % (fd.name)
+ request_types = trans.app.model.RequestType.query().all()
+ if not request_types:
+ msg = msg + "Now you can create requests to associate with this form."
+ return fd, msg
+
+ class FieldUI(object):
+ def __init__(self, index, field=None, field_type=None):
+ '''
+ This method returns a list of widgets which describes a field. This
+ includes label, helptext, type, & required/optional
+ '''
+ self.index = index
+ self.label = TextField('field_name_'+str(index), 40, '')
+ self.helptext = TextField('field_helptext_'+str(index), 40, '')
+ self.fieldtype = SelectField('field_type_'+str(index),
+ refresh_on_change=True,
+ refresh_on_change_values=['SelectField'])
+ self.selectbox_options = []
+ for ft in BaseField.form_field_types():
+ self.fieldtype.add_option(ft, ft)
+ self.required = SelectField('field_required_'+str(index), display='radio')
+ self.required.add_option('Required', 'true')
+ self.required.add_option('Optional', 'true', selected=True)
+ if field:
+ self.fill(field, field_type)
+ def fill(self, field, field_type=None):
+ # label
+ self.label.value = field['label']
+ # helptext
+ self.helptext.value = field['helptext']
+ # type
+ self.fieldtype = SelectField('field_type_'+str(self.index),
+ refresh_on_change=True,
+ refresh_on_change_values=['SelectField'])
+ if field_type:
+ field['type'] = unicode(field_type)
+ if field_type == 'SelectField' and not field['selectlist']:
+ field['selectlist'] = ['', '']
+ for ft in BaseField.form_field_types():
+ if ft == field['type']:
+ self.fieldtype.add_option(ft, ft, selected=True)
+ if ft == 'SelectField':
+ self.selectbox_ui(field)
+ else:
+ self.fieldtype.add_option(ft, ft)
+ # required/optional
+ if field['required']:
+ self.required = SelectField('required_'+str(self.index), display='radio')
+ self.required.add_option('Required', 'true', selected=True)
+ self.required.add_option('Optional', 'true')
+ def selectbox_ui(self, field):
+ self.selectbox_options = []
+ if field['selectlist']:
+ for ctr, option in enumerate(field['selectlist']):
+ self.selectbox_options.append(('Option '+str(ctr+1),
+ TextField('field_'+str(self.index)+'_option_'+str(ctr),
+ 40, option)))
+ def get(self):
+ return [( 'Label', self.label ),
+ ( 'Help text', self.helptext ),
+ ( 'Type', self.fieldtype, self.selectbox_options),
+ ( '', self.required)]
+ def __repr__(self):
+ return str(self.index)+'.'+self.label
+ def label(self):
+ return str(self.index)+'.'+self.label
+
+ def __show(self, trans, params, form, msg=None, messagetype='done'):
+ '''
+ This method displays the form and any of the changes made to it
+ '''
+ # name & description
+ form_details = [ ( 'Name', TextField('name', 40, self.current_form['name']) ),
+ ( 'Description', TextField('description', 40, self.current_form['desc']) ) ]
+ # fields
+ field_details = []
+ for index, field in enumerate(self.current_form['fields']):
+ field_ui = self.FieldUI(index, field)
+ field_details.append( field_ui.get() )
+ return trans.fill_template( '/admin/forms/edit_form.mako',
+ form_details=form_details,
+ field_details=field_details,
+ form=form,
+ field_types=BaseField.form_field_types(),
+ msg=msg,
+ messagetype=messagetype )
diff -r 267db48a2371 -r b46f27137744 lib/galaxy/web/controllers/requests.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/web/controllers/requests.py Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,429 @@
+from galaxy.web.base.controller import *
+from galaxy.web.framework.helpers import time_ago, iff, grids
+from galaxy.model.orm import *
+from galaxy.datatypes import sniff
+from galaxy import util
+from galaxy.util.streamball import StreamBall
+import logging, tempfile, zipfile, tarfile, os, sys
+from galaxy.web.form_builder import *
+
+log = logging.getLogger( __name__ )
+
+# States for passing messages
+SUCCESS, INFO, WARNING, ERROR = "done", "info", "warning", "error"
+
+class RequestsListGrid( grids.Grid ):
+ title = "Requests"
+ model_class = model.Request
+ default_sort_key = "-create_time"
+ columns = [
+ grids.GridColumn( "Name", key="name",
+ link=( lambda item: iff( item.deleted, None, dict( operation="show_request", id=item.id ) ) ),
+ attach_popup=True ),
+ grids.GridColumn( "Description", key='desc'),
+ grids.GridColumn( "Sample(s)", method='number_of_samples',
+ link=( lambda item: iff( item.deleted, None, dict( operation="samples", id=item.id ) ) ), ),
+ grids.GridColumn( "Type", key="request_type_id", method='get_request_type'),
+ grids.GridColumn( "Last update", key="update_time", format=time_ago )
+ ]
+ operations = [
+# grids.GridOperation( "Edit", allow_multiple=False, condition=( lambda item: not item.deleted ) ),
+ grids.GridOperation( "Samples", allow_multiple=False, condition=( lambda item: not item.deleted ) ),
+# grids.GridOperation( "Delete", condition=( lambda item: not item.deleted ) ),
+# grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ) ),
+ ]
+ standard_filters = [
+ grids.GridColumnFilter( "Active", args=dict( deleted=False ) ),
+ grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ),
+ grids.GridColumnFilter( "All", args=dict( deleted='All' ) )
+ ]
+ #default_filter = dict( deleted=False )
+ def get_current_item( self, trans ):
+ return None
+ def get_request_type(self, trans, request):
+ request_type = trans.app.model.RequestType.get(request.request_type_id)
+ return request_type.name
+ def apply_default_filter( self, trans, query ):
+ return query.filter_by( user=trans.user )
+ def number_of_samples(self, trans, request):
+ return str(len(trans.app.model.Sample.filter(trans.app.model.Sample.table.c.request_id==request.id).all()))
+
+class SamplesListGrid( grids.Grid ):
+ model_class = model.Sample
+ default_sort_key = "-create_time"
+ columns = [
+ grids.GridColumn( "Name", key="name",
+ link=( lambda item: iff( item.deleted, None, dict( operation="show_sample", id=item.id ) ) ),
+ attach_popup=True ),
+ grids.GridColumn( "Description", key='desc' ),
+ grids.GridColumn( "Status", method="get_status",
+ link=( lambda item: iff( item.deleted, None, dict( operation="events", id=item.id ) ) )),
+
+ grids.GridColumn( "Last update", key="update_time", format=time_ago )
+
+ # Valid for filtering but invisible
+ #grids.GridColumn( "Deleted", key="deleted", visible=False )
+ ]
+ operations = [
+# grids.GridOperation( "Edit", allow_multiple=False, condition=( lambda item: not item.deleted ) ),
+# grids.GridOperation( "Delete", condition=( lambda item: not item.deleted ) ),
+# grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ) ),
+
+ ]
+ standard_filters = [
+ grids.GridColumnFilter( "Active", args=dict( deleted=False ) ),
+ grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ),
+ grids.GridColumnFilter( "All", args=dict( deleted='All' ) )
+ ]
+ def __init__(self, request):
+ self.request = request
+ def get_current_item( self, trans ):
+ return None
+ def apply_default_filter( self, trans, query ):
+ return query.filter_by( request_id=self.request.id )
+ def get_status(self, trans, sample):
+ all_states = trans.app.model.SampleEvent.filter(trans.app.model.SampleEvent.table.c.sample_id == sample.id).all()
+ curr_state = trans.app.model.SampleState.get(all_states[len(all_states)-1].sample_state_id)
+ return curr_state.name
+
+class Requests( BaseController ):
+ request_grid = RequestsListGrid()
+
+ @web.expose
+ def index( self, trans ):
+ return trans.fill_template( "requests/index.mako" )
+ def get_authorized_libs(self, trans):
+ all_libraries = trans.app.model.Library.filter(trans.app.model.Library.table.c.deleted == False).order_by(trans.app.model.Library.name).all()
+ authorized_libraries = []
+ for library in all_libraries:
+ if trans.app.security_agent.allow_action(trans.user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=library) or trans.app.security_agent.allow_action(trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library) or trans.app.security_agent.allow_action(trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=library) or trans.app.security_agent.check_folder_contents(trans.user, library) or trans.app.security_agent.show_library_item(trans.user, library):
+ authorized_libraries.append(library)
+ return authorized_libraries
+ @web.expose
+ def list( self, trans, **kwargs ):
+ '''
+ List all request made by the current user
+ '''
+ status = message = None
+ if 'operation' in kwargs:
+ operation = kwargs['operation'].lower()
+ if operation == "show_request":
+ id = trans.security.decode_id(kwargs['id'])
+ return self.show_read_only(trans, id)
+ elif operation == "samples":
+ id = trans.security.decode_id(kwargs['id'])
+ return self.show_samples(trans, id, kwargs)
+ elif operation == "show_sample":
+ id = trans.security.decode_id(kwargs['id'])
+ return self.show_sample_read_only(trans, id)
+ elif operation == "events":
+ id = trans.security.decode_id(kwargs['id'])
+ return self.show_events(trans, id)
+ # Render the list view
+ return self.request_grid( trans, status=status, message=message, template='/requests/grid.mako', **kwargs )
+ def show_samples(self, trans, id, kwargs):
+ '''
+ Shows all the samples associated with this request
+ '''
+ status = message = None
+ request = trans.app.model.Request.get(id)
+ self.samples_grid = SamplesListGrid(request)
+ return self.samples_grid( trans, status=status, message=message, template='/sample/grid.mako', **kwargs )
+ def show_read_only(self, trans, id):
+ '''
+ Shows the request details
+ '''
+ request = trans.app.model.Request.get(id)
+ request_type = trans.app.model.RequestType.get(request.request_type_id)
+ request_form = trans.app.model.FormDefinition.get(request_type.request_form_id)
+ request_values = trans.app.model.FormValues.get(request.form_values_id)
+ libraries = self.get_authorized_libs(trans)
+ # list of widgets to be rendered on the request form
+ request_details = []
+ # main details
+ request_details.append(dict(label='Name',
+ value=request.name,
+ helptext=''))
+ request_details.append(dict(label='Description',
+ value=request.desc,
+ helptext=''))
+ request_details.append(dict(label='Type',
+ value=request_type.name,
+ helptext=''))
+ request_details.append(dict(label='Date created',
+ value=request.create_time,
+ helptext=''))
+ request_details.append(dict(label='Date updated',
+ value=request.create_time,
+ helptext=''))
+ request_details.append(dict(label='User',
+ value=str(trans.user.email),
+ helptext=''))
+ # library associated
+ request_details.append(dict(label='Library',
+ value=trans.app.model.Library.get(request.library_id).name,
+ helptext='Associated library where the resultant \
+ dataset will be stored'))
+ # form fields
+ for field in request_form.fields:
+ if field['required']:
+ req = 'Required'
+ else:
+ req = 'Optional'
+ request_details.append(dict(label=field['label'],
+ value=request_values.content[field['label']],
+ helptext=field['helptext']+' ('+req+')'))
+ return trans.fill_template( '/requests/view_request.mako',
+ request_form_id=request_form.id,
+ request_details=request_details,
+ request_type=request_type)
+ @web.expose
+ def new(self, trans, **kwd):
+ params = util.Params( kwd )
+ msg = util.restore_text( params.get( 'msg', '' ) )
+ messagetype = params.get( 'messagetype', 'done' )
+ if params.get('select_request_type', False) == 'True':
+ return trans.fill_template( '/requests/select_request_type.mako',
+ request_types=trans.app.model.RequestType.query().all(),
+ libraries=self.get_authorized_libs(trans),
+ msg=msg,
+ messagetype=messagetype )
+ elif params.get('create', False) == 'True':
+ request_type_id = int(util.restore_text( params.request_type_id ))
+ return self.__show_request_form(trans, params, request_type_id)
+ elif params.get('save', False) == 'True':
+ request = self.__save(trans, params)
+ msg = 'The new request named %s has been created' % request.name
+ request_type_id = int(util.restore_text( params.request_type_id ))
+ return trans.response.send_redirect( web.url_for( controller='requests',
+ action='list',
+ msg=msg ,
+ messagetype='done') )
+ return self.__show_request_form(trans, params, request_type_id, request=request)
+ def __save(self, trans, params, request_id=None):
+ '''
+ This method save a new request if request_id is None.
+ '''
+ if not request_id:
+ request_type_id = int(util.restore_text( params.request_type_id ))
+ request_form_id = trans.app.model.RequestType.get(request_type_id).request_form_id
+ request_form = trans.app.model.FormDefinition.get(request_form_id)
+ else:
+ request = trans.app.model.Request.get(request_id)
+ form_values = trans.app.model.FormValues.get(request.form_values_id)
+ request_form = trans.app.model.FormDefinition.get(form_values.request_form_id)
+ name = params.get('name', '')
+ desc = params.get('desc', '')
+ library_id = params.get('library', '')
+ values = {}
+ for field in request_form.fields:
+ values[field['label']] = params.get(field['label'], '')
+ if not request_id:
+ form_values = trans.app.model.FormValues(request_form_id, values)
+ form_values.flush()
+ request = trans.app.model.Request(name, desc, request_type_id,
+ trans.user.id, form_values.id,
+ library_id)
+ request.flush()
+ else:
+ form_values.content = values
+ form_values.flush()
+ return request
+ def __show_request_form(self, trans, params, request_type_id, request=None):
+ request_type = trans.app.model.RequestType.get(request_type_id)
+ request_form_id = request_type.request_form_id
+ if request:
+ form_values = trans.app.model.FormValues.get(request.form_values_id)
+ else:
+ form_values = None
+ # list of widgets to be rendered on the request form
+ widgets = []
+ widgets.append(dict(label='Name',
+ widget=TextField('name'),
+ helptext='(Required)'))
+ widgets.append(dict(label='Description',
+ widget=TextField('desc'),
+ helptext='(Optional)'))
+ widgets[0]['widget'].set_size(40)
+ widgets[1]['widget'].set_size(40)
+ # libraries selectbox
+ libraries = self.get_authorized_libs(trans)
+ lib_list = SelectField('library')
+ for lib in libraries:
+ lib_list.add_option(lib.name, lib.id)
+ widgets.append(dict(label='Library',
+ widget=lib_list,
+ helptext='Associated library where the resultant \
+ dataset will be stored'))
+ widgets = self.__create_form(trans, params, request_form_id, widgets, form_values)
+ title = 'Add a new request of type: %s' % request_type.name
+ return trans.fill_template( '/requests/new_request.mako',
+ request_form_id=request_form_id,
+ request_type=request_type,
+ widgets=widgets,
+ title=title)
+
+ def __create_form(self, trans, params, form_id, widgets=[], form_values=None):
+ form = trans.app.model.FormDefinition.get(form_id)
+ if not form_values:
+ values = {}
+ for field in form.fields:
+ if field['type'] in ['SelectField' or 'CheckBoxField']:
+ values[field['label']] = False
+ else:
+ values[field['label']] = ''
+ else:
+ values = form_values.content
+ # form fields
+ for field in form.fields:
+ fw = eval(field['type'])(field['label'])
+ if field['type'] == 'TextField':
+ fw.set_size(40)
+ fw.value = values[field['label']]
+ elif field['type'] == 'TextArea':
+ fw.set_size(3, 40)
+ fw.value = values[field['label']]
+ elif field['type'] == 'SelectField':
+ for option in field['selectlist']:
+ fw.add_option(option, option, values[field['label']])
+ elif field['type'] == 'CheckBoxField':
+ fw.checked = values[field['label']]
+
+ if field['required']:
+ req = 'Required'
+ else:
+ req = 'Optional'
+ widgets.append(dict(label=field['label'],
+ widget=fw,
+ helptext=field['helptext']+' ('+req+')'))
+ return widgets
+ @web.expose
+ def add_sample(self, trans, **kwd):
+ params = util.Params( kwd )
+ msg = util.restore_text( params.get( 'msg', '' ) )
+ messagetype = params.get( 'messagetype', 'done' )
+ request_id = int(util.restore_text( params.get( 'id', '' ) ))
+ return self.__show_sample_form(trans, params, request_id)
+
+ def __show_sample_form(self, trans, params, request_id, sample=None):
+ request = trans.app.model.Request.get(request_id)
+ request_type = trans.app.model.RequestType.get(request.request_type_id)
+ sample_form_id = request_type.sample_form_id
+ if sample:
+ form_values = trans.app.model.FormValues.get(sample.form_values_id)
+ else:
+ form_values = None
+ # list of widgets to be rendered on the request form
+ widgets = []
+ widgets.append(dict(label='Name',
+ widget=TextField('name'),
+ helptext='(Required)'))
+ widgets.append(dict(label='Description',
+ widget=TextField('desc'),
+ helptext='(Optional)'))
+ widgets[0]['widget'].set_size(40)
+ widgets[1]['widget'].set_size(40)
+ widgets = self.__create_form(trans, params, sample_form_id, widgets, form_values)
+ title = 'Add a new sample to request: %s of type: %s' % (request.name, request_type.name)
+ return trans.fill_template( '/sample/new_sample.mako',
+ sample_form_id=sample_form_id,
+ request_id=request.id,
+ widgets=widgets,
+ title=title)
+ @web.expose
+ def samples(self, trans, **kwd):
+ params = util.Params( kwd )
+ if params.get('save', False) == 'True':
+ sample = self.__save_sample(trans, params)
+ return trans.response.send_redirect( web.url_for( controller='requests',
+ action='list',
+ operation='samples',
+ id=trans.security.encode_id(sample.request_id)) )
+ def __save_sample(self, trans, params, sample_id=None):
+ if not sample_id:
+ request = trans.app.model.Request.get(int(util.restore_text( params.request_id )))
+ request_type = trans.app.model.RequestType.get(request.request_type_id)
+ sample_form = trans.app.model.FormDefinition.get(request_type.sample_form_id)
+ else:
+ sample = trans.app.model.Sample.get(sample_id)
+ form_data = trans.app.model.FormData.get(sample.form_data_id)
+ form = trans.app.model.FormDefinition.get(form_data.form_definition_id)
+ name = params.get('name', '')
+ desc = params.get('desc', '')
+ values = {}
+ for field in sample_form.fields:
+ values[field['label']] = params.get(field['label'], '')
+ if not sample_id:
+ form_values = trans.app.model.FormValues(sample_form.id, values)
+ form_values.flush()
+ sample = trans.app.model.Sample(name, desc, request.id, form_values.id)
+ sample.flush()
+ # set the initial state
+ state = trans.app.model.SampleState.filter(trans.app.model.SampleState.table.c.request_type_id == request_type.id).first()
+ event = trans.app.model.SampleEvent(sample.id, state.id)
+ event.flush()
+ else:
+ form_data.content = values
+ form_data.flush()
+ return sample
+ def show_sample_read_only(self, trans, sample_id):
+ '''
+ Shows the sample details
+ '''
+ sample = trans.app.model.Sample.get(sample_id)
+ request = trans.app.model.Request.get(sample.request_id)
+ request_type = trans.app.model.RequestType.get(request.request_type_id)
+ sample_form = trans.app.model.FormDefinition.get(request_type.sample_form_id)
+ sample_values = trans.app.model.FormValues.get(sample.form_values_id)
+ # list of widgets to be rendered on the request form
+ sample_details = []
+ # main details
+ sample_details.append(dict(label='Name',
+ value=sample.name,
+ helptext=''))
+ sample_details.append(dict(label='Description',
+ value=sample.desc,
+ helptext=''))
+ sample_details.append(dict(label='Date created',
+ value=sample.create_time,
+ helptext=''))
+ sample_details.append(dict(label='Date updated',
+ value=sample.create_time,
+ helptext=''))
+ sample_details.append(dict(label='User',
+ value=str(trans.user.email),
+ helptext=''))
+ sample_details.append(dict(label='Request',
+ value=request.name,
+ helptext='Name/ID of the request this sample belongs to.'))
+ # get the current state of the sample
+ all_states = trans.app.model.SampleEvent.filter(trans.app.model.SampleEvent.table.c.sample_id == sample_id).all()
+ curr_state = trans.app.model.SampleState.get(all_states[len(all_states)-1].sample_state_id)
+ sample_details.append(dict(label='State',
+ value=curr_state.name,
+ helptext=curr_state.desc))
+ # form fields
+ for field in sample_form.fields:
+ if field['required']:
+ req = 'Required'
+ else:
+ req = 'Optional'
+ sample_details.append(dict(label=field['label'],
+ value=sample_values.content[field['label']],
+ helptext=field['helptext']+' ('+req+')'))
+ return trans.fill_template( '/sample/view_sample.mako',
+ sample_details=sample_details)
+ def show_events(self, trans, sample_id):
+ sample = trans.app.model.Sample.get(sample_id)
+ events_list = []
+ for event in trans.app.model.SampleEvent.filter(trans.app.model.SampleEvent.table.c.sample_id == sample_id).all():
+ state = trans.app.model.SampleState.get(event.sample_state_id)
+ events_list.append((state.name, event.update_time, state.desc, event.comment))
+ return trans.fill_template( '/sample/sample_events.mako',
+ events_list=events_list,
+ sample_name=sample.name,
+ request=trans.app.model.Request.get(sample.request_id).name)
+
+
+
+
diff -r 267db48a2371 -r b46f27137744 lib/galaxy/web/controllers/requests_admin.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/web/controllers/requests_admin.py Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,315 @@
+from galaxy.web.base.controller import *
+from galaxy.web.framework.helpers import time_ago, iff, grids
+from galaxy.model.orm import *
+from galaxy.datatypes import sniff
+from galaxy import util
+from galaxy.util.streamball import StreamBall
+import logging, tempfile, zipfile, tarfile, os, sys
+from galaxy.web.form_builder import *
+from datetime import datetime, timedelta
+
+log = logging.getLogger( __name__ )
+
+
+# States for passing messages
+SUCCESS, INFO, WARNING, ERROR = "done", "info", "warning", "error"
+
+class RequestsListGrid( grids.Grid ):
+ title = "Requests"
+ model_class = model.Request
+ default_sort_key = "-create_time"
+ columns = [
+ grids.GridColumn( "Name", key="name",
+ link=( lambda item: iff( item.deleted, None, dict( operation="show_request", id=item.id ) ) ),
+ attach_popup=True ),
+ grids.GridColumn( "Description", key="desc"),
+ grids.GridColumn( "Sample(s)", method='number_of_samples',
+ link=( lambda item: iff( item.deleted, None, dict( operation="samples", id=item.id ) ) ), ),
+ grids.GridColumn( "Type", key="request_type_id", method='get_request_type'),
+ grids.GridColumn( "Last update", key="update_time", format=time_ago ),
+ grids.GridColumn( "User", key="user_id", method='get_user')
+
+ ]
+ operations = [
+# grids.GridOperation( "Edit", allow_multiple=False, condition=( lambda item: not item.deleted ) ),
+ grids.GridOperation( "Samples", allow_multiple=False, condition=( lambda item: not item.deleted ) ),
+# grids.GridOperation( "Delete", condition=( lambda item: not item.deleted ) ),
+# grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ) ),
+ ]
+ standard_filters = [
+ grids.GridColumnFilter( "Active", args=dict( deleted=False ) ),
+ grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ),
+ grids.GridColumnFilter( "All", args=dict( deleted='All' ) )
+ ]
+ def get_user(self, trans, request):
+ return trans.app.model.User.get(request.user_id).email
+ def get_current_item( self, trans ):
+ return None
+ def get_request_type(self, trans, request):
+ request_type = trans.app.model.RequestType.get(request.request_type_id)
+ return request_type.name
+ def apply_default_filter( self, trans, query ):
+ return query
+ def number_of_samples(self, trans, request):
+ return str(len(trans.app.model.Sample.filter(trans.app.model.Sample.table.c.request_id==request.id).all()))
+
+class SamplesListGrid( grids.Grid ):
+ model_class = model.Sample
+ default_sort_key = "-create_time"
+ columns = [
+ grids.GridColumn( "Name", key="name",
+ link=( lambda item: iff( item.deleted, None, dict( operation="show_sample", id=item.id ) ) ),
+ attach_popup=True ),
+ grids.GridColumn( "Description", key='desc' ),
+ grids.GridColumn( "Status", method="get_status",
+ link=( lambda item: iff( item.deleted, None, dict( operation="events", id=item.id ) ) )),
+
+ grids.GridColumn( "Last update", key="update_time", format=time_ago )
+
+ # Valid for filtering but invisible
+ #grids.GridColumn( "Deleted", key="deleted", visible=False )
+ ]
+ operations = [
+# grids.GridOperation( "Edit", allow_multiple=False, condition=( lambda item: not item.deleted ) ),
+ grids.GridOperation( "Change state", condition=( lambda item: not item.deleted ) ),
+# grids.GridOperation( "Delete", condition=( lambda item: not item.deleted ) ),
+# grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ) ),
+
+ ]
+ standard_filters = [
+ grids.GridColumnFilter( "Active", args=dict( deleted=False ) ),
+ grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ),
+ grids.GridColumnFilter( "All", args=dict( deleted='All' ) )
+ ]
+ def __init__(self, request, user):
+ self.request = request
+ self.user = user
+ def get_current_item( self, trans ):
+ return None
+ def apply_default_filter( self, trans, query ):
+ return query.filter_by( request_id=self.request.id )
+ def get_status(self, trans, sample):
+ all_states = trans.app.model.SampleEvent.filter(trans.app.model.SampleEvent.table.c.sample_id == sample.id).all()
+ curr_state = trans.app.model.SampleState.get(all_states[len(all_states)-1].sample_state_id)
+ return curr_state.name
+
+class Requests( BaseController ):
+ request_grid = RequestsListGrid()
+
+ @web.expose
+ @web.require_admin
+ def index( self, trans ):
+ return trans.fill_template( "/admin/requests/index.mako" )
+ def get_authorized_libs(self, trans):
+ all_libraries = trans.app.model.Library.filter(trans.app.model.Library.table.c.deleted == False).order_by(trans.app.model.Library.name).all()
+ authorized_libraries = []
+ for library in all_libraries:
+ if trans.app.security_agent.allow_action(trans.user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=library) or trans.app.security_agent.allow_action(trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library) or trans.app.security_agent.allow_action(trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=library) or trans.app.security_agent.check_folder_contents(trans.user, library) or trans.app.security_agent.show_library_item(trans.user, library):
+ authorized_libraries.append(library)
+ return authorized_libraries
+ @web.expose
+ @web.require_admin
+ def list( self, trans, **kwargs ):
+ '''
+ List all request made by the current user
+ '''
+ status = message = None
+ if 'operation' in kwargs:
+ operation = kwargs['operation'].lower()
+ if operation == "show_request":
+ id = trans.security.decode_id(kwargs['id'])
+ return self.show_read_only(trans, id)
+ elif operation == "samples":
+ id = trans.security.decode_id(kwargs['id'])
+ return self.show_samples(trans, id, kwargs)
+ elif operation == "show_sample":
+ id = trans.security.decode_id(kwargs['id'])
+ return self.show_sample_read_only(trans, id)
+ elif operation == "change state":
+ id_list = [trans.security.decode_id(id) for id in util.listify(kwargs['id'])]
+ return self.change_state(trans, id_list)
+ elif operation == "events":
+ id = trans.security.decode_id(kwargs['id'])
+ return self.show_events(trans, id)
+ # Render the list view
+ return self.request_grid( trans, status=status, message=message, template='/admin/requests/grid.mako', **kwargs )
+ def show_samples(self, trans, id, kwargs):
+ '''
+ Shows all the samples associated with this request
+ '''
+ status = message = None
+ request = trans.app.model.Request.get(id)
+ self.samples_grid = SamplesListGrid(request, trans.app.model.User.get(request.user_id))
+ return self.samples_grid( trans, status=status, message=message, template='/admin/samples/grid.mako', **kwargs )
+ def show_read_only(self, trans, id):
+ '''
+ Shows the request details
+ '''
+ request = trans.app.model.Request.get(id)
+ request_type = trans.app.model.RequestType.get(request.request_type_id)
+ request_form = trans.app.model.FormDefinition.get(request_type.request_form_id)
+ request_values = trans.app.model.FormValues.get(request.form_values_id)
+ libraries = self.get_authorized_libs(trans)
+ # list of widgets to be rendered on the request form
+ request_details = []
+ # main details
+ request_details.append(dict(label='Name',
+ value=request.name,
+ helptext=''))
+ request_details.append(dict(label='Description',
+ value=request.desc,
+ helptext=''))
+ request_details.append(dict(label='Type',
+ value=request_type.name,
+ helptext=''))
+ request_details.append(dict(label='Date created',
+ value=request.create_time,
+ helptext=''))
+ request_details.append(dict(label='Date updated',
+ value=request.create_time,
+ helptext=''))
+ request_details.append(dict(label='User',
+ value=str(trans.user.email),
+ helptext=''))
+ # library associated
+ request_details.append(dict(label='Library',
+ value=trans.app.model.Library.get(request.library_id).name,
+ helptext='Associated library where the resultant \
+ dataset will be stored'))
+ # form fields
+ for field in request_form.fields:
+ if field['required']:
+ req = 'Required'
+ else:
+ req = 'Optional'
+ request_details.append(dict(label=field['label'],
+ value=request_values.content[field['label']],
+ helptext=field['helptext']+' ('+req+')'))
+ return trans.fill_template( '/admin/requests/view_request.mako',
+ request_form_id=request_form.id,
+ request_details=request_details,
+ request_type=request_type)
+
+ @web.expose
+ @web.require_admin
+ def samples(self, trans, **kwd):
+ params = util.Params( kwd )
+ if params.get('save', False) == 'True':
+ sample = self.__save_sample(trans, params)
+ return self.show_samples(trans, sample.request_id, {})
+ def show_sample_read_only(self, trans, sample_id):
+ '''
+ Shows the sample details
+ '''
+ sample = trans.app.model.Sample.get(sample_id)
+ request = trans.app.model.Request.get(sample.request_id)
+ request_type = trans.app.model.RequestType.get(request.request_type_id)
+ sample_form = trans.app.model.FormDefinition.get(request_type.sample_form_id)
+ sample_values = trans.app.model.FormValues.get(sample.form_values_id)
+ # list of widgets to be rendered on the request form
+ sample_details = []
+ # main details
+ sample_details.append(dict(label='Name',
+ value=request.name,
+ helptext=''))
+ sample_details.append(dict(label='Description',
+ value=request.desc,
+ helptext=''))
+ sample_details.append(dict(label='Date created',
+ value=sample.create_time,
+ helptext=''))
+ sample_details.append(dict(label='Date updated',
+ value=sample.create_time,
+ helptext=''))
+ sample_details.append(dict(label='User',
+ value=str(trans.user.email),
+ helptext=''))
+ sample_details.append(dict(label='Request',
+ value=request.name,
+ helptext='Name/ID of the request this sample belongs to.'))
+ # get the current state of the sample
+ all_states = trans.app.model.SampleEvent.filter(trans.app.model.SampleEvent.table.c.sample_id == sample_id).all()
+ curr_state = trans.app.model.SampleState.get(all_states[len(all_states)-1].sample_state_id)
+ sample_details.append(dict(label='State',
+ value=curr_state.name,
+ helptext=curr_state.desc))
+ # form fields
+ for field in sample_form.fields:
+ if field['required']:
+ req = 'Required'
+ else:
+ req = 'Optional'
+ sample_details.append(dict(label=field['label'],
+ value=sample_values.content[field['label']],
+ helptext=field['helptext']+' ('+req+')'))
+ return trans.fill_template( '/admin/samples/view_sample.mako',
+ sample_details=sample_details)
+ def __get_all_states(self, trans, sample):
+ request = trans.app.model.Request.get(sample.request_id)
+ request_type = trans.app.model.RequestType.get(request.request_type_id)
+ all_states = trans.app.model.SampleEvent.filter(trans.app.model.SampleEvent.table.c.sample_id == sample.id).all()
+ curr_state = trans.app.model.SampleState.get(all_states[len(all_states)-1].sample_state_id)
+ states_list = trans.app.model.SampleState.filter(trans.app.model.SampleState.table.c.request_type_id == request_type.id)
+ return states_list
+ def __get_curr_state(self, trans, sample):
+ all_states = trans.app.model.SampleEvent.filter(trans.app.model.SampleEvent.table.c.sample_id == sample.id).all()
+ curr_state = trans.app.model.SampleState.get(all_states[len(all_states)-1].sample_state_id)
+ return curr_state
+ def change_state(self, trans, sample_id_list):
+ sample = trans.app.model.Sample.get(sample_id_list[0])
+ states_list = self.__get_all_states(trans, sample)
+ curr_state = self.__get_curr_state(trans, sample)
+ states_input = SelectField('select_state')
+ for state in states_list:
+ if len(sample_id_list) == 1:
+ if curr_state.name == state.name:
+ states_input.add_option(state.name+' (Current)', state.name, selected=True)
+ else:
+ states_input.add_option(state.name, state.name)
+ else:
+ states_input.add_option(state.name, state.name)
+ widgets = []
+ widgets.append(('Select the new state of the sample(s) from the list of possible state(s)',
+ states_input))
+ widgets.append(('Comments', TextArea('comment')))
+ title = 'Change current state of sample: ' + sample.name
+ return trans.fill_template( '/admin/samples/change_state.mako',
+ widgets=widgets, title=title,
+ sample_id_list=util.object_to_string(sample_id_list))
+ @web.expose
+ @web.require_admin
+ def save_state(self, trans, **kwd):
+ params = util.Params( kwd )
+ sample_id_list = util.string_to_object(util.restore_text( params.sample_id_list ))
+ comments = util.restore_text( params.comment )
+ sample = trans.app.model.Sample.get(sample_id_list[0])
+ request = trans.app.model.Request.get(sample.request_id)
+ selected_state = util.restore_text( params.select_state )
+ new_state = trans.app.model.SampleState.filter(trans.app.model.SampleState.table.c.request_type_id == request.request_type_id
+ and trans.app.model.SampleState.table.c.name == selected_state)[0]
+ for sample_id in sample_id_list:
+ event = trans.app.model.SampleEvent(sample_id, new_state.id, comments)
+ event.flush()
+ return trans.response.send_redirect( web.url_for( controller='requests_admin',
+ action='list',
+ operation='samples',
+ id=trans.security.encode_id(request.id)) )
+ @web.expose
+ @web.require_admin
+ def show_events(self, trans, sample_id):
+ sample = trans.app.model.Sample.get(sample_id)
+ request = trans.app.model.Request.get(sample.request_id)
+ events_list = []
+ for event in trans.app.model.SampleEvent.filter(trans.app.model.SampleEvent.table.c.sample_id == sample_id).order_by(trans.app.model.SampleEvent.c.update_time.desc()).all():
+ state = trans.app.model.SampleState.get(event.sample_state_id)
+ delta = datetime.utcnow() - event.update_time
+ if delta > timedelta( minutes=60 ):
+ last_update = '%s hours' % int( delta.seconds / 60 / 60 )
+ else:
+ last_update = '%s minutes' % int( delta.seconds / 60 )
+ events_list.append((state.name, state.desc, last_update, event.comment))
+ return trans.fill_template( '/admin/samples/events.mako',
+ events_list=events_list,
+ sample_name=sample.name, user=trans.app.model.User.get(request.user_id),
+ request=request.name)
+
\ No newline at end of file
diff -r 267db48a2371 -r b46f27137744 lib/galaxy/web/form_builder.py
--- a/lib/galaxy/web/form_builder.py Thu Jul 09 15:49:26 2009 -0400
+++ b/lib/galaxy/web/form_builder.py Fri Jul 10 11:37:28 2009 -0400
@@ -9,6 +9,11 @@
def get_html( self, prefix="" ):
"""Returns the html widget corresponding to the parameter"""
raise TypeError( "Abstract Method" )
+ @staticmethod
+ def form_field_types():
+ return ['TextField', 'TextArea', 'SelectField', 'CheckboxField']
+
+
class TextField(BaseField):
"""
@@ -26,6 +31,8 @@
def get_html( self, prefix="" ):
return '<input type="text" name="%s%s" size="%d" value="%s">' \
% ( prefix, self.name, self.size, self.value )
+ def set_size(self, size):
+ self.size = int( size )
class TextArea(BaseField):
"""
@@ -45,6 +52,9 @@
def get_html( self, prefix="" ):
return '<textarea name="%s%s" rows="%d" cols="%d">%s</textarea>' \
% ( prefix, self.name, self.rows, self.cols, self.value )
+ def set_size(self, rows, cols):
+ self.rows = rows
+ self.cols = cols
class CheckboxField(BaseField):
"""
@@ -215,6 +225,17 @@
rval.insert( 0, '<select name="%s%s"%s%s%s>' % ( prefix, self.name, multiple, self.refresh_on_change_text, last_selected_value ) )
rval.append( '</select>' )
return "\n".join( rval )
+ def get_selected(self):
+ '''
+ This method returns the currently selected option's text and value
+ '''
+ for text, value, selected in self.options:
+ if selected:
+ return text, value
+ if self.options:
+ return self.options[0]
+ return None
+
class DrillDownField( BaseField ):
diff -r 267db48a2371 -r b46f27137744 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py Thu Jul 09 15:49:26 2009 -0400
+++ b/lib/galaxy/web/framework/__init__.py Fri Jul 10 11:37:28 2009 -0400
@@ -607,6 +607,11 @@
if dbkey == ds.dbkey:
return ds
return None
+
+ def request_types(self):
+ if self.app.model.RequestType.query().all():
+ return True
+ return False
class FormBuilder( object ):
"""
diff -r 267db48a2371 -r b46f27137744 templates/admin/forms/create_form.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/forms/create_form.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,31 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">Create a new form definition</div>
+ <div class="toolFormBody">
+ <form name="create_form" action="${h.url_for( controller='forms', action='new', create_form=True, new=False, create_fields=False )}" method="post" >
+ %for label, input in inputs:
+ <div class="form-row">
+ <label>${label}</label>
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ ${input.get_html()}
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ %endfor
+ <div class="form-row">
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="hidden" name="new" value="submitted" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <input type="submit" name="save_form" value="Save"/>
+ </form>
+ </div>
+</div>
diff -r 267db48a2371 -r b46f27137744 templates/admin/forms/edit_form.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/forms/edit_form.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,105 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+<script type="text/javascript">
+$( function() {
+ $( "select[refresh_on_change='true']").change( function() {
+ var refresh = false;
+ var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
+ if ( refresh_on_change_values ) {
+ refresh_on_change_values = refresh_on_change_values.value.split( ',' );
+ var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
+ for( i= 0; i < refresh_on_change_values.length; i++ ) {
+ if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
+ refresh = true;
+ break;
+ }
+ }
+ }
+ else {
+ refresh = true;
+ }
+ if ( refresh ){
+ $( "#edit_form" ).submit();
+ }
+ });
+});
+</script>
+
+<%def name="render_selectbox_options( index, field_attr )">
+ %if field_attr[0] == 'Type':
+ %if field_attr[1].get_selected()[0] == 'SelectField':
+ <% options = field_attr[2] %>
+ <div class="repeat-group-item">
+ <label> Options</label>
+ %for i, option in enumerate(options):
+ <b> ${i+1}</b>
+ ${option[1].get_html()}
+ ##<input type="submit" name="remove_option_${index}" value="Remove option ${i+1}"/><br>
+ <a class="action-button" href="${h.url_for( controller='forms', action='edit', form_id=form.id, select_box_options='remove', field_index=index, option_index=i )}">Remove</a><br>
+ %endfor
+ </div>
+ <div class="form-row">
+ <a class="action-button" href="${h.url_for( controller='forms', action='edit', form_id=form.id, select_box_options='add', field_index=index )}">Add</a>
+ </div>
+ ##<div class="form-row">
+ ## <input type="submit" name="add_option_field_${index}" value="Add option"/>
+ ##</div>
+ %endif
+ %endif
+</%def>
+
+
+<%def name="render_field( index, field )">
+ <div class="repeat-group-item">
+ <div class="form-row">
+ <label>Field ${1+index}</label>
+ </div>
+ %for field_attr in field:
+ <div class="form-row">
+ <label>${field_attr[0]}</label>
+ ${field_attr[1].get_html()}
+ ${render_selectbox_options( index, field_attr )}
+ </div>
+ %endfor
+ <div class="form-row">
+ <input type="submit" name="remove_button" value="Remove field ${index+1}"/>
+ </div>
+ </div>
+</%def>
+
+<div class="toolForm">
+ <div class="toolFormTitle">Edit form definition '${form.name}'</div>
+ <form id="edit_form" name="edit_form" action="${h.url_for( controller='forms', action='edit', form_id=form.id, num_fields=len(form.fields) )}" method="post" >
+ %for label, input in form_details:
+ <div class="form-row">
+ <label>${label}</label>
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ ${input.get_html()}
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ %endfor
+ <div class="toolFormTitle">Sample fields (${len(form.fields)})</div>
+ %for ctr, field in enumerate(field_details):
+ ${render_field( ctr, field )}
+ %endfor
+ <div class="form-row">
+ <input type="submit" name="add_field_button" value="Add field"/>
+ </div>
+ <div class="form-row">
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="hidden" name="refresh" value="true" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <input type="submit" name="save_changes_button" value="Save"/>
+ </form>
+ </div>
+</div>
\ No newline at end of file
diff -r 267db48a2371 -r b46f27137744 templates/admin/forms/manage_forms.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/forms/manage_forms.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,73 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+
+<%def name="title()">Manage Form Definitions</%def>
+
+## Render a row
+<%def name="render_row( form, ctr )">
+ %if ctr % 2 == 1:
+ <tr class="odd_row">
+ %else:
+ <tr>
+ %endif
+ <td>
+ <b><a href="${h.url_for( controller='forms', action='edit', form_id=form.id, read_only=True )}">${form.name}</a></b>
+ <a id="form-${form.id}-popup" class="popup-arrow" style="display: none;">▼</a>
+ <div popupmenu="form-${form.id}-popup">
+ <a class="action-button" href="${h.url_for( action='edit', form_id=form.id, show_form=True )}">Edit form definition</a>
+ </div>
+ </td>
+ <td><i>${form.desc}</i></td>
+ </tr>
+</%def>
+
+
+<h2>
+ %if deleted:
+ Deleted
+ %endif
+ Forms
+</h2>
+
+
+
+<ul class="manage-table-actions">
+ %if not deleted:
+ <li>
+ <a class="action-button" href="${h.url_for( controller='forms', action='new', new=True )}">
+ <img src="${h.url_for('/static/images/silk/add.png')}" />
+ <span>Define a new form</span></a>
+ </li>
+ %endif
+</ul>
+
+
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+%if not fdc_list:
+ %if deleted:
+ There are no deleted forms
+ %else:
+ There are no forms.
+ %endif
+%else:
+ <table class="grid">
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ %for ctr, fdc in enumerate( fdc_list ):
+ <tr>
+ ${render_row( fdc.latest_form, ctr )}
+ </tr>
+ %endfor
+ </tbody>
+ </table>
+%endif
diff -r 267db48a2371 -r b46f27137744 templates/admin/forms/show_form_read_only.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/forms/show_form_read_only.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,67 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">${form.name} - <i>${form.desc}</i></div>
+ <form name="library" action="${h.url_for( controller='forms', action='manage' )}" method="post" >
+ <table class = "grid">
+ <tbody>
+ %for index, field in enumerate(form.fields):
+ <tr>
+ <td>
+ <div class="form-row">
+ <label>${1+index}. Label</label>
+ <a>${field['label']}</a>
+ %if field['type'] == 'SelectField':
+ <a id="${field['label']}-popup" class="popup-arrow" style="display: none;">▼</a>
+ %for option in field['selectlist']:
+ <div popupmenu="${field['label']}-type-popup">
+ <a class="action-button" href="" >${option}</a>
+ </div>
+ %endfor
+ %endif
+ </div>
+ </td>
+ <td>
+ <div class="form-row">
+ <label>Help text </label>
+ %if not field['helptext']:
+ <a><i>No helptext</i></a>
+ %else:
+ <a>${field['helptext']}</a>
+ %endif
+ </div>
+ </td>
+ <td>
+ <div class="form-row">
+ <label>Type:</label>
+ <a>${field['type']}</a>
+ %if field['type'] == 'SelectField':
+ <a id="fieldtype-popup" class="popup-arrow" style="display: none;">▼</a>
+ %for option in field['selectlist']:
+ <div popupmenu="type-popup">
+ <a class="action-button" href="" >${option}</a>
+ </div>
+ %endfor
+ %endif
+ </div>
+ </td>
+ <td>
+ <div class="form-row">
+ <label>Required?</label>
+ <a>${field['required']}</a>
+ </div>
+ </td>
+ </tr>
+ %endfor
+ </tbody>
+ </table>
+ ##<input type="submit" name="save_changes_button" value="Back"/>
+ </form>
+ </div>
+</div>
\ No newline at end of file
diff -r 267db48a2371 -r b46f27137744 templates/admin/index.mako
--- a/templates/admin/index.mako Thu Jul 09 15:49:26 2009 -0400
+++ b/templates/admin/index.mako Fri Jul 10 11:37:28 2009 -0400
@@ -103,13 +103,35 @@
<div class="toolTitle"><a href="${h.url_for( controller='admin', action='jobs' )}" target="galaxy_main">Manage jobs</a></div>
</div>
</div>
+ <div class="toolSectionPad"></div>
+ <div class="toolSectionTitle">
+ <span>Forms</span>
+ </div>
+ <div class="toolSectionBody">
+ <div class="toolSectionBg">
+ <div class="toolTitle"><a href="${h.url_for( controller='forms', action='manage' )}" target="galaxy_main">Manage forms</a></div>
+ </div>
+ </div>
+ <div class="toolSectionPad"></div>
+ <div class="toolSectionTitle">
+ <span>Requests</span>
+ </div>
+ <div class="toolSectionBody">
+ <div class="toolSectionBg">
+ <div class="toolTitle"><a href="${h.url_for( controller='admin', action='manage_request_types' )}" target="galaxy_main">Manage request types</a></div>
+ <div class="toolTitle"><a href="${h.url_for( controller='requests_admin', action='list')}" target="galaxy_main">Manage requests</a></div>
+ </div>
+ </div>
</div>
</div>
</div>
+ ##<iframe name="galaxy_admin" src="${h.url_for( controller='admin', action='index' )}" frameborder="0" style="position: absolute; margin: 0; border: 0 none; height: 100%; width: 100%;"> </iframe>
</%def>
<%def name="center_panel()">
-
- <iframe name="galaxy_main" id="galaxy_main" frameborder="0" style="position: absolute; width: 100%; height: 100%;" src="${h.url_for( action='center' )}"> </iframe>
+ <%
+ center_url = h.url_for( action='center' )
+ %>
+ <iframe name="galaxy_main" id="galaxy_main" frameborder="0" style="position: absolute; width: 100%; height: 100%;" src="${center_url}"> </iframe>
</%def>
diff -r 267db48a2371 -r b46f27137744 templates/admin/requests/add_states.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/requests/add_states.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,26 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">Create ${num_states} states for the '${sample_type_name}' sample type</div>
+ <form name="new_form_fields" action="${h.url_for( controller='admin', action='request_type', save_new=True, create=False, edit=False, name=sample_type_name, description=desc, num_states=num_states, request_form_id=request_form_id, sample_form_id=sample_form_id)}" method="post" >
+ <div class="toolFormBody">
+ %for element_count in range( num_states ):
+ <div class="form-row">
+ <label>${1+element_count}) State name:</label>
+ <input type="text" name="new_element_name_${element_count}" value="" size="40"/>
+ <label>State help text (optional):</label>
+ <input type="text" name="new_element_description_${element_count}" value="" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ %endfor
+ </div>
+ <div class="toolFormBody">
+ <input type="submit" name="save_new_sample_type" value="Save"/>
+ </div>
+ </form>
+</div>
\ No newline at end of file
diff -r 267db48a2371 -r b46f27137744 templates/admin/requests/create_request_type.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/requests/create_request_type.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,66 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">Create a new request type</div>
+ %if not forms:
+ Create a form definition first to create a new request type.
+ %else:
+ <div class="toolFormBody">
+ <form name="create_request_type" action="${h.url_for( controller='admin', action='request_type', add_states=True, create=False, edit=False )}" method="post" >
+ <div class="form-row">
+ <label>Name:</label>
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="text" name="name" value="New Request Type" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Description:</label>
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="text" name="description" value="" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>
+ Request Form definition:
+ </label>
+ <select name="request_form_id">
+ %for form in forms:
+ <option value="${form.id}">${form.name}</option>
+ %endfor
+ </select>
+ </div>
+ <div class="form-row">
+ <label>
+ Sample Form definition:
+ </label>
+ <select name="sample_form_id">
+ %for form in forms:
+ <option value="${form.id}">${form.name}</option>
+ %endfor
+ </select>
+ </div>
+ <div class="form-row">
+ <label>Number of sample states:</label>
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="text" size="3" name="num_states" value="1"/>
+ </div>
+ </div>
+ <div class="form-row">
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="hidden" name="new" value="submitted" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <input type="submit" name="create_library_button" value="Define states"/>
+ </form>
+ </div>
+ %endif
+</div>
\ No newline at end of file
diff -r 267db48a2371 -r b46f27137744 templates/admin/requests/edit_request_type.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/requests/edit_request_type.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,78 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+<% num_states=len(states_list) %>
+
+<div class="toolForm">
+ <div class="toolFormTitle">Edit the request type</div>
+ <div class="toolFormBody">
+ <form name="library" action="${h.url_for( controller='admin', action='request_type', save_changes=True, create=False, id=request_type.id, num_states=num_states )}" method="post" >
+ <div class="form-row">
+ <label>Name:</label>
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="text" name="name" value="${request_type.name}" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Description:</label>
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="text" name="description" value="${request_type.desc}" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>
+ Request Form definition:
+ </label>
+ <select name="form_id">
+ %for form in forms:
+ %if form.id == request_type.request_form_id:
+ <option value="${form.id}" selected>${form.name}</option>
+ %else:
+ <option value="${form.id}">${form.name}</option>
+ %endif
+ %endfor
+ </select>
+ </div>
+ <div class="form-row">
+ <label>
+ Sample Form definition:
+ </label>
+ <select name="form_id">
+ %for form in forms:
+ %if form.id == request_type.sample_form_id:
+ <option value="${form.id}" selected>${form.name}</option>
+ %else:
+ <option value="${form.id}">${form.name}</option>
+ %endif
+ %endfor
+ </select>
+ </div>
+ <div class="toolFormBody">
+ %for element_count, state in enumerate(states_list):
+ <div class="form-row">
+ <label>${1+element_count}) State name:</label>
+ <input type="text" name="new_element_name_${element_count}" value="${state.name}" size="40"/>
+ <label>State help text (optional):</label>
+ <input type="text" name="new_element_description_${element_count}" value="${state.desc}" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ %endfor
+ </div>
+ <div class="form-row">
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="hidden" name="new" value="submitted" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+
+ <input type="submit" name="edit_request_type_button" value="Save"/>
+ </form>
+ </div>
+</div>
\ No newline at end of file
diff -r 267db48a2371 -r b46f27137744 templates/admin/requests/grid.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/requests/grid.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,205 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+<%def name="title()">Browse Requests</%def>
+
+%if message:
+ <p>
+ <div class="${message_type}message transient-message">${message}</div>
+ <div style="clear: both"></div>
+ </p>
+%endif
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ <script type="text/javascript">
+ ## TODO: generalize and move into galaxy.base.js
+ $(document).ready(function() {
+ $(".grid").each( function() {
+ var grid = this;
+ var checkboxes = $(this).find("input.grid-row-select-checkbox");
+ var update = $(this).find( "span.grid-selected-count" );
+ $(checkboxes).each( function() {
+ $(this).change( function() {
+ var n = $(checkboxes).filter("[checked]").size();
+ update.text( n );
+ });
+ })
+ });
+ });
+ ## Can this be moved into base.mako?
+ %if refresh_frames:
+ %if 'masthead' in refresh_frames:
+ ## Refresh masthead == user changes (backward compatibility)
+ if ( parent.user_changed ) {
+ %if trans.user:
+ parent.user_changed( "${trans.user.email}", ${int( app.config.is_admin_user( trans.user ) )} );
+ %else:
+ parent.user_changed( null, false );
+ %endif
+ }
+ %endif
+ %if 'history' in refresh_frames:
+ if ( parent.frames && parent.frames.galaxy_history ) {
+ parent.frames.galaxy_history.location.href="${h.url_for( controller='root', action='history')}";
+ if ( parent.force_right_panel ) {
+ parent.force_right_panel( 'show' );
+ }
+ }
+ %endif
+ %if 'tools' in refresh_frames:
+ if ( parent.frames && parent.frames.galaxy_tools ) {
+ parent.frames.galaxy_tools.location.href="${h.url_for( controller='root', action='tool_menu')}";
+ if ( parent.force_left_panel ) {
+ parent.force_left_panel( 'show' );
+ }
+ }
+ %endif
+ %endif
+ </script>
+</%def>
+
+<%def name="stylesheets()">
+ <link href="${h.url_for('/static/style/base.css')}" rel="stylesheet" type="text/css" />
+ <style>
+ ## Not generic to all grids -- move to base?
+ .count-box {
+ min-width: 1.1em;
+ padding: 5px;
+ border-width: 1px;
+ border-style: solid;
+ text-align: center;
+ display: inline-block;
+ }
+ </style>
+</%def>
+
+<div class="grid-header">
+ <h2>${grid.title}</h2>
+ %if len(query.all()):
+ <h3>All Users</h3>
+ %endif
+## %if len(query.all()):
+## <span class="title">Filter:</span>
+## %for i, filter in enumerate( grid.standard_filters ):
+## %if i > 0:
+## <span>|</span>
+## %endif
+## <span class="filter"><a href="${url( filter.get_url_args() )}">${filter.label}</a></span>
+## %endfor
+## %endif
+</div>
+
+
+%if not len(query.all()):
+ There are no request(s).
+%else:
+<form name="history_actions" action="${url()}" method="post" >
+ <table class="grid">
+ <thead>
+ <tr>
+ <th></th>
+ %for column in grid.columns:
+ %if column.visible:
+ <%
+ href = ""
+ extra = ""
+ if column.sortable:
+ if sort_key == column.key:
+ if sort_order == "asc":
+ href = url( sort=( "-" + column.key ) )
+ extra = "↓"
+ else:
+ href = url( sort=( column.key ) )
+ extra = "↑"
+ else:
+ href = url( sort=column.key )
+ %>
+ <th\
+ %if column.ncells > 1:
+ colspan="${column.ncells}"
+ %endif
+ >
+ %if href:
+ <a href="${href}">${column.label}</a>
+ %else:
+ ${column.label}
+ %endif
+ <span>${extra}</span>
+ </th>
+ %endif
+ %endfor
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ %for i, item in enumerate( query ):
+ <tr \
+ %if current_item == item:
+ class="current" \
+ %endif
+ >
+ ## Item selection column
+ <td style="width: 1.5em;">
+ <input type="checkbox" name="id" value=${trans.security.encode_id( item.id )} class="grid-row-select-checkbox" />
+ </td>
+ ## Data columns
+ %for column in grid.columns:
+ %if column.visible:
+ <%
+ # Link
+ if column.link and column.link( item ):
+ href = url( **column.link( item ) )
+ else:
+ href = None
+ # Value (coerced to list so we can loop)
+ value = column.get_value( trans, grid, item )
+ if column.ncells == 1:
+ value = [ value ]
+ %>
+ %for cellnum, v in enumerate( value ):
+ <%
+ # Attach popup menu?
+ if column.attach_popup and cellnum == 0:
+ extra = '<a id="grid-%d-popup" class="popup-arrow" style="display: none;">▼</a>' % i
+ else:
+ extra = ""
+ %>
+ %if href:
+ <td><a href="${href}">${v}</a> ${extra}</td>
+ %else:
+ <td >${v}${extra}</td>
+ %endif
+ </td>
+ %endfor
+ %endif
+ %endfor
+ ## Actions column
+ <td>
+ <div popupmenu="grid-${i}-popup">
+ %for operation in grid.operations:
+ %if operation.allowed( item ):
+ <a class="action-button" href="${url( operation=operation.label, id=item.id )}">${operation.label}</a>
+ %endif
+ %endfor
+ </div>
+ </td>
+ </tr>
+ %endfor
+ </tbody>
+## <tfoot>
+## <tr>
+## <td></td>
+## <td colspan="100">
+## For <span class="grid-selected-count"></span> selected requests:
+## %for operation in grid.operations:
+## %if operation.allow_multiple:
+## <input type="submit" name="operation" value="${operation.label}" class="action-button">
+## %endif
+## %endfor
+## </td>
+## </tr>
+## </tfoot>
+ </table>
+</form>
+%endif
\ No newline at end of file
diff -r 267db48a2371 -r b46f27137744 templates/admin/requests/manage_request_types.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/requests/manage_request_types.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,60 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+<%def name="title()">request Types</%def>
+
+<h2>
+ %if deleted:
+ Deleted
+ %endif
+ Request Types
+</h2>
+
+<ul class="manage-table-actions">
+ <li>
+ <a class="action-button" href="${h.url_for( controller='admin', action='request_type', create=True )}"><span>Create a new request type</span></a>
+ </li>
+</ul>
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+%if not request_types:
+ %if deleted:
+ There are no deleted request types
+ %else:
+ There are no request types.
+ %endif
+%else:
+ <table class="grid">
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ <th>Request Form</th>
+ <th>Sample Form</th>
+ </tr>
+ </thead>
+ <tbody>
+ %for request_type in request_types:
+ <tr>
+ <td><b><a href="${h.url_for( controller='admin', action='request_type', edit='True', id=request_type.id)}">${request_type.name}</a></b></td>
+ <td><i>${request_type.desc}</i></td>
+ <% for form in forms:
+ if form.id == request_type.request_form_id:
+ form_name = form.name
+ break
+ %>
+ <td><a href="${h.url_for( controller='forms', action='edit', form_id=request_type.request_form_id, read_only=True)}">${form_name}</a></td>
+ <% for form in forms:
+ if form.id == request_type.sample_form_id:
+ form_name = form.name
+ break
+ %>
+ <td><a href="${h.url_for( controller='forms', action='edit', form_id=request_type.sample_form_id, read_only=True)}">${form_name}</a></td>
+ </tr>
+ %endfor
+ </tbody>
+ </table>
+%endif
\ No newline at end of file
diff -r 267db48a2371 -r b46f27137744 templates/admin/requests/view_request.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/requests/view_request.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,20 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">Request Details: '${request_details[0]['value']}'</div>
+ %for index, rd in enumerate(request_details):
+ <div class="form-row">
+ <label>${rd['label']}</label>
+ ##<i>${rd['helptext']}</i>
+ ${rd['value']}
+ </div>
+ <div style="clear: both"></div>
+ %endfor
+ </div>
+</div>
\ No newline at end of file
diff -r 267db48a2371 -r b46f27137744 templates/admin/samples/change_state.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/samples/change_state.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,30 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+<div class="toolForm">
+ <div class="toolFormTitle">${title}</div>
+ <div class="toolFormBody">
+ <form name="event" action="${h.url_for( controller='requests_admin', action='save_state', new=True, sample_id_list=sample_id_list)}" method="post" >
+ %for w in widgets:
+ <div class="form-row">
+ <label>
+ ${w[0]}
+ </label>
+ ${w[1].get_html()}
+ %if w[0] == 'Comments':
+ <div class="toolParamHelp" style="clear: both;">
+ Optional
+ </div>
+ %endif
+ </div>
+ %endfor
+ <div class="form-row">
+ <input type="submit" name="add_event" value="Save"/>
+ </div>
+ </form>
+ </div>
+</div>
\ No newline at end of file
diff -r 267db48a2371 -r b46f27137744 templates/admin/samples/edit_sample.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/samples/edit_sample.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,83 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">Edit sample named: ${values.content['Name']}</div>
+ <div class="toolFormBody">
+ <form name="sample" action="${h.url_for( controller='sample', action='do', save_changes=True, sample_id=sample.id )}" method="post" >
+ <div class="form-row">
+ <label>
+ Library:
+ </label>
+ <select name="library_id">
+ %for library in libraries:
+ <option value="${library.id}">${library.name}</option>
+ %endfor
+ </select>
+ </div>
+ %for i, field in enumerate(form.fields):
+ <div class="form-row">
+ <label>${field['label']}</label>
+ %if field['type'] == 'TextField':
+ <input type="text" name="${field['label']}" value="${values.content[field['label']]}" size="40"/>
+ %elif field['type'] == 'TextArea':
+ <textarea name="${field['label']}" rows="3" cols="35">${values.content[field['label']]}</textarea>
+ %elif field['type'] == 'CheckBox':
+ %if values.content[field['label']] == "true":
+ <input type="checkbox" name="${field['label']}" value="true" checked>
+ %else:
+ <input type="checkbox" name="${field['label']}" value="true">
+ %endif
+ %elif field['type'] == 'SelectBox':
+ <select name="${field['label']}">
+ %for ft in field['selectlist']:
+ %if ft == values.content[field['label']]:
+ <option value="${ft}" selected>${ft}</option>
+ %else:
+ <option value="${ft}">${ft}</option>
+ %endif
+ %endfor
+ </select>
+ %endif
+ <div class="toolParamHelp" style="clear: both;">
+ ${field['helptext']}
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ %endfor
+ <div class="form-row">
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="hidden" name="new" value="submitted" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <input type="submit" name="create_library_button" value="Save"/>
+ </div>
+ </form>
+ </div>
+</div>
+<div class="toolForm">
+ <div class="toolFormBody">
+ <form name="event" action="${h.url_for( controller='admin', action='event', new=True, sample_id=sample.id)}" method="post" >
+ <div class="form-row">
+ <label>
+ Change sample state to:
+ </label>
+ <select name="state_id">
+ %for state in states:
+ <option value="${state.id}">${state.name}</option>
+ %endfor
+ </select>
+ </div>
+ <div class="form-row">
+ <input type="submit" name="add_event" value="Save"/>
+ </div>
+ </form>
+ </div>
+</div>
\ No newline at end of file
diff -r 267db48a2371 -r b46f27137744 templates/admin/samples/events.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/samples/events.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,33 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+<%def name="title()">Events for Sample ${sample_name}</%def>
+
+<h2>Events for Sample "${sample_name}" of Request: ${request}</h2>
+<h3>User: ${user.email}</h3>
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+
+<table class="grid">
+ <thead>
+ <tr>
+ <th>State</th>
+ <th>Description</th>
+ <th>Last Update</th>
+ <th>Comments</th>
+ </tr>
+ </thead>
+ <tbody>
+ %for state, desc, updated, comments in events_list:
+ <tr class="libraryRow libraryOrFolderRow" id="libraryRow">
+ <td><b><a>${state}</a></b></td>
+ <td><a>${desc}</a></td>
+ <td><a>${updated}</a></td>
+ <td><a>${comments}</a></td>
+ </tr>
+ %endfor
+ </tbody>
+</table>
\ No newline at end of file
diff -r 267db48a2371 -r b46f27137744 templates/admin/samples/grid.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/samples/grid.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,203 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+<%def name="title()">Browse Samples</%def>
+
+%if message:
+ <p>
+ <div class="${message_type}message transient-message">${message}</div>
+ <div style="clear: both"></div>
+ </p>
+%endif
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ <script type="text/javascript">
+ ## TODO: generalize and move into galaxy.base.js
+ $(document).ready(function() {
+ $(".grid").each( function() {
+ var grid = this;
+ var checkboxes = $(this).find("input.grid-row-select-checkbox");
+ var update = $(this).find( "span.grid-selected-count" );
+ $(checkboxes).each( function() {
+ $(this).change( function() {
+ var n = $(checkboxes).filter("[checked]").size();
+ update.text( n );
+ });
+ })
+ });
+ });
+ ## Can this be moved into base.mako?
+ %if refresh_frames:
+ %if 'masthead' in refresh_frames:
+ ## Refresh masthead == user changes (backward compatibility)
+ if ( parent.user_changed ) {
+ %if trans.user:
+ parent.user_changed( "${trans.user.email}", ${int( app.config.is_admin_user( trans.user ) )} );
+ %else:
+ parent.user_changed( null, false );
+ %endif
+ }
+ %endif
+ %if 'history' in refresh_frames:
+ if ( parent.frames && parent.frames.galaxy_history ) {
+ parent.frames.galaxy_history.location.href="${h.url_for( controller='root', action='history')}";
+ if ( parent.force_right_panel ) {
+ parent.force_right_panel( 'show' );
+ }
+ }
+ %endif
+ %if 'tools' in refresh_frames:
+ if ( parent.frames && parent.frames.galaxy_tools ) {
+ parent.frames.galaxy_tools.location.href="${h.url_for( controller='root', action='tool_menu')}";
+ if ( parent.force_left_panel ) {
+ parent.force_left_panel( 'show' );
+ }
+ }
+ %endif
+ %endif
+ </script>
+</%def>
+
+<%def name="stylesheets()">
+ <link href="${h.url_for('/static/style/base.css')}" rel="stylesheet" type="text/css" />
+ <style>
+ ## Not generic to all grids -- move to base?
+ .count-box {
+ min-width: 1.1em;
+ padding: 5px;
+ border-width: 1px;
+ border-style: solid;
+ text-align: center;
+ display: inline-block;
+ }
+ </style>
+</%def>
+
+<div class="grid-header">
+ <h2>Samples associated with request: ${grid.request.name}</h2>
+ <h3>User: ${grid.user.email}</h3>
+## %if len(query.all()):
+## <span class="title">Filter:</span>
+## %for i, filter in enumerate( grid.standard_filters ):
+## %if i > 0:
+## <span>|</span>
+## %endif
+## <span class="filter"><a href="${url( filter.get_url_args() )}">${filter.label}</a></span>
+## %endfor
+## %endif
+</div>
+
+%if not len(query.all()):
+ There are no sample(s).
+%else:
+<form name="history_actions" action="${url()}" method="post" >
+ <table class="grid">
+ <thead>
+ <tr>
+ <th></th>
+ %for column in grid.columns:
+ %if column.visible:
+ <%
+ href = ""
+ extra = ""
+ if column.sortable:
+ if sort_key == column.key:
+ if sort_order == "asc":
+ href = url( sort=( "-" + column.key ) )
+ extra = "↓"
+ else:
+ href = url( sort=( column.key ) )
+ extra = "↑"
+ else:
+ href = url( sort=column.key )
+ %>
+ <th\
+ %if column.ncells > 1:
+ colspan="${column.ncells}"
+ %endif
+ >
+ %if href:
+ <a href="${href}">${column.label}</a>
+ %else:
+ ${column.label}
+ %endif
+ <span>${extra}</span>
+ </th>
+ %endif
+ %endfor
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ %for i, item in enumerate( query ):
+ <tr \
+ %if current_item == item:
+ class="current" \
+ %endif
+ >
+ ## Item selection column
+ <td style="width: 1.5em;">
+ <input type="checkbox" name="id" value=${trans.security.encode_id( item.id )} class="grid-row-select-checkbox" />
+ </td>
+ ## Data columns
+ %for column in grid.columns:
+ %if column.visible:
+ <%
+ # Link
+ if column.link and column.link( item ):
+ href = url( **column.link( item ) )
+ else:
+ href = None
+ # Value (coerced to list so we can loop)
+ value = column.get_value( trans, grid, item )
+ if column.ncells == 1:
+ value = [ value ]
+ %>
+ %for cellnum, v in enumerate( value ):
+ <%
+ # Attach popup menu?
+ if column.attach_popup and cellnum == 0:
+ extra = '<a id="grid-%d-popup" class="popup-arrow" style="display: none;">▼</a>' % i
+ else:
+ extra = ""
+ %>
+ %if href:
+ <td><a href="${href}">${v}</a> ${extra}</td>
+ %else:
+ <td >${v}${extra}</td>
+ %endif
+ </td>
+ %endfor
+ %endif
+ %endfor
+ ## Actions column
+ <td>
+ <div popupmenu="grid-${i}-popup">
+ %for operation in grid.operations:
+ %if operation.allowed( item ):
+ <a class="action-button" href="${url( operation=operation.label, id=item.id )}">${operation.label}</a>
+ %endif
+ %endfor
+ </div>
+ </td>
+ </tr>
+ %endfor
+ </tbody>
+ <tfoot>
+ <tr>
+ <td></td>
+ <td colspan="100">
+ For <span class="grid-selected-count"></span> selected requests:
+ %for operation in grid.operations:
+ %if operation.allow_multiple:
+ <input type="submit" name="operation" value="${operation.label}" class="action-button">
+ %endif
+ %endfor
+ </td>
+ </tr>
+ </tfoot>
+ </table>
+</form>
+
+%endif
diff -r 267db48a2371 -r b46f27137744 templates/admin/samples/view_sample.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/admin/samples/view_sample.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,19 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">Sample Details: '${sample_details[0]['value']}'</div>
+ %for index, rd in enumerate(sample_details):
+ <div class="form-row">
+ <label>${rd['label']}</label>
+ ${rd['value']}
+ </div>
+ <div style="clear: both"></div>
+ %endfor
+ </div>
+</div>
diff -r 267db48a2371 -r b46f27137744 templates/base.mako
--- a/templates/base.mako Thu Jul 09 15:49:26 2009 -0400
+++ b/templates/base.mako Fri Jul 10 11:37:28 2009 -0400
@@ -29,4 +29,33 @@
## <![endif]-->
<script type="text/javascript" src="${h.url_for('/static/scripts/jquery.js')}"></script>
<script type="text/javascript" src="${h.url_for('/static/scripts/galaxy.base.js')}"></script>
+
+
</%def>
+
+<script type="text/javascript">
+$( function() {
+ $( "select[refresh_on_change='true']").change( function() {
+ var refresh = false;
+ var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
+ if ( refresh_on_change_values ) {
+ refresh_on_change_values = refresh_on_change_values.value.split( ',' );
+ var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
+ for( i= 0; i < refresh_on_change_values.length; i++ ) {
+ if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
+ refresh = true;
+ break;
+ }
+ }
+ }
+ else {
+ refresh = true;
+ }
+ if ( refresh ){
+ $( ':file' ).each( function() {
+ var file_value = $( this )[0].value;
+ } );
+ $( "#edit_form" ).submit();
+ }
+ });
+});
\ No newline at end of file
diff -r 267db48a2371 -r b46f27137744 templates/base_panels.mako
--- a/templates/base_panels.mako Thu Jul 09 15:49:26 2009 -0400
+++ b/templates/base_panels.mako Fri Jul 10 11:37:28 2009 -0400
@@ -153,6 +153,8 @@
${tab( "workflow", "Workflow", h.url_for( controller='workflow', action='index' ))}
${tab( "libraries", "Libraries", h.url_for( controller='library', action='index' ))}
+
+ ${tab( "requests", "Requests", h.url_for( controller='requests', action='index' ), visible = (trans.user and trans.request_types)) }
%if app.config.get_bool( 'enable_tracks', False ):
<span class="tab">
diff -r 267db48a2371 -r b46f27137744 templates/requests/grid.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/requests/grid.mako Fri Jul 10 11:37:28 2009 -0400
@@ -0,0 +1,210 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+<%def name="title()">Browse Samples</%def>
+
+%if message:
+ <p>
+ <div class="${message_type}message transient-message">${message}</div>
+ <div style="clear: both"></div>
+ </p>
+%endif
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ <script type="text/javascript">
+ ## TODO: generalize and move into galaxy.base.js
+ $(document).ready(function() {
+ $(".grid").each( function() {
+ var grid = this;
+ var checkboxes = $(this).find("input.grid-row-select-checkbox");
+ var update = $(this).find( "span.grid-selected-count" );
+ $(checkboxes).each( function() {
+ $(this).change( function() {
+ var n = $(checkboxes).filter("[checked]").size();
+ update.text( n );
+ });
+ })
+ });
+ });
+ ## Can this be moved into base.mako?
+ %if refresh_frames:
+ %if 'masthead' in refresh_frames:
+ ## Refresh masthead == user changes (backward compatibility)
+ if ( parent.user_changed ) {
+ %if trans.user:
+ parent.user_changed( "${trans.user.email}", ${int( app.config.is_admin_user( trans.user ) )} );
+ %else:
+ parent.user_changed( null, false );
+ %endif
+ }
+ %endif
+ %if 'history' in refresh_frames:
+ if ( parent.frames && parent.frames.galaxy_history ) {
+ parent.frames.galaxy_history.location.href="${h.url_for( controller='root', action='history')}";
+ if ( parent.force_right_panel ) {
+ parent.force_right_panel( 'show' );
+ }
+ }
+ %endif
+ %if 'tools' in refresh_frames:
+ if ( parent.frames && parent.frames.galaxy_tools ) {
+ parent.frames.galaxy_tools.location.href="${h.url_for( controller='root', action='tool_menu')}";
+ if ( parent.force_left_panel ) {
+ parent.force_left_panel( 'show' );
+ }
+ }
+ %endif
+ %endif
+ </script>
+</%def>
+
+<%def name="stylesheets()">
1
0
15 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/267db48a2371
changeset: 2470:267db48a2371
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Thu Jul 09 15:49:26 2009 -0400
description:
Some history sharing cleanup and a fix for job error reports.
5 file(s) affected in this change:
lib/galaxy/web/controllers/dataset.py
lib/galaxy/web/controllers/history.py
templates/history/list_shared.mako
templates/history/share.mako
test/functional/test_history_functions.py
diffs (364 lines):
diff -r 073c9a0b2467 -r 267db48a2371 lib/galaxy/web/controllers/dataset.py
--- a/lib/galaxy/web/controllers/dataset.py Wed Jul 08 17:01:49 2009 -0400
+++ b/lib/galaxy/web/controllers/dataset.py Thu Jul 09 15:49:26 2009 -0400
@@ -17,7 +17,7 @@
------------------------
This error report was sent from the Galaxy instance hosted on the server
-"${remote_hostname}"
+"${host}"
-----------------------------------------------------------------------------
This is in reference to output dataset ${dataset_id}.
-----------------------------------------------------------------------------
@@ -65,10 +65,10 @@
dataset = model.HistoryDatasetAssociation.get( id )
job = dataset.creating_job_associations[0].job
# Get the name of the server hosting the Galaxy instance from which this report originated
- remote_hostname = trans.request.remote_hostname
+ host = trans.request.host
# Build the email message
msg = MIMEText( string.Template( error_report_template )
- .safe_substitute( remote_hostname=remote_hostname,
+ .safe_substitute( host=host,
dataset_id=dataset.id,
email=email,
message=message,
diff -r 073c9a0b2467 -r 267db48a2371 lib/galaxy/web/controllers/history.py
--- a/lib/galaxy/web/controllers/history.py Wed Jul 08 17:01:49 2009 -0400
+++ b/lib/galaxy/web/controllers/history.py Thu Jul 09 15:49:26 2009 -0400
@@ -310,8 +310,9 @@
email=email,
send_to_err=send_to_err )
if params.get( 'share_button', False ):
- can_change, cannot_change, no_change_needed, send_to_err = \
- self._populate_restricted( trans, user, histories, send_to_users, None, send_to_err )
+ # The user has not yet made a choice about how to share, so dictionaries will be built for display
+ can_change, cannot_change, no_change_needed, unique_no_change_needed, send_to_err = \
+ self._populate_restricted( trans, user, histories, send_to_users, None, send_to_err, unique=True )
if can_change or cannot_change:
return trans.fill_template( "/history/share.mako",
histories=histories,
@@ -319,7 +320,7 @@
send_to_err=send_to_err,
can_change=can_change,
cannot_change=cannot_change,
- no_change_needed=no_change_needed )
+ no_change_needed=unique_no_change_needed )
if no_change_needed:
return self._share_histories( trans, user, send_to_err, histories=no_change_needed )
elif not send_to_err:
@@ -335,7 +336,8 @@
user = trans.get_user()
histories, send_to_users, send_to_err = self._get_histories_and_users( trans, user, id, email )
send_to_err = ''
- can_change, cannot_change, no_change_needed, send_to_err = \
+ # The user has made a choice, so dictionaries will be built for sharing
+ can_change, cannot_change, no_change_needed, unique_no_change_needed, send_to_err = \
self._populate_restricted( trans, user, histories, send_to_users, action, send_to_err )
# Now that we've populated the can_change, cannot_change, and no_change_needed dictionaries,
# we'll populate the histories_for_sharing dictionary from each of them.
@@ -408,13 +410,13 @@
send_to_err += "%s is not a valid Galaxy user. " % email_address
return histories, send_to_users, send_to_err
def _populate( self, trans, histories_for_sharing, other, send_to_err ):
- # this method will populate the histories_for_sharing dictionary with the users and
+ # This method will populate the histories_for_sharing dictionary with the users and
# histories in other, eliminating histories that have already been shared with the
# associated user. No security checking on datasets is performed.
# If not empty, the histories_for_sharing dictionary looks like:
# { userA: [ historyX, historyY ], userB: [ historyY ] }
# other looks like:
- # ## { userA: {historyX : [hda, hda], historyY : [hda]}, userB: {historyY : [hda]} }
+ # { userA: {historyX : [hda, hda], historyY : [hda]}, userB: {historyY : [hda]} }
for send_to_user, history_dict in other.items():
for history in history_dict:
# Make sure the current history has not already been shared with the current send_to_user
@@ -430,20 +432,22 @@
elif history not in histories_for_sharing[ send_to_user ]:
histories_for_sharing[ send_to_user ].append( history )
return histories_for_sharing, send_to_err
- def _populate_restricted( self, trans, user, histories, send_to_users, action, send_to_err ):
+ def _populate_restricted( self, trans, user, histories, send_to_users, action, send_to_err, unique=False ):
# The user may be attempting to share histories whose datasets cannot all be accessed by other users.
# If this is the case, the user sharing the histories can:
# 1) action=='public': choose to make the datasets public if he is permitted to do so
# 2) action=='private': automatically create a new "sharing role" allowing protected
# datasets to be accessed only by the desired users
- # 3) action=='share_anyway': share only what can be shared when no permissions are changed
- # 4) action=='no_share': Do not share anything
- # In addition, the user may be sharing a history with a user with which the history was already shared
- # and it will not be shared twice.
- # This method will populate the can_change, cannot_change and no_change_needed dictionaries.
+ # This method will populate the can_change, cannot_change and no_change_needed dictionaries, which
+ # are used for either displaying to the user, letting them make 1 of the choices above, or sharing
+ # after the user has made a choice. They will be used for display if 'unique' is True, and will look
+ # like: {historyX : [hda, hda], historyY : [hda] }
+ # For sharing, they will look like:
+ # { userA: {historyX : [hda, hda], historyY : [hda]}, userB: {historyY : [hda]} }
can_change = {}
cannot_change = {}
no_change_needed = {}
+ unique_no_change_needed = {}
for history in histories:
for send_to_user in send_to_users:
# Make sure the current history has not already been shared with the current send_to_user
@@ -456,7 +460,15 @@
# Only deal with datasets that have not been purged
for hda in history.activatable_datasets:
if trans.app.security_agent.dataset_is_public( hda.dataset ):
- # Build the dict that will show the user what doesn't need to be changed
+ # The no_change_needed dictionary is a special case. If both of can_change
+ # and cannot_change are empty, no_change_needed will used for sharing. Otherwise
+ # unique_no_change_needed will be used for displaying, so we need to populate both.
+ # Build the dictionaries for display, containing unique histories only
+ if history not in unique_no_change_needed:
+ unique_no_change_needed[ history ] = [ hda ]
+ else:
+ unique_no_change_needed[ history ].append( hda )
+ # Build the dictionaries for sharing
if send_to_user not in no_change_needed:
no_change_needed[ send_to_user ] = {}
if history not in no_change_needed[ send_to_user ]:
@@ -473,28 +485,40 @@
# The current user has authority to change permissions on the current dataset because
# they have permission to manage permissions on the dataset and the dataset is not associated
# with a library.
- if send_to_user not in can_change:
- # Build the set of histories / datasets on which the current user has authority
- # to "manage permissions".
- can_change[ send_to_user ] = {}
- if history not in can_change[ send_to_user ]:
- can_change[ send_to_user ][ history ] = [ hda ]
+ if unique:
+ # Build the dictionaries for display, containing unique histories only
+ if history not in can_change:
+ can_change[ history ] = [ hda ]
+ else:
+ can_change[ history ].append( hda )
else:
- can_change[ send_to_user ][ history ].append( hda )
+ # Build the dictionaries for sharing
+ if send_to_user not in can_change:
+ can_change[ send_to_user ] = {}
+ if history not in can_change[ send_to_user ]:
+ can_change[ send_to_user ][ history ] = [ hda ]
+ else:
+ can_change[ send_to_user ][ history ].append( hda )
else:
if action in [ "private", "public" ]:
- # Don't change stuff that the user doesn't have permission to change
+ # The user has made a choice, so 'unique' doesn't apply. Don't change stuff
+ # that the user doesn't have permission to change
continue
- #elif send_to_user not in cannot_change:
- if send_to_user not in cannot_change:
- # Build the set of histories / datasets on which the current user does
- # not have authority to "manage permissions".
- cannot_change[ send_to_user ] = {}
- if history not in cannot_change[ send_to_user ]:
- cannot_change[ send_to_user ][ history ] = [ hda ]
+ if unique:
+ # Build the dictionaries for display, containing unique histories only
+ if history not in cannot_change:
+ cannot_change[ history ] = [ hda ]
+ else:
+ cannot_change[ history ].append( hda )
else:
- cannot_change[ send_to_user ][ history ].append( hda )
- return can_change, cannot_change, no_change_needed, send_to_err
+ # Build the dictionaries for sharing
+ if send_to_user not in cannot_change:
+ cannot_change[ send_to_user ] = {}
+ if history not in cannot_change[ send_to_user ]:
+ cannot_change[ send_to_user ][ history ] = [ hda ]
+ else:
+ cannot_change[ send_to_user ][ history ].append( hda )
+ return can_change, cannot_change, no_change_needed, unique_no_change_needed, send_to_err
def _share_histories( self, trans, user, send_to_err, histories={} ):
# histories looks like: { userA: [ historyX, historyY ], userB: [ historyY ] }
msg = ""
@@ -605,6 +629,7 @@
if clone_choice == 'activatable':
new_history = history.copy( name=name, target_user=user, activatable=True )
elif clone_choice == 'active':
+ name += " (active items only)"
new_history = history.copy( name=name, target_user=user )
# Render the list view
return trans.show_ok_message( 'Clone with name "%s" is now included in your list of stored histories.' % new_history.name )
diff -r 073c9a0b2467 -r 267db48a2371 templates/history/list_shared.mako
--- a/templates/history/list_shared.mako Wed Jul 08 17:01:49 2009 -0400
+++ b/templates/history/list_shared.mako Thu Jul 09 15:49:26 2009 -0400
@@ -18,7 +18,7 @@
${history.name}
<a id="shared-${i}-popup" class="popup-arrow" style="display: none;">▼</a>
<div popupmenu="shared-${i}-popup">
- <a class="action-button" href="${h.url_for( controller='history', action='clone', id=trans.security.encode_id( history.id ), clone_choice='activatable' )}">Clone</a>
+ <a class="action-button" href="${h.url_for( controller='history', action='clone', id=trans.security.encode_id( history.id ) )}">Clone</a>
</div>
</td>
<td>${history.user.email}</td>
diff -r 073c9a0b2467 -r 267db48a2371 templates/history/share.mako
--- a/templates/history/share.mako Wed Jul 08 17:01:49 2009 -0400
+++ b/templates/history/share.mako Thu Jul 09 15:49:26 2009 -0400
@@ -64,35 +64,14 @@
<input type="hidden" name="id" value="${trans.security.encode_id( history.id )}">
%endfor
%if no_change_needed:
+ ## no_change_needed looks like: {historyX : [hda, hda], historyY : [hda] }
<div style="clear: both"></div>
<div class="form-row">
<div class="donemessage">
The following datasets can be shared with ${email} with no changes
</div>
- </div>
- ## no_change_needed looks like:
- ## { userA: {historyX : [hda, hda], historyY : [hda]}, userB: {historyY : [hda]} }
- <%
- # TODO: move generation of these unique dictionaries to the history controller
- # Build the list of unique histories and datasets
- unique_stuff = {}
- %>
- %for user, history_dict in no_change_needed.items():
- %for history, hdas in history_dict.items():
- <%
- if history in unique_stuff:
- for hda in hdas:
- if hda not in unique_stuff[ history ]:
- unique_stuff[ history ].append( hda )
- else:
- unique_stuff[ history ] = []
- for hda in hdas:
- if hda not in unique_stuff[ history ]:
- unique_stuff[ history ].append( hda )
- %>
- %endfor
- %endfor
- %for history, hdas in unique_stuff.items():
+ </div>
+ %for history, hdas in no_change_needed.items():
<div class="form-row">
<label>History</label>
${history.name}
@@ -104,40 +83,22 @@
%for hda in hdas:
<div class="form-row">
${hda.name}
+ %if hda.deleted:
+ (deleted)
+ %endif
</div>
%endfor
%endfor
%endif
%if can_change:
+ ## can_change looks like: {historyX : [hda, hda], historyY : [hda] }
<div style="clear: both"></div>
<div class="form-row">
<div class="warningmessage">
The following datasets can be shared with ${email} by updating their permissions
</div>
</div>
- ## can_change looks like:
- ## { userA: {historyX : [hda, hda], historyY : [hda]}, userB: {historyY : [hda]} }
- <%
- # TODO: move generation of these unique dictionaries to the history controller
- # Build the list of unique histories and datasets
- unique_stuff = {}
- %>
- %for user, history_dict in can_change.items():
- %for history, hdas in history_dict.items():
- <%
- if history in unique_stuff:
- for hda in hdas:
- if hda not in unique_stuff[ history ]:
- unique_stuff[ history ].append( hda )
- else:
- unique_stuff[ history ] = []
- for hda in hdas:
- if hda not in unique_stuff[ history ]:
- unique_stuff[ history ].append( hda )
- %>
- %endfor
- %endfor
- %for history, hdas in unique_stuff.items():
+ %for history, hdas in can_change.items():
<div class="form-row">
<label>History</label>
${history.name}
@@ -149,11 +110,15 @@
%for hda in hdas:
<div class="form-row">
${hda.name}
+ %if hda.deleted:
+ (deleted)
+ %endif
</div>
%endfor
%endfor
%endif
%if cannot_change:
+ ## cannot_change looks like: {historyX : [hda, hda], historyY : [hda] }
<div style="clear: both"></div>
<div class="form-row">
<div class="errormessage">
@@ -161,29 +126,7 @@
change the permissions on them
</div>
</div>
- ## cannot_change looks like:
- ## { userA: {historyX : [hda, hda], historyY : [hda]}, userB: {historyY : [hda]} }
- <%
- # TODO: move generation of these unique dictionaries to the history controller
- # Build the list of unique histories and datasets
- unique_stuff = {}
- %>
- %for user, history_dict in can_change.items():
- %for history, hdas in history_dict.items():
- <%
- if history in unique_stuff:
- for hda in hdas:
- if hda not in unique_stuff[ history ]:
- unique_stuff[ history ].append( hda )
- else:
- unique_stuff[ history ] = []
- for hda in hdas:
- if hda not in unique_stuff[ history ]:
- unique_stuff[ history ].append( hda )
- %>
- %endfor
- %endfor
- %for history, hdas in unique_stuff.items():
+ %for history, hdas in cannot_change.items():
<div class="form-row">
<label>History</label>
${history.name}
@@ -195,10 +138,17 @@
%for hda in hdas:
<div class="form-row">
${hda.name}
+ %if hda.deleted:
+ (deleted)
+ %endif
</div>
%endfor
%endfor
%endif
+ <div class="toolFormTitle"></div>
+ <div class="form-row">
+ Deleted items can be eliminated by the users with which you are sharing the history.
+ </div>
<div class="form-row">
<label>How would you like to proceed?</label>
</div>
diff -r 073c9a0b2467 -r 267db48a2371 test/functional/test_history_functions.py
--- a/test/functional/test_history_functions.py Wed Jul 08 17:01:49 2009 -0400
+++ b/test/functional/test_history_functions.py Thu Jul 09 15:49:26 2009 -0400
@@ -253,7 +253,7 @@
# Check list of histories to make sure shared history3 was cloned
self.view_stored_active_histories( check_str="Clone of '%s'" % history3.name )
# Switch to the cloned history to make sure activatable datasets were cloned
- self.switch_history( id=self.security.encode_id( history3_clone3.id ), name=history3_clone3.name )
+ self.switch_history( id=self.security.encode_id( history3_clone3.id ) )
# Make sure the deleted datasets are NOT included in the cloned history
try:
self.check_history_for_string( 'This dataset has been deleted.', show_deleted=True )
1
0
09 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/073c9a0b2467
changeset: 2469:073c9a0b2467
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Wed Jul 08 17:01:49 2009 -0400
description:
Change folder.active_datasets mapper to a property, and correct the list of library_datasets it returns - fixes the 'bug' part of ticket # 102 reported by Ross Lazarus.
3 file(s) affected in this change:
lib/galaxy/model/__init__.py
lib/galaxy/model/mapping.py
lib/galaxy/web/controllers/admin.py
diffs (54 lines):
diff -r 035c0dc31963 -r 073c9a0b2467 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py Wed Jul 08 15:25:57 2009 -0400
+++ b/lib/galaxy/model/__init__.py Wed Jul 08 17:01:49 2009 -0400
@@ -734,11 +734,17 @@
def active_components( self ):
return list( self.active_folders ) + list( self.active_datasets )
@property
+ def active_datasets( self ):
+ # This needs to be a list
+ return [ ld for ld in self.datasets if not ld.library_dataset_dataset_association.deleted ]
+ @property
def activatable_datasets( self ):
- return [ ld for ld in self.datasets if not ld.library_dataset_dataset_association.dataset.deleted ] #this needs to be a list
+ # This needs to be a list
+ return [ ld for ld in self.datasets if not ld.library_dataset_dataset_association.dataset.deleted ]
@property #make this a relation
def activatable_folders( self ):
- return [ folder for folder in self.folders if not folder.purged ] #this needs to be a list
+ # This needs to be a list
+ return [ folder for folder in self.folders if not folder.purged ]
class LibraryDataset( object ):
# This class acts as a proxy to the currently selected LDDA
diff -r 035c0dc31963 -r 073c9a0b2467 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py Wed Jul 08 15:25:57 2009 -0400
+++ b/lib/galaxy/model/mapping.py Wed Jul 08 17:01:49 2009 -0400
@@ -706,11 +706,6 @@
primaryjoin=( ( LibraryDataset.table.c.folder_id == LibraryFolder.table.c.id ) ),
order_by=asc( LibraryDataset.table.c.order_id ),
lazy=False,
- viewonly=True ),
- active_datasets=relation( LibraryDataset,
- primaryjoin=( ( LibraryDataset.table.c.folder_id == LibraryFolder.table.c.id ) & ( not_( LibraryDataset.table.c.deleted ) ) ),
- order_by=asc( LibraryDataset.table.c.order_id ),
- lazy=False,
viewonly=True )
) )
diff -r 035c0dc31963 -r 073c9a0b2467 lib/galaxy/web/controllers/admin.py
--- a/lib/galaxy/web/controllers/admin.py Wed Jul 08 15:25:57 2009 -0400
+++ b/lib/galaxy/web/controllers/admin.py Wed Jul 08 17:01:49 2009 -0400
@@ -1937,10 +1937,11 @@
ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( id )
ldda.deleted = True
ldda.flush()
- msg = "The selected datasets have been removed from this library"
+ msg = "The selected datasets have been removed from this library"
trans.response.send_redirect( web.url_for( controller='admin',
action='browse_library',
id=library_id,
+ show_deleted=False,
msg=util.sanitize_text( msg ),
messagetype='done' ) )
else:
1
0
09 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/035c0dc31963
changeset: 2468:035c0dc31963
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Wed Jul 08 15:25:57 2009 -0400
description:
Add remote_user logout anchor href configuration provided by Morita Hideyuki.
3 file(s) affected in this change:
lib/galaxy/config.py
templates/base_panels.mako
universe_wsgi.ini.sample
diffs (60 lines):
diff -r 319e2ba6a7be -r 035c0dc31963 lib/galaxy/config.py
--- a/lib/galaxy/config.py Wed Jul 08 14:10:45 2009 -0400
+++ b/lib/galaxy/config.py Wed Jul 08 15:25:57 2009 -0400
@@ -42,6 +42,7 @@
self.set_metadata_externally = string_as_bool( kwargs.get( "set_metadata_externally", "False" ) )
self.use_remote_user = string_as_bool( kwargs.get( "use_remote_user", "False" ) )
self.remote_user_maildomain = kwargs.get( "remote_user_maildomain", None )
+ self.remote_user_logout_href = kwargs.get( "remote_user_logout_href", None )
self.require_login = string_as_bool( kwargs.get( "require_login", "False" ) )
self.allow_user_creation = string_as_bool( kwargs.get( "allow_user_creation", "True" ) )
self.allow_user_deletion = string_as_bool( kwargs.get( "allow_user_deletion", "False" ) )
diff -r 319e2ba6a7be -r 035c0dc31963 templates/base_panels.mako
--- a/templates/base_panels.mako Wed Jul 08 14:10:45 2009 -0400
+++ b/templates/base_panels.mako Wed Jul 08 15:25:57 2009 -0400
@@ -199,16 +199,22 @@
</ul>
<ul class="loggedin-only" style="${style2}">
<li>Logged in as <span id="user-email">${user_email}</span></li>
- <li><a target="galaxy_main" href="${h.url_for( controller='user', action='index' )}">Preferences</a></li>
- <%
- if app.config.require_login:
- logout_target = ""
- logout_url = h.url_for( controller='root', action='index', m_c='user', m_a='logout' )
- else:
- logout_target = "galaxy_main"
- logout_url = h.url_for( controller='user', action='logout' )
- %>
- <li><a target="${logout_target}" href="${logout_url}">Logout</a></li>
+ %if app.config.use_remote_user:
+ %if app.config.remote_user_logout_href:
+ <li><a href="${app.config.remote_user_logout_href}" target="_top">Logout</a></li>
+ %endif
+ %else:
+ <li><a target="galaxy_main" href="${h.url_for( controller='user', action='index' )}">Preferences</a></li>
+ <%
+ if app.config.require_login:
+ logout_target = ""
+ logout_url = h.url_for( controller='root', action='index', m_c='user', m_a='logout' )
+ else:
+ logout_target = "galaxy_main"
+ logout_url = h.url_for( controller='user', action='logout' )
+ %>
+ <li><a target="${logout_target}" href="${logout_url}">Logout</a></li>
+ %endif
</ul>
</div>
</span>
diff -r 319e2ba6a7be -r 035c0dc31963 universe_wsgi.ini.sample
--- a/universe_wsgi.ini.sample Wed Jul 08 14:10:45 2009 -0400
+++ b/universe_wsgi.ini.sample Wed Jul 08 15:25:57 2009 -0400
@@ -141,6 +141,9 @@
# method just returns bare usernames, set a default mail domain
#remote_user_maildomain = example.org
+# If use_remote_user is enabled, set a logout anchor href option
+#remote_user_logout_href = /logout
+
# this should be a comma-separated list of valid Galaxy users
#admin_users = user1@example.org,user2@example.org
1
0
09 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/319e2ba6a7be
changeset: 2467:319e2ba6a7be
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Wed Jul 08 14:10:45 2009 -0400
description:
Enhance history cloning to allow for cloning active or activatable datasets from the original history - resolves ticket # 29.
6 file(s) affected in this change:
lib/galaxy/model/__init__.py
lib/galaxy/web/controllers/history.py
templates/history/clone.mako
templates/history/list_shared.mako
test/base/twilltestcase.py
test/functional/test_history_functions.py
diffs (395 lines):
diff -r 539d481c8f59 -r 319e2ba6a7be lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py Tue Jul 07 20:32:00 2009 -0400
+++ b/lib/galaxy/model/__init__.py Wed Jul 08 14:10:45 2009 -0400
@@ -214,17 +214,21 @@
if genome_build not in [None, '?']:
self.genome_build = genome_build
self.datasets.append( dataset )
- def copy( self, name=None, target_user=None ):
+ def copy( self, name=None, target_user=None, activatable=False ):
if not name:
name = self.name
if not target_user:
target_user = self.user
new_history = History( name=name, user=target_user )
new_history.flush()
- for data in self.datasets:
- new_data = data.copy( copy_children=True, target_history=new_history )
- new_history.add_dataset( new_data, set_hid = False )
- new_data.flush()
+ if activatable:
+ hdas = self.activatable_datasets
+ else:
+ hdas = self.active_datasets
+ for hda in hdas:
+ new_hda = hda.copy( copy_children=True, target_history=new_history )
+ new_history.add_dataset( new_hda, set_hid = False )
+ new_hda.flush()
new_history.hid_counter = self.hid_counter
new_history.flush()
return new_history
diff -r 539d481c8f59 -r 319e2ba6a7be lib/galaxy/web/controllers/history.py
--- a/lib/galaxy/web/controllers/history.py Tue Jul 07 20:32:00 2009 -0400
+++ b/lib/galaxy/web/controllers/history.py Wed Jul 08 14:10:45 2009 -0400
@@ -310,8 +310,8 @@
email=email,
send_to_err=send_to_err )
if params.get( 'share_button', False ):
- can_change, cannot_change, no_change_needed = \
- self._populate_restricted( trans, user, histories, send_to_users, None )
+ can_change, cannot_change, no_change_needed, send_to_err = \
+ self._populate_restricted( trans, user, histories, send_to_users, None, send_to_err )
if can_change or cannot_change:
return trans.fill_template( "/history/share.mako",
histories=histories,
@@ -335,8 +335,8 @@
user = trans.get_user()
histories, send_to_users, send_to_err = self._get_histories_and_users( trans, user, id, email )
send_to_err = ''
- can_change, cannot_change, no_change_needed = \
- self._populate_restricted( trans, user, histories, send_to_users, action )
+ can_change, cannot_change, no_change_needed, send_to_err = \
+ self._populate_restricted( trans, user, histories, send_to_users, action, send_to_err )
# Now that we've populated the can_change, cannot_change, and no_change_needed dictionaries,
# we'll populate the histories_for_sharing dictionary from each of them.
histories_for_sharing = {}
@@ -430,7 +430,7 @@
elif history not in histories_for_sharing[ send_to_user ]:
histories_for_sharing[ send_to_user ].append( history )
return histories_for_sharing, send_to_err
- def _populate_restricted( self, trans, user, histories, send_to_users, action ):
+ def _populate_restricted( self, trans, user, histories, send_to_users, action, send_to_err ):
# The user may be attempting to share histories whose datasets cannot all be accessed by other users.
# If this is the case, the user sharing the histories can:
# 1) action=='public': choose to make the datasets public if he is permitted to do so
@@ -494,7 +494,7 @@
cannot_change[ send_to_user ][ history ] = [ hda ]
else:
cannot_change[ send_to_user ][ history ].append( hda )
- return can_change, cannot_change, no_change_needed
+ return can_change, cannot_change, no_change_needed, send_to_err
def _share_histories( self, trans, user, send_to_err, histories={} ):
# histories looks like: { userA: [ historyX, historyY ], userB: [ historyY ] }
msg = ""
@@ -585,8 +585,12 @@
return trans.show_message( "<p>%s" % change_msg, refresh_frames=['history'] )
@web.expose
@web.require_login( "clone shared Galaxy history" )
- def clone( self, trans, id ):
+ def clone( self, trans, id, **kwd ):
history = get_history( trans, id, check_ownership=False )
+ params = util.Params( kwd )
+ clone_choice = params.get( 'clone_choice', None )
+ if not clone_choice:
+ return trans.fill_template( "/history/clone.mako", history=history )
user = trans.get_user()
if history.user == user:
owner = True
@@ -598,7 +602,10 @@
name = "Clone of '%s'" % history.name
if not owner:
name += " shared by '%s'" % history.user.email
- new_history = history.copy( name=name, target_user=user )
+ if clone_choice == 'activatable':
+ new_history = history.copy( name=name, target_user=user, activatable=True )
+ elif clone_choice == 'active':
+ new_history = history.copy( name=name, target_user=user )
# Render the list view
return trans.show_ok_message( 'Clone with name "%s" is now included in your list of stored histories.' % new_history.name )
diff -r 539d481c8f59 -r 319e2ba6a7be templates/history/clone.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/history/clone.mako Wed Jul 08 14:10:45 2009 -0400
@@ -0,0 +1,25 @@
+<% _=n_ %>
+<%inherit file="/base.mako"/>
+<%def name="title()">Clone History</%def>
+
+<div class="toolForm">
+ <div class="toolFormTitle">Clone History</div>
+ <div class="toolFormBody">
+ <form action="${h.url_for( controller='history', action='clone' )}" method="post" >
+ <div class="form-row">
+ <input type="hidden" name="id" value="${trans.security.encode_id( history.id )}">
+ You can clone the history such that the clone will include all items in the original
+ history, or you can eliminate the original history's deleted items from the clone.
+ </div>
+ <div class="form-row">
+ <input type="radio" name="clone_choice" value="activatable"> Clone all history items, including deleted items
+ </div>
+ <div class="form-row">
+ <input type="radio" name="clone_choice" value="active"> Clone only items that are not deleted
+ </div>
+ <div class="form-row">
+ <input type="submit" name="clone_choice_button" value="Clone">
+ </div>
+ </form>
+ </div>
+</div>
diff -r 539d481c8f59 -r 319e2ba6a7be templates/history/list_shared.mako
--- a/templates/history/list_shared.mako Tue Jul 07 20:32:00 2009 -0400
+++ b/templates/history/list_shared.mako Wed Jul 08 14:10:45 2009 -0400
@@ -18,7 +18,7 @@
${history.name}
<a id="shared-${i}-popup" class="popup-arrow" style="display: none;">▼</a>
<div popupmenu="shared-${i}-popup">
- <a class="action-button" href="${h.url_for( controller='history', action='clone', id=trans.security.encode_id( history.id ) )}">Clone</a>
+ <a class="action-button" href="${h.url_for( controller='history', action='clone', id=trans.security.encode_id( history.id ), clone_choice='activatable' )}">Clone</a>
</div>
</td>
<td>${history.user.email}</td>
diff -r 539d481c8f59 -r 319e2ba6a7be test/base/twilltestcase.py
--- a/test/base/twilltestcase.py Tue Jul 07 20:32:00 2009 -0400
+++ b/test/base/twilltestcase.py Wed Jul 08 14:10:45 2009 -0400
@@ -121,10 +121,13 @@
page = self.last_page()
if page.find( 'error' ) > -1:
raise AssertionError('Errors in the history for user %s' % self.user )
- def check_history_for_string( self, patt ):
+ def check_history_for_string( self, patt, show_deleted=False ):
"""Looks for 'string' in history page"""
self.home()
- self.visit_page( "history" )
+ if show_deleted:
+ self.visit_page( "history?show_deleted=True" )
+ else:
+ self.visit_page( "history" )
for subpatt in patt.split():
tc.find(subpatt)
self.home()
@@ -268,11 +271,6 @@
self.home()
def switch_history( self, id='', name='' ):
"""Switches to a history in the current list of histories"""
- data_list = self.get_histories_as_data_list()
- self.assertTrue( data_list )
- if not id:
- history = history_list[0]
- id = history.get( 'id' )
self.visit_url( "%s/history/list?operation=switch&id=%s" % ( self.url, id ) )
if name:
self.check_history_for_string( name )
@@ -305,11 +303,15 @@
if check_str2:
self.check_page_for_string( check_str2 )
self.home()
- def clone_history( self, history_id, check_str1='' ):
+ def clone_history( self, history_id, clone_choice, check_str1='', check_str_after_submit='' ):
self.home()
self.visit_page( "history/clone?id=%s" % history_id )
if check_str1:
self.check_page_for_string( check_str1 )
+ tc.fv( '1', 'clone_choice', clone_choice )
+ tc.submit( 'clone_choice_button' )
+ if check_str_after_submit:
+ self.check_page_for_string( check_str_after_submit )
self.home()
def enable_import_via_link( self, history_id, check_str='', check_str_after_submit='' ):
self.home()
@@ -366,34 +368,22 @@
self.visit_page( "edit?hid=%d" % hid )
for subpatt in patt.split():
tc.find(subpatt)
- def delete_history_item( self, hid, check_str='' ):
+ def delete_history_item( self, hda_id, check_str='' ):
"""Deletes an item from a history"""
try:
- hid = int( hid )
+ hda_id = int( hda_id )
except:
- raise AssertionError, "Invalid hid '%s' - must be int" % hid
- hid = str(hid)
- data_list = self.get_history_as_data_list()
- self.assertTrue( data_list )
- elems = [ elem for elem in data_list if elem.get( 'hid' ) == hid ]
- self.assertEqual( len( elems ), 1 )
- self.home()
- self.visit_page( "delete?id=%s" % elems[0].get( 'id' ) )
+ raise AssertionError, "Invalid hda_id '%s' - must be int" % hda_id
+ self.visit_url( "%s/root/delete?show_deleted_on_refresh=False&id=%s" % ( self.url, hda_id ) )
if check_str:
self.check_page_for_string( check_str )
- def undelete_history_item( self, hid, show_deleted=False, check_str='' ):
+ def undelete_history_item( self, hda_id, check_str='' ):
"""Un-deletes a deleted item in a history"""
try:
- hid = int( hid )
+ hda_id = int( hda_id )
except:
- raise AssertionError, "Invalid hid '%s' - must be int" % hid
- hid = str( hid )
- data_list = self.get_history_as_data_list( show_deleted=show_deleted )
- self.assertTrue( data_list )
- elems = [ elem for elem in data_list if elem.get( 'hid' ) == hid ]
- self.assertEqual( len( elems ), 1 )
- self.home()
- self.visit_url( "%s/dataset/undelete?id=%s" % ( self.url, elems[0].get( 'id' ) ) )
+ raise AssertionError, "Invalid hda_id '%s' - must be int" % hda_id
+ self.visit_url( "%s/dataset/undelete?id=%s" % ( self.url, hda_id ) )
if check_str:
self.check_page_for_string( check_str )
def display_history_item( self, id, check_str='' ):
diff -r 539d481c8f59 -r 319e2ba6a7be test/functional/test_history_functions.py
--- a/test/functional/test_history_functions.py Tue Jul 07 20:32:00 2009 -0400
+++ b/test/functional/test_history_functions.py Wed Jul 08 14:10:45 2009 -0400
@@ -168,11 +168,6 @@
# Test sharing history3 with an invalid user
self.share_current_history( 'jack(a)jill.com',
check_str_after_submit='jack(a)jill.com is not a valid Galaxy user.' )
-
-
-
-
-
def test_025_delete_shared_current_history( self ):
"""Testing deleting the current history after it was shared"""
# Logged in as admin_user
@@ -187,7 +182,8 @@
# Shared history3 should be in regular_user1's list of shared histories
self.view_shared_histories( check_str=history3.name, check_str2=admin_user.email )
self.clone_history( self.security.encode_id( history3.id ),
- check_str1='is now included in your list of stored histories.' )
+ 'activatable',
+ check_str_after_submit='is now included in your list of stored histories.' )
global history3_clone1
history3_clone1 = galaxy.model.History.filter( and_( galaxy.model.History.table.c.deleted==False,
galaxy.model.History.table.c.user_id==regular_user1.id ) ) \
@@ -201,8 +197,26 @@
# logged in as regular_user1
self.logout()
self.login( email=admin_user.email )
+ # Current history should be history3, add more datasets to history3, then delete them so we can
+ # test cloning activatable datasets as well as only the active datasets
+ self.upload_file( '2.bed', dbkey='hg18' )
+ hda_2_bed = galaxy.model.HistoryDatasetAssociation \
+ .filter( and_( galaxy.model.HistoryDatasetAssociation.table.c.history_id==history3.id,
+ galaxy.model.HistoryDatasetAssociation.table.c.name=='2.bed' ) ) \
+ .first()
+ assert hda_2_bed is not None, "Problem retrieving hda_2_bed from database"
+ self.delete_history_item( str( hda_2_bed.id ) )
+ self.upload_file( '3.bed', dbkey='hg18' )
+ hda_3_bed = galaxy.model.HistoryDatasetAssociation \
+ .filter( and_( galaxy.model.HistoryDatasetAssociation.table.c.history_id==history3.id,
+ galaxy.model.HistoryDatasetAssociation.table.c.name=='3.bed' ) ) \
+ .first()
+ assert hda_3_bed is not None, "Problem retrieving hda_3_bed from database"
+ self.delete_history_item( str( hda_3_bed.id ) )
+ # Test cloning activatable datasets
self.clone_history( self.security.encode_id( history3.id ),
- check_str1='is now included in your list of stored histories.' )
+ 'activatable',
+ check_str_after_submit='is now included in your list of stored histories.' )
global history3_clone2
history3_clone2 = galaxy.model.History.filter( and_( galaxy.model.History.table.c.deleted==False,
galaxy.model.History.table.c.user_id==admin_user.id ) ) \
@@ -210,6 +224,42 @@
assert history3_clone2 is not None, "Problem retrieving history3_clone2 from database"
# Check list of histories to make sure shared history3 was cloned
self.view_stored_active_histories( check_str="Clone of '%s'" % history3.name )
+ # Switch to the cloned history to make sure activatable datasets were cloned
+ self.switch_history( id=self.security.encode_id( history3_clone2.id ), name=history3_clone2.name )
+ hda_2_bed = galaxy.model.HistoryDatasetAssociation \
+ .filter( and_( galaxy.model.HistoryDatasetAssociation.table.c.history_id==history3_clone2.id,
+ galaxy.model.HistoryDatasetAssociation.table.c.name=='2.bed' ) ) \
+ .first()
+ assert hda_2_bed is not None, "Problem retrieving hda_2_bed from database"
+ hda_3_bed = galaxy.model.HistoryDatasetAssociation \
+ .filter( and_( galaxy.model.HistoryDatasetAssociation.table.c.history_id==history3_clone2.id,
+ galaxy.model.HistoryDatasetAssociation.table.c.name=='3.bed' ) ) \
+ .first()
+ assert hda_3_bed is not None, "Problem retrieving hda_3_bed from database"
+ # Make sure the deleted datasets are included in the cloned history
+ check_str = 'This dataset has been deleted. Click undelete id=%d"' % hda_2_bed.id
+ self.check_history_for_string( check_str, show_deleted=True )
+ check_str = 'This dataset has been deleted. Click undelete id=%d"' % hda_3_bed.id
+ self.check_history_for_string( check_str, show_deleted=True )
+ # Test cloning only active datasets
+ self.clone_history( self.security.encode_id( history3.id ),
+ 'active',
+ check_str_after_submit='is now included in your list of stored histories.' )
+ global history3_clone3
+ history3_clone3 = galaxy.model.History.filter( and_( galaxy.model.History.table.c.deleted==False,
+ galaxy.model.History.table.c.user_id==admin_user.id ) ) \
+ .order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
+ assert history3_clone3 is not None, "Problem retrieving history3_clone3 from database"
+ # Check list of histories to make sure shared history3 was cloned
+ self.view_stored_active_histories( check_str="Clone of '%s'" % history3.name )
+ # Switch to the cloned history to make sure activatable datasets were cloned
+ self.switch_history( id=self.security.encode_id( history3_clone3.id ), name=history3_clone3.name )
+ # Make sure the deleted datasets are NOT included in the cloned history
+ try:
+ self.check_history_for_string( 'This dataset has been deleted.', show_deleted=True )
+ raise AssertionError, "Deleted datasets incorrectly included in cloned history history3_clone3"
+ except:
+ pass
def test_040_sharing_mulitple_histories_with_multiple_users( self ):
"""Testing sharing multiple histories containing only public datasets with multiple users"""
# Logged in as admin_user
@@ -304,7 +354,8 @@
self.view_shared_histories( check_str=history5.name, check_str2=admin_user.email )
# Clone restricted history5
self.clone_history( self.security.encode_id( history5.id ),
- check_str1='is now included in your list of stored histories.' )
+ 'activatable',
+ check_str_after_submit='is now included in your list of stored histories.' )
global history5_clone1
history5_clone1 = galaxy.model.History.filter( and_( galaxy.model.History.table.c.deleted==False,
galaxy.model.History.table.c.user_id==regular_user1.id ) ) \
@@ -359,7 +410,8 @@
self.view_shared_histories( check_str=history5.name, check_str2=admin_user.email )
# Clone restricted history5
self.clone_history( self.security.encode_id( history5.id ),
- check_str1='is now included in your list of stored histories.' )
+ 'activatable',
+ check_str_after_submit='is now included in your list of stored histories.' )
global history5_clone2
history5_clone2 = galaxy.model.History.filter( and_( galaxy.model.History.table.c.deleted==False,
galaxy.model.History.table.c.user_id==regular_user2.id ) ) \
@@ -431,7 +483,8 @@
self.view_shared_histories( check_str=history5.name, check_str2=admin_user.email )
# Clone restricted history5
self.clone_history( self.security.encode_id( history5.id ),
- check_str1='is now included in your list of stored histories.' )
+ 'activatable',
+ check_str_after_submit='is now included in your list of stored histories.' )
global history5_clone3
history5_clone3 = galaxy.model.History.filter( and_( galaxy.model.History.table.c.deleted==False,
galaxy.model.History.table.c.user_id==regular_user2.id ) ) \
@@ -468,7 +521,8 @@
self.view_shared_histories( check_str=history5.name, check_str2=admin_user.email )
# Clone restricted history5
self.clone_history( self.security.encode_id( history5.id ),
- check_str1='is now included in your list of stored histories.' )
+ 'activatable',
+ check_str_after_submit='is now included in your list of stored histories.' )
global history5_clone4
history5_clone4 = galaxy.model.History.filter( and_( galaxy.model.History.table.c.deleted==False,
galaxy.model.History.table.c.user_id==regular_user3.id ) ) \
@@ -587,16 +641,16 @@
self.check_page_for_string( 'hg15' )
self.assertEqual ( len( self.get_history_as_data_list() ), 1 )
# Delete the history item
- self.delete_history_item( latest_hda.hid, check_str="Your history is empty" )
+ self.delete_history_item( str( latest_hda.id ), check_str="Your history is empty" )
self.assertEqual ( len( self.get_history_as_data_list() ), 0 )
# Try deleting an invalid hid
try:
self.delete_history_item( 'XXX' )
- raise AssertionError, "Inproperly able to delete hid 'XXX' which is not an integer"
+ raise AssertionError, "Inproperly able to delete hda_id 'XXX' which is not an integer"
except:
pass
# Undelete the history item
- self.undelete_history_item( latest_hda.hid, show_deleted=True )
+ self.undelete_history_item( str( latest_hda.id ) )
self.home()
self.visit_url( "%s/history/?show_deleted=False" % self.url )
self.check_page_for_string( '1.bed' )
@@ -673,6 +727,7 @@
# Delete histories
self.delete_history( id=self.security.encode_id( history3.id ) )
self.delete_history( id=self.security.encode_id( history3_clone2.id ) )
+ self.delete_history( id=self.security.encode_id( history3_clone3.id ) )
self.delete_history( id=self.security.encode_id( history4.id ) )
self.delete_history( id=self.security.encode_id( history5.id ) )
# Eliminate Sharing role for: test(a)bx.psu.edu, test2(a)bx.psu.edu
1
0
08 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/539d481c8f59
changeset: 2466:539d481c8f59
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Tue Jul 07 20:32:00 2009 -0400
description:
Fix for popup menus on history grid - no longer necessary to encode ids in the template.
1 file(s) affected in this change:
templates/history/grid.mako
diffs (12 lines):
diff -r 3bbb2d2caa5f -r 539d481c8f59 templates/history/grid.mako
--- a/templates/history/grid.mako Tue Jul 07 14:48:01 2009 -0400
+++ b/templates/history/grid.mako Tue Jul 07 20:32:00 2009 -0400
@@ -168,7 +168,7 @@
<div popupmenu="grid-${i}-popup">
%for operation in grid.operations:
%if operation.allowed( item ):
- <a class="action-button" href="${url( operation=operation.label, id=trans.security.encode_id( item.id ) )}">${operation.label}</a>
+ <a class="action-button" href="${url( operation=operation.label, id=item.id )}">${operation.label}</a>
%endif
%endfor
</div>
1
0