Uploading binary files to a library
by SHAUN WEBB
Hi, not sure if this is a bug or a problem with our local install.
I am having trouble uploading binary files to a library. The error
given is "Unable to finish job, tool error", the full traceback is
below.
I have added a few extra binary datatypes to the binary.py file but
this seems to be affecting all binary types. I have been able to
upload these files in the past so I think the problem has been caused
by a recent update.
Thanks in advance for your help
Shaun Webb
galaxy.jobs.runners.local ERROR 2010-01-21 15:05:23,968 Job wrapper
finish method failed
Traceback (most recent call last):
File
"/home/swebb/galaxy/galaxy_dist/lib/galaxy/jobs/runners/local.py",
line 122, in run_job
job_wrapper.finish( stdout, stderr )
File "/home/swebb/galaxy/galaxy_dist/lib/galaxy/jobs/__init__.py",
line 558, in finish
dataset.set_peek()
File "/home/swebb/galaxy/galaxy_dist/lib/galaxy/model/__init__.py",
line 537, in set_peek
return self.datatype.set_peek( self, is_multi_byte=is_multi_byte )
File
"/home/swebb/galaxy/galaxy_dist/lib/galaxy/datatypes/binary.py", line
38, in set_peek
export_url = "/history_add_to?" + urlencode(
{'history_id':dataset.history_id,'ext':'ab1','name':'ab1
sequence','info':'Sequence file','dbkey':dataset.dbkey} )
AttributeError: 'LibraryDatasetDatasetAssociation' object has no
attribute 'history_id'
129.215.15.86 - - [21/Jan/2010:15:05:24 +0100] "POST
/library_common/library_item_updates HTTP/1.1" 200 -
"http://bifx3.bio.ed.ac.uk:8083/library_common/browse_library?cntrller=lib..." "Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.17) Gecko/2010010604 Ubuntu/8.04 (hardy)
Firefox/3.0.17"
--
The University of Edinburgh is a charitable body, registered in
Scotland, with registration number SC005336.
12 years, 3 months
[hg] galaxy 3296: Remove unneeded legacy "export_url" code from ...
by Greg Von Kuster
details: http://www.bx.psu.edu/hg/galaxy/rev/30cd8d9f8ac9
changeset: 3296:30cd8d9f8ac9
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Thu Jan 28 11:06:38 2010 -0500
description:
Remove unneeded legacy "export_url" code from the set_peek methods in binary data types - fixes uploading binary files to a library. Also fix main's tool_conf again.
diffstat:
lib/galaxy/datatypes/binary.py | 4 ----
tool_conf.xml.main | 6 +++---
2 files changed, 3 insertions(+), 7 deletions(-)
diffs (56 lines):
diff -r 3669500f699c -r 30cd8d9f8ac9 lib/galaxy/datatypes/binary.py
--- a/lib/galaxy/datatypes/binary.py Thu Jan 28 10:51:38 2010 -0500
+++ b/lib/galaxy/datatypes/binary.py Thu Jan 28 11:06:38 2010 -0500
@@ -35,7 +35,6 @@
def set_peek( self, dataset, is_multi_byte=False ):
if not dataset.dataset.purged:
- export_url = "/history_add_to?" + urlencode( {'history_id':dataset.history_id,'ext':'ab1','name':'ab1 sequence','info':'Sequence file','dbkey':dataset.dbkey} )
dataset.peek = "Binary ab1 sequence file"
dataset.blurb = data.nice_size( dataset.get_size() )
else:
@@ -121,7 +120,6 @@
return False
def set_peek( self, dataset, is_multi_byte=False ):
if not dataset.dataset.purged:
- export_url = "/history_add_to?" + urlencode( {'history_id':dataset.history_id,'ext':'bam','name':'bam alignments','info':'Alignments file','dbkey':dataset.dbkey} )
dataset.peek = "Binary bam alignments file"
dataset.blurb = data.nice_size( dataset.get_size() )
else:
@@ -163,7 +161,6 @@
def set_peek( self, dataset, is_multi_byte=False ):
if not dataset.dataset.purged:
- export_url = "/history_add_to?" + urlencode({'history_id':dataset.history_id,'ext':'scf','name':'scf sequence','info':'Sequence file','dbkey':dataset.dbkey})
dataset.peek = "Binary scf sequence file"
dataset.blurb = data.nice_size( dataset.get_size() )
else:
@@ -193,7 +190,6 @@
return False
def set_peek( self, dataset, is_multi_byte=False ):
if not dataset.dataset.purged:
- export_url = "/history_add_to?" + urlencode( {'history_id':dataset.history_id,'ext':'sff','name':'sff file','info':'sff file','dbkey':dataset.dbkey} )
dataset.peek = "Binary sff file"
dataset.blurb = data.nice_size( dataset.get_size() )
else:
diff -r 3669500f699c -r 30cd8d9f8ac9 tool_conf.xml.main
--- a/tool_conf.xml.main Thu Jan 28 10:51:38 2010 -0500
+++ b/tool_conf.xml.main Thu Jan 28 11:06:38 2010 -0500
@@ -279,14 +279,14 @@
<tool file="solid_tools/solid_qual_boxplot.xml" />
</section>
<section name="NGS: Mapping" id="ngs_mapping">
- <label text="Illumina" />
+ <label text="Illumina" id="illumina"/>
<tool file="sr_mapping/bowtie_wrapper.xml" />
<tool file="sr_mapping/bwa_wrapper.xml" />
- <label text="Roche-454" />
+ <label text="Roche-454" id="roche_454"/>
<tool file="sr_mapping/lastz_wrapper.xml" />
<tool file="metag_tools/megablast_wrapper.xml" />
<tool file="metag_tools/megablast_xml_parser.xml" />
- <label text="AB-SOLiD" />
+ <label text="AB-SOLiD" id="ab_solid"/>
<tool file="sr_mapping/bowtie_color_wrapper.xml" />
</section>
<section name="NGS: SAM Tools" id="samtools">
12 years, 3 months
[hg] galaxy 3295: Cleanup display code and remove debugging code...
by Greg Von Kuster
details: http://www.bx.psu.edu/hg/galaxy/rev/3669500f699c
changeset: 3295:3669500f699c
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Thu Jan 28 10:51:38 2010 -0500
description:
Cleanup display code and remove debugging code from page editor.
diffstat:
templates/display_base.mako | 17 ++++++++---------
templates/page/display.mako | 9 ---------
templates/page/editor.mako | 5 -----
3 files changed, 8 insertions(+), 23 deletions(-)
diffs (72 lines):
diff -r c265090bef9d -r 3669500f699c templates/display_base.mako
--- a/templates/display_base.mako Thu Jan 28 10:33:12 2010 -0500
+++ b/templates/display_base.mako Thu Jan 28 10:51:38 2010 -0500
@@ -4,26 +4,25 @@
return '/base.mako'
else:
return '/base_panels.mako'
- from galaxy import model
+
+ from galaxy.model import History, StoredWorkflow, Page
+ from galaxy.web.framework.helpers import iff
%>
<%inherit file="${inherit( context )}"/>
<%namespace file="/tagging_common.mako" import="render_individual_tagging_element, render_community_tagging_element" />
<%namespace file="/display_common.mako" import="*" />
-<%!
- from galaxy.model import History, StoredWorkflow, Page
- from galaxy.web.framework.helpers import iff
-%>
-
<%def name="title()">
Galaxy | ${iff( item.published, "Published ", iff( item.importable , "Accessible ", iff( item.users_shared_with, "Shared ", "Private " ) ) ) + get_class_display_name( item.__class__ )} | ${get_item_name( item )}
</%def>
<%def name="init()">
<%
- self.has_left_panel=False
- self.has_right_panel=item.published
- self.message_box_visible=False
+ self.has_left_panel=False
+ self.has_right_panel=item.published
+ self.message_box_visible=False
+ self.active_view="user"
+ self.overlay_visible=False
%>
</%def>
diff -r c265090bef9d -r 3669500f699c templates/page/display.mako
--- a/templates/page/display.mako Thu Jan 28 10:33:12 2010 -0500
+++ b/templates/page/display.mako Thu Jan 28 10:51:38 2010 -0500
@@ -150,15 +150,6 @@
${h.css( "base", "history", "autocomplete_tagging" )}
</%def>
-<%def name="init()">
-<%
- self.has_left_panel=False
- self.has_right_panel=item.published
- self.active_view="user"
- self.overlay_visible=False
-%>
-</%def>
-
<%def name="get_item_name( page )">
<% return page.title %>
</%def>
diff -r c265090bef9d -r 3669500f699c templates/page/editor.mako
--- a/templates/page/editor.mako Thu Jan 28 10:33:12 2010 -0500
+++ b/templates/page/editor.mako Thu Jan 28 10:51:38 2010 -0500
@@ -387,11 +387,6 @@
annotations[ annotations.length ] = annotation;
});
- // Remove inserted elements temporarily.
- var annotated_history = $('.annotated_item');
- alert(annotated_history);
- annotated_history.remove();
-
// Do save.
$.ajax( {
url: "${h.url_for( action='save' )}",
12 years, 3 months
[hg] galaxy 3294: Added framework for annotating histories, hdas...
by Greg Von Kuster
details: http://www.bx.psu.edu/hg/galaxy/rev/c265090bef9d
changeset: 3294:c265090bef9d
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Thu Jan 28 10:33:12 2010 -0500
description:
Added framework for annotating histories, hdas, workflows, and workflows steps. Specific additions: (a) annotation tables; and (b) saving annotations on pages. Also fixed bugs: (i) all page history links in Galaxy now use slugs; and (ii) removed 'pages shared with user' header in published pages view.
diffstat:
lib/galaxy/model/__init__.py | 15 +
lib/galaxy/model/mapping.py | 82 +++++-
lib/galaxy/model/migrate/versions/0035_item_annotations_and_workflow_step_tags.py | 129 ++++++++++
lib/galaxy/web/base/controller.py | 16 +-
lib/galaxy/web/controllers/history.py | 14 +-
lib/galaxy/web/controllers/page.py | 44 +++-
lib/galaxy/web/controllers/tag.py | 13 +-
templates/page/editor.mako | 91 +++---
templates/page/history_annotation_table.mako | 113 ++++----
templates/page/list_published.mako | 20 +
10 files changed, 405 insertions(+), 132 deletions(-)
diffs (726 lines):
diff -r fef431822a73 -r c265090bef9d lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py Thu Jan 28 09:05:13 2010 -0500
+++ b/lib/galaxy/model/__init__.py Thu Jan 28 10:33:12 2010 -0500
@@ -1476,9 +1476,24 @@
class WorkflowTagAssociation ( ItemTagAssociation ):
pass
+class WorkflowStepTagAssociation ( ItemTagAssociation ):
+ pass
+
class StoredWorkflowTagAssociation ( ItemTagAssociation ):
pass
+class HistoryAnnotationAssociation( object ):
+ pass
+
+class HistoryDatasetAssociationAnnotationAssociation( object ):
+ pass
+
+class StoredWorkflowAnnotationAssociation( object ):
+ pass
+
+class WorkflowStepAnnotationAssociation( object ):
+ pass
+
class UserPreference ( object ):
def __init__( self, name=None, value=None ):
self.name = name
diff -r fef431822a73 -r c265090bef9d lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py Thu Jan 28 09:05:13 2010 -0500
+++ b/lib/galaxy/model/mapping.py Thu Jan 28 10:33:12 2010 -0500
@@ -708,6 +708,8 @@
Column( "title", TEXT ),
Column( "config", JSONType )
)
+
+# Tagging tables.
Tag.table = Table( "tag", metadata,
Column( "id", Integer, primary_key=True ),
@@ -770,6 +772,43 @@
Column( "value", TrimmedString(255), index=True),
Column( "user_value", TrimmedString(255), index=True) )
+WorkflowStepTagAssociation.table = Table( "workflow_step_tag_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "workflow_step_id", Integer, ForeignKey( "workflow_step.id" ), index=True ),
+ Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "user_tname", Unicode(255), index=True),
+ Column( "value", Unicode(255), index=True),
+ Column( "user_value", Unicode(255), index=True) )
+
+# Annotation tables.
+
+HistoryAnnotationAssociation.table = Table( "history_annotation_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "history_id", Integer, ForeignKey( "history.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "annotation", TEXT, index=True) )
+
+HistoryDatasetAssociationAnnotationAssociation.table = Table( "history_dataset_association_annotation_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "history_dataset_association_id", Integer, ForeignKey( "history_dataset_association.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "annotation", TEXT, index=True) )
+
+StoredWorkflowAnnotationAssociation.table = Table( "stored_workflow_annotation_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "stored_workflow_id", Integer, ForeignKey( "stored_workflow.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "annotation", TEXT, index=True) )
+
+WorkflowStepAnnotationAssociation.table = Table( "workflow_step_annotation_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "workflow_step_id", Integer, ForeignKey( "workflow_step.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "annotation", TEXT, index=True) )
+
+# User tables.
+
UserPreference.table = Table( "user_preference", metadata,
Column( "id", Integer, primary_key=True ),
Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
@@ -893,8 +932,9 @@
visible_children=relation(
HistoryDatasetAssociation,
primaryjoin=( ( HistoryDatasetAssociation.table.c.parent_id == HistoryDatasetAssociation.table.c.id ) & ( HistoryDatasetAssociation.table.c.visible == True ) ) ),
- tags=relation(HistoryDatasetAssociationTagAssociation, order_by=HistoryDatasetAssociationTagAssociation.table.c.id, backref='history_tag_associations')
- ) )
+ tags=relation( HistoryDatasetAssociationTagAssociation, order_by=HistoryDatasetAssociationTagAssociation.table.c.id, backref='history_tag_associations' ),
+ annotations=relation( HistoryDatasetAssociationAnnotationAssociation, order_by=HistoryDatasetAssociationAnnotationAssociation.table.c.id, backref="hdas" ) )
+ )
assign_mapper( context, Dataset, Dataset.table,
properties=dict(
@@ -930,8 +970,9 @@
properties=dict( galaxy_sessions=relation( GalaxySessionToHistoryAssociation ),
datasets=relation( HistoryDatasetAssociation, backref="history", order_by=asc(HistoryDatasetAssociation.table.c.hid) ),
active_datasets=relation( HistoryDatasetAssociation, primaryjoin=( ( HistoryDatasetAssociation.table.c.history_id == History.table.c.id ) & ( not_( HistoryDatasetAssociation.table.c.deleted ) ) ), order_by=asc( HistoryDatasetAssociation.table.c.hid ), viewonly=True ),
- tags=relation(HistoryTagAssociation, order_by=HistoryTagAssociation.table.c.id, backref="histories")
- ) )
+ tags=relation( HistoryTagAssociation, order_by=HistoryTagAssociation.table.c.id, backref="histories" ),
+ annotations=relation( HistoryAnnotationAssociation, order_by=HistoryAnnotationAssociation.table.c.id, backref="histories" ) )
+ )
assign_mapper( context, HistoryUserShareAssociation, HistoryUserShareAssociation.table,
properties=dict( user=relation( User, backref='histories_shared_by_others' ),
@@ -1164,7 +1205,11 @@
) )
-assign_mapper( context, WorkflowStep, WorkflowStep.table )
+assign_mapper( context, WorkflowStep, WorkflowStep.table,
+ properties=dict(
+ tags=relation(WorkflowStepTagAssociation, order_by=WorkflowStepTagAssociation.table.c.id, backref="workflow_steps"),
+ annotations=relation( WorkflowStepAnnotationAssociation, order_by=WorkflowStepAnnotationAssociation.table.c.id, backref="workflow_steps" ) )
+ )
assign_mapper( context, WorkflowStepConnection, WorkflowStepConnection.table,
properties=dict( input_step=relation( WorkflowStep, backref="input_connections", cascade="all",
@@ -1216,8 +1261,9 @@
latest_workflow=relation( Workflow, post_update=True,
primaryjoin=( StoredWorkflow.table.c.latest_workflow_id == Workflow.table.c.id ),
lazy=False ),
- tags=relation(StoredWorkflowTagAssociation, order_by=StoredWorkflowTagAssociation.table.c.id, backref="stored_workflows")
- ) )
+ tags=relation( StoredWorkflowTagAssociation, order_by=StoredWorkflowTagAssociation.table.c.id, backref="stored_workflows" ),
+ annotations=relation( StoredWorkflowAnnotationAssociation, order_by=StoredWorkflowAnnotationAssociation.table.c.id, backref="stored_workflows" ) )
+ )
assign_mapper( context, StoredWorkflowUserShareAssociation, StoredWorkflowUserShareAssociation.table,
properties=dict( user=relation( User, backref='workflows_shared_by_others' ),
@@ -1287,7 +1333,27 @@
assign_mapper( context, StoredWorkflowTagAssociation, StoredWorkflowTagAssociation.table,
properties=dict( tag=relation(Tag, backref="tagged_stored_workflows"), user=relation( User ) )
)
-
+
+assign_mapper( context, WorkflowStepTagAssociation, WorkflowStepTagAssociation.table,
+ properties=dict( tag=relation(Tag, backref="tagged_workflow_steps"), user=relation( User ) )
+ )
+
+assign_mapper( context, HistoryAnnotationAssociation, HistoryAnnotationAssociation.table,
+ properties=dict( history=relation( History ), user=relation( User ) )
+ )
+
+assign_mapper( context, HistoryDatasetAssociationAnnotationAssociation, HistoryDatasetAssociationAnnotationAssociation.table,
+ properties=dict( hda=relation( HistoryDatasetAssociation ), user=relation( User ) )
+ )
+
+assign_mapper( context, StoredWorkflowAnnotationAssociation, StoredWorkflowAnnotationAssociation.table,
+ properties=dict( stored_workflow=relation( StoredWorkflow ), user=relation( User ) )
+ )
+
+assign_mapper( context, WorkflowStepAnnotationAssociation, WorkflowStepAnnotationAssociation.table,
+ properties=dict( workflow_step=relation( WorkflowStep ), user=relation( User ) )
+ )
+
assign_mapper( context, UserPreference, UserPreference.table,
properties = {}
)
diff -r fef431822a73 -r c265090bef9d lib/galaxy/model/migrate/versions/0035_item_annotations_and_workflow_step_tags.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/model/migrate/versions/0035_item_annotations_and_workflow_step_tags.py Thu Jan 28 10:33:12 2010 -0500
@@ -0,0 +1,129 @@
+"""
+Migration script to (a) create tables for annotating objects and (b) create tags for workflow steps.
+"""
+
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData( migrate_engine )
+db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) )
+
+# Annotation tables.
+
+HistoryAnnotationAssociation_table = Table( "history_annotation_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "history_id", Integer, ForeignKey( "history.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "annotation", TEXT, index=True) )
+
+HistoryDatasetAssociationAnnotationAssociation_table = Table( "history_dataset_association_annotation_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "history_dataset_association_id", Integer, ForeignKey( "history_dataset_association.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "annotation", TEXT, index=True) )
+
+StoredWorkflowAnnotationAssociation_table = Table( "stored_workflow_annotation_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "stored_workflow_id", Integer, ForeignKey( "stored_workflow.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "annotation", TEXT, index=True) )
+
+WorkflowStepAnnotationAssociation_table = Table( "workflow_step_annotation_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "workflow_step_id", Integer, ForeignKey( "workflow_step.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "annotation", TEXT, index=True) )
+
+# Tagging tables.
+
+WorkflowStepTagAssociation_table = Table( "workflow_step_tag_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "workflow_step_id", Integer, ForeignKey( "workflow_step.id" ), index=True ),
+ Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "user_tname", Unicode(255), index=True),
+ Column( "value", Unicode(255), index=True),
+ Column( "user_value", Unicode(255), index=True) )
+
+def upgrade():
+ print __doc__
+ metadata.reflect()
+
+ # Create history_annotation_association table.
+ try:
+ HistoryAnnotationAssociation_table.create()
+ except Exception, e:
+ print str(e)
+ log.debug( "Creating history_annotation_association table failed: %s" % str( e ) )
+
+ # Create history_dataset_association_annotation_association table.
+ try:
+ HistoryDatasetAssociationAnnotationAssociation_table.create()
+ except Exception, e:
+ print str(e)
+ log.debug( "Creating history_dataset_association_annotation_association table failed: %s" % str( e ) )
+
+ # Create stored_workflow_annotation_association table.
+ try:
+ StoredWorkflowAnnotationAssociation_table.create()
+ except Exception, e:
+ print str(e)
+ log.debug( "Creating stored_workflow_annotation_association table failed: %s" % str( e ) )
+
+ # Create workflow_step_annotation_association table.
+ try:
+ WorkflowStepAnnotationAssociation_table.create()
+ except Exception, e:
+ print str(e)
+ log.debug( "Creating workflow_step_annotation_association table failed: %s" % str( e ) )
+
+ # Create workflow_step_tag_association table.
+ try:
+ WorkflowStepTagAssociation_table.create()
+ except Exception, e:
+ print str(e)
+ log.debug( "Creating workflow_step_tag_association table failed: %s" % str( e ) )
+
+def downgrade():
+ metadata.reflect()
+
+ # Drop history_annotation_association table.
+ try:
+ HistoryAnnotationAssociation_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping history_annotation_association table failed: %s" % str( e ) )
+
+ # Drop history_dataset_association_annotation_association table.
+ try:
+ HistoryDatasetAssociationAnnotationAssociation_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping history_dataset_association_annotation_association table failed: %s" % str( e ) )
+
+ # Drop stored_workflow_annotation_association table.
+ try:
+ StoredWorkflowAnnotationAssociation_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping stored_workflow_annotation_association table failed: %s" % str( e ) )
+
+ # Drop workflow_step_annotation_association table.
+ try:
+ WorkflowStepAnnotationAssociation_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping workflow_step_annotation_association table failed: %s" % str( e ) )
+
+ # Drop workflow_step_tag_association table.
+ try:
+ WorkflowStepTagAssociation_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping workflow_step_tag_association table failed: %s" % str( e ) )
+
\ No newline at end of file
diff -r fef431822a73 -r c265090bef9d lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py Thu Jan 28 09:05:13 2010 -0500
+++ b/lib/galaxy/web/base/controller.py Thu Jan 28 10:33:12 2010 -0500
@@ -59,6 +59,20 @@
error( "History is not owned by current user" )
return history
+ def get_class( self, class_name ):
+ """ Returns the class object that a string denotes. Without this method, we'd have to do eval(<class_name>). """
+ if class_name == 'History':
+ item_class = model.History
+ elif class_name == 'HistoryDatasetAssociation':
+ item_class = model.HistoryDatasetAssociation
+ elif class_name == 'Page':
+ item_class = model.Page
+ elif class_name == 'StoredWorkflow':
+ item_class = model.StoredWorkflow
+ else:
+ item_class = None
+ return item_class
+
Root = BaseController
class SharingStatusColumn( grids.GridColumn ):
@@ -79,7 +93,7 @@
return ", ".join( sharing_statuses )
def get_link( self, trans, grid, item ):
- if not item.deleted and ( item.users_shared_with or item.importable ):
+ if not item.deleted and ( item.users_shared_with or item.importable or item.published ):
return dict( operation="share or publish", id=item.id )
return None
diff -r fef431822a73 -r c265090bef9d lib/galaxy/web/controllers/history.py
--- a/lib/galaxy/web/controllers/history.py Thu Jan 28 09:05:13 2010 -0500
+++ b/lib/galaxy/web/controllers/history.py Thu Jan 28 10:33:12 2010 -0500
@@ -367,16 +367,18 @@
trans.sa_session.flush()
@web.expose
- @web.require_login( "get history name, slug, and owner's username" )
- def get_name_slug_username_async( self, trans, id=None ):
- """ Returns the name, slug, and owner's username for a given history. """
+ @web.json
+ @web.require_login( "get history name and link" )
+ def get_name_and_link_async( self, trans, id=None ):
+ """ Returns history's name and link. """
history = self.get_history( trans, id, False )
# To get info: user must own history.
if history.user == trans.get_user():
- slug = iff( history.slug, history.slug, "" )
- username = iff ( history.user.username, history.user.username, "" )
- return history.name + "," + slug + "," + username
+ if self.set_item_slug( trans.sa_session, history ):
+ trans.sa_session.flush()
+ return_dict = { "name" : history.name, "link" : "/u/%s/h/%s" % ( history.user.username, history.slug ) }
+ return return_dict
return
@web.expose
diff -r fef431822a73 -r c265090bef9d lib/galaxy/web/controllers/page.py
--- a/lib/galaxy/web/controllers/page.py Thu Jan 28 09:05:13 2010 -0500
+++ b/lib/galaxy/web/controllers/page.py Thu Jan 28 10:33:12 2010 -0500
@@ -2,6 +2,7 @@
from galaxy.web.framework.helpers import time_ago, grids
from galaxy.util.sanitize_html import sanitize_html
from galaxy.util.odict import odict
+from galaxy.util.json import from_json_string
import re
@@ -193,7 +194,7 @@
return grid
else:
# Render grid wrapped in panels
- return trans.fill_template( "page/index.mako", grid=grid )
+ return trans.fill_template( "page/list_published.mako", grid=grid )
@web.expose
@@ -370,18 +371,52 @@
@web.expose
@web.require_login()
- def save( self, trans, id, content ):
+ def save( self, trans, id, content, annotations ):
id = trans.security.decode_id( id )
page = trans.sa_session.query( model.Page ).get( id )
assert page.user == trans.user
+
# Sanitize content
content = sanitize_html( content, 'utf-8', 'text/html' )
- # Add a new revision to the page with the provided content
+
+ # Add a new revision to the page with the provided content.
page_revision = model.PageRevision()
page_revision.title = page.title
page_revision.page = page
page.latest_revision = page_revision
page_revision.content = content
+
+ # Save annotations.
+ annotations = from_json_string( annotations )
+ for annotation_dict in annotations:
+ item_id = trans.security.decode_id( annotation_dict[ 'item_id' ] )
+ item_class = self.get_class( annotation_dict[ 'item_class' ] )
+ item = trans.sa_session.query( item_class ).filter_by( id=item_id ).first()
+ if not item:
+ raise RuntimeError( "cannot find annotated item" )
+ text = sanitize_html( annotation_dict[ 'text' ], 'utf-8', 'text/html' )
+
+ # Add/update annotation.
+ if item_id and item_class and text:
+ # Get annotation association.
+ annotation_assoc_class = eval( "model.%sAnnotationAssociation" % item_class.__name__ )
+ annotation_assoc = trans.sa_session.query( annotation_assoc_class ).filter_by( user=trans.get_user() )
+ if item_class == model.History.__class__:
+ annotation_assoc = annotation_assoc.filter_by( history=item )
+ elif item_class == model.HistoryDatasetAssociation.__class__:
+ annotation_assoc = annotation_assoc.filter_by( hda=item )
+ elif item_class == model.StoredWorkflow.__class__:
+ annotation_assoc = annotation_assoc.filter_by( stored_workflow=item )
+ elif item_class == model.WorkflowStep.__class__:
+ annotation_assoc = annotation_assoc.filter_by( workflow_step=item )
+ annotation_assoc = annotation_assoc.first()
+ if not annotation_assoc:
+ # Create association.
+ annotation_assoc = annotation_assoc_class()
+ item.annotations.append( annotation_assoc )
+ annotation_assoc.user = trans.get_user()
+ # Set annotation user text.
+ annotation_assoc.annotation = text
trans.sa_session.flush()
@web.expose
@@ -448,5 +483,4 @@
@web.expose
def get_editor_iframe( self, trans ):
""" Returns the document for the page editor's iframe. """
- return trans.fill_template( "page/wymiframe.mako" )
-
\ No newline at end of file
+ return trans.fill_template( "page/wymiframe.mako" )
\ No newline at end of file
diff -r fef431822a73 -r c265090bef9d lib/galaxy/web/controllers/tag.py
--- a/lib/galaxy/web/controllers/tag.py Thu Jan 28 09:05:13 2010 -0500
+++ b/lib/galaxy/web/controllers/tag.py Thu Jan 28 10:33:12 2010 -0500
@@ -70,17 +70,8 @@
if item_id is not None:
item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) )
user = trans.get_user()
-
- # Get item class. TODO: we should have a mapper that goes from class_name to class object.
- if item_class == 'History':
- item_class = model.History
- elif item_class == 'HistoryDatasetAssociation':
- item_class = model.HistoryDatasetAssociation
- elif item_class == 'Page':
- item_class = model.Page
- elif item_class == 'StoredWorkflow':
- item_class = model.StoredWorkflow
-
+ item_class = self.get_class( item_class )
+
q = q.encode('utf-8')
if q.find(":") == -1:
return self._get_tag_autocomplete_names(trans, q, limit, timestamp, user, item, item_class)
diff -r fef431822a73 -r c265090bef9d templates/page/editor.mako
--- a/templates/page/editor.mako Thu Jan 28 09:05:13 2010 -0500
+++ b/templates/page/editor.mako Thu Jan 28 10:33:12 2010 -0500
@@ -233,52 +233,31 @@
type: "POST",
url: '${h.url_for( controller='history', action='set_accessible_async' )}',
data: { id: item_id, accessible: 'True' },
- error: function() { alert('Make history importable failed; id=' + item_id) }
+ error: function() { alert('Make history accessible failed; id=' + item_id) }
});
-
- // Insert link.
- wym._exec(WYMeditor.CREATE_LINK, sStamp);
- var link_text = $("a[href=" + sStamp + "]", wym._doc.body).text();
- if (
- link_text == "" // Firefox.
- ||
- link_text == sStamp // Safari
- )
- {
- // User selected no text; create link from scratch and use default text.
- // Get history name.
- $.get( '${h.url_for( controller='history', action='get_name_slug_username_async' )}?id=' + item_id,
- function( history_info ) {
- // Parse history info.
- history_info = history_info.split(",");
- var
- history_name = history_info[0],
- history_slug = history_info[1],
- history_user_username = history_info[2];
-
- // Build href from history info.
- var href;
- if (history_slug != "" && history_user_username != "")
- {
- var href =
- '${h.url_for( controller='/history', action='display_by_username_and_slug', username='USERNAME', slug='SLUG' )}';
- href = href.replace('USERNAME', history_user_username);
- href = href.replace('SLUG', history_slug);
- }
- else
- var href = '${h.url_for( controller='/history', action='view' )}?id=' + item_id;
- wym.insert("<a href='" + href + "'>History '" + history_name + "'</a>");
- });
- }
- else
- {
- // Link created from selected text; add href and title.
- $("a[href=" + sStamp + "]", wym._doc.body)
- .attr(WYMeditor.HREF, '${h.url_for( controller='history', action='view' )}' + '?id=' + item_id)
- .attr(WYMeditor.TITLE, "History" + item_id);
- }
-
+ // Insert link. This is done by getting history info and then manipulating wym.
+ $.getJSON( '${h.url_for( controller='history', action='get_name_and_link_async' )}?id=' + item_id, function( history_info ) {
+ // Get link text.
+ wym._exec(WYMeditor.CREATE_LINK, sStamp);
+ var link_text = $("a[href=" + sStamp + "]", wym._doc.body).text();
+
+ // Insert link: need to do different actions depending on link text.
+ if (
+ link_text == "" // Firefox.
+ ||
+ link_text == sStamp // Safari
+ )
+ {
+ // User selected no text; create link from scratch and use default text.
+ wym.insert("<a href='" + history_info.link + "'>History '" + history_info.name + "'</a>");
+ }
+ else
+ {
+ // Link created from selected text; add href and title.
+ $("a[href=" + sStamp + "]", wym._doc.body).attr(WYMeditor.HREF, history_info.link).attr(WYMeditor.TITLE, "History" + item_id);
+ }
+ });
});
hide_modal();
@@ -393,12 +372,34 @@
var editor = $.wymeditors(0);
var save = function ( callback ) {
show_modal( "Saving page", "progress" );
- $.ajax( {
+ // Gather annotations.
+ var annotations = new Array();
+
+ $('.annotation', editor._doc.body).each( function() {
+ var item_class = $(this).attr( 'item_class' );
+ var item_id = $(this).attr( 'item_id' );
+ var text = $(this).text();
+ annotation = {
+ "item_class" : item_class,
+ "item_id" : item_id,
+ "text" : text
+ };
+ annotations[ annotations.length ] = annotation;
+ });
+
+ // Remove inserted elements temporarily.
+ var annotated_history = $('.annotated_item');
+ alert(annotated_history);
+ annotated_history.remove();
+
+ // Do save.
+ $.ajax( {
url: "${h.url_for( action='save' )}",
type: "POST",
data: {
id: "${trans.security.encode_id(page.id)}",
content: editor.xhtml(),
+ annotations: JSON.stringify(annotations),
"_": "true"
},
success: function() {
diff -r fef431822a73 -r c265090bef9d templates/page/history_annotation_table.mako
--- a/templates/page/history_annotation_table.mako Thu Jan 28 09:05:13 2010 -0500
+++ b/templates/page/history_annotation_table.mako Thu Jan 28 10:33:12 2010 -0500
@@ -1,60 +1,61 @@
<%namespace file="../tagging_common.mako" import="render_tagging_element_html" />
<%namespace file="../root/history_common.mako" import="render_dataset" />
-<table>
- ## Table header.
- <tr>
- <th colspan='2'>History '${history.get_display_name()}'</th>
- </tr>
- <tr>
- ## Status messages and tags.
- <td colspan='2'>
- %if history.deleted:
- <div class="warningmessagesmall">
- ${_('This is a deleted history.')}
- </div>
- %endif
- ## Tags come for free with community tagging, so not sure if this is necessary.
- ##%if trans.get_user() is not None:
- ## Tags: ${render_tagging_element_html( tags=history.tags, editable=False, use_toggle_link=False )}
- ##%endif
- </td>
- </tr>
- <tr>
- <td colspan="2" class="annotation">Description of History:
- <ol>
- <li>What was the motivation for this history?
- <li>What is the outcome of this history?
- <li>What are unresolved questions from this history?
- <li>What new questions arise from this history?
- </ol>
- </td>
- </tr>
+<div class="annotated_item">
+ <table>
+ ## Table header.
+ <tr>
+ <th colspan='2'>History '${history.get_display_name()}'</th>
+ </tr>
+ <tr>
+ ## Status messages and tags.
+ <td colspan='2'>
+ %if history.deleted:
+ <div class="warningmessagesmall">
+ ${_('This is a deleted history.')}
+ </div>
+ %endif
+ ## Tags come for free with community tagging, so not sure if this is necessary.
+ ##%if trans.get_user() is not None:
+ ## Tags: ${render_tagging_element_html( tags=history.tags, editable=False, use_toggle_link=False )}
+ ##%endif
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" class="annotation" item_class="History" item_id="${trans.security.encode_id( history.id )}">Description of History:
+ <ol>
+ <li>What was the motivation for this history?
+ <li>What is the outcome of this history?
+ <li>What are unresolved questions from this history?
+ <li>What new questions arise from this history?
+ </ol>
+ </td>
+ </tr>
- ## Table body. For each dataset, there is an area to annotate the dataset.
- %if not datasets:
- <tr>
- <td>
- <div class="infomessagesmall" id="emptyHistoryMessage">
- ${_("Your history is empty. Click 'Get Data' on the left pane to start")}
- </div>
- </td>
- </tr>
- %else:
- ## Render requested datasets.
- %for data in datasets:
- %if data.visible:
- <tr>
- <td valign="top"><span class="annotation">Describe this step: why was it done? what data did it produce?</span></td>
- ##<td valign="top" class="annotation">Describe this step: why was it done? what data does it produce?</td>
- <td>
- <div class="historyItemContainer" id="historyItemContainer-${data.id}">
- ${render_dataset( data, data.hid, show_deleted_on_refresh = show_deleted, user_owns_dataset = False )}
- </div>
- </td>
- </tr>
- %endif
- %endfor
- %endif
-</table>
-
\ No newline at end of file
+ ## Table body. For each dataset, there is an area to annotate the dataset.
+ %if not datasets:
+ <tr>
+ <td>
+ <div class="infomessagesmall" id="emptyHistoryMessage">
+ ${_("Your history is empty. Click 'Get Data' on the left pane to start")}
+ </div>
+ </td>
+ </tr>
+ %else:
+ ## Render requested datasets.
+ %for data in datasets:
+ %if data.visible:
+ <tr>
+ <td valign="top" class="annotation" item_class="HistoryDatasetAssociation" item_id="${trans.security.encode_id( data.id )}">Describe this step: why was it done? what data did it produce?</td>
+ ##<td valign="top" class="annotation">Describe this step: why was it done? what data does it produce?</td>
+ <td>
+ <div class="historyItemContainer" id="historyItemContainer-${data.id}">
+ ${render_dataset( data, data.hid, show_deleted_on_refresh = show_deleted, user_owns_dataset = False )}
+ </div>
+ </td>
+ </tr>
+ %endif
+ %endfor
+ %endif
+ </table>
+</div>
\ No newline at end of file
diff -r fef431822a73 -r c265090bef9d templates/page/list_published.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/page/list_published.mako Thu Jan 28 10:33:12 2010 -0500
@@ -0,0 +1,20 @@
+<%inherit file="/base_panels.mako"/>
+
+<%def name="init()">
+<%
+ self.has_left_panel=False
+ self.has_right_panel=False
+ self.active_view="page"
+ self.message_box_visible=False
+%>
+</%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( controller="page", action="list" )}"> </iframe>
+
+ <div style="overflow: auto; height: 100%;">
+ <div class="page-container" style="padding: 10px;">
+ ${grid}
+
+</%def>
12 years, 3 months
[hg] galaxy 3293: Derive roles for the permissions forms on the ...
by Greg Von Kuster
details: http://www.bx.psu.edu/hg/galaxy/rev/fef431822a73
changeset: 3293:fef431822a73
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Thu Jan 28 09:05:13 2010 -0500
description:
Derive roles for the permissions forms on the edit attributes page from the roles associated with the access permission on the dataset. Addd error checking to ensure the user does not set access permissions in such a way that the dataset is inaccessible to himself or everyone. Fix a bug when clicking on a library dataset to view it's info from the Data Libraries view.
diffstat:
lib/galaxy/security/__init__.py | 40 +++++++++++++++++---------
lib/galaxy/web/controllers/library_common.py | 7 ++--
lib/galaxy/web/controllers/root.py | 41 ++++++++++++++++++++++-----
lib/galaxy/web/controllers/tool_runner.py | 2 +-
templates/dataset/edit_attributes.mako | 4 ++
5 files changed, 68 insertions(+), 26 deletions(-)
diffs (221 lines):
diff -r 19334cf7f9b4 -r fef431822a73 lib/galaxy/security/__init__.py
--- a/lib/galaxy/security/__init__.py Wed Jan 27 18:34:36 2010 -0500
+++ b/lib/galaxy/security/__init__.py Thu Jan 28 09:05:13 2010 -0500
@@ -81,7 +81,7 @@
raise "Unimplemented Method"
def get_legitimate_roles( self, trans, item ):
raise "Unimplemented Method"
- def check_library_dataset_access( self, trans, library_id, **kwd ):
+ def derive_roles_from_access( self, trans, item_id, library=False, **kwd ):
raise "Unimplemented Method"
def get_component_associations( self, **kwd ):
raise "Unimplemented Method"
@@ -119,6 +119,7 @@
"""
if ( isinstance( item, self.model.Library ) and self.library_is_public( item ) ) or \
( isinstance( item, self.model.Dataset ) and self.dataset_is_public( item ) ):
+ # If item is public, private roles will always be allowed
return trans.sa_session.query( trans.app.model.Role ) \
.filter( trans.app.model.Role.table.c.deleted==False ) \
.order_by( trans.app.model.Role.table.c.name )
@@ -136,7 +137,7 @@
# (which can be expensive or prohibited) in case of equal attribute values.
intermed = map( None, map( getattr, seq, ( attr, ) * len( seq ) ), xrange( len( seq ) ), seq )
intermed.sort()
- return map( operator.getitem, intermed, ( -1, ) * len( intermed ) )
+ return map( operator.getitem, intermed, ( -1, ) * len( intermed ) )
roles = set()
# If item has roles associated with the access permission, we need to start with them.
access_roles = item.get_access_roles( trans )
@@ -172,7 +173,7 @@
break
return ret_val
def can_access_dataset( self, roles, dataset ):
- return self.allow_action( roles, self.permitted_actions.DATASET_ACCESS, dataset )
+ return self.dataset_is_public( dataset ) or self.allow_action( roles, self.permitted_actions.DATASET_ACCESS, dataset )
def can_manage_dataset( self, roles, dataset ):
return self.allow_action( roles, self.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset )
def can_access_library( self, roles, library ):
@@ -452,8 +453,9 @@
if lp.action == self.permitted_actions.LIBRARY_ACCESS.action:
self.sa_session.delete( lp )
self.sa_session.flush()
- def check_library_dataset_access( self, trans, library_id, **kwd ):
- # library_id must be decoded before being sent
+ def derive_roles_from_access( self, trans, item_id, library=False, **kwd ):
+ # Check the access permission on a dataset. If library is true, item_id refers to a library. If library
+ # is False, item_id refers to a dataset ( item_id must currently be decoded before being sent ).
msg = ''
permissions = {}
# accessible will be True only if at least 1 user has every role in DATASET_ACCESS_in
@@ -465,22 +467,32 @@
for k, v in get_permitted_actions( filter='DATASET' ).items():
in_roles = [ self.sa_session.query( self.model.Role ).get( x ) for x in listify( kwd.get( k + '_in', [] ) ) ]
if v == self.permitted_actions.DATASET_ACCESS and in_roles:
- library = self.model.Library.get( library_id )
- if not self.library_is_public( library ):
+ if library:
+ item = self.model.Library.get( item_id )
+ else:
+ item = self.model.Dataset.get( item_id )
+ if ( library and not self.library_is_public( item ) ) or ( not library and not self.dataset_is_public( item ) ):
# Ensure that roles being associated with DATASET_ACCESS are a subset of the legitimate roles
- # derived from the roles associated with the LIBRARY_ACCESS permission on the library if it's
- # not public. This will keep ill-legitimate roles from being associated with the DATASET_ACCESS
- # permission on the dataset (i.e., if Role1 is associated with LIBRARY_ACCESS, then only those users
- # that have Role1 should be associated with DATASET_ACCESS.
- legitimate_roles = self.get_legitimate_roles( trans, library )
+ # derived from the roles associated with the access permission on item if it's not public. This
+ # will keep ill-legitimate roles from being associated with the DATASET_ACCESS permission on the
+ # dataset (i.e., in the case where item is a library, if Role1 is associated with LIBRARY_ACCESS,
+ # then only those users that have Role1 should be associated with DATASET_ACCESS.
+ legitimate_roles = self.get_legitimate_roles( trans, item )
ill_legitimate_roles = []
for role in in_roles:
if role not in legitimate_roles:
ill_legitimate_roles.append( role )
if ill_legitimate_roles:
+ # NOTE: this condition should never occur since ill-legitimate roles are filtered out of the set of
+ # roles displayed on the permissions forms, but just in case there is a bug somewhere that incorrectly
+ # filters, we'll display this message.
error = self.ILL_LEGITIMATE
- msg += "The following roles are not associated with users that have the 'access library' permission on this "
- msg += "library, so they cannot be associated with the 'access' permission on the datasets: "
+ if library:
+ msg += "The following roles are not associated with users that have the 'access library' permission on this "
+ msg += "library, so they cannot be associated with the 'access' permission on the datasets: "
+ else:
+ msg += "The following roles are not associated with users that have the 'access' permission on this "
+ msg += "dataset, so they were incorrectly displayed on the permission form: "
for role in ill_legitimate_roles:
msg += "%s, " % role.name
msg = msg.rstrip( ", " )
diff -r 19334cf7f9b4 -r fef431822a73 lib/galaxy/web/controllers/library_common.py
--- a/lib/galaxy/web/controllers/library_common.py Wed Jan 27 18:34:36 2010 -0500
+++ b/lib/galaxy/web/controllers/library_common.py Thu Jan 28 09:05:13 2010 -0500
@@ -469,6 +469,7 @@
library=library,
show_deleted=show_deleted,
widgets=widgets,
+ current_user_roles=current_user_roles,
msg=msg,
messagetype=messagetype )
@web.expose
@@ -506,11 +507,11 @@
if cntrller=='library_admin' or ( trans.app.security_agent.can_manage_library_item( current_user_roles, ldda ) and \
trans.app.security_agent.can_manage_dataset( current_user_roles, ldda.dataset ) ):
permissions, in_roles, error, msg = \
- trans.app.security_agent.check_library_dataset_access( trans, trans.app.security.decode_id( library_id ), **kwd )
+ trans.app.security_agent.derive_roles_from_access( trans, trans.app.security.decode_id( library_id ), library=True, **kwd )
for ldda in lddas:
# Set the DATASET permissions on the Dataset.
if error == trans.app.security_agent.IN_ACCESSIBLE:
- # If the check_library_dataset_access() returned a "in_accessible" error, then we keep the original role
+ # If derive_roles_from_access() returned an "in_accessible" error, then we keep the original role
# associations for the DATASET_ACCESS permission on each ldda.
a = trans.app.security_agent.get_action( trans.app.security_agent.permitted_actions.DATASET_ACCESS.action )
permissions[ a ] = ldda.get_access_roles( trans )
@@ -619,7 +620,7 @@
if roles:
vars = dict( DATASET_ACCESS_in=roles )
permissions, in_roles, error, msg = \
- trans.app.security_agent.check_library_dataset_access( trans, trans.app.security.decode_id( library_id ), **vars )
+ trans.app.security_agent.derive_roles_from_access( trans, trans.app.security.decode_id( library_id ), library=True, **vars )
if error:
if error == trans.app.security_agent.IN_ACCESSIBLE:
msg = "At least 1 user must have every role associated with accessing datasets. The roles you "
diff -r 19334cf7f9b4 -r fef431822a73 lib/galaxy/web/controllers/root.py
--- a/lib/galaxy/web/controllers/root.py Wed Jan 27 18:34:36 2010 -0500
+++ b/lib/galaxy/web/controllers/root.py Thu Jan 28 09:05:13 2010 -0500
@@ -240,6 +240,8 @@
@web.expose
def edit(self, trans, id=None, hid=None, **kwd):
"""Allows user to modify parameters of an HDA."""
+ msg = ''
+ error = False
def __ok_to_edit_metadata( dataset_id ):
#prevent modifying metadata when dataset is queued or running as input/output
#This code could be more efficient, i.e. by using mappers, but to prevent slowing down loading a History panel, we'll leave the code here for now
@@ -334,13 +336,29 @@
if not trans.user:
return trans.show_error_message( "You must be logged in if you want to change permissions." )
if trans.app.security_agent.can_manage_dataset( current_user_roles, data.dataset ):
- permissions = {}
- for k, v in trans.app.model.Dataset.permitted_actions.items():
- in_roles = params.get( k + '_in', [] )
- if not isinstance( in_roles, list ):
- in_roles = [ in_roles ]
- in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( x ) for x in in_roles ]
- permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
+ # The user associated the DATASET_ACCESS permission on the dataset with 1 or more roles. We need
+ # to ensure that they did not associated roles that would make the dataset in-accessible by everyone.
+ permissions, in_roles, error, msg = \
+ trans.app.security_agent.derive_roles_from_access( trans, data.dataset.id, **kwd )
+ a = trans.app.security_agent.get_action( trans.app.security_agent.permitted_actions.DATASET_ACCESS.action )
+ if error == trans.app.security_agent.IN_ACCESSIBLE:
+ # If derive_roles_from_access() returned an "in_accessible" error, then we keep the original role
+ # associations for the DATASET_ACCESS permission on the dataset.
+ permissions[ a ] = data.dataset.get_access_roles( trans )
+ # Make sure the user is not associating another user's private role with the DATASET_ACCESS permission.
+ # It would be better to filter out other user's private roles from the access box on the permission form,
+ # but that gets a bit tricky since we are not differentiating between permissions ( i.e., the same set of
+ # derived roles are used for both the manage permissions and the access box ).
+ current_user_private_role = trans.app.security_agent.get_private_user_role( trans.user )
+ access_roles = permissions[ a ]
+ for role in access_roles:
+ if role.type == trans.app.model.Role.types.PRIVATE and role is not current_user_private_role:
+ error = trans.app.security_agent.IN_ACCESSIBLE
+ permissions[ a ] = data.dataset.get_access_roles( trans )
+ msg = "You cannot associate another user's private role with the access permission on this dataset "
+ msg += "or it will become in-accessible to you. Access permissions were left in their original state."
+ messagetype = 'error'
+ break
trans.app.security_agent.set_all_dataset_permissions( data.dataset, permissions )
trans.sa_session.refresh( data.dataset )
else:
@@ -358,11 +376,18 @@
ldatatypes = [ dtype_name for dtype_name, dtype_value in trans.app.datatypes_registry.datatypes_by_extension.iteritems() if dtype_value.allow_datatype_change ]
ldatatypes.sort()
all_roles = trans.app.security_agent.get_legitimate_roles( trans, data.dataset )
+ if error:
+ messagetype = 'error'
+ else:
+ msg = 'Your changes completed successfully.'
+ messagetype = 'done'
return trans.fill_template( "/dataset/edit_attributes.mako",
data=data,
datatypes=ldatatypes,
current_user_roles=current_user_roles,
- all_roles=all_roles )
+ all_roles=all_roles,
+ msg=msg,
+ messagetype=messagetype )
else:
return trans.show_error_message( "You do not have permission to edit this dataset's ( id: %s ) information." % str( id ) )
diff -r 19334cf7f9b4 -r fef431822a73 lib/galaxy/web/controllers/tool_runner.py
--- a/lib/galaxy/web/controllers/tool_runner.py Wed Jan 27 18:34:36 2010 -0500
+++ b/lib/galaxy/web/controllers/tool_runner.py Thu Jan 28 09:05:13 2010 -0500
@@ -151,7 +151,7 @@
# did not associated roles that would make the dataset in-accessible by everyone.
library_id = trans.app.security.decode_id( kwd.get( 'library_id', '' ) )
vars = dict( DATASET_ACCESS_in=roles )
- permissions, in_roles, error, msg = trans.app.security_agent.check_library_dataset_access( trans, library_id, **vars )
+ permissions, in_roles, error, msg = trans.app.security_agent.check_access_permission( trans, library_id, library=True, **vars )
if error:
return [ 'error', msg ]
permissions = trans.app.security_agent.history_get_default_permissions( trans.history )
diff -r 19334cf7f9b4 -r fef431822a73 templates/dataset/edit_attributes.mako
--- a/templates/dataset/edit_attributes.mako Wed Jan 27 18:34:36 2010 -0500
+++ b/templates/dataset/edit_attributes.mako Thu Jan 28 09:05:13 2010 -0500
@@ -30,6 +30,10 @@
</select>
</%def>
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
<div class="toolForm">
<div class="toolFormTitle">${_('Edit Attributes')}</div>
<div class="toolFormBody">
12 years, 3 months
[hg] galaxy 3292: Use right panel for viewing (pages, histories, ...
by Greg Von Kuster
details: http://www.bx.psu.edu/hg/galaxy/rev/19334cf7f9b4
changeset: 3292:19334cf7f9b4
user: James Taylor <james(a)jamestaylor.org>
date: Wed Jan 27 18:34:36 2010 -0500
description:
Use right panel for viewing (pages, histories, ...?)
diffstat:
templates/display_base.mako | 40 ++++++++++++++++++++++++++++++++++------
templates/page/display.mako | 2 +-
2 files changed, 35 insertions(+), 7 deletions(-)
diffs (91 lines):
diff -r f5e3c6a1d135 -r 19334cf7f9b4 templates/display_base.mako
--- a/templates/display_base.mako Wed Jan 27 18:33:48 2010 -0500
+++ b/templates/display_base.mako Wed Jan 27 18:34:36 2010 -0500
@@ -22,7 +22,7 @@
<%def name="init()">
<%
self.has_left_panel=False
- self.has_right_panel=False
+ self.has_right_panel=item.published
self.message_box_visible=False
%>
</%def>
@@ -54,8 +54,8 @@
.page-body
{
padding: 10px;
- float: left;
- width: 65%;
+ ## float: left;
+ ## width: 65%;
}
.page-meta
{
@@ -126,16 +126,41 @@
${self.render_item( item, item_data )}
</div>
+
+ </div>
+ </div>
+</%def>
+
+<%def name="right_panel()">
+
+ <%
+ ## FIXME: duplicated from above for now
+ controller_name = get_controller_name( item )
+ item_plural = get_item_plural( item )
+ href_to_all_items = h.url_for( controller='/' + controller_name, action='list_published')
+ href_to_user_items = h.url_for( controller='/' + controller_name, action='list_published', xxx=item.user.username)
+ href_to_user_items = href_to_user_items.replace( 'xxx', 'f-username')
+ %>
+
+ <div class="unified-panel-header" unselectable="on">
+ <div class="unified-panel-header-inner">
+ About this ${get_class_display_name( item.__class__ )}
+ </div>
+ </div>
+
+ <div class="unified-panel-body">
+ <div style="overflow: auto; height: 100%;">
+
%if item.published:
- <div class="page-meta">
+ <div style="padding: 10px;">
## Page meta.
- <div><strong>Related ${item_plural}</strong></div>
+ <h4>Related ${item_plural}</h4>
<p>
<a href="${href_to_all_items}">All published ${item_plural.lower()}</a><br>
<a href="${href_to_user_items}">${item_plural} owned by ${item.user.username}</a>
## Tags.
- <div><strong>Tags</strong></div>
+ <h4>Tags</strong></h4>
<p>
## Community tags.
<div>
@@ -153,6 +178,9 @@
</div>
</div>
%endif
+
+
</div>
</div>
+
</%def>
\ No newline at end of file
diff -r f5e3c6a1d135 -r 19334cf7f9b4 templates/page/display.mako
--- a/templates/page/display.mako Wed Jan 27 18:33:48 2010 -0500
+++ b/templates/page/display.mako Wed Jan 27 18:34:36 2010 -0500
@@ -153,7 +153,7 @@
<%def name="init()">
<%
self.has_left_panel=False
- self.has_right_panel=False
+ self.has_right_panel=item.published
self.active_view="user"
self.overlay_visible=False
%>
12 years, 3 months
[hg] galaxy 3291: Fix masthead fonts, remove padding from first ...
by Greg Von Kuster
details: http://www.bx.psu.edu/hg/galaxy/rev/f5e3c6a1d135
changeset: 3291:f5e3c6a1d135
user: James Taylor <james(a)jamestaylor.org>
date: Wed Jan 27 18:33:48 2010 -0500
description:
Fix masthead fonts, remove padding from first header in a block.
diffstat:
static/june_2007_style/base.css.tmpl | 4 ++++
static/june_2007_style/blue/base.css | 1 +
static/june_2007_style/blue/panel_layout.css | 4 ++--
static/june_2007_style/panel_layout.css.tmpl | 2 +-
4 files changed, 8 insertions(+), 3 deletions(-)
diffs (59 lines):
diff -r 75052c65e483 -r f5e3c6a1d135 static/june_2007_style/base.css.tmpl
--- a/static/june_2007_style/base.css.tmpl Wed Jan 27 17:46:14 2010 -0500
+++ b/static/june_2007_style/base.css.tmpl Wed Jan 27 18:33:48 2010 -0500
@@ -40,6 +40,10 @@
/*text-shadow: #bbb 2px 2px 1px;*/
}
+h1:first-child, h2:first-child, h3:first-child, h4:first-child {
+ margin-top: 0px;
+}
+
hr {
border: none;
height: 0px;
diff -r 75052c65e483 -r f5e3c6a1d135 static/june_2007_style/blue/base.css
--- a/static/june_2007_style/blue/base.css Wed Jan 27 17:46:14 2010 -0500
+++ b/static/june_2007_style/blue/base.css Wed Jan 27 18:33:48 2010 -0500
@@ -9,6 +9,7 @@
img{border:0;}
a:link,a:visited,a:active{color:#303030;}
h1,h2,h3,h4{color:#023858;}
+h1:first-child,h2:first-child,h3:first-child,h4:first-child{margin-top:0px;}
hr{border:none;height:0px;border-bottom:dotted #303030 1px;}
th{text-align:left;}
div.toolForm{border:solid #d8b365 1px;}
diff -r 75052c65e483 -r f5e3c6a1d135 static/june_2007_style/blue/panel_layout.css
--- a/static/june_2007_style/blue/panel_layout.css Wed Jan 27 17:46:14 2010 -0500
+++ b/static/june_2007_style/blue/panel_layout.css Wed Jan 27 18:33:48 2010 -0500
@@ -32,9 +32,9 @@
.panel-warning-message{background-image:url(warn_small.png);background-color:#FFFFCC;}
.panel-done-message{background-image:url(done_small.png);background-color:#CCFFCC;}
.panel-info-message{background-image:url(info_small.png);background-color:#CCCCFF;}
-#masthead{font-family: verdana;arial;sans-serif;position:absolute;top:0;left:0;width:100%;min-width:900px;height:32px;background:#2C3143;color:#fff;border-bottom:solid #444 1px;z-index:15000;padding:0;}
+#masthead{position:absolute;top:0;left:0;width:100%;min-width:900px;height:32px;background:#2C3143;color:#fff;border-bottom:solid #444 1px;z-index:15000;padding:0;}
#masthead a{color:#eeeeee;text-decoration:none;}
-#masthead .title{padding:3px 10px;font-size:175%;font-weight:bold;}
+#masthead .title{font-family:verdana;padding:3px 10px;font-size:175%;font-weight:bold;}
#masthead a:hover{text-decoration:underline;}
.tab-group{margin:0;padding:0 10px;height:100%;white-space:nowrap;cursor:default;background:transparent;}
.tab-group .tab{background:#2C3143;position:relative;float:left;margin:0;padding:0 1em;height:32px;line-height:32px;text-align:left;}
diff -r 75052c65e483 -r f5e3c6a1d135 static/june_2007_style/panel_layout.css.tmpl
--- a/static/june_2007_style/panel_layout.css.tmpl Wed Jan 27 17:46:14 2010 -0500
+++ b/static/june_2007_style/panel_layout.css.tmpl Wed Jan 27 18:33:48 2010 -0500
@@ -230,7 +230,6 @@
## Masthead
#masthead {
- font-family: verdana;arial;sans-serif;
position:absolute;
top:0;
left:0;
@@ -249,6 +248,7 @@
}
.title {
+ font-family: verdana;
padding: 3px 10px;
font-size: 175%;
font-weight: bold;
12 years, 3 months
[hg] galaxy 3290: Fix margins and scrolling on grid pages that u...
by Greg Von Kuster
details: http://www.bx.psu.edu/hg/galaxy/rev/75052c65e483
changeset: 3290:75052c65e483
user: James Taylor <james(a)jamestaylor.org>
date: Wed Jan 27 17:46:14 2010 -0500
description:
Fix margins and scrolling on grid pages that use panels
diffstat:
templates/panels.mako | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)
diffs (17 lines):
diff -r 41a77e993641 -r 75052c65e483 templates/panels.mako
--- a/templates/panels.mako Wed Jan 27 16:58:12 2010 -0500
+++ b/templates/panels.mako Wed Jan 27 17:46:14 2010 -0500
@@ -10,7 +10,11 @@
</%def>
<%def name="center_panel()">
-
- ${grid}
+
+ <div style="overflow: auto; height: 100%;">
+ <div style="padding: 10px">
+ ${grid}
+ </div>
+ </div>
</%def>
12 years, 3 months
[hg] galaxy 3289: Also do not use default value for repeats when...
by Greg Von Kuster
details: http://www.bx.psu.edu/hg/galaxy/rev/41a77e993641
changeset: 3289:41a77e993641
user: James Taylor <james(a)jamestaylor.org>
date: Wed Jan 27 16:58:12 2010 -0500
description:
Also do not use default value for repeats when ignore_errors=True
diffstat:
lib/galaxy/tools/parameters/grouping.py | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)
diffs (17 lines):
diff -r a357369bd0a2 -r 41a77e993641 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py Wed Jan 27 16:51:24 2010 -0500
+++ b/lib/galaxy/tools/parameters/grouping.py Wed Jan 27 16:58:12 2010 -0500
@@ -69,8 +69,11 @@
rval_dict['__index__'] = d.get( '__index__', i )
# Restore child inputs
for input in self.inputs.itervalues():
- if ignore_errors and input.name not in d: #this wasn't tested
- rval_dict[ input.name ] = input.get_initial_value( None, d )
+ if ignore_errors and input.name not in d:
+ # If we do not have a value, and are ignoring errors, we simply
+ # do nothing. There will be no value for the parameter in the
+ # conditional's values dictionary.
+ pass
else:
rval_dict[ input.name ] = input.value_from_basic( d[input.name], app, ignore_errors )
rval.append( rval_dict )
12 years, 3 months
[hg] galaxy 3288: Better handling of missing tool parameters in ...
by Greg Von Kuster
details: http://www.bx.psu.edu/hg/galaxy/rev/a357369bd0a2
changeset: 3288:a357369bd0a2
user: James Taylor <james(a)jamestaylor.org>
date: Wed Jan 27 16:51:24 2010 -0500
description:
Better handling of missing tool parameters in workflows. Missing conditionals and repeats should be handled. Running workflows with missing params is now possible. Editing and running both display details of all parameter changes that were made
diffstat:
lib/galaxy/tools/__init__.py | 7 +++----
lib/galaxy/tools/parameters/grouping.py | 13 +++++++++----
lib/galaxy/web/controllers/workflow.py | 26 +++++++++++++++++++++-----
templates/workflow/editor.mako | 8 ++++++--
templates/workflow/run.mako | 11 +++++++++++
5 files changed, 50 insertions(+), 15 deletions(-)
diffs (194 lines):
diff -r 0126990119e9 -r a357369bd0a2 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py Wed Jan 27 16:33:49 2010 -0500
+++ b/lib/galaxy/tools/__init__.py Wed Jan 27 16:51:24 2010 -0500
@@ -1068,7 +1068,6 @@
def params_from_strings( self, params, app, ignore_errors=False ):
return params_from_strings( self.inputs, params, app, ignore_errors )
-
def check_and_update_param_values( self, values, trans ):
"""
@@ -1076,7 +1075,7 @@
values where neccesary. This could be called after loading values
from a database in case new parameters have been added.
"""
- messages = []
+ messages = {}
self.check_and_update_param_values_helper( self.inputs, values, trans, messages )
return messages
@@ -1088,8 +1087,8 @@
for input in inputs.itervalues():
# No value, insert the default
if input.name not in values:
- messages.append( prefix + input.label )
- values[input.name] = input.get_initial_value( trans, context )
+ messages[ input.name ] = "No value found for '%s%s', used default" % ( prefix, input.label )
+ values[ input.name ] = input.get_initial_value( trans, context )
# Value, visit recursively as usual
else:
if isinstance( input, Repeat ):
diff -r 0126990119e9 -r a357369bd0a2 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py Wed Jan 27 16:33:49 2010 -0500
+++ b/lib/galaxy/tools/parameters/grouping.py Wed Jan 27 16:51:24 2010 -0500
@@ -47,6 +47,8 @@
return self.title
else:
return self.title + "s"
+ def label( self ):
+ return "Repeat (%s)" % self.title
def value_to_basic( self, value, app ):
rval = []
for d in value:
@@ -333,6 +335,9 @@
self.cases = []
self.value_ref = None
self.value_ref_in_group = True #When our test_param is not part of the conditional Group, this is False
+ @property
+ def label( self ):
+ return "Conditional (%s)" % self.name
def get_current_case( self, value, trans ):
# Convert value to user representation
str_value = self.test_param.filter_value( value, trans )
@@ -354,10 +359,10 @@
rval[ self.test_param.name ] = self.test_param.value_from_basic( value[ self.test_param.name ], app, ignore_errors )
for input in self.cases[current_case].inputs.itervalues():
if ignore_errors and input.name not in value:
- #two options here, either try to use unvalidated None or use initial==default value
- #using unvalidated values here will cause, i.e., integer fields within groupings to be filled in workflow building mode like '<galaxy.tools.parameters.basic.UnvalidatedValue object at 0x981818c>'
- #we will go with using the default value
- rval[ input.name ] = input.get_initial_value( None, value ) #use default value
+ # If we do not have a value, and are ignoring errors, we simply
+ # do nothing. There will be no value for the parameter in the
+ # conditional's values dictionary.
+ pass
else:
rval[ input.name ] = input.value_from_basic( value[ input.name ], app, ignore_errors )
return rval
diff -r 0126990119e9 -r a357369bd0a2 lib/galaxy/web/controllers/workflow.py
--- a/lib/galaxy/web/controllers/workflow.py Wed Jan 27 16:33:49 2010 -0500
+++ b/lib/galaxy/web/controllers/workflow.py Wed Jan 27 16:51:24 2010 -0500
@@ -474,7 +474,9 @@
# Fix any missing parameters
upgrade_message = module.check_and_update_state()
if upgrade_message:
- data['upgrade_messages'][step.order_index] = upgrade_message
+ # FIXME: Frontend should be able to handle workflow messages
+ # as a dictionary not just the values
+ data['upgrade_messages'][step.order_index] = upgrade_message.values()
# Pack attributes into plain dictionary
step_dict = {
'id': step.order_index,
@@ -706,6 +708,8 @@
error( "Workflow cannot be run because of validation errors in some steps" )
# Build the state for each step
errors = {}
+ has_upgrade_messages = False
+ has_errors = False
if kwargs:
# If kwargs were provided, the states for each step should have
# been POSTed
@@ -720,6 +724,10 @@
step_errors = None
if step.type == 'tool' or step.type is None:
module = module_factory.from_workflow_step( trans, step )
+ # Fix any missing parameters
+ step.upgrade_messages = module.check_and_update_state()
+ if step.upgrade_messages:
+ has_upgrade_messages = True
# Any connected input needs to have value DummyDataset (these
# are not persisted so we need to do it every time)
module.add_dummy_datasets( connections=step.input_connections )
@@ -761,18 +769,24 @@
workflow=stored,
outputs=outputs )
else:
+ # Prepare each step
for step in workflow.steps:
+ # Contruct modules
if step.type == 'tool' or step.type is None:
# Restore the tool state for the step
- module = module_factory.from_workflow_step( trans, step )
+ step.module = module_factory.from_workflow_step( trans, step )
+ # Fix any missing parameters
+ step.upgrade_messages = step.module.check_and_update_state()
+ if step.upgrade_messages:
+ has_upgrade_messages = True
# Any connected input needs to have value DummyDataset (these
# are not persisted so we need to do it every time)
- module.add_dummy_datasets( connections=step.input_connections )
+ step.module.add_dummy_datasets( connections=step.input_connections )
# Store state with the step
- step.module = module
- step.state = module.state
+ step.state = step.module.state
# Error dict
if step.tool_errors:
+ has_errors = True
errors[step.id] = step.tool_errors
else:
## Non-tool specific stuff?
@@ -785,6 +799,7 @@
"workflow/run.mako",
steps=workflow.steps,
workflow=stored,
+ has_upgrade_messages=has_upgrade_messages,
errors=errors,
incoming=kwargs )
@@ -978,3 +993,4 @@
cleanup( prefix, input.cases[current_case].inputs, group_values )
cleanup( "", inputs, values )
return associations
+
\ No newline at end of file
diff -r 0126990119e9 -r a357369bd0a2 templates/workflow/editor.mako
--- a/templates/workflow/editor.mako Wed Jan 27 16:33:49 2010 -0500
+++ b/templates/workflow/editor.mako Wed Jan 27 16:51:24 2010 -0500
@@ -90,11 +90,15 @@
// Determine if any parameters were 'upgraded' and provide message
upgrade_message = ""
$.each( data['upgrade_messages'], function( k, v ) {
- upgrade_message += ( "<li>Step " + ( parseInt(k) + 1 ) + ": " + workflow.nodes[k].name + " -- " + v.join( ", " ) );
+ upgrade_message += ( "<li>Step " + ( parseInt(k) + 1 ) + ": " + workflow.nodes[k].name + "<ul>");
+ $.each( v, function( i, vv ) {
+ upgrade_message += "<li>" + vv +"</li>";
+ });
+ upgrade_message += "</ul></li>";
});
if ( upgrade_message ) {
show_modal( "Workflow loaded with changes",
- "Values were not found for the following parameters (possibly a result of tool upgrades), <br/> default values have been used. Please review the following parameters and then save.<ul>" + upgrade_message + "</ul>",
+ "Problems were encountered loading this workflow (possibly a result of tool upgrades). Please review the following parameters and then save.<ul>" + upgrade_message + "</ul>",
{ "Continue" : hide_modal } );
} else {
hide_modal();
diff -r 0126990119e9 -r a357369bd0a2 templates/workflow/run.mako
--- a/templates/workflow/run.mako Wed Jan 27 16:33:49 2010 -0500
+++ b/templates/workflow/run.mako Wed Jan 27 16:51:24 2010 -0500
@@ -104,6 +104,9 @@
${param.value_to_display_text( value, app )}
%endif
</div>
+ %if step.upgrade_messages and param.name in step.upgrade_messages:
+ <div class="warningmark">${step.upgrade_messages[param.name]}</div>
+ %endif
%if error_dict.has_key( param.name ):
<div style="color: red; font-weight: bold; padding-top: 1px; padding-bottom: 3px;">
<div style="width: 300px;"><img style="vertical-align: middle;" src="${h.url_for('/static/style/error_small.png')}"> <span style="vertical-align: middle;">${error_dict[param.name]}</span></div>
@@ -115,6 +118,14 @@
<h2>Running workflow "${workflow.name}"</h2>
+%if has_upgrade_messages:
+<div class="warningmessage">
+ Problems were encourered when loading this workflow, likely due to tool
+ version changes. Missing parameter values have been replaced with default.
+ Please review the parameter values below.
+</div>
+%endif
+
<form id="tool_form" name="tool_form" method="POST">
## <input type="hidden" name="workflow_name" value="${workflow.name | h}" />
%for i, step in enumerate( steps ):
12 years, 3 months