[hg] galaxy 3600: Make visualizations (a) importable and (b) emb...
details: http://www.bx.psu.edu/hg/galaxy/rev/146eae852b97 changeset: 3600:146eae852b97 user: jeremy goecks <jeremy.goecks@emory.edu> date: Fri Apr 02 11:10:23 2010 -0400 description: Make visualizations (a) importable and (b) embeddable in pages. Still need to add code for displaying visualizations in pages. diffstat: lib/galaxy/web/base/controller.py | 2 +- lib/galaxy/web/controllers/page.py | 35 +++++++++++++++- lib/galaxy/web/controllers/visualization.py | 63 ++++++++++++++++++++++++++++- lib/galaxy/web/controllers/workflow.py | 4 - static/june_2007_style/blue/embed_item.css | 2 + static/june_2007_style/embed_item.css.tmpl | 10 ++++ templates/page/editor.mako | 32 ++++++++++++-- templates/visualization/embed.mako | 4 + 8 files changed, 140 insertions(+), 12 deletions(-) diffs (337 lines): diff -r b07142ce9dbb -r 146eae852b97 lib/galaxy/web/base/controller.py --- a/lib/galaxy/web/base/controller.py Thu Apr 01 22:48:57 2010 -0400 +++ b/lib/galaxy/web/base/controller.py Fri Apr 02 11:10:23 2010 -0400 @@ -178,7 +178,7 @@ if not visualization: error( "Visualization not found" ) else: - return self.security_check( trans.get_user(), stored, check_ownership, check_accessible ) + return self.security_check( trans.get_user(), visualization, check_ownership, check_accessible ) class UsesStoredWorkflow( SharableItemSecurity ): """ Mixin for controllers that use StoredWorkflow objects. """ diff -r b07142ce9dbb -r 146eae852b97 lib/galaxy/web/controllers/page.py --- a/lib/galaxy/web/controllers/page.py Thu Apr 01 22:48:57 2010 -0400 +++ b/lib/galaxy/web/controllers/page.py Fri Apr 02 11:10:23 2010 -0400 @@ -186,6 +186,25 @@ key="free-text-search", visible=False, filterable="standard" ) ) +class VisualizationSelectionGrid( ItemSelectionGrid ): + """ Grid for selecting visualizations. """ + # Grid definition. + title = "Saved Visualizations" + model_class = model.Visualization + columns = [ + grids.TextColumn( "Title", key="title", model_class=model.Visualization, filterable="advanced" ), + grids.TextColumn( "Type", key="type", model_class=model.Visualization ), + grids.IndividualTagsColumn( "Tags", "tags", model.Visualization, model.VisualizationTagAssociation, filterable="advanced", grid_name="VisualizationListGrid" ), + grids.SharingStatusColumn( "Sharing", key="sharing", model_class=model.Visualization, filterable="advanced", sortable=False ), + grids.GridColumn( "Last Updated", key="update_time", format=time_ago ), + ] + columns.append( + grids.MulticolFilterColumn( + "Search", + cols_to_filter=[ columns[0], columns[2] ], + key="free-text-search", visible=False, filterable="standard" ) + ) + class _PageContentProcessor( _BaseHTMLProcessor ): """ Processes page content to produce HTML that is suitable for display. For now, processor renders embedded objects. """ @@ -249,7 +268,7 @@ # Default behavior: _BaseHTMLProcessor.unknown_endtag( self, tag ) -class PageController( BaseController, Sharable, UsesAnnotations, UsesHistory, UsesStoredWorkflow, UsesHistoryDatasetAssociation ): +class PageController( BaseController, Sharable, UsesAnnotations, UsesHistory, UsesStoredWorkflow, UsesHistoryDatasetAssociation, UsesVisualization ): _page_list = PageListGrid() _all_published_list = PageAllPublishedGrid() @@ -257,6 +276,7 @@ _workflow_selection_grid = WorkflowSelectionGrid() _datasets_selection_grid = HistoryDatasetAssociationSelectionGrid() _page_selection_grid = PageSelectionGrid() + _visualization_selection_grid = VisualizationSelectionGrid() @web.expose @web.require_login() @@ -626,6 +646,13 @@ return self._workflow_selection_grid( trans, **kwargs ) @web.expose + @web.require_login("select a visualization from saved visualizations") + def list_visualizations_for_selection( self, trans, **kwargs ): + """ Returns HTML that enables a user to select one or more visualizations. """ + # Render the list view + return self._visualization_selection_grid( trans, **kwargs ) + + @web.expose @web.require_login("select a page from saved pages") def list_pages_for_selection( self, trans, **kwargs ): """ Returns HTML that enables a user to select one or more pages. """ @@ -685,6 +712,12 @@ if workflow: self.get_stored_workflow_steps( trans, workflow ) return trans.fill_template( "workflow/embed.mako", item=workflow, item_data=workflow.latest_workflow.steps ) + elif item_class == model.Visualization: + visualization = self.get_visualization( trans, item_id, False, True ) + visualization.annotation = self.get_item_annotation_str( trans.sa_session, visualization.user, visualization ) + if visualization: + return trans.fill_template( "visualization/embed.mako", item=visualization, item_data=None ) + elif item_class == model.Page: pass diff -r b07142ce9dbb -r 146eae852b97 lib/galaxy/web/controllers/visualization.py --- a/lib/galaxy/web/controllers/visualization.py Thu Apr 01 22:48:57 2010 -0400 +++ b/lib/galaxy/web/controllers/visualization.py Fri Apr 02 11:10:23 2010 -0400 @@ -73,6 +73,12 @@ else: # Render grid wrapped in panels return trans.fill_template( "visualization/list_published.mako", grid=grid ) + + @web.expose + @web.require_login( "use Galaxy visualizations", use_panels=True ) + def index( self, trans, *args, **kwargs ): + """ Lists user's saved visualizations. """ + return self.list( trans, args, kwargs ) @web.expose @web.require_login( "use Galaxy visualizations", use_panels=True ) @@ -110,6 +116,61 @@ visualization.slug = new_slug trans.sa_session.flush() return visualization.slug + + @web.expose + @web.require_login( "use Galaxy visualizations" ) + def set_accessible_async( self, trans, id=None, accessible=False ): + """ Set visualization's importable attribute and slug. """ + visualization = self.get_visualization( trans, id ) + + # Only set if importable value would change; this prevents a change in the update_time unless attribute really changed. + importable = accessible in ['True', 'true', 't', 'T']; + if visualization and visualization.importable != importable: + if importable: + self._make_item_accessible( trans.sa_session, visualization ) + else: + visualization.importable = importable + trans.sa_session.flush() + + return + + @web.expose + @web.require_login( "share Galaxy visualizations" ) + def imp( self, trans, id ): + """ Import a visualization into user's workspace. """ + # Set referer message. + referer = trans.request.referer + if referer is not "": + referer_message = "<a href='%s'>return to the previous page</a>" % referer + else: + referer_message = "<a href='%s'>go to Galaxy's start page</a>" % url_for( '/' ) + + # Do import. + session = trans.sa_session + visualization = self.get_visualization( trans, id, check_ownership=False ) + if visualization.importable == False: + return trans.show_error_message( "The owner of this visualization has disabled imports via this link.<br>You can %s" % referer_message, use_panels=True ) + elif visualization.user == trans.user: + return trans.show_error_message( "You can't import this visualization because you own it.<br>You can %s" % referer_message, use_panels=True ) + elif visualization.deleted: + return trans.show_error_message( "You can't import this visualization because it has been deleted.<br>You can %s" % referer_message, use_panels=True ) + else: + # Create imported visualization via copy. TODO: Visualizations use datasets -- do we need to check to ensure that + # datasets can be imported/viewed and/or copy datasets to user? + imported_visualization = model.Visualization() + imported_visualization.title = "imported: " + visualization.title + imported_visualization.latest_revision = visualization.latest_revision + imported_visualization.user = trans.user + # Save new visualization. + session = trans.sa_session + session.add( imported_visualization ) + session.flush() + + # Redirect to load galaxy frames. + return trans.show_ok_message( + message="""Visualization "%s" has been imported. <br>You can <a href="%s">start using this visualization</a> or %s.""" + % ( visualization.title, web.url_for( controller='visualization' ), referer_message ), use_panels=True ) + @web.expose @web.require_login( "share Galaxy visualizations" ) @@ -214,7 +275,7 @@ @web.require_login("get item content asynchronously") def get_item_content_async( self, trans, id ): """ Returns item content in HTML format. """ - pass + return "TODO: visualization content" @web.expose @web.require_login( "create visualizations" ) diff -r b07142ce9dbb -r 146eae852b97 lib/galaxy/web/controllers/workflow.py --- a/lib/galaxy/web/controllers/workflow.py Thu Apr 01 22:48:57 2010 -0400 +++ b/lib/galaxy/web/controllers/workflow.py Fri Apr 02 11:10:23 2010 -0400 @@ -294,10 +294,6 @@ return trans.show_error_message( "You can't import this workflow because you own it.<br>You can %s" % referer_message, use_panels=True ) elif stored.deleted: return trans.show_error_message( "You can't import this workflow because it has been deleted.<br>You can %s" % referer_message, use_panels=True ) - elif session.query( model.StoredWorkflowUserShareAssociation ) \ - .filter_by( user=trans.user, stored_workflow=stored ).count() > 0: - # TODO: this is only reasonable as long as import creates a sharing relation. - return trans.show_error_message( "You can't import this workflow because it is already shared with you.<br>You can %s" % referer_message, use_panels=True ) else: # Create imported workflow via copy. imported_stored = model.StoredWorkflow() diff -r b07142ce9dbb -r 146eae852b97 static/june_2007_style/blue/embed_item.css --- a/static/june_2007_style/blue/embed_item.css Thu Apr 01 22:48:57 2010 -0400 +++ b/static/june_2007_style/blue/embed_item.css Fri Apr 02 11:10:23 2010 -0400 @@ -6,6 +6,8 @@ .embedded-item.dataset p{background:#CFC no-repeat 2px 2px;margin-top:0;margin-bottom:0;} .embedded-item.workflow{background-color:#FBDDB3} .embedded-item.workflow p{background:#FBDDB3 no-repeat 2px 2px;margin-top:0;margin-bottom:0;} +.embedded-item.visualization{background-color:#BBBBBB} +.embedded-item.visualization p{background:#BBBBBB no-repeat 2px 2px;margin-top:0;margin-bottom:0;} .embedded-item.placeholder{} .embedded-item .item-content{max-height:25em;overflow:auto;display:none;} .embedded-item .title{vertical-align:top;text-align:center;font-weight:bold;} diff -r b07142ce9dbb -r 146eae852b97 static/june_2007_style/embed_item.css.tmpl --- a/static/june_2007_style/embed_item.css.tmpl Thu Apr 01 22:48:57 2010 -0400 +++ b/static/june_2007_style/embed_item.css.tmpl Fri Apr 02 11:10:23 2010 -0400 @@ -41,6 +41,16 @@ margin-bottom:0; } +.embedded-item.visualization { + background-color:#BBBBBB +} + +.embedded-item.visualization p { + background:#BBBBBB no-repeat 2px 2px; + margin-top:0; + margin-bottom:0; +} + .embedded-item.placeholder{} .embedded-item .item-content { diff -r b07142ce9dbb -r 146eae852b97 templates/page/editor.mako --- a/templates/page/editor.mako Thu Apr 01 22:48:57 2010 -0400 +++ b/templates/page/editor.mako Fri Apr 02 11:10:23 2010 -0400 @@ -34,18 +34,21 @@ ITEM_DATASET : "item_dataset", ITEM_WORKFLOW : "item_workflow", ITEM_PAGE : "item_page", + ITEM_VISUALIZATION : "item_visualization", // Link dialogs. DIALOG_HISTORY_LINK : "link_history", DIALOG_DATASET_LINK : "link_dataset", DIALOG_WORKFLOW_LINK : "link_workflow", DIALOG_PAGE_LINK : "link_page", + DIALOG_VISUALIZATION_LINK : "link_visualization", // Embed dialogs. DIALOG_EMBED_HISTORY : "embed_history", DIALOG_EMBED_DATASET : "embed_dataset", DIALOG_EMBED_WORKFLOW : "embed_workflow", DIALOG_EMBED_PAGE : "embed_page", + DIALOG_EMBED_VISUALIZATION : "embed_visualization", // Annotation dialogs. DIALOG_HISTORY_ANNOTATE : "history_annotate", @@ -101,6 +104,11 @@ item_plural = "Pages"; item_controller = "page"; item_class = "Page"; + case( Galaxy.ITEM_VISUALIZATION ): + item_singular = "Visualization"; + item_plural = "Visualizations"; + item_controller = "visualization"; + item_class = "Visualization"; break; } @@ -316,9 +324,10 @@ ); } - // INSERT "GALAXY ITEM" (HISTORY, DATASET, WORKFLOW, PAGE) LINK DIALOG + // INSERT "GALAXY ITEM" LINK DIALOG if ( dialogType == Galaxy.DIALOG_HISTORY_LINK || dialogType == Galaxy.DIALOG_DATASET_LINK || - dialogType == Galaxy.DIALOG_WORKFLOW_LINK || dialogType == Galaxy.DIALOG_PAGE_LINK ) { + dialogType == Galaxy.DIALOG_WORKFLOW_LINK || dialogType == Galaxy.DIALOG_PAGE_LINK || + dialogType == Galaxy.DIALOG_VISUALIZATION_LINK ) { // Based on item type, set useful vars. var item_info; switch(dialogType) @@ -335,6 +344,9 @@ case(Galaxy.DIALOG_PAGE_LINK): item_info = get_item_info(Galaxy.ITEM_PAGE); break; + case(Galaxy.DIALOG_VISUALIZATION_LINK): + item_info = get_item_info(Galaxy.ITEM_VISUALIZATION); + break; } $.ajax( @@ -405,7 +417,7 @@ }); } // EMBED GALAXY OBJECT DIALOGS - if ( dialogType == Galaxy.DIALOG_EMBED_HISTORY || dialogType == Galaxy.DIALOG_EMBED_DATASET || dialogType == Galaxy.DIALOG_EMBED_WORKFLOW || dialogType == Galaxy.DIALOG_EMBED_PAGE ) { + if ( dialogType == Galaxy.DIALOG_EMBED_HISTORY || dialogType == Galaxy.DIALOG_EMBED_DATASET || dialogType == Galaxy.DIALOG_EMBED_WORKFLOW || dialogType == Galaxy.DIALOG_EMBED_PAGE || dialogType == Galaxy.DIALOG_EMBED_VISUALIZATION ) { // Based on item type, set useful vars. var item_info; switch(dialogType) @@ -422,6 +434,9 @@ case(Galaxy.DIALOG_EMBED_PAGE): item_info = get_item_info(Galaxy.ITEM_PAGE); break; + case(Galaxy.DIALOG_EMBED_VISUALIZATION): + item_info = get_item_info(Galaxy.ITEM_VISUALIZATION); + break; } $.ajax( @@ -432,7 +447,8 @@ success: function(list_html) { // Can make histories, workflows importable; cannot make datasets importable. - if (dialogType == Galaxy.DIALOG_EMBED_HISTORY || dialogType == Galaxy.DIALOG_EMBED_WORKFLOW) + if (dialogType == Galaxy.DIALOG_EMBED_HISTORY || dialogType == Galaxy.DIALOG_EMBED_WORKFLOW + || dialogType == Galaxy.DIALOG_EMBED_VISUALIZATION) list_html = list_html + "<div><input id='make-importable' type='checkbox' checked/>" + "Make the selected " + item_info.plural.toLowerCase() + " accessible so that they can viewed by everyone.</div>"; show_modal( @@ -687,7 +703,10 @@ }, "Insert Page Link": function() { editor.dialog(Galaxy.DIALOG_PAGE_LINK); - } + }, + "Insert Visualization Link": function() { + editor.dialog(Galaxy.DIALOG_VISUALIZATION_LINK); + }, }); // @@ -709,6 +728,9 @@ "Embed Workflow": function() { editor.dialog(Galaxy.DIALOG_EMBED_WORKFLOW); }, + "Embed Visualization": function() { + editor.dialog(Galaxy.DIALOG_EMBED_VISUALIZATION); + }, ##"Embed Page": function() { ## editor.dialog(Galaxy.DIALOG_EMBED_PAGE); ##} diff -r b07142ce9dbb -r 146eae852b97 templates/visualization/embed.mako --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/visualization/embed.mako Fri Apr 02 11:10:23 2010 -0400 @@ -0,0 +1,4 @@ +<%inherit file="/embed_base.mako"/> + +<%def name="render_summary_content( workflow, steps )"> +</%def>
participants (1)
-
Greg Von Kuster