From c245b5b6ca9aac6cbd852cd033071fd30d3bb104 Mon Sep 17 00:00:00 2001
From: James Taylor
Date: Mon, 12 Jan 2009 18:25:32 -0500
Subject: [PATCH] Changes to the 'list histories' interface. This incorporates
the changes from Assaf Gordon to display datasets by state, as well as
changing how switch / delete/ undelete work to make the interface less
disruptive. Share and rename still work as before. There is now a history
controller, and some fixes to tests to deal with that. New grid styles used
here will eventually be propogated to other data grid tables.
---
lib/galaxy/web/buildapp.py | 2 +
lib/galaxy/web/controllers/root.py | 313 +------------------
static/june_2007_style/base.css.tmpl | 67 +++-
static/june_2007_style/blue/base.css | 65 +++-
static/june_2007_style/blue/panel_layout.css | 65 +---
static/june_2007_style/make_style.py | 8 +-
static/june_2007_style/panel_layout.css.tmpl | 65 +---
static/scripts/galaxy.base.js | 16 +
templates/history/list.mako | 252 +++++++++++----
templates/history/options.mako | 8 +-
templates/history/rename.mako | 2 +-
templates/history/share.mako | 4 +-
test/base/twilltestcase.py | 27 +-
test/functional/test_history_functions.py | 10 +-
14 files changed, 384 insertions(+), 520 deletions(-)
diff --git a/lib/galaxy/web/buildapp.py b/lib/galaxy/web/buildapp.py
index a9ab866cdc2..797a4aca263 100644
--- a/lib/galaxy/web/buildapp.py
+++ b/lib/galaxy/web/buildapp.py
@@ -57,6 +57,8 @@ def app_factory( global_conf, **kwargs ):
# Create the universe WSGI application
webapp = galaxy.web.framework.WebApplication( app, session_cookie='galaxysession' )
add_controllers( webapp, app )
+ # Force /history to go to /root/history -- needed since the tests assume this
+ webapp.add_route( '/history', controller='root', action='history' )
# These two routes handle our simple needs at the moment
webapp.add_route( '/async/:tool_id/:data_id/:data_secret', controller='async', action='index', tool_id=None, data_id=None, data_secret=None )
webapp.add_route( '/:controller/:action', action='index' )
diff --git a/lib/galaxy/web/controllers/root.py b/lib/galaxy/web/controllers/root.py
index e6abee11d59..faa2dd2540b 100644
--- a/lib/galaxy/web/controllers/root.py
+++ b/lib/galaxy/web/controllers/root.py
@@ -371,128 +371,13 @@ class RootController( BaseController ):
"""Displays a list of history related actions"""
return trans.fill_template( "/history/options.mako",
user = trans.get_user(), history = trans.get_history() )
-
+
@web.expose
- def history_delete( self, trans, id=None, **kwd):
- """Deletes a list of histories, ensures that histories are owned by current user"""
- if trans.app.memory_usage:
- # Keep track of memory usage
- m0 = self.app.memory_usage.memory()
- history_names = []
- if id:
- if isinstance( id, list ):
- history_ids = id
- else:
- history_ids = [ id ]
- user = trans.get_user()
- for hid in history_ids:
- try:
- int( hid )
- except:
- return trans.show_message( "Invalid history: %s" % str( hid ) )
- history = self.app.model.History.get( hid )
- if history:
- if history.user_id != None and user:
- assert user.id == history.user_id, "History does not belong to current user"
- # Delete DefaultHistoryPermissions
- for dhp in history.default_permissions:
- dhp.delete()
- dhp.flush()
- # Mark history as deleted in db
- history.deleted = True
- history_names.append(history.name)
- # If deleting the current history, make a new current.
- if history == trans.get_history():
- trans.new_history()
- else:
- return trans.show_message( "Not able to find history %s" % str( hid ) )
- self.app.model.flush()
- trans.log_event( "History id %s marked as deleted" % str(hid) )
- else:
- return trans.show_message( "You must select at least one history to delete." )
- if self.app.memory_usage:
- m1 = trans.app.memory_usage.memory( m0, pretty=True )
- log.info( "End of root/history_delete, memory used increased by %s" % m1 )
- return trans.show_message( "History deleted: %s" % ",".join(history_names),
- refresh_frames=['history'])
-
- @web.expose
- def history_undelete( self, trans, id=[], **kwd):
- """Undeletes a list of histories, ensures that histories are owned by current user"""
- history_names = []
- errors = []
- ok_msg = ""
- if id:
- if not isinstance( id, list ):
- id = id.split( "," )
- user = trans.get_user()
- for hid in id:
- try:
- int( hid )
- except:
- errors.append( "Invalid history: %s" % str( hid ) )
- continue
- history = self.app.model.History.get( hid )
- if history:
- if history.user != user:
- errors.append( "History does not belong to current user." )
- continue
- if history.purged:
- errors.append( "History has already been purged and can not be undeleted." )
- continue
- history_names.append( history.name )
- history.deleted = False
- else:
- errors.append( "Not able to find history %s." % str( hid ) )
- trans.log_event( "History id %s marked as undeleted" % str(hid) )
- self.app.model.flush()
- if history_names:
- ok_msg = "Histories (%s) have been undeleted." % ", ".join( history_names )
- else:
- errors.append( "You must select at least one history to undelete." )
- return self.history_available( trans, id=','.join( id ), show_deleted=True, ok_msg = ok_msg, error_msg = " ".join( errors ) )
-
- @web.expose
- def history_undelete( self, trans, id=[], **kwd):
- """Undeletes a list of histories, ensures that histories are owned by current user"""
- if trans.app.memory_usage:
- # Keep track of memory usage
- m0 = self.app.memory_usage.memory()
- history_names = []
- errors = []
- ok_msg = ""
- if id:
- if not isinstance( id, list ):
- id = id.split( "," )
- user = trans.get_user()
- for hid in id:
- try:
- int( hid )
- except:
- errors.append( "Invalid history: %s" % str( hid ) )
- continue
- history = self.app.model.History.get( hid )
- if history:
- if history.user != user:
- errors.append( "History does not belong to current user." )
- continue
- if history.purged:
- errors.append( "History has already been purged and can not be undeleted." )
- continue
- history_names.append( history.name )
- history.deleted = False
- else:
- errors.append( "Not able to find history %s." % str( hid ) )
- trans.log_event( "History id %s marked as undeleted" % str(hid) )
- self.app.model.flush()
- if history_names:
- ok_msg = "Histories (%s) have been undeleted." % ", ".join( history_names )
- else:
- errors.append( "You must select at least one history to undelete." )
- if self.app.memory_usage:
- m1 = trans.app.memory_usage.memory( m0, pretty=True )
- log.info( "End of root/history_undelete, memory used increased by %s" % m1 )
- return self.history_available( trans, id=','.join( id ), show_deleted=True, ok_msg = ok_msg, error_msg = " ".join( errors ) )
+ def history_delete( self, trans, id ):
+ """
+ Backward compatibility with check_galaxy script.
+ """
+ return trans.webapp.controllers['history'].list( trans, id, operation='delete' )
@web.expose
def clear_history( self, trans ):
@@ -510,117 +395,6 @@ class RootController( BaseController ):
m1 = trans.app.memory_usage.memory( m0, pretty=True )
log.info( "End of root/clear_history, memory used increased by %s" % m1 )
trans.response.send_redirect( url_for("/index" ) )
-
- @web.expose
- @web.require_login( "share histories with other users" )
- def history_share( self, trans, id=None, email="", **kwd ):
- send_to_err = ""
- if not id:
- id = trans.get_history().id
- if not isinstance( id, list ):
- id = [ id ]
- histories = []
- history_names = []
- for hid in id:
- histories.append( trans.app.model.History.get( hid ) )
- history_names.append(histories[-1].name)
- if not email:
- return trans.fill_template("/history/share.mako", histories=histories, email=email, send_to_err=send_to_err)
- user = trans.get_user()
- send_to_user = trans.app.model.User.filter( trans.app.model.User.table.c.email==email ).first()
- params = util.Params( kwd )
- action = params.get( 'action', None )
- if action == "no_share":
- trans.response.send_redirect( url_for( action='history_options' ) )
- if not send_to_user:
- send_to_err = "No such user"
- elif user.email == email:
- send_to_err = "You can't send histories to yourself"
- else:
- if 'history_share_btn' in kwd or action != 'share':
- # The user is attempting to share a history whose datasets cannot all be accessed by the other user. In this case,
- # the user sharing the history can chose to make the datasets public ( action == 'public' ) if he has the authority
- # to do so, or automatically create a new "sharing role" that allows the user to share his private datasets only with the
- # desired user ( action == 'private' ).
- can_change = {}
- cannot_change = {}
- for history in histories:
- for hda in history.activatable_datasets:
- # Only deal with datasets that have not been purged
- if not trans.app.security_agent.allow_action( send_to_user,
- trans.app.security_agent.permitted_actions.DATASET_ACCESS,
- dataset=hda ):
- # The user with which we are sharing the history does not have access permission on the current dataset
- if trans.app.security_agent.allow_action( user,
- trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS,
- dataset=hda ) and not hda.dataset.library_associations:
- # The current user has authority to change permissions on the current dataset because
- # they have permission to manage permissions on the dataset and the dataset is not associated
- # with a library.
- if action == "private":
- trans.app.security_agent.privately_share_dataset( hda.dataset, users=[ user, send_to_user ] )
- elif action == "public":
- trans.app.security_agent.make_dataset_public( hda.dataset )
- elif history not in can_change:
- # Build the set of histories / datasets on which the current user has authority
- # to "manage permissions". This is used in /history/share.mako
- can_change[ history ] = [ hda ]
- else:
- can_change[ history ].append( hda )
- else:
- if action in [ "private", "public" ]:
- # Don't change stuff that the user doesn't have permission to change
- continue
- elif history not in cannot_change:
- # Build the set of histories / datasets on which the current user does
- # not have authority to "manage permissions". This is used in /history/share.mako
- cannot_change[ history ] = [ hda ]
- else:
- cannot_change[ history ].append( hda )
- if can_change or cannot_change:
- return trans.fill_template( "/history/share.mako",
- histories=histories,
- email=email,
- send_to_err=send_to_err,
- can_change=can_change,
- cannot_change=cannot_change )
- for history in histories:
- new_history = history.copy( target_user=send_to_user )
- new_history.name = history.name + " from " + user.email
- new_history.user_id = send_to_user.id
- trans.log_event( "History share, id: %s, name: '%s': to new id: %s" % ( str( history.id ), history.name, str( new_history.id ) ) )
- self.app.model.flush()
- return trans.show_message( "History (%s) has been shared with: %s" % ( ",".join( history_names ),email ) )
- return trans.fill_template( "/history/share.mako", histories=histories, email=email, send_to_err=send_to_err )
-
- @web.expose
- @web.require_login( "work with multiple histories" )
- def history_available( self, trans, id=[], do_operation = "view", show_deleted = False, ok_msg = "", error_msg="", as_xml=False, **kwd ):
- """
- List all available histories
- """
- if trans.app.memory_usage:
- # Keep track of memory usage
- m0 = self.app.memory_usage.memory()
- if as_xml:
- trans.response.set_content_type('text/xml')
- return trans.fill_template( "/history/list_as_xml.mako" )
- if not isinstance( id, list ):
- id = id.split( "," )
- trans.log_event( "History id %s available" % str( id ) )
- history_operations = dict( share=self.history_share, rename=self.history_rename, delete=self.history_delete, undelete=self.history_undelete )
- if self.app.memory_usage:
- m1 = trans.app.memory_usage.memory( m0, pretty=True )
- log.info( "End of root/history_available, memory used increased by %s" % m1 )
- if do_operation in history_operations:
- return history_operations[do_operation]( trans, id=id, show_deleted=show_deleted, ok_msg=ok_msg, error_msg=error_msg, **kwd )
- return trans.fill_template( "/history/list.mako", ids=id,
- user=trans.get_user(),
- current_history=trans.get_history(),
- show_deleted=util.string_as_bool( show_deleted ),
- ok_msg=ok_msg, error_msg=error_msg )
-
-
@web.expose
def history_import( self, trans, id=None, confirm=False, **kwd ):
@@ -677,34 +451,6 @@ class RootController( BaseController ):
Warning! If you import this history, you will lose your current
history. Click here to confirm.
""" % web.url_for( id=id, confirm=True ) )
-
- @web.expose
- @web.require_login( "switch histories" )
- def history_switch( self, trans, id=None ):
- if not id:
- return trans.response.send_redirect( web.url_for( action='history_available' ) )
- else:
- if trans.app.memory_usage:
- # Keep track of memory usage
- m0 = self.app.memory_usage.memory()
- new_history = trans.app.model.History.get( id )
- if new_history:
- 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 switched to id: %s, name: '%s'" % (str(new_history.id), new_history.name ) )
- if self.app.memory_usage:
- m1 = trans.app.memory_usage.memory( m0, pretty=True )
- log.info( "End of root/history_switch, memory used increased by %s" % m1 )
- return trans.show_message( "History switched to: %s" % new_history.name,
- refresh_frames=['history'])
- else:
- return trans.show_error_message( "History not found" )
@web.expose
def history_new( self, trans ):
@@ -718,53 +464,6 @@ class RootController( BaseController ):
log.info( "End of root/history_new, memory used increased by %s" % m1 )
return trans.show_message( "New history created", refresh_frames = ['history'] )
- @web.expose
- @web.require_login( "renames histories" )
- def history_rename( self, trans, id=None, name=None, **kwd ):
- if trans.app.memory_usage:
- # Keep track of memory usage
- m0 = self.app.memory_usage.memory()
- user = trans.get_user()
-
- if not isinstance( id, list ):
- if id != None:
- id = [ id ]
- if not isinstance( name, list ):
- if name != None:
- name = [ name ]
- histories = []
- cur_names = []
- if not id:
- if not trans.get_history().user:
- return trans.show_error_message( "You must save your history before renaming it." )
- id = [trans.get_history().id]
- for history_id in id:
- history = trans.app.model.History.get( history_id )
- if history and history.user_id == user.id:
- histories.append(history)
- cur_names.append(history.name)
- if not name or len(histories)!=len(name):
- return trans.fill_template( "/history/rename.mako",histories=histories )
- change_msg = ""
- for i in range(len(histories)):
- if histories[i].user_id == user.id:
- if name[i] == histories[i].name:
- change_msg = change_msg + "History: "+cur_names[i]+" is already named: "+name[i]+"
"
- elif name[i] not in [None,'',' ']:
- name[i] = escape(name[i])
- histories[i].name = name[i]
- histories[i].flush()
- change_msg = change_msg + "History: "+cur_names[i]+" renamed to: "+name[i]+"
"
- trans.log_event( "History renamed: id: %s, renamed to: '%s'" % (str(histories[i].id), name[i] ) )
- else:
- change_msg = change_msg + "You must specify a valid name for History: "+cur_names[i]+"
"
- else:
- change_msg = change_msg + "History: "+cur_names[i]+" does not appear to belong to you.
"
- if self.app.memory_usage:
- m1 = trans.app.memory_usage.memory( m0, pretty=True )
- log.info( "End of root/history_rename, memory used increased by %s" % m1 )
- return trans.show_message( "%s" % change_msg, refresh_frames=['history'] )
-
@web.expose
def history_add_to( self, trans, history_id=None, file_data=None, name="Data Added to History",info=None,ext="txt",dbkey="?",copy_access_from=None,**kwd ):
"""Adds a POSTed file to a History"""
diff --git a/static/june_2007_style/base.css.tmpl b/static/june_2007_style/base.css.tmpl
index b780a8acda6..fc06c2008ff 100644
--- a/static/june_2007_style/base.css.tmpl
+++ b/static/june_2007_style/base.css.tmpl
@@ -142,6 +142,7 @@ div.form-row label
select, input, textarea
{
+ font: inherit;
font-size: 115%;
}
@@ -444,6 +445,30 @@ ul.manage-table-actions li {
margin-left: 0.5em;
}
+## State colors
+
+.state-color-queued {
+ border-color: $history_queued_border;
+ background: $history_queued_bg;
+}
+
+.state-color-ok {
+ border-color: $history_ok_border;
+ background: $history_ok_bg;
+}
+
+.state-color-error {
+ border-color: $history_error_border;
+ background: $history_error_bg;
+}
+
+.state-color-running {
+ border-color: $history_running_border;
+ background: $history_running_bg;
+}
+
+## Button styles
+
.action-button {
background: #eeeeee;
color: #333;
@@ -459,6 +484,9 @@ ul.manage-table-actions li {
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
border-radius: 0.5em;
+ user-select: none;
+ -moz-user-select: none;
+ -webkit-user-select: none;
}
.action-button > * {
@@ -467,13 +495,15 @@ ul.manage-table-actions li {
.action-button:hover {
color: black;
- background: #aaaaaa;
+ background: #dddddd;
}
.action-button:active {
color: white;
background: #aaaaaa;
}
+## Popup menu styles
+
div.popupmenu {
display: none;
background: #eeeeee;
@@ -488,6 +518,9 @@ div.popupmenu {
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
border-radius: 0.5em;
+ user-select: none;
+ -moz-user-select: none;
+ -webkit-user-select: none;
}
div.popupmenu-item {
@@ -515,3 +548,35 @@ div.popupmenu-item:hover {
div.permissionContainer {
padding-left: 20px;
}
+
+## Data grid style
+
+.grid {
+ padding-top: 1em;
+ border-collapse: collapse;
+ width: 100%;
+}
+.grid tbody td {
+ border-top: solid #DDDDDD 1px;
+ border-bottom: solid #DDDDDD 1px;
+ padding: 0.5em 1em;
+}
+.grid thead th {
+ background: $table_header_bg;
+ background-image: url(form_title_bg.png);
+ background-repeat: repeat-x;
+ background-position: top;
+ border-top: solid $table_border 1px;
+ border-bottom: solid $table_border 1px;
+ padding: 0.5em 1em;
+ text-align: left;
+}
+.grid tfoot td {
+ background-color: #F8F8F8;
+ border-top: solid #DDDDDD 1px;
+ border-bottom: solid #DDDDDD 1px;
+ padding: 0.5em 1em;
+}
+.grid .current {
+ background-color: #EEEEFF;
+}
\ No newline at end of file
diff --git a/static/june_2007_style/blue/base.css b/static/june_2007_style/blue/base.css
index 173f0d6dfa4..2962cfb40b2 100644
--- a/static/june_2007_style/blue/base.css
+++ b/static/june_2007_style/blue/base.css
@@ -142,6 +142,7 @@ div.form-row label
select, input, textarea
{
+ font: inherit;
font-size: 115%;
}
@@ -152,7 +153,7 @@ select, textarea, input[type="text"], input[type="file"]
/* Messages */
-.errormessage, .warningmessage, .donemessage, .infomessage, .welcomeBlue, .welcomeRed, .screencastBox, .yellowbox, .redbox, .bluebox, .greenbox
+.errormessage, .warningmessage, .donemessage, .infomessage, .welcomeBlue, .welcomeRed , .screencastBox, .yellowbox, .redbox, .bluebox, .greenbox
{
padding: 10px;
padding-left: 52px;
@@ -443,6 +444,28 @@ ul.manage-table-actions li {
margin-left: 0.5em;
}
+
+.state-color-queued {
+ border-color: #888888;
+ background: #EEEEEE;
+}
+
+.state-color-ok {
+ border-color: #66AA66;
+ background: #CCFFCC;
+}
+
+.state-color-error {
+ border-color: #AA6666;
+ background: #FFCCCC;
+}
+
+.state-color-running {
+ border-color: #AAAA66;
+ background: #FFFFCC;
+}
+
+
.action-button {
background: #eeeeee;
color: #333;
@@ -458,6 +481,9 @@ ul.manage-table-actions li {
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
border-radius: 0.5em;
+ user-select: none;
+ -moz-user-select: none;
+ -webkit-user-select: none;
}
.action-button > * {
@@ -466,13 +492,14 @@ ul.manage-table-actions li {
.action-button:hover {
color: black;
- background: #aaaaaa;
+ background: #dddddd;
}
.action-button:active {
color: white;
background: #aaaaaa;
}
+
div.popupmenu {
display: none;
background: #eeeeee;
@@ -487,6 +514,9 @@ div.popupmenu {
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
border-radius: 0.5em;
+ user-select: none;
+ -moz-user-select: none;
+ -webkit-user-select: none;
}
div.popupmenu-item {
@@ -514,3 +544,34 @@ div.popupmenu-item:hover {
div.permissionContainer {
padding-left: 20px;
}
+
+
+.grid {
+ padding-top: 1em;
+ border-collapse: collapse;
+ width: 100%;
+}
+.grid tbody td {
+ border-top: solid #DDDDDD 1px;
+ border-bottom: solid #DDDDDD 1px;
+ padding: 0.5em 1em;
+}
+.grid thead th {
+ background: #ebd9b2;
+ background-image: url(form_title_bg.png);
+ background-repeat: repeat-x;
+ background-position: top;
+ border-top: solid #d8b365 1px;
+ border-bottom: solid #d8b365 1px;
+ padding: 0.5em 1em;
+ text-align: left;
+}
+.grid tfoot td {
+ background-color: #F8F8F8;
+ border-top: solid #DDDDDD 1px;
+ border-bottom: solid #DDDDDD 1px;
+ padding: 0.5em 1em;
+}
+.grid .current {
+ background-color: #EEEEFF;
+}
\ No newline at end of file
diff --git a/static/june_2007_style/blue/panel_layout.css b/static/june_2007_style/blue/panel_layout.css
index 7dda79706a8..e48f52009af 100644
--- a/static/june_2007_style/blue/panel_layout.css
+++ b/static/june_2007_style/blue/panel_layout.css
@@ -131,31 +131,6 @@ body
right: 0px;
z-index: 200;
}
-td.panel-header
-{
- background: #f5f5f5;
- background-image: url(panel_header_bg.png);
- background-position: top center;
- background-repeat: repeat-x;
- padding: 0;
- border-bottom: solid #999 1px;
-}
-div.panel-header
-{
- margin: 0;
- padding: 4px;
- padding-right: 10px;
- padding-left: 10px;
- color: #333;
- font-weight: bold;
-}
-
-table.column-layout
-{
- position: absolute;
- width: 100%;
- height: 100%;
-}
.unified-panel-header {
height: 2em;
@@ -171,6 +146,9 @@ table.column-layout
padding-left: 10px;
color: #333;
font-weight: bold;
+ user-select: none;
+ -moz-user-select: none;
+ -webkit-user-select: none;
}
.unified-panel-header-inner {
@@ -214,43 +192,6 @@ div.unified-panel-body {
background: #aaaaaa;
}
-div.popupmenu {
- display: none;
- background: #eee;
- position: fixed;
- z-index: 20000;
- background: #cccccc;
- background-image: url(panel_header_bg.png);
- background-position: top center;
- background-repeat: repeat-x;
- border: solid #999 1px;
- padding-top: 3px;
- padding-bottom: 3px;
-}
-
-div.popupmenu-top {
- padding-bottom: 3px;
-}
-div.popupmenu-top-inner {
- height: 10px;
- width: 20px;
- margin-top: -13px;
- margin-left: auto;
- margin-right: 20px;
- background: url(popupmenu_callout_top.png);
-}
-
-div.popupmenu-item {
- padding: 3px;
- padding-left: 10px;
- padding-right: 10px;
- cursor: pointer;
-}
-
-div.popupmenu-item:hover {
- background: #AAAAEE;
-}
-
#overlay {
position: fixed;
top: 0; left: 0; width: 100%; height: 100%;
diff --git a/static/june_2007_style/make_style.py b/static/june_2007_style/make_style.py
index f3a6a08503a..5d62c7f1f56 100755
--- a/static/june_2007_style/make_style.py
+++ b/static/june_2007_style/make_style.py
@@ -1,11 +1,11 @@
#!/usr/bin/env python
-from galaxy import eggs
-import pkg_resources
-pkg_resources.require("Cheetah")
+#from galaxy import eggs
+#import pkg_resources
+#pkg_resources.require("Cheetah")
import sys, string, os.path
-from galaxy import eggs
+#from galaxy import eggs
import pkg_resources
pkg_resources.require( "Cheetah" )
diff --git a/static/june_2007_style/panel_layout.css.tmpl b/static/june_2007_style/panel_layout.css.tmpl
index 4df44dba18a..016b228a0e0 100644
--- a/static/june_2007_style/panel_layout.css.tmpl
+++ b/static/june_2007_style/panel_layout.css.tmpl
@@ -131,31 +131,6 @@ body
right: 0px;
z-index: 200;
}
-td.panel-header
-{
- background: ${panel_header_bg_top};
- background-image: url(panel_header_bg.png);
- background-position: top center;
- background-repeat: repeat-x;
- padding: 0;
- border-bottom: solid ${layout_border} 1px;
-}
-div.panel-header
-{
- margin: 0;
- padding: 4px;
- padding-right: 10px;
- padding-left: 10px;
- color: #333;
- font-weight: bold;
-}
-
-table.column-layout
-{
- position: absolute;
- width: 100%;
- height: 100%;
-}
.unified-panel-header {
height: 2em;
@@ -171,6 +146,9 @@ table.column-layout
padding-left: 10px;
color: #333;
font-weight: bold;
+ user-select: none;
+ -moz-user-select: none;
+ -webkit-user-select: none;
}
.unified-panel-header-inner {
@@ -214,43 +192,6 @@ div.unified-panel-body {
background: #aaaaaa;
}
-div.popupmenu {
- display: none;
- background: #eee;
- position: fixed;
- z-index: 20000;
- background: ${panel_header_bg_bottom};
- background-image: url(panel_header_bg.png);
- background-position: top center;
- background-repeat: repeat-x;
- border: solid ${layout_border} 1px;
- padding-top: 3px;
- padding-bottom: 3px;
-}
-
-div.popupmenu-top {
- padding-bottom: 3px;
-}
-div.popupmenu-top-inner {
- height: 10px;
- width: 20px;
- margin-top: -13px;
- margin-left: auto;
- margin-right: 20px;
- background: url(popupmenu_callout_top.png);
-}
-
-div.popupmenu-item {
- padding: 3px;
- padding-left: 10px;
- padding-right: 10px;
- cursor: pointer;
-}
-
-div.popupmenu-item:hover {
- background: ${layout_hover};
-}
-
#overlay {
position: fixed;
top: 0; left: 0; width: 100%; height: 100%;
diff --git a/static/scripts/galaxy.base.js b/static/scripts/galaxy.base.js
index a14244dcac8..f343c31269a 100644
--- a/static/scripts/galaxy.base.js
+++ b/static/scripts/galaxy.base.js
@@ -1,3 +1,19 @@
+$.fn.makeAbsolute = function(rebase) {
+ return this.each(function() {
+ var el = $(this);
+ var pos = el.position();
+ el.css({
+ position: "absolute",
+ marginLeft: 0, marginTop: 0,
+ top: pos.top, left: pos.left,
+ right: $(window).width() - ( pos.left + el.width() )
+ });
+ if (rebase) {
+ el.remove().appendTo("body");
+ }
+ });
+}
+
jQuery(document).ready( function() {
// Links with confirmation
jQuery( "a[@confirm]" ).click( function() {
diff --git a/templates/history/list.mako b/templates/history/list.mako
index a30e5c5f7c2..a5de3273c68 100644
--- a/templates/history/list.mako
+++ b/templates/history/list.mako
@@ -1,65 +1,201 @@
<%inherit file="/base.mako"/>
<%def name="title()">Your saved histories%def>
-%if error_msg:
-
-
${error_msg}
-
-
-%endif
-%if ok_msg:
-
-
${ok_msg}
-
-
+%if message:
+
+
${message}
+
+
%endif
-%if user.histories:
- Stored Histories
- %if show_deleted:
-
- %else:
-
- %endif
-