galaxy-commits
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
- 15302 discussions
10 May '10
details: http://www.bx.psu.edu/hg/galaxy/rev/5f59c890ee8d
changeset: 3744:5f59c890ee8d
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Tue May 04 22:27:05 2010 -0400
description:
Fix bug that mucked up fetch for chrom lengths in new track browsers.
diffstat:
lib/galaxy/web/controllers/tracks.py | 32 ++++++++++++++++++++------------
templates/tracks/browser.mako | 7 ++++++-
2 files changed, 26 insertions(+), 13 deletions(-)
diffs (76 lines):
diff -r b5c76e1a28ea -r 5f59c890ee8d lib/galaxy/web/controllers/tracks.py
--- a/lib/galaxy/web/controllers/tracks.py Tue May 04 21:57:26 2010 -0400
+++ b/lib/galaxy/web/controllers/tracks.py Tue May 04 22:27:05 2010 -0400
@@ -158,9 +158,9 @@
return trans.fill_template( 'tracks/browser.mako', config=config )
@web.json
- def chroms(self, trans, vis_id=None ):
+ def chroms(self, trans, vis_id=None, dbkey=None ):
"""
- Returns a naturally sorted list of chroms/contigs for the given dbkey
+ Returns a naturally sorted list of chroms/contigs for either a given visualization or a given dbkey.
"""
def check_int(s):
if s.isdigit():
@@ -171,25 +171,33 @@
def split_by_number(s):
return [ check_int(c) for c in re.split('([0-9]+)', s) ]
- # Get visualization and config.
- visualization = self.get_visualization( trans, vis_id, check_ownership=False, check_accessible=True )
- visualization.config = self.get_visualization_config( trans, visualization )
- if visualization is None:
- raise web.httpexceptions.HTTPNotFound()
+ # Must specify either vis_id or dbkey.
+ if not vis_id and not dbkey:
+ return trans.show_error_message("No visualization id or dbkey specified.")
+
+ # Need to get user and dbkey in order to get chroms data.
+ if vis_id:
+ # Use user, dbkey from viz.
+ visualization = self.get_visualization( trans, vis_id, check_ownership=False, check_accessible=True )
+ visualization.config = self.get_visualization_config( trans, visualization )
+ vis_user = visualization.user
+ vis_dbkey = visualization.config['dbkey']
+ else:
+ # No vis_id, so visualization is new. User is current user, dbkey must be given.
+ vis_user = trans.user
+ vis_dbkey = dbkey
# Get chroms data.
- chroms = self._chroms( trans, visualization )
+ chroms = self._chroms( trans, vis_user, vis_dbkey )
to_sort = [{ 'chrom': chrom, 'len': length } for chrom, length in chroms.iteritems()]
to_sort.sort(lambda a,b: cmp( split_by_number(a['chrom']), split_by_number(b['chrom']) ))
return to_sort
- def _chroms( self, trans, visualization ):
+ def _chroms( self, trans, user, dbkey ):
"""
- Called by the browser to get a list of valid chromosomes and lengths
+ Helper method that returns chrom lengths for a given user and dbkey.
"""
# If there is any dataset in the history of extension `len`, this will use it
- user = visualization.user
- dbkey = visualization.config['dbkey']
if 'dbkeys' in user.preferences:
user_keys = from_json_string( user.preferences['dbkeys'] )
if dbkey in user_keys:
diff -r b5c76e1a28ea -r 5f59c890ee8d templates/tracks/browser.mako
--- a/templates/tracks/browser.mako Tue May 04 21:57:26 2010 -0400
+++ b/templates/tracks/browser.mako Tue May 04 22:27:05 2010 -0400
@@ -272,7 +272,12 @@
$.ajax({
url: "${h.url_for( action='chroms' )}",
- data: { vis_id: view.vis_id },
+ ## If vis is new, it doesn't have an id, so send the dbkey instead.
+ %if config.get('vis_id'):
+ data: { vis_id: view.vis_id },
+ %else:
+ data: { dbkey: view.dbkey },
+ %endif
dataType: "json",
success: function ( data ) {
view.chrom_data = data;
1
0
10 May '10
details: http://www.bx.psu.edu/hg/galaxy/rev/49c11691bc2e
changeset: 3742:49c11691bc2e
user: Kanwei Li <kanwei(a)gmail.com>
date: Tue May 04 15:43:34 2010 -0400
description:
trackster: fix BAM data error; display tweaks
diffstat:
lib/galaxy/datatypes/converters/bed_to_summary_tree_converter.py | 2 +-
lib/galaxy/visualization/tracks/data/bam.py | 11 +++++++++-
lib/galaxy/visualization/tracks/data/summary_tree.py | 4 +-
static/scripts/trackster.js | 5 ++-
4 files changed, 16 insertions(+), 6 deletions(-)
diffs (84 lines):
diff -r c7607fba91b9 -r 49c11691bc2e lib/galaxy/datatypes/converters/bed_to_summary_tree_converter.py
--- a/lib/galaxy/datatypes/converters/bed_to_summary_tree_converter.py Tue May 04 14:21:21 2010 -0400
+++ b/lib/galaxy/datatypes/converters/bed_to_summary_tree_converter.py Tue May 04 15:43:34 2010 -0400
@@ -15,7 +15,7 @@
reader = BedReader( open( input_fname ) )
- st = SummaryTree(block_size=100, levels=4, draw_cutoff=100, detail_cutoff=20)
+ st = SummaryTree(block_size=25, levels=6, draw_cutoff=150, detail_cutoff=30)
for chrom, chrom_start, chrom_end, name, score in reader:
st.insert_range(chrom, chrom_start, chrom_end)
diff -r c7607fba91b9 -r 49c11691bc2e lib/galaxy/visualization/tracks/data/bam.py
--- a/lib/galaxy/visualization/tracks/data/bam.py Tue May 04 14:21:21 2010 -0400
+++ b/lib/galaxy/visualization/tracks/data/bam.py Tue May 04 15:43:34 2010 -0400
@@ -10,6 +10,8 @@
import logging
log = logging.getLogger(__name__)
+MAX_VALS = 50 # only display first MAX_VALS datapoints
+
class BamDataProvider( object ):
"""
Provides access to intervals from a sorted indexed BAM file.
@@ -26,18 +28,25 @@
start, end = int(start), int(end)
# Attempt to open the BAM file with index
bamfile = csamtools.Samfile( filename=self.original_dataset.file_name, mode='rb', index_filename=self.index.file_name )
+ message = None
try:
data = bamfile.fetch(start=start, end=end, reference=chrom)
except ValueError, e:
# Some BAM files do not prefix chromosome names with chr, try without
if chrom.startswith( 'chr' ):
- data = bamfile.fetch( start=start, end=end, reference=chrom[3:] )
+ try:
+ data = bamfile.fetch( start=start, end=end, reference=chrom[3:] )
+ except:
+ return None
else:
return None
# Encode reads as list of dictionaries
results = []
paired_pending = {}
for read in data:
+ if len(results) > MAX_VALS:
+ message = "Only the first %s pairs are being displayed." % MAX_VALS
+ break
qname = read.qname
if read.is_proper_pair:
if qname in paired_pending: # one in dict is always first
diff -r c7607fba91b9 -r 49c11691bc2e lib/galaxy/visualization/tracks/data/summary_tree.py
--- a/lib/galaxy/visualization/tracks/data/summary_tree.py Tue May 04 14:21:21 2010 -0400
+++ b/lib/galaxy/visualization/tracks/data/summary_tree.py Tue May 04 15:43:34 2010 -0400
@@ -32,12 +32,12 @@
level = int(max( level, 0 ))
if level <= 0:
return None
-
+
stats = st.chrom_stats[chrom]
results = st.query(chrom, int(start), int(end), level)
if results == "detail":
return None
- elif results == "draw":
+ elif results == "draw" or level <= 1:
return "no_detail"
else:
return results, stats[level]["max"], stats[level]["avg"], stats[level]["delta"]
diff -r c7607fba91b9 -r 49c11691bc2e static/scripts/trackster.js
--- a/static/scripts/trackster.js Tue May 04 14:21:21 2010 -0400
+++ b/static/scripts/trackster.js Tue May 04 15:43:34 2010 -0400
@@ -439,8 +439,9 @@
return;
}
- var data = this.data_cache.get(key);
- if (data === null) { return; }
+ var result = this.data_cache.get(key);
+ if (result === null) { return; }
+ console.log(result);
canvas.css( {
position: "absolute",
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/b5c76e1a28ea
changeset: 3743:b5c76e1a28ea
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Tue May 04 21:57:26 2010 -0400
description:
Removing debugging msg.
diffstat:
tools/ngs_rna/cuffcompare_wrapper.py | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diffs (11 lines):
diff -r 49c11691bc2e -r b5c76e1a28ea tools/ngs_rna/cuffcompare_wrapper.py
--- a/tools/ngs_rna/cuffcompare_wrapper.py Tue May 04 15:43:34 2010 -0400
+++ b/tools/ngs_rna/cuffcompare_wrapper.py Tue May 04 21:57:26 2010 -0400
@@ -52,7 +52,6 @@
input2_file_name = tmp_output_dir + "/input2"
os.symlink( options.input2, input2_file_name )
cmd += " %s" % input2_file_name
- print cmd
# Run command.
try:
1
0
10 May '10
details: http://www.bx.psu.edu/hg/galaxy/rev/c7607fba91b9
changeset: 3741:c7607fba91b9
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Tue May 04 14:21:21 2010 -0400
description:
Fix the recentrly introduced grid filter / search bug. Revert the recently introduced grid filter_params hack for generating links since we now use a different approach to rendering links. Convert a few more 'message_type' params to be 'status' instead. Many fixes for the community space app.
diffstat:
lib/galaxy/tools/__init__.py | 4 +-
lib/galaxy/web/framework/__init__.py | 2 +-
lib/galaxy/web/framework/helpers/grids.py | 17 +-
lib/galaxy/webapps/community/controllers/admin.py | 154 +++++++++++++-------
lib/galaxy/webapps/community/controllers/common.py | 90 ++++++++---
lib/galaxy/webapps/community/controllers/tool.py | 157 +++++++++++---------
lib/galaxy/webapps/community/controllers/upload.py | 33 ++--
lib/galaxy/webapps/community/model/__init__.py | 4 +-
templates/dataset/display_application/display.mako | 4 +-
templates/display_common.mako | 4 +-
templates/grid_base.mako | 16 +-
templates/grid_base_async.mako | 2 +-
templates/message.mako | 12 +-
templates/page/select_items_grid_async.mako | 2 +-
templates/webapps/community/admin/center.mako | 39 ++++-
templates/webapps/community/tool/edit_tool.mako | 19 +-
templates/webapps/community/tool/view_tool.mako | 25 ++-
17 files changed, 354 insertions(+), 230 deletions(-)
diffs (1213 lines):
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/tools/__init__.py Tue May 04 14:21:21 2010 -0400
@@ -837,7 +837,7 @@
assert isinstance( out_data, odict )
return 'tool_executed.mako', dict( out_data=out_data )
except:
- return 'message.mako', dict( message_type='error', message='odict not returned from tool execution', refresh_frames=[] )
+ return 'message.mako', dict( status='error', message='odict not returned from tool execution', refresh_frames=[] )
# Otherwise move on to the next page
else:
state.page += 1
@@ -890,7 +890,7 @@
self.sa_session.add( data )
self.sa_session.flush()
# It's unlikely the user will ever see this.
- return 'message.mako', dict( message_type='error', message='Your upload was interrupted. If this was uninentional, please retry it.', refresh_frames=[], cont=None )
+ return 'message.mako', dict( status='error', message='Your upload was interrupted. If this was uninentional, please retry it.', refresh_frames=[], cont=None )
def update_state( self, trans, inputs, state, incoming, prefix="", context=None,
update_only=False, old_errors={}, item_callback=None ):
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/web/framework/__init__.py Tue May 04 14:21:21 2010 -0400
@@ -591,7 +591,7 @@
`refresh_frames`: names of frames in the interface that should be
refreshed when the message is displayed
"""
- return self.fill_template( "message.mako", message_type=type, message=message, refresh_frames=refresh_frames, cont=cont, use_panels=use_panels, active_view=active_view )
+ return self.fill_template( "message.mako", status=type, message=message, refresh_frames=refresh_frames, cont=cont, use_panels=use_panels, active_view=active_view )
def show_error_message( self, message, refresh_frames=[], use_panels=False, active_view="" ):
"""
Convenience method for displaying an error message. See `show_message`.
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/web/framework/helpers/grids.py
--- a/lib/galaxy/web/framework/helpers/grids.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/web/framework/helpers/grids.py Tue May 04 14:21:21 2010 -0400
@@ -134,13 +134,16 @@
column_filter = unicode(column_filter)
extra_url_args[ "f-" + column.key ] = column_filter.encode("utf-8")
# Process sort arguments.
- sort_key = sort_order = None
+ sort_key = None
+ sort_order = None
if 'sort' in kwargs:
sort_key = kwargs['sort']
elif base_sort_key:
sort_key = base_sort_key
encoded_sort_key = sort_key
if sort_key:
+ # TODO: what if the model object of the grid column being sorted is not
+ # the same object as self.model_class?
if sort_key.startswith( "-" ):
sort_key = sort_key[1:]
sort_order = 'desc'
@@ -230,10 +233,10 @@
current_item=current_item,
ids = kwargs.get( 'id', [] ),
url = url,
- message_type = status,
+ status = status,
message = message,
use_panels=use_panels,
- webapp=self.webapp,
+ webapp=webapp,
# Pass back kwargs so that grid template can set and use args without
# grid explicitly having to pass them.
kwargs=kwargs )
@@ -290,9 +293,7 @@
if self.format:
value = self.format( value )
return value
- def get_link( self, trans, grid, item, filter_params ):
- # FIXME: filter_params is only here so we can do grid filtering from
- # column links. remove once a better way is created.
+ def get_link( self, trans, grid, item ):
if self.link and self.link( item ):
return self.link( item )
return None
@@ -449,7 +450,7 @@
class PublicURLColumn( TextColumn ):
""" Column displays item's public URL based on username and slug. """
- def get_link( self, trans, grid, item, filter_params ):
+ def get_link( self, trans, grid, item ):
if item.user.username and item.slug:
return dict( action='display_by_username_and_slug', username=item.user.username, slug=item.slug )
elif not item.user.username:
@@ -485,7 +486,7 @@
if item.published:
sharing_statuses.append( "Published" )
return ", ".join( sharing_statuses )
- def get_link( self, trans, grid, item, filter_params ):
+ def get_link( self, trans, grid, item ):
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 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/webapps/community/controllers/admin.py
--- a/lib/galaxy/webapps/community/controllers/admin.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/webapps/community/controllers/admin.py Tue May 04 14:21:21 2010 -0400
@@ -47,7 +47,7 @@
return ""
class ToolsColumn( grids.TextColumn ):
def get_value( self, trans, grid, user ):
- return '<a href="browse_tools_by_user?operation=browse&id=%s">%s</a>' % ( trans.security.encode_id( user.id ), str( len( user.tools ) ) )
+ return '<a href="browse_tools_by_user?operation=browse&id=%s&webapp=community">%s</a>' % ( trans.security.encode_id( user.id ), str( len( user.tools ) ) )
# Grid definition
webapp = "community"
@@ -77,7 +77,10 @@
attach_popup=False,
filterable="advanced" ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
cols_to_filter=[ columns[0], columns[1] ],
@@ -168,7 +171,10 @@
UsersColumn( "Users", attach_popup=False ),
StatusColumn( "Status", attach_popup=False ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
cols_to_filter=[ columns[0], columns[1], columns[2] ],
@@ -238,16 +244,20 @@
default_sort_key = "name"
columns = [
NameColumn( "Name",
- key="name",
+ #key="name",
link=( lambda item: dict( operation="Manage users and roles", id=item.id, webapp="community" ) ),
model_class=model.Group,
- attach_popup=True,
- filterable="advanced" ),
+ attach_popup=True
+ #filterable="advanced"
+ ),
UsersColumn( "Users", attach_popup=False ),
RolesColumn( "Roles", attach_popup=False ),
StatusColumn( "Status", attach_popup=False ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
cols_to_filter=[ columns[0], columns[1], columns[2] ],
@@ -309,14 +319,18 @@
attach_popup=False,
filterable="advanced" ),
DescriptionColumn( "Description",
+ key="description",
model_class=model.Category,
attach_popup=False,
filterable="advanced" ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
- cols_to_filter=[ columns[0], columns[1], columns[2] ],
+ cols_to_filter=[ columns[0], columns[1] ],
key="free-text-search",
visible=False,
filterable="standard" ) )
@@ -370,24 +384,34 @@
default_sort_key = "name"
columns = [
NameColumn( "Name",
- key="name",
+ # TODO: we cannot currently sort by columns since the grid may be filtered by tool ids
+ # and it is not clear if / how that will work. We need to be able to send to the grid helper
+ # the list of ids on which to filter when sorting on the column.
+ #key="name",
+ model_class=model.Category,
link=( lambda item: dict( operation="Browse Category", id=item.id, webapp="community" ) ),
- model_class=model.Category,
- attach_popup=True,
- filterable="advanced" ),
+ attach_popup=False
+ #filterable="advanced"
+ ),
DescriptionColumn( "Description",
+ #key="description",
model_class=model.Category,
- attach_popup=False,
- filterable="advanced" ),
+ attach_popup=False
+ #filterable="advanced"
+ ),
ToolsColumn( "Tools",
- model_class=model.Category,
+ model_class=model.Tool,
attach_popup=False,
filterable="advanced" ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
- cols_to_filter=[ columns[0], columns[1], columns[2] ],
+ #cols_to_filter=[ columns[0], columns[1] ],
+ cols_to_filter=[],
key="free-text-search",
visible=False,
filterable="standard" ) )
@@ -399,10 +423,17 @@
num_rows_per_page = 50
preserve_state = False
use_paging = True
- def get_current_item( self, trans ):
- return None
def build_initial_query( self, session ):
return session.query( self.model_class )
+ def apply_default_filter( self, trans, query, **kwd ):
+ ids = kwd.get( 'ids', False )
+ if ids:
+ if str( ids ).lower() == 'none':
+ # No tools for display
+ return query.filter( model.Tool.id == None )
+ ids = util.listify( ids )
+ query = query.filter( or_( *map( lambda id: self.model_class.id == id, ids ) ) )
+ return query
class ToolListGrid( grids.Grid ):
class NameColumn( grids.TextColumn ):
@@ -419,7 +450,7 @@
if tool.categories:
rval = ''
for tca in tool.categories:
- rval += '<a href="browse_category?id=%s">%s</a><br/>\n' % ( trans.security.encode_id( tca.category.id ), tca.category.name )
+ rval += '<a href="browse_category?id=%s&webapp=community">%s</a><br/>\n' % ( trans.security.encode_id( tca.category.id ), tca.category.name )
return rval
return 'not set'
class StateColumn( grids.GridColumn ):
@@ -450,7 +481,7 @@
return accepted_filters
class UserColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
- return '<a href="browse_tools_by_user?operation=browse&id=%s">%s</a>' % ( trans.security.encode_id( tool.user.id ), tool.user.username )
+ return '<a href="browse_tools_by_user?operation=browse&id=%s&webapp=community">%s</a>' % ( trans.security.encode_id( tool.user.id ), tool.user.username )
# Grid definition
title = "Tools"
model_class = model.Tool
@@ -458,19 +489,25 @@
default_sort_key = "name"
columns = [
NameColumn( "Name",
- key="name",
+ # TODO: we cannot currently sort by columns since the grid may be filtered by tool ids
+ # and it is not clear if / how that will work. We need to be able to send to the grid helper
+ # the list of ids on which to filter when sorting on the column.
+ #key="name",
+ link=( lambda item: dict( operation="View Tool", id=item.id, cntrller="admin", webapp="community" ) ),
model_class=model.Tool,
- link=( lambda item: dict( operation="View Tool", id=item.id, cntrller='admin', webapp="community" ) ),
- attach_popup=True,
- filterable="advanced" ),
+ attach_popup=True
+ #filterable="advanced"
+ ),
VersionColumn( "Version",
model_class=model.Tool,
attach_popup=False,
filterable="advanced" ),
DescriptionColumn( "Description",
- model_class=model.Tool,
- attach_popup=False,
- filterable="advanced" ),
+ #key="description",
+ model_class=model.Tool,
+ attach_popup=False
+ #filterable="advanced"
+ ),
CategoryColumn( "Category",
model_class=model.Category,
attach_popup=False,
@@ -479,15 +516,19 @@
model_class=model.Event,
attach_popup=False ),
UserColumn( "Uploaded By",
- key="username",
model_class=model.User,
attach_popup=False,
filterable="advanced" ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", model_class=model.Tool, key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ model_class=model.Tool,
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
- cols_to_filter=[ columns[0], columns[1] ],
+ #cols_to_filter=[ columns[0], columns[2], columns[5] ],
+ cols_to_filter=[],
key="free-text-search",
visible=False,
filterable="standard" ) )
@@ -499,7 +540,7 @@
]
standard_filters = [
grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ),
- grids.GridColumnFilter( "All", args=dict( deleted='All' ) )
+ grids.GridColumnFilter( "All", args=dict( deleted='All' ) ),
]
default_filter = dict( name="All", deleted="False" )
num_rows_per_page = 50
@@ -508,15 +549,14 @@
def build_initial_query( self, session ):
return session.query( self.model_class )
def apply_default_filter( self, trans, query, **kwd ):
- tool_id = kwd.get( 'tool_id', False )
- if tool_id:
- if str( tool_id ).lower() in [ '', 'none' ]:
- # Return an empty query since the current user cannot view any
- # tools (possibly due to state not being approved, etc).
+ ids = kwd.get( 'ids', False )
+ if ids:
+ if str( ids ).lower() == 'none':
+ # No tools for display
return query.filter( model.Tool.id == None )
- tool_id = util.listify( tool_id )
- query = query.filter( or_( *map( lambda id: self.model_class.id == id, tool_id ) ) )
- return query.filter( self.model_class.deleted==False )
+ ids = util.listify( ids )
+ query = query.filter( or_( *map( lambda id: self.model_class.id == id, ids ) ) )
+ return query
class AdminController( BaseController, Admin ):
@@ -616,12 +656,12 @@
status='error' ) )
event = get_event( trans, id )
state = event.state
- tool_id = get_tools_by_state( trans, state )
- if not tool_id:
- tool_id = 'None'
+ ids = get_tools_by_state( trans, state )
+ if not ids:
+ ids = 'none'
return trans.response.send_redirect( web.url_for( controller='admin',
action='browse_tools',
- tool_id=tool_id ) )
+ ids=ids ) )
@web.expose
@web.require_admin
def browse_category( self, trans, **kwd ):
@@ -681,7 +721,10 @@
# If we're approving a tool, all previous versions must be set to archived
for version in get_versions( trans, tool ):
if version != tool and version.is_approved():
- self.set_tool_state( trans, trans.app.model.Tool.states.ARCHIVED, id=trans.app.security.encode_id( version.id ), redirect='False' )
+ self.set_tool_state( trans,
+ trans.app.model.Tool.states.ARCHIVED,
+ id=trans.security.encode_id( version.id ),
+ redirect='False' )
event = trans.model.Event( state )
# Flush so we an get an id
trans.sa_session.add( event )
@@ -842,33 +885,34 @@
## ---- Utility methods -------------------------------------------------------
def get_tools_by_state( trans, state ):
- tool_id = []
+ # TODO: write this as a query using eagerload - will be much faster.
+ ids = []
if state == trans.model.Tool.states.NEW:
for tool in get_tools( trans ):
if tool.is_new():
- tool_id.append( tool.id )
+ ids.append( tool.id )
elif state == trans.model.Tool.states.ERROR:
for tool in get_tools( trans ):
if tool.is_error():
- tool_id.append( tool.id )
+ ids.append( tool.id )
elif state == trans.model.Tool.states.DELETED:
for tool in get_tools( trans ):
if tool.is_deleted():
- tool_id.append( tool.id )
+ ids.append( tool.id )
elif state == trans.model.Tool.states.WAITING:
for tool in get_tools( trans ):
if tool.is_waiting():
- tool_id.append( tool.id )
+ ids.append( tool.id )
elif state == trans.model.Tool.states.APPROVED:
for tool in get_tools( trans ):
if tool.is_approved():
- tool_id.append( tool.id )
+ ids.append( tool.id )
elif state == trans.model.Tool.states.REJECTED:
for tool in get_tools( trans ):
if tool.is_rejected():
- tool_id.append( tool.id )
+ ids.append( tool.id )
elif state == trans.model.Tool.states.ARCHIVED:
for tool in get_tools( trans ):
if tool.is_archived():
- tool_id.append( tool.id )
- return tool_id
+ ids.append( tool.id )
+ return ids
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/webapps/community/controllers/common.py
--- a/lib/galaxy/webapps/community/controllers/common.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/webapps/community/controllers/common.py Tue May 04 14:21:21 2010 -0400
@@ -91,6 +91,35 @@
message=message,
status=status )
@web.expose
+ def delete_tool( self, trans, cntrller, **kwd ):
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ id = params.get( 'id', None )
+ if not id:
+ message='Select a tool to delete'
+ status='error'
+ else:
+ tool = get_tool( trans, id )
+ # Create a new event
+ event = trans.model.Event( state=trans.model.Tool.states.DELETED )
+ # Flush so we can get an event id
+ trans.sa_session.add( event )
+ trans.sa_session.flush()
+ # Associate the tool with the event
+ tea = trans.model.ToolEventAssociation( tool=tool, event=event )
+ # Delete the tool, keeping state for categories, events and versions
+ tool.deleted = True
+ trans.sa_session.add_all( ( tool, tea ) )
+ trans.sa_session.flush()
+ # TODO: What if the tool has versions, should they all be deleted?
+ message = "Tool '%s' has been marked deleted"
+ status = 'done'
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='browse_tools',
+ message=message,
+ status=status ) )
+ @web.expose
def upload_new_tool_version( self, trans, cntrller, **kwd ):
params = util.Params( kwd )
message = util.restore_text( params.get( 'message', '' ) )
@@ -122,15 +151,15 @@
# If request came from the tool controller, then we need to filter by the state of the
# tool in addition to the category.
if cntrller == 'tool':
- tool_id = get_approved_tools( trans, category=category )
+ ids = get_approved_tools( trans, category=category )
else:
# If request came from the admin controller, we don't filter on tool state.
- tool_id = [ tca.tool.id for tca in category.tools ]
- if not tool_id:
- tool_id = 'None'
+ ids = [ tca.tool.id for tca in category.tools ]
+ if not ids:
+ ids = 'none'
return trans.response.send_redirect( web.url_for( controller=cntrller,
action='browse_tools',
- tool_id=tool_id ) )
+ ids=ids ) )
@web.expose
def browse_tools_by_user( self, trans, cntrller, **kwd ):
params = util.Params( kwd )
@@ -146,15 +175,21 @@
# If request came from the tool controller, then we need to filter by the state of the
# tool if the user is not viewing his own tools
if cntrller == 'tool':
- tool_id = get_approved_tools( trans, user=user )
+ ids = get_tools_uploaded_by( trans, user )
else:
- # If request came from the admin controller, we don't filter on tool state.
- tool_id = [ tool.id for tool in user.tools ]
- if not tool_id:
- tool_id = 'None'
+ # If request came from the admin controller we don't filter on tool state.
+ ids = [ tool.id for tool in user.tools ]
+ if not ids:
+ ids = 'none'
+ if cntrller == 'tool' and user != trans.user:
+ # If the user is browsing someone else's tools, then we do not want to
+ # use the BrowseToolsByUser list grid since it includes a status column.
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='browse_tools',
+ ids=ids ) )
return trans.response.send_redirect( web.url_for( controller=cntrller,
action='browse_tools_by_user',
- tool_id=tool_id ) )
+ ids=ids ) )
## ---- Utility methods -------------------------------------------------------
@@ -202,30 +237,33 @@
return trans.sa_session.query( trans.model.Tool ).get( trans.app.security.decode_id( id ) )
def get_tools( trans ):
return trans.sa_session.query( trans.model.Tool ).order_by( trans.model.Tool.name )
-def get_approved_tools( trans, category=None, user=None ):
- tool_id = []
+def get_approved_tools( trans, category=None ):
+ # TODO: write this as a query using eagerload - will be much faster.
+ ids = []
if category:
# Return only the approved tools in the category
for tca in category.tools:
tool = tca.tool
if tool.is_approved():
- tool_id.append( tool.id )
- elif user:
- if trans.user == user:
- # If the current user is browsing his own tools, then don't filter on state
- tool_id = [ tool.id for tool in user.tools ]
- else:
- # The current user is viewing all tools uploaded by another user, so show only
- # approved tools
- for tool in user.active_tools:
- if tool.is_approved():
- tool_id.append( tool.id )
+ ids.append( tool.id )
else:
# Return all approved tools
for tool in get_tools( trans ):
if tool.is_approved():
- tool_id.append( tool.id )
- return tool_id
+ ids.append( tool.id )
+ return ids
+def get_tools_uploaded_by( trans, user ):
+ # TODO: write this as a query using eagerload - will be much faster.
+ ids = []
+ if trans.user == user:
+ # If the current user is browsing his own tools, then don't filter on state
+ ids = [ tool.id for tool in user.tools ]
+ else:
+ # The current user is viewing tools uploaded by another user, so show only approved tools
+ for tool in user.active_tools:
+ if tool.is_approved():
+ ids.append( tool.id )
+ return ids
def get_event( trans, id ):
return trans.sa_session.query( trans.model.Event ).get( trans.security.decode_id( id ) )
def get_user( trans, id ):
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/webapps/community/controllers/tool.py
--- a/lib/galaxy/webapps/community/controllers/tool.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/webapps/community/controllers/tool.py Tue May 04 14:21:21 2010 -0400
@@ -26,12 +26,12 @@
if tool.categories:
rval = ''
for tca in tool.categories:
- rval += '<a href="browse_category?id=%s">%s</a><br/>\n' % ( trans.security.encode_id( tca.category.id ), tca.category.name )
+ rval += '<a href="browse_category?id=%s&webapp=community">%s</a><br/>\n' % ( trans.security.encode_id( tca.category.id ), tca.category.name )
return rval
return 'not set'
class UserColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
- return '<a href="browse_tools_by_user?operation=browse&id=%s">%s</a>' % ( trans.security.encode_id( tool.user.id ), tool.user.username )
+ return '<a href="browse_tools_by_user?operation=browse&id=%s&webapp=community">%s</a>' % ( trans.security.encode_id( tool.user.id ), tool.user.username )
# Grid definition
title = "Tools"
model_class = model.Tool
@@ -39,33 +39,44 @@
default_sort_key = "name"
columns = [
NameColumn( "Name",
- key="name",
+ # TODO: we cannot currently sort by columns since the grid may be filtered by tool ids
+ # and it is not clear if / how that will work. We need to be able to send to the grid helper
+ # the list of ids on which to filter when sorting on the column.
+ #key="name",
model_class=model.Tool,
link=( lambda item: dict( operation="View Tool", id=item.id, cntrller='tool', webapp="community" ) ),
- attach_popup=True,
- filterable="advanced" ),
+ attach_popup=True
+ #filterable="advanced"
+ ),
VersionColumn( "Version",
model_class=model.Tool,
attach_popup=False,
filterable="advanced" ),
DescriptionColumn( "Description",
- model_class=model.Tool,
- attach_popup=False,
- filterable="advanced" ),
+ #key="description",
+ model_class=model.Tool,
+ attach_popup=False
+ #filterable="advanced"
+ ),
CategoryColumn( "Categories",
model_class=model.Category,
attach_popup=False,
filterable="advanced" ),
UserColumn( "Uploaded By",
- key="username",
+ #key="username",
model_class=model.User,
- attach_popup=False,
- filterable="advanced" ),
+ attach_popup=False
+ #filterable="advanced"
+ ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
- cols_to_filter=[ columns[0], columns[1] ],
+ #cols_to_filter=[ columns[0], columns[2], columns[4] ],
+ cols_to_filter=[],
key="free-text-search",
visible=False,
filterable="standard" ) )
@@ -86,21 +97,15 @@
def build_initial_query( self, session ):
return session.query( self.model_class )
def apply_default_filter( self, trans, query, **kwd ):
- def filter_query( query, tool_id ):
- if str( tool_id ).lower() in [ '', 'none' ]:
- # Return an empty query since the current user cannot view any
- # tools (possibly due to state not being approved, etc).
- return query.filter( model.Tool.id == None )
- tool_id = util.listify( tool_id )
- query = query.filter( or_( *map( lambda id: self.model_class.id == id, tool_id ) ) )
- return query.filter( self.model_class.deleted==False )
- tool_id = kwd.get( 'tool_id', False )
- if not tool_id:
+ ids = kwd.get( 'ids', False )
+ if not ids:
# Display only approved tools
- tool_id = get_approved_tools( trans )
- if not tool_id:
- tool_id = 'None'
- return filter_query( query, tool_id )
+ ids = get_approved_tools( trans )
+ if not ids or str( ids ).lower() == 'none':
+ return query.filter( trans.model.Tool.id == None )
+ ids = util.listify( ids )
+ query = query.filter( or_( *map( lambda id: self.model_class.id == id, ids ) ) )
+ return query
class ToolsByUserListGrid( grids.Grid ):
class NameColumn( grids.TextColumn ):
@@ -117,7 +122,7 @@
if tool.categories:
rval = ''
for tca in tool.categories:
- rval += '<a href="browse_category?id=%s">%s</a><br/>\n' % ( trans.security.encode_id( tca.category.id ), tca.category.name )
+ rval += '<a href="browse_category?id=%s&webapp=community">%s</a><br/>\n' % ( trans.security.encode_id( tca.category.id ), tca.category.name )
return rval
return 'not set'
class StateColumn( grids.GridColumn ):
@@ -148,7 +153,7 @@
return accepted_filters
class UserColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
- return '<a href="browse_tools_by_user?operation=browse&id=%s">%s</a>' % ( trans.security.encode_id( tool.user.id ), tool.user.username )
+ return '<a href="browse_tools_by_user?operation=browse&id=%s&webapp=community">%s</a>' % ( trans.security.encode_id( tool.user.id ), tool.user.username )
# Grid definition
title = "Tools By User"
model_class = model.Tool
@@ -156,19 +161,24 @@
default_sort_key = "name"
columns = [
NameColumn( "Name",
- key="name",
+ # TODO: we cannot currently sort by columns since the grid may be filtered by tool ids
+ # and it is not clear if / how that will work. We need to be able to send to the grid helper
+ # the list of ids on which to filter when sorting on the column.
+ #key="name",
model_class=model.Tool,
link=( lambda item: dict( operation="View Tool", id=item.id, cntrller='tool', webapp="community" ) ),
- attach_popup=True,
- filterable="advanced" ),
+ attach_popup=True
+ #filterable="advanced"
+ ),
VersionColumn( "Version",
model_class=model.Tool,
- attach_popup=False,
- filterable="advanced" ),
+ attach_popup=False ),
DescriptionColumn( "Description",
- model_class=model.Tool,
- attach_popup=False,
- filterable="advanced" ),
+ #key="description",
+ model_class=model.Tool,
+ attach_popup=False
+ #filterable="advanced"
+ ),
CategoryColumn( "Categories",
model_class=model.Category,
attach_popup=False,
@@ -177,15 +187,20 @@
model_class=model.Event,
attach_popup=False ),
UserColumn( "Uploaded By",
- key="username",
+ #key="username",
model_class=model.User,
- attach_popup=False,
- filterable="advanced" ),
+ attach_popup=False
+ #filterable="advanced"
+ ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
- cols_to_filter=[ columns[0], columns[1] ],
+ #cols_to_filter=[ columns[0], columns[2], columns[5] ],
+ cols_to_filter=[],
key="free-text-search",
visible=False,
filterable="standard" ) )
@@ -199,30 +214,24 @@
grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ),
grids.GridColumnFilter( "All", args=dict( deleted='All' ) )
]
- default_filter = dict( name="All", deleted="False", username="All" )
+ default_filter = dict( name="All", deleted="False" )
num_rows_per_page = 50
preserve_state = False
use_paging = True
def build_initial_query( self, session ):
return session.query( self.model_class )
def apply_default_filter( self, trans, query, **kwd ):
- def filter_query( query, tool_id ):
- if str( tool_id ).lower() in [ '', 'none' ]:
- # Return an empty query since the current user cannot view any
- # tools (possibly due to state not being approved, etc).
- return query.filter( model.Tool.id == None )
- tool_id = util.listify( tool_id )
- query = query.filter( or_( *map( lambda id: self.model_class.id == id, tool_id ) ) )
- return query.filter( self.model_class.deleted==False )
- tool_id = kwd.get( 'tool_id', False )
- if not tool_id:
+ ids = kwd.get( 'ids', False )
+ if not ids:
# Display only approved tools
- tool_id = get_approved_tools( trans )
- if not tool_id:
- tool_id = 'None'
- return filter_query( query, tool_id )
+ ids = get_approved_tools( trans )
+ if not ids or str( ids ).lower() == 'none':
+ return query.filter( trans.model.Tool.id == None )
+ ids = util.listify( ids )
+ query = query.filter( or_( *map( lambda id: self.model_class.id == id, ids ) ) )
+ return query
-class CategoryListGrid( grids.Grid ):
+class ToolsByCategoryListGrid( grids.Grid ):
class NameColumn( grids.TextColumn ):
def get_value( self, trans, grid, category ):
return category.name
@@ -242,28 +251,36 @@
# Grid definition
webapp = "community"
- title = "Tool Categories"
+ title = "Tools by Category"
model_class = model.Category
template='/webapps/community/category/grid.mako'
default_sort_key = "name"
columns = [
NameColumn( "Name",
- key="name",
+ # TODO: we cannot currently sort by columns since the grid may be filtered by tool ids
+ # and it is not clear if / how that will work. We need to be able to send to the grid helper
+ # the list of ids on which to filter when sorting on the column.
+ #key="name",
model_class=model.Category,
link=( lambda item: dict( operation="Browse Category", id=item.id, webapp="community" ) ),
- attach_popup=False,
- filterable="advanced" ),
+ attach_popup=False
+ #filterable="advanced"
+ ),
DescriptionColumn( "Description",
- key="description",
- model_class=model.Category,
- attach_popup=False,
- filterable="advanced" ),
+ #key="description",
+ model_class=model.Category,
+ attach_popup=False
+ #filterable="advanced"
+ ),
ToolsColumn( "Tools",
model_class=model.Tool,
attach_popup=False,
filterable="advanced" ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
cols_to_filter=[ columns[0], columns[1] ],
@@ -280,14 +297,12 @@
use_paging = True
def build_initial_query( self, session ):
return session.query( self.model_class )
- def apply_default_filter( self, trans, query, **kwd ):
- return query.filter( self.model_class.deleted==False )
class ToolController( BaseController ):
tool_list_grid = ToolListGrid()
tools_by_user_list_grid = ToolsByUserListGrid()
- category_list_grid = CategoryListGrid()
+ tools_by_category_list_grid = ToolsByCategoryListGrid()
@web.expose
def index( self, trans, **kwd ):
@@ -312,7 +327,7 @@
cntrller='tool',
**kwd ) )
# Render the list view
- return self.category_list_grid( trans, **kwd )
+ return self.tools_by_category_list_grid( trans, **kwd )
@web.expose
def browse_category( self, trans, **kwd ):
return trans.response.send_redirect( web.url_for( controller='common',
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/webapps/community/controllers/upload.py
--- a/lib/galaxy/webapps/community/controllers/upload.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/webapps/community/controllers/upload.py Tue May 04 14:21:21 2010 -0400
@@ -60,28 +60,26 @@
obj = datatype.create_model_object( meta )
trans.sa_session.add( obj )
if isinstance( obj, trans.app.model.Tool ):
- existing = trans.sa_session.query( trans.app.model.Tool ).filter_by( tool_id = meta.id ).all()
+ existing = trans.sa_session.query( trans.app.model.Tool ).filter_by( tool_id = meta.id ).first()
if existing and replace_id is None:
raise UploadError( 'A tool with the same ID already exists. If you are trying to update this tool to a new version, please use the upload form on the "Edit Tool" page. Otherwise, please choose a new ID.' )
elif existing:
- replace_version = trans.sa_session.query( trans.app.model.Tool ).get( int( trans.app.security.decode_id( replace_id ) ) )
+ replace_version = trans.sa_session.query( trans.app.model.Tool ).get( trans.security.decode_id( replace_id ) )
if replace_version.newer_version:
# If the user has picked an old version, switch to the newest version
replace_version = get_versions( trans, replace_version )[0]
- if trans.user != replace_version.user:
- raise UploadError( 'You are not the owner of this tool and may not upload new versions of it.' )
if replace_version.tool_id != meta.id:
- raise UploadError( 'The new tool id (%s) does not match the old tool id (%s). Please check the tool XML file' % ( meta.id, replace_version.tool_id ) )
+ raise UploadError( 'The new tool id (%s) does not match the old tool id (%s). Check the tool XML file' % ( meta.id, replace_version.tool_id ) )
for old_version in get_versions( trans, replace_version ):
if old_version.version == meta.version:
- raise UploadError( 'The new version (%s) matches an old version. Please check your version in the tool XML file' % meta.version )
+ raise UploadError( 'The new version (%s) matches an old version. Check your version in the tool XML file' % meta.version )
if old_version.is_new():
- raise UploadError( 'There is an existing version of this tool which is unsubmitted. Please either <a href="%s">submit or delete it</a> before uploading a new version.' % url_for( controller='common',
- action='view_tool',
- cntrller='tool',
- id=trans.app.security.encode_id( old_version.id ) ) )
+ raise UploadError( 'There is an existing version of this tool which has not yet been submitted for approval, so either <a href="%s">submit or delete it</a> before uploading a new version.' % url_for( controller='common',
+ action='view_tool',
+ cntrller='tool',
+ id=trans.security.encode_id( old_version.id ) ) )
if old_version.is_waiting():
- raise UploadError( 'There is an existing version of this tool which is waiting for administrative approval. Please contact an administrator for help.' )
+ raise UploadError( 'There is an existing version of this tool which is waiting for administrative approval, so contact an administrator for help.' )
# Defer setting the id since the newer version id doesn't exist until the new Tool object is flushed
if category_ids:
for category_id in category_ids:
@@ -91,12 +89,15 @@
trans.sa_session.add( tca )
# Initialize the tool event
event = trans.app.model.Event( state=trans.app.model.Tool.states.NEW )
+ # Flush to get an event id
+ trans.sa_session.add( event )
+ trans.sa_session.flush()
tea = trans.app.model.ToolEventAssociation( obj, event )
- trans.sa_session.add_all( ( event, tea ) )
- trans.sa_session.flush()
+ trans.sa_session.add( tea )
if replace_version and replace_id:
replace_version.newer_version_id = obj.id
- trans.sa_session.flush()
+ trans.sa_session.add( replace_version )
+ trans.sa_session.flush()
try:
os.link( uploaded_file.name, obj.file_name )
except OSError:
@@ -117,10 +118,10 @@
old_version = None
for old_version in get_versions( trans, replace_version ):
if old_version.is_new():
- message = 'There is an existing version of this tool which is unsubmitted. Please either submit or delete it before uploading a new version.'
+ message = 'There is an existing version of this tool which has not been submitted for approval, so either submit or delete it before uploading a new version.'
break
if old_version.is_waiting():
- message = 'There is an existing version of this tool which is waiting for administrative approval. Please contact an administrator for help.'
+ message = 'There is an existing version of this tool which is waiting for administrative approval, so contact an administrator for help.'
break
else:
old_version = None
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/webapps/community/model/__init__.py
--- a/lib/galaxy/webapps/community/model/__init__.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/webapps/community/model/__init__.py Tue May 04 14:21:21 2010 -0400
@@ -94,7 +94,8 @@
APPROVED = 'approved',
REJECTED = 'rejected',
ARCHIVED = 'archived' )
- def __init__( self, guid=None, tool_id=None, name=None, description=None, user_description=None, category=None, version=None, user_id=None, external_filename=None ):
+ def __init__( self, guid=None, tool_id=None, name=None, description=None, user_description=None,
+ category=None, version=None, user_id=None, external_filename=None ):
self.guid = guid
self.tool_id = tool_id
self.name = name or "Unnamed tool"
@@ -103,6 +104,7 @@
self.version = version or "1.0.0"
self.user_id = user_id
self.external_filename = external_filename
+ self.deleted = False
self.__extension = None
def get_file_name( self ):
if not self.external_filename:
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/dataset/display_application/display.mako
--- a/templates/dataset/display_application/display.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/dataset/display_application/display.mako Tue May 04 14:21:21 2010 -0400
@@ -1,8 +1,8 @@
<%inherit file="/base.mako"/>
<%namespace file="/message.mako" import="render_msg" />
<%def name="title()">Display Application: ${display_link.link.display_application.name} ${display_link.link.name}</%def>
-%for message, message_type in msg:
- ${render_msg( message, message_type )}
+%for message, status in msg:
+ ${render_msg( message, status )}
%endfor
%if refresh:
<%def name="metas()"><meta http-equiv="refresh" content="10" /></%def>
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/display_common.mako
--- a/templates/display_common.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/display_common.mako Tue May 04 14:21:21 2010 -0400
@@ -129,10 +129,10 @@
</%def>
## Render message.
-<%def name="render_message( message, message_type )">
+<%def name="render_message( message, status )">
%if message:
<p>
- <div class="${message_type}message transient-message">${util.restore_text( message )}</div>
+ <div class="${status}message transient-message">${util.restore_text( message )}</div>
<div style="clear: both"></div>
</p>
%endif
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/grid_base.mako
--- a/templates/grid_base.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/grid_base.mako Tue May 04 14:21:21 2010 -0400
@@ -508,12 +508,10 @@
webapp = href_parms[index].split('=')[1];
}
}
-
// Do operation.
do_operation(webapp, operation, id);
return false;
}
-
}
// Navigate window to the URL defined by url_args. This method should be used to short-circuit grid AJAXing.
@@ -678,7 +676,7 @@
<tr>
<td width="75%">${self.render_grid_header( grid )}</td>
<td></td>
- <td width="25%" id="grid-message" valign="top">${render_message( message, message_type )}</td>
+ <td width="25%" id="grid-message" valign="top">${render_message( message, status )}</td>
</tr>
</table>
@@ -774,10 +772,6 @@
## Render grid table body contents.
<%def name="render_grid_table_body_contents(grid, show_item_checkboxes=False)">
- ## Include the webapp value in the form
- <td style="width: 1.5em;">
- <input type="hidden" name="webapp" value="${webapp}" />
- </td>
<% num_rows_rendered = 0 %>
%if query.count() == 0:
## No results.
@@ -801,12 +795,8 @@
%for column in grid.columns:
%if column.visible:
<%
- # Get filter params for generating filter links
- filter_params = {}
- for k, v in cur_filter_dict.items():
- filter_params['f-' + k] = v
# Link
- link = column.get_link( trans, grid, item, filter_params )
+ link = column.get_link( trans, grid, item )
if link:
href = url( **link )
else:
@@ -831,6 +821,7 @@
cls = "menubutton"
if column.attach_popup and href:
cls = "menubutton split"
+
%>
%if href:
<td><div id="${id}" class="${cls}" style="float: left;"><a class="label" href="${href}">${v}</a></div></td>
@@ -915,3 +906,4 @@
</tr>
%endif
</%def>
+
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/grid_base_async.mako
--- a/templates/grid_base_async.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/grid_base_async.mako Tue May 04 14:21:21 2010 -0400
@@ -13,4 +13,4 @@
*****
${num_pages}
*****
-${render_message( message, message_type )}
\ No newline at end of file
+${render_message( message, status )}
\ No newline at end of file
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/message.mako
--- a/templates/message.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/message.mako Tue May 04 14:21:21 2010 -0400
@@ -66,21 +66,21 @@
##
<%def name="center_panel()">
- ${render_large_message( message, message_type )}
+ ${render_large_message( message, status )}
</%def>
<%def name="body()">
- ${render_large_message( message, message_type )}
+ ${render_large_message( message, status )}
</%def>
## Render large message.
-<%def name="render_large_message( message, message_type )">
- <div class="${message_type}messagelarge" style="margin: 1em">${_(message)}</div>
+<%def name="render_large_message( message, status )">
+ <div class="${status}messagelarge" style="margin: 1em">${_(message)}</div>
</%def>
## Render a message
-<%def name="render_msg( msg, messagetype='done' )">
- <div class="${messagetype}message">${_(msg)}</div>
+<%def name="render_msg( msg, status='done' )">
+ <div class="${status}message">${_(msg)}</div>
<br/>
</%def>
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/page/select_items_grid_async.mako
--- a/templates/page/select_items_grid_async.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/page/select_items_grid_async.mako Tue May 04 14:21:21 2010 -0400
@@ -6,4 +6,4 @@
*****
${num_pages}
*****
-${render_message( message, message_type )}
\ No newline at end of file
+${render_message( message, status )}
\ No newline at end of file
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/webapps/community/admin/center.mako
--- a/templates/webapps/community/admin/center.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/webapps/community/admin/center.mako Tue May 04 14:21:21 2010 -0400
@@ -6,7 +6,36 @@
<p>The menu on the left provides the following features</p>
<ul>
- <li><strong>Security</strong> - see the <strong>Data Security and Data Libraries</strong> section below for details
+ <li>
+ <strong>Tools</strong>
+ <p/>
+ <ul>
+ <li>
+ <strong>Tools awaiting approval</strong>
+ </li>
+ <p/>
+ <li>
+ <strong>Browse by category</strong>
+ </li>
+ <p/>
+ <li>
+ <strong>Browse all tools</strong>
+ </li>
+ <p/>
+ </ul>
+ </li>
+ <li>
+ <strong>Categories</strong>
+ <p/>
+ <ul>
+ <li>
+ <strong>Manage categories</strong>
+ </li>
+ <p/>
+ </ul>
+ </li>
+ <li>
+ <strong>Security</strong>
<p/>
<ul>
<li>
@@ -29,13 +58,5 @@
</ul>
</li>
<p/>
- <li><strong>Tools</strong>
- <p/>
- <ul>
- <li>
- <strong>Manage tools</strong> - coming soon...
- </li>
- </ul>
- </li>
</ul>
<br/>
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/webapps/community/tool/edit_tool.mako
--- a/templates/webapps/community/tool/edit_tool.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/webapps/community/tool/edit_tool.mako Tue May 04 14:21:21 2010 -0400
@@ -51,16 +51,21 @@
${render_msg( message, status )}
%endif
-%if cntrller == 'admin' or ( tool.is_new() and trans.user == tool.user ):
+%if cntrller == 'admin' or trans.user == tool.user:
<form id="edit_tool" name="edit_tool" action="${h.url_for( controller='common', action='edit_tool' )}" method="post">
<div class="toolForm">
<div class="toolFormTitle">${tool.name}
- <a id="tool-${tool.id}-popup" class="popup-arrow" style="display: none;">▼</a>
- <div popupmenu="tool-${tool.id}-popup">
- <a class="action-button" href="${h.url_for( controller='common', action='view_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">View information</a>
- <a class="action-button" href="${h.url_for( controller='common', action='upload_new_tool_version', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Upload a new version</a>
- <a class="action-button" href="${h.url_for( controller='tool', action='download_tool', id=trans.app.security.encode_id( tool.id ) )}">Download tool</a>
- </div>
+ %if not tool.deleted:
+ <a id="tool-${tool.id}-popup" class="popup-arrow" style="display: none;">▼</a>
+ <div popupmenu="tool-${tool.id}-popup">
+ <a class="action-button" href="${h.url_for( controller='common', action='view_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">View information</a>
+ <a class="action-button" href="${h.url_for( controller='tool', action='download_tool', id=trans.app.security.encode_id( tool.id ) )}">Download tool</a>
+ <a class="action-button" href="${h.url_for( controller='common', action='delete_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Delete tool</a>
+ %if not tool.is_new() and not tool.is_waiting():
+ <a class="action-button" href="${h.url_for( controller='common', action='upload_new_tool_version', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Upload a new version</a>
+ %endif
+ </div>
+ %endif
</div>
<div class="toolFormBody">
<input type="hidden" name="id" value="${trans.app.security.encode_id( tool.id )}"/>
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/webapps/community/tool/view_tool.mako
--- a/templates/webapps/community/tool/view_tool.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/webapps/community/tool/view_tool.mako Tue May 04 14:21:21 2010 -0400
@@ -85,16 +85,21 @@
<div class="toolForm">
<div class="toolFormTitle">${tool.name}
- <a id="tool-${tool.id}-popup" class="popup-arrow" style="display: none;">▼</a>
- <div popupmenu="tool-${tool.id}-popup">
- %if cntrller=='admin' or can_edit:
- <a class="action-button" href="${h.url_for( controller='common', action='edit_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Edit information</a>
- %endif
- %if cntrller=='admin' or can_upload_new_version:
- <a class="action-button" href="${h.url_for( controller='common', action='upload_new_tool_version', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Upload a new version</a>
- %endif
- <a class="action-button" href="${h.url_for( controller='tool', action='download_tool', id=trans.app.security.encode_id( tool.id ) )}">Download tool</a>
- </div>
+ %if not tool.deleted:
+ <a id="tool-${tool.id}-popup" class="popup-arrow" style="display: none;">▼</a>
+ <div popupmenu="tool-${tool.id}-popup">
+ %if cntrller=='admin' or can_edit:
+ <a class="action-button" href="${h.url_for( controller='common', action='edit_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Edit information</a>
+ %endif
+ <a class="action-button" href="${h.url_for( controller='tool', action='download_tool', id=trans.app.security.encode_id( tool.id ) )}">Download tool</a>
+ %if cntrller=='admin' or trans.user==tool.user:
+ <a class="action-button" href="${h.url_for( controller='common', action='delete_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Delete tool</a>
+ %endif
+ %if cntrller=='admin' or can_upload_new_version:
+ <a class="action-button" href="${h.url_for( controller='common', action='upload_new_tool_version', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Upload a new version</a>
+ %endif
+ </div>
+ %endif
</div>
<div class="toolFormBody">
<div class="form-row">
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/68fc85a43bb8
changeset: 3740:68fc85a43bb8
user: Dannon Baker <dannon.baker(a)emory.edu>
date: Tue May 04 14:19:44 2010 -0400
description:
Secure=True by default for workflows.
diffstat:
lib/galaxy/workflow/modules.py | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diffs (26 lines):
diff -r 9057a05dc7d3 -r 68fc85a43bb8 lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py Tue May 04 13:45:57 2010 -0400
+++ b/lib/galaxy/workflow/modules.py Tue May 04 14:19:44 2010 -0400
@@ -96,7 +96,7 @@
module.state = dict( name="Input Dataset" )
return module
@classmethod
- def from_dict( Class, trans, d, secure=False ):
+ def from_dict( Class, trans, d, secure=True ):
module = Class( trans )
state = from_json_string( d["tool_state"] )
module.state = dict( name=state.get( "name", "Input Dataset" ) )
@@ -172,11 +172,11 @@
module.state = module.tool.new_state( trans, all_pages=True )
return module
@classmethod
- def from_dict( Class, trans, d, secure=False ):
+ def from_dict( Class, trans, d, secure=True ):
tool_id = d['tool_id']
module = Class( trans, tool_id )
module.state = DefaultToolState()
- module.state.decode( d["tool_state"], module.tool, module.trans.app, secure=False )
+ module.state.decode( d["tool_state"], module.tool, module.trans.app, secure=secure )
module.errors = d.get( "tool_errors", None )
return module
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/9057a05dc7d3
changeset: 3739:9057a05dc7d3
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Tue May 04 13:45:57 2010 -0400
description:
Update types for cuffcompare output files.
diffstat:
tools/ngs_rna/cuffcompare_wrapper.xml | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diffs (31 lines):
diff -r a3f32c37d423 -r 9057a05dc7d3 tools/ngs_rna/cuffcompare_wrapper.xml
--- a/tools/ngs_rna/cuffcompare_wrapper.xml Tue May 04 12:50:48 2010 -0400
+++ b/tools/ngs_rna/cuffcompare_wrapper.xml Tue May 04 13:45:57 2010 -0400
@@ -50,21 +50,21 @@
</inputs>
<outputs>
- <data format="tmap" name="input1_tmap" label="${tool.name} on ${on_string}: data ${input1.hid} tmap file"/>
- <data format="refmap" name="input1_refmap" label="${tool.name} on ${on_string}: data ${input1.hid} refmap file"/>
- <data format="tmap" name="input2_tmap" label="${tool.name} on ${on_string}: data ${second_gtf.input2.hid} tmap file">
+ <data format="tabular" name="input1_tmap" label="${tool.name} on ${on_string}: data ${input1.hid} tmap file"/>
+ <data format="tabular" name="input1_refmap" label="${tool.name} on ${on_string}: data ${input1.hid} refmap file"/>
+ <data format="tabular" name="input2_tmap" label="${tool.name} on ${on_string}: data ${second_gtf.input2.hid} tmap file">
<filter>second_gtf['use_second_gtf'] == "Yes"</filter>
</data>
- <data format="refmap" name="input2_refmap" label="${tool.name} on ${on_string}: data ${second_gtf.input2.hid} refmap file">
+ <data format="tabular" name="input2_refmap" label="${tool.name} on ${on_string}: data ${second_gtf.input2.hid} refmap file">
<filter>second_gtf['use_second_gtf'] == "Yes"</filter>
</data>
<data format="gtf" name="transcripts_combined" label="${tool.name} on ${on_string}: combined transcripts">
<filter>second_gtf['use_second_gtf'] == "Yes"</filter>
</data>
- <data format="tracking" name="transcripts_tracking" label="${tool.name} on ${on_string}: transcript tracking">
+ <data format="tabular" name="transcripts_tracking" label="${tool.name} on ${on_string}: transcript tracking">
<filter>second_gtf['use_second_gtf'] == "Yes"</filter>
</data>
- <data format="gtf" name="transcripts_accuracy" label="${tool.name} on ${on_string}: transcript accuracy"/>
+ <data format="txt" name="transcripts_accuracy" label="${tool.name} on ${on_string}: transcript accuracy"/>
</outputs>
<tests>
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/a3f32c37d423
changeset: 3738:a3f32c37d423
user: Kanwei Li <kanwei(a)gmail.com>
date: Tue May 04 12:50:48 2010 -0400
description:
trackster: add filled line display
diffstat:
static/scripts/trackster.js | 48 ++++++++++++++++++++++++++++++---------------
1 files changed, 32 insertions(+), 16 deletions(-)
diffs (128 lines):
diff -r 3b81af3f51ab -r a3f32c37d423 static/scripts/trackster.js
--- a/static/scripts/trackster.js Tue May 04 10:18:42 2010 -0400
+++ b/static/scripts/trackster.js Tue May 04 12:50:48 2010 -0400
@@ -352,7 +352,6 @@
TiledTrack.call( this );
this.height_px = 100;
- this.container_div.addClass( "line-track" );
this.dataset_id = dataset_id;
this.data_cache = new Cache(CACHED_DATA);
this.tile_cache = new Cache(CACHED_TILES_LINE);
@@ -369,6 +368,8 @@
track.vertical_range = undefined;
this.init_each({ stats: true, chrom: track.view.chrom, low: null, high: null,
dataset_id: track.dataset_id }, function(result) {
+
+ track.container_div.addClass( "line-track" );
data = result.data;
if ( isNaN(parseFloat(track.prefs.min_value)) || isNaN(parseFloat(track.prefs.max_value)) ) {
track.prefs.min_value = data.min;
@@ -387,10 +388,10 @@
var min_label = $("<div></div>").addClass('yaxislabel').attr("id", 'linetrack_' + track_id + '_minval').text(track.prefs.min_value);
var max_label = $("<div></div>").addClass('yaxislabel').attr("id", 'linetrack_' + track_id + '_maxval').text(track.prefs.max_value);
- max_label.css({ position: "relative", top: "25px" });
+ max_label.css({ position: "relative", top: "25px", left: "10px" });
max_label.prependTo(track.container_div);
- min_label.css({ position: "relative", top: track.height_px + 55 + "px" });
+ min_label.css({ position: "relative", top: track.height_px + 55 + "px", left: "10px" });
min_label.prependTo(track.container_div);
});
},
@@ -455,7 +456,8 @@
max_value = this.prefs.max_value,
vertical_range = this.vertical_range,
total_frequency = this.total_frequency,
- height_px = this.height_px;
+ height_px = this.height_px,
+ mode = this.prefs.mode;
ctx.beginPath();
@@ -466,16 +468,17 @@
var delta_x_px = 10;
}
+ var x_scaled, y;
+
for ( var i = 0; i < data.length; i++ ) {
- var x = data[i][0] - tile_low;
- var y = data[i][1];
+ x_scaled = (data[i][0] - tile_low) * w_scale;
+ y = data[i][1];
- if ( this.prefs.mode == "Intensity" ) {
+ if ( mode == "Intensity" ) {
// DRAW INTENSITY
if (y === null) {
continue;
}
- x = x * w_scale;
if (y <= min_value) {
y = min_value;
} else if (y >= max_value) {
@@ -483,16 +486,17 @@
}
y = 255 - Math.floor( (y - min_value) / vertical_range * 255 );
ctx.fillStyle = "rgb(" +y+ "," +y+ "," +y+ ")";
- ctx.fillRect(x, 0, delta_x_px, this.height_px);
+ ctx.fillRect(x_scaled, 0, delta_x_px, this.height_px);
}
else {
// Missing data causes us to stop drawing
if (y === null) {
+ if (in_path && mode === "Filled") {
+ ctx.lineTo(x_scaled, height_px);
+ }
in_path = false;
continue;
} else {
- // Translate
- x = x * w_scale;
// console.log(y, this.min_value, this.vertical_range, (y - this.min_value) / this.vertical_range * this.height_px);
if (y <= min_value) {
y = min_value;
@@ -501,16 +505,28 @@
}
y = Math.round( height_px - (y - min_value) / vertical_range * height_px );
// console.log(canvas.get(0).height, canvas.get(0).width);
- if ( in_path ) {
- ctx.lineTo( x, y );
+ if (in_path) {
+ ctx.lineTo(x_scaled, y);
} else {
- ctx.moveTo( x, y );
in_path = true;
+ if (mode === "Filled") {
+ ctx.moveTo(x_scaled, height_px);
+ ctx.lineTo(x_scaled, y);
+ } else {
+ ctx.moveTo(x_scaled, y);
+ }
}
}
}
}
- ctx.stroke();
+ if (mode === "Filled") {
+ if (in_path) {
+ ctx.lineTo(x_scaled, height_px);
+ }
+ ctx.fill();
+ } else {
+ ctx.stroke();
+ }
parent_element.append( canvas );
return canvas;
}, gen_options: function(track_id) {
@@ -527,7 +543,7 @@
max_input = $('<input></input>').attr("id", maxval).val(max_val),
mode_label = $('<label></label>').attr("for", mode).text("Display mode:"),
mode_val = (this.prefs.mode === undefined ? "Line" : this.prefs.mode),
- mode_input = $('<select id="' +mode+ '"><option value="Line" id="mode_Line">Line</option><option value="Intensity" id="mode_Intensity">Intensity</option></select>');
+ mode_input = $('<select id="' +mode+ '"><option value="Line" id="mode_Line">Line</option><option value="Filled" id="mode_Filled">Filled</option><option value="Intensity" id="mode_Intensity">Intensity</option></select>');
mode_input.children("#mode_"+mode_val).attr('selected', 'selected');
1
0
10 May '10
details: http://www.bx.psu.edu/hg/galaxy/rev/eec050533545
changeset: 3736:eec050533545
user: James Taylor <james(a)jamestaylor.org>
date: Mon May 03 17:35:54 2010 -0400
description:
Very basic support for exporting and importing workflows among instances
diffstat:
lib/galaxy/tools/__init__.py | 24 +++--
lib/galaxy/web/__init__.py | 2 +-
lib/galaxy/web/controllers/workflow.py | 153 ++++++++++++++++++++++++++++++++-
lib/galaxy/web/framework/__init__.py | 9 +
lib/galaxy/workflow/modules.py | 14 +-
templates/form.mako | 6 +-
6 files changed, 187 insertions(+), 21 deletions(-)
diffs (327 lines):
diff -r c75c0f9b0bf7 -r eec050533545 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py Mon May 03 16:32:35 2010 -0400
+++ b/lib/galaxy/tools/__init__.py Mon May 03 17:35:54 2010 -0400
@@ -203,7 +203,7 @@
def __init__( self ):
self.page = 0
self.inputs = None
- def encode( self, tool, app ):
+ def encode( self, tool, app, secure=True ):
"""
Convert the data to a string
"""
@@ -213,18 +213,22 @@
value["__page__"] = self.page
value = simplejson.dumps( value )
# Make it secure
- a = hmac_new( app.config.tool_secret, value )
- b = binascii.hexlify( value )
- return "%s:%s" % ( a, b )
- def decode( self, value, tool, app ):
+ if secure:
+ a = hmac_new( app.config.tool_secret, value )
+ b = binascii.hexlify( value )
+ return "%s:%s" % ( a, b )
+ else:
+ return value
+ def decode( self, value, tool, app, secure=True ):
"""
Restore the state from a string
"""
- # Extract and verify hash
- a, b = value.split( ":" )
- value = binascii.unhexlify( b )
- test = hmac_new( app.config.tool_secret, value )
- assert a == test
+ if secure:
+ # Extract and verify hash
+ a, b = value.split( ":" )
+ value = binascii.unhexlify( b )
+ test = hmac_new( app.config.tool_secret, value )
+ assert a == test
# Restore from string
values = json_fix( simplejson.loads( value ) )
self.page = values.pop( "__page__" )
diff -r c75c0f9b0bf7 -r eec050533545 lib/galaxy/web/__init__.py
--- a/lib/galaxy/web/__init__.py Mon May 03 16:32:35 2010 -0400
+++ b/lib/galaxy/web/__init__.py Mon May 03 17:35:54 2010 -0400
@@ -2,6 +2,6 @@
The Galaxy web application.
"""
-from framework import expose, json, require_login, require_admin, url_for, error, form, FormBuilder
+from framework import expose, json, json_pretty, require_login, require_admin, url_for, error, form, FormBuilder
from framework.base import httpexceptions
diff -r c75c0f9b0bf7 -r eec050533545 lib/galaxy/web/controllers/workflow.py
--- a/lib/galaxy/web/controllers/workflow.py Mon May 03 16:32:35 2010 -0400
+++ b/lib/galaxy/web/controllers/workflow.py Mon May 03 17:35:54 2010 -0400
@@ -18,6 +18,8 @@
from galaxy.model.mapping import desc
from galaxy.model.orm import *
+import urllib2
+
class StoredWorkflowListGrid( grids.Grid ):
class StepsColumn( grids.GridColumn ):
def get_value(self, trans, grid, workflow):
@@ -621,7 +623,6 @@
step_dict['position'] = step.position
# Add to return value
data['steps'][step.order_index] = step_dict
- print data['upgrade_messages']
return data
@web.json
@@ -660,7 +661,6 @@
workflow.has_errors = True
# Stick this in the step temporarily
step.temp_input_connections = step_dict['input_connections']
-
# Save step annotation.
annotation = step_dict[ 'annotation' ]
if annotation:
@@ -698,6 +698,155 @@
rval['name'] = workflow.name
return rval
+ @web.json_pretty
+ def export_workflow( self, trans, id ):
+ """
+ Get the latest Workflow for the StoredWorkflow identified by `id` and
+ encode it as a json string that can be imported back into Galaxy
+
+ This has slightly different information than the above. In particular,
+ it does not attempt to decode forms and build UIs, it just stores
+ the raw state.
+ """
+ user = trans.get_user()
+ id = trans.security.decode_id( id )
+ trans.workflow_building_mode = True
+ # Load encoded workflow from database
+ stored = trans.sa_session.query( model.StoredWorkflow ).get( id )
+ self.security_check( trans.get_user(), stored, False, True )
+ workflow = stored.latest_workflow
+ # Pack workflow data into a dictionary and return
+ data = {}
+ data['name'] = workflow.name
+ data['steps'] = {}
+ # For each step, rebuild the form and encode the state
+ for step in workflow.steps:
+ # Load from database representation
+ module = module_factory.from_workflow_step( trans, step )
+ # Get user annotation.
+ step_annotation = self.get_item_annotation_obj( trans, trans.user, step )
+ annotation_str = ""
+ if step_annotation:
+ annotation_str = step_annotation.annotation
+ # Pack attributes into plain dictionary
+ step_dict = {
+ 'id': step.order_index,
+ 'type': module.type,
+ 'tool_id': module.get_tool_id(),
+ 'name': module.get_name(),
+ 'tool_state': module.get_state( secure=False ),
+ 'tool_errors': module.get_errors(),
+ ## 'data_inputs': module.get_data_inputs(),
+ ## 'data_outputs': module.get_data_outputs(),
+ 'annotation' : annotation_str
+ }
+ # Connections
+ input_connections = step.input_connections
+ if step.type is None or step.type == 'tool':
+ # Determine full (prefixed) names of valid input datasets
+ data_input_names = {}
+ def callback( input, value, prefixed_name, prefixed_label ):
+ if isinstance( input, DataToolParameter ):
+ data_input_names[ prefixed_name ] = True
+ visit_input_values( module.tool.inputs, module.state.inputs, callback )
+ # Filter
+ # FIXME: this removes connection without displaying a message currently!
+ input_connections = [ conn for conn in input_connections if conn.input_name in data_input_names ]
+ # Encode input connections as dictionary
+ input_conn_dict = {}
+ for conn in input_connections:
+ input_conn_dict[ conn.input_name ] = \
+ dict( id=conn.output_step.order_index, output_name=conn.output_name )
+ step_dict['input_connections'] = input_conn_dict
+ # Position
+ step_dict['position'] = step.position
+ # Add to return value
+ data['steps'][step.order_index] = step_dict
+ return data
+
+ @web.expose
+ def import_workflow( self, trans, workflow_text=None, url=None ):
+ if workflow_text is None and url is None:
+ return form( url_for(), "Import Workflow", submit_text="Import" ) \
+ .add_text( "url", "URL to load workflow from", "" ) \
+ .add_input( "textarea", "Encoded workflow (as generated by export workflow)", "workflow_text", "" )
+ if url:
+ # Load workflow from external URL
+ # NOTE: blocks the web thread.
+ try:
+ workflow_data = urllib2.urlopen( url ).read()
+ except Exception, e:
+ return trans.show_error_message( "Failed to open URL %s<br><br>Message: %s" % ( url, str( e ) ) )
+ else:
+ workflow_data = workflow_text
+ # Convert incoming workflow data from json
+ try:
+ data = simplejson.loads( workflow_data )
+ except Exception, e:
+ return trans.show_error_message( "Data at '%s' does not appear to be a Galaxy workflow<br><br>Message: %s" % ( url, str( e ) ) )
+ # Put parameters in workflow mode
+ trans.workflow_building_mode = True
+ # Create new workflow from incoming data
+ workflow = model.Workflow()
+ # Just keep the last name (user can rename later)
+ workflow.name = data['name']
+ # Assume no errors until we find a step that has some
+ workflow.has_errors = False
+ # Create each step
+ steps = []
+ # The editor will provide ids for each step that we don't need to save,
+ # but do need to use to make connections
+ steps_by_external_id = {}
+ # First pass to build step objects and populate basic values
+ for key, step_dict in data['steps'].iteritems():
+ # Create the model class for the step
+ step = model.WorkflowStep()
+ steps.append( step )
+ steps_by_external_id[ step_dict['id' ] ] = step
+ # FIXME: Position should be handled inside module
+ step.position = step_dict['position']
+ module = module_factory.from_dict( trans, step_dict, secure=False )
+ module.save_to_step( step )
+ if step.tool_errors:
+ workflow.has_errors = True
+ # Stick this in the step temporarily
+ step.temp_input_connections = step_dict['input_connections']
+ # Save step annotation.
+ annotation = step_dict[ 'annotation' ]
+ if annotation:
+ annotation = sanitize_html( annotation, 'utf-8', 'text/html' )
+ self.add_item_annotation( trans, step, annotation )
+ # Second pass to deal with connections between steps
+ for step in steps:
+ # Input connections
+ for input_name, conn_dict in step.temp_input_connections.iteritems():
+ if conn_dict:
+ conn = model.WorkflowStepConnection()
+ conn.input_step = step
+ conn.input_name = input_name
+ conn.output_name = conn_dict['output_name']
+ conn.output_step = steps_by_external_id[ conn_dict['id'] ]
+ del step.temp_input_connections
+ # Order the steps if possible
+ attach_ordered_steps( workflow, steps )
+ # Connect up
+ stored = model.StoredWorkflow()
+ stored.name = workflow.name
+ workflow.stored_workflow = stored
+ stored.latest_workflow = workflow
+ stored.user = trans.user
+ # Persist
+ trans.sa_session.add( stored )
+ trans.sa_session.flush()
+ # Return something informative
+ errors = []
+ if workflow.has_errors:
+ return trans.show_warn_message( "Imported, but some steps in this workflow have validation errors" )
+ if workflow.has_cycles:
+ return trans.show_warn_message( "Imported, but this workflow contains cycles" )
+ else:
+ return trans.show_message( "Workflow '%s' imported" % workflow.name )
+
@web.json
def get_datatypes( self, trans ):
ext_to_class_name = dict()
diff -r c75c0f9b0bf7 -r eec050533545 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py Mon May 03 16:32:35 2010 -0400
+++ b/lib/galaxy/web/framework/__init__.py Mon May 03 17:35:54 2010 -0400
@@ -66,6 +66,15 @@
decorator.exposed = True
return decorator
+def json_pretty( func ):
+ def decorator( self, trans, *args, **kwargs ):
+ trans.response.set_content_type( "text/javascript" )
+ return simplejson.dumps( func( self, trans, *args, **kwargs ), indent=4, sort_keys=True )
+ if not hasattr(func, '_orig'):
+ decorator._orig = func
+ decorator.exposed = True
+ return decorator
+
def require_login( verb="perform this action", use_panels=False, webapp='galaxy' ):
def argcatcher( func ):
def decorator( self, trans, *args, **kwargs ):
diff -r c75c0f9b0bf7 -r eec050533545 lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py Mon May 03 16:32:35 2010 -0400
+++ b/lib/galaxy/workflow/modules.py Mon May 03 17:35:54 2010 -0400
@@ -96,7 +96,7 @@
module.state = dict( name="Input Dataset" )
return module
@classmethod
- def from_dict( Class, trans, d ):
+ def from_dict( Class, trans, d, secure=False ):
module = Class( trans )
state = from_json_string( d["tool_state"] )
module.state = dict( name=state.get( "name", "Input Dataset" ) )
@@ -172,11 +172,11 @@
module.state = module.tool.new_state( trans, all_pages=True )
return module
@classmethod
- def from_dict( Class, trans, d ):
+ def from_dict( Class, trans, d, secure=False ):
tool_id = d['tool_id']
module = Class( trans, tool_id )
module.state = DefaultToolState()
- module.state.decode( d["tool_state"], module.tool, module.trans.app )
+ module.state.decode( d["tool_state"], module.tool, module.trans.app, secure=False )
module.errors = d.get( "tool_errors", None )
return module
@@ -199,8 +199,8 @@
return self.tool.name
def get_tool_id( self ):
return self.tool_id
- def get_state( self ):
- return self.state.encode( self.tool, self.trans.app )
+ def get_state( self, secure=True ):
+ return self.state.encode( self.tool, self.trans.app, secure=secure )
def get_errors( self ):
return self.errors
def get_tooltip( self ):
@@ -278,13 +278,13 @@
"""
assert type in self.module_types
return self.module_types[type].new( trans, tool_id )
- def from_dict( self, trans, d ):
+ def from_dict( self, trans, d, **kwargs ):
"""
Return module initialized from the data in dictionary `d`.
"""
type = d['type']
assert type in self.module_types
- return self.module_types[type].from_dict( trans, d )
+ return self.module_types[type].from_dict( trans, d, **kwargs )
def from_workflow_step( self, trans, step ):
"""
Return module initializd from the WorkflowStep object `step`.
diff -r c75c0f9b0bf7 -r eec050533545 templates/form.mako
--- a/templates/form.mako Mon May 03 16:32:35 2010 -0400
+++ b/templates/form.mako Mon May 03 17:35:54 2010 -0400
@@ -60,7 +60,11 @@
</label>
%endif
<div class="form-row-input">
- <input type="${input.type}" name="${input.name}" value="${input.value}" size="40">
+ %if input.type == 'textarea':
+ <textarea name="${input.name}" cols="40">${input.value}</textarea>
+ %else:
+ <input type="${input.type}" name="${input.name}" value="${input.value}" size="40">
+ %endif
</div>
%if input.error:
<div class="form-row-error-message">${input.error}</div>
1
0
10 May '10
details: http://www.bx.psu.edu/hg/galaxy/rev/3b81af3f51ab
changeset: 3737:3b81af3f51ab
user: Nate Coraor <nate(a)bx.psu.edu>
date: Tue May 04 10:18:42 2010 -0400
description:
Add a tip to the upload tool about using url paste for big files
diffstat:
tools/data_source/upload.xml | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diffs (12 lines):
diff -r eec050533545 -r 3b81af3f51ab tools/data_source/upload.xml
--- a/tools/data_source/upload.xml Mon May 03 17:35:54 2010 -0400
+++ b/tools/data_source/upload.xml Tue May 04 10:18:42 2010 -0400
@@ -25,7 +25,7 @@
</param>
<param name="async_datasets" type="hidden" value="None"/>
<upload_dataset name="files" title="Specify Files for Dataset" file_type_name="file_type" metadata_ref="files_metadata">
- <param name="file_data" type="file" size="30" label="File" ajax-upload="true">
+ <param name="file_data" type="file" size="30" label="File" ajax-upload="true" help="TIP: For NGS and other large files (>~2GB), uploading via HTTP/FTP URL (below) is the most reliable method.">
<validator type="expression" message="You will need to reselect the file you specified (%s)." substitute_value_in_message="True">not ( ( isinstance( value, unicode ) or isinstance( value, str ) ) and value != "" )</validator> <!-- use validator to post message to user about needing to reselect the file, since most browsers won't accept the value attribute for file inputs -->
</param>
<param name="url_paste" type="text" area="true" size="5x35" label="URL/Text" help="Here you may specify a list of URLs (one per line) or paste the contents of a file."/>
1
0
10 May '10
details: http://www.bx.psu.edu/hg/galaxy/rev/5ebac527fa31
changeset: 3734:5ebac527fa31
user: Nate Coraor <nate(a)bx.psu.edu>
date: Mon May 03 15:33:34 2010 -0400
description:
Community: add help for tool-related operations
diffstat:
lib/galaxy/webapps/community/controllers/tool.py | 6 +
lib/galaxy/webapps/community/security/__init__.py | 2 +-
templates/webapps/community/base_panels.mako | 1 +
templates/webapps/community/tool/help.mako | 125 ++++++++++++++++++++++
templates/webapps/community/tool/view_tool.mako | 8 +-
templates/webapps/community/upload/upload.mako | 8 +-
6 files changed, 139 insertions(+), 11 deletions(-)
diffs (205 lines):
diff -r 8bdbd5fc8721 -r 5ebac527fa31 lib/galaxy/webapps/community/controllers/tool.py
--- a/lib/galaxy/webapps/community/controllers/tool.py Mon May 03 14:03:01 2010 -0400
+++ b/lib/galaxy/webapps/community/controllers/tool.py Mon May 03 15:33:34 2010 -0400
@@ -402,3 +402,9 @@
tool_file = tarfile.open( tool.file_name ).extractfile( tool_file_name )
trans.response.set_content_type( 'text/plain' )
return tool_file
+ @web.expose
+ def help( self, trans, **kwd ):
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ return trans.fill_template( '/webapps/community/tool/help.mako', message=message, status=status, **kwd )
diff -r 8bdbd5fc8721 -r 5ebac527fa31 lib/galaxy/webapps/community/security/__init__.py
--- a/lib/galaxy/webapps/community/security/__init__.py Mon May 03 14:03:01 2010 -0400
+++ b/lib/galaxy/webapps/community/security/__init__.py Mon May 03 15:33:34 2010 -0400
@@ -170,7 +170,7 @@
def can_upload_new_version( self, user, item, versions ):
state_ok = True
for version in versions:
- if version.is_new() or version.is_approved():
+ if version.is_new() or version.is_waiting():
state_ok = False
return user and user==item.user and state_ok
diff -r 8bdbd5fc8721 -r 5ebac527fa31 templates/webapps/community/base_panels.mako
--- a/templates/webapps/community/base_panels.mako Mon May 03 14:03:01 2010 -0400
+++ b/templates/webapps/community/base_panels.mako Mon May 03 15:33:34 2010 -0400
@@ -33,6 +33,7 @@
<a>Help</a>
<div class="submenu">
<ul>
+ <li><a target="galaxy_main" href="${h.url_for( controller='tool', action='help' )}">How to upload, download and install tools</a></li>
<li><a href="${app.config.get( "bugs_email", "mailto:galaxy-bugs@bx.psu.edu" )}">Email comments, bug reports, or suggestions</a></li>
<li><a target="_blank" href="${app.config.get( "wiki_url", "http://bitbucket.org/galaxy/galaxy-central/wiki" )}">Galaxy Wiki</a></li>
<li><a target="_blank" href="${app.config.get( "screencasts_url", "http://galaxycast.org" )}">Video tutorials (screencasts)</a></li>
diff -r 8bdbd5fc8721 -r 5ebac527fa31 templates/webapps/community/tool/help.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/webapps/community/tool/help.mako Mon May 03 15:33:34 2010 -0400
@@ -0,0 +1,125 @@
+<%namespace file="/message.mako" import="render_msg" />
+
+<%!
+ def inherit(context):
+ if context.get('use_panels'):
+ return '/webapps/community/base_panels.mako'
+ else:
+ return '/base.mako'
+%>
+<%inherit file="${inherit(context)}"/>
+
+<%def name="title()">Tool Help</%def>
+
+<h2>Tool Help</h2>
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<h3>Uploading Tools</h3>
+
+<p><strong>Tool File Format</strong></p>
+<p>
+
+ A tool file is a tar-format (bzipped or gzipped tar are valid) archive
+ containing all the files necessary to load the tool in Galaxy. At the very
+ least, it must contain a
+ <a href="http://bitbucket.org/galaxy/galaxy-central/wiki/ToolConfigSyntax" target="_blank">Tool XML File</a>,
+ and will probably also include a tool script. If any steps are necessary
+ to install your tool beyond the basic instructions below, please include a
+ README file which details these steps. If the tool (or parts of it) are
+ written in C, the source code can be included (or put links to the source
+ in the README). Please do not include precompiled binaries without source,
+ since Galaxy is run on a wide variety of platforms. Also, if you are only
+ wrapping or providing a Galaxy config for a tool that is not your own,
+ please be sure the license allows for redistribution before including any
+ part of that tool in the tar archive!
+</p>
+<p>
+ There are no requirements about the directory structure inside the tar
+ archive, but for ease of use, it's generally a good idea to put everything
+ inside of a subdirectory, instead of directly at the top level.
+</p>
+
+<p><strong>Tool File Example</strong></p>
+<p>
+ To package up the LASTZ tool's config file, Galaxy wrapper, and the C source:
+ <pre>
+ user@host:~% tar jcvf ~/Desktop/galaxy_lastz_tool.tar.bz2 lastz
+ lastz/
+ lastz/README
+ lastz/lastz_wrapper.py
+ lastz/lastz_wrapper.xml
+ lastz/lastz-distrib-1.02.00/
+ lastz/lastz-distrib-1.02.00/src/
+ lastz/lastz-distrib-1.02.00/src/Makefile
+ lastz/lastz-distrib-1.02.00/src/version.mak
+ lastz/lastz-distrib-1.02.00/src/lastz.c
+ lastz/lastz-distrib-1.02.00/src/lastz.h
+ ...
+ </pre>
+ <code>~/Desktop/galaxy_lastz_tool.tar.bz2</code> is now ready to be uploaded.
+</p>
+
+<p><strong>Editing Information, Categories, and Submitting For Approval</strong></p>
+
+<p>
+ Simply uploading a tool to the Community will not allow other users to find
+ and download your tool. It will need to be approved by an administrator
+ before it appears in the tool list.
+</p>
+<p>
+ After the tool has successfully uploaded, you will be redirected to the
+ Edit Tool page. Please provide a detailed description of what the tool
+ does - this will be used by administrators to understand the tool before
+ approving it for display on the site. Once approved, this information will
+ be displayed to users who view your tool. In addition, the site
+ administrators will have configured a number of categories with which you
+ can associate your tool to make it easily findable by users looking to
+ solve specific problems. Please associate as many categories as are
+ relevant to your tool. You may change the description and associated
+ categories as often as you'd like until you click the "<strong>Submit for
+ approval</strong>" button. Once submitted, the tool will be approved or
+ rejected by an administrator. Once approved, it will be visible to
+ everyone. At that point, the description and associated categories can
+ only be changed by an administrator.
+</p>
+<p>
+ Once the tool has been approved or rejected, you may upload a new version
+ by browsing to the tool's "View Tool" page, clicking the context menu to
+ the right of the tool's name, and selecting "Upload a new version."
+</p>
+
+<hr/>
+
+<h3>Downloading and Installing Tools</h3>
+
+<p>
+ A tool's download link will send you the tool tar archive. Once
+ downloaded, unpack the tool on your local Galaxy instance's server:
+ <pre>
+ user@host:~% tar xvf galaxy_tool.tar
+ ...
+ user@host:~% tar zxvf galaxy_tool.tar.gz
+ ...
+ user@host:~% tar jxvf galaxy_tool.tar.bz2
+ ...
+ </pre>
+ If the tar archive includes a README file, consult it for installation
+ instructions. If not, follow these basic steps:
+ <ol>
+ <li>Create a directory under <code>galaxy_dist/tools/</code> to house downloaded tool(s).</li>
+ <li>In the new directory, place the XML and any script file(s) which were contained in the tar archive.</li>
+ <li>If the tool includes binaries, you'll need to copy them to a directory on your <code>$PATH</code>. If the tool depends on C binaries but does not come with them (only source), you'll need to compile the source first.</li>
+ <li>Add the tool to <code>galaxy_dist/tool_conf.xml</code>.</li>
+ <li>Restart the Galaxy server process.</li>
+ </ol>
+</p>
+
+<p>
+ We plan to implement a more direct method to install tools via the Galaxy
+ administrator user interface instead of placing files on the filesystem and
+ managing the <code>tool_conf.xml</code> file by hand. In the meantime,
+ this is the process.
+</p>
diff -r 8bdbd5fc8721 -r 5ebac527fa31 templates/webapps/community/tool/view_tool.mako
--- a/templates/webapps/community/tool/view_tool.mako Mon May 03 14:03:01 2010 -0400
+++ b/templates/webapps/community/tool/view_tool.mako Mon May 03 15:33:34 2010 -0400
@@ -125,9 +125,11 @@
<div class="form-row">
<label>Categories:</label>
%if categories:
- %for category in categories:
- ${category.name}
- %endfor
+ <ul>
+ %for category in categories:
+ <li>${category.name}</li>
+ %endfor
+ </ul>
%else:
none set
%endif
diff -r 8bdbd5fc8721 -r 5ebac527fa31 templates/webapps/community/upload/upload.mako
--- a/templates/webapps/community/upload/upload.mako Mon May 03 14:03:01 2010 -0400
+++ b/templates/webapps/community/upload/upload.mako Mon May 03 15:33:34 2010 -0400
@@ -39,7 +39,7 @@
</select>
</div>
<div class="toolParamHelp" style="clear: both;">
- Need help creating a tool file? See help below.
+ Need help creating a tool file? See the <a href="${h.url_for( controller='tool', action='help' )}">Tool Help</a> page.
</div>
<div style="clear: both"></div>
</div>
@@ -77,9 +77,3 @@
</form>
</div>
</div>
-<div class="toolHelp">
- <div class="toolHelpBody">
- <p><strong>Creating tool files</strong></p>
- <p>Help coming...</p>
- </div>
-</div>
1
0