galaxy-commits
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
October 2013
- 1 participants
- 226 discussions
9 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/0eafcb644470/
Changeset: 0eafcb644470
Branch: next-stable
User: dannon
Date: 2013-10-21 22:23:43
Summary: Strip unused data_provider_registry
Affected #: 1 file
diff -r 81880a04e6e79d944a6d9c225b36417114cd38ec -r 0eafcb6444701fb40339ee6918a3d33fdf4a0479 lib/galaxy/webapps/galaxy/api/datasets.py
--- a/lib/galaxy/webapps/galaxy/api/datasets.py
+++ b/lib/galaxy/webapps/galaxy/api/datasets.py
@@ -101,7 +101,6 @@
# If there is a chrom, check for data on the chrom.
if chrom:
- data_provider_registry = trans.app.data_provider_registry
data_provider = trans.app.data_provider_registry.get_data_provider( trans,
original_dataset=dataset, source='index' )
if not data_provider.has_data( chrom ):
https://bitbucket.org/galaxy/galaxy-central/commits/86912262ab6f/
Changeset: 86912262ab6f
Branch: next-stable
User: dannon
Date: 2013-10-21 22:40:30
Summary: Expose dataset api anonymously -- this reflects the behavior one expects in the web interface, delegating permission enforcement to the backend
Affected #: 1 file
diff -r 0eafcb6444701fb40339ee6918a3d33fdf4a0479 -r 86912262ab6f47a9019556731940d0cde19f7b99 lib/galaxy/webapps/galaxy/api/datasets.py
--- a/lib/galaxy/webapps/galaxy/api/datasets.py
+++ b/lib/galaxy/webapps/galaxy/api/datasets.py
@@ -23,7 +23,7 @@
trans.response.status = 501
return 'not implemented'
- @web.expose_api
+ @web.expose_api_anonymous
def show( self, trans, id, hda_ldda='hda', data_type=None, provider=None, **kwd ):
"""
GET /api/datasets/{encoded_dataset_id}
@@ -243,7 +243,7 @@
return data
- @web.expose_api_raw
+ @web.expose_api_raw_anonymous
def display( self, trans, history_content_id, history_id,
preview=False, filename=None, to_ext=None, chunk=None, **kwd ):
"""
https://bitbucket.org/galaxy/galaxy-central/commits/bf169fb107cc/
Changeset: bf169fb107cc
Branch: next-stable
User: dannon
Date: 2013-10-21 22:41:04
Summary: Add decorator for exposing via the api both anonymously and raw -- to be refactored later
Affected #: 1 file
diff -r 86912262ab6f47a9019556731940d0cde19f7b99 -r bf169fb107cc441fbefbf01544764d87fa6e2af1 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py
+++ b/lib/galaxy/web/framework/__init__.py
@@ -110,6 +110,14 @@
"""
return expose_api( func, to_json=False )
+#DBTODO refactor these post-dist.
+def expose_api_raw_anonymous( func ):
+ """
+ Expose this function via the API but don't dump the results
+ to JSON.
+ """
+ return expose_api( func, to_json=False, user_required=False )
+
def expose_api_anonymous( func, to_json=True ):
"""
Expose this function via the API but don't require a set user.
https://bitbucket.org/galaxy/galaxy-central/commits/e9a6c1738ffc/
Changeset: e9a6c1738ffc
Branch: next-stable
User: dannon
Date: 2013-10-21 23:31:09
Summary: Add expose_api_raw_anonymous to galaxy/web package
Affected #: 1 file
diff -r bf169fb107cc441fbefbf01544764d87fa6e2af1 -r e9a6c1738ffc3dab035f5c2eb01b99c57fe77aa5 lib/galaxy/web/__init__.py
--- a/lib/galaxy/web/__init__.py
+++ b/lib/galaxy/web/__init__.py
@@ -13,4 +13,5 @@
from framework import expose_api
from framework import expose_api_anonymous
from framework import expose_api_raw
+from framework import expose_api_raw_anonymous
from framework.base import httpexceptions
https://bitbucket.org/galaxy/galaxy-central/commits/902bf096a4aa/
Changeset: 902bf096a4aa
User: dannon
Date: 2013-10-21 23:31:50
Summary: Merge next-stable to default
Affected #: 3 files
diff -r 6882fa888d10b469524669325a547a2c0f6c7e41 -r 902bf096a4aa1be446676d178ac5f6db4e5b558f lib/galaxy/web/__init__.py
--- a/lib/galaxy/web/__init__.py
+++ b/lib/galaxy/web/__init__.py
@@ -13,4 +13,5 @@
from framework import expose_api
from framework import expose_api_anonymous
from framework import expose_api_raw
+from framework import expose_api_raw_anonymous
from framework.base import httpexceptions
diff -r 6882fa888d10b469524669325a547a2c0f6c7e41 -r 902bf096a4aa1be446676d178ac5f6db4e5b558f lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py
+++ b/lib/galaxy/web/framework/__init__.py
@@ -110,6 +110,14 @@
"""
return expose_api( func, to_json=False )
+#DBTODO refactor these post-dist.
+def expose_api_raw_anonymous( func ):
+ """
+ Expose this function via the API but don't dump the results
+ to JSON.
+ """
+ return expose_api( func, to_json=False, user_required=False )
+
def expose_api_anonymous( func, to_json=True ):
"""
Expose this function via the API but don't require a set user.
diff -r 6882fa888d10b469524669325a547a2c0f6c7e41 -r 902bf096a4aa1be446676d178ac5f6db4e5b558f lib/galaxy/webapps/galaxy/api/datasets.py
--- a/lib/galaxy/webapps/galaxy/api/datasets.py
+++ b/lib/galaxy/webapps/galaxy/api/datasets.py
@@ -23,7 +23,7 @@
trans.response.status = 501
return 'not implemented'
- @web.expose_api
+ @web.expose_api_anonymous
def show( self, trans, id, hda_ldda='hda', data_type=None, provider=None, **kwd ):
"""
GET /api/datasets/{encoded_dataset_id}
@@ -101,7 +101,6 @@
# If there is a chrom, check for data on the chrom.
if chrom:
- data_provider_registry = trans.app.data_provider_registry
data_provider = trans.app.data_provider_registry.get_data_provider( trans,
original_dataset=dataset, source='index' )
if not data_provider.has_data( chrom ):
@@ -244,7 +243,7 @@
return data
- @web.expose_api_raw
+ @web.expose_api_raw_anonymous
def display( self, trans, history_content_id, history_id,
preview=False, filename=None, to_ext=None, chunk=None, **kwd ):
"""
https://bitbucket.org/galaxy/galaxy-central/commits/bb8975aafcd9/
Changeset: bb8975aafcd9
User: dannon
Date: 2013-10-21 23:32:06
Summary: Merge with central
Affected #: 29 files
diff -r 902bf096a4aa1be446676d178ac5f6db4e5b558f -r bb8975aafcd91ca055ab5aa64a7b8e6a866f8cce lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -633,11 +633,11 @@
# if a tool declares 'force_history_refresh' in its xml, when the hda -> ready, reload the history panel
# expensive
- if( ( hda.state in [ 'running', 'queued' ] )
- and ( hda.creating_job and hda.creating_job.tool_id ) ):
- tool_used = trans.app.toolbox.get_tool( hda.creating_job.tool_id )
- if tool_used and tool_used.force_history_refresh:
- hda_dict[ 'force_history_refresh' ] = True
+ #if( ( hda.state in [ 'running', 'queued' ] )
+ #and ( hda.creating_job and hda.creating_job.tool_id ) ):
+ # tool_used = trans.app.toolbox.get_tool( hda.creating_job.tool_id )
+ # if tool_used and tool_used.force_history_refresh:
+ # hda_dict[ 'force_history_refresh' ] = True
return trans.security.encode_dict_ids( hda_dict )
@@ -653,13 +653,14 @@
'accessible': False
})
- def get_hda_dict_with_error( self, trans, hda, error_msg='' ):
+ def get_hda_dict_with_error( self, trans, hda=None, history_id=None, id=None, error_msg='Error' ):
return trans.security.encode_dict_ids({
- 'id' : hda.id,
- 'history_id': hda.history.id,
- 'hid' : hda.hid,
- 'name' : hda.name,
- 'error' : error_msg
+ 'id' : hda.id if hda else id,
+ 'history_id': hda.history.id if hda else history_id,
+ 'hid' : hda.hid if hda else '(unknown)',
+ 'name' : hda.name if hda else '(unknown)',
+ 'error' : error_msg,
+ 'state' : trans.model.Dataset.states.NEW
})
def get_display_apps( self, trans, hda ):
diff -r 902bf096a4aa1be446676d178ac5f6db4e5b558f -r bb8975aafcd91ca055ab5aa64a7b8e6a866f8cce lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -97,6 +97,9 @@
# Most recent active history for user sessions, not deleted
history = trans.user.galaxy_sessions[0].histories[-1].history
+ elif history_id == "current":
+ history = trans.get_history( create=True )
+
else:
history = self.get_history( trans, history_id, check_ownership=False,
check_accessible=True, deleted=deleted )
@@ -110,7 +113,7 @@
except Exception, e:
msg = "Error in history API at showing history detail: %s" % ( str( e ) )
- log.exception( msg, exc_info=True )
+ log.exception( e )
trans.response.status = 500
return msg
@@ -174,7 +177,8 @@
trans.sa_session.add( new_history )
trans.sa_session.flush()
- item = new_history.to_dict(view='element', value_mapper={'id':trans.security.encode_id})
+ #item = new_history.to_dict(view='element', value_mapper={'id':trans.security.encode_id})
+ item = self.get_history_dict( trans, new_history )
item['url'] = url_for( 'history', id=item['id'] )
#TODO: possibly default to True here - but favor explicit for now (and backwards compat)
diff -r 902bf096a4aa1be446676d178ac5f6db4e5b558f -r bb8975aafcd91ca055ab5aa64a7b8e6a866f8cce lib/galaxy/webapps/galaxy/api/history_contents.py
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -59,22 +59,21 @@
encoded_hda_id = trans.security.encode_id( hda.id )
if encoded_hda_id in ids:
#TODO: share code with show
- try:
- hda_dict = self.get_hda_dict( trans, hda )
- hda_dict[ 'display_types' ] = self.get_old_display_applications( trans, hda )
- hda_dict[ 'display_apps' ] = self.get_display_apps( trans, hda )
- rval.append( hda_dict )
-
- except Exception, exc:
- # don't fail entire list if hda err's, record and move on
- log.error( "Error in history API at listing contents with history %s, hda %s: (%s) %s",
- history_id, encoded_hda_id, type( exc ), str( exc ), exc_info=True )
- rval.append( self.get_hda_dict_with_error( trans, hda, str( exc ) ) )
+ rval.append( self._detailed_hda_dict( trans, hda ) )
# if no ids passed, return a _SUMMARY_ of _all_ datasets in the history
else:
+ details = kwd.get( 'details', None ) or []
+ if details and details != 'all':
+ details = util.listify( details )
+
for hda in history.datasets:
- rval.append( self._summary_hda_dict( trans, history_id, hda ) )
+ encoded_hda_id = trans.security.encode_id( hda.id )
+ if( ( encoded_hda_id in details )
+ or ( details == 'all' ) ):
+ rval.append( self._detailed_hda_dict( trans, hda ) )
+ else:
+ rval.append( self._summary_hda_dict( trans, history_id, hda ) )
except Exception, e:
# for errors that are not specific to one hda (history lookup or summary list)
@@ -85,7 +84,7 @@
return rval
#TODO: move to model or Mixin
- def _summary_hda_dict( self, trans, history_id, hda ):
+ def _summary_hda_dict( self, trans, encoded_history_id, hda ):
"""
Returns a dictionary based on the HDA in summary form::
{
@@ -99,11 +98,32 @@
encoded_id = trans.security.encode_id( hda.id )
return {
'id' : encoded_id,
+ 'history_id' : encoded_history_id,
'name' : hda.name,
'type' : api_type,
- 'url' : url_for( 'history_content', history_id=history_id, id=encoded_id, ),
+ 'state' : hda.state,
+ 'deleted': hda.deleted,
+ 'visible': hda.visible,
+ 'hid' : hda.hid,
+ 'url' : url_for( 'history_content', history_id=encoded_history_id, id=encoded_id, ),
}
+ def _detailed_hda_dict( self, trans, hda ):
+ """
+ Detailed dictionary of hda values.
+ """
+ try:
+ hda_dict = self.get_hda_dict( trans, hda )
+ hda_dict[ 'display_types' ] = self.get_old_display_applications( trans, hda )
+ hda_dict[ 'display_apps' ] = self.get_display_apps( trans, hda )
+ return hda_dict
+
+ except Exception, exc:
+ # catch error here - returning a briefer hda_dict with an error attribute
+ log.exception( "Error in history API at listing contents with history %s, hda %s: (%s) %s",
+ hda.history_id, hda.id, type( exc ), str( exc ) )
+ return self.get_hda_dict_with_error( trans, hda=hda, error_msg=str( exc ) )
+
@web.expose_api_anonymous
def show( self, trans, id, history_id, **kwd ):
"""
@@ -244,7 +264,7 @@
trans.response.status = 501
return
- @web.expose_api
+ @web.expose_api_anonymous
def update( self, trans, history_id, id, payload, **kwd ):
"""
update( self, trans, history_id, id, payload, **kwd )
@@ -269,10 +289,28 @@
#TODO: PUT /api/histories/{encoded_history_id} payload = { rating: rating } (w/ no security checks)
changed = {}
try:
- hda = self.get_dataset( trans, id,
- check_ownership=True, check_accessible=True, check_state=True )
- # validation handled here and some parsing, processing, and conversion
- payload = self._validate_and_parse_update_payload( payload )
+ # anon user
+ if trans.user == None:
+ if history_id != trans.security.encode_id( trans.history.id ):
+ trans.response.status = 401
+ return { 'error': 'Anonymous users cannot edit histories other than their current history' }
+
+ anon_allowed_payload = {}
+ if 'deleted' in payload:
+ anon_allowed_payload[ 'deleted' ] = payload[ 'deleted' ]
+ if 'visible' in payload:
+ anon_allowed_payload[ 'visible' ] = payload[ 'visible' ]
+
+ payload = self._validate_and_parse_update_payload( anon_allowed_payload )
+ hda = self.get_dataset( trans, id, check_ownership=False, check_accessible=False, check_state=True )
+ if hda.history != trans.history:
+ trans.response.status = 401
+ return { 'error': 'Anonymous users cannot edit datasets outside their current history' }
+
+ else:
+ payload = self._validate_and_parse_update_payload( payload )
+ hda = self.get_dataset( trans, id, check_ownership=True, check_accessible=True, check_state=True )
+
# additional checks here (security, etc.)
changed = self.set_hda_from_dict( trans, hda, payload )
diff -r 902bf096a4aa1be446676d178ac5f6db4e5b558f -r bb8975aafcd91ca055ab5aa64a7b8e6a866f8cce lib/galaxy/webapps/galaxy/controllers/root.py
--- a/lib/galaxy/webapps/galaxy/controllers/root.py
+++ b/lib/galaxy/webapps/galaxy/controllers/root.py
@@ -5,7 +5,7 @@
import os
import urllib
-from paste.httpexceptions import HTTPNotFound
+from paste.httpexceptions import HTTPNotFound, HTTPBadGateway
from galaxy import web
from galaxy.web import url_for
@@ -30,7 +30,8 @@
@web.expose
def index(self, trans, id=None, tool_id=None, mode=None, workflow_id=None, m_c=None, m_a=None, **kwd):
- """Called on the root url to display the main Galaxy page.
+ """
+ Called on the root url to display the main Galaxy page.
"""
return trans.fill_template( "root/index.mako",
tool_id=tool_id,
@@ -99,63 +100,75 @@
show_deleted=string_as_bool( show_deleted ),
show_hidden=string_as_bool( show_hidden ) )
- @web.expose
- def history( self, trans, as_xml=False, show_deleted=None, show_hidden=None, hda_id=None, **kwd ):
- """Display the current history, creating a new history if necessary.
-
- NOTE: No longer accepts "id" or "template" options for security reasons.
- """
- if as_xml:
- return self.history_as_xml( trans,
- show_deleted=string_as_bool( show_deleted ), show_hidden=string_as_bool( show_hidden ) )
-
- # get all datasets server-side, client-side will get flags and render appropriately
- show_deleted = string_as_bool_or_none( show_deleted )
- show_purged = show_deleted
- show_hidden = string_as_bool_or_none( show_hidden )
- params = Params( kwd )
- message = params.get( 'message', '' )
- #TODO: ugh...
- message = message if message != 'None' else ''
- status = params.get( 'status', 'done' )
-
- if trans.app.config.require_login and not trans.user:
- return trans.fill_template( '/no_access.mako', message = 'Please log in to access Galaxy histories.' )
-
- def err_msg( where=None ):
- where = where if where else 'getting the history data from the server'
- err_msg = ( 'An error occurred %s. '
- + 'Please contact a Galaxy administrator if the problem persists.' ) %( where )
- return err_msg, 'error'
-
+ def _get_current_history_data( self, trans ):
history_dictionary = {}
hda_dictionaries = []
+
try:
history = trans.get_history( create=True )
hdas = self.get_history_datasets( trans, history,
show_deleted=True, show_hidden=True, show_purged=True )
for hda in hdas:
+ hda_dict = {}
try:
- hda_dictionaries.append( self.get_hda_dict( trans, hda ) )
+ hda_dict = self.get_hda_dict( trans, hda )
except Exception, exc:
# don't fail entire list if hda err's, record and move on
log.error( 'Error bootstrapping hda %d: %s', hda.id, str( exc ), exc_info=True )
- hda_dictionaries.append( self.get_hda_dict_with_error( trans, hda, str( exc ) ) )
+ hda_dict = self.get_hda_dict_with_error( trans, hda, str( exc ) )
+
+ hda_dictionaries.append( hda_dict )
# re-use the hdas above to get the history data...
history_dictionary = self.get_history_dict( trans, history, hda_dictionaries=hda_dictionaries )
except Exception, exc:
user_id = str( trans.user.id ) if trans.user else '(anonymous)'
- log.error( 'Error bootstrapping history for user %s: %s', user_id, str( exc ), exc_info=True )
- message, status = err_msg()
+ log.exception( 'Error bootstrapping history for user %s: %s', user_id, str( exc ) )
+ message = ( 'An error occurred getting the history data from the server. '
+ + 'Please contact a Galaxy administrator if the problem persists.' )
history_dictionary[ 'error' ] = message
- return trans.stream_template_mako( "root/history.mako",
- history_json = to_json_string( history_dictionary ), hda_json = to_json_string( hda_dictionaries ),
- show_deleted=show_deleted, show_hidden=show_hidden, hda_id=hda_id, log=log, message=message, status=status )
+ return {
+ 'history' : history_dictionary,
+ 'hdas' : hda_dictionaries
+ }
+
+ @web.expose
+ def history( self, trans, as_xml=False, show_deleted=None, show_hidden=None, **kwd ):
+ """
+ Display the current history in it's own page or as xml.
+ """
+ if as_xml:
+ return self.history_as_xml( trans,
+ show_deleted=string_as_bool( show_deleted ), show_hidden=string_as_bool( show_hidden ) )
+
+ if trans.app.config.require_login and not trans.user:
+ return trans.fill_template( '/no_access.mako', message = 'Please log in to access Galaxy histories.' )
+
+ # get all datasets server-side, client-side will get flags and render appropriately
+ show_deleted = string_as_bool_or_none( show_deleted )
+ show_purged = show_deleted
+ show_hidden = string_as_bool_or_none( show_hidden )
+
+ history_dictionary = {}
+ hda_dictionaries = []
+ try:
+ history_data = self._get_current_history_data( trans )
+ history_dictionary = history_data[ 'history' ]
+ hda_dictionaries = history_data[ 'hdas' ]
+
+ except Exception, exc:
+ user_id = str( trans.user.id ) if trans.user else '(anonymous)'
+ log.exception( 'Error bootstrapping history for user %s: %s', user_id, str( exc ) )
+ history_dictionary[ 'error' ] = ( 'An error occurred getting the history data from the server. '
+ + 'Please contact a Galaxy administrator if the problem persists.' )
+
+ return trans.fill_template_mako( "root/history.mako",
+ history = history_dictionary, hdas = hda_dictionaries,
+ show_deleted=show_deleted, show_hidden=show_hidden )
## ---- Dataset display / editing ----------------------------------------
@web.expose
@@ -503,7 +516,22 @@
return rval
@web.expose
- def generate_error( self, trans ):
+ def generate_error( self, trans, code=500 ):
"""Raises an exception (debugging).
"""
+ trans.response.status = code
raise Exception( "Fake error!" )
+
+ @web.json
+ def generate_json_error( self, trans, code=500 ):
+ """Raises an exception (debugging).
+ """
+ try:
+ code = int( code )
+ except Exception, exc:
+ code = 500
+
+ if code == 502:
+ raise HTTPBadGateway()
+ trans.response.status = code
+ return { 'error': 'Fake error!' }
diff -r 902bf096a4aa1be446676d178ac5f6db4e5b558f -r bb8975aafcd91ca055ab5aa64a7b8e6a866f8cce lib/galaxy/webapps/galaxy/controllers/tool_runner.py
--- a/lib/galaxy/webapps/galaxy/controllers/tool_runner.py
+++ b/lib/galaxy/webapps/galaxy/controllers/tool_runner.py
@@ -325,4 +325,5 @@
<p><b>Please do not use your browser\'s "stop" or "reload" buttons until the upload is complete, or it may be interrupted.</b></p><p>You may safely continue to use Galaxy while the upload is in progress. Using "stop" and "reload" on pages other than Galaxy is also safe.</p>
"""
+ #return trans.show_message( msg, refresh_frames=[ 'history' ] )
return trans.show_message( msg )
diff -r 902bf096a4aa1be446676d178ac5f6db4e5b558f -r bb8975aafcd91ca055ab5aa64a7b8e6a866f8cce static/scripts/mvc/base-mvc.js
--- a/static/scripts/mvc/base-mvc.js
+++ b/static/scripts/mvc/base-mvc.js
@@ -7,31 +7,30 @@
name: null,
hidden: false
},
-
+
show: function() {
this.set("hidden", false);
},
-
+
hide: function() {
this.set("hidden", true);
},
-
+
is_visible: function() {
return !this.attributes.hidden;
}
});
-
/**
* Base view that handles visibility based on model's hidden attribute.
*/
var BaseView = Backbone.View.extend({
-
+
initialize: function() {
this.model.on("change:hidden", this.update_visible, this);
this.update_visible();
},
-
+
update_visible: function() {
if( this.model.attributes.hidden ){
this.$el.hide();
@@ -120,7 +119,8 @@
// ~constants for the current engine
var STORAGE_ENGINE = sessionStorage,
STORAGE_ENGINE_GETTER = function sessionStorageGet( key ){
- return JSON.parse( this.getItem( key ) );
+ var item = this.getItem( key );
+ return ( item !== null )?( JSON.parse( this.getItem( key ) ) ):( null );
},
STORAGE_ENGINE_SETTER = function sessionStorageSet( key, val ){
return this.setItem( key, JSON.stringify( val ) );
@@ -182,7 +182,7 @@
}
//??: more readable to make another class?
- var returnedStorage = {};
+ var returnedStorage = {},
// attempt to get starting data from engine...
data = STORAGE_ENGINE_GETTER.call( STORAGE_ENGINE, storageKey );
@@ -216,3 +216,63 @@
return returnedStorage;
};
+
+
+//==============================================================================
+function LoadingIndicator( $where ){
+ var self = this,
+ $indicator;
+
+ function setPosition(){
+ // even tho pos is 'fixed' - give illusion of width 100% and margin by manually setting width, offset
+ var padding = 4,
+ width = $indicator.parent().width() || $where.width(),
+ offset = $indicator.parent().offset() || $where.offset();
+
+ $indicator.outerWidth( width - ( padding * 2 ) );
+ // have to use css top, left and not offset (wont work when indicator is hidden)
+ $indicator.css({ top: offset.top + padding + 'px' , left: offset.left + padding + 'px' });
+ }
+
+ function render(){
+ var $spinner = $( '<span class="fa-icon-spinner fa-icon-spin fa-icon-large"></span>')
+ .css({ 'color' : 'grey', 'font-size' : '16px' });
+ var $message = $( '<i>loading...</i>' )
+ .css({ 'color' : 'grey', 'margin-left' : '8px' });
+ $indicator = $( '<div/>' ).addClass( 'loading-indicator' )
+ .css({
+ 'position' : 'fixed',
+ 'padding' : '4px',
+ 'text-align' : 'center',
+ 'background-color' : 'white',
+ 'opacity' : '0.85',
+ 'border-radius' : '3px'
+ })
+ .append( $spinner, $message )
+ //NOTE: insert as sibling to $where
+ .insertBefore( $where );
+ setPosition();
+ return $indicator.hide();
+ }
+
+ self.show = function( speed, callback ){
+ speed = speed || 'fast';
+ setPosition();
+ $indicator.fadeIn( speed, callback );
+ // not using full fadeOut allows using scroll to still work
+ //$whatIsLoading.fadeTo( speed, 0.0001, callback );
+ return self;
+ };
+
+ self.hide = function( speed, callback ){
+ speed = speed || 'fast';
+ //$whatIsLoading.fadeTo( speed, 1.0, function(){
+ // if( callback ){ callback(); }
+ //});
+ $indicator.fadeOut( speed, callback );
+ return self;
+ };
+ $indicator = render();
+ return self;
+}
+
diff -r 902bf096a4aa1be446676d178ac5f6db4e5b558f -r bb8975aafcd91ca055ab5aa64a7b8e6a866f8cce static/scripts/mvc/dataset/hda-base.js
--- a/static/scripts/mvc/dataset/hda-base.js
+++ b/static/scripts/mvc/dataset/hda-base.js
@@ -1,7 +1,6 @@
-//define([
-// "../mvc/base-mvc"
-//], function(){
-
+define([
+ "mvc/dataset/hda-model"
+], function( hdaModel ){
/* global Backbone, LoggableMixin, HistoryDatasetAssociation, HDABaseView */
//==============================================================================
/** @class Read only view for HistoryDatasetAssociation.
@@ -22,6 +21,8 @@
tagName : "div",
className : "historyItemContainer",
+ fxSpeed : 'fast',
+
// ......................................................................... SET UP
/** Set up the view, cache url templates, bind listeners
* @param {Object} attributes
@@ -38,33 +39,20 @@
this._render_showParamsButton
];
- // cache urlTemplates (gen. provided by GalaxyPaths) to urls
- if( !attributes.urlTemplates ){ throw( 'HDAView needs urlTemplates on initialize' ); }
- this.urlTemplates = attributes.urlTemplates;
-
/** is the body of this hda view expanded/not. */
this.expanded = attributes.expanded || false;
+ this._setUpListeners();
+ },
+ _setUpListeners : function(){
// re-rendering on any model changes
- this.model.bind( 'change', function( model, options ){
- // if more than the display apps have changed: render everything
- var nonDisplayAppChanges = _.omit( this.model.changedAttributes(), 'display_apps', 'display_types' );
- if( _.keys( nonDisplayAppChanges ).length ){
- this.render();
+ this.model.on( 'change', this.render, this );
- // if just the display links, and it's already expanded: render the links only
- } else {
- if( this.expanded ){
- this._render_displayApps();
- }
- }
- }, this );
-
- //this.bind( 'all', function( event ){
+ //this.on( 'all', function( event ){
// this.log( event );
//}, this );
},
-
+
// ......................................................................... RENDER MAIN
/** Render this HDA, set up ui.
* @fires rendered:ready when rendered and NO running HDAs
@@ -86,9 +74,8 @@
// handle that here by removing previous view's tooltips
this.$el.find("[title]").tooltip( "destroy" );
- /** web controller urls for functions relating to this hda.
- * These are rendered from urlTemplates using the model data. */
- this.urls = this._renderUrls( this.urlTemplates, this.model.toJSON() );
+ /** web controller urls for functions relating to this hda. */
+ this.urls = this.model.urls();
itemWrapper
.addClass( 'historyItemWrapper' ).addClass( 'historyItem' )
@@ -104,9 +91,9 @@
itemWrapper.append( this.body );
// transition...
- this.$el.fadeOut( 'fast', function(){
+ this.$el.fadeOut( this.fxSpeed, function(){
view.$el.children().remove();
- view.$el.append( itemWrapper ).fadeIn( 'fast', function(){
+ view.$el.append( itemWrapper ).fadeIn( view.fxSpeed, function(){
view.log( view + ' rendered:', view.$el );
var renderedEventName = 'rendered';
@@ -121,55 +108,6 @@
return this;
},
- /** render the urls for this hda using the model data and the url templates from initialize.
- * @param {Object} urlTemplates a map (or nested map) of underscore templates (currently, anyhoo)
- * @param {Object} modelJson data from the model
- * @returns {Object} the templated urls
- */
- _renderUrls : function( urlTemplates, modelJson ){
- var hdaView = this,
- urls = {};
- _.each( urlTemplates, function( urlTemplateOrObj, urlKey ){
- // object == nested templates: recurse
- if( _.isObject( urlTemplateOrObj ) ){
- urls[ urlKey ] = hdaView._renderUrls( urlTemplateOrObj, modelJson );
-
- // string == template:
- } else {
- // meta_down load is a special case (see renderMetaDownloadUrls)
- //TODO: should be a better (gen.) way to handle this case
- if( urlKey === 'meta_download' ){
- urls[ urlKey ] = hdaView._renderMetaDownloadUrls( urlTemplateOrObj, modelJson );
-
- } else {
- try {
- urls[ urlKey ] = _.template( urlTemplateOrObj, modelJson );
- } catch( Error ){
- throw( hdaView + '._renderUrls error: ' + Error +
- '\n rendering:' + urlTemplateOrObj +
- '\n with ' + JSON.stringify( modelJson ) );
- }
- }
- }
- });
- return urls;
- },
-
- /** there can be more than one meta_file (e.g. bam index) to download,
- * so return a list of url and file_type for each
- * @param {Object} urlTemplate underscore templates for meta download urls
- * @param {Object} modelJson data from the model
- * @returns {Object} url and filetype for each meta file
- */
- _renderMetaDownloadUrls : function( urlTemplate, modelJson ){
- return _.map( modelJson.meta_files, function( meta_file ){
- return {
- url : _.template( urlTemplate, { id: modelJson.id, file_type: meta_file.file_type }),
- file_type : meta_file.file_type
- };
- });
- },
-
/** set up js behaviors, event handlers for elements within the given container
* @param {jQuery} $container jq object that contains the elements to process (defaults to this.$el)
*/
@@ -218,8 +156,8 @@
_render_displayButton : function(){
// don't show display if not viewable or not accessible
// (do show if in error, running)
- if( ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
- || ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NEW )
+ if( ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
+ || ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NEW )
|| ( !this.model.get( 'accessible' ) ) ){
this.displayButton = null;
return null;
@@ -237,7 +175,7 @@
displayBtnData.title = _l( 'Cannot display datasets removed from disk' );
// disable if still uploading
- } else if( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.UPLOAD ){
+ } else if( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.UPLOAD ){
displayBtnData.enabled = false;
displayBtnData.title = _l( 'This dataset must finish uploading before it can be viewed' );
@@ -406,40 +344,40 @@
body.html( '' );
//TODO: not a fan of this dispatch
switch( this.model.get( 'state' ) ){
- case HistoryDatasetAssociation.STATES.NEW :
+ case hdaModel.HistoryDatasetAssociation.STATES.NEW :
this._render_body_new( body );
break;
- case HistoryDatasetAssociation.STATES.NOT_VIEWABLE :
+ case hdaModel.HistoryDatasetAssociation.STATES.NOT_VIEWABLE :
this._render_body_not_viewable( body );
break;
- case HistoryDatasetAssociation.STATES.UPLOAD :
+ case hdaModel.HistoryDatasetAssociation.STATES.UPLOAD :
this._render_body_uploading( body );
break;
- case HistoryDatasetAssociation.STATES.PAUSED:
+ case hdaModel.HistoryDatasetAssociation.STATES.PAUSED:
this._render_body_paused( body );
break;
- case HistoryDatasetAssociation.STATES.QUEUED :
+ case hdaModel.HistoryDatasetAssociation.STATES.QUEUED :
this._render_body_queued( body );
break;
- case HistoryDatasetAssociation.STATES.RUNNING :
+ case hdaModel.HistoryDatasetAssociation.STATES.RUNNING :
this._render_body_running( body );
break;
- case HistoryDatasetAssociation.STATES.ERROR :
+ case hdaModel.HistoryDatasetAssociation.STATES.ERROR :
this._render_body_error( body );
break;
- case HistoryDatasetAssociation.STATES.DISCARDED :
+ case hdaModel.HistoryDatasetAssociation.STATES.DISCARDED :
this._render_body_discarded( body );
break;
- case HistoryDatasetAssociation.STATES.SETTING_METADATA :
+ case hdaModel.HistoryDatasetAssociation.STATES.SETTING_METADATA :
this._render_body_setting_metadata( body );
break;
- case HistoryDatasetAssociation.STATES.EMPTY :
+ case hdaModel.HistoryDatasetAssociation.STATES.EMPTY :
this._render_body_empty( body );
break;
- case HistoryDatasetAssociation.STATES.FAILED_METADATA :
+ case hdaModel.HistoryDatasetAssociation.STATES.FAILED_METADATA :
this._render_body_failed_metadata( body );
break;
- case HistoryDatasetAssociation.STATES.OK :
+ case hdaModel.HistoryDatasetAssociation.STATES.OK :
this._render_body_ok( body );
break;
default:
@@ -591,27 +529,44 @@
* @fires body-expanded when a body has been expanded
* @fires body-collapsed when a body has been collapsed
*/
- toggleBodyVisibility : function( event, expanded ){
+ toggleBodyVisibility : function( event, expand ){
var hdaView = this;
- this.expanded = ( expanded === undefined )?( !this.body.is( ':visible' ) ):( expanded );
- //this.log( 'toggleBodyVisibility, expanded:', expanded, '$body:', $body );
+ expand = ( expand === undefined )?( !this.body.is( ':visible' ) ):( expand );
+ if( expand ){
+ if( this.model.inReadyState() && !this.model.hasDetails() ){
+ var xhr = this.model.fetch();
+ xhr.done( function( model ){
+ hdaView.expandBody();
+ });
+ } else {
+ this.expandBody();
+ }
+ } else {
+ this.collapseBody();
+ }
+ },
- if( this.expanded ){
- hdaView._render_body_html( hdaView.body );
- this.body.slideDown( 'fast', function(){
- hdaView.trigger( 'body-expanded', hdaView.model.get( 'id' ) );
- });
- } else {
- this.body.slideUp( 'fast', function(){
- hdaView.trigger( 'body-collapsed', hdaView.model.get( 'id' ) );
- });
- }
+ expandBody : function(){
+ var hdaView = this;
+ hdaView._render_body_html( hdaView.body );
+ this.body.slideDown( hdaView.fxSpeed, function(){
+ hdaView.expanded = true;
+ hdaView.trigger( 'body-expanded', hdaView.model.get( 'id' ) );
+ });
+ },
+
+ collapseBody : function(){
+ var hdaView = this;
+ this.body.slideUp( hdaView.fxSpeed, function(){
+ hdaView.expanded = false;
+ hdaView.trigger( 'body-collapsed', hdaView.model.get( 'id' ) );
+ });
},
// ......................................................................... DELETION
remove : function( callback ){
var hdaView = this;
- this.$el.fadeOut( 'fast', function(){
+ this.$el.fadeOut( hdaView.fxSpeed, function(){
hdaView.$el.remove();
hdaView.off();
if( callback ){ callback(); }
@@ -638,6 +593,6 @@
};
//==============================================================================
-//return {
-// HDABaseView : HDABaseView,
-//};});
+return {
+ HDABaseView : HDABaseView,
+};});
diff -r 902bf096a4aa1be446676d178ac5f6db4e5b558f -r bb8975aafcd91ca055ab5aa64a7b8e6a866f8cce static/scripts/mvc/dataset/hda-edit.js
--- a/static/scripts/mvc/dataset/hda-edit.js
+++ b/static/scripts/mvc/dataset/hda-edit.js
@@ -1,6 +1,7 @@
-//define([
-// "../mvc/base-mvc"
-//], function(){
+define([
+ "mvc/dataset/hda-model",
+ "mvc/dataset/hda-base"
+], function( hdaModel, hdaBase ){
//==============================================================================
/** @class Editing view for HistoryDatasetAssociation.
* @name HDAEditView
@@ -10,7 +11,7 @@
* @borrows LoggableMixin#log as #log
* @constructs
*/
-var HDAEditView = HDABaseView.extend( LoggableMixin ).extend(
+var HDAEditView = hdaBase.HDABaseView.extend( LoggableMixin ).extend(
/** @lends HDAEditView.prototype */{
// ......................................................................... SET UP
@@ -22,7 +23,8 @@
* @see HDABaseView#initialize
*/
initialize : function( attributes ){
- HDABaseView.prototype.initialize.call( this, attributes );
+ hdaBase.HDABaseView.prototype.initialize.call( this, attributes );
+ this.hasUser = attributes.hasUser;
/** list of rendering functions for the default, primary icon-buttons. */
this.defaultPrimaryActionButtonRenderers = [
@@ -37,33 +39,8 @@
* @param {jQuery} $container jq object that contains the elements to process (defaults to this.$el)
*/
_setUpBehaviors : function( $container ){
- //TODO: ideally this would be a DELETE call to the api
- // using purge async for now
- HDABaseView.prototype._setUpBehaviors.call( this, $container );
-
- // use purge_async with an ajax call
- var hdaView = this,
- purge_url = this.urls.purge,
- purge_link = $container.find( '#historyItemPurger-' + this.model.get( 'id' ) );
- if( purge_link ){
- //TODO: remove href from template
- purge_link.attr( 'href', [ "javascript", "void(0)" ].join( ':' ) );
- purge_link.click( function( event ){
- //TODO??: confirm?
- var xhr = jQuery.ajax( purge_url );
- xhr.success( function( message, status, responseObj ){
- hdaView.model.set( 'purged', true );
- hdaView.trigger( 'purged', hdaView );
- });
- xhr.error( function( error, status, message ){
- //TODO: Exception messages are hidden within error page
- //!NOTE: that includes the 'Removal of datasets by users is not allowed in this Galaxy instance.'
- view.trigger( 'error',
- hdaView, xhr, { url: purge_url }, _l( "Unable to purge this dataset" ) );
- });
- });
- }
- //TODO: same with undelete_async
+ hdaBase.HDABaseView.prototype._setUpBehaviors.call( this, $container );
+ //var hdaView = this;
},
// ......................................................................... RENDER WARNINGS
@@ -74,7 +51,7 @@
*/
_render_warnings : function(){
// jQ errs on building dom with whitespace - if there are no messages, trim -> ''
- return $( jQuery.trim( HDABaseView.templates.messages(
+ return $( jQuery.trim( hdaBase.HDABaseView.templates.messages(
_.extend( this.model.toJSON(), { urls: this.urls } )
)));
},
@@ -101,9 +78,9 @@
// don't show edit while uploading, in-accessible
// DO show if in error (ala previous history panel)
//TODO??: not viewable/accessible are essentially the same (not viewable set from accessible)
- if( ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NEW )
- || ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.UPLOAD )
- || ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
+ if( ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NEW )
+ || ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.UPLOAD )
+ || ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
|| ( !this.model.get( 'accessible' ) ) ){
this.editButton = null;
return null;
@@ -138,44 +115,26 @@
_render_deleteButton : function(){
// don't show delete if...
//TODO??: not viewable/accessible are essentially the same (not viewable set from accessible)
- if( ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NEW )
- || ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
+ if( ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NEW )
+ || ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
|| ( !this.model.get( 'accessible' ) ) ){
this.deleteButton = null;
return null;
}
var self = this,
+ id = 'historyItemDeleter-' + self.model.get( 'id' ),
delete_url = self.urls[ 'delete' ],
deleteBtnData = {
- title : _l( 'Delete' ),
- href : delete_url,
- id : 'historyItemDeleter-' + this.model.get( 'id' ),
- icon_class : 'delete',
- on_click : function() {
- // Delete the dataset on the server and update HDA + view depending on success/failure.
- // FIXME: when HDA-delete is implemented in the API, can call set(), then save directly
- // on the model.
- $.ajax({
- url: delete_url,
- type: 'POST',
- error: function() {
- // Something went wrong, so show HDA again.
- // TODO: an error notification would be good.
- self.trigger( 'error', self, null, null, { url: delete_url }, _l( 'deletion failed' ) );
- self.$el.show();
- },
- success: function() {
- // FIXME: setting model attribute causes re-rendering, which is unnecessary.
- //self.$el.remove();
-
- self.model.set({ deleted: true });
- }
- });
-
- // Return false so that anchor action (page reload) does not happen.
- //return false;
- }
+ title : _l( 'Delete' ),
+ href : delete_url,
+ id : id,
+ icon_class : 'delete',
+ on_click : function() {
+ // ...bler... tooltips being left behind in DOM (hover out never called on deletion)
+ self.$el.find( '.menu-button.delete' ).trigger( 'mouseout' );
+ self.model[ 'delete' ]();
+ }
};
if( this.model.get( 'deleted' ) || this.model.get( 'purged' ) ){
deleteBtnData = {
@@ -202,7 +161,7 @@
//TODO: use HDABaseView and select/replace base on this switch
_.extend( modelData, { dbkey_unknown_and_editable : true });
}
- return HDABaseView.templates.hdaSummary( modelData );
+ return hdaBase.HDABaseView.templates.hdaSummary( modelData );
},
// ......................................................................... primary actions
@@ -210,7 +169,7 @@
* @returns {jQuery} rendered DOM
*/
_render_errButton : function(){
- if( this.model.get( 'state' ) !== HistoryDatasetAssociation.STATES.ERROR ){
+ if( this.model.get( 'state' ) !== hdaModel.HistoryDatasetAssociation.STATES.ERROR ){
this.errButton = null;
return null;
}
@@ -378,8 +337,7 @@
//TODO: these should be a sub-MV
_render_tagButton : function(){
//TODO: check for User
- if( !( this.model.hasData() )
- || ( !this.urls.tags.get ) ){
+ if( !this.hasUser || !this.urls.tags.get ){
this.tagButton = null;
return null;
}
@@ -399,8 +357,7 @@
//TODO: these should be a sub-MV
_render_annotateButton : function(){
//TODO: check for User
- if( !( this.model.hasData() )
- || ( !this.urls.annotation.get ) ){
+ if( !this.hasUser || !this.urls.annotation.get ){
this.annotateButton = null;
return null;
}
@@ -417,8 +374,8 @@
/** Render area to display tags.
* @returns {jQuery} rendered DOM
*/
- //TODO: into sub-MV
- //TODO: check for User
+//TODO: into sub-MV
+//TODO: check for User
_render_tagArea : function(){
if( !this.urls.tags.set ){ return null; }
//TODO: move to mvc/tags.js
@@ -430,8 +387,8 @@
/** Render area to display annotation.
* @returns {jQuery} rendered DOM
*/
- //TODO: into sub-MV
- //TODO: check for User
+//TODO: into sub-MV
+//TODO: check for User
_render_annotationArea : function(){
if( !this.urls.annotation.get ){ return null; }
//TODO: move to mvc/annotations.js
@@ -447,7 +404,7 @@
* @see HDABaseView#_render_body_error
*/
_render_body_error : function( parent ){
- HDABaseView.prototype._render_body_error.call( this, parent );
+ hdaBase.HDABaseView.prototype._render_body_error.call( this, parent );
var primaryActions = parent.find( '#primary-actions-' + this.model.get( 'id' ) );
primaryActions.prepend( this._render_errButton() );
},
@@ -498,11 +455,21 @@
/** event map */
events : {
'click .historyItemTitle' : 'toggleBodyVisibility',
+ 'click .historyItemUndelete' : function( ev ){ this.model.undelete(); return false; },
+ 'click .historyItemUnhide' : function( ev ){ this.model.unhide(); return false; },
+ 'click .historyItemPurge' : 'confirmPurge',
+
'click a.icon-button.tags' : 'loadAndDisplayTags',
'click a.icon-button.annotate' : 'loadAndDisplayAnnotation'
},
// ......................................................................... STATE CHANGES / MANIPULATION
+ confirmPurge : function _confirmPurge( ev ){
+ //TODO: confirm dialog
+ this.model.purge({ url: this.urls.purge });
+ return false;
+ },
+
/** Find the tag area and, if initial: load the html (via ajax) for displaying them; otherwise, unhide/hide
*/
//TODO: into sub-MV
@@ -523,30 +490,29 @@
url: this.urls.tags.get,
error: function( xhr, status, error ){
view.log( "Tagging failed", xhr, status, error );
- view.trigger( 'error', view, xhr, { url: view.urls.tags.get }, _l( "Tagging failed" ) );
+ view.trigger( 'error', view, xhr, {}, _l( "Tagging failed" ) );
},
success: function(tag_elt_html) {
tagElt.html(tag_elt_html);
tagElt.find("[title]").tooltip();
- tagArea.slideDown("fast");
+ tagArea.slideDown( view.fxSpeed );
}
});
} else {
// Tag element is filled; show.
- tagArea.slideDown("fast");
+ tagArea.slideDown( view.fxSpeed );
}
} else {
// Hide.
- tagArea.slideUp("fast");
+ tagArea.slideUp( view.fxSpeed );
}
return false;
},
/** Find the annotation area and, if initial: load the html (via ajax) for displaying them; otherwise, unhide/hide
*/
- //TODO: into sub-MV
loadAndDisplayAnnotation : function( event ){
- //TODO: this is a drop in from history.mako - should use MV as well
+//TODO: this is a drop in from history.mako - should use MV as well
this.log( this + '.loadAndDisplayAnnotation', event );
var view = this,
annotationArea = this.$el.find( '.annotation-area' ),
@@ -559,10 +525,9 @@
// Need to fill annotation element.
$.ajax({
url: this.urls.annotation.get,
- error: function( xhr, status, message ){
- view.log( "Annotation failed", xhr, status, message );
- view.trigger( 'error',
- view, xhr, { url: view.urls.annotation.get }, _l( "Annotation failed" ) );
+ error: function(){
+ view.log( "Annotation failed", xhr, status, error );
+ view.trigger( 'error', view, xhr, {}, _l( "Annotation failed" ) );
},
success: function( htmlFromAjax ){
if( htmlFromAjax === "" ){
@@ -576,16 +541,16 @@
setAnnotationUrl,
"new_annotation", 18, true, 4
);
- annotationArea.slideDown("fast");
+ annotationArea.slideDown( view.fxSpeed );
}
});
} else {
- annotationArea.slideDown("fast");
+ annotationArea.slideDown( view.fxSpeed );
}
} else {
// Hide.
- annotationArea.slideUp("fast");
+ annotationArea.slideUp( view.fxSpeed );
}
return false;
},
@@ -712,6 +677,6 @@
//==============================================================================
-//return {
-// HDAView : HDAView,
-//};});
+return {
+ HDAEditView : HDAEditView,
+};});
diff -r 902bf096a4aa1be446676d178ac5f6db4e5b558f -r bb8975aafcd91ca055ab5aa64a7b8e6a866f8cce static/scripts/mvc/dataset/hda-model.js
--- a/static/scripts/mvc/dataset/hda-model.js
+++ b/static/scripts/mvc/dataset/hda-model.js
@@ -1,6 +1,5 @@
-//define([
-// "../mvc/base-mvc"
-//], function(){
+define([
+], function(){
//==============================================================================
/** @class (HDA) model for a Galaxy dataset
* related to a history.
@@ -34,6 +33,13 @@
name : '(unnamed dataset)',
// one of HistoryDatasetAssociation.STATES
state : 'new',
+
+ deleted : false,
+ visible : true,
+
+ accessible : true,
+ purged : false,
+
// sniffed datatype (sam, tabular, bed, etc.)
data_type : null,
// size in bytes
@@ -44,37 +50,67 @@
meta_files : [],
misc_blurb : '',
- misc_info : '',
-
- deleted : false,
- purged : false,
- visible : true,
- accessible : true
+ misc_info : ''
},
/** fetch location of this history in the api */
urlRoot: 'api/histories/',
url : function(){
- //TODO: get this via url router
return this.urlRoot + this.get( 'history_id' ) + '/contents/' + this.get( 'id' );
- //TODO: this breaks on save()
},
+ urls : function(){
+ var id = this.get( 'id' );
+ if( !id ){ return {}; }
+ var urls = {
+ 'delete' : '/datasets/' + id + '/delete_async',
+ 'purge' : '/datasets/' + id + '/purge_async',
+ 'unhide' : '/datasets/' + id + '/unhide',
+ 'undelete' : '/datasets/' + id + '/undelete',
+
+ 'display' : '/datasets/' + id + '/display/?preview=True',
+ 'download' : '/datasets/' + id + '/display?to_ext=' + this.get( 'file_ext' ),
+ 'edit' : '/datasets/' + id + '/edit',
+ 'report_error': '/dataset/errors?id=' + id,
+ 'rerun' : '/tool_runner/rerun?id=' + id,
+ 'show_params': '/datasets/' + id + '/show_params',
+ 'visualization': '/visualization',
+
+ 'annotation': { 'get': '/dataset/get_annotation_async?id=' + id,
+ 'set': '/dataset/annotate_async?id=' + id },
+ 'tags' : { 'get': '/tag/get_tagging_elt_async?item_id=' + id + '&item_class=HistoryDatasetAssociation',
+ 'set': '/tag/retag?item_id=' + id + '&item_class=HistoryDatasetAssociation' }
+ };
+ //'meta_download': '/dataset/get_metadata_file?hda_id=%3C%25%3D+id+%25%3E&metadata_name=%3C%25%3D+file_type+%25%3E',
+ var meta_files = this.get( 'meta_files' );
+ if( meta_files ){
+ urls.meta_download = _.map( meta_files, function( meta_file ){
+ return {
+ //url : _.template( urlTemplate, { id: modelJson.id, file_type: meta_file.file_type }),
+ url : '/dataset/get_metadata_file?hda_id=' + id + '&metadata_name=' + meta_file.file_type,
+ file_type : meta_file.file_type
+ };
+ });
+ }
+ return urls;
+ },
+
/** Set up the model, determine if accessible, bind listeners
* @see Backbone.Model#initialize
*/
- //TODO:? use initialize (or validate) to check purged AND deleted -> purged XOR deleted
- initialize : function(){
+ initialize : function( data ){
this.log( this + '.initialize', this.attributes );
this.log( '\tparent history_id: ' + this.get( 'history_id' ) );
- // (curr) only handles changing state of non-accessible hdas to STATES.NOT_VIEWABLE
//!! this state is not in trans.app.model.Dataset.states - set it here -
- //TODO: change to server side.
if( !this.get( 'accessible' ) ){
this.set( 'state', HistoryDatasetAssociation.STATES.NOT_VIEWABLE );
}
+ this._setUpListeners();
+ },
+
+ _setUpListeners : function(){
// if the state has changed and the new state is a ready state, fire an event
this.on( 'change:state', function( currModel, newState ){
this.log( this + ' has changed state:', currModel, newState );
@@ -82,16 +118,9 @@
this.trigger( 'state:ready', currModel, newState, this.previous( 'state' ) );
}
});
-
- // debug on change events
- //this.on( 'change', function( currModel, changedList ){
- // this.log( this + ' has changed:', currModel, changedList );
- //});
- //this.bind( 'all', function( event ){
- // this.log( this + '', arguments );
- //});
},
+ // ........................................................................ common queries
/** Is this hda deleted or purged?
*/
isDeletedOrPurged : function(){
@@ -117,24 +146,21 @@
return isVisible;
},
+ hidden : function(){
+ return !this.get( 'visible' );
+ },
+
/** Is this HDA in a 'ready' state; where 'Ready' states are states where no
* processing (for the ds) is left to do on the server.
- * Currently: NEW, OK, EMPTY, FAILED_METADATA, NOT_VIEWABLE, DISCARDED,
- * and ERROR
*/
inReadyState : function(){
- var state = this.get( 'state' );
- //TODO: to list inclusion test
- //TODO: class level readyStates list
- return (
- this.isDeletedOrPurged()
- || ( state === HistoryDatasetAssociation.STATES.OK )
- || ( state === HistoryDatasetAssociation.STATES.EMPTY )
- || ( state === HistoryDatasetAssociation.STATES.FAILED_METADATA )
- || ( state === HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
- || ( state === HistoryDatasetAssociation.STATES.DISCARDED )
- || ( state === HistoryDatasetAssociation.STATES.ERROR )
- );
+ var ready = _.contains( HistoryDatasetAssociation.READY_STATES, this.get( 'state' ) );
+ return ( this.isDeletedOrPurged() || ready );
+ },
+
+ hasDetails : function(){
+ //?? this may not be reliable
+ return _.has( this.attributes, 'genome_build' );
},
/** Convenience function to match hda.has_data.
@@ -144,6 +170,64 @@
return ( this.get( 'file_size' ) > 0 );
},
+ // ........................................................................ ajax
+ 'delete' : function _delete( options ){
+ return this.save( { deleted: true }, options );
+ },
+ undelete : function _undelete( options ){
+ return this.save( { deleted: false }, options );
+ },
+
+ hide : function _hide( options ){
+ return this.save( { visible: false }, options );
+ },
+ unhide : function _uhide( options ){
+ return this.save( { visible: true }, options );
+ },
+
+ purge : function _purge( options ){
+ //TODO: ideally this would be a DELETE call to the api
+ // using purge async for now
+ var hda = this,
+ xhr = jQuery.ajax( options );
+ xhr.done( function( message, status, responseObj ){
+ hda.set( 'purged', true );
+ });
+ xhr.fail( function( xhr, status, message ){
+ // Exception messages are hidden within error page including: '...not allowed in this Galaxy instance.'
+ // unbury and re-add to xhr
+ var error = _l( "Unable to purge this dataset" );
+ var messageBuriedInUnfortunatelyFormattedError = ( 'Removal of datasets by users '
+ + 'is not allowed in this Galaxy instance' );
+ if( xhr.responseJSON && xhr.responseJSON.error ){
+ error = xhr.responseJSON.error;
+ } else if( xhr.responseText.indexOf( messageBuriedInUnfortunatelyFormattedError ) !== -1 ){
+ error = messageBuriedInUnfortunatelyFormattedError;
+ }
+ xhr.responseText = error;
+ hda.trigger( 'error', hda, xhr, options, _l( error ), { error: error } );
+ });
+ },
+
+ // ........................................................................ sorting/filtering
+ searchKeys : [
+ 'name', 'file_ext', 'genome_build', 'misc_blurb', 'misc_info', 'annotation', 'tags'
+ ],
+
+ search : function( searchFor ){
+ var model = this;
+ searchFor = searchFor.toLowerCase();
+ return _.filter( this.searchKeys, function( key ){
+ var attr = model.get( key );
+ return ( _.isString( attr ) && attr.toLowerCase().indexOf( searchFor ) !== -1 );
+ });
+ },
+
+ matches : function( matchesWhat ){
+ return !!this.search( matchesWhat ).length;
+ },
+
+ // ........................................................................ misc
/** String representation
*/
toString : function(){
@@ -165,8 +249,6 @@
UPLOAD : 'upload',
/** the job that will produce the dataset queued in the runner */
QUEUED : 'queued',
- /** the job that will produce the dataset paused */
- PAUSED : 'paused',
/** the job that will produce the dataset is running */
RUNNING : 'running',
/** metadata for the dataset is being discovered/set */
@@ -180,6 +262,8 @@
/** has successfully completed running */
OK : 'ok',
+ /** the job that will produce the dataset paused */
+ PAUSED : 'paused',
/** metadata discovery/setting failed or errored (but otherwise ok) */
FAILED_METADATA : 'failed_metadata',
/** not accessible to the current user (i.e. due to permissions) */
@@ -190,6 +274,24 @@
ERROR : 'error'
};
+HistoryDatasetAssociation.READY_STATES = [
+ HistoryDatasetAssociation.STATES.NEW,
+ HistoryDatasetAssociation.STATES.OK,
+ HistoryDatasetAssociation.STATES.EMPTY,
+ HistoryDatasetAssociation.STATES.PAUSED,
+ HistoryDatasetAssociation.STATES.FAILED_METADATA,
+ HistoryDatasetAssociation.STATES.NOT_VIEWABLE,
+ HistoryDatasetAssociation.STATES.DISCARDED,
+ HistoryDatasetAssociation.STATES.ERROR
+];
+
+HistoryDatasetAssociation.NOT_READY_STATES = [
+ HistoryDatasetAssociation.STATES.UPLOAD,
+ HistoryDatasetAssociation.STATES.QUEUED,
+ HistoryDatasetAssociation.STATES.RUNNING,
+ HistoryDatasetAssociation.STATES.SETTING_METADATA
+];
+
//==============================================================================
/** @class Backbone collection of (HDA) models
*
@@ -204,83 +306,35 @@
///** logger used to record this.log messages, commonly set to console */
//// comment this out to suppress log output
//logger : console,
+ urlRoot : '/api/histories',
+ url : function(){
+ return this.urlRoot + '/' + this.historyId + '/contents';
+ },
/** Set up.
* @see Backbone.Collection#initialize
*/
- initialize : function(){
- //this.bind( 'all', function( event ){
- // this.log( this + '', arguments );
- //});
+ initialize : function( models, options ){
+ options = options || {};
+ this.historyId = options.historyId;
+ this._setUpListeners();
},
+ _setUpListeners : function(){
+ },
+
+ // ........................................................................ common queries
/** Get the ids of every hda in this collection
- * @returns array of encoded ids
+ * @returns array of encoded ids
*/
ids : function(){
return this.map( function( hda ){ return hda.id; });
},
- /** Get the hda with the given hid
- * @param {Int} hid the hid to search for
- * @returns {HistoryDatasetAssociation} the hda with the given hid or undefined if not found
- */
- getByHid : function( hid ){
- return _.first( this.filter( function( hda ){ return hda.get( 'hid' ) === hid; }) );
- },
-
- /** If the given hid is in the collection, return it's index. If not, return the insertion point it would need.
- * NOTE: assumes hids are unique and valid
- * @param {Int} hid the hid to find or create. If hid is 0, null, undefined: return the last hid + 1
- * @returns the collection index of the existing hda or an insertion point if it doesn't exist
- */
- hidToCollectionIndex : function( hid ){
- // if the hid is 0, null, undefined: assume a request for a new hid (return the last index)
- if( !hid ){
- return this.models.length;
- }
-
- var endingIndex = this.models.length - 1;
- //TODO: prob. more efficient to cycle backwards through these (assuming ordered by hid)
- for( var i=endingIndex; i>=0; i-- ){
- var hdaHid = this.at( i ).get( 'hid' );
- //this.log( i, 'hdaHid:', hdaHid );
- if( hdaHid === hid ){
- //this.log( '\t match:', hdaHid, hid, ' returning:', i );
- return i;
- }
- if( hdaHid < hid ){
- //this.log( '\t past it, returning:', ( i + 1 ) );
- return i + 1;
- }
- }
- return null;
- },
-
- /** Get every 'shown' hda in this collection based on show_deleted/hidden
- * @param {Boolean} show_deleted are we showing deleted hdas?
- * @param {Boolean} show_hidden are we showing hidden hdas?
- * @returns array of hda models
- * @see HistoryDatasetAssociation#isVisible
- */
- getVisible : function( show_deleted, show_hidden ){
- return this.filter( function( item ){ return item.isVisible( show_deleted, show_hidden ); });
- },
-
- /** For each possible hda state, get an array of all hda ids in that state
- * @returns a map of states -> hda ids
- * @see HistoryDatasetAssociation#STATES
- */
- getStateLists : function(){
- var stateLists = {};
- _.each( _.values( HistoryDatasetAssociation.STATES ), function( state ){
- stateLists[ state ] = [];
+ notReady : function(){
+ return this.filter( function( hda ){
+ return !hda.inReadyState();
});
- //NOTE: will err on unknown state
- this.each( function( item ){
- stateLists[ item.get( 'state' ) ].push( item.get( 'id' ) );
- });
- return stateLists;
},
/** Get the id of every hda in this collection not in a 'ready' state (running).
@@ -297,26 +351,55 @@
return idList;
},
- /** Update (fetch) the data of the hdas with the given ids.
- * @param {String[]} ids an array of hda ids to update
- * @returns {HistoryDatasetAssociation[]} hda models that were updated
- * @see HistoryDatasetAssociation#fetch
+ /** Get the hda with the given hid
+ * @param {Int} hid the hid to search for
+ * @returns {HistoryDatasetAssociation} the hda with the given hid or undefined if not found
*/
- update : function( ids ){
- this.log( this + 'update:', ids );
+ getByHid : function( hid ){
+ return _.first( this.filter( function( hda ){ return hda.get( 'hid' ) === hid; }) );
+ },
- if( !( ids && ids.length ) ){ return []; }
+ /** Get every 'shown' hda in this collection based on show_deleted/hidden
+ * @param {Boolean} show_deleted are we showing deleted hdas?
+ * @param {Boolean} show_hidden are we showing hidden hdas?
+ * @returns array of hda models
+ * @see HistoryDatasetAssociation#isVisible
+ */
+ getVisible : function( show_deleted, show_hidden ){
+ return this.filter( function( item ){ return item.isVisible( show_deleted, show_hidden ); });
+ },
- var collection = this,
- updatedHdas = null;
- _.each( ids, function( id, index ){
- var hda = collection.get( id );
- if( hda ){
- hda.fetch();
- updatedHdas.push( hda );
- }
+ // ........................................................................ ajax
+ fetchAllDetails : function(){
+ return this.fetch({ data : { details : 'all' } });
+ },
+
+ // ........................................................................ sorting/filtering
+ matches : function( matchesWhat ){
+ return this.filter( function( hda ){
+ return hda.matches( matchesWhat );
});
- return updatedHdas;
+ },
+
+ // ........................................................................ misc
+ set : function( models, options ){
+ // arrrrrrrrrrrrrrrrrg...
+ // override to get a correct/smarter merge when incoming data is partial (e.g. stupid backbone)
+ // w/o this partial models from the server will fill in missing data with model defaults
+ // and overwrite existing data on the client
+ // see Backbone.Collection.set and _prepareModel
+ var collection = this;
+ models = _.map( models, function( model ){
+ var existing = collection.get( model.id );
+ if( !existing ){ return model; }
+
+ // merge the models _BEFORE_ calling the superclass version
+ var merged = existing.toJSON();
+ _.extend( merged, model );
+ return merged;
+ });
+ // now call superclass when the data is filled
+ Backbone.Collection.prototype.set.call( this, models, options );
},
/** String representation. */
@@ -326,7 +409,7 @@
});
//==============================================================================
-//return {
-// HistoryDatasetAssociation : HistoryDatasetAssociation,
-// HDACollection : HDACollection,
-//};});
+return {
+ HistoryDatasetAssociation : HistoryDatasetAssociation,
+ HDACollection : HDACollection
+};});
This diff is so big that we needed to truncate the remainder.
https://bitbucket.org/galaxy/galaxy-central/commits/14fbaad2645b/
Changeset: 14fbaad2645b
Branch: next-stable
User: dannon
Date: 2013-10-21 23:32:34
Summary: Merge next-stable
Affected #: 3 files
diff -r 3b4cbba69871ab36384f1f8b28cb5555ba3dd20b -r 14fbaad2645bd7b8a0a2f9a4a682b38ecf18c7d0 lib/galaxy/web/__init__.py
--- a/lib/galaxy/web/__init__.py
+++ b/lib/galaxy/web/__init__.py
@@ -13,4 +13,5 @@
from framework import expose_api
from framework import expose_api_anonymous
from framework import expose_api_raw
+from framework import expose_api_raw_anonymous
from framework.base import httpexceptions
diff -r 3b4cbba69871ab36384f1f8b28cb5555ba3dd20b -r 14fbaad2645bd7b8a0a2f9a4a682b38ecf18c7d0 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py
+++ b/lib/galaxy/web/framework/__init__.py
@@ -110,6 +110,14 @@
"""
return expose_api( func, to_json=False )
+#DBTODO refactor these post-dist.
+def expose_api_raw_anonymous( func ):
+ """
+ Expose this function via the API but don't dump the results
+ to JSON.
+ """
+ return expose_api( func, to_json=False, user_required=False )
+
def expose_api_anonymous( func, to_json=True ):
"""
Expose this function via the API but don't require a set user.
diff -r 3b4cbba69871ab36384f1f8b28cb5555ba3dd20b -r 14fbaad2645bd7b8a0a2f9a4a682b38ecf18c7d0 lib/galaxy/webapps/galaxy/api/datasets.py
--- a/lib/galaxy/webapps/galaxy/api/datasets.py
+++ b/lib/galaxy/webapps/galaxy/api/datasets.py
@@ -23,7 +23,7 @@
trans.response.status = 501
return 'not implemented'
- @web.expose_api
+ @web.expose_api_anonymous
def show( self, trans, id, hda_ldda='hda', data_type=None, provider=None, **kwd ):
"""
GET /api/datasets/{encoded_dataset_id}
@@ -101,7 +101,6 @@
# If there is a chrom, check for data on the chrom.
if chrom:
- data_provider_registry = trans.app.data_provider_registry
data_provider = trans.app.data_provider_registry.get_data_provider( trans,
original_dataset=dataset, source='index' )
if not data_provider.has_data( chrom ):
@@ -244,7 +243,7 @@
return data
- @web.expose_api_raw
+ @web.expose_api_raw_anonymous
def display( self, trans, history_content_id, history_id,
preview=False, filename=None, to_ext=None, chunk=None, **kwd ):
"""
https://bitbucket.org/galaxy/galaxy-central/commits/361f581d1e51/
Changeset: 361f581d1e51
User: dannon
Date: 2013-10-21 23:33:47
Summary: Merge
Affected #: 0 files
https://bitbucket.org/galaxy/galaxy-central/commits/315018626d87/
Changeset: 315018626d87
User: dannon
Date: 2013-10-21 23:34:09
Summary: Merge.
Affected #: 1 file
diff -r 361f581d1e5188b01476f6da5ca22af7d5c6ba5e -r 315018626d873654e822ef97984c0f3288360fb2 lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -113,7 +113,7 @@
except Exception, e:
msg = "Error in history API at showing history detail: %s" % ( str( e ) )
- log.exception( e )
+ log.exception( msg )
trans.response.status = 500
return msg
@@ -148,7 +148,7 @@
except Exception, e:
msg = "Error in history API when switching current history: %s" % ( str( e ) )
- log.exception( e )
+ log.exception( msg )
trans.response.status = 500
return msg
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: Histories API: use proper logging technique for exceptions
by commits-noreply@bitbucket.org 21 Oct '13
by commits-noreply@bitbucket.org 21 Oct '13
21 Oct '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/80db2712720c/
Changeset: 80db2712720c
User: carlfeberhard
Date: 2013-10-21 23:32:12
Summary: Histories API: use proper logging technique for exceptions
Affected #: 1 file
diff -r fbf1898d7dea43a46a0f8ec80fd41540ac6fc204 -r 80db2712720c4ea153e51bbc72e981cc9886e73c lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -113,7 +113,7 @@
except Exception, e:
msg = "Error in history API at showing history detail: %s" % ( str( e ) )
- log.exception( e )
+ log.exception( msg )
trans.response.status = 500
return msg
@@ -148,7 +148,7 @@
except Exception, e:
msg = "Error in history API when switching current history: %s" % ( str( e ) )
- log.exception( e )
+ log.exception( msg )
trans.response.status = 500
return msg
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/3b4cbba69871/
Changeset: 3b4cbba69871
Branch: next-stable
User: jgoecks
Date: 2013-10-21 23:11:17
Summary: Use progressive approach to integrate tabular chunked data display into collaboration framework. This fixes a bug that prevented chunkable datasets from being viewable in pages.
Affected #: 1 file
diff -r 81880a04e6e79d944a6d9c225b36417114cd38ec -r 3b4cbba69871ab36384f1f8b28cb5555ba3dd20b templates/webapps/galaxy/dataset/display.mako
--- a/templates/webapps/galaxy/dataset/display.mako
+++ b/templates/webapps/galaxy/dataset/display.mako
@@ -18,6 +18,12 @@
});
require(['mvc/data'], function(data) {
+ //
+ // Use tabular data display progressively by deleting data from page body
+ // and then showing dataset view.
+ //
+ $('.page-body').children().remove();
+
data.createTabularDatasetChunkedView(
// Dataset config. TODO: encode id.
_.extend( ${h.to_json_string( item.to_dict() )},
@@ -59,10 +65,10 @@
title="Import dataset"></a></%def>
+## Renders dataset content. Function is used to render data in stand-along page and to provide content for embedded datasets as well.
<%def name="render_item( data, data_to_render )">
- ## Chunkable data is rendered in JavaScript above; render unchunkable data below.
${ render_deleted_data_message( data ) }
- %if not data.datatype.CHUNKABLE and data_to_render:
+ %if data_to_render:
%if truncated:
<div class="warningmessagelarge">
This dataset is large and only the first megabyte is shown below. |
https://bitbucket.org/galaxy/galaxy-central/commits/fbf1898d7dea/
Changeset: fbf1898d7dea
User: jgoecks
Date: 2013-10-21 23:11:48
Summary: Automated merge of next-stable branch into default
Affected #: 1 file
diff -r 4f1c25230dd009efd1f04f8d7a74d83733f8b75a -r fbf1898d7dea43a46a0f8ec80fd41540ac6fc204 templates/webapps/galaxy/dataset/display.mako
--- a/templates/webapps/galaxy/dataset/display.mako
+++ b/templates/webapps/galaxy/dataset/display.mako
@@ -18,6 +18,12 @@
});
require(['mvc/data'], function(data) {
+ //
+ // Use tabular data display progressively by deleting data from page body
+ // and then showing dataset view.
+ //
+ $('.page-body').children().remove();
+
data.createTabularDatasetChunkedView(
// Dataset config. TODO: encode id.
_.extend( ${h.to_json_string( item.to_dict() )},
@@ -59,10 +65,10 @@
title="Import dataset"></a></%def>
+## Renders dataset content. Function is used to render data in stand-along page and to provide content for embedded datasets as well.
<%def name="render_item( data, data_to_render )">
- ## Chunkable data is rendered in JavaScript above; render unchunkable data below.
${ render_deleted_data_message( data ) }
- %if not data.datatype.CHUNKABLE and data_to_render:
+ %if data_to_render:
%if truncated:
<div class="warningmessagelarge">
This dataset is large and only the first megabyte is shown below. |
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: History panel: remove from iframe, general improvements; pack scripts
by commits-noreply@bitbucket.org 21 Oct '13
by commits-noreply@bitbucket.org 21 Oct '13
21 Oct '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4f1c25230dd0/
Changeset: 4f1c25230dd0
User: carlfeberhard
Date: 2013-10-21 22:26:47
Summary: History panel: remove from iframe, general improvements; pack scripts
Affected #: 28 files
diff -r 6882fa888d10b469524669325a547a2c0f6c7e41 -r 4f1c25230dd009efd1f04f8d7a74d83733f8b75a lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -633,11 +633,11 @@
# if a tool declares 'force_history_refresh' in its xml, when the hda -> ready, reload the history panel
# expensive
- if( ( hda.state in [ 'running', 'queued' ] )
- and ( hda.creating_job and hda.creating_job.tool_id ) ):
- tool_used = trans.app.toolbox.get_tool( hda.creating_job.tool_id )
- if tool_used and tool_used.force_history_refresh:
- hda_dict[ 'force_history_refresh' ] = True
+ #if( ( hda.state in [ 'running', 'queued' ] )
+ #and ( hda.creating_job and hda.creating_job.tool_id ) ):
+ # tool_used = trans.app.toolbox.get_tool( hda.creating_job.tool_id )
+ # if tool_used and tool_used.force_history_refresh:
+ # hda_dict[ 'force_history_refresh' ] = True
return trans.security.encode_dict_ids( hda_dict )
@@ -653,13 +653,14 @@
'accessible': False
})
- def get_hda_dict_with_error( self, trans, hda, error_msg='' ):
+ def get_hda_dict_with_error( self, trans, hda=None, history_id=None, id=None, error_msg='Error' ):
return trans.security.encode_dict_ids({
- 'id' : hda.id,
- 'history_id': hda.history.id,
- 'hid' : hda.hid,
- 'name' : hda.name,
- 'error' : error_msg
+ 'id' : hda.id if hda else id,
+ 'history_id': hda.history.id if hda else history_id,
+ 'hid' : hda.hid if hda else '(unknown)',
+ 'name' : hda.name if hda else '(unknown)',
+ 'error' : error_msg,
+ 'state' : trans.model.Dataset.states.NEW
})
def get_display_apps( self, trans, hda ):
diff -r 6882fa888d10b469524669325a547a2c0f6c7e41 -r 4f1c25230dd009efd1f04f8d7a74d83733f8b75a lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -97,6 +97,9 @@
# Most recent active history for user sessions, not deleted
history = trans.user.galaxy_sessions[0].histories[-1].history
+ elif history_id == "current":
+ history = trans.get_history( create=True )
+
else:
history = self.get_history( trans, history_id, check_ownership=False,
check_accessible=True, deleted=deleted )
@@ -110,7 +113,7 @@
except Exception, e:
msg = "Error in history API at showing history detail: %s" % ( str( e ) )
- log.exception( msg, exc_info=True )
+ log.exception( e )
trans.response.status = 500
return msg
@@ -174,7 +177,8 @@
trans.sa_session.add( new_history )
trans.sa_session.flush()
- item = new_history.to_dict(view='element', value_mapper={'id':trans.security.encode_id})
+ #item = new_history.to_dict(view='element', value_mapper={'id':trans.security.encode_id})
+ item = self.get_history_dict( trans, new_history )
item['url'] = url_for( 'history', id=item['id'] )
#TODO: possibly default to True here - but favor explicit for now (and backwards compat)
diff -r 6882fa888d10b469524669325a547a2c0f6c7e41 -r 4f1c25230dd009efd1f04f8d7a74d83733f8b75a lib/galaxy/webapps/galaxy/api/history_contents.py
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -59,22 +59,21 @@
encoded_hda_id = trans.security.encode_id( hda.id )
if encoded_hda_id in ids:
#TODO: share code with show
- try:
- hda_dict = self.get_hda_dict( trans, hda )
- hda_dict[ 'display_types' ] = self.get_old_display_applications( trans, hda )
- hda_dict[ 'display_apps' ] = self.get_display_apps( trans, hda )
- rval.append( hda_dict )
-
- except Exception, exc:
- # don't fail entire list if hda err's, record and move on
- log.error( "Error in history API at listing contents with history %s, hda %s: (%s) %s",
- history_id, encoded_hda_id, type( exc ), str( exc ), exc_info=True )
- rval.append( self.get_hda_dict_with_error( trans, hda, str( exc ) ) )
+ rval.append( self._detailed_hda_dict( trans, hda ) )
# if no ids passed, return a _SUMMARY_ of _all_ datasets in the history
else:
+ details = kwd.get( 'details', None ) or []
+ if details and details != 'all':
+ details = util.listify( details )
+
for hda in history.datasets:
- rval.append( self._summary_hda_dict( trans, history_id, hda ) )
+ encoded_hda_id = trans.security.encode_id( hda.id )
+ if( ( encoded_hda_id in details )
+ or ( details == 'all' ) ):
+ rval.append( self._detailed_hda_dict( trans, hda ) )
+ else:
+ rval.append( self._summary_hda_dict( trans, history_id, hda ) )
except Exception, e:
# for errors that are not specific to one hda (history lookup or summary list)
@@ -85,7 +84,7 @@
return rval
#TODO: move to model or Mixin
- def _summary_hda_dict( self, trans, history_id, hda ):
+ def _summary_hda_dict( self, trans, encoded_history_id, hda ):
"""
Returns a dictionary based on the HDA in summary form::
{
@@ -99,11 +98,32 @@
encoded_id = trans.security.encode_id( hda.id )
return {
'id' : encoded_id,
+ 'history_id' : encoded_history_id,
'name' : hda.name,
'type' : api_type,
- 'url' : url_for( 'history_content', history_id=history_id, id=encoded_id, ),
+ 'state' : hda.state,
+ 'deleted': hda.deleted,
+ 'visible': hda.visible,
+ 'hid' : hda.hid,
+ 'url' : url_for( 'history_content', history_id=encoded_history_id, id=encoded_id, ),
}
+ def _detailed_hda_dict( self, trans, hda ):
+ """
+ Detailed dictionary of hda values.
+ """
+ try:
+ hda_dict = self.get_hda_dict( trans, hda )
+ hda_dict[ 'display_types' ] = self.get_old_display_applications( trans, hda )
+ hda_dict[ 'display_apps' ] = self.get_display_apps( trans, hda )
+ return hda_dict
+
+ except Exception, exc:
+ # catch error here - returning a briefer hda_dict with an error attribute
+ log.exception( "Error in history API at listing contents with history %s, hda %s: (%s) %s",
+ hda.history_id, hda.id, type( exc ), str( exc ) )
+ return self.get_hda_dict_with_error( trans, hda=hda, error_msg=str( exc ) )
+
@web.expose_api_anonymous
def show( self, trans, id, history_id, **kwd ):
"""
@@ -244,7 +264,7 @@
trans.response.status = 501
return
- @web.expose_api
+ @web.expose_api_anonymous
def update( self, trans, history_id, id, payload, **kwd ):
"""
update( self, trans, history_id, id, payload, **kwd )
@@ -269,10 +289,28 @@
#TODO: PUT /api/histories/{encoded_history_id} payload = { rating: rating } (w/ no security checks)
changed = {}
try:
- hda = self.get_dataset( trans, id,
- check_ownership=True, check_accessible=True, check_state=True )
- # validation handled here and some parsing, processing, and conversion
- payload = self._validate_and_parse_update_payload( payload )
+ # anon user
+ if trans.user == None:
+ if history_id != trans.security.encode_id( trans.history.id ):
+ trans.response.status = 401
+ return { 'error': 'Anonymous users cannot edit histories other than their current history' }
+
+ anon_allowed_payload = {}
+ if 'deleted' in payload:
+ anon_allowed_payload[ 'deleted' ] = payload[ 'deleted' ]
+ if 'visible' in payload:
+ anon_allowed_payload[ 'visible' ] = payload[ 'visible' ]
+
+ payload = self._validate_and_parse_update_payload( anon_allowed_payload )
+ hda = self.get_dataset( trans, id, check_ownership=False, check_accessible=False, check_state=True )
+ if hda.history != trans.history:
+ trans.response.status = 401
+ return { 'error': 'Anonymous users cannot edit datasets outside their current history' }
+
+ else:
+ payload = self._validate_and_parse_update_payload( payload )
+ hda = self.get_dataset( trans, id, check_ownership=True, check_accessible=True, check_state=True )
+
# additional checks here (security, etc.)
changed = self.set_hda_from_dict( trans, hda, payload )
diff -r 6882fa888d10b469524669325a547a2c0f6c7e41 -r 4f1c25230dd009efd1f04f8d7a74d83733f8b75a lib/galaxy/webapps/galaxy/controllers/root.py
--- a/lib/galaxy/webapps/galaxy/controllers/root.py
+++ b/lib/galaxy/webapps/galaxy/controllers/root.py
@@ -5,7 +5,7 @@
import os
import urllib
-from paste.httpexceptions import HTTPNotFound
+from paste.httpexceptions import HTTPNotFound, HTTPBadGateway
from galaxy import web
from galaxy.web import url_for
@@ -30,7 +30,8 @@
@web.expose
def index(self, trans, id=None, tool_id=None, mode=None, workflow_id=None, m_c=None, m_a=None, **kwd):
- """Called on the root url to display the main Galaxy page.
+ """
+ Called on the root url to display the main Galaxy page.
"""
return trans.fill_template( "root/index.mako",
tool_id=tool_id,
@@ -99,63 +100,75 @@
show_deleted=string_as_bool( show_deleted ),
show_hidden=string_as_bool( show_hidden ) )
- @web.expose
- def history( self, trans, as_xml=False, show_deleted=None, show_hidden=None, hda_id=None, **kwd ):
- """Display the current history, creating a new history if necessary.
-
- NOTE: No longer accepts "id" or "template" options for security reasons.
- """
- if as_xml:
- return self.history_as_xml( trans,
- show_deleted=string_as_bool( show_deleted ), show_hidden=string_as_bool( show_hidden ) )
-
- # get all datasets server-side, client-side will get flags and render appropriately
- show_deleted = string_as_bool_or_none( show_deleted )
- show_purged = show_deleted
- show_hidden = string_as_bool_or_none( show_hidden )
- params = Params( kwd )
- message = params.get( 'message', '' )
- #TODO: ugh...
- message = message if message != 'None' else ''
- status = params.get( 'status', 'done' )
-
- if trans.app.config.require_login and not trans.user:
- return trans.fill_template( '/no_access.mako', message = 'Please log in to access Galaxy histories.' )
-
- def err_msg( where=None ):
- where = where if where else 'getting the history data from the server'
- err_msg = ( 'An error occurred %s. '
- + 'Please contact a Galaxy administrator if the problem persists.' ) %( where )
- return err_msg, 'error'
-
+ def _get_current_history_data( self, trans ):
history_dictionary = {}
hda_dictionaries = []
+
try:
history = trans.get_history( create=True )
hdas = self.get_history_datasets( trans, history,
show_deleted=True, show_hidden=True, show_purged=True )
for hda in hdas:
+ hda_dict = {}
try:
- hda_dictionaries.append( self.get_hda_dict( trans, hda ) )
+ hda_dict = self.get_hda_dict( trans, hda )
except Exception, exc:
# don't fail entire list if hda err's, record and move on
log.error( 'Error bootstrapping hda %d: %s', hda.id, str( exc ), exc_info=True )
- hda_dictionaries.append( self.get_hda_dict_with_error( trans, hda, str( exc ) ) )
+ hda_dict = self.get_hda_dict_with_error( trans, hda, str( exc ) )
+
+ hda_dictionaries.append( hda_dict )
# re-use the hdas above to get the history data...
history_dictionary = self.get_history_dict( trans, history, hda_dictionaries=hda_dictionaries )
except Exception, exc:
user_id = str( trans.user.id ) if trans.user else '(anonymous)'
- log.error( 'Error bootstrapping history for user %s: %s', user_id, str( exc ), exc_info=True )
- message, status = err_msg()
+ log.exception( 'Error bootstrapping history for user %s: %s', user_id, str( exc ) )
+ message = ( 'An error occurred getting the history data from the server. '
+ + 'Please contact a Galaxy administrator if the problem persists.' )
history_dictionary[ 'error' ] = message
- return trans.stream_template_mako( "root/history.mako",
- history_json = to_json_string( history_dictionary ), hda_json = to_json_string( hda_dictionaries ),
- show_deleted=show_deleted, show_hidden=show_hidden, hda_id=hda_id, log=log, message=message, status=status )
+ return {
+ 'history' : history_dictionary,
+ 'hdas' : hda_dictionaries
+ }
+
+ @web.expose
+ def history( self, trans, as_xml=False, show_deleted=None, show_hidden=None, **kwd ):
+ """
+ Display the current history in it's own page or as xml.
+ """
+ if as_xml:
+ return self.history_as_xml( trans,
+ show_deleted=string_as_bool( show_deleted ), show_hidden=string_as_bool( show_hidden ) )
+
+ if trans.app.config.require_login and not trans.user:
+ return trans.fill_template( '/no_access.mako', message = 'Please log in to access Galaxy histories.' )
+
+ # get all datasets server-side, client-side will get flags and render appropriately
+ show_deleted = string_as_bool_or_none( show_deleted )
+ show_purged = show_deleted
+ show_hidden = string_as_bool_or_none( show_hidden )
+
+ history_dictionary = {}
+ hda_dictionaries = []
+ try:
+ history_data = self._get_current_history_data( trans )
+ history_dictionary = history_data[ 'history' ]
+ hda_dictionaries = history_data[ 'hdas' ]
+
+ except Exception, exc:
+ user_id = str( trans.user.id ) if trans.user else '(anonymous)'
+ log.exception( 'Error bootstrapping history for user %s: %s', user_id, str( exc ) )
+ history_dictionary[ 'error' ] = ( 'An error occurred getting the history data from the server. '
+ + 'Please contact a Galaxy administrator if the problem persists.' )
+
+ return trans.fill_template_mako( "root/history.mako",
+ history = history_dictionary, hdas = hda_dictionaries,
+ show_deleted=show_deleted, show_hidden=show_hidden )
## ---- Dataset display / editing ----------------------------------------
@web.expose
@@ -503,7 +516,22 @@
return rval
@web.expose
- def generate_error( self, trans ):
+ def generate_error( self, trans, code=500 ):
"""Raises an exception (debugging).
"""
+ trans.response.status = code
raise Exception( "Fake error!" )
+
+ @web.json
+ def generate_json_error( self, trans, code=500 ):
+ """Raises an exception (debugging).
+ """
+ try:
+ code = int( code )
+ except Exception, exc:
+ code = 500
+
+ if code == 502:
+ raise HTTPBadGateway()
+ trans.response.status = code
+ return { 'error': 'Fake error!' }
diff -r 6882fa888d10b469524669325a547a2c0f6c7e41 -r 4f1c25230dd009efd1f04f8d7a74d83733f8b75a lib/galaxy/webapps/galaxy/controllers/tool_runner.py
--- a/lib/galaxy/webapps/galaxy/controllers/tool_runner.py
+++ b/lib/galaxy/webapps/galaxy/controllers/tool_runner.py
@@ -325,4 +325,5 @@
<p><b>Please do not use your browser\'s "stop" or "reload" buttons until the upload is complete, or it may be interrupted.</b></p><p>You may safely continue to use Galaxy while the upload is in progress. Using "stop" and "reload" on pages other than Galaxy is also safe.</p>
"""
+ #return trans.show_message( msg, refresh_frames=[ 'history' ] )
return trans.show_message( msg )
diff -r 6882fa888d10b469524669325a547a2c0f6c7e41 -r 4f1c25230dd009efd1f04f8d7a74d83733f8b75a static/scripts/mvc/base-mvc.js
--- a/static/scripts/mvc/base-mvc.js
+++ b/static/scripts/mvc/base-mvc.js
@@ -7,31 +7,30 @@
name: null,
hidden: false
},
-
+
show: function() {
this.set("hidden", false);
},
-
+
hide: function() {
this.set("hidden", true);
},
-
+
is_visible: function() {
return !this.attributes.hidden;
}
});
-
/**
* Base view that handles visibility based on model's hidden attribute.
*/
var BaseView = Backbone.View.extend({
-
+
initialize: function() {
this.model.on("change:hidden", this.update_visible, this);
this.update_visible();
},
-
+
update_visible: function() {
if( this.model.attributes.hidden ){
this.$el.hide();
@@ -120,7 +119,8 @@
// ~constants for the current engine
var STORAGE_ENGINE = sessionStorage,
STORAGE_ENGINE_GETTER = function sessionStorageGet( key ){
- return JSON.parse( this.getItem( key ) );
+ var item = this.getItem( key );
+ return ( item !== null )?( JSON.parse( this.getItem( key ) ) ):( null );
},
STORAGE_ENGINE_SETTER = function sessionStorageSet( key, val ){
return this.setItem( key, JSON.stringify( val ) );
@@ -182,7 +182,7 @@
}
//??: more readable to make another class?
- var returnedStorage = {};
+ var returnedStorage = {},
// attempt to get starting data from engine...
data = STORAGE_ENGINE_GETTER.call( STORAGE_ENGINE, storageKey );
@@ -216,3 +216,63 @@
return returnedStorage;
};
+
+
+//==============================================================================
+function LoadingIndicator( $where ){
+ var self = this,
+ $indicator;
+
+ function setPosition(){
+ // even tho pos is 'fixed' - give illusion of width 100% and margin by manually setting width, offset
+ var padding = 4,
+ width = $indicator.parent().width() || $where.width(),
+ offset = $indicator.parent().offset() || $where.offset();
+
+ $indicator.outerWidth( width - ( padding * 2 ) );
+ // have to use css top, left and not offset (wont work when indicator is hidden)
+ $indicator.css({ top: offset.top + padding + 'px' , left: offset.left + padding + 'px' });
+ }
+
+ function render(){
+ var $spinner = $( '<span class="fa-icon-spinner fa-icon-spin fa-icon-large"></span>')
+ .css({ 'color' : 'grey', 'font-size' : '16px' });
+ var $message = $( '<i>loading...</i>' )
+ .css({ 'color' : 'grey', 'margin-left' : '8px' });
+ $indicator = $( '<div/>' ).addClass( 'loading-indicator' )
+ .css({
+ 'position' : 'fixed',
+ 'padding' : '4px',
+ 'text-align' : 'center',
+ 'background-color' : 'white',
+ 'opacity' : '0.85',
+ 'border-radius' : '3px'
+ })
+ .append( $spinner, $message )
+ //NOTE: insert as sibling to $where
+ .insertBefore( $where );
+ setPosition();
+ return $indicator.hide();
+ }
+
+ self.show = function( speed, callback ){
+ speed = speed || 'fast';
+ setPosition();
+ $indicator.fadeIn( speed, callback );
+ // not using full fadeOut allows using scroll to still work
+ //$whatIsLoading.fadeTo( speed, 0.0001, callback );
+ return self;
+ };
+
+ self.hide = function( speed, callback ){
+ speed = speed || 'fast';
+ //$whatIsLoading.fadeTo( speed, 1.0, function(){
+ // if( callback ){ callback(); }
+ //});
+ $indicator.fadeOut( speed, callback );
+ return self;
+ };
+ $indicator = render();
+ return self;
+}
+
diff -r 6882fa888d10b469524669325a547a2c0f6c7e41 -r 4f1c25230dd009efd1f04f8d7a74d83733f8b75a static/scripts/mvc/dataset/hda-base.js
--- a/static/scripts/mvc/dataset/hda-base.js
+++ b/static/scripts/mvc/dataset/hda-base.js
@@ -1,7 +1,6 @@
-//define([
-// "../mvc/base-mvc"
-//], function(){
-
+define([
+ "mvc/dataset/hda-model"
+], function( hdaModel ){
/* global Backbone, LoggableMixin, HistoryDatasetAssociation, HDABaseView */
//==============================================================================
/** @class Read only view for HistoryDatasetAssociation.
@@ -22,6 +21,8 @@
tagName : "div",
className : "historyItemContainer",
+ fxSpeed : 'fast',
+
// ......................................................................... SET UP
/** Set up the view, cache url templates, bind listeners
* @param {Object} attributes
@@ -38,33 +39,20 @@
this._render_showParamsButton
];
- // cache urlTemplates (gen. provided by GalaxyPaths) to urls
- if( !attributes.urlTemplates ){ throw( 'HDAView needs urlTemplates on initialize' ); }
- this.urlTemplates = attributes.urlTemplates;
-
/** is the body of this hda view expanded/not. */
this.expanded = attributes.expanded || false;
+ this._setUpListeners();
+ },
+ _setUpListeners : function(){
// re-rendering on any model changes
- this.model.bind( 'change', function( model, options ){
- // if more than the display apps have changed: render everything
- var nonDisplayAppChanges = _.omit( this.model.changedAttributes(), 'display_apps', 'display_types' );
- if( _.keys( nonDisplayAppChanges ).length ){
- this.render();
+ this.model.on( 'change', this.render, this );
- // if just the display links, and it's already expanded: render the links only
- } else {
- if( this.expanded ){
- this._render_displayApps();
- }
- }
- }, this );
-
- //this.bind( 'all', function( event ){
+ //this.on( 'all', function( event ){
// this.log( event );
//}, this );
},
-
+
// ......................................................................... RENDER MAIN
/** Render this HDA, set up ui.
* @fires rendered:ready when rendered and NO running HDAs
@@ -86,9 +74,8 @@
// handle that here by removing previous view's tooltips
this.$el.find("[title]").tooltip( "destroy" );
- /** web controller urls for functions relating to this hda.
- * These are rendered from urlTemplates using the model data. */
- this.urls = this._renderUrls( this.urlTemplates, this.model.toJSON() );
+ /** web controller urls for functions relating to this hda. */
+ this.urls = this.model.urls();
itemWrapper
.addClass( 'historyItemWrapper' ).addClass( 'historyItem' )
@@ -104,9 +91,9 @@
itemWrapper.append( this.body );
// transition...
- this.$el.fadeOut( 'fast', function(){
+ this.$el.fadeOut( this.fxSpeed, function(){
view.$el.children().remove();
- view.$el.append( itemWrapper ).fadeIn( 'fast', function(){
+ view.$el.append( itemWrapper ).fadeIn( view.fxSpeed, function(){
view.log( view + ' rendered:', view.$el );
var renderedEventName = 'rendered';
@@ -121,55 +108,6 @@
return this;
},
- /** render the urls for this hda using the model data and the url templates from initialize.
- * @param {Object} urlTemplates a map (or nested map) of underscore templates (currently, anyhoo)
- * @param {Object} modelJson data from the model
- * @returns {Object} the templated urls
- */
- _renderUrls : function( urlTemplates, modelJson ){
- var hdaView = this,
- urls = {};
- _.each( urlTemplates, function( urlTemplateOrObj, urlKey ){
- // object == nested templates: recurse
- if( _.isObject( urlTemplateOrObj ) ){
- urls[ urlKey ] = hdaView._renderUrls( urlTemplateOrObj, modelJson );
-
- // string == template:
- } else {
- // meta_down load is a special case (see renderMetaDownloadUrls)
- //TODO: should be a better (gen.) way to handle this case
- if( urlKey === 'meta_download' ){
- urls[ urlKey ] = hdaView._renderMetaDownloadUrls( urlTemplateOrObj, modelJson );
-
- } else {
- try {
- urls[ urlKey ] = _.template( urlTemplateOrObj, modelJson );
- } catch( Error ){
- throw( hdaView + '._renderUrls error: ' + Error +
- '\n rendering:' + urlTemplateOrObj +
- '\n with ' + JSON.stringify( modelJson ) );
- }
- }
- }
- });
- return urls;
- },
-
- /** there can be more than one meta_file (e.g. bam index) to download,
- * so return a list of url and file_type for each
- * @param {Object} urlTemplate underscore templates for meta download urls
- * @param {Object} modelJson data from the model
- * @returns {Object} url and filetype for each meta file
- */
- _renderMetaDownloadUrls : function( urlTemplate, modelJson ){
- return _.map( modelJson.meta_files, function( meta_file ){
- return {
- url : _.template( urlTemplate, { id: modelJson.id, file_type: meta_file.file_type }),
- file_type : meta_file.file_type
- };
- });
- },
-
/** set up js behaviors, event handlers for elements within the given container
* @param {jQuery} $container jq object that contains the elements to process (defaults to this.$el)
*/
@@ -218,8 +156,8 @@
_render_displayButton : function(){
// don't show display if not viewable or not accessible
// (do show if in error, running)
- if( ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
- || ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NEW )
+ if( ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
+ || ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NEW )
|| ( !this.model.get( 'accessible' ) ) ){
this.displayButton = null;
return null;
@@ -237,7 +175,7 @@
displayBtnData.title = _l( 'Cannot display datasets removed from disk' );
// disable if still uploading
- } else if( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.UPLOAD ){
+ } else if( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.UPLOAD ){
displayBtnData.enabled = false;
displayBtnData.title = _l( 'This dataset must finish uploading before it can be viewed' );
@@ -406,40 +344,40 @@
body.html( '' );
//TODO: not a fan of this dispatch
switch( this.model.get( 'state' ) ){
- case HistoryDatasetAssociation.STATES.NEW :
+ case hdaModel.HistoryDatasetAssociation.STATES.NEW :
this._render_body_new( body );
break;
- case HistoryDatasetAssociation.STATES.NOT_VIEWABLE :
+ case hdaModel.HistoryDatasetAssociation.STATES.NOT_VIEWABLE :
this._render_body_not_viewable( body );
break;
- case HistoryDatasetAssociation.STATES.UPLOAD :
+ case hdaModel.HistoryDatasetAssociation.STATES.UPLOAD :
this._render_body_uploading( body );
break;
- case HistoryDatasetAssociation.STATES.PAUSED:
+ case hdaModel.HistoryDatasetAssociation.STATES.PAUSED:
this._render_body_paused( body );
break;
- case HistoryDatasetAssociation.STATES.QUEUED :
+ case hdaModel.HistoryDatasetAssociation.STATES.QUEUED :
this._render_body_queued( body );
break;
- case HistoryDatasetAssociation.STATES.RUNNING :
+ case hdaModel.HistoryDatasetAssociation.STATES.RUNNING :
this._render_body_running( body );
break;
- case HistoryDatasetAssociation.STATES.ERROR :
+ case hdaModel.HistoryDatasetAssociation.STATES.ERROR :
this._render_body_error( body );
break;
- case HistoryDatasetAssociation.STATES.DISCARDED :
+ case hdaModel.HistoryDatasetAssociation.STATES.DISCARDED :
this._render_body_discarded( body );
break;
- case HistoryDatasetAssociation.STATES.SETTING_METADATA :
+ case hdaModel.HistoryDatasetAssociation.STATES.SETTING_METADATA :
this._render_body_setting_metadata( body );
break;
- case HistoryDatasetAssociation.STATES.EMPTY :
+ case hdaModel.HistoryDatasetAssociation.STATES.EMPTY :
this._render_body_empty( body );
break;
- case HistoryDatasetAssociation.STATES.FAILED_METADATA :
+ case hdaModel.HistoryDatasetAssociation.STATES.FAILED_METADATA :
this._render_body_failed_metadata( body );
break;
- case HistoryDatasetAssociation.STATES.OK :
+ case hdaModel.HistoryDatasetAssociation.STATES.OK :
this._render_body_ok( body );
break;
default:
@@ -591,27 +529,44 @@
* @fires body-expanded when a body has been expanded
* @fires body-collapsed when a body has been collapsed
*/
- toggleBodyVisibility : function( event, expanded ){
+ toggleBodyVisibility : function( event, expand ){
var hdaView = this;
- this.expanded = ( expanded === undefined )?( !this.body.is( ':visible' ) ):( expanded );
- //this.log( 'toggleBodyVisibility, expanded:', expanded, '$body:', $body );
+ expand = ( expand === undefined )?( !this.body.is( ':visible' ) ):( expand );
+ if( expand ){
+ if( this.model.inReadyState() && !this.model.hasDetails() ){
+ var xhr = this.model.fetch();
+ xhr.done( function( model ){
+ hdaView.expandBody();
+ });
+ } else {
+ this.expandBody();
+ }
+ } else {
+ this.collapseBody();
+ }
+ },
- if( this.expanded ){
- hdaView._render_body_html( hdaView.body );
- this.body.slideDown( 'fast', function(){
- hdaView.trigger( 'body-expanded', hdaView.model.get( 'id' ) );
- });
- } else {
- this.body.slideUp( 'fast', function(){
- hdaView.trigger( 'body-collapsed', hdaView.model.get( 'id' ) );
- });
- }
+ expandBody : function(){
+ var hdaView = this;
+ hdaView._render_body_html( hdaView.body );
+ this.body.slideDown( hdaView.fxSpeed, function(){
+ hdaView.expanded = true;
+ hdaView.trigger( 'body-expanded', hdaView.model.get( 'id' ) );
+ });
+ },
+
+ collapseBody : function(){
+ var hdaView = this;
+ this.body.slideUp( hdaView.fxSpeed, function(){
+ hdaView.expanded = false;
+ hdaView.trigger( 'body-collapsed', hdaView.model.get( 'id' ) );
+ });
},
// ......................................................................... DELETION
remove : function( callback ){
var hdaView = this;
- this.$el.fadeOut( 'fast', function(){
+ this.$el.fadeOut( hdaView.fxSpeed, function(){
hdaView.$el.remove();
hdaView.off();
if( callback ){ callback(); }
@@ -638,6 +593,6 @@
};
//==============================================================================
-//return {
-// HDABaseView : HDABaseView,
-//};});
+return {
+ HDABaseView : HDABaseView,
+};});
diff -r 6882fa888d10b469524669325a547a2c0f6c7e41 -r 4f1c25230dd009efd1f04f8d7a74d83733f8b75a static/scripts/mvc/dataset/hda-edit.js
--- a/static/scripts/mvc/dataset/hda-edit.js
+++ b/static/scripts/mvc/dataset/hda-edit.js
@@ -1,6 +1,7 @@
-//define([
-// "../mvc/base-mvc"
-//], function(){
+define([
+ "mvc/dataset/hda-model",
+ "mvc/dataset/hda-base"
+], function( hdaModel, hdaBase ){
//==============================================================================
/** @class Editing view for HistoryDatasetAssociation.
* @name HDAEditView
@@ -10,7 +11,7 @@
* @borrows LoggableMixin#log as #log
* @constructs
*/
-var HDAEditView = HDABaseView.extend( LoggableMixin ).extend(
+var HDAEditView = hdaBase.HDABaseView.extend( LoggableMixin ).extend(
/** @lends HDAEditView.prototype */{
// ......................................................................... SET UP
@@ -22,7 +23,8 @@
* @see HDABaseView#initialize
*/
initialize : function( attributes ){
- HDABaseView.prototype.initialize.call( this, attributes );
+ hdaBase.HDABaseView.prototype.initialize.call( this, attributes );
+ this.hasUser = attributes.hasUser;
/** list of rendering functions for the default, primary icon-buttons. */
this.defaultPrimaryActionButtonRenderers = [
@@ -37,33 +39,8 @@
* @param {jQuery} $container jq object that contains the elements to process (defaults to this.$el)
*/
_setUpBehaviors : function( $container ){
- //TODO: ideally this would be a DELETE call to the api
- // using purge async for now
- HDABaseView.prototype._setUpBehaviors.call( this, $container );
-
- // use purge_async with an ajax call
- var hdaView = this,
- purge_url = this.urls.purge,
- purge_link = $container.find( '#historyItemPurger-' + this.model.get( 'id' ) );
- if( purge_link ){
- //TODO: remove href from template
- purge_link.attr( 'href', [ "javascript", "void(0)" ].join( ':' ) );
- purge_link.click( function( event ){
- //TODO??: confirm?
- var xhr = jQuery.ajax( purge_url );
- xhr.success( function( message, status, responseObj ){
- hdaView.model.set( 'purged', true );
- hdaView.trigger( 'purged', hdaView );
- });
- xhr.error( function( error, status, message ){
- //TODO: Exception messages are hidden within error page
- //!NOTE: that includes the 'Removal of datasets by users is not allowed in this Galaxy instance.'
- view.trigger( 'error',
- hdaView, xhr, { url: purge_url }, _l( "Unable to purge this dataset" ) );
- });
- });
- }
- //TODO: same with undelete_async
+ hdaBase.HDABaseView.prototype._setUpBehaviors.call( this, $container );
+ //var hdaView = this;
},
// ......................................................................... RENDER WARNINGS
@@ -74,7 +51,7 @@
*/
_render_warnings : function(){
// jQ errs on building dom with whitespace - if there are no messages, trim -> ''
- return $( jQuery.trim( HDABaseView.templates.messages(
+ return $( jQuery.trim( hdaBase.HDABaseView.templates.messages(
_.extend( this.model.toJSON(), { urls: this.urls } )
)));
},
@@ -101,9 +78,9 @@
// don't show edit while uploading, in-accessible
// DO show if in error (ala previous history panel)
//TODO??: not viewable/accessible are essentially the same (not viewable set from accessible)
- if( ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NEW )
- || ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.UPLOAD )
- || ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
+ if( ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NEW )
+ || ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.UPLOAD )
+ || ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
|| ( !this.model.get( 'accessible' ) ) ){
this.editButton = null;
return null;
@@ -138,44 +115,26 @@
_render_deleteButton : function(){
// don't show delete if...
//TODO??: not viewable/accessible are essentially the same (not viewable set from accessible)
- if( ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NEW )
- || ( this.model.get( 'state' ) === HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
+ if( ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NEW )
+ || ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
|| ( !this.model.get( 'accessible' ) ) ){
this.deleteButton = null;
return null;
}
var self = this,
+ id = 'historyItemDeleter-' + self.model.get( 'id' ),
delete_url = self.urls[ 'delete' ],
deleteBtnData = {
- title : _l( 'Delete' ),
- href : delete_url,
- id : 'historyItemDeleter-' + this.model.get( 'id' ),
- icon_class : 'delete',
- on_click : function() {
- // Delete the dataset on the server and update HDA + view depending on success/failure.
- // FIXME: when HDA-delete is implemented in the API, can call set(), then save directly
- // on the model.
- $.ajax({
- url: delete_url,
- type: 'POST',
- error: function() {
- // Something went wrong, so show HDA again.
- // TODO: an error notification would be good.
- self.trigger( 'error', self, null, null, { url: delete_url }, _l( 'deletion failed' ) );
- self.$el.show();
- },
- success: function() {
- // FIXME: setting model attribute causes re-rendering, which is unnecessary.
- //self.$el.remove();
-
- self.model.set({ deleted: true });
- }
- });
-
- // Return false so that anchor action (page reload) does not happen.
- //return false;
- }
+ title : _l( 'Delete' ),
+ href : delete_url,
+ id : id,
+ icon_class : 'delete',
+ on_click : function() {
+ // ...bler... tooltips being left behind in DOM (hover out never called on deletion)
+ self.$el.find( '.menu-button.delete' ).trigger( 'mouseout' );
+ self.model[ 'delete' ]();
+ }
};
if( this.model.get( 'deleted' ) || this.model.get( 'purged' ) ){
deleteBtnData = {
@@ -202,7 +161,7 @@
//TODO: use HDABaseView and select/replace base on this switch
_.extend( modelData, { dbkey_unknown_and_editable : true });
}
- return HDABaseView.templates.hdaSummary( modelData );
+ return hdaBase.HDABaseView.templates.hdaSummary( modelData );
},
// ......................................................................... primary actions
@@ -210,7 +169,7 @@
* @returns {jQuery} rendered DOM
*/
_render_errButton : function(){
- if( this.model.get( 'state' ) !== HistoryDatasetAssociation.STATES.ERROR ){
+ if( this.model.get( 'state' ) !== hdaModel.HistoryDatasetAssociation.STATES.ERROR ){
this.errButton = null;
return null;
}
@@ -378,8 +337,7 @@
//TODO: these should be a sub-MV
_render_tagButton : function(){
//TODO: check for User
- if( !( this.model.hasData() )
- || ( !this.urls.tags.get ) ){
+ if( !this.hasUser || !this.urls.tags.get ){
this.tagButton = null;
return null;
}
@@ -399,8 +357,7 @@
//TODO: these should be a sub-MV
_render_annotateButton : function(){
//TODO: check for User
- if( !( this.model.hasData() )
- || ( !this.urls.annotation.get ) ){
+ if( !this.hasUser || !this.urls.annotation.get ){
this.annotateButton = null;
return null;
}
@@ -417,8 +374,8 @@
/** Render area to display tags.
* @returns {jQuery} rendered DOM
*/
- //TODO: into sub-MV
- //TODO: check for User
+//TODO: into sub-MV
+//TODO: check for User
_render_tagArea : function(){
if( !this.urls.tags.set ){ return null; }
//TODO: move to mvc/tags.js
@@ -430,8 +387,8 @@
/** Render area to display annotation.
* @returns {jQuery} rendered DOM
*/
- //TODO: into sub-MV
- //TODO: check for User
+//TODO: into sub-MV
+//TODO: check for User
_render_annotationArea : function(){
if( !this.urls.annotation.get ){ return null; }
//TODO: move to mvc/annotations.js
@@ -447,7 +404,7 @@
* @see HDABaseView#_render_body_error
*/
_render_body_error : function( parent ){
- HDABaseView.prototype._render_body_error.call( this, parent );
+ hdaBase.HDABaseView.prototype._render_body_error.call( this, parent );
var primaryActions = parent.find( '#primary-actions-' + this.model.get( 'id' ) );
primaryActions.prepend( this._render_errButton() );
},
@@ -498,11 +455,21 @@
/** event map */
events : {
'click .historyItemTitle' : 'toggleBodyVisibility',
+ 'click .historyItemUndelete' : function( ev ){ this.model.undelete(); return false; },
+ 'click .historyItemUnhide' : function( ev ){ this.model.unhide(); return false; },
+ 'click .historyItemPurge' : 'confirmPurge',
+
'click a.icon-button.tags' : 'loadAndDisplayTags',
'click a.icon-button.annotate' : 'loadAndDisplayAnnotation'
},
// ......................................................................... STATE CHANGES / MANIPULATION
+ confirmPurge : function _confirmPurge( ev ){
+ //TODO: confirm dialog
+ this.model.purge({ url: this.urls.purge });
+ return false;
+ },
+
/** Find the tag area and, if initial: load the html (via ajax) for displaying them; otherwise, unhide/hide
*/
//TODO: into sub-MV
@@ -523,30 +490,29 @@
url: this.urls.tags.get,
error: function( xhr, status, error ){
view.log( "Tagging failed", xhr, status, error );
- view.trigger( 'error', view, xhr, { url: view.urls.tags.get }, _l( "Tagging failed" ) );
+ view.trigger( 'error', view, xhr, {}, _l( "Tagging failed" ) );
},
success: function(tag_elt_html) {
tagElt.html(tag_elt_html);
tagElt.find("[title]").tooltip();
- tagArea.slideDown("fast");
+ tagArea.slideDown( view.fxSpeed );
}
});
} else {
// Tag element is filled; show.
- tagArea.slideDown("fast");
+ tagArea.slideDown( view.fxSpeed );
}
} else {
// Hide.
- tagArea.slideUp("fast");
+ tagArea.slideUp( view.fxSpeed );
}
return false;
},
/** Find the annotation area and, if initial: load the html (via ajax) for displaying them; otherwise, unhide/hide
*/
- //TODO: into sub-MV
loadAndDisplayAnnotation : function( event ){
- //TODO: this is a drop in from history.mako - should use MV as well
+//TODO: this is a drop in from history.mako - should use MV as well
this.log( this + '.loadAndDisplayAnnotation', event );
var view = this,
annotationArea = this.$el.find( '.annotation-area' ),
@@ -559,10 +525,9 @@
// Need to fill annotation element.
$.ajax({
url: this.urls.annotation.get,
- error: function( xhr, status, message ){
- view.log( "Annotation failed", xhr, status, message );
- view.trigger( 'error',
- view, xhr, { url: view.urls.annotation.get }, _l( "Annotation failed" ) );
+ error: function(){
+ view.log( "Annotation failed", xhr, status, error );
+ view.trigger( 'error', view, xhr, {}, _l( "Annotation failed" ) );
},
success: function( htmlFromAjax ){
if( htmlFromAjax === "" ){
@@ -576,16 +541,16 @@
setAnnotationUrl,
"new_annotation", 18, true, 4
);
- annotationArea.slideDown("fast");
+ annotationArea.slideDown( view.fxSpeed );
}
});
} else {
- annotationArea.slideDown("fast");
+ annotationArea.slideDown( view.fxSpeed );
}
} else {
// Hide.
- annotationArea.slideUp("fast");
+ annotationArea.slideUp( view.fxSpeed );
}
return false;
},
@@ -712,6 +677,6 @@
//==============================================================================
-//return {
-// HDAView : HDAView,
-//};});
+return {
+ HDAEditView : HDAEditView,
+};});
diff -r 6882fa888d10b469524669325a547a2c0f6c7e41 -r 4f1c25230dd009efd1f04f8d7a74d83733f8b75a static/scripts/mvc/dataset/hda-model.js
--- a/static/scripts/mvc/dataset/hda-model.js
+++ b/static/scripts/mvc/dataset/hda-model.js
@@ -1,6 +1,5 @@
-//define([
-// "../mvc/base-mvc"
-//], function(){
+define([
+], function(){
//==============================================================================
/** @class (HDA) model for a Galaxy dataset
* related to a history.
@@ -34,6 +33,13 @@
name : '(unnamed dataset)',
// one of HistoryDatasetAssociation.STATES
state : 'new',
+
+ deleted : false,
+ visible : true,
+
+ accessible : true,
+ purged : false,
+
// sniffed datatype (sam, tabular, bed, etc.)
data_type : null,
// size in bytes
@@ -44,37 +50,67 @@
meta_files : [],
misc_blurb : '',
- misc_info : '',
-
- deleted : false,
- purged : false,
- visible : true,
- accessible : true
+ misc_info : ''
},
/** fetch location of this history in the api */
urlRoot: 'api/histories/',
url : function(){
- //TODO: get this via url router
return this.urlRoot + this.get( 'history_id' ) + '/contents/' + this.get( 'id' );
- //TODO: this breaks on save()
},
+ urls : function(){
+ var id = this.get( 'id' );
+ if( !id ){ return {}; }
+ var urls = {
+ 'delete' : '/datasets/' + id + '/delete_async',
+ 'purge' : '/datasets/' + id + '/purge_async',
+ 'unhide' : '/datasets/' + id + '/unhide',
+ 'undelete' : '/datasets/' + id + '/undelete',
+
+ 'display' : '/datasets/' + id + '/display/?preview=True',
+ 'download' : '/datasets/' + id + '/display?to_ext=' + this.get( 'file_ext' ),
+ 'edit' : '/datasets/' + id + '/edit',
+ 'report_error': '/dataset/errors?id=' + id,
+ 'rerun' : '/tool_runner/rerun?id=' + id,
+ 'show_params': '/datasets/' + id + '/show_params',
+ 'visualization': '/visualization',
+
+ 'annotation': { 'get': '/dataset/get_annotation_async?id=' + id,
+ 'set': '/dataset/annotate_async?id=' + id },
+ 'tags' : { 'get': '/tag/get_tagging_elt_async?item_id=' + id + '&item_class=HistoryDatasetAssociation',
+ 'set': '/tag/retag?item_id=' + id + '&item_class=HistoryDatasetAssociation' }
+ };
+ //'meta_download': '/dataset/get_metadata_file?hda_id=%3C%25%3D+id+%25%3E&metadata_name=%3C%25%3D+file_type+%25%3E',
+ var meta_files = this.get( 'meta_files' );
+ if( meta_files ){
+ urls.meta_download = _.map( meta_files, function( meta_file ){
+ return {
+ //url : _.template( urlTemplate, { id: modelJson.id, file_type: meta_file.file_type }),
+ url : '/dataset/get_metadata_file?hda_id=' + id + '&metadata_name=' + meta_file.file_type,
+ file_type : meta_file.file_type
+ };
+ });
+ }
+ return urls;
+ },
+
/** Set up the model, determine if accessible, bind listeners
* @see Backbone.Model#initialize
*/
- //TODO:? use initialize (or validate) to check purged AND deleted -> purged XOR deleted
- initialize : function(){
+ initialize : function( data ){
this.log( this + '.initialize', this.attributes );
this.log( '\tparent history_id: ' + this.get( 'history_id' ) );
- // (curr) only handles changing state of non-accessible hdas to STATES.NOT_VIEWABLE
//!! this state is not in trans.app.model.Dataset.states - set it here -
- //TODO: change to server side.
if( !this.get( 'accessible' ) ){
this.set( 'state', HistoryDatasetAssociation.STATES.NOT_VIEWABLE );
}
+ this._setUpListeners();
+ },
+
+ _setUpListeners : function(){
// if the state has changed and the new state is a ready state, fire an event
this.on( 'change:state', function( currModel, newState ){
this.log( this + ' has changed state:', currModel, newState );
@@ -82,16 +118,9 @@
this.trigger( 'state:ready', currModel, newState, this.previous( 'state' ) );
}
});
-
- // debug on change events
- //this.on( 'change', function( currModel, changedList ){
- // this.log( this + ' has changed:', currModel, changedList );
- //});
- //this.bind( 'all', function( event ){
- // this.log( this + '', arguments );
- //});
},
+ // ........................................................................ common queries
/** Is this hda deleted or purged?
*/
isDeletedOrPurged : function(){
@@ -117,24 +146,21 @@
return isVisible;
},
+ hidden : function(){
+ return !this.get( 'visible' );
+ },
+
/** Is this HDA in a 'ready' state; where 'Ready' states are states where no
* processing (for the ds) is left to do on the server.
- * Currently: NEW, OK, EMPTY, FAILED_METADATA, NOT_VIEWABLE, DISCARDED,
- * and ERROR
*/
inReadyState : function(){
- var state = this.get( 'state' );
- //TODO: to list inclusion test
- //TODO: class level readyStates list
- return (
- this.isDeletedOrPurged()
- || ( state === HistoryDatasetAssociation.STATES.OK )
- || ( state === HistoryDatasetAssociation.STATES.EMPTY )
- || ( state === HistoryDatasetAssociation.STATES.FAILED_METADATA )
- || ( state === HistoryDatasetAssociation.STATES.NOT_VIEWABLE )
- || ( state === HistoryDatasetAssociation.STATES.DISCARDED )
- || ( state === HistoryDatasetAssociation.STATES.ERROR )
- );
+ var ready = _.contains( HistoryDatasetAssociation.READY_STATES, this.get( 'state' ) );
+ return ( this.isDeletedOrPurged() || ready );
+ },
+
+ hasDetails : function(){
+ //?? this may not be reliable
+ return _.has( this.attributes, 'genome_build' );
},
/** Convenience function to match hda.has_data.
@@ -144,6 +170,64 @@
return ( this.get( 'file_size' ) > 0 );
},
+ // ........................................................................ ajax
+ 'delete' : function _delete( options ){
+ return this.save( { deleted: true }, options );
+ },
+ undelete : function _undelete( options ){
+ return this.save( { deleted: false }, options );
+ },
+
+ hide : function _hide( options ){
+ return this.save( { visible: false }, options );
+ },
+ unhide : function _uhide( options ){
+ return this.save( { visible: true }, options );
+ },
+
+ purge : function _purge( options ){
+ //TODO: ideally this would be a DELETE call to the api
+ // using purge async for now
+ var hda = this,
+ xhr = jQuery.ajax( options );
+ xhr.done( function( message, status, responseObj ){
+ hda.set( 'purged', true );
+ });
+ xhr.fail( function( xhr, status, message ){
+ // Exception messages are hidden within error page including: '...not allowed in this Galaxy instance.'
+ // unbury and re-add to xhr
+ var error = _l( "Unable to purge this dataset" );
+ var messageBuriedInUnfortunatelyFormattedError = ( 'Removal of datasets by users '
+ + 'is not allowed in this Galaxy instance' );
+ if( xhr.responseJSON && xhr.responseJSON.error ){
+ error = xhr.responseJSON.error;
+ } else if( xhr.responseText.indexOf( messageBuriedInUnfortunatelyFormattedError ) !== -1 ){
+ error = messageBuriedInUnfortunatelyFormattedError;
+ }
+ xhr.responseText = error;
+ hda.trigger( 'error', hda, xhr, options, _l( error ), { error: error } );
+ });
+ },
+
+ // ........................................................................ sorting/filtering
+ searchKeys : [
+ 'name', 'file_ext', 'genome_build', 'misc_blurb', 'misc_info', 'annotation', 'tags'
+ ],
+
+ search : function( searchFor ){
+ var model = this;
+ searchFor = searchFor.toLowerCase();
+ return _.filter( this.searchKeys, function( key ){
+ var attr = model.get( key );
+ return ( _.isString( attr ) && attr.toLowerCase().indexOf( searchFor ) !== -1 );
+ });
+ },
+
+ matches : function( matchesWhat ){
+ return !!this.search( matchesWhat ).length;
+ },
+
+ // ........................................................................ misc
/** String representation
*/
toString : function(){
@@ -165,8 +249,6 @@
UPLOAD : 'upload',
/** the job that will produce the dataset queued in the runner */
QUEUED : 'queued',
- /** the job that will produce the dataset paused */
- PAUSED : 'paused',
/** the job that will produce the dataset is running */
RUNNING : 'running',
/** metadata for the dataset is being discovered/set */
@@ -180,6 +262,8 @@
/** has successfully completed running */
OK : 'ok',
+ /** the job that will produce the dataset paused */
+ PAUSED : 'paused',
/** metadata discovery/setting failed or errored (but otherwise ok) */
FAILED_METADATA : 'failed_metadata',
/** not accessible to the current user (i.e. due to permissions) */
@@ -190,6 +274,24 @@
ERROR : 'error'
};
+HistoryDatasetAssociation.READY_STATES = [
+ HistoryDatasetAssociation.STATES.NEW,
+ HistoryDatasetAssociation.STATES.OK,
+ HistoryDatasetAssociation.STATES.EMPTY,
+ HistoryDatasetAssociation.STATES.PAUSED,
+ HistoryDatasetAssociation.STATES.FAILED_METADATA,
+ HistoryDatasetAssociation.STATES.NOT_VIEWABLE,
+ HistoryDatasetAssociation.STATES.DISCARDED,
+ HistoryDatasetAssociation.STATES.ERROR
+];
+
+HistoryDatasetAssociation.NOT_READY_STATES = [
+ HistoryDatasetAssociation.STATES.UPLOAD,
+ HistoryDatasetAssociation.STATES.QUEUED,
+ HistoryDatasetAssociation.STATES.RUNNING,
+ HistoryDatasetAssociation.STATES.SETTING_METADATA
+];
+
//==============================================================================
/** @class Backbone collection of (HDA) models
*
@@ -204,83 +306,35 @@
///** logger used to record this.log messages, commonly set to console */
//// comment this out to suppress log output
//logger : console,
+ urlRoot : '/api/histories',
+ url : function(){
+ return this.urlRoot + '/' + this.historyId + '/contents';
+ },
/** Set up.
* @see Backbone.Collection#initialize
*/
- initialize : function(){
- //this.bind( 'all', function( event ){
- // this.log( this + '', arguments );
- //});
+ initialize : function( models, options ){
+ options = options || {};
+ this.historyId = options.historyId;
+ this._setUpListeners();
},
+ _setUpListeners : function(){
+ },
+
+ // ........................................................................ common queries
/** Get the ids of every hda in this collection
- * @returns array of encoded ids
+ * @returns array of encoded ids
*/
ids : function(){
return this.map( function( hda ){ return hda.id; });
},
- /** Get the hda with the given hid
- * @param {Int} hid the hid to search for
- * @returns {HistoryDatasetAssociation} the hda with the given hid or undefined if not found
- */
- getByHid : function( hid ){
- return _.first( this.filter( function( hda ){ return hda.get( 'hid' ) === hid; }) );
- },
-
- /** If the given hid is in the collection, return it's index. If not, return the insertion point it would need.
- * NOTE: assumes hids are unique and valid
- * @param {Int} hid the hid to find or create. If hid is 0, null, undefined: return the last hid + 1
- * @returns the collection index of the existing hda or an insertion point if it doesn't exist
- */
- hidToCollectionIndex : function( hid ){
- // if the hid is 0, null, undefined: assume a request for a new hid (return the last index)
- if( !hid ){
- return this.models.length;
- }
-
- var endingIndex = this.models.length - 1;
- //TODO: prob. more efficient to cycle backwards through these (assuming ordered by hid)
- for( var i=endingIndex; i>=0; i-- ){
- var hdaHid = this.at( i ).get( 'hid' );
- //this.log( i, 'hdaHid:', hdaHid );
- if( hdaHid === hid ){
- //this.log( '\t match:', hdaHid, hid, ' returning:', i );
- return i;
- }
- if( hdaHid < hid ){
- //this.log( '\t past it, returning:', ( i + 1 ) );
- return i + 1;
- }
- }
- return null;
- },
-
- /** Get every 'shown' hda in this collection based on show_deleted/hidden
- * @param {Boolean} show_deleted are we showing deleted hdas?
- * @param {Boolean} show_hidden are we showing hidden hdas?
- * @returns array of hda models
- * @see HistoryDatasetAssociation#isVisible
- */
- getVisible : function( show_deleted, show_hidden ){
- return this.filter( function( item ){ return item.isVisible( show_deleted, show_hidden ); });
- },
-
- /** For each possible hda state, get an array of all hda ids in that state
- * @returns a map of states -> hda ids
- * @see HistoryDatasetAssociation#STATES
- */
- getStateLists : function(){
- var stateLists = {};
- _.each( _.values( HistoryDatasetAssociation.STATES ), function( state ){
- stateLists[ state ] = [];
+ notReady : function(){
+ return this.filter( function( hda ){
+ return !hda.inReadyState();
});
- //NOTE: will err on unknown state
- this.each( function( item ){
- stateLists[ item.get( 'state' ) ].push( item.get( 'id' ) );
- });
- return stateLists;
},
/** Get the id of every hda in this collection not in a 'ready' state (running).
@@ -297,26 +351,55 @@
return idList;
},
- /** Update (fetch) the data of the hdas with the given ids.
- * @param {String[]} ids an array of hda ids to update
- * @returns {HistoryDatasetAssociation[]} hda models that were updated
- * @see HistoryDatasetAssociation#fetch
+ /** Get the hda with the given hid
+ * @param {Int} hid the hid to search for
+ * @returns {HistoryDatasetAssociation} the hda with the given hid or undefined if not found
*/
- update : function( ids ){
- this.log( this + 'update:', ids );
+ getByHid : function( hid ){
+ return _.first( this.filter( function( hda ){ return hda.get( 'hid' ) === hid; }) );
+ },
- if( !( ids && ids.length ) ){ return []; }
+ /** Get every 'shown' hda in this collection based on show_deleted/hidden
+ * @param {Boolean} show_deleted are we showing deleted hdas?
+ * @param {Boolean} show_hidden are we showing hidden hdas?
+ * @returns array of hda models
+ * @see HistoryDatasetAssociation#isVisible
+ */
+ getVisible : function( show_deleted, show_hidden ){
+ return this.filter( function( item ){ return item.isVisible( show_deleted, show_hidden ); });
+ },
- var collection = this,
- updatedHdas = null;
- _.each( ids, function( id, index ){
- var hda = collection.get( id );
- if( hda ){
- hda.fetch();
- updatedHdas.push( hda );
- }
+ // ........................................................................ ajax
+ fetchAllDetails : function(){
+ return this.fetch({ data : { details : 'all' } });
+ },
+
+ // ........................................................................ sorting/filtering
+ matches : function( matchesWhat ){
+ return this.filter( function( hda ){
+ return hda.matches( matchesWhat );
});
- return updatedHdas;
+ },
+
+ // ........................................................................ misc
+ set : function( models, options ){
+ // arrrrrrrrrrrrrrrrrg...
+ // override to get a correct/smarter merge when incoming data is partial (e.g. stupid backbone)
+ // w/o this partial models from the server will fill in missing data with model defaults
+ // and overwrite existing data on the client
+ // see Backbone.Collection.set and _prepareModel
+ var collection = this;
+ models = _.map( models, function( model ){
+ var existing = collection.get( model.id );
+ if( !existing ){ return model; }
+
+ // merge the models _BEFORE_ calling the superclass version
+ var merged = existing.toJSON();
+ _.extend( merged, model );
+ return merged;
+ });
+ // now call superclass when the data is filled
+ Backbone.Collection.prototype.set.call( this, models, options );
},
/** String representation. */
@@ -326,7 +409,7 @@
});
//==============================================================================
-//return {
-// HistoryDatasetAssociation : HistoryDatasetAssociation,
-// HDACollection : HDACollection,
-//};});
+return {
+ HistoryDatasetAssociation : HistoryDatasetAssociation,
+ HDACollection : HDACollection
+};});
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Datatypes controller should allow anonymous access.
by commits-noreply@bitbucket.org 21 Oct '13
by commits-noreply@bitbucket.org 21 Oct '13
21 Oct '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/81880a04e6e7/
Changeset: 81880a04e6e7
Branch: next-stable
User: dannon
Date: 2013-10-21 22:16:01
Summary: Datatypes controller should allow anonymous access.
Affected #: 1 file
diff -r 000d11c7ce7e6125998d7095a247774a150c120e -r 81880a04e6e79d944a6d9c225b36417114cd38ec lib/galaxy/webapps/galaxy/api/datatypes.py
--- a/lib/galaxy/webapps/galaxy/api/datatypes.py
+++ b/lib/galaxy/webapps/galaxy/api/datatypes.py
@@ -4,13 +4,12 @@
from galaxy import web
from galaxy.web.base.controller import BaseAPIController
-from galaxy.datatypes.registry import Registry
import logging
log = logging.getLogger( __name__ )
class DatatypesController( BaseAPIController ):
- @web.expose_api
+ @web.expose_api_anonymous
def index( self, trans, **kwd ):
"""
GET /api/datatypes
@@ -18,8 +17,7 @@
"""
try:
return trans.app.datatypes_registry.upload_file_formats
-
except Exception, exception:
log.error( 'could not get datatypes: %s', str( exception ), exc_info=True )
trans.response.status = 500
- return { 'error': str( exception ) }
\ No newline at end of file
+ return { 'error': str( exception ) }
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Datatypes controller should allow anonymous access.
by commits-noreply@bitbucket.org 21 Oct '13
by commits-noreply@bitbucket.org 21 Oct '13
21 Oct '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6882fa888d10/
Changeset: 6882fa888d10
User: dannon
Date: 2013-10-21 22:16:01
Summary: Datatypes controller should allow anonymous access.
Affected #: 1 file
diff -r d1fb4c641a79eb5451320397d4e22068d1c95bcf -r 6882fa888d10b469524669325a547a2c0f6c7e41 lib/galaxy/webapps/galaxy/api/datatypes.py
--- a/lib/galaxy/webapps/galaxy/api/datatypes.py
+++ b/lib/galaxy/webapps/galaxy/api/datatypes.py
@@ -4,13 +4,12 @@
from galaxy import web
from galaxy.web.base.controller import BaseAPIController
-from galaxy.datatypes.registry import Registry
import logging
log = logging.getLogger( __name__ )
class DatatypesController( BaseAPIController ):
- @web.expose_api
+ @web.expose_api_anonymous
def index( self, trans, **kwd ):
"""
GET /api/datatypes
@@ -18,8 +17,7 @@
"""
try:
return trans.app.datatypes_registry.upload_file_formats
-
except Exception, exception:
log.error( 'could not get datatypes: %s', str( exception ), exc_info=True )
trans.response.status = 500
- return { 'error': str( exception ) }
\ No newline at end of file
+ return { 'error': str( exception ) }
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
21 Oct '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d1fb4c641a79/
Changeset: d1fb4c641a79
User: natefoo
Date: 2013-10-21 16:10:54
Summary: Merge stable branch.
Affected #: 1 file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Trackster: add needed height config preference.
by commits-noreply@bitbucket.org 19 Oct '13
by commits-noreply@bitbucket.org 19 Oct '13
19 Oct '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2778e2829d28/
Changeset: 2778e2829d28
User: jgoecks
Date: 2013-10-19 21:59:43
Summary: Trackster: add needed height config preference.
Affected #: 1 file
diff -r 95815478f355009d925ea91e95e4db0a9d887ded -r 2778e2829d28bb053b12d47c6615c98052134a83 static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -4220,7 +4220,8 @@
{ key: 'show_sample_data', label: 'Show sample data', type: 'bool', default_value: true },
{ key: 'show_labels', label: 'Show summary and sample labels', type: 'bool', default_value: true },
{ key: 'summary_height', label: 'Locus summary height', type: 'float', default_value: 20 },
- { key: 'mode', type: 'string', default_value: this.mode, hidden: true }
+ { key: 'mode', type: 'string', default_value: this.mode, hidden: true },
+ { key: 'height', type: 'int', default_value: 0, hidden: true }
] ),
config_onchange: function() {
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
18 Oct '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/95815478f355/
Changeset: 95815478f355
User: greg
Date: 2013-10-18 22:43:29
Summary: Enhance the Repair repository feature for tool shed repositories installed into Galaxy to handle repository and tool dependencies that are not only in an error status, but may also have one of the "installing" status values. This feature will now properly handle dependencies that are stuck in one of these installing states foe some reason. Existing system processes are not automatically killed (if they happen to exist), but warning messages are displayed.
Affected #: 7 files
diff -r 068afb09a7ba896f1fdfee104d0b68c0a2e77de3 -r 95815478f355009d925ea91e95e4db0a9d887ded lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -3679,7 +3679,11 @@
"""Return the repository's repository dependencies that are currently being installed."""
required_repositories_being_installed = []
for required_repository in self.repository_dependencies:
- if required_repository.status == self.installation_status.INSTALLING:
+ if required_repository.status in [ self.installation_status.CLONING,
+ self.installation_status.INSTALLING_REPOSITORY_DEPENDENCIES,
+ self.installation_status.INSTALLING_TOOL_DEPENDENCIES,
+ self.installation_status.LOADING_PROPRIETARY_DATATYPES,
+ self.installation_status.SETTING_TOOL_VERSIONS ]:
required_repositories_being_installed.append( required_repository )
return required_repositories_being_installed
diff -r 068afb09a7ba896f1fdfee104d0b68c0a2e77de3 -r 95815478f355009d925ea91e95e4db0a9d887ded lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -1185,6 +1185,21 @@
message=message,
status=status )
+ @web.expose
+ @web.require_admin
+ def repair_tool_shed_repositories( self, trans, tool_shed_repositories, repo_info_dicts, **kwd ):
+ """Repair specified tool shed repositories."""
+ # The received lists of tool_shed_repositories and repo_info_dicts are ordered.
+ for index, tool_shed_repository in enumerate( tool_shed_repositories ):
+ repo_info_dict = repo_info_dicts[ index ]
+ repair_dict = repository_util.repair_tool_shed_repository( trans,
+ tool_shed_repository,
+ encoding_util.tool_shed_encode( repo_info_dict ) )
+ tsr_ids_for_monitoring = [ trans.security.encode_id( tsr.id ) for tsr in tool_shed_repositories ]
+ return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
+ action='monitor_repository_installation',
+ tool_shed_repository_ids=tsr_ids_for_monitoring ) )
+
@web.json
def repository_installation_status_updates( self, trans, ids=None, status_list=None ):
# Avoid caching
@@ -1208,21 +1223,6 @@
@web.expose
@web.require_admin
- def repair_tool_shed_repositories( self, trans, tool_shed_repositories, repo_info_dicts, **kwd ):
- """Repair specified tool shed repositories."""
- # The received lists of tool_shed_repositories and repo_info_dicts are ordered.
- for index, tool_shed_repository in enumerate( tool_shed_repositories ):
- repo_info_dict = repo_info_dicts[ index ]
- repair_dict = repository_util.repair_tool_shed_repository( trans,
- tool_shed_repository,
- encoding_util.tool_shed_encode( repo_info_dict ) )
- tsr_ids_for_monitoring = [ trans.security.encode_id( tsr.id ) for tsr in tool_shed_repositories ]
- return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
- action='monitor_repository_installation',
- tool_shed_repository_ids=tsr_ids_for_monitoring ) )
-
- @web.expose
- @web.require_admin
def reselect_tool_panel_section( self, trans, **kwd ):
"""
Select or change the tool panel section to contain the tools included in the tool shed repository being reinstalled. If there are updates
diff -r 068afb09a7ba896f1fdfee104d0b68c0a2e77de3 -r 95815478f355009d925ea91e95e4db0a9d887ded lib/tool_shed/galaxy_install/grids/admin_toolshed_grids.py
--- a/lib/tool_shed/galaxy_install/grids/admin_toolshed_grids.py
+++ b/lib/tool_shed/galaxy_install/grids/admin_toolshed_grids.py
@@ -101,33 +101,7 @@
class StatusColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool_shed_repository ):
- status_label = tool_shed_repository.status
- if tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.CLONING,
- trans.model.ToolShedRepository.installation_status.SETTING_TOOL_VERSIONS,
- trans.model.ToolShedRepository.installation_status.INSTALLING_REPOSITORY_DEPENDENCIES,
- trans.model.ToolShedRepository.installation_status.INSTALLING_TOOL_DEPENDENCIES,
- trans.model.ToolShedRepository.installation_status.LOADING_PROPRIETARY_DATATYPES ]:
- bgcolor = trans.model.ToolShedRepository.states.INSTALLING
- elif tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.NEW,
- trans.model.ToolShedRepository.installation_status.UNINSTALLED ]:
- bgcolor = trans.model.ToolShedRepository.states.UNINSTALLED
- elif tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.ERROR ]:
- bgcolor = trans.model.ToolShedRepository.states.ERROR
- elif tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.DEACTIVATED ]:
- bgcolor = trans.model.ToolShedRepository.states.WARNING
- elif tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.INSTALLED ]:
- if tool_shed_repository.missing_repository_dependencies:
- bgcolor = trans.model.ToolShedRepository.states.WARNING
- status_label = '%s, missing repository dependencies' % status_label
- elif tool_shed_repository.missing_tool_dependencies:
- bgcolor = trans.model.ToolShedRepository.states.WARNING
- status_label = '%s, missing tool dependencies' % status_label
- else:
- bgcolor = trans.model.ToolShedRepository.states.OK
- else:
- bgcolor = trans.model.ToolShedRepository.states.ERROR
- rval = '<div class="count-box state-color-%s">%s</div>' % ( bgcolor, status_label )
- return rval
+ return suc.get_tool_shed_repository_status_label( trans, tool_shed_repository )
class ToolShedColumn( grids.TextColumn ):
diff -r 068afb09a7ba896f1fdfee104d0b68c0a2e77de3 -r 95815478f355009d925ea91e95e4db0a9d887ded lib/tool_shed/galaxy_install/repository_util.py
--- a/lib/tool_shed/galaxy_install/repository_util.py
+++ b/lib/tool_shed/galaxy_install/repository_util.py
@@ -758,7 +758,6 @@
log.debug( error_message )
repair_dict [ repository.name ] = error_message
elif repository.status not in [ trans.model.ToolShedRepository.installation_status.INSTALLED ]:
- # TODO: this may cause problems if the repository is currently being installed.
shed_tool_conf, tool_path, relative_install_dir = suc.get_tool_panel_config_tool_path_install_dir( trans.app, repository )
# Reset the repository attributes to the New state for installation.
if metadata:
@@ -793,7 +792,8 @@
work_dir = tempfile.mkdtemp( prefix="tmp-toolshed-itdep" )
# Reset missing tool dependencies.
for tool_dependency in repository.missing_tool_dependencies:
- if tool_dependency.status in [ trans.model.ToolDependency.installation_status.ERROR ]:
+ if tool_dependency.status in [ trans.model.ToolDependency.installation_status.ERROR,
+ trans.model.ToolDependency.installation_status.INSTALLING ]:
tool_dependency_util.set_tool_dependency_attributes( trans,
tool_dependency,
trans.model.ToolDependency.installation_status.UNINSTALLED,
diff -r 068afb09a7ba896f1fdfee104d0b68c0a2e77de3 -r 95815478f355009d925ea91e95e4db0a9d887ded lib/tool_shed/util/shed_util_common.py
--- a/lib/tool_shed/util/shed_util_common.py
+++ b/lib/tool_shed/util/shed_util_common.py
@@ -1282,6 +1282,53 @@
log.exception( "Error attempting to get tool shed status for installed repository %s: %s" % ( str( repository.name ), str( e ) ) )
return {}
+def get_tool_shed_repository_status_label( trans, tool_shed_repository=None, name=None, owner=None, changeset_revision=None, repository_clone_url=None ):
+ """Return a color-coded label for the status of the received tool-shed_repository installed into Galaxy."""
+ if tool_shed_repository is None:
+ if name is not None and owner is not None and repository_clone_url is not None:
+ tool_shed = get_tool_shed_from_clone_url( repository_clone_url )
+ tool_shed_repository = get_tool_shed_repository_by_shed_name_owner_installed_changeset_revision( trans.app,
+ tool_shed,
+ name,
+ owner,
+ changeset_revision )
+ if tool_shed_repository:
+ status_label = tool_shed_repository.status
+ if tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.CLONING,
+ trans.model.ToolShedRepository.installation_status.SETTING_TOOL_VERSIONS,
+ trans.model.ToolShedRepository.installation_status.INSTALLING_REPOSITORY_DEPENDENCIES,
+ trans.model.ToolShedRepository.installation_status.INSTALLING_TOOL_DEPENDENCIES,
+ trans.model.ToolShedRepository.installation_status.LOADING_PROPRIETARY_DATATYPES ]:
+ bgcolor = trans.model.ToolShedRepository.states.INSTALLING
+ elif tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.NEW,
+ trans.model.ToolShedRepository.installation_status.UNINSTALLED ]:
+ bgcolor = trans.model.ToolShedRepository.states.UNINSTALLED
+ elif tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.ERROR ]:
+ bgcolor = trans.model.ToolShedRepository.states.ERROR
+ elif tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.DEACTIVATED ]:
+ bgcolor = trans.model.ToolShedRepository.states.WARNING
+ elif tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.INSTALLED ]:
+ if tool_shed_repository.repository_dependencies_being_installed:
+ bgcolor = trans.model.ToolShedRepository.states.WARNING
+ status_label = '%s, %s' % ( status_label, trans.model.ToolShedRepository.installation_status.INSTALLING_REPOSITORY_DEPENDENCIES )
+ elif tool_shed_repository.missing_repository_dependencies:
+ bgcolor = trans.model.ToolShedRepository.states.WARNING
+ status_label = '%s, missing repository dependencies' % status_label
+ elif tool_shed_repository.tool_dependencies_being_installed:
+ bgcolor = trans.model.ToolShedRepository.states.WARNING
+ status_label = '%s, %s' % (status_label, trans.model.ToolShedRepository.installation_status.INSTALLING_TOOL_DEPENDENCIES )
+ elif tool_shed_repository.missing_tool_dependencies:
+ bgcolor = trans.model.ToolShedRepository.states.WARNING
+ status_label = '%s, missing tool dependencies' % status_label
+ else:
+ bgcolor = trans.model.ToolShedRepository.states.OK
+ else:
+ bgcolor = trans.model.ToolShedRepository.states.ERROR
+ else:
+ bgcolor = trans.model.ToolShedRepository.states.WARNING
+ status_label = '%s, unknown status' % status_label
+ return '<div class="count-box state-color-%s">%s</div>' % ( bgcolor, status_label )
+
def get_updated_changeset_revisions( trans, name, owner, changeset_revision ):
"""
Return a string of comma-separated changeset revision hashes for all available updates to the received changeset revision for the repository
diff -r 068afb09a7ba896f1fdfee104d0b68c0a2e77de3 -r 95815478f355009d925ea91e95e4db0a9d887ded templates/admin/tool_shed_repository/repair_repository.mako
--- a/templates/admin/tool_shed_repository/repair_repository.mako
+++ b/templates/admin/tool_shed_repository/repair_repository.mako
@@ -18,27 +18,56 @@
%endif
<div class="warningmessage">
- The following repositories will be inspected and repaired in the order listed to ensure each repository and all of it's tool dependencies are correctly
- installed. Click <b>Repair</b> to inspect and repair these repositories.
+ <p>
+ The following repositories will be inspected and repaired in the order listed to ensure each repository and all of it's tool dependencies are
+ correctly installed.
+ </p>
+ <p>
+ Existing system processes associated with repositories or tool dependencies that are currently being installed will not be automatically
+ terminated. If possible, make sure no installation processes are still running for repositories whose status is or includes <b>cloning</b>,
+ <b>setting tool versions</b>, <b>installing repository dependencies</b>, or <b>installing tool dependencies</b> before clicking the <b>Repair</b>
+ button.
+ </p>
+ <p>
+ All repositories that do not display an <b>Installed</b> status will be removed from disk and reinstalled.
+ </p>
+ <p>
+ Click <b>Repair</b> to inspect and repair these repositories.
+ </p></div><div class="toolForm">
- <div class="toolFormTitle">Repair tool shed repository '${repository.name}'</div>
- <br/><br/>
- <form name="repair_repository" id="repair_repository" action="${h.url_for( controller='admin_toolshed', action='repair_repository', id=trans.security.encode_id( repository.id ), repair_dict=encoded_repair_dict )}" method="post" >
- <% ordered_repo_info_dicts = repair_dict.get( 'ordered_repo_info_dicts', [] ) %>
+ <div class="toolFormTitle">Repair tool shed repository <b>${repository.name}</b></div>
+ <form name="repair_repository" id="repair_repository" action="${h.url_for( controller='admin_toolshed', action='repair_repository', id=trans.security.encode_id( repository.id ) )}" method="post" >
+ <input type="hidden" name="repair_dict" value="${encoded_repair_dict}"/>
+ <%
+ from tool_shed.util.shed_util_common import get_tool_shed_repository_status_label
+ ordered_repo_info_dicts = repair_dict.get( 'ordered_repo_info_dicts', [] )
+ %><table class="grid">
- <tr><th bgcolor="#D8D8D8">Name</th><th bgcolor="#D8D8D8">Owner</th><th bgcolor="#D8D8D8">Changeset revision</th></tr>
+ <tr>
+ <th bgcolor="#D8D8D8">Name</th>
+ <th bgcolor="#D8D8D8">Owner</th>
+ <th bgcolor="#D8D8D8">Changeset revision</th>
+ <th bgcolor="#D8D8D8">Status</th>
+ </tr>
%for repo_info_dict in ordered_repo_info_dicts:
<%
for name, repo_info_tuple in repo_info_dict.items():
description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = repo_info_tuple
break
+ status_label = get_tool_shed_repository_status_label( trans,
+ tool_shed_repository=None,
+ name=name,
+ owner=repository_owner,
+ changeset_revision=changeset_revision,
+ repository_clone_url=repository_clone_url )
%><tr><td>${name | h}</td><td>${repository_owner | h}</td><td>${changeset_revision | h}</td>
+ <td>${status_label}</td></tr>
%endfor
</table>
diff -r 068afb09a7ba896f1fdfee104d0b68c0a2e77de3 -r 95815478f355009d925ea91e95e4db0a9d887ded test/tool_shed/base/twilltestcase.py
--- a/test/tool_shed/base/twilltestcase.py
+++ b/test/tool_shed/base/twilltestcase.py
@@ -969,7 +969,7 @@
self.check_for_strings( [ 'Metadata has been reset' ] )
def reset_metadata_on_selected_repositories( self, repository_ids ):
- self.visit_url( '/admin/reset_metadata_on_selected_repositories' )
+ self.visit_url( '/admin/reset_metadata_on_selected_repositories_in_tool_shed' )
kwd = dict( repository_ids=repository_ids )
self.submit_form( form_no=1, button="reset_metadata_on_selected_repositories_button", **kwd )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: Tools API, show: remove unused flag, show io_details/link_details where possible; ToolParameters: improve polymorphism in to_dict
by commits-noreply@bitbucket.org 18 Oct '13
by commits-noreply@bitbucket.org 18 Oct '13
18 Oct '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/068afb09a7ba/
Changeset: 068afb09a7ba
User: carlfeberhard
Date: 2013-10-18 21:37:59
Summary: Tools API, show: remove unused flag, show io_details/link_details where possible; ToolParameters: improve polymorphism in to_dict
Affected #: 2 files
diff -r 799dca8ebe2375f962603382380dfc1da720764f -r 068afb09a7ba896f1fdfee104d0b68c0a2e77de3 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -17,6 +17,7 @@
log = logging.getLogger(__name__)
+
class ToolParameter( object, Dictifiable ):
"""
Describes a parameter accepted by a tool. This is just a simple stub at the
@@ -172,9 +173,10 @@
def to_dict( self, trans, view='collection', value_mapper=None ):
""" to_dict tool parameter. This can be overridden by subclasses. """
-
tool_dict = super( ToolParameter, self ).to_dict()
- tool_dict[ 'html' ] = urllib.quote( self.get_html( trans ) )
+ #TODO: removing html as it causes a lot of errors on subclasses - needs histories, etc.
+ #tool_dict[ 'html' ] = urllib.quote( self.get_html( trans ) )
+ tool_dict[ 'model_class' ] = self.__class__.__name__
if hasattr( self, 'value' ):
tool_dict[ 'value' ] = self.value
return tool_dict
@@ -193,6 +195,7 @@
else:
return parameter_types[param_type]( tool, param )
+
class TextToolParameter( ToolParameter ):
"""
Parameter that can take on any text value.
@@ -210,12 +213,14 @@
self.size = elem.get( 'size' )
self.value = elem.get( 'value' )
self.area = string_as_bool( elem.get( 'area', False ) )
+
def get_html_field( self, trans=None, value=None, other_values={} ):
if value is None: value = self.value
if self.area:
return form_builder.TextArea( self.name, self.size, value )
else:
return form_builder.TextField( self.name, self.size, value )
+
def get_initial_value( self, trans, context, history=None ):
return self.value
@@ -266,6 +271,7 @@
if isinstance( value, int ):
value = str( value )
return super( IntegerToolParameter, self ).get_html_field( trans=trans, value=value, other_values=other_values )
+
def from_html( self, value, trans=None, other_values={} ):
try:
return int( value )
@@ -273,12 +279,14 @@
if not value and self.optional:
return ""
raise ValueError( "An integer is required" )
+
def to_string( self, value, app ):
"""Convert a value to a string representation suitable for persisting"""
if value is None:
return ""
else:
return str( value )
+
def to_python( self, value, app ):
try:
return int( value )
@@ -286,12 +294,14 @@
if not value and self.optional:
return None
raise err
+
def get_initial_value( self, trans, context, history=None ):
if self.value:
return int( self.value )
else:
return None
+
class FloatToolParameter( TextToolParameter ):
"""
Parameter that takes a real number value.
@@ -334,10 +344,12 @@
raise ValueError( "A real number is required" )
if self.min and self.max:
self.validators.append( validation.InRangeValidator( None, self.min, self.max ) )
+
def get_html_field( self, trans=None, value=None, other_values={} ):
if isinstance( value, float ):
value = str( value )
return super( FloatToolParameter, self ).get_html_field( trans=trans, value=value, other_values=other_values )
+
def from_html( self, value, trans=None, other_values={} ):
try:
return float( value )
@@ -345,12 +357,14 @@
if not value and self.optional:
return ""
raise ValueError( "A real number is required" )
+
def to_string( self, value, app ):
"""Convert a value to a string representation suitable for persisting"""
if value is None:
return ""
else:
return str( value )
+
def to_python( self, value, app ):
try:
return float( value )
@@ -358,12 +372,14 @@
if not value and self.optional:
return None
raise err
+
def get_initial_value( self, trans, context, history=None ):
try:
return float( self.value )
except:
return None
+
class BooleanToolParameter( ToolParameter ):
"""
Parameter that takes one of two values.
@@ -387,31 +403,39 @@
self.truevalue = elem.get( 'truevalue', 'true' )
self.falsevalue = elem.get( 'falsevalue', 'false' )
self.checked = string_as_bool( elem.get( 'checked' ) )
+
def get_html_field( self, trans=None, value=None, other_values={} ):
checked = self.checked
if value is not None:
checked = form_builder.CheckboxField.is_checked( value )
return form_builder.CheckboxField( self.name, checked, refresh_on_change = self.refresh_on_change )
+
def from_html( self, value, trans=None, other_values={} ):
return form_builder.CheckboxField.is_checked( value )
+
def to_html_value( self, value, app ):
if value:
return [ 'true', 'true' ]
else:
return [ 'true' ]
+
def to_python( self, value, app ):
return ( value == 'True' )
+
def get_initial_value( self, trans, context, history=None ):
return self.checked
+
def to_param_dict_string( self, value, other_values={} ):
if value:
return self.truevalue
else:
return self.falsevalue
+
@property
def legal_values( self ):
return [ self.truevalue, self.falsevalue ]
+
class FileToolParameter( ToolParameter ):
"""
Parameter that takes an uploaded file as a value.
@@ -431,8 +455,10 @@
"""
ToolParameter.__init__( self, tool, elem )
self.ajax = string_as_bool( elem.get( 'ajax-upload' ) )
+
def get_html_field( self, trans=None, value=None, other_values={} ):
return form_builder.FileField( self.name, ajax = self.ajax, value = value )
+
def from_html( self, value, trans=None, other_values={} ):
# Middleware or proxies may encode files in special ways (TODO: this
# should be pluggable)
@@ -450,11 +476,13 @@
local_filename = local_filename
)
return value
+
def get_required_enctype( self ):
"""
File upload elements require the multipart/form-data encoding
"""
return "multipart/form-data"
+
def to_string( self, value, app ):
if value in [ None, '' ]:
return None
@@ -467,6 +495,7 @@
except:
return None
raise Exception( "FileToolParameter cannot be persisted" )
+
def to_python( self, value, app ):
if value is None:
return None
@@ -474,9 +503,11 @@
return value
else:
raise Exception( "FileToolParameter cannot be persisted" )
+
def get_initial_value( self, trans, context, history=None ):
return None
+
class FTPFileToolParameter( ToolParameter ):
"""
Parameter that takes a file uploaded via FTP as a value.
@@ -486,36 +517,43 @@
Example: C{<param name="bins" type="file" />}
"""
ToolParameter.__init__( self, tool, elem )
+
@property
def visible( self ):
if self.tool.app.config.ftp_upload_dir is None or self.tool.app.config.ftp_upload_site is None:
return False
return True
+
def get_html_field( self, trans=None, value=None, other_values={} ):
if trans is None or trans.user is None:
user_ftp_dir = None
else:
user_ftp_dir = trans.user_ftp_dir
return form_builder.FTPFileField( self.name, user_ftp_dir, trans.app.config.ftp_upload_site, value = value )
+
def from_html( self, value, trans=None, other_values={} ):
try:
assert type( value ) is list
except:
value = [ value ]
return value
+
def to_string( self, value, app ):
if value in [ None, '' ]:
return None
elif isinstance( value, unicode ) or isinstance( value, str ) or isinstance( value, list ):
return value
+
def to_python( self, value, app ):
if value is None:
return None
elif isinstance( value, unicode ) or isinstance( value, str ) or isinstance( value, list ):
return value
+
def get_initial_value( self, trans, context, history=None ):
return None
+
class HiddenToolParameter( ToolParameter ):
"""
Parameter that takes one of two values.
@@ -532,10 +570,13 @@
def __init__( self, tool, elem ):
ToolParameter.__init__( self, tool, elem )
self.value = elem.get( 'value' )
+
def get_html_field( self, trans=None, value=None, other_values={} ):
return form_builder.HiddenField( self.name, self.value )
+
def get_initial_value( self, trans, context, history=None ):
return self.value
+
def get_label( self ):
return None
@@ -543,26 +584,33 @@
## can change, there needs to be a different way to specify this. I'm leaving
## it for now to avoid breaking any tools.
+
class BaseURLToolParameter( ToolParameter ):
"""
Returns a parameter the contains its value prepended by the
current server base url. Used in all redirects.
"""
+
def __init__( self, tool, elem ):
ToolParameter.__init__( self, tool, elem )
self.value = elem.get( 'value', '' )
+
def get_value( self, trans ):
# url = trans.request.base + self.value
url = url_for( self.value, qualified=True )
return url
+
def get_html_field( self, trans=None, value=None, other_values={} ):
return form_builder.HiddenField( self.name, self.get_value( trans ) )
+
def get_initial_value( self, trans, context, history=None ):
return self.value
+
def get_label( self ):
# BaseURLToolParameters are ultimately "hidden" parameters
return None
+
class SelectToolParameter( ToolParameter ):
"""
Parameter that takes on one (or many) or a specific set of values.
@@ -665,6 +713,7 @@
selected = string_as_bool( option.get( "selected", False ) )
self.static_options.append( ( option.text or value, value, selected ) )
self.is_dynamic = ( ( self.dynamic_options is not None ) or ( self.options is not None ) )
+
def get_options( self, trans, other_values ):
if self.options:
return self.options.get_options( trans, other_values )
@@ -672,6 +721,7 @@
return eval( self.dynamic_options, self.tool.code_namespace, other_values )
else:
return self.static_options
+
def get_legal_values( self, trans, other_values ):
def _get_UnvalidatedValue_value( value ):
if isinstance( value, UnvalidatedValue ):
@@ -683,6 +733,7 @@
return set( v for _, v, _ in eval( self.dynamic_options, self.tool.code_namespace, other_values ) )
else:
return self.legal_values
+
def get_html_field( self, trans=None, value=None, context={} ):
# Dynamic options are not yet supported in workflow, allow
# specifying the value as text for now.
@@ -710,6 +761,7 @@
selected = ( optval in value )
field.add_option( text, optval, selected )
return field
+
def from_html( self, value, trans=None, context={} ):
if self.need_late_validation( trans, context ):
if self.multiple:
@@ -747,11 +799,13 @@
if value not in legal_values:
raise ValueError( "An invalid option was selected, please verify" )
return value
+
def to_html_value( self, value, app ):
if isinstance( value, list ):
return value
else:
return str( value )
+
def to_param_dict_string( self, value, other_values={} ):
if value is None:
return "None"
@@ -769,6 +823,7 @@
if isinstance( value, list ):
value = self.separator.join( value )
return value
+
def value_to_basic( self, value, app ):
if isinstance( value, UnvalidatedValue ):
return { "__class__": "UnvalidatedValue", "value": value.value }
@@ -778,10 +833,12 @@
# breaks multiple selection
return { "__class__": "RuntimeValue" }
return value
+
def value_from_basic( self, value, app, ignore_errors=False ):
if isinstance( value, dict ) and value.get( "__class__", None ) == "UnvalidatedValue":
return UnvalidatedValue( value["value"] )
return super( SelectToolParameter, self ).value_from_basic( value, app, ignore_errors=ignore_errors )
+
def need_late_validation( self, trans, context ):
"""
Determine whether we need to wait to validate this parameters value
@@ -826,6 +883,7 @@
return True
# Dynamic, but all dependenceis are known and have values
return False
+
def get_initial_value( self, trans, context, history=None ):
# More working around dynamic options for workflow
if self.need_late_validation( trans, context ):
@@ -844,6 +902,7 @@
elif len( value ) == 1:
value = value[0]
return value
+
def value_to_display_text( self, value, app ):
if isinstance( value, UnvalidatedValue ):
suffix = "\n(value not yet validated)"
@@ -863,6 +922,7 @@
if v in value:
rval.append( t )
return "\n".join( rval ) + suffix
+
def get_dependencies( self ):
"""
Get the *names* of the other params this param depends on.
@@ -876,17 +936,24 @@
d = super( SelectToolParameter, self ).to_dict( trans )
# Get options, value.
- options = self.get_options( trans, [] )
- value = options[0][1]
- for option in options:
- if option[2]:
- # Found selected option.
- value = option[1]
+ options = []
+ try:
+ options = self.get_options( trans, {} )
+ except AssertionError, assertion:
+ # we dont/cant set other_values (the {} above), so params that require other params to be filled will error:
+ # required dependency in filter_options
+ # associated DataToolParam in get_column_list
+ pass
- d.update( {
- 'options': options,
- 'value': value
- } )
+ d[ 'options' ] = options
+ if options:
+ value = options[0][1]
+ for option in options:
+ if option[2]:
+ # Found selected option.
+ value = option[1]
+ d[ 'value' ] = options
+
return d
@@ -933,6 +1000,7 @@
def __init__( self, *args, **kwds ):
super( GenomeBuildParameter, self ).__init__( *args, **kwds )
self.static_options = [ ( value, key, False ) for key, value in util.dbnames ]
+
def get_options( self, trans, other_values ):
if not trans.history:
yield 'unspecified', '?', False
@@ -940,11 +1008,31 @@
last_used_build = trans.history.genome_build
for dbkey, build_name in trans.db_builds:
yield build_name, dbkey, ( dbkey == last_used_build )
+
def get_legal_values( self, trans, other_values ):
if not trans.history:
return set( '?' )
return set( dbkey for dbkey, _ in trans.db_builds )
+ def to_dict( self, trans, view='collection', value_mapper=None ):
+ # skip SelectToolParameter (the immediate parent) bc we need to get options in a different way here
+ d = ToolParameter.to_dict( self, trans )
+
+ # Get options, value - options is a generator here, so compile to list
+ options = list( self.get_options( trans, {} ) )
+ value = options[0][1]
+ for option in options:
+ if option[2]:
+ # Found selected option.
+ value = option[1]
+
+ d.update({
+ 'options': options,
+ 'value': value
+ })
+ return d
+
+
class ColumnListParameter( SelectToolParameter ):
"""
Select list that consists of either the total number of columns or only
@@ -1081,10 +1169,13 @@
return UnvalidatedValue( self.default_value )
return self.default_value
return SelectToolParameter.get_initial_value( self, trans, context )
+
def get_legal_values( self, trans, other_values ):
return set( self.get_column_list( trans, other_values ) )
+
def get_dependencies( self ):
return [ self.data_ref ]
+
def need_late_validation( self, trans, context ):
if super( ColumnListParameter, self ).need_late_validation( trans, context ):
return True
@@ -1245,7 +1336,6 @@
call_other_values.update( other_values.dict )
return eval( self.dynamic_options, self.tool.code_namespace, call_other_values )
-
def get_options( self, trans=None, value=None, other_values={} ):
if self.is_dynamic:
if self.dynamic_options:
@@ -1353,6 +1443,7 @@
else:
rval = sanitize_param( rval )
return rval
+
def get_initial_value( self, trans, context, history=None ):
def recurse_options( initial_values, options ):
for option in options:
@@ -1407,9 +1498,26 @@
"""
return self.filtered.keys()
+ def to_dict( self, trans, view='collection', value_mapper=None ):
+ # skip SelectToolParameter (the immediate parent) bc we need to get options in a different way here
+ d = ToolParameter.to_dict( self, trans )
+
+ options = []
+ try:
+ options = self.get_options( trans, {} )
+ except KeyError, key_err:
+ # will sometimes error if self.is_dynamic and self.filtered
+ # bc we dont/cant fill out other_values above ({})
+ pass
+
+ d[ 'options' ] = options;
+ return d
+
+
class DummyDataset( object ):
pass
+
class DataToolParameter( ToolParameter ):
# TODO, Nate: Make sure the following unit tests appropriately test the dataset security
# components. Add as many additional tests as necessary.
@@ -1720,6 +1828,7 @@
ref = ref()
return ref
+
class HiddenDataToolParameter( HiddenToolParameter, DataToolParameter ):
"""
Hidden parameter that behaves as a DataToolParameter. As with all hidden
@@ -1845,9 +1954,11 @@
"""
def __init__( self, value ):
self.value = value
+
def __str__( self ):
return str( self.value )
+
class RuntimeValue( object ):
"""
Wrapper to note a value that is not yet set, but will be required at
diff -r 799dca8ebe2375f962603382380dfc1da720764f -r 068afb09a7ba896f1fdfee104d0b68c0a2e77de3 lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -1,3 +1,5 @@
+import urllib
+
from galaxy import web, util
from galaxy.web.base.controller import BaseAPIController, UsesHistoryDatasetAssociationMixin, UsesVisualizationMixin
from galaxy.visualization.genomes import GenomeRegion
@@ -44,8 +46,16 @@
GET /api/tools/{tool_id}
Returns tool information, including parameters and inputs.
"""
+ io_details = util.string_as_bool( kwd.get( 'io_details', False ) )
+ link_details = util.string_as_bool( kwd.get( 'link_details', False ) )
try:
- return self.app.toolbox.tools_by_id[ id ].to_dict( trans, for_display=True )
+ id = urllib.unquote_plus( id )
+ tool = self.app.toolbox.tools_by_id.get( id, None )
+ if not tool:
+ trans.response.status = 404
+ return { 'error': 'tool not found', 'id': id }
+ return tool.to_dict( trans, io_details=io_details, link_details=link_details )
+
except Exception, exc:
log.error( 'could not convert tool (%s) to dictionary: %s', id, str( exc ), exc_info=True )
trans.response.status = 500
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0