galaxy-dev
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
May 2009
- 9 participants
- 41 discussions
06 May '09
details: http://www.bx.psu.edu/hg/galaxy/rev/2e2b80fcbd47
changeset: 2401:2e2b80fcbd47
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Tue May 05 13:48:01 2009 -0400
description:
Fixes for deleting library items on the admin side.
- Purged library items will not be displayed
- Deleted library items can only be viewed or undeleted
- Differentiate between displaying deleted libraries and displaying deleted items within an undeleted library
8 file(s) affected in this change:
lib/galaxy/web/controllers/admin.py
lib/galaxy/web/controllers/library.py
templates/admin/dataset_security/group_create.mako
templates/admin/library/browse_libraries.mako
templates/admin/library/browse_library.mako
templates/admin/library/common.mako
templates/admin/library/ldda_info.mako
templates/library/ldda_info.mako
diffs (551 lines):
diff -r 8da91a231cdf -r 2e2b80fcbd47 lib/galaxy/web/controllers/admin.py
--- a/lib/galaxy/web/controllers/admin.py Tue May 05 13:03:23 2009 -0400
+++ b/lib/galaxy/web/controllers/admin.py Tue May 05 13:48:01 2009 -0400
@@ -678,6 +678,7 @@
libraries=trans.app.model.Library.filter( trans.app.model.Library.table.c.deleted==False ) \
.order_by( trans.app.model.Library.name ).all(),
deleted=False,
+ show_deleted=False,
msg=msg,
messagetype=messagetype )
@web.expose
@@ -687,6 +688,8 @@
msg = util.restore_text( params.get( 'msg', '' ) )
messagetype = params.get( 'messagetype', 'done' )
id = params.get( 'id', None )
+ deleted = util.string_as_bool( params.get( 'deleted', False ) )
+ show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
if not id:
msg = "You must specify a library id."
return trans.response.send_redirect( web.url_for( controller='admin',
@@ -701,9 +704,9 @@
msg=util.sanitize_text( msg ),
messagetype='error' ) )
created_ldda_ids = params.get( 'created_ldda_ids', '' )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
return trans.fill_template( '/admin/library/browse_library.mako',
library=trans.app.model.Library.get( id ),
+ deleted=deleted,
created_ldda_ids=created_ldda_ids,
msg=msg,
messagetype=messagetype,
@@ -842,7 +845,7 @@
deleted=True,
msg=msg,
messagetype=messagetype,
- show_deleted = True )
+ show_deleted=True )
@web.expose
@web.require_admin
def undelete_library( self, trans, **kwd ):
@@ -1088,7 +1091,9 @@
def library_dataset_dataset_association( self, trans, library_id, folder_id, id=None, **kwd ):
params = util.Params( kwd )
msg = util.restore_text( params.get( 'msg', '' ) )
- messagetype = params.get( 'messagetype', 'done' )
+ messagetype = params.get( 'messagetype', 'done' )
+ deleted = util.string_as_bool( params.get( 'deleted', False ) )
+ show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
dbkey = params.get( 'dbkey', None )
if isinstance( dbkey, list ):
last_used_build = dbkey[0]
@@ -1250,6 +1255,8 @@
return trans.fill_template( '/admin/library/ldda_info.mako',
ldda=ldda,
library_id=library_id,
+ deleted=deleted,
+ show_deleted=show_deleted,
msg=msg,
messagetype=messagetype )
elif action == 'edit_info':
@@ -1322,8 +1329,6 @@
msg=msg,
messagetype=messagetype )
elif params.get( 'delete', False ):
- # TODO: need to revamp the way we remove datasets from disk.
- # The user selected the "Remove this dataset from the library" pop-up menu option
ldda.deleted = True
ldda.flush()
msg = 'Dataset %s has been removed from this library' % ldda.name
@@ -1955,69 +1960,56 @@
id=library_id,
msg=util.sanitize_text( msg ),
messagetype=messagetype ) )
-
@web.expose
@web.require_admin
- def delete_library_item( self, trans, library_id = None, library_item_id = None, library_item_type = None ):
- #this action will handle deleting all types of library items in library browsing mode
- library_item_types = { 'library': trans.app.model.Library, 'folder': trans.app.model.LibraryFolder, 'dataset': trans.app.model.LibraryDataset, }
+ def delete_library_item( self, trans, library_id, library_item_id, library_item_type ):
+ # This action will handle deleting all types of library items. State is saved for libraries and
+ # folders ( i.e., if undeleted, the state of contents of the library or folder will remain, so previously
+ # deleted / purged contents will have the same state ). When a library or folder has been deleted for
+ # the amount of time defined in the cleanup_datasets.py script, the library or folder and all of its
+ # contents will be purged. The association between this method and the cleanup_datasets.py script
+ # enables clean maintenance of libraries and library dataset disk files. This is also why the following
+ # 3 objects, and not any of the associations ( the cleanup_datasets.py scipot handles everything else ).
+ library_item_types = { 'library': trans.app.model.Library,
+ 'folder': trans.app.model.LibraryFolder,
+ 'library_dataset': trans.app.model.LibraryDataset }
if library_item_type not in library_item_types:
- raise ValueError( 'Bad library_item_type specified: %s' % library_item_types )
- if library_item_id is None:
- raise ValueError( 'library_item_id not specified' )
- library_item = library_item_types[ library_item_type ].get( int( library_item_id ) )
- library_item.deleted = True
- library_item.flush()
- #need to str because unicode isn't accepted...
- msg = str( "%s '%s' has been marked deleted" % ( library_item_type, library_item.name ) )
- messagetype = str( "done" )
- if library_item_type == 'library' or library_id is None:
- return self.browse_libraries( trans, msg = msg, messagetype = messagetype )
+ msg = 'Bad library_item_type specified: %s' % str( library_item_type )
+ messagetype = 'error'
else:
- return self.browse_library( trans, id = library_id , msg = msg, messagetype = messagetype )
-
+ library_item = library_item_types[ library_item_type ].get( int( library_item_id ) )
+ library_item.deleted = True
+ library_item.flush()
+ msg = util.sanitize_text( "%s '%s' has been marked deleted" % ( library_item_type, library_item.name ) )
+ messagetype = 'done'
+ if library_item_type == 'library':
+ return self.browse_libraries( trans, msg=msg, messagetype=messagetype )
+ else:
+ return self.browse_library( trans, id=library_id , msg=msg, messagetype=messagetype )
@web.expose
@web.require_admin
- def undelete_library_item( self, trans, library_id = None, library_item_id = None, library_item_type = None ):
- #this action will handle deleting all types of library items in library browsing mode
- library_item_types = { 'library': trans.app.model.Library, 'folder': trans.app.model.LibraryFolder, 'dataset': trans.app.model.LibraryDataset, }
+ def undelete_library_item( self, trans, library_id, library_item_id, library_item_type ):
+ # This action will handle undeleting all types of library items
+ library_item_types = { 'library': trans.app.model.Library,
+ 'folder': trans.app.model.LibraryFolder,
+ 'library_dataset': trans.app.model.LibraryDataset }
if library_item_type not in library_item_types:
- raise ValueError( 'Bad library_item_type specified: %s' % library_item_types )
- if library_item_id is None:
- raise ValueError( 'library_item_id not specified' )
- library_item = library_item_types[ library_item_type ].get( int( library_item_id ) )
- if library_item.purged:
- raise ValueError( '%s %s cannot be undeleted' % ( library_item_type, library_item.name ) )
- library_item.deleted = False
- library_item.flush()
- msg = str( "%s '%s' has been undeleted" % ( library_item_type, library_item.name ) )
- messagetype = str( "done" )
- if library_item_type == 'library' or library_id is None:
- return self.browse_libraries( trans, msg = msg, messagetype = messagetype )
+ msg = 'Bad library_item_type specified: %s' % str( library_item_type )
+ messagetype = 'error'
else:
- return self.browse_library( trans, id = library_id , msg = msg, messagetype = messagetype )
-
-
-
- #(a)web.expose
- #(a)web.require_admin
- #def delete_dataset( self, trans, id=None, **kwd):
- # if id:
- # # id is a LibraryDatasetDatasetAssociation.id
- # ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( id )
- # ldda.deleted = True
- # ldda.flush()
- # msg = "Dataset %s was deleted from library folder %s" % ( ldda.name, ldda.folder.name )
- # trans.response.send_redirect( web.url_for( action='folder',
- # id=str( ldda.folder.id ),
- # msg=util.sanitize_text( msg ),
- # messagetype='done' ) )
- # msg = "You did not specify a dataset to delete."
- # return trans.response.send_redirect( web.url_for( action='folder',
- # id=str( ldda.folder.id ),
- # msg=util.sanitize_text( msg ),
- # messagetype='error' ) )
-
+ library_item = library_item_types[ library_item_type ].get( int( library_item_id ) )
+ if library_item.purged:
+ msg = '%s %s has been purged, so it cannot be undeleted' % ( library_item_type, library_item.name )
+ messagetype = 'error'
+ else:
+ library_item.deleted = False
+ library_item.flush()
+ msg = util.sanitize_text( "%s '%s' has been marked undeleted" % ( library_item_type, library_item.name ) )
+ messagetype = 'done'
+ if library_item_type == 'library':
+ return self.browse_libraries( trans, msg=msg, messagetype=messagetype )
+ else:
+ return self.browse_library( trans, id=library_id , msg=msg, messagetype=messagetype )
@web.expose
@web.require_admin
def memdump( self, trans, ids = 'None', sorts = 'None', pages = 'None', new_id = None, new_sort = None, **kwd ):
diff -r 8da91a231cdf -r 2e2b80fcbd47 lib/galaxy/web/controllers/library.py
--- a/lib/galaxy/web/controllers/library.py Tue May 05 13:03:23 2009 -0400
+++ b/lib/galaxy/web/controllers/library.py Tue May 05 13:48:01 2009 -0400
@@ -587,8 +587,6 @@
msg=msg,
messagetype=messagetype )
elif params.get( 'delete', False ):
- # TODO: need to revamp the way we remove datasets from disk.
- # The user selected the "Remove this dataset from the library" pop-up menu option
if trans.app.security_agent.allow_action( trans.user,
trans.app.security_agent.permitted_actions.LIBRARY_MODIFY,
library_item=folder ):
diff -r 8da91a231cdf -r 2e2b80fcbd47 templates/admin/dataset_security/group_create.mako
--- a/templates/admin/dataset_security/group_create.mako Tue May 05 13:03:23 2009 -0400
+++ b/templates/admin/dataset_security/group_create.mako Tue May 05 13:48:01 2009 -0400
@@ -57,24 +57,24 @@
</div>
<div class="form-row">
<div style="float: left; margin-right: 10px;">
- <label>Groups associated with new role</label>
+ <label>Roles associated with new group</label>
${render_select( "in_roles", in_roles )}<br/>
<input type="submit" id="roles_remove_button" value=">>"/>
</div>
<div>
- <label>Groups not associated with new role</label>
+ <label>Roles not associated with new group</label>
${render_select( "out_roles", out_roles )}<br/>
<input type="submit" id="roles_add_button" value="<<"/>
</div>
</div>
<div class="form-row">
<div style="float: left; margin-right: 10px;">
- <label>Users associated with new role</label>
+ <label>Users associated with new group</label>
${render_select( "in_users", in_users )}<br/>
<input type="submit" id="users_remove_button" value=">>"/>
</div>
<div>
- <label>Users not associated with new role</label>
+ <label>Users not associated with new group</label>
${render_select( "out_users", out_users )}<br/>
<input type="submit" id="users_add_button" value="<<"/>
</div>
diff -r 8da91a231cdf -r 2e2b80fcbd47 templates/admin/library/browse_libraries.mako
--- a/templates/admin/library/browse_libraries.mako Tue May 05 13:03:23 2009 -0400
+++ b/templates/admin/library/browse_libraries.mako Tue May 05 13:48:01 2009 -0400
@@ -42,7 +42,7 @@
<tbody>
%for library in libraries:
<tr class="libraryRow libraryOrFolderRow" id="libraryRow">
- <td><a href="${h.url_for( controller='admin', action='browse_library', id=library.id )}">${library.name}</a></td>
+ <td><a href="${h.url_for( controller='admin', action='browse_library', id=library.id, deleted=deleted, show_deleted=show_deleted )}">${library.name}</a></td>
<td><i>${library.description}</i></td>
</tr>
%endfor
diff -r 8da91a231cdf -r 2e2b80fcbd47 templates/admin/library/browse_library.mako
--- a/templates/admin/library/browse_library.mako Tue May 05 13:03:23 2009 -0400
+++ b/templates/admin/library/browse_library.mako Tue May 05 13:48:01 2009 -0400
@@ -72,20 +72,20 @@
}
</script>
-<%def name="render_folder( parent, parent_pad, deleted, created_ldda_ids, library_id )">
+<%def name="render_folder( folder, folder_pad, deleted, show_deleted, created_ldda_ids, library_id )">
<%
- root_folder = not parent.parent
+ root_folder = not folder.parent
if root_folder:
- pad = parent_pad
+ pad = folder_pad
else:
- pad = parent_pad + 20
- if parent_pad == 0:
+ pad = folder_pad + 20
+ if folder_pad == 0:
expander = "/static/images/silk/resultset_bottom.png"
- folder = "/static/images/silk/folder_page.png"
+ folder_img = "/static/images/silk/folder_page.png"
subfolder = False
else:
expander = "/static/images/silk/resultset_next.png"
- folder = "/static/images/silk/folder.png"
+ folder_img = "/static/images/silk/folder.png"
subfolder = True
created_ldda_id_list = util.listify( created_ldda_ids )
if created_ldda_id_list:
@@ -93,35 +93,37 @@
%>
%if not root_folder:
<li class="folderRow libraryOrFolderRow" style="padding-left: ${pad}px;">
- <div class="rowTitle libraryItemDeleted-${parent.deleted}">
- <img src="${h.url_for( expander )}" class="expanderIcon"/><img src="${h.url_for( folder )}" class="rowIcon"/>
- ${parent.name}
- %if parent.description:
- <i>- ${parent.description}</i>
- %endif
- <a id="folder-${parent.id}-popup" class="popup-arrow" style="display: none;">▼</a>
- </div>
- %if not parent.deleted:
+ %if not folder.deleted or show_deleted:
+ <div class="rowTitle libraryItemDeleted-${deleted}">
+ <img src="${h.url_for( expander )}" class="expanderIcon"/><img src="${h.url_for( folder_img )}" class="rowIcon"/>
+ ${folder.name}
+ %if folder.description:
+ <i>- ${folder.description}</i>
+ %endif
+ <a id="folder-${folder.id}-popup" class="popup-arrow" style="display: none;">▼</a>
+ </div>
+ %endif
+ %if not folder.deleted:
<%
library_item_ids = {}
- library_item_ids[ 'folder' ] = parent.id
+ library_item_ids[ 'folder' ] = folder.id
%>
- <div popupmenu="folder-${parent.id}-popup">
- <a class="action-button" href="${h.url_for( controller='admin', action='library_dataset_dataset_association', library_id=library_id, folder_id=parent.id )}">Add datasets to this folder</a>
- <a class="action-button" href="${h.url_for( controller='admin', action='folder', new=True, id=parent.id, library_id=library_id )}">Create a new sub-folder in this folder</a>
- <a class="action-button" href="${h.url_for( controller='admin', action='folder', information=True, id=parent.id, library_id=library_id )}">Edit this folder's information</a>
- %if parent.library_folder_info_template_associations:
- <% template = parent.get_library_item_info_templates( template_list=[], restrict=True )[0] %>
- <a class="action-button" href="${h.url_for( controller='admin', action='info_template', library_id=library.id, id=template.id, edit_template=True )}">Edit this folder's information template</a>
+ <div popupmenu="folder-${folder.id}-popup">
+ <a class="action-button" href="${h.url_for( controller='admin', action='library_dataset_dataset_association', library_id=library_id, folder_id=folder.id )}">Add datasets to this folder</a>
+ <a class="action-button" href="${h.url_for( controller='admin', action='folder', new=True, id=folder.id, library_id=library_id )}">Create a new sub-folder in this folder</a>
+ <a class="action-button" href="${h.url_for( controller='admin', action='folder', information=True, id=folder.id, library_id=library_id )}">Edit this folder's information</a>
+ %if folder.library_folder_info_template_associations:
+ <% template = folder.get_library_item_info_templates( template_list=[], restrict=True )[0] %>
+ <a class="action-button" href="${h.url_for( controller='admin', action='info_template', library_id=library_id, id=template.id, edit_template=True )}">Edit this folder's information template</a>
%else:
- <a class="action-button" href="${h.url_for( controller='admin', action='info_template', library_id=library.id, folder_id=parent.id, new_template=True )}">Add an information template to this folder</a>
+ <a class="action-button" href="${h.url_for( controller='admin', action='info_template', library_id=library_id, folder_id=folder.id, new_template=True )}">Add an information template to this folder</a>
%endif
- <a class="action-button" href="${h.url_for( controller='admin', action='folder', permissions=True, id=parent.id, library_id=library_id )}">Edit this folder's permissions</a>
- <a class="action-button" confirm="Click OK to delete the folder '${parent.name}'" href="${h.url_for( controller='admin', action='delete_library_item', library_id=library_id, library_item_id=parent.id, library_item_type='folder' )}">Remove this folder and its contents from the library</a>
+ <a class="action-button" href="${h.url_for( controller='admin', action='folder', permissions=True, id=folder.id, library_id=library_id )}">Edit this folder's permissions</a>
+ <a class="action-button" confirm="Click OK to delete the folder '${folder.name}.'" href="${h.url_for( controller='admin', action='delete_library_item', library_id=library_id, library_item_id=folder.id, library_item_type='folder' )}">Delete this folder and its contents</a>
</div>
- %else:
- <div popupmenu="folder-${parent.id}-popup">
- <a class="action-button" href="${h.url_for( controller='admin', action='undelete_library_item', library_id=library_id, library_item_id=parent.id, library_item_type='folder' )}">Undelete this folder</a>
+ %elif not deleted and folder.deleted and not folder.purged:
+ <div popupmenu="folder-${folder.id}-popup">
+ <a class="action-button" href="${h.url_for( controller='admin', action='undelete_library_item', library_id=library_id, library_item_id=folder.id, library_item_type='folder' )}">Undelete this folder</a>
</div>
%endif
</li>
@@ -131,31 +133,31 @@
%else:
<ul>
%endif
- %if deleted:
+ %if show_deleted:
<%
- parent_folders = parent.activatable_folders
- parent_datasets = parent.activatable_datasets
+ parent_folders = folder.activatable_folders
+ parent_datasets = folder.activatable_datasets
%>
%else:
<%
- parent_folders = parent.active_folders
- parent_datasets = parent.active_datasets
+ parent_folders = folder.active_folders
+ parent_datasets = folder.active_datasets
%>
%endif
%for folder in name_sorted( parent_folders ):
- ${render_folder( folder, pad, deleted, created_ldda_ids, library.id )}
+ ${render_folder( folder, pad, deleted, show_deleted, created_ldda_ids, library_id )}
%endfor
%for library_dataset in name_sorted( parent_datasets ):
<%
selected = created_ldda_ids and library_dataset.library_dataset_dataset_association.id in created_ldda_ids
%>
- <li class="datasetRow" style="padding-left: ${pad + 18}px;">${render_dataset( library_dataset, selected, library )}</li>
+ <li class="datasetRow" style="padding-left: ${pad + 18}px;">${render_dataset( library_dataset, selected, library, deleted, show_deleted )}</li>
%endfor
</ul>
</%def>
<h2>
- %if library.deleted:
+ %if deleted:
Deleted
%endif
Library '${library.name}'
@@ -183,7 +185,7 @@
<table cellspacing="0" cellpadding="0" border="0" width="100%" class="libraryTitle">
<th width="*">
<img src="${h.url_for( '/static/images/silk/resultset_bottom.png' )}" class="expanderIcon"/><img src="${h.url_for( '/static/images/silk/book_open.png' )}" class="rowIcon"/>
- <span class="libraryItemDeleted-${library.deleted}">
+ <span class="libraryItemDeleted-${deleted}">
${library.name}
%if library.description:
<i>- ${library.description}</i>
@@ -191,7 +193,7 @@
</span>
<a id="library-${library.id}-popup" class="popup-arrow" style="display: none;">▼</a>
<div popupmenu="library-${library.id}-popup">
- %if not library.deleted:
+ %if not deleted:
<%
library_item_ids = {}
library_item_ids[ 'library' ] = library.id
@@ -205,14 +207,14 @@
<a class="action-button" href="${h.url_for( controller='admin', action='info_template', library_id=library.id, new_template=True )}">Add an information template to this library</a>
%endif
<a class="action-button" href="${h.url_for( controller='admin', action='library', id=library.id, permissions=True )}">Edit this library's permissions</a>
- <a class="action-button" confirm="Current state will not be saved, so undeleting the library will restore all of its contents. Click OK to delete the library named '${library.name}'?" href="${h.url_for( controller='admin', action='delete_library_item', library_item_type='library', library_item_id=library.id )}">Delete this library and its contents</a>
+ <a class="action-button" confirm="Click OK to delete the library named '${library.name}'." href="${h.url_for( controller='admin', action='delete_library_item', library_id=library.id, library_item_id=library.id, library_item_type='library' )}">Delete this library and its contents</a>
%if show_deleted:
<a class="action-button" href="${h.url_for( controller='admin', action='browse_library', id=library.id, show_deleted=False )}">Hide deleted library items</a>
%else:
<a class="action-button" href="${h.url_for( controller='admin', action='browse_library', id=library.id, show_deleted=True )}">Show deleted library items</a>
%endif
%elif not library.purged:
- <a class="action-button" href="${h.url_for( controller='admin', action='undelete_library_item', library_item_type='library', library_item_id=library.id )}">Undelete this library</a>
+ <a class="action-button" href="${h.url_for( controller='admin', action='undelete_library_item', library_id=library.id, library_item_id=library.id, library_item_type='library' )}">Undelete this library</a>
%endif
</div>
</th>
@@ -223,16 +225,16 @@
</div>
</li>
<ul>
- ${render_folder( library.root_folder, 0, library.deleted or show_deleted, created_ldda_ids, library.id )}
+ ${render_folder( library.root_folder, 0, deleted, show_deleted, created_ldda_ids, library.id )}
</ul>
<br/>
</ul>
- %if not library.deleted:
+ %if not deleted and not show_deleted:
<p>
<b>Perform action on selected datasets:</b>
<select name="action" id="action_on_datasets_select">
<option value="edit">Edit selected datasets' permissions</option>
- ##TODO: fix deleting library items<option value="delete">Remove selected datasets from this library</option>
+ <option value="delete">Delete selected datasets</option>
</select>
<input type="submit" class="primary-button" name="action_on_datasets_button" id="action_on_datasets_button" value="Go"/>
</p>
diff -r 8da91a231cdf -r 2e2b80fcbd47 templates/admin/library/common.mako
--- a/templates/admin/library/common.mako Tue May 05 13:03:23 2009 -0400
+++ b/templates/admin/library/common.mako Tue May 05 13:48:01 2009 -0400
@@ -1,6 +1,6 @@
<% from time import strftime %>
-<%def name="render_dataset( library_dataset, selected, library, show_deleted = False )">
+<%def name="render_dataset( library_dataset, selected, library, deleted, show_deleted )">
<%
## The received data must always be a LibraryDataset object, but the object id passed to methods from the drop down menu
## should be the underlying ldda id to prevent id collision ( which could happen when displaying children, which are always
@@ -28,10 +28,10 @@
<input type="checkbox" name="ldda_ids" value="${ldda.id}"/>
%endif
<span class="libraryItemDeleted-${library_dataset.deleted}">
- <a href="${h.url_for( controller='admin', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, info=True )}"><b>${ldda.name[:50]}</b></a>
+ <a href="${h.url_for( controller='admin', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, info=True, deleted=deleted, show_deleted=show_deleted )}"><b>${ldda.name[:50]}</b></a>
</span>
<a id="dataset-${ldda.id}-popup" class="popup-arrow" style="display: none;">▼</a>
- %if not library_dataset.deleted:
+ %if not library.deleted and not library_dataset.folder.deleted and not library_dataset.deleted:
<%
library_item_ids = {}
library_item_ids[ 'ldda' ] = ldda.id
@@ -47,12 +47,11 @@
%if ldda.has_data:
<a class="action-button" href="${h.url_for( controller='admin', action='download_dataset_from_folder', id=ldda.id, library_id=library.id )}">Download this dataset</a>
%endif
- ##TODO: need to revamp the way we remove datasets from disk.
- <a class="action-button" confirm="Click OK to remove dataset '${ldda.name}'?" href="${h.url_for( controller='admin', action='delete_library_item', library_id=library.id, library_item_id=library_dataset.id, library_item_type='dataset' )}">Remove this dataset from the library</a>
+ <a class="action-button" confirm="Click OK to delete dataset '${ldda.name}'." href="${h.url_for( controller='admin', action='delete_library_item', library_id=library.id, library_item_id=library_dataset.id, library_item_type='library_dataset' )}">Delete this dataset</a>
</div>
- %else:
+ %elif not library.deleted and not library_dataset.folder.deleted and library_dataset.deleted:
<div popupmenu="dataset-${ldda.id}-popup">
- <a class="action-button" href="${h.url_for( controller='admin', action='undelete_library_item', library_id=library.id, library_item_id=library_dataset.id, library_item_type='dataset' )}">Undelete this dataset</a>
+ <a class="action-button" href="${h.url_for( controller='admin', action='undelete_library_item', library_id=library.id, library_item_id=library_dataset.id, library_item_type='library_dataset' )}">Undelete this dataset</a>
</div>
%endif
</td>
diff -r 8da91a231cdf -r 2e2b80fcbd47 templates/admin/library/ldda_info.mako
--- a/templates/admin/library/ldda_info.mako Tue May 05 13:03:23 2009 -0400
+++ b/templates/admin/library/ldda_info.mako Tue May 05 13:48:01 2009 -0400
@@ -5,6 +5,7 @@
<% from galaxy import util %>
<%
+ library = trans.app.model.Library.get( library_id )
if ldda == ldda.library_dataset.library_dataset_dataset_association:
current_version = True
else:
@@ -20,7 +21,7 @@
<ul class="manage-table-actions">
<li>
- <a class="action-button" href="${h.url_for( controller='admin', action='browse_library', id=library_id )}"><span>Browse this library</span></a>
+ <a class="action-button" href="${h.url_for( controller='admin', action='browse_library', id=library_id, deleted=library.deleted, show_deleted=show_deleted )}"><span>Browse this library</span></a>
</li>
</ul>
@@ -38,21 +39,24 @@
<div class="toolForm">
<div class="toolFormTitle">
Information about ${ldda.name}
- <a id="dataset-${ldda.id}-popup" class="popup-arrow" style="display: none;">▼</a>
- <div popupmenu="dataset-${ldda.id}-popup">
- <a class="action-button" href="${h.url_for( controller='admin', action='library_dataset_dataset_association', library_id=library_id, folder_id=ldda.library_dataset.folder.id, id=ldda.id, edit_info=True )}">Edit this dataset's information</a>
- ## We're disabling the ability to add templates at the LDDA and LibraryDataset level, but will leave this here for possible future use
- ##<a class="action-button" href="${h.url_for( controller='admin', action='info_template', library_id=library_id, library_dataset_id=ldda.library_dataset.id, new_template=True )}">Add an information template to this dataset</a>
- <a class="action-button" href="${h.url_for( controller='admin', action='library_dataset_dataset_association', library_id=library_id, folder_id=ldda.library_dataset.folder.id, id=ldda.id, permissions=True )}">Edit this dataset's permissions</a>
- %if current_version:
- <a class="action-button" href="${h.url_for( controller='admin', action='library_dataset_dataset_association', library_id=library_id, folder_id=ldda.library_dataset.folder.id, replace_id=ldda.library_dataset.id )}">Upload a new version of this dataset</a>
- %endif
- %if ldda.has_data:
- <a class="action-button" href="${h.url_for( controller='admin', action='download_dataset_from_folder', id=ldda.id, library_id=library_id )}">Download this dataset</a>
- %endif
- ##TODO: need to revamp the way we remove datasets from disk.
- ##<a class="action-button" confirm="Click OK to remove dataset '${ldda.name}'?" href="${h.url_for( controller='admin', action='library_dataset_dataset_association', library_id=library_id, folder_id=ldda.library_dataset.folder.id, id=ldda.id, delete=True )}">Remove this dataset from the library</a>
- </div>
+ %if not library.deleted and not ldda.library_dataset.folder.deleted and not ldda.deleted:
+ <a id="dataset-${ldda.id}-popup" class="popup-arrow" style="display: none;">▼</a>
+ <div popupmenu="dataset-${ldda.id}-popup">
+ <a class="action-button" href="${h.url_for( controller='admin', action='library_dataset_dataset_association', library_id=library_id, folder_id=ldda.library_dataset.folder.id, id=ldda.id, edit_info=True )}">Edit this dataset's information</a>
+ ## We're disabling the ability to add templates at the LDDA and LibraryDataset level, but will leave this here for possible future use
+ ##<a class="action-button" href="${h.url_for( controller='admin', action='info_template', library_id=library_id, library_dataset_id=ldda.library_dataset.id, new_template=True )}">Add an information template to this dataset</a>
+ <a class="action-button" href="${h.url_for( controller='admin', action='library_dataset_dataset_association', library_id=library_id, folder_id=ldda.library_dataset.folder.id, id=ldda.id, permissions=True )}">Edit this dataset's permissions</a>
+ %if current_version:
+ <a class="action-button" href="${h.url_for( controller='admin', action='library_dataset_dataset_association', library_id=library_id, folder_id=ldda.library_dataset.folder.id, replace_id=ldda.library_dataset.id )}">Upload a new version of this dataset</a>
+ %endif
+ %if ldda.has_data:
+ <a class="action-button" href="${h.url_for( controller='admin', action='download_dataset_from_folder', id=ldda.id, library_id=library_id )}">Download this dataset</a>
+ %endif
+ %if not library.deleted and not ldda.library_dataset.folder.deleted and not ldda.deleted:
+ <a class="action-button" confirm="Click OK to remove dataset '${ldda.name}'?" href="${h.url_for( controller='admin', action='library_dataset_dataset_association', library_id=library_id, folder_id=ldda.library_dataset.folder.id, id=ldda.id, delete=True )}">Delete this dataset</a>
+ %endif
+ </div>
+ %endif
</div>
<div class="toolFormBody">
<div class="form-row">
@@ -104,7 +108,10 @@
<div>
There are ${len( ldda.visible_children )} secondary datasets.
%for idx, child in enumerate( ldda.visible_children ):
- ${ render_dataset( child, selected, library.deleted ) }
+ ## TODO: do we need to clarify if the child is deleted?
+ %if not child.purged:
+ ${ render_dataset( child, selected, library, False, False ) }
+ %endif
%endfor
</div>
%endif
diff -r 8da91a231cdf -r 2e2b80fcbd47 templates/library/ldda_info.mako
--- a/templates/library/ldda_info.mako Tue May 05 13:03:23 2009 -0400
+++ b/templates/library/ldda_info.mako Tue May 05 13:48:01 2009 -0400
@@ -111,7 +111,10 @@
<div>
There are ${len( ldda.visible_children )} secondary datasets.
%for idx, child in enumerate( ldda.visible_children ):
- ${ render_dataset( child, selected, library.deleted ) }
+ ## TODO: do we need to clarify if the child is deleted?
+ %if not child.purged:
+ ${ render_dataset( child, selected, library ) }
+ %endif
%endfor
</div>
%endif
1
0
05 May '09
details: http://www.bx.psu.edu/hg/galaxy/rev/3abf689d6f6f
changeset: 2399:3abf689d6f6f
user: Nate Coraor <nate(a)bx.psu.edu>
date: Tue May 05 12:03:40 2009 -0400
description:
Directly stream .tar.gz and .tar.bz2 library downloads. .zip is still created
on-disk first since Python's zipfile can't write to file-like objects like
tarfile can. For response body generators (e.g. this feature) to work
properly, you must set use_interactive and debug to False in universe_wsgi.ini.
3 file(s) affected in this change:
lib/galaxy/util/streamball.py
lib/galaxy/web/controllers/library.py
templates/library/browse_library.mako
diffs (277 lines):
diff -r 6c76023580e3 -r 3abf689d6f6f lib/galaxy/util/streamball.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/util/streamball.py Tue May 05 12:03:40 2009 -0400
@@ -0,0 +1,50 @@
+"""
+A simple wrapper for writing tarballs as a stream. The work is performed in a
+thread and data is written to a Queue instead of a file.
+"""
+
+import logging, tarfile
+
+from Queue import Queue, Empty, Full
+from threading import Thread
+
+log = logging.getLogger( __name__ )
+
+class QueueArchive( object ):
+ queue_size = 32
+ def __init__( self ):
+ self.queue = Queue( QueueArchive.queue_size )
+ self.get = self.queue.get
+ self.empty = self.queue.empty
+ def write( self, data ):
+ self.queue.put( data, block=True, timeout=300 )
+ def tell( self ):
+ return 0
+
+class StreamBall( object ):
+ def __init__( self, mode, members={} ):
+ self.mode = mode
+ self.members = members
+ self.tarfileobj = QueueArchive()
+ def add( self, file, relpath ):
+ self.members[file] = relpath
+ def stream( self ):
+ t = Thread( target=self.thread_write )
+ t.start()
+ while t.isAlive():
+ try:
+ yield self.tarfileobj.get( block=False )
+ except Empty:
+ pass
+ t.join()
+ # exhaust the queue
+ while not self.tarfileobj.empty():
+ yield self.tarfileobj.get()
+ def thread_write( self ):
+ tf = tarfile.open( mode=self.mode, fileobj=self.tarfileobj )
+ try:
+ for file, rel in self.members.items():
+ tf.add( file, arcname=rel )
+ tf.close()
+ except Full:
+ log.warning( 'Queue full for longer than 300 seconds, timing out' )
diff -r 6c76023580e3 -r 3abf689d6f6f lib/galaxy/web/controllers/library.py
--- a/lib/galaxy/web/controllers/library.py Tue May 05 08:29:23 2009 -0400
+++ b/lib/galaxy/web/controllers/library.py Tue May 05 12:03:40 2009 -0400
@@ -2,6 +2,7 @@
from galaxy.model.orm import *
from galaxy.datatypes import sniff
from galaxy import util
+from galaxy.util.streamball import StreamBall
import logging, tempfile, zipfile, tarfile, os, sys
if sys.version_info[:2] < ( 2, 6 ):
@@ -10,6 +11,40 @@
zipfile.LargeZipFile = zipfile.error
log = logging.getLogger( __name__ )
+
+# Test for available compression types
+tmpd = tempfile.mkdtemp()
+comptypes = []
+for comptype in ( 'gz', 'bz2' ):
+ tmpf = os.path.join( tmpd, 'compression_test.tar.' + comptype )
+ try:
+ archive = tarfile.open( tmpf, 'w:' + comptype )
+ archive.close()
+ comptypes.append( comptype )
+ except tarfile.CompressionError:
+ log.exception( "Compression error when testing %s compression. This option will be disabled for library downloads." % comptype )
+ try:
+ os.unlink( tmpf )
+ except OSError:
+ pass
+ziptype = '32'
+tmpf = os.path.join( tmpd, 'compression_test.zip' )
+try:
+ archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED, True )
+ archive.close()
+ comptypes.append( 'zip' )
+ ziptype = '64'
+except RuntimeError:
+ log.exception( "Compression error when testing zip compression. This option will be disabled for library downloads." )
+except (TypeError, zipfile.LargeZipFile):
+ # ZIP64 is only in Python2.5+. Remove TypeError when 2.4 support is dropped
+ log.warning( 'Max zip file size is 2GB, ZIP64 not supported' )
+ comptypes.append( 'zip' )
+try:
+ os.unlink( tmpf )
+except OSError:
+ pass
+os.rmdir( tmpd )
class Library( BaseController ):
@web.expose
@@ -66,6 +101,7 @@
library=trans.app.model.Library.get( id ),
created_ldda_ids=created_ldda_ids,
default_action=params.get( 'default_action', None ),
+ comptypes=comptypes,
msg=msg,
messagetype=messagetype )
@web.expose
@@ -195,49 +231,21 @@
msg=util.sanitize_text( msg ),
messagetype=messagetype ) )
else:
- # Can't use mkstemp - the file must not exist first
try:
- tmpd = tempfile.mkdtemp()
- tmpf = os.path.join( tmpd, 'library_download.' + params.do_action )
if params.do_action == 'zip':
- try:
+ # Can't use mkstemp - the file must not exist first
+ tmpd = tempfile.mkdtemp()
+ tmpf = os.path.join( tmpd, 'library_download.' + params.do_action )
+ if ziptype == '64':
archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED, True )
- except RuntimeError:
- log.exception( "Compression error when opening zipfile for library download" )
- msg = "ZIP compression is not available in this Python, please notify an administrator"
- return trans.response.send_redirect( web.url_for( controller='library',
- action='browse_library',
- id=library_id,
- msg=util.sanitize_text( msg ),
- messagetype='error' ) )
- except (TypeError, zipfile.LargeZipFile):
- # ZIP64 is only in Python2.5+. Remove TypeError when 2.4 support is dropped
- log.warning( 'Max zip file size is 2GB, ZIP64 not supported' )
+ else:
archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED )
archive.add = lambda x, y: archive.write( x, y.encode('CP437') )
elif params.do_action == 'tgz':
- try:
- archive = tarfile.open( tmpf, 'w:gz' )
- except tarfile.CompressionError:
- log.exception( "Compression error when opening tarfile for library download" )
- msg = "gzip compression is not available in this Python, please notify an administrator"
- return trans.response.send_redirect( web.url_for( controller='library',
- action='browse_library',
- id=library_id,
- msg=util.sanitize_text( msg ),
- messagetype='error' ) )
+ archive = util.streamball.StreamBall( 'w|gz' )
elif params.do_action == 'tbz':
- try:
- archive = tarfile.open( tmpf, 'w:bz2' )
- except tarfile.CompressionError:
- log.exception( "Compression error when opening tarfile for library download" )
- msg = "bzip2 compression is not available in this Python, please notify an administrator"
- return trans.response.send_redirect( web.url_for( controller='library',
- action='browse_library',
- id=library_id,
- msg=util.sanitize_text( msg ),
- messagetype='error' ) )
- except (OSError, zipfile.BadZipFile, tarfile.ReadError):
+ archive = util.streamball.StreamBall( 'w|bz2' )
+ except (OSError, zipfile.BadZipFile):
log.exception( "Unable to create archive for download" )
msg = "Unable to create archive for download, please report this error"
return trans.response.send_redirect( web.url_for( controller='library',
@@ -255,9 +263,11 @@
path = ""
parent_folder = ldda.library_dataset.folder
while parent_folder is not None:
- path = os.path.join( parent_folder.name, path )
+ # Exclude the now-hidden "root folder"
if parent_folder.parent is None:
path = os.path.join( parent_folder.library_root[0].name, path )
+ break
+ path = os.path.join( parent_folder.name, path )
parent_folder = parent_folder.parent
path += ldda.name
while path in seen:
@@ -273,22 +283,28 @@
id=library_id,
msg=util.sanitize_text( msg ),
messagetype='error' ) )
- archive.close()
- tmpfh = open( tmpf )
- # clean up now
- try:
- os.unlink( tmpf )
- os.rmdir( tmpd )
- except OSError:
- log.exception( "Unable to remove temporary library download archive and directory" )
- msg = "Unable to create archive for download, please report this error"
- return trans.response.send_redirect( web.url_for( controller='library',
- action='browse_library',
- id=library_id,
- msg=util.sanitize_text( msg ),
- messagetype='error' ) )
- trans.response.headers[ "Content-Disposition" ] = "attachment; filename=GalaxyLibraryFiles.%s" % params.do_action
- return tmpfh
+ if params.do_action == 'zip':
+ archive.close()
+ tmpfh = open( tmpf )
+ # clean up now
+ try:
+ os.unlink( tmpf )
+ os.rmdir( tmpd )
+ except OSError:
+ log.exception( "Unable to remove temporary library download archive and directory" )
+ msg = "Unable to create archive for download, please report this error"
+ return trans.response.send_redirect( web.url_for( controller='library',
+ action='browse_library',
+ id=library_id,
+ msg=util.sanitize_text( msg ),
+ messagetype='error' ) )
+ trans.response.set_content_type( "application/x-zip-compressed" )
+ trans.response.headers[ "Content-Disposition" ] = "attachment; filename=GalaxyLibraryFiles.%s" % params.do_action
+ return tmpfh
+ else:
+ trans.response.set_content_type( "application/x-tar" )
+ trans.response.headers[ "Content-Disposition" ] = "attachment; filename=GalaxyLibraryFiles.%s" % params.do_action
+ return archive.stream()
@web.expose
def download_dataset_from_folder(self, trans, id, library_id=None, **kwd):
"""Catches the dataset id and displays file contents as directed"""
diff -r 6c76023580e3 -r 3abf689d6f6f templates/library/browse_library.mako
--- a/templates/library/browse_library.mako Tue May 05 08:29:23 2009 -0400
+++ b/templates/library/browse_library.mako Tue May 05 12:03:40 2009 -0400
@@ -268,13 +268,38 @@
# This condition should not contain an else clause because the user is not authorized
# to manage dataset permissions unless the default action is 'manage_permissions'
%endif
- %if default_action == 'download':
- <option value="zip" selected>Download selected datasets as a .zip file</option>
- %else:
+ %if 'bz2' in comptypes:
+ <option value="tbz"
+ %if default_action == 'download':
+ selected
+ %endif>
+ >Download selected datasets as a .tar.bz2 file</option>
+ %endif
+ %if 'gz' in comptypes:
+ <option value="tgz">Download selected datasets as a .tar.gz file</option>
+ %endif
+ %if 'zip' in comptypes:
<option value="zip">Download selected datasets as a .zip file</option>
%endif
- <option value="tgz">Download selected datasets as a .tar.gz file</option>
- <option value="tbz">Download selected datasets as a .tar.bz2 file</option>
</select>
<input type="submit" class="primary-button" name="action_on_datasets_button" id="action_on_datasets_button" value="Go"/>
</form>
+
+%if len( comptypes ) > 1:
+ <div>
+ <p class="infomark">
+ TIP: Multiple compression options are available for downloading library datasets:
+ </p>
+ <ul style="padding-left: 1em; list-style-type: disc;">
+ %if 'bz2' in comptypes:
+ <li>bzip2: Compression takes the most time but is better for slower network connections (that transfer slower than the rate of compression) since the resulting file size is smallest.</li>
+ %endif
+ %if 'gz' in comptypes:
+ <li>gzip: Compression is faster and yields a larger file, making it more suitable for fast network connections.</li>
+ %endif
+ %if 'zip' in comptypes:
+ <li>ZIP: Not recommended but is provided as an option for those on Windows without WinZip (since WinZip can read .bz2 and .gz files).</li>
+ %endif
+ </ul>
+ </div>
+%endif
1
0
05 May '09
details: http://www.bx.psu.edu/hg/galaxy/rev/8da91a231cdf
changeset: 2400:8da91a231cdf
user: Nate Coraor <nate(a)bx.psu.edu>
date: Tue May 05 13:03:23 2009 -0400
description:
Fix history deletion method in Galaxy check script
1 file(s) affected in this change:
scripts/check_galaxy.py
diffs (38 lines):
diff -r 3abf689d6f6f -r 8da91a231cdf scripts/check_galaxy.py
--- a/scripts/check_galaxy.py Tue May 05 12:03:40 2009 -0400
+++ b/scripts/check_galaxy.py Tue May 05 13:03:23 2009 -0400
@@ -141,15 +141,8 @@
print "Remaining datasets ids:", " ".join( p.dids )
raise Exception, "History still contains datasets after attempting to delete them"
if new_history:
- self.get("/root/history_options")
- p = hidParser()
- p.feed(tc.browser.get_html())
- if p.hid is None:
- print "Unable to determine hid to delete old history"
- sys.exit(1)
- else:
- self.get("/root/history_delete?id=%s" % p.hid)
- tc.save_cookies(self.cookie_jar)
+ self.get("/history/delete_current")
+ tc.save_cookies(self.cookie_jar)
def check_redir(self, url):
try:
@@ -334,16 +327,6 @@
self.dids.append( i[1].rsplit("historyItemContainer-", 1)[1] )
dprint("got a dataset id: %s" % self.dids[-1])
-class hidParser(htmllib.HTMLParser):
- def __init__(self):
- htmllib.HTMLParser.__init__(self, formatter.NullFormatter())
- self.hid = None
- def start_a(self, attrs):
- for i in attrs:
- if i[0] == "href" and i[1].startswith("/root/history_delete"):
- self.hid = i[1].rsplit("=", 1)[1]
- dprint("got a history id: %s" % self.hid)
-
class loggedinParser(htmllib.HTMLParser):
def __init__(self):
htmllib.HTMLParser.__init__(self, formatter.NullFormatter())
1
0
05 May '09
details: http://www.bx.psu.edu/hg/galaxy/rev/6de7eb773877
changeset: 2396:6de7eb773877
user: James Taylor <james(a)jamestaylor.org>
date: Mon May 04 12:06:11 2009 -0400
description:
Fix import history links, now using encode_id as well
2 file(s) affected in this change:
lib/galaxy/web/controllers/history.py
templates/history/share.mako
diffs (73 lines):
diff -r df824c53f2f3 -r 6de7eb773877 lib/galaxy/web/controllers/history.py
--- a/lib/galaxy/web/controllers/history.py Fri May 01 17:19:17 2009 -0400
+++ b/lib/galaxy/web/controllers/history.py Mon May 04 12:06:11 2009 -0400
@@ -213,6 +213,57 @@
## These have been moved from 'root' but not cleaned up
@web.expose
+ def imp( self, trans, id=None, confirm=False, **kwd ):
+ msg = ""
+ user = trans.get_user()
+ user_history = trans.get_history()
+ if not id:
+ return trans.show_error_message( "You must specify a history you want to import.")
+ id = trans.security.decode_id( id )
+ import_history = trans.app.model.History.get( id )
+ if not import_history:
+ return trans.show_error_message( "The specified history does not exist.")
+ if user:
+ if import_history.user_id == user.id:
+ return trans.show_error_message( "You cannot import your own history.")
+ new_history = import_history.copy( target_user=trans.user )
+ new_history.name = "imported: "+new_history.name
+ new_history.user_id = user.id
+ galaxy_session = trans.get_galaxy_session()
+ try:
+ association = trans.app.model.GalaxySessionToHistoryAssociation.filter_by( session_id=galaxy_session.id, history_id=new_history.id ).first()
+ except:
+ association = None
+ new_history.add_galaxy_session( galaxy_session, association=association )
+ new_history.flush()
+ if not user_history.datasets:
+ trans.set_history( new_history )
+ trans.log_event( "History imported, id: %s, name: '%s': " % (str(new_history.id) , new_history.name ) )
+ return trans.show_ok_message( """
+ History "%s" has been imported. Click <a href="%s">here</a>
+ to begin.""" % ( new_history.name, web.url_for( '/' ) ) )
+ elif not user_history.datasets or confirm:
+ new_history = import_history.copy()
+ new_history.name = "imported: "+new_history.name
+ new_history.user_id = None
+ galaxy_session = trans.get_galaxy_session()
+ try:
+ association = trans.app.model.GalaxySessionToHistoryAssociation.filter_by( session_id=galaxy_session.id, history_id=new_history.id ).first()
+ except:
+ association = None
+ new_history.add_galaxy_session( galaxy_session, association=association )
+ new_history.flush()
+ trans.set_history( new_history )
+ trans.log_event( "History imported, id: %s, name: '%s': " % (str(new_history.id) , new_history.name ) )
+ return trans.show_ok_message( """
+ History "%s" has been imported. Click <a href="%s">here</a>
+ to begin.""" % ( new_history.name, web.url_for( '/' ) ) )
+ return trans.show_warn_message( """
+ Warning! If you import this history, you will lose your current
+ history. Click <a href="%s">here</a> to confirm.
+ """ % web.url_for( id=id, confirm=True ) )
+
+ @web.expose
@web.require_login( "share histories with other users" )
def share( self, trans, id=None, email="", **kwd ):
send_to_err = ""
diff -r df824c53f2f3 -r 6de7eb773877 templates/history/share.mako
--- a/templates/history/share.mako Fri May 01 17:19:17 2009 -0400
+++ b/templates/history/share.mako Mon May 04 12:06:11 2009 -0400
@@ -18,7 +18,7 @@
${len(history.datasets)}
%endif
</td>
- <td align="center"><a href="${h.url_for( action='history_import', id=history.id )}">${_('copy link to share')}</a></td>
+ <td align="center"><a href="${h.url_for( controller='history', action='imp', id=trans.security.encode_id(history.id) )}">${_('copy link to share')}</a></td>
</tr>
%endfor
<tr><td>${_('Email of User to share with:')}</td><td><input type="text" name="email" value="${email}" size="40"></td></tr>
1
0
05 May '09
details: http://www.bx.psu.edu/hg/galaxy/rev/df824c53f2f3
changeset: 2395:df824c53f2f3
user: James Taylor <james(a)jamestaylor.org>
date: Fri May 01 17:19:17 2009 -0400
description:
Simplifying the grid helper a bit. Fix a bug where sort/filter were not retained when performing actions on multiple items
4 file(s) affected in this change:
lib/galaxy/web/controllers/history.py
lib/galaxy/web/framework/helpers/__init__.py
lib/galaxy/web/framework/helpers/grids.py
templates/grid.mako
diffs (279 lines):
diff -r 80e00a9cdeb0 -r df824c53f2f3 lib/galaxy/web/controllers/history.py
--- a/lib/galaxy/web/controllers/history.py Fri May 01 12:24:24 2009 -0400
+++ b/lib/galaxy/web/controllers/history.py Fri May 01 17:19:17 2009 -0400
@@ -1,5 +1,5 @@
from galaxy.web.base.controller import *
-from galaxy.web.framework.helpers.grids import *
+from galaxy.web.framework.helpers import time_ago, iff, grids
import webhelpers
from datetime import datetime
from cgi import escape
@@ -9,42 +9,33 @@
# States for passing messages
SUCCESS, INFO, WARNING, ERROR = "done", "info", "warning", "error"
-def time_ago( x ):
- return webhelpers.date.distance_of_time_in_words( x, datetime.utcnow() )
-
-def iff( a, b, c ):
- if a:
- return b
- else:
- return c
-
-class HistoryListGrid( Grid ):
+class HistoryListGrid( grids.Grid ):
title = "Stored histories"
model_class = model.History
default_sort_key = "-create_time"
columns = [
- GridColumn( "Name", key="name",
+ grids.GridColumn( "Name", key="name",
link=( lambda item: iff( item.deleted, None, dict( operation="switch", id=item.id ) ) ),
attach_popup=True ),
- GridColumn( "Datasets (by state)", method='_build_datasets_by_state', ncells=4 ),
- GridColumn( "Status", method='_build_status' ),
- GridColumn( "Age", key="create_time", format=time_ago ),
- GridColumn( "Last update", key="update_time", format=time_ago ),
+ grids.GridColumn( "Datasets (by state)", method='_build_datasets_by_state', ncells=4 ),
+ grids.GridColumn( "Status", method='_build_status' ),
+ grids.GridColumn( "Age", key="create_time", format=time_ago ),
+ grids.GridColumn( "Last update", key="update_time", format=time_ago ),
# Valid for filtering but invisible
- GridColumn( "Deleted", key="deleted", visible=False )
+ grids.GridColumn( "Deleted", key="deleted", visible=False )
]
operations = [
- GridOperation( "Switch", allow_multiple=False, condition=( lambda item: not item.deleted ) ),
- GridOperation( "Share", condition=( lambda item: not item.deleted ) ),
- GridOperation( "Rename", condition=( lambda item: not item.deleted ) ),
- GridOperation( "Delete", condition=( lambda item: not item.deleted ) ),
- GridOperation( "Undelete", condition=( lambda item: item.deleted ) )
+ grids.GridOperation( "Switch", allow_multiple=False, condition=( lambda item: not item.deleted ) ),
+ grids.GridOperation( "Share", condition=( lambda item: not item.deleted ) ),
+ grids.GridOperation( "Rename", condition=( lambda item: not item.deleted ) ),
+ grids.GridOperation( "Delete", condition=( lambda item: not item.deleted ) ),
+ grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ) )
]
standard_filters = [
- GridColumnFilter( "Active", args=dict( deleted=False ) ),
- GridColumnFilter( "Deleted", args=dict( deleted=True ) ),
- GridColumnFilter( "All", args=dict( deleted='All' ) )
+ grids.GridColumnFilter( "Active", args=dict( deleted=False ) ),
+ grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ),
+ grids.GridColumnFilter( "All", args=dict( deleted='All' ) )
]
default_filter = dict( deleted=False )
@@ -53,41 +44,7 @@
def apply_default_filter( self, trans, query ):
return query.filter_by( user=trans.user, purged=False )
-
- def handle_operation( self, trans, operation, history_ids ):
- # Display no message by default
- status, message = None, None
- refresh_history = False
- # Load the histories and ensure they all belong to the current user
- histories = []
- for hid in history_ids:
- history = model.History.get( hid )
- if history:
- # Ensure history is owned by current user
- if history.user_id != None and trans.user:
- assert trans.user.id == history.user_id, "History does not belong to current user"
- histories.append( history )
- else:
- log.warn( "Invalid history id '%r' passed to list", hid )
- operation = operation.lower()
- if operation == "switch":
- status, message = self._list_switch( trans, histories )
- # Current history changed, refresh history frame
- trans.template_context['refresh_frames'] = ['history']
- elif operation == "share":
- ## Caught above for now
- pass
- elif operation == "rename":
- ## Caught above for now
- pass
- elif operation == "delete":
- status, message = self._list_delete( trans, histories )
- elif operation == "undelete":
- status, message = self._list_undelete( trans, histories )
- trans.sa_session.flush()
- # Render the list view
- return status, message
-
+
def _build_datasets_by_state( self, trans, history ):
rval = []
for state in ( 'ok', 'running', 'queued', 'error' ):
@@ -102,6 +59,64 @@
if history.deleted:
return "deleted"
return ""
+
+class HistoryController( BaseController ):
+
+ @web.expose
+ def index( self, trans ):
+ return ""
+
+ @web.expose
+ def list_as_xml( self, trans ):
+ """
+ XML history list for functional tests
+ """
+ return trans.fill_template( "/history/list_as_xml.mako" )
+
+ list_grid = HistoryListGrid()
+
+ @web.expose
+ @web.require_login( "work with multiple histories" )
+ def list( self, trans, **kwargs ):
+ """
+ List all available histories
+ """
+ status = message = None
+ if 'operation' in kwargs:
+ operation = kwargs['operation'].lower()
+ if operation == "share":
+ return self.share( trans, **kwargs )
+ elif operation == "rename":
+ return self.rename( trans, **kwargs )
+ # Display no message by default
+ status, message = None, None
+ refresh_history = False
+ # Load the histories and ensure they all belong to the current user
+ history_ids = kwargs.get( 'id', [] )
+ if type( history_ids ) is not list:
+ history_ids = [ history_ids ]
+ histories = []
+ for hid in history_ids:
+ history = model.History.get( hid )
+ if history:
+ # Ensure history is owned by current user
+ if history.user_id != None and trans.user:
+ assert trans.user.id == history.user_id, "History does not belong to current user"
+ histories.append( history )
+ else:
+ log.warn( "Invalid history id '%r' passed to list", hid )
+ if histories:
+ if operation == "switch":
+ status, message = self._list_switch( trans, histories )
+ # Current history changed, refresh history frame
+ trans.template_context['refresh_frames'] = ['history']
+ elif operation == "delete":
+ status, message = self._list_delete( trans, histories )
+ elif operation == "undelete":
+ status, message = self._list_undelete( trans, histories )
+ trans.sa_session.flush()
+ # Render the list view
+ return self.list_grid( trans, status=status, message=message, **kwargs )
def _list_delete( self, trans, histories ):
"""Delete histories"""
@@ -164,37 +179,6 @@
trans.log_event( "History switched to id: %s, name: '%s'" % (str(new_history.id), new_history.name ) )
# No message
return None, None
-
-class HistoryController( BaseController ):
-
- @web.expose
- def index( self, trans ):
- return ""
-
- @web.expose
- def list_as_xml( self, trans ):
- """
- XML history list for functional tests
- """
- return trans.fill_template( "/history/list_as_xml.mako" )
-
- _list_grid = HistoryListGrid()
-
- @web.expose
- @web.require_login( "work with multiple histories" )
- def list( self, trans, *args, **kwargs ):
- """
- List all available histories
- """
- # TODO: these two operations need to be updates still
- operation = kwargs.get( 'operation', None )
- if operation:
- operation = operation.lower()
- if operation == "share":
- return self.share( trans, **kwargs )
- elif operation == "rename":
- return self.rename( trans, **kwargs )
- return self._list_grid( trans, *args, **kwargs )
@web.expose
def delete_current( self, trans ):
diff -r 80e00a9cdeb0 -r df824c53f2f3 lib/galaxy/web/framework/helpers/__init__.py
--- a/lib/galaxy/web/framework/helpers/__init__.py Fri May 01 12:24:24 2009 -0400
+++ b/lib/galaxy/web/framework/helpers/__init__.py Fri May 01 17:19:17 2009 -0400
@@ -0,0 +1,12 @@
+from webhelpers import *
+
+from datetime import datetime
+
+def time_ago( x ):
+ return date.distance_of_time_in_words( x, datetime.utcnow() )
+
+def iff( a, b, c ):
+ if a:
+ return b
+ else:
+ return c
\ No newline at end of file
diff -r 80e00a9cdeb0 -r df824c53f2f3 lib/galaxy/web/framework/helpers/grids.py
--- a/lib/galaxy/web/framework/helpers/grids.py Fri May 01 12:24:24 2009 -0400
+++ b/lib/galaxy/web/framework/helpers/grids.py Fri May 01 17:19:17 2009 -0400
@@ -16,18 +16,13 @@
standard_filters = []
default_filter = None
default_sort_key = None
+ pass_through_operations = {}
def __init__( self ):
pass
def __call__( self, trans, **kwargs ):
- # Session
+ status = kwargs.get( 'status', None )
+ message = kwargs.get( 'message', None )
session = trans.sa_session
- # Process any actions
- status = message = None
- ids = self.get_ids( **kwargs )
- operation = kwargs.get( 'operation', None )
- if operation:
- operation = operation.lower()
- status, message = self.handle_operation( trans, operation, ids )
# Build initial query
query = self.build_initial_query( session )
query = self.apply_default_filter( trans, query )
@@ -83,7 +78,7 @@
encoded_sort_key=encoded_sort_key,
sort_order=sort_order,
current_item=current_item,
- ids = ids,
+ ids = kwargs.get( 'id', [] ),
url = url,
message_type = status,
message = message )
diff -r 80e00a9cdeb0 -r df824c53f2f3 templates/grid.mako
--- a/templates/grid.mako Fri May 01 12:24:24 2009 -0400
+++ b/templates/grid.mako Fri May 01 17:19:17 2009 -0400
@@ -85,9 +85,7 @@
%endfor
</div>
-<form name="history_actions" action="${h.url_for()}" method="post" >
-
- <input type="hidden" name="sort" value="${sort_key}">
+<form name="history_actions" action="${url()}" method="post" >
<table class="grid">
<thead>
1
0
05 May '09
details: http://www.bx.psu.edu/hg/galaxy/rev/8edceee8c818
changeset: 2397:8edceee8c818
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Mon May 04 12:20:26 2009 -0400
description:
Fix closing label tags in 2 ldda_info_templates.
2 file(s) affected in this change:
templates/admin/library/ldda_info.mako
templates/library/ldda_info.mako
diffs (90 lines):
diff -r 6de7eb773877 -r 8edceee8c818 templates/admin/library/ldda_info.mako
--- a/templates/admin/library/ldda_info.mako Mon May 04 12:06:11 2009 -0400
+++ b/templates/admin/library/ldda_info.mako Mon May 04 12:20:26 2009 -0400
@@ -63,28 +63,28 @@
<div style="clear: both"></div>
</div>
<div class="form-row">
- <label>Uploaded by:</lable>
+ <label>Uploaded by:</label>
<div style="float: left; width: 250px; margin-right: 10px;">
${uploaded_by}
</div>
<div style="clear: both"></div>
</div>
<div class="form-row">
- <label>Date uploaded:</lable>
+ <label>Date uploaded:</label>
<div style="float: left; width: 250px; margin-right: 10px;">
${ldda.create_time.strftime( "%Y-%m-%d" )}
</div>
<div style="clear: both"></div>
</div>
<div class="form-row">
- <label>Build:</lable>
+ <label>Build:</label>
<div style="float: left; width: 250px; margin-right: 10px;">
${ldda.dbkey}
</div>
<div style="clear: both"></div>
</div>
<div class="form-row">
- <label>Miscellaneous information:</lable>
+ <label>Miscellaneous information:</label>
<div style="float: left; width: 250px; margin-right: 10px;">
${ldda.info}
</div>
@@ -96,7 +96,7 @@
<div class="form-row">
<div id="info${ldda.id}" class="historyItemBody">
%if ldda.peek != "no peek":
- <label>Peek:</lable>
+ <label>Peek:</label>
<div><pre id="peek${ldda.id}" class="peek">${ldda.display_peek()}</pre></div>
%endif
## Recurse for child datasets
diff -r 6de7eb773877 -r 8edceee8c818 templates/library/ldda_info.mako
--- a/templates/library/ldda_info.mako Mon May 04 12:06:11 2009 -0400
+++ b/templates/library/ldda_info.mako Mon May 04 12:20:26 2009 -0400
@@ -70,28 +70,28 @@
<div style="clear: both"></div>
</div>
<div class="form-row">
- <label>Uploaded by:</lable>
+ <label>Uploaded by:</label>
<div style="float: left; width: 250px; margin-right: 10px;">
${uploaded_by}
</div>
<div style="clear: both"></div>
</div>
<div class="form-row">
- <label>Date uploaded:</lable>
+ <label>Date uploaded:</label>
<div style="float: left; width: 250px; margin-right: 10px;">
${ldda.create_time.strftime( "%Y-%m-%d" )}
</div>
<div style="clear: both"></div>
</div>
<div class="form-row">
- <label>Build:</lable>
+ <label>Build:</label>
<div style="float: left; width: 250px; margin-right: 10px;">
${ldda.dbkey}
</div>
<div style="clear: both"></div>
</div>
<div class="form-row">
- <label>Miscellaneous information:</lable>
+ <label>Miscellaneous information:</label>
<div style="float: left; width: 250px; margin-right: 10px;">
${ldda.info}
</div>
@@ -103,7 +103,7 @@
<div class="form-row">
<div id="info${ldda.id}" class="historyItemBody">
%if ldda.peek != "no peek":
- <label>Peek:</lable>
+ <label>Peek:</label>
<div><pre id="peek${ldda.id}" class="peek">${ldda.display_peek()}</pre></div>
%endif
## Recurse for child datasets
1
0
05 May '09
details: http://www.bx.psu.edu/hg/galaxy/rev/6c76023580e3
changeset: 2398:6c76023580e3
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Tue May 05 08:29:23 2009 -0400
description:
Exclude controllers from unit tests to eliminate the broken genetrack test.
1 file(s) affected in this change:
run_unit_tests.sh
diffs (12 lines):
diff -r 8edceee8c818 -r 6c76023580e3 run_unit_tests.sh
--- a/run_unit_tests.sh Mon May 04 12:20:26 2009 -0400
+++ b/run_unit_tests.sh Tue May 05 08:29:23 2009 -0400
@@ -1,5 +1,7 @@
#!/bin/sh
+
+## Excluding controllers due to the problematic genetrack dependency
python -ES ./scripts/nosetests.py -v -w lib \
--with-nosehtml --html-report-file run_unit_tests.html \
- --with-doctest --exclude=functional --exclude="^get"
+ --with-doctest --exclude=functional --exclude="^get" --exclude=controllers
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/80e00a9cdeb0
changeset: 2394:80e00a9cdeb0
user: James Taylor <james(a)jamestaylor.org>
date: Fri May 01 12:24:24 2009 -0400
description:
Tweaking styles for quickies
1 file(s) affected in this change:
static/welcome.html
diffs (108 lines):
diff -r a9d5f8e80bcd -r 80e00a9cdeb0 static/welcome.html
--- a/static/welcome.html Fri May 01 12:24:07 2009 -0400
+++ b/static/welcome.html Fri May 01 12:24:24 2009 -0400
@@ -8,39 +8,22 @@
<style type="text/css">
.quickie {
text-align: center;
- min-height: 100px;
background: black;
+ margin: 10px;
}
.current-quickie {
width: 100%;
background: black;
}
- .quickie .head {
- font-size: 200%;
- color: white;
- padding: 20px 20px;
- }
- .quickie .sub {
- font-size: 150%;
- color: orange;
- padding: 20px 20px;
- }
.previous {
width: 100%;
overflow: auto;
+ border: solid #ccc 1px;
}
.previous .quickie {
+ padding-top: 10px;
+ min-height: 90px;
min-width: 150px;
- }
- .previous .quickie .head {
- font-size: 120%;
- padding: 10px 10px;
- text-decoration: none;
- }
- .previous .quickie .sub {
- font-size: 100%;
- padding: 10px 10px;
- text-decoration: none;
}
#screencasts {
max-width: 50em;
@@ -64,7 +47,6 @@
<div id="screencasts">
<h2>Introducing Galactic Quickies</h2>
-<hr>
<p>
Galactic quickies are <i>super-short</i> screencasts that are <i>always</i> under 5 minutes. We thought it may be a good way to spread the word about Galaxy's functionality while keeping the "annoyance factor" to the minimum. The quickies will be updated weekly.
</p>
@@ -84,35 +66,32 @@
</div>
<h3>Previous Quickies</h3>
-<hr>
-<div class="previous">
+<div class="previous" id="previous">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
- <td width="50%" style="border-right: solid white 10px; border-bottom: solid white 10px">
+ <td>
<a href="javascript:parent.show_in_overlay({url:'http://screencast.g2.bx.psu.edu/galaxy/quickie1_TabSeq/flow.html',width:640,height:500,scroll:'no'})">
<div class="quickie">
<img src="images/qk/quickie1_small.png" border="0">
</div>
</a>
</td>
- <td width="50%" style="border-left: solid white 10px; border-bottom: solid white 10px">
+ <td>
<a href="javascript:parent.show_in_overlay({url:'http://screencast.g2.bx.psu.edu/galaxy/quickie2_Grouping/flow.html',width:640,height:500,scroll:'no'})">
<div class="quickie">
<img src="images/qk/quickie2_small.png" border="0">
</div>
</a>
</td>
- </tr>
- <tr>
- <td width="50%" style="border-right: solid white 10px; border-top: solid white 10px" >
+ <td>
<a href="javascript:parent.show_in_overlay({url:'http://screencast.g2.bx.psu.edu/galaxy/quickie3_Intervals/flow.html',width:640,height:500,scroll:'no'})">
<div class="quickie">
<img src="images/qk/quickie3_small.png" border="0">
</div>
</a>
</td>
- <td width="50%" style="border-left: solid white 10px; border-top: solid white 10px" >
+ <td>
<a href="javascript:parent.show_in_overlay({url:'http://screencast.g2.bx.psu.edu/galaxy/quickie4_whatsNew/flow.html',width:640,height:500,scroll:'no'})">
<div class="quickie">
<img src="images/qk/quickie4_small.png" border="0">
@@ -123,6 +102,11 @@
</table>
</div>
+<script type="text/javascript">
+ // Scroll to last quickie in box
+ document.getElementById("previous").scrollLeft = 100000000;
+</script>
+
<br/>
<br/>
<br/>
1
0
01 May '09
details: http://www.bx.psu.edu/hg/galaxy/rev/a9d5f8e80bcd
changeset: 2393:a9d5f8e80bcd
user: James Taylor <james(a)jamestaylor.org>
date: Fri May 01 12:24:07 2009 -0400
description:
Updating packed script for workflow editor
1 file(s) affected in this change:
static/scripts/packed/galaxy.workflow_editor.canvas.js
diffs (8 lines):
diff -r 84ecf82a2ce7 -r a9d5f8e80bcd static/scripts/packed/galaxy.workflow_editor.canvas.js
--- a/static/scripts/packed/galaxy.workflow_editor.canvas.js Fri May 01 11:09:04 2009 -0400
+++ b/static/scripts/packed/galaxy.workflow_editor.canvas.js Fri May 01 12:24:07 2009 -0400
@@ -1,1 +1,1 @@
-function Terminal(a){this.element=a;this.connectors=[]}Terminal.prototype={connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}};function OutputTerminal(a,b){Terminal.call(this,a);this.datatype=b}OutputTerminal.prototype=new Terminal;function InputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}InputTerminal.prototype=new Terminal;$.extend(InputTerminal.prototype,{can_accept:function(a){if(this.connectors.length<1){for(t in this.datatypes){if(a.datatype=="input"){return true}if(issubtype(a.datatype,this.datatypes[t])){return true}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a){this.connect(b,a)
}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;this.handle1.connect(this);this.handle2=a;this.handle2.connect(this)},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var m=function(c){return $(c).offset().left-d.offset().left};var h=function(c){return $(c).offset().top-d.offset().top};var g=m(this.handle1.element)+5;var f=h(this.handle1.element)+5;var o=m(this.handle2.element)+5;var l=h(this.handle2.element)+5;var e=100;var j=Math.min(g,o);var a=Math.max(g,o);var i=Math.min(f,l);var s=Math.max(f,l);var b=Math.min(Math.max(Math.abs(s-i)/2,100),300);var n=j-e;var r=i-e;var p=a-j+2*e;var k=s-i+2*e;this.canvas.style.
left=n+"px";this.canvas.style.top=r+"px";this.canvas.setAttribute("width",p);this.canvas.setAttribute("height",k);g-=n;f-=r;o-=n;l-=r;var q=this.canvas.getContext("2d");q.lineCap="round";q.strokeStyle=this.outer_color;q.lineWidth=7;q.beginPath();q.moveTo(g,f);q.bezierCurveTo(g+b,f,o-b,l,o,l);q.stroke();q.strokeStyle=this.inner_color;q.lineWidth=5;q.beginPath();q.moveTo(g,f);q.bezierCurveTo(g+b,f,o-b,l,o,l);q.stroke()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{enable_input_terminal:function(d,a,b){var c=this;$(d).each(function(){var e=this.terminal=new InputTerminal(this,b);e.node=c;e.name=a;$(this).bind("dropstart",function(f){f.dragProxy.terminal.connectors[0].inner_color="#BBFFBB"}).bind("dropend",function(f){f.dragProxy.terminal.connectors[0].inner_color="#FFFFFF"}).bind("drop",function(f){new Connector(f.dragTarget.terminal,f.dropTarget.terminal).redraw()}).bind("hover",function(){if(e.
connectors.length>0){var f=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='buttons'></div>").append($("<img src='../images/delete_icon.png' />").click(function(){$.each(e.connectors,function(h,g){g.destroy()});f.remove()}))).bind("mouseleave",function(){$(this).remove()});f.css({top:$(this).offset().top-2,left:$(this).offset().left-f.width(),"padding-right":$(this).width()}).show()}});c.input_terminals[a]=e})},enable_output_terminal:function(d,a,b){var c=this;$(d).each(function(){var f=this;var e=this.terminal=new OutputTerminal(this,b);e.node=c;e.name=a;$(this).bind("dragstart",function(i){var g=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);g.terminal=new OutputTerminal(g);var j=new Connector();j.dragging=true;j.connect(this.terminal,g.terminal);$.dropManage({filter:function(h){return this.terminal.can_accept(e)}}).addClass("input-terminal-active");return g}).bind("drag",
function(h){var g=function(){var j=$(h.dragProxy).offsetParent().offset(),i=h.offsetX-j.left,k=h.offsetY-j.top;$(h.dragProxy).css({left:i,top:k});h.dragProxy.terminal.redraw()};g();$("#canvas-container").get(0).scroll_panel.test(h,g)}).bind("dragend",function(g){g.dragProxy.terminal.connectors[0].destroy();$(g.dragProxy).remove();$.dropManage().removeClass("input-terminal-active")});c.output_terminals[a]=e})},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(e){var d=this.ele
ment;if(e.type){this.type=e.type}this.form_html=e.form_html;this.tool_state=e.tool_state;this.tool_errors=e.tool_errors;if(this.tool_errors){d.addClass("tool-node-error")}else{d.removeClass("tool-node-error")}var c=this;var a=d.find(".toolFormBody");a.find("div").remove();var g=$("<div class='inputs'></div>").appendTo(a);$.each(e.data_inputs,function(h,b){var f=$("<div class='terminal input-terminal'></div>");c.enable_input_terminal(f,b.name,b.extensions);g.append($("<div class='form-row dataRow input-data-row' name='"+b.name+"'>"+b.label+"</div>").prepend(f))});if((e.data_inputs.length>0)&&(e.data_outputs.length>0)){a.append($("<div class='rule'></div>"))}$.each(e.data_outputs,function(j,b){var h=$("<div class='terminal output-terminal'></div>");c.enable_output_terminal(h,b.name,b.extension);var f=b.name;if(b.extension!="input"){f=f+" ("+b.extension+")"}a.append($("<div class='form-row dataRow'>"+f+"</div>").append(h))});workflow.node_changed(this)},update_field_data:functi
on(e){var c=$(this.element),d=this;this.tool_state=e.tool_state;this.form_html=e.form_html;this.tool_errors=e.tool_errors;if(this.tool_errors){c.addClass("tool-node-error")}else{c.removeClass("tool-node-error")}var f=c.find("div.inputs");var b=$("<div class='inputs'></div>");var a=f.find("div.input-data-row");$.each(e.data_inputs,function(j,g){var h=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(h,g.name,g.extensions);f.find("div[name="+g.name+"]").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){h[0].terminal.connectors[0]=i;i.handle2=h[0].terminal}});$(this).remove()});b.append($("<div class='form-row dataRow input-data-row' name='"+g.name+"'>"+g.label+"</div>").prepend(h))});f.replaceWith(b);f.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.changed();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c=
"<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},changed:function(){workflow.node_changed(this)}});function Workflow(){this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},to_simple:function(){var a={};$.each(this.nodes,function(b,d){var e={};$.each(d.input_terminals,function(f,g){e[g.name]=null;$.each(g.connectors,function(h,j){e[g.name]={id:j.handle1.node.id,output_name:j.handle1.name}})});var c={id:d.id,type:d.type,tool_id:d.tool_id,tool_state:d.tool_state,tool_errors:d.tool_errors,input_connec
tions:e,position:$(d.element).position()};a[d.id]=c});return{steps:a}},from_simple:function(a){wf=this;var b=0;wf.name=a.name;$.each(a.steps,function(e,d){var c=prebuild_node("tool",d.name,d.tool_id);c.init_field_data(d);if(d.position){c.element.css({top:d.position.top,left:d.position.left})}c.id=d.id;wf.nodes[c.id]=c;b=Math.max(b,parseInt(e))});wf.id_counter=b+1;$.each(a.steps,function(e,d){var c=wf.nodes[e];$.each(d.input_connections,function(g,f){if(f){var h=wf.nodes[f.id];var i=new Connector();i.connect(h.output_terminals[f.output_name],c.input_terminals[g]);i.redraw()}})})},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.clear_active_node();parent.show_form_for_tool(a.form_html,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){parent.show_form
_for_tool(a.form_html,a)}}});function prebuild_node(j,h,m){var g=$("<div class='toolForm toolFormInCanvas'></div>");var d=new Node(g);d.type=j;if(j=="tool"){d.tool_id=m}var l=$("<div class='toolFormTitle unselectable'>"+h+"</div>");g.append(l);g.css("left",$(window).scrollLeft()+20);g.css("top",$(window).scrollTop()+20);var k=$("<div class='toolFormBody'></div>");var e="<div><img height='16' align='middle' src='../images/loading_small_white_bg.gif'/> loading tool info...</div>";k.append(e);d.form_html=e;g.append(k);var i=$("<div class='buttons' style='float: right;'></div>");i.append($("<img src='../images/delete_icon.png' />").click(function(b){d.destroy()}).hover(function(){$(this).attr("src","../images/delete_icon_dark.png")},function(){$(this).attr("src","../images/delete_icon.png")}));g.appendTo("#canvas-container");var c=$("#canvas-container").position();g.css({left:(-c.left)+10,top:(-c.top)+10});var a=g.width();i.prependTo(l);a+=(i.width()+10);g.css("width",a);$(g).bi
nd("dragstart",function(){workflow.activate_node(d)}).bind("dragend",function(){workflow.node_changed(this)}).bind("dragclickonly",function(){workflow.activate_node(d)}).bind("drag",function(n){var f=$(this).offsetParent().offset(),b=n.offsetX-f.left,o=n.offsetY-f.top;$(this).css({left:b,top:o});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return d}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(f,c){clearTimeout(this.timeout);var a=f.pageX,g=f.pageY;b=$(this.panel),panel_pos=b.position(),panel_w=b.width(),panel_h=b.height();viewport=b.parent();viewport_w=viewport.width(),viewport_h=viewport.height(),viewport_offset=viewport.offset(),min_x=viewport_offset.left,min_y=viewport_offset.top,max_x=
min_x+viewport.width(),max_y=min_y+viewport.height(),p_min_x=-(panel_w-viewport_w),p_min_y=-(panel_h-viewport_h),p_max_x=0,p_max_y=0,moved=false,close_dist=5,nudge=23;if(a-close_dist<min_x){if(panel_pos.left<p_max_x){var d=Math.min(nudge,p_max_x-panel_pos.left);b.css("left",panel_pos.left+d);moved=true}}else{if(a+close_dist>max_x){if(panel_pos.left>p_min_x){var d=Math.min(nudge,panel_pos.left-p_min_x);b.css("left",panel_pos.left-d);moved=true}}else{if(g-close_dist<min_y){if(panel_pos.top<p_max_y){var d=Math.min(nudge,p_max_y-panel_pos.top);b.css("top",panel_pos.top+d);moved=true}}else{if(g+close_dist>max_y){if(panel_pos.top>p_min_y){var d=Math.min(nudge,panel_pos.top-p_min_x);b.css("top",(panel_pos.top-d)+"px");moved=true}}}}}if(moved){c();var b=this;this.timeout=setTimeout(function(){b.test(f,c)},50)}},drag:function(g,h){clearTimeout(this.timeout);var c=g.dragProxy,a=this.panel,b=a.position(),i=a.width(),d=a.height();viewport=a.parent();viewport_w=viewport.width(),viewport_
h=viewport.height(),element_w=c.width(),element_h=c.height(),moved=false,close_dist=5,nudge=23,p_min_x=-(i-viewport_w),p_min_y=-(d-viewport_h),p_max_x=0,p_max_y=0,min_vis_x=-b.left,max_vis_x=min_vis_x+viewport_w,min_vis_y=-b.top,max_vis_y=min_vis_y+viewport_h,mouse_x=h.position.left+instance.offset.click.left;mouse_y=h.position.top+instance.offset.click.top;if((b.left<p_max_x)&&(mouse_x-close_dist<min_vis_x)){var j=Math.min(nudge,p_max_x-b.left);a.css("left",b.left+j);moved=true;instance.offset.parent.left+=j;h.position.left-=j}if((!moved)&&(b.left>p_min_x)&&(mouse_x+close_dist>max_vis_x)){var j=Math.min(nudge,b.left-p_min_x);a.css("left",b.left-j);moved=true;instance.offset.parent.left-=j;h.position.left+=j}if((!moved)&&(b.top<p_max_y)&&(mouse_y-close_dist<min_vis_y)){var j=Math.min(nudge,p_max_y-b.top);a.css("top",b.top+j);var f=a.position().top-b.top;instance.offset.parent.top+=f;h.position.top-=f;moved=true}if((!moved)&&(b.top>p_min_y)&&(mouse_y+close_dist>max_vis_y)){va
r j=Math.min(nudge,b.top-p_min_x);a.css("top",(b.top-j)+"px");var f=b.top-a.position().top;instance.offset.parent.top-=f;h.position.top+=f;moved=true}h.position.left=Math.max(h.position.left,0);h.position.top=Math.max(h.position.top,0);h.position.left=Math.min(h.position.left,i-element_w);h.position.top=Math.min(h.position.top,d-element_h);if(moved){$.ui.ddmanager.prepareOffsets(instance,g)}if(moved){this.timeout=setTimeout(function(){instance.mouseMove(g)},50)}},stop:function(c,b){var a=$(this).data("draggable");clearTimeout(a.timeout)}});
\ No newline at end of file
+function Terminal(a){this.element=a;this.connectors=[]}Terminal.prototype={connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}};function OutputTerminal(a,b){Terminal.call(this,a);this.datatype=b}OutputTerminal.prototype=new Terminal;function InputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}InputTerminal.prototype=new Terminal;$.extend(InputTerminal.prototype,{can_accept:function(a){if(this.connectors.length<1){for(t in this.datatypes){if(a.datatype=="input"){return true}if(issubtype(a.datatype,this.datatypes[t])){return true}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a){this.connect(b,a)
}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;this.handle1.connect(this);this.handle2=a;this.handle2.connect(this)},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var o=function(c){return $(c).offset().left-d.offset().left};var j=function(c){return $(c).offset().top-d.offset().top};var i=o(this.handle1.element)+5;var g=j(this.handle1.element)+5;var q=o(this.handle2.element)+5;var n=j(this.handle2.element)+5;var f=100;var l=Math.min(i,q);var a=Math.max(i,q);var k=Math.min(g,n);var v=Math.max(g,n);var b=Math.min(Math.max(Math.abs(v-k)/2,100),300);var p=l-f;var u=k-f;var r=a-l+2*f;var m=v-k+2*f;this.canvas.style.
left=p+"px";this.canvas.style.top=u+"px";this.canvas.setAttribute("width",r);this.canvas.setAttribute("height",m);i-=p;g-=u;q-=p;n-=u;var s=this.canvas.getContext("2d");s.lineCap="round";s.strokeStyle=this.outer_color;s.lineWidth=7;s.beginPath();s.moveTo(i,g);s.bezierCurveTo(i+b,g,q-b,n,q,n);s.stroke();s.strokeStyle=this.inner_color;s.lineWidth=5;s.beginPath();s.moveTo(i,g);s.bezierCurveTo(i+b,g,q-b,n,q,n);s.stroke()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{enable_input_terminal:function(d,a,b){var c=this;$(d).each(function(){var f=this.terminal=new InputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dropstart",function(g){g.dragProxy.terminal.connectors[0].inner_color="#BBFFBB"}).bind("dropend",function(g){g.dragProxy.terminal.connectors[0].inner_color="#FFFFFF"}).bind("drop",function(g){new Connector(g.dragTarget.terminal,g.dropTarget.terminal).redraw()}).bind("hover",function(){if(f.
connectors.length>0){var g=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='buttons'></div>").append($("<img src='../images/delete_icon.png' />").click(function(){$.each(f.connectors,function(j,i){i.destroy()});g.remove()}))).bind("mouseleave",function(){$(this).remove()});g.css({top:$(this).offset().top-2,left:$(this).offset().left-g.width(),"padding-right":$(this).width()}).show()}});c.input_terminals[a]=f})},enable_output_terminal:function(d,a,b){var c=this;$(d).each(function(){var g=this;var f=this.terminal=new OutputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dragstart",function(j){var i=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);i.terminal=new OutputTerminal(i);var k=new Connector();k.dragging=true;k.connect(this.terminal,i.terminal);$.dropManage({filter:function(l){return this.terminal.can_accept(f)}}).addClass("input-terminal-active");return i}).bind("drag",
function(j){var i=function(){var l=$(j.dragProxy).offsetParent().offset(),k=j.offsetX-l.left,m=j.offsetY-l.top;$(j.dragProxy).css({left:k,top:m});j.dragProxy.terminal.redraw();canvas_manager.update_viewport_overlay()};i();$("#canvas-container").get(0).scroll_panel.test(j,i)}).bind("dragend",function(i){i.dragProxy.terminal.connectors[0].destroy();$(i.dragProxy).remove();$.dropManage().removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()});c.output_terminals[a]=f})},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b.appendChild(a)})(a.
parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(g){var d=this.element;if(g.type){this.type=g.type}this.name=g.name;this.form_html=g.form_html;this.tool_state=g.tool_state;this.tool_errors=g.tool_errors;if(this.tool_errors){d.addClass("tool-node-error")}else{d.removeClass("tool-node-error")}var c=this;var a=d.find(".toolFormBody");a.find("div").remove();var i=$("<div class='inputs'></div>").appendTo(a);$.each(g.data_inputs,function(j,b){var f=$("<div class='terminal input-terminal'></div>");c.enable_input_terminal(f,b.name,b.extensions);i.append($("<div class='form-row dataRow input-data-row' name='"+b.name+"'>"+b.label+"</div>").prepend(f))});if((g.data_inputs.length>0)&&(g.data_outputs.length>0)){a.append($("<div class='rule'></div>"))}$.each(g.data_outputs,function(k,b){var j=$("<div class='terminal output-terminal'></div>");c.enable_output_terminal(j,b.name,b.extension);var f=b.name;if(b.extension!="input"){f=f+" ("+b.extension+")"}a.append($("<d
iv class='form-row dataRow'>"+f+"</div>").append(j))});workflow.node_changed(this)},update_field_data:function(f){var c=$(this.element),d=this;this.tool_state=f.tool_state;this.form_html=f.form_html;this.tool_errors=f.tool_errors;if(this.tool_errors){c.addClass("tool-node-error")}else{c.removeClass("tool-node-error")}var g=c.find("div.inputs");var b=$("<div class='inputs'></div>");var a=g.find("div.input-data-row");$.each(f.data_inputs,function(l,j){var k=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(k,j.name,j.extensions);g.find("div[name="+j.name+"]").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){k[0].terminal.connectors[0]=i;i.handle2=k[0].terminal}});$(this).remove()});b.append($("<div class='form-row dataRow input-data-row' name='"+j.name+"'>"+j.label+"</div>").prepend(k))});g.replaceWith(b);g.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.changed(
);this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},changed:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},to_simple:function(){var a={};$.each(this.nodes,function(b,d){var f={};$.each(d.input_terminals,function(g,i){f[i.name]=null;$.each(i.connectors,function(j,k){f[i.name]={id:k.handle1.node.id,output
_name:k.handle1.name}})});var c={id:d.id,type:d.type,tool_id:d.tool_id,tool_state:d.tool_state,tool_errors:d.tool_errors,input_connections:f,position:$(d.element).position()};a[d.id]=c});return{steps:a}},from_simple:function(a){wf=this;var b=0;wf.name=a.name;$.each(a.steps,function(f,d){var c=prebuild_node("tool",d.name,d.tool_id);c.init_field_data(d);if(d.position){c.element.css({top:d.position.top,left:d.position.left})}c.id=d.id;wf.nodes[c.id]=c;b=Math.max(b,parseInt(f))});wf.id_counter=b+1;$.each(a.steps,function(f,d){var c=wf.nodes[f];$.each(d.input_connections,function(i,g){if(g){var j=wf.nodes[g.id];var l=new Connector();l.connect(j.output_terminals[g.output_name],c.input_terminals[i]);l.redraw()}})})},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.clear_active_node();parent.show_form_for_tool(a.form
_html,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){parent.show_form_for_tool(a.form_html,a)}},layout:function(){var a={};var b={};$.each(this.nodes,function(i,g){if(a[i]===undefined){a[i]=0}if(b[i]===undefined){b[i]=[]}});$.each(this.nodes,function(i,g){$.each(g.input_terminals,function(k,l){$.each(l.connectors,function(m,n){var j=n.handle1.node;a[g.id]+=1;b[j.id].push(g.id)})})});node_ids_by_level=[];while(true){level_parents=[];$.each(a,function(i,g){if(g==0){level_parents.push(i)}});if(level_parents.length==0){break}node_ids_by_level.push(level_parents);$.each(level_parents,function(i,g){delete a[g];$.each(b[g],function(k,j){a[j]-=1})})}if(a.length){return}var d=this.nodes;var c=80;v_pad=30;var f=c;$.each(node_ids_by_level,function(g,j){j.sort(function(m,i){return $(d[m].element).position().top-$(d[i].element).position().top});var k=0;var l=v_pad;$.each(j,function(i,o){var n=d[o];var m=$(n.element);$(m).css
({top:l,left:f});k=Math.max(k,$(m).width());l+=$(m).height()+v_pad});f+=k+c});$.each(d,function(g,i){i.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(i,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var j=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var i=fix_delta(a.ymin,100);d=Math.max(d,f.left);i=Math.max(i,f.top);var c=f.left-d;var g=f.top-i;var b=round_up(a.xmax+100,100)+d;var k=round_up(a.ymax+100,100)+i;b=Math.max(b,-c+j.width());k=Math.max(k,-g+j.height());this.canvas_container.css({left:c,top:g,width:b,height:k,});this.canvas_container.children().each(function(){var l=$(this).position();$(this).css("left",l.left+d);$(this).css("top",l.top+i)})}});func
tion fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(m,k,s){var j=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node(j);g.type=m;if(m=="tool"){g.tool_id=s}var q=$("<div class='toolFormTitle unselectable'>"+k+"</div>");j.append(q);j.css("left",$(window).scrollLeft()+20);j.css("top",$(window).scrollTop()+20);var n=$("<div class='toolFormBody'></div>");var i="<div><img height='16' align='middle' src='../images/loading_small_white_bg.gif'/> loading tool info...</div>";n.append(i);g.form_html=i;j.append(n);var l=$("<div class='buttons' style='float: right;'></div>");l.append($("<img src='../images/delete_icon.png' />").click(function(b){g.destroy()}).hover(function(){$(this).attr("src","../images/delete_icon_dark.png")},function(){$(this).attr("src","../images/delete_icon.png")}));j.appendTo("#canvas-container");var d=$("#canvas-container").position(
);var c=$("#canvas-container").parent();var a=j.width();var r=j.height();j.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(r/2)});l.prependTo(q);a+=(l.width()+10);j.css("width",a);$(j).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o){var f=$(this).offsetParent().offset(),b=o.offsetX-f.left,p=o.offsetY-f.top;$(this).css({left:b,top:p});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(f,c){clearTim
eout(this.timeout);var a=f.pageX,g=f.pageY;b=$(this.panel),panel_pos=b.position(),panel_w=b.width(),panel_h=b.height();viewport=b.parent();viewport_w=viewport.width(),viewport_h=viewport.height(),viewport_offset=viewport.offset(),min_x=viewport_offset.left,min_y=viewport_offset.top,max_x=min_x+viewport.width(),max_y=min_y+viewport.height(),p_min_x=-(panel_w-(viewport_w/2)),p_min_y=-(panel_h-(viewport_h/2)),p_max_x=(viewport_w/2),p_max_y=(viewport_h/2),moved=false,close_dist=5,nudge=23;if(a-close_dist<min_x){if(panel_pos.left<p_max_x){var d=Math.min(nudge,p_max_x-panel_pos.left);b.css("left",panel_pos.left+d);moved=true}}else{if(a+close_dist>max_x){if(panel_pos.left>p_min_x){var d=Math.min(nudge,panel_pos.left-p_min_x);b.css("left",panel_pos.left-d);moved=true}}else{if(g-close_dist<min_y){if(panel_pos.top<p_max_y){var d=Math.min(nudge,p_max_y-panel_pos.top);b.css("top",panel_pos.top+d);moved=true}}else{if(g+close_dist>max_y){if(panel_pos.top>p_min_y){var d=Math.min(nudge,pane
l_pos.top-p_min_x);b.css("top",(panel_pos.top-d)+"px");moved=true}}}}}if(moved){c();var b=this;this.timeout=setTimeout(function(){b.test(f,c)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(g){var i=$(this).offset();var f=b.cc.position();c=f.top-i.top;d=f.left-i.left}).bind("drag",function(f){a(f.offsetX+d,f.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("dra
g",function(l){var k=b.cc.width();var g=b.cc.height();var f=b.oc.width();var i=b.oc.height();var j=$(this).offsetParent().offset();var n=l.offsetX-j.left;var m=l.offsetY-j.top;a(-(n/f*k),-(m/i*g))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g){var j=$(this).offsetParent();var i=j.offset();var f=Math.max(j.width()-(g.offsetX-i.left),j.height()-(g.offsetY-i.top));$(this).css({width:f,height:f});b.draw_overview()})},update_viewport_overlay:function(){var b=this.cc;var f=this.cv;var a=this.oc;var c=this.ov;var d=b.width();var k=b.height();var j=a.width();var g=a.height();var i=b.position();c.css({left:-(i.left/d*j),top:-(i.top/k*g),width:(f.width()/d*j)-2,height:(f.height()/k*g)-2})},draw_overview:function(){var k=$("#overview-canvas");var n=k.parent().parent().width();var j=k.get(0).getContext("2d");var d=$("#canvas-container").width();var m=$("#canvas-container").height();var g,a,l,f;var i=this.cv.wi
dth();var b=this.cv.height();if(d<i&&m<b){l=d/i*n;f=(n-l)/2;g=m/b*n;a=(n-g)/2}else{if(d<m){a=0;g=n;l=Math.ceil(g*d/m);f=(n-l)/2}else{l=n;f=0;g=Math.ceil(l*m/d);a=(n-g)/2}}k.parent().css({left:f,top:a,width:l,height:g});k.attr("width",l);k.attr("height",g);j.fillStyle="#D2C099";j.strokeStyle="#D8B365";j.lineWidth=1;$.each(workflow.nodes,function(p,c){var o=$(c.element);position=o.position(),x=position.left/d*l,y=position.top/m*g,w=o.width()/d*l,h=o.height()/m*g;j.fillRect(x,y,w,h);j.strokeRect(x,y,w,h)});this.update_viewport_overlay()}});
\ No newline at end of file
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/84ecf82a2ce7
changeset: 2392:84ecf82a2ce7
user: Anton Nekrutenko <anton(a)bx.psu.edu>
date: Fri May 01 11:09:04 2009 -0400
description:
New quickie
3 file(s) affected in this change:
static/images/qk/quickie5_lrg.png
static/images/qk/quickie5_small.png
static/welcome.html
diffs (99 lines):
diff -r 9ad7b4abbfc7 -r 84ecf82a2ce7 static/images/qk/quickie5_lrg.png
Binary file static/images/qk/quickie5_lrg.png has changed
diff -r 9ad7b4abbfc7 -r 84ecf82a2ce7 static/images/qk/quickie5_small.png
Binary file static/images/qk/quickie5_small.png has changed
diff -r 9ad7b4abbfc7 -r 84ecf82a2ce7 static/welcome.html
--- a/static/welcome.html Fri May 01 10:11:00 2009 -0400
+++ b/static/welcome.html Fri May 01 11:09:04 2009 -0400
@@ -71,15 +71,15 @@
<div class="current-quickie">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
- <tr>
- <td align="center">
- <a href="javascript:parent.show_in_overlay({url:'http://screencast.g2.bx.psu.edu/galaxy/quickie4_whatsnew/flow.html',width:640,height:500,scroll:'no'})">
- <img src="images/qk/quickie4_lrg.png" border="0">
- <br>
- </a>
+ <tr>
+ <td align="center">
+ <a href="javascript:parent.show_in_overlay({url:'http://screencast.g2.bx.psu.edu/galaxy/quickie5_join/flow.html',width:640,height:500,scroll:'no'})">
+ <img src="images/qk/quickie5_lrg.png" border="0">
+ <br>
+ </a>
- </td>
- </tr>
+ </td>
+ </tr>
</table>
</div>
@@ -87,34 +87,40 @@
<hr>
<div class="previous">
- <table border="0" cellpadding="0" cellspacing="0" width="100%">
- <tr>
- <td width="32%" style="border-right: solid white 10px;">
- <a href="javascript:parent.show_in_overlay({url:'http://screencast.g2.bx.psu.edu/galaxy/quickie1_TabSeq/flow.html',width:640,height:500,scroll:'no'})">
- <div class="quickie">
- <img src="images/qk/quickie1_small.png" border="0">
- </div>
- </a>
- </td>
- <td width="32%" style="border-left: solid white 5px; border-right: solid white 5px">
- <a href="javascript:parent.show_in_overlay({url:'http://screencast.g2.bx.psu.edu/galaxy/quickie2_Grouping/flow.html',width:640,height:500,scroll:'no'})">
- <div class="quickie">
- <img src="images/qk/quickie2_small.png" border="0">
- </div>
- </a>
- </div>
- </td>
- <td width="32%" style="border-left: solid white 10px;" >
- <a href="javascript:parent.show_in_overlay({url:'http://screencast.g2.bx.psu.edu/galaxy/quickie3_Intervals/flow.html',width:640,height:500,scroll:'no'})">
- <div class="quickie">
- <img src="images/qk/quickie3_small.png" border="0">
- </div>
- </a>
- </td>
-
- </tr>
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr>
+ <td width="50%" style="border-right: solid white 10px; border-bottom: solid white 10px">
+ <a href="javascript:parent.show_in_overlay({url:'http://screencast.g2.bx.psu.edu/galaxy/quickie1_TabSeq/flow.html',width:640,height:500,scroll:'no'})">
+ <div class="quickie">
+ <img src="images/qk/quickie1_small.png" border="0">
+ </div>
+ </a>
+ </td>
+ <td width="50%" style="border-left: solid white 10px; border-bottom: solid white 10px">
+ <a href="javascript:parent.show_in_overlay({url:'http://screencast.g2.bx.psu.edu/galaxy/quickie2_Grouping/flow.html',width:640,height:500,scroll:'no'})">
+ <div class="quickie">
+ <img src="images/qk/quickie2_small.png" border="0">
+ </div>
+ </a>
+ </td>
+ </tr>
+ <tr>
+ <td width="50%" style="border-right: solid white 10px; border-top: solid white 10px" >
+ <a href="javascript:parent.show_in_overlay({url:'http://screencast.g2.bx.psu.edu/galaxy/quickie3_Intervals/flow.html',width:640,height:500,scroll:'no'})">
+ <div class="quickie">
+ <img src="images/qk/quickie3_small.png" border="0">
+ </div>
+ </a>
+ </td>
+ <td width="50%" style="border-left: solid white 10px; border-top: solid white 10px" >
+ <a href="javascript:parent.show_in_overlay({url:'http://screencast.g2.bx.psu.edu/galaxy/quickie4_whatsNew/flow.html',width:640,height:500,scroll:'no'})">
+ <div class="quickie">
+ <img src="images/qk/quickie4_small.png" border="0">
+ </div>
+ </a>
+ </td>
+ </tr>
</table>
-</div>
</div>
<br/>
1
0