galaxy-commits
Threads by month
- ----- 2025 -----
- January
- ----- 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
November 2010
- 1 participants
- 286 discussions
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Dannon Baker <dannonbaker(a)me.com>
# Date 1288645775 14400
# Node ID 695c89309bcb2f5d31bfb8b9d8b0124ff3abf90f
# Parent cf7ec71c561323940ce95c8148d2008508920092
Cleanup of debug info.
--- a/static/scripts/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/galaxy.workflow_editor.canvas.js
@@ -476,7 +476,6 @@ function Workflow( canvas_container ) {
});
…
[View More]},
rectify_workflow_outputs : function() {
- console.log("RECTIFICATION!");
// Find out if we're using workflow_outputs or not.
var using_workflow_outputs = false;
$.each( this.nodes, function ( k, node ) {
@@ -493,7 +492,6 @@ function Workflow( canvas_container ) {
if (node.type == 'tool'){
var node_changed = false;
if (node.post_job_actions == null){
- console.log("CREATED FOR NEW NODE");
node.post_job_actions = {};
}
var pjas_to_rem = [];
[View Less]
1
0
galaxy-dist commit c4d8ffb3109e: Increment js version to get around cached editors.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Dannon Baker <dannonbaker(a)me.com>
# Date 1288647270 14400
# Node ID c4d8ffb3109e8cfb8143dc87c88dee3337bb7569
# Parent 9285b39ae2f3dfd5017808b4d9b657094fec802b
Increment js version to get around cached editors.
--- a/lib/galaxy/web/framework/helpers/__init__.py
+++ b/lib/galaxy/web/framework/helpers/__init__.py
@@ -44,7 +44,7 @@ def js( *args ):
TODO: This has …
[View More]a hardcoded "?v=X" to defeat caching. This should be done
in a better way.
"""
- return "\n".join( [ javascript_include_tag( "/static/scripts/" + name + ".js?v=7" ) for name in args ] )
+ return "\n".join( [ javascript_include_tag( "/static/scripts/" + name + ".js?v=8" ) for name in args ] )
# Hashes
[View Less]
1
0
galaxy-dist commit b7ac22fab158: First pass of bug fixes, anbd additional UI cleanup for Sample Tracking.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1288713844 14400
# Node ID b7ac22fab1588a565a07acc4972564c2b9198489
# Parent 667043341e81261a7fe587daa475110486b15292
First pass of bug fixes, anbd additional UI cleanup for Sample Tracking.
--- a/templates/requests/common/edit_samples.mako
+++ b/templates/requests/common/edit_samples.mako
@@ -73,9 +73,10 @@
is_complete …
[View More]= request.is_complete
is_unsubmitted = request.is_unsubmitted
can_add_samples = is_unsubmitted
- can_edit_or_delete_samples = is_unsubmitted and request.samples
+ can_edit_or_delete_samples = request.samples and not is_complete
can_edit_request = ( is_admin and not request.is_complete ) or request.is_unsubmitted
can_reject_or_transfer = is_admin and request.is_submitted
+ can_submit = request.samples and is_unsubmitted
%><br/><br/>
@@ -87,7 +88,7 @@
%if editing_samples and can_add_samples:
<li><a class="action-button" href="${h.url_for( controller='requests_common', action='add_sample', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), add_sample_button='Add sample' )}">Add sample</a></li>
%endif
- %if is_unsubmitted:
+ %if can_submit:
<li><a class="action-button" confirm="More samples cannot be added to this request after it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit request</a></li>
%endif
<li><a class="action-button" id="request-${request.id}-popup" class="menubutton">Request actions</a></li>
@@ -209,12 +210,12 @@
Click the <b>Save</b> button when you have finished editing the samples
</div>
%endif
- %if request.samples and request.is_submitted:
- <script type="text/javascript">
- // Updater
- updater( {${ ",".join( [ '"%s" : "%s"' % ( s.id, s.state.name ) for s in request.samples ] ) }});
- </script>
- %endif
+ ##%if request.samples and request.is_submitted:
+ ## <script type="text/javascript">
+ ## // Updater
+ ## updater( {${ ",".join( [ '"%s" : "%s"' % ( s.id, s.state.name ) for s in request.samples ] ) }});
+ ## </script>
+ ##%endif
</form></div>
%if is_unsubmitted and not editing_samples:
--- a/lib/galaxy/web/controllers/requests.py
+++ b/lib/galaxy/web/controllers/requests.py
@@ -36,6 +36,12 @@ class Requests( BaseController ):
action='edit_basic_request_info',
cntrller='requests',
**kwd ) )
+ if operation == "edit_samples":
+ kwd[ 'editing_samples' ] = True
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ action='edit_samples',
+ cntrller='requests',
+ **kwd ) )
if operation == "view_request":
return trans.response.send_redirect( web.url_for( controller='requests_common',
action='view_request',
--- a/lib/galaxy/web/controllers/requests_common.py
+++ b/lib/galaxy/web/controllers/requests_common.py
@@ -46,17 +46,6 @@ class RequestsGrid( grids.Grid ):
.filter( model.RequestEvent.table.c.id.in_( select( columns=[ func.max( model.RequestEvent.table.c.id ) ],
from_obj=model.RequestEvent.table,
group_by=model.RequestEvent.table.c.request_id ) ) )
- def get_accepted_filters( self ):
- """ Returns a list of accepted filters for this column. """
- # TODO: is this method necessary?
- accepted_filter_labels_and_vals = [ model.Request.states.get( state ) for state in model.Request.states ]
- accepted_filter_labels_and_vals.append( "All" )
- accepted_filters = []
- for val in accepted_filter_labels_and_vals:
- label = val.lower()
- args = { self.key: val }
- accepted_filters.append( grids.GridColumnFilter( label, args ) )
- return accepted_filters
# Grid definition
title = "Sequencing Requests"
@@ -64,7 +53,6 @@ class RequestsGrid( grids.Grid ):
model_class = model.Request
default_sort_key = "-update_time"
num_rows_per_page = 50
- preserve_state = True
use_paging = True
default_filter = dict( state="All", deleted="False" )
columns = [
@@ -379,14 +367,24 @@ class RequestsCommon( BaseController, Us
sample_event_comment = ""
event = trans.model.RequestEvent( request, request.states.SUBMITTED, sample_event_comment )
trans.sa_session.add( event )
- # change the state of each of the samples of thus request
- new_state = request.type.states[0]
+ # Change the state of each of the samples of this request
+ # request.type.states is the list of SampleState objects configured
+ # by the admin for this RequestType.
+ trans.sa_session.add( event )
+ trans.sa_session.flush()
+ # Samples will not have an associated SampleState until the request is submitted, at which
+ # time all samples of the request will be set to the first SampleState configured for the
+ # request's RequestType configured by the admin.
+ initial_sample_state_after_request_submitted = request.type.states[0]
for sample in request.samples:
- event = trans.model.SampleEvent( sample, new_state, 'Samples created.' )
+ event_comment = 'Request submitted and sample state set to %s.' % request.type.states[0].name
+ event = trans.model.SampleEvent( sample,
+ initial_sample_state_after_request_submitted,
+ event_comment )
trans.sa_session.add( event )
trans.sa_session.add( request )
trans.sa_session.flush()
- request.send_email_notification( trans, new_state )
+ request.send_email_notification( trans, initial_sample_state_after_request_submitted )
message = 'The request has been submitted.'
return trans.response.send_redirect( web.url_for( controller=cntrller,
action='browse_requests',
@@ -519,8 +517,6 @@ class RequestsCommon( BaseController, Us
try:
request = trans.sa_session.query( trans.model.Request ).get( trans.security.decode_id( id ) )
except:
- message += "Invalid request ID (%s). " % str( id )
- status = 'error'
ok_for_now = False
if ok_for_now:
request.deleted = True
@@ -549,8 +545,6 @@ class RequestsCommon( BaseController, Us
try:
request = trans.sa_session.query( trans.model.Request ).get( trans.security.decode_id( id ) )
except:
- message += "Invalid request ID (%s). " % str( id )
- status = 'error'
ok_for_now = False
if ok_for_now:
request.deleted = False
@@ -903,6 +897,7 @@ class RequestsCommon( BaseController, Us
action='edit_samples',
cntrller=cntrller,
id=trans.security.encode_id( sample.request.id ),
+ editing_samples=True,
status=status,
message=message ) )
if is_admin:
@@ -1024,7 +1019,7 @@ class RequestsCommon( BaseController, Us
if sample_state_id in [ None, 'none' ]:
message = "Select a new state from the <b>Change current state</b> list before clicking the <b>Save</b> button."
kwd[ 'message' ] = message
- del kwd[ 'save_changes_button' ]
+ del kwd[ 'save_samples_button' ]
handle_error( **kwd )
sample_event_comment = util.restore_text( params.get( 'sample_event_comment', '' ) )
new_state = trans.sa_session.query( trans.model.SampleState ).get( trans.security.decode_id( sample_state_id ) )
@@ -1056,32 +1051,38 @@ class RequestsCommon( BaseController, Us
folder_id = params.get( 'sample_0_folder_id', 'none' )
library, folder = self.__get_library_and_folder( trans, library_id, folder_id )
self.__update_samples( trans, request, samples, **kwd )
- # See if all the samples' barcodes are in the same state,
- # and if so send email if configured to.
- common_state = request.samples_have_common_state
- if common_state and common_state.id == request.type.states[1].id:
- event = trans.model.RequestEvent( request,
- request.states.SUBMITTED,
- "All samples are in %s state." % common_state.name )
- trans.sa_session.add( event )
- trans.sa_session.flush()
- request.send_email_notification( trans, request.type.states[1] )
+ # Samples will not have an associated SampleState until the request is submitted, at which
+ # time all samples of the request will be set to the first SampleState configured for the
+ # request's RequestType defined by the admin.
+ if request.is_submitted:
+ # See if all the samples' barcodes are in the same state, and if so send email if configured to.
+ common_state = request.samples_have_common_state
+ if common_state and common_state.id == request.type.states[1].id:
+ event = trans.model.RequestEvent( request,
+ request.states.SUBMITTED,
+ "All samples are in %s state." % common_state.name )
+ trans.sa_session.add( event )
+ trans.sa_session.flush()
+ request.send_email_notification( trans, request.type.states[1] )
message = 'Changes made to the samples have been saved. '
else:
- # Saving a newly created sample.
+ # Saving a newly created sample. The sample will not have an associated SampleState
+ # until the request is submitted, at which time all samples of the request will be
+ # set to the first SampleState configured for the request's RequestType configured
+ # by the admin ( i.e., the sample's SampleState would be set to request.type.states[0] ).
for index in range( len( samples ) - len( request.samples ) ):
sample_index = len( request.samples )
current_sample = samples[ sample_index ]
form_values = trans.model.FormValues( request.type.sample_form, current_sample[ 'field_values' ] )
trans.sa_session.add( form_values )
trans.sa_session.flush()
- s = trans.model.Sample( current_sample[ 'name' ],
- '',
- request,
- form_values,
- current_sample[ 'barcode' ],
- current_sample[ 'library' ],
- current_sample[ 'folder' ] )
+ s = trans.model.Sample( name=current_sample[ 'name' ],
+ desc='',
+ request=request,
+ form_values=form_values,
+ bar_code='',
+ library=current_sample[ 'library' ],
+ folder=current_sample[ 'folder' ] )
trans.sa_session.add( s )
trans.sa_session.flush()
return trans.response.send_redirect( web.url_for( controller='requests_common',
@@ -1113,49 +1114,55 @@ class RequestsCommon( BaseController, Us
if obj is not None:
# obj will be None if the user checked sample check boxes and selected an action
# to perform on multiple samples, but did not select certain samples.
- sample_updated = False
- # If this sample has values in kwd, then kwd will include a
- # key whose value is this sample's ( possibly changed ) name. An
- # example of this key is 'sample_0_name'.
- for k, v in kwd.items():
- name_key = 'sample_%i_name' % index
- if k == name_key:
- sample_updated = True
- break
- if sample_updated:
- id_index = index + 1
- if sample_operation == 'none':
- # We are handling changes to a single sample.
- library_id = params.get( 'sample_%i_library_id' % id_index, 'none' )
- folder_id = params.get( 'sample_%i_folder_id' % id_index, 'none' )
- # Update the corresponding sample's values as well as the sample_widget.
- sample = request.samples[ index ]
- sample.name = util.restore_text( params.get( 'sample_%i_name' % index, '' ) )
- # The bar_code field requires special handling because after a request is submitted, the
- # state of a sample cannot be changed without a bar_code assocaited with the sample.
- bar_code = util.restore_text( params.get( 'sample_%i_barcode' % index, '' ) )
- if not bar_code and not sample.bar_code:
- # If this is a 'new' (still in its first state) sample, create an event
- if sample.state.id == request.states[0].id:
- event = trans.model.SampleEvent( sample,
- request.type.states[1],
- 'Sample added to the system' )
+ sample = request.samples[ index ]
+ # See if any values in kwd are different from the values already associated with this sample.
+ id_index = index + 1
+ if sample_operation == 'none':
+ # We are handling changes to a single sample.
+ library_id = params.get( 'sample_%i_library_id' % id_index, 'none' )
+ folder_id = params.get( 'sample_%i_folder_id' % id_index, 'none' )
+ # Update the corresponding sample's values as well as the sample_widget.
+ name = util.restore_text( params.get( 'sample_%i_name' % index, '' ) )
+ # The bar_code field requires special handling because after a request is submitted, the
+ # state of a sample cannot be changed without a bar_code associated with the sample. Bar
+ # codes can only be added to a sample after the request is submitted. Also, a samples will
+ # not have an associated SampleState until the request is submitted, at which time the sample
+ # is automatically associated with the first SamplesState configured by the admin for the
+ # request's RequestType.
+ bar_code = util.restore_text( params.get( 'sample_%i_barcode' % index, '' ) )
+ if bar_code:
+ bc_message = self.__validate_barcode( trans, sample, bar_code )
+ if bc_message:
+ kwd[ 'message' ] = bc_message
+ del kwd[ 'save_samples_button' ]
+ handle_error( **kwd )
+ if not sample.bar_code:
+ # If the sample's associated SampleState is still the initial state
+ # configured by the admin for the request's RequestType, this must be
+ # the first time a bar code was added to the sample, so change it's state
+ # to the next associated SampleState.
+ if sample.state.id == request.type.states[0].id:
+ event = trans.app.model.SampleEvent(sample,
+ request.type.states[1],
+ 'Bar code associated with the sample' )
trans.sa_session.add( event )
trans.sa_session.flush()
- elif bar_code:
- bc_message = self.__validate_barcode( trans, sample, bar_code )
- if bc_message:
- kwd[ 'message' ] = bc_message
- del kwd[ 'save_samples_button' ]
- handle_error( **kwd )
+ library, folder = self.__get_library_and_folder( trans, library_id, folder_id )
+ field_values = []
+ for field_index in range( len( request.type.sample_form.fields ) ):
+ field_values.append( util.restore_text( params.get( 'sample_%i_field_%i' % ( index, field_index ), '' ) ) )
+ form_values = trans.sa_session.query( trans.model.FormValues ).get( sample.values.id )
+ form_values.content = field_values
+ if sample.name != name or \
+ sample.bar_code != bar_code or \
+ sample.library != library or \
+ sample.folder != folder or \
+ form_values.content != field_values:
+ # Information about this sample has been changed.
+ sample.name = name
sample.bar_code = bar_code
- library, folder = self.__get_library_and_folder( trans, library_id, folder_id )
sample.library = library
sample.folder = folder
- field_values = []
- for field_index in range( len( request.type.sample_form.fields ) ):
- field_values.append( util.restore_text( params.get( 'sample_%i_field_%i' % ( index, field_index ), '' ) ) )
- form_values = trans.sa_session.query( trans.model.FormValues ).get( sample.values.id )
form_values.content = field_values
trans.sa_session.add_all( ( sample, form_values ) )
trans.sa_session.flush()
--- a/lib/galaxy/web/controllers/requests_admin.py
+++ b/lib/galaxy/web/controllers/requests_admin.py
@@ -9,8 +9,6 @@ import logging, os, pexpect, ConfigParse
log = logging.getLogger( __name__ )
-
-
class AdminRequestsGrid( RequestsGrid ):
class UserColumn( grids.TextColumn ):
def get_value( self, trans, grid, request ):
@@ -51,6 +49,7 @@ class RequestTypeGrid( grids.Grid ):
return request_type.sample_form.name
# Grid definition
+ webapp = "galaxy"
title = "Sequencer Configurations"
template = "admin/requests/grid.mako"
model_class = model.RequestType
@@ -103,6 +102,7 @@ class DataTransferGrid( grids.Grid ):
def get_value( self, trans, grid, sample_dataset ):
return sample_dataset.status
# Grid definition
+ webapp = "galaxy"
title = "Sample Datasets"
template = "admin/requests/grid.mako"
model_class = model.SampleDataset
@@ -129,9 +129,19 @@ class DataTransferGrid( grids.Grid ):
visible=False,
filterable="standard" ) )
operations = [
- grids.GridOperation( "Start Transfer", allow_multiple=True, condition=( lambda item: item.status in [ model.SampleDataset.transfer_status.NOT_STARTED ] ) ),
- grids.GridOperation( "Rename", allow_multiple=True, allow_popup=False, condition=( lambda item: item.status in [ model.SampleDataset.transfer_status.NOT_STARTED ] ) ),
- grids.GridOperation( "Delete", allow_multiple=True, condition=( lambda item: item.status in [ model.SampleDataset.transfer_status.NOT_STARTED ] ) ),
+ grids.GridOperation( "Transfer",
+ allow_multiple=True,
+ condition=( lambda item: item.status in [ model.SampleDataset.transfer_status.NOT_STARTED ] ),
+ url_args=dict( webapp="galaxy" ) ),
+ grids.GridOperation( "Rename",
+ allow_multiple=True,
+ allow_popup=False,
+ condition=( lambda item: item.status in [ model.SampleDataset.transfer_status.NOT_STARTED ] ),
+ url_args=dict( webapp="galaxy" ) ),
+ grids.GridOperation( "Delete",
+ allow_multiple=True,
+ condition=( lambda item: item.status in [ model.SampleDataset.transfer_status.NOT_STARTED ] ),
+ url_args=dict( webapp="galaxy" ) )
]
def apply_query_filter( self, trans, query, **kwd ):
sample_id = kwd.get( 'sample_id', None )
@@ -158,6 +168,12 @@ class RequestsAdmin( BaseController, Use
action='edit_basic_request_info',
cntrller='requests_admin',
**kwd ) )
+ if operation == "edit_samples":
+ kwd[ 'editing_samples' ] = True
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ action='edit_samples',
+ cntrller='requests_admin',
+ **kwd ) )
if operation == "view_request":
return trans.response.send_redirect( web.url_for( controller='requests_common',
action='view_request',
@@ -273,7 +289,7 @@ class RequestsAdmin( BaseController, Use
break
if no_datasets_transferred:
status = 'error'
- message = 'A dataset can be renamed only if it is in the "Not Started" state.'
+ message = 'A dataset can be renamed only if it has been transferred.'
return trans.response.send_redirect( web.url_for( controller='requests_admin',
action='manage_datasets',
sample_id=trans.security.encode_id( selected_sample_datasets[0].sample.id ),
@@ -282,7 +298,7 @@ class RequestsAdmin( BaseController, Use
return trans.fill_template( '/admin/requests/rename_datasets.mako',
sample=selected_sample_datasets[0].sample,
id_list=id_list )
- elif operation == "start transfer":
+ elif operation == "transfer":
self.__start_datatx( trans, selected_sample_datasets[0].sample, selected_sample_datasets )
# Render the grid view
sample_id = params.get( 'sample_id', None )
@@ -292,7 +308,7 @@ class RequestsAdmin( BaseController, Use
return invalid_id_redirect( trans, 'requests_admin', sample_id )
request_id = trans.security.encode_id( sample.request.id )
library_id = trans.security.encode_id( sample.library.id )
- self.datatx_grid.global_actions = [ grids.GridAction( "Refresh",
+ self.datatx_grid.global_actions = [ grids.GridAction( "Refresh page",
dict( controller='requests_admin',
action='manage_datasets',
sample_id=sample_id ) ),
@@ -302,11 +318,11 @@ class RequestsAdmin( BaseController, Use
request_id=request_id,
folder_path=sample.request.type.datatx_info[ 'data_dir' ],
sample_id=sample_id ) ),
- #grids.GridAction( 'Data library "%s"' % sample.library.name,
- # dict( controller='library_common',
- # action='browse_library',
- # cntrller='library_admin',
- # id=library_id ) ),
+ grids.GridAction( "Browse target data library",
+ dict( controller='library_common',
+ action='browse_library',
+ cntrller='library_admin',
+ id=library_id ) ),
grids.GridAction( "Browse this request",
dict( controller='requests_common',
action='view_request',
--- a/templates/requests/common/view_request.mako
+++ b/templates/requests/common/view_request.mako
@@ -18,15 +18,18 @@
from galaxy.web.framework.helpers import time_ago
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
+ is_complete = request.is_complete
is_unsubmitted = request.is_unsubmitted
can_edit_request = ( is_admin and not request.is_complete ) or request.is_unsubmitted
can_add_samples = is_unsubmitted
+ can_edit_or_delete_samples = request.samples and not is_complete
+ can_submit = request.samples and is_unsubmitted
%><br/><br/><ul class="manage-table-actions">
- %if is_unsubmitted:
+ %if can_submit:
<li><a class="action-button" confirm="More samples cannot be added to this request after it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit request</a></li>
%endif
<li><a class="action-button" id="request-${request.id}-popup" class="menubutton">Request actions</a></li>
@@ -66,13 +69,12 @@
</div><div class="form-row"><label>User:</label>
- %if is_admin:
- ${request.user.email}
- %elif request.user.username:
- ${request.user.username}
- %else:
- Unknown
- %endif
+ ${request.user.email}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Sequencer configuration:</label>
+ ${request.type.name}
<div style="clear: both"></div></div><div class="form-row">
@@ -129,11 +131,6 @@
${states}
<div style="clear: both"></div></div>
- <div class="form-row">
- <label>Sequencer configuration:</label>
- ${request.type.name}
- <div style="clear: both"></div>
- </div></div></div></div>
@@ -141,7 +138,7 @@
<p/>
%if current_samples:
<% grid_header = '<h3>Samples</h3>' %>
- ${render_samples_grid( cntrller, request, current_samples=current_samples, action='view_request', editing_samples=False, encoded_selected_sample_ids=[], render_buttons=can_edit_request, grid_header=grid_header )}
+ ${render_samples_grid( cntrller, request, current_samples=current_samples, action='view_request', editing_samples=False, encoded_selected_sample_ids=[], render_buttons=can_edit_or_delete_samples, grid_header=grid_header )}
%else:
There are no samples.
%if can_add_samples:
--- a/templates/grid_base.mako
+++ b/templates/grid_base.mako
@@ -752,11 +752,18 @@
%if grid.global_actions:
<ul class="manage-table-actions">
- %for action in grid.global_actions:
- <li>
- <a class="action-button" href="${h.url_for( **action.url_args )}">${action.label}</a>
- </li>
- %endfor
+ %if len( grid.global_actions ) < 4:
+ %for action in grid.global_actions:
+ <li><a class="action-button" href="${h.url_for( **action.url_args )}">${action.label}</a></li>
+ %endfor
+ %else:
+ <li><a class="action-button" id="action-8675309-popup" class="menubutton">Actions</a></li>
+ <div popupmenu="action-8675309-popup">
+ %for action in grid.global_actions:
+ <a class="action-button" href="${h.url_for( **action.url_args )}">${action.label}</a>
+ %endfor
+ </div>
+ %endif
</ul>
%endif
--- a/templates/requests/common/common.mako
+++ b/templates/requests/common/common.mako
@@ -88,26 +88,26 @@
%if is_admin and is_submitted and editing_samples:
<td><input type="checkbox" name=select_sample_${sample.id} id="sample_checkbox" value="true" ${checked_str}/><input type="hidden" name=select_sample_${sample.id} id="sample_checkbox" value="true"/></td>
%endif
- <td>
+ <td valign="top"><input type="text" name="sample_${current_sample_index}_name" value="${current_sample['name']}" size="10"/><div class="toolParamHelp" style="clear: both;"><i>${' (required)' }</i></div></td>
%if sample and is_submitted or is_complete:
- <td><input type="text" name="sample_${current_sample_index}_barcode" value="${current_sample['barcode']}" size="10"/></td>
+ <td valign="top"><input type="text" name="sample_${current_sample_index}_barcode" value="${current_sample['barcode']}" size="10"/></td>
%endif
%if sample:
%if is_unsubmitted:
<td>Unsubmitted</td>
%else:
- <td><a href="${h.url_for( controller='requests_common', action='sample_events', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${sample.state.name}</a></td>
+ <td valign="top"><a href="${h.url_for( controller='requests_common', action='sample_events', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${sample.state.name}</a></td>
%endif
%else:
<td></td>
%endif
- <td>${current_sample['library_select_field'].get_html()}</td>
- <td>${current_sample['folder_select_field'].get_html()}</td>
+ <td valign="top">${current_sample['library_select_field'].get_html()}</td>
+ <td valign="top">${current_sample['folder_select_field'].get_html()}</td>
%if is_submitted or is_complete:
<%
if sample:
@@ -115,12 +115,12 @@
else:
label = 'add'
%>
- <td><a href="${h.url_for( controller='requests_common', action='view_dataset_transfer', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${label}</a></td>
- <td><a href="${h.url_for( controller='requests_common', action='view_dataset_transfer', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${label}</a></td>
+ <td valign="top"><a href="${h.url_for( controller='requests_common', action='view_dataset_transfer', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${label}</a></td>
+ <td valign="top"><a href="${h.url_for( controller='requests_common', action='view_dataset_transfer', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${label}</a></td>
%endif
%if sample and ( is_admin or is_unsubmitted ):
## Delete button
- <td><a class="action-button" href="${h.url_for( controller='requests_common', action='delete_sample', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id=current_sample_index )}"><img src="${h.url_for('/static/images/delete_icon.png')}" style="cursor:pointer;"/></a></td>
+ <td valign="top"><a class="action-button" href="${h.url_for( controller='requests_common', action='delete_sample', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id=current_sample_index )}"><img src="${h.url_for('/static/images/delete_icon.png')}" style="cursor:pointer;"/></a></td>
%endif
</%def>
@@ -132,7 +132,7 @@
is_submitted = request.is_submitted
is_unsubmitted = request.is_unsubmitted
can_add_samples = request.is_unsubmitted
- can_edit_or_delete_samples = request.samples and ( is_admin or request.is_unsubmitted )
+ can_edit_or_delete_samples = request.samples and not is_complete
%>
${grid_header}
%if render_buttons and ( can_add_samples or can_edit_or_delete_samples ):
[View Less]
1
0
galaxy-dist commit 667043341e81: Significant cleanup for the Sample Tracking UI. Things are more streamlined and Galaxy UI standards are now followed.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1288649810 14400
# Node ID 667043341e81261a7fe587daa475110486b15292
# Parent c4d8ffb3109e8cfb8143dc87c88dee3337bb7569
Significant cleanup for the Sample Tracking UI. Things are more streamlined and Galaxy UI standards are now followed.
--- a/templates/requests/common/sample_events.mako
+++ b/templates/requests/common/…
[View More]sample_events.mako
@@ -5,10 +5,7 @@
<h2>Events for Sample "${sample.name}"</h2><ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_common', action='manage_request', cntrller=cntrller, id=trans.security.encode_id( sample.request.id ) )}">
- <span>Browse this request</span></a>
- </li>
+ <li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( sample.request.id ) )}">Browse this request</a></li></ul><h3>Sequencing Request "${sample.request.name}"</h3>
--- /dev/null
+++ b/templates/requests/common/edit_samples.mako
@@ -0,0 +1,240 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+<%namespace file="/requests/common/common.mako" import="common_javascripts" />
+<%namespace file="/requests/common/common.mako" import="render_samples_grid" />
+<%namespace file="/requests/common/common.mako" import="render_request_type_sample_form_grids" />
+
+<%def name="stylesheets()">
+ ${parent.stylesheets()}
+ ${h.css( "library" )}
+</%def>
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ ${common_javascripts()}
+ ${local_javascripts()}
+</%def>
+
+<%def name="local_javascripts()">
+ <script type="text/javascript">
+ // Looks for changes in sample states using an async request. Keeps
+ // calling itself (via setTimeout) until all samples are in a terminal
+ // state.
+ var updater = function ( sample_states ) {
+ // Check if there are any items left to track
+ var empty = true;
+ for ( i in sample_states ) {
+ empty = false;
+ break;
+ }
+ if ( ! empty ) {
+ setTimeout( function() { updater_callback( sample_states ) }, 1000 );
+ }
+ };
+
+ var updater_callback = function ( sample_states ) {
+ // Build request data
+ var ids = []
+ var states = []
+ $.each( sample_states, function ( id, state ) {
+ ids.push( id );
+ states.push( state );
+ });
+ // Make ajax call
+ $.ajax( {
+ type: "POST",
+ url: "${h.url_for( controller='requests_common', action='sample_state_updates' )}",
+ dataType: "json",
+ data: { ids: ids.join( "," ), states: states.join( "," ) },
+ success : function ( data ) {
+ $.each( data, function( id, val ) {
+ // Replace HTML
+ var cell1 = $("#sampleState-" + id);
+ cell1.html( val.html_state );
+ var cell2 = $("#sampleDatasets-" + id);
+ cell2.html( val.html_datasets );
+ sample_states[ parseInt( id ) ] = val.state;
+ });
+ updater( sample_states );
+ },
+ error: function() {
+ // Just retry, like the old method, should try to be smarter
+ updater( sample_states );
+ }
+ });
+ };
+ </script>
+</%def>
+
+<%
+ from galaxy.web.framework.helpers import time_ago
+
+ is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
+ is_complete = request.is_complete
+ is_unsubmitted = request.is_unsubmitted
+ can_add_samples = is_unsubmitted
+ can_edit_or_delete_samples = is_unsubmitted and request.samples
+ can_edit_request = ( is_admin and not request.is_complete ) or request.is_unsubmitted
+ can_reject_or_transfer = is_admin and request.is_submitted
+%>
+
+<br/><br/>
+
+<ul class="manage-table-actions">
+ %if not editing_samples and can_edit_or_delete_samples:
+ <li><a class="action-button" href="${h.url_for( controller='requests_common', action='edit_samples', cntrller=cntrller, id=trans.security.encode_id( request.id ), editing_samples='True' )}">Edit samples</a></li>
+ %endif
+ %if editing_samples and can_add_samples:
+ <li><a class="action-button" href="${h.url_for( controller='requests_common', action='add_sample', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), add_sample_button='Add sample' )}">Add sample</a></li>
+ %endif
+ %if is_unsubmitted:
+ <li><a class="action-button" confirm="More samples cannot be added to this request after it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit request</a></li>
+ %endif
+ <li><a class="action-button" id="request-${request.id}-popup" class="menubutton">Request actions</a></li>
+ <div popupmenu="request-${request.id}-popup">
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a>
+ %if can_edit_request:
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit</a>
+ %endif
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">View history</a>
+ %if can_reject_or_transfer:
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject</a>
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='get_data', request_id=trans.security.encode_id( request.id ) )}">Select datasets to transfer</a>
+ %endif
+ </div>
+</ul>
+
+%if request.samples_without_library_destinations:
+ <br/>
+ <font color="red"><b><i>Select a target data library and folder for all samples before starting the sequence run</i></b></font>
+ <br/>
+%endif
+
+%if request.is_rejected:
+ <br/>
+ <font color="red"><b><i>Reason for rejection: </i></b></font><b>${request.last_comment}</b>
+ <br/>
+%endif
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<div class="toolFormBody">
+ <form id="edit_samples" name="edit_samples" action="${h.url_for( controller='requests_common', action='edit_samples', cntrller=cntrller, id=trans.security.encode_id( request.id ), editing_samples=editing_samples )}" method="post">
+ %if current_samples:
+ <%
+ if editing_samples:
+ grid_header = '<h3>Edit Current Samples of Request "%s"</h3>' % request.name
+ else:
+ grid_header = '<h3>Add Samples to Request "%s"</h3>' % request.name
+ %>
+ ${render_samples_grid( cntrller, request, current_samples, action='edit_samples', editing_samples=editing_samples, encoded_selected_sample_ids=encoded_selected_sample_ids, render_buttons=False, grid_header=grid_header )}
+ %if editing_samples and len( sample_operation_select_field.options ) > 1 and not ( is_unsubmitted or is_complete ):
+ <div class="form-row" style="background-color:#FAFAFA;">
+ For selected samples:
+ ${sample_operation_select_field.get_html()}
+ </div>
+ <% sample_operation_selected_value = sample_operation_select_field.get_selected( return_value=True ) %>
+ %if sample_operation_selected_value != 'none' and encoded_selected_sample_ids:
+ <div class="form-row" style="background-color:#FAFAFA;">
+ %if sample_operation_selected_value == trans.model.Sample.bulk_operations.CHANGE_STATE:
+ ## sample_operation_selected_value == 'Change state'
+ <div class="form-row">
+ <label>Change current state</label>
+ ${sample_state_id_select_field.get_html()}
+ <label>Comments</label>
+ <input type="text" name="sample_event_comment" value=""/>
+ <div class="toolParamHelp" style="clear: both;">
+ Optional
+ </div>
+ </div>
+ %elif sample_operation_selected_value == trans.app.model.Sample.bulk_operations.SELECT_LIBRARY:
+ <% libraries_selected_value = libraries_select_field.get_selected( return_value=True ) %>
+ <div class="form-row">
+ <label>Select data library:</label>
+ ${libraries_select_field.get_html()}
+ </div>
+ %if libraries_selected_value != 'none':
+ <div class="form-row">
+ <label>Select folder:</label>
+ ${folders_select_field.get_html()}
+ </div>
+ %endif
+ %endif
+ </div>
+ %endif
+ %endif
+ ## Render the other grids
+ <% trans.sa_session.refresh( request.type.sample_form ) %>
+ %for grid_index, grid_name in enumerate( request.type.sample_form.layout ):
+ ${render_request_type_sample_form_grids( grid_index, grid_name, request.type.sample_form.grid_fields( grid_index ), editing_samples=editing_samples )}
+ %endfor
+ %else:
+ <label>There are no samples.</label>
+ %endif
+ %if not editing_samples and is_unsubmitted:
+ ## The user is adding a new sample
+ %if current_samples:
+ <p/>
+ <div class="form-row">
+ <label> Copy <input type="text" name="num_sample_to_copy" value="1" size="3"/> samples from sample ${sample_copy.get_html()}</label>
+ <div class="toolParamHelp" style="clear: both;">
+ Select the sample from which the new sample should be copied or leave selection as <b>None</b> to add a new "generic" sample.
+ </div>
+ </div>
+ %endif
+ <p/>
+ <div class="form-row">
+ %if ( request.samples or current_samples ) and ( editing_samples or len( current_samples ) > len( request.samples ) ):
+ <input type="submit" name="add_sample_button" value="Add sample"/>
+ <input type="submit" name="save_samples_button" value="Save"/>
+ <input type="submit" name="cancel_changes_button" value="Cancel"/>
+ <div class="toolParamHelp" style="clear: both;">
+ Click the <b>Add sample</b> button for each new sample and click the <b>Save</b> button when you have finished adding samples.
+ </div>
+ %else:
+ <input type="submit" name="add_sample_button" value="Add sample"/>
+ <div class="toolParamHelp" style="clear: both;">
+ Click the <b>Add sample</b> button for each new sample.
+ </div>
+ %endif
+ </div>
+ %elif editing_samples:
+ <p/>
+ <div class="form-row">
+ <input type="submit" name="save_samples_button" value="Save"/>
+ <input type="submit" name="cancel_changes_button" value="Cancel"/>
+ <div class="toolParamHelp" style="clear: both;">
+ Click the <b>Save</b> button when you have finished editing the samples
+ </div>
+ %endif
+ %if request.samples and request.is_submitted:
+ <script type="text/javascript">
+ // Updater
+ updater( {${ ",".join( [ '"%s" : "%s"' % ( s.id, s.state.name ) for s in request.samples ] ) }});
+ </script>
+ %endif
+ </form>
+</div>
+%if is_unsubmitted and not editing_samples:
+ <p/>
+ ##<div class="toolForm">
+ ##<div class="toolFormTitle">Import samples from csv file</div>
+ <h4><img src="/static/images/fugue/toggle-expand.png" alt="Hide" onclick="showContent(this);" style="cursor:pointer;"/> Import samples from csv file</h4>
+ <div style="display:none;">
+ <div class="toolFormBody">
+ <form id="import" name="import" action="${h.url_for( controller='requests_common', action='edit_samples', cntrller=cntrller, id=trans.security.encode_id( request.id ), editing_samples=editing_samples )}" enctype="multipart/form-data" method="post" >
+ <div class="form-row">
+ <input type="file" name="file_data" />
+ <input type="submit" name="import_samples_button" value="Import samples"/>
+ <div class="toolParamHelp" style="clear: both;">
+ The csv file must be in the following format:<br/>
+ SampleName,DataLibrary,DataLibraryFolder,FieldValue1,FieldValue2...
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ ##</div>
+%endif
--- a/test/functional/test_forms_and_requests.py
+++ b/test/functional/test_forms_and_requests.py
@@ -225,15 +225,12 @@ class TestFormsAndRequests( TwillTestCas
strings_displayed_after_submit = [ 'Unsubmitted' ]
for sample_name, field_values in sample_value_tuples:
strings_displayed_after_submit.append( sample_name )
- for field_value in field_values:
- strings_displayed_after_submit.append( field_value )
# Add samples to the request
self.add_samples( cntrller='requests',
request_id=self.security.encode_id( request_one.id ),
request_name=request_one.name,
sample_value_tuples=sample_value_tuples,
- strings_displayed=[ 'Sequencing Request "%s"' % request_one.name,
- 'There are no samples.' ],
+ strings_displayed=[ 'There are no samples.' ],
strings_displayed_after_submit=strings_displayed_after_submit )
def test_030_edit_basic_request_info( self ):
"""Testing editing the basic information of a sequence run request"""
@@ -277,11 +274,11 @@ class TestFormsAndRequests( TwillTestCas
self.check_request_grid( cntrller='requests_admin',
state=request_one.states.SUBMITTED,
strings_displayed=[ request_one.name ] )
- self.visit_url( "%s/requests_common/manage_request?cntrller=requests&id=%s" % ( self.url, self.security.encode_id( request_one.id ) ) )
- self.check_page_for_string( 'Sequencing Request "%s"' % request_one.name )
+ self.visit_url( "%s/requests_common/view_request?cntrller=requests&id=%s" % ( self.url, self.security.encode_id( request_one.id ) ) )
+ # TODO: add some string for checking on the page above...
# Set bar codes for the samples
bar_codes = [ '1234567890', '0987654321' ]
- strings_displayed_after_submit=[ 'Changes made to the samples are saved.' ]
+ strings_displayed_after_submit=[ 'Changes made to the samples have been saved.' ]
for bar_code in bar_codes:
strings_displayed_after_submit.append( bar_code )
self.add_bar_codes( request_id=self.security.encode_id( request_one.id ),
@@ -333,7 +330,7 @@ class TestFormsAndRequests( TwillTestCas
test_field_name1,
test_field_name2,
test_field_name3 ],
- strings_displayed_after_submit=[ "The request has been created" ] )
+ strings_displayed_after_submit=[ "The request has been created." ] )
global request_two
request_two = get_request_by_name( name )
# Make sure the request is showing in the 'new' filter
@@ -349,15 +346,12 @@ class TestFormsAndRequests( TwillTestCas
strings_displayed_after_submit = [ 'Unsubmitted' ]
for sample_name, field_values in sample_value_tuples:
strings_displayed_after_submit.append( sample_name )
- for field_value in field_values:
- strings_displayed_after_submit.append( field_value )
# Add samples to the request
self.add_samples( cntrller='requests_admin',
request_id=self.security.encode_id( request_two.id ),
request_name=request_two.name,
sample_value_tuples=sample_value_tuples,
- strings_displayed=[ 'Sequencing Request "%s"' % request_two.name,
- 'There are no samples.' ],
+ strings_displayed=[ 'There are no samples.' ],
strings_displayed_after_submit=strings_displayed_after_submit )
# Submit the request
self.submit_request( cntrller='requests_admin',
@@ -394,6 +388,7 @@ class TestFormsAndRequests( TwillTestCas
% ( request_two.name, request_two.states.REJECTED )
def test_055_reset_data_for_later_test_runs( self ):
"""Reseting data to enable later test runs to pass"""
+ """
# Logged in as admin_user
##################
# Delete request_type permissions
@@ -438,3 +433,4 @@ class TestFormsAndRequests( TwillTestCas
# Manually delete the group from the database
refresh( group )
delete( group )
+ """
--- a/templates/admin/requests/rename_datasets.mako
+++ b/templates/admin/requests/rename_datasets.mako
@@ -10,7 +10,7 @@
<a class="action-button" href="${h.url_for( controller='requests_admin', action='manage_datasets', sample_id=trans.security.encode_id( sample.id ) )}">Browse datasets</a></li><li>
- <a class="action-button" href="${h.url_for( controller='requests_common', action='manage_request', cntrller='requests_admin', id=trans.security.encode_id( sample.request.id ) )}">Browse this request</a>
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller='requests_admin', id=trans.security.encode_id( sample.request.id ) )}">Browse this request</a></li></ul>
--- a/lib/galaxy/web/controllers/requests_admin.py
+++ b/lib/galaxy/web/controllers/requests_admin.py
@@ -158,9 +158,9 @@ class RequestsAdmin( BaseController, Use
action='edit_basic_request_info',
cntrller='requests_admin',
**kwd ) )
- if operation == "manage_request":
+ if operation == "view_request":
return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
+ action='view_request',
cntrller='requests_admin',
**kwd ) )
if operation == "request_events":
@@ -186,14 +186,14 @@ class RequestsAdmin( BaseController, Use
return self.request_grid( trans, **kwd )
@web.expose
@web.require_admin
- def reject( self, trans, **kwd ):
+ def reject_request( self, trans, **kwd ):
params = util.Params( kwd )
request_id = params.get( 'id', '' )
status = params.get( 'status', 'done' )
message = params.get( 'message', 'done' )
if params.get( 'cancel_reject_button', False ):
return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
+ action='view_request',
cntrller='requests_admin',
id=request_id ) )
try:
@@ -292,7 +292,6 @@ class RequestsAdmin( BaseController, Use
return invalid_id_redirect( trans, 'requests_admin', sample_id )
request_id = trans.security.encode_id( sample.request.id )
library_id = trans.security.encode_id( sample.library.id )
- self.datatx_grid.title = 'Datasets of sample "%s"' % sample.name
self.datatx_grid.global_actions = [ grids.GridAction( "Refresh",
dict( controller='requests_admin',
action='manage_datasets',
@@ -303,14 +302,14 @@ class RequestsAdmin( BaseController, Use
request_id=request_id,
folder_path=sample.request.type.datatx_info[ 'data_dir' ],
sample_id=sample_id ) ),
- grids.GridAction( 'Data library "%s"' % sample.library.name,
- dict( controller='library_common',
- action='browse_library',
- cntrller='library_admin',
- id=library_id ) ),
+ #grids.GridAction( 'Data library "%s"' % sample.library.name,
+ # dict( controller='library_common',
+ # action='browse_library',
+ # cntrller='library_admin',
+ # id=library_id ) ),
grids.GridAction( "Browse this request",
dict( controller='requests_common',
- action='manage_request',
+ action='view_request',
cntrller='requests_admin',
id=request_id ) ) ]
return self.datatx_grid( trans, **kwd )
--- a/templates/requests/common/edit_basic_request_info.mako
+++ b/templates/requests/common/edit_basic_request_info.mako
@@ -1,14 +1,25 @@
<%inherit file="/base.mako"/><%namespace file="/message.mako" import="render_msg" />
+<%
+ is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
+ can_add_samples = request.is_unsubmitted
+%>
+
<br/><br/><ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_common', action='manage_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a>
- </li>
- <li>
- <a class="action-button" href="${h.url_for( controller=cntrller, action='browse_requests' )}">Browse all requests</a>
- </li>
+ <li><a class="action-button" id="request-${request.id}-popup" class="menubutton">Request Actions</a></li>
+ <div popupmenu="request-${request.id}-popup">
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a>
+ %if can_add_samples:
+ <a class="action-button" confirm="More samples cannot be added to this request once it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit</a>
+ %endif
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">View history</a>
+ %if is_admin and request.is_submitted:
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject</a>
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='get_data', request_id=trans.security.encode_id( request.id ) )}">Select datasets to transfer</a>
+ %endif
+ </div></ul>
%if message:
--- /dev/null
+++ b/templates/requests/common/view_request.mako
@@ -0,0 +1,157 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+<%namespace file="/requests/common/common.mako" import="common_javascripts" />
+<%namespace file="/requests/common/common.mako" import="render_samples_grid" />
+<%namespace file="/requests/common/common.mako" import="render_request_type_sample_form_grids" />
+
+<%def name="stylesheets()">
+ ${parent.stylesheets()}
+ ${h.css( "library" )}
+</%def>
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ ${common_javascripts()}
+</%def>
+
+<%
+ from galaxy.web.framework.helpers import time_ago
+
+ is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
+ is_unsubmitted = request.is_unsubmitted
+ can_edit_request = ( is_admin and not request.is_complete ) or request.is_unsubmitted
+ can_add_samples = is_unsubmitted
+%>
+
+<br/><br/>
+
+<ul class="manage-table-actions">
+ %if is_unsubmitted:
+ <li><a class="action-button" confirm="More samples cannot be added to this request after it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit request</a></li>
+ %endif
+ <li><a class="action-button" id="request-${request.id}-popup" class="menubutton">Request actions</a></li>
+ <div popupmenu="request-${request.id}-popup">
+ %if can_edit_request:
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit</a>
+ %endif
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">View history</a>
+ %if is_admin and request.is_submitted:
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject</a>
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='get_data', request_id=trans.security.encode_id( request.id ) )}">Select datasets to transfer</a>
+ %endif
+ </div>
+</ul>
+
+%if request.is_rejected:
+ <font color="red"><b><i>Reason for rejection: </i></b></font><b>${request.last_comment}</b>
+ <br/><br/>
+%endif
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">Sequencing request "${request.name}"</div>
+ <div class="toolFormBody">
+ <div class="form-row">
+ <label>Current state:</label>
+ ${request.state}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Description:</label>
+ ${request.desc}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>User:</label>
+ %if is_admin:
+ ${request.user.email}
+ %elif request.user.username:
+ ${request.user.username}
+ %else:
+ Unknown
+ %endif
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <h4><img src="/static/images/fugue/toggle-expand.png" alt="Show" onclick="showContent(this);" style="cursor:pointer;"/> More</h4>
+ <div style="display:none;">
+ %for index, rd in enumerate( request_widgets ):
+ <%
+ field_label = rd[ 'label' ]
+ field_value = rd[ 'value' ]
+ %>
+ <div class="form-row">
+ <label>${field_label}:</label>
+ %if field_label == 'State':
+ <a href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">${field_value}</a>
+ %else:
+ ${field_value}
+ %endif
+ </div>
+ <div style="clear: both"></div>
+ %endfor
+ <div class="form-row">
+ <label>Date created:</label>
+ ${request.create_time}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Last updated:</label>
+ ${time_ago( request.update_time )}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Email recipients:</label>
+ <%
+ if request.notification:
+ emails = ', '.join( request.notification[ 'email' ] )
+ else:
+ emails = ''
+ %>
+ ${emails}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Send email when state changes to:</label>
+ <%
+ if request.notification:
+ states = []
+ for ss in request.type.states:
+ if ss.id in request.notification[ 'sample_states' ]:
+ states.append( ss.name )
+ states = ', '.join( states )
+ else:
+ states = ''
+ %>
+ ${states}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Sequencer configuration:</label>
+ ${request.type.name}
+ <div style="clear: both"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+<p/>
+%if current_samples:
+ <% grid_header = '<h3>Samples</h3>' %>
+ ${render_samples_grid( cntrller, request, current_samples=current_samples, action='view_request', editing_samples=False, encoded_selected_sample_ids=[], render_buttons=can_edit_request, grid_header=grid_header )}
+%else:
+ There are no samples.
+ %if can_add_samples:
+ <ul class="manage-table-actions">
+ <li><a class="action-button" href="${h.url_for( controller='requests_common', action='add_sample', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), add_sample_button='Add sample' )}">Add sample</a></li>
+ </ul>
+ %endif
+%endif
+## Render the other grids
+<% trans.sa_session.refresh( request.type.sample_form ) %>
+%for grid_index, grid_name in enumerate( request.type.sample_form.layout ):
+ ${render_request_type_sample_form_grids( grid_index, grid_name, request.type.sample_form.grid_fields( grid_index ), editing_samples=False )}
+%endfor
--- a/lib/galaxy/web/controllers/library.py
+++ b/lib/galaxy/web/controllers/library.py
@@ -24,13 +24,11 @@ class LibraryListGrid( grids.Grid ):
columns = [
NameColumn( "Name",
key="name",
- model_class=model.Library,
link=( lambda library: dict( operation="browse", id=library.id ) ),
attach_popup=False,
filterable="advanced" ),
DescriptionColumn( "Description",
key="description",
- model_class=model.Library,
attach_popup=False,
filterable="advanced" ),
]
--- a/templates/admin/forms/show_form_read_only.mako
+++ b/templates/admin/forms/show_form_read_only.mako
@@ -81,10 +81,10 @@
<form name="library" action="${h.url_for( controller='forms', action='manage' )}" method="post" >
%if form_definition.type == trans.app.model.FormDefinition.types.SAMPLE:
%if not len(form_definition.layout):
- ${render_grid( 0, '', form_definition.fields_of_grid( None ) )}
+ ${render_grid( 0, '', form_definition.grid_fields( None ) )}
%else:
%for grid_index, grid_name in enumerate(form_definition.layout):
- ${render_grid( grid_index, grid_name, form_definition.fields_of_grid( grid_index ) )}
+ ${render_grid( grid_index, grid_name, form_definition.grid_fields( grid_index ) )}
%endfor
%endif
%else:
--- a/templates/library/common/browse_library.mako
+++ b/templates/library/common/browse_library.mako
@@ -346,7 +346,6 @@
><td style="padding-left: ${folder_pad}px;"><input type="checkbox" class="folderCheckbox"/>
-
%if folder.deleted:
<span class="libraryItem-error">
%endif
@@ -354,7 +353,6 @@
<div style="float: left; margin-left: 2px;" class="menubutton split popup" id="folder_img-${folder.id}-popup"><a href="javascript:void(0);">${folder.name}</a></div>
-
%if folder.deleted:
</span>
%endif
--- a/templates/admin/requests/reject.mako
+++ b/templates/admin/requests/reject.mako
@@ -8,16 +8,16 @@
<h2>Reject Sequencing Request "${request.name}"</h2><ul class="manage-table-actions"><li>
- <a class="action-button" href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id(request.id) )}">Events</a>
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id(request.id) )}">View history</a></li><li>
- <a class="action-button" href="${h.url_for( controller='requests_common', action='manage_request', cntrller=cntrller, id=trans.security.encode_id(request.id) )}">Browse this request</a>
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id(request.id) )}">Browse this request</a></li></ul><div class="toolForm"><div class="toolFormTitle">Reject request</div>
- <form name="event" action="${h.url_for( controller='requests_admin', action='reject', id=trans.security.encode_id( request.id ) )}" method="post" >
+ <form name="event" action="${h.url_for( controller='requests_admin', action='reject_request', id=trans.security.encode_id( request.id ) )}" method="post" ><div class="form-row">
Rejecting this request will move the request state to <b>Rejected</b>.
</div>
--- a/templates/admin/requests/get_data.mako
+++ b/templates/admin/requests/get_data.mako
@@ -75,7 +75,7 @@
<a class="action-button" href="${h.url_for( controller='requests_admin', action='view_request_type', id=trans.security.encode_id( request.type.id ) )}">Sequencer configuration "${request.type.name}"</a></li><li>
- <a class="action-button" href="${h.url_for( controller='requests_common', action='manage_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a>
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a></li></ul>
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -1488,25 +1488,23 @@ class MetadataFile( object ):
return os.path.abspath( os.path.join( path, "metadata_%d.dat" % self.id ) )
class FormDefinition( object ):
- types = Bunch( REQUEST = 'Sequencing Request Form',
- SAMPLE = 'Sequencing Sample Form',
- LIBRARY_INFO_TEMPLATE = 'Library information template',
- USER_INFO = 'User Information' )
- def __init__(self, name=None, desc=None, fields=[],
- form_definition_current=None, form_type=None, layout=None):
+ types = Bunch( REQUEST = 'Sequencing Request Form',
+ SAMPLE = 'Sequencing Sample Form',
+ LIBRARY_INFO_TEMPLATE = 'Library information template',
+ USER_INFO = 'User Information' )
+ def __init__( self, name=None, desc=None, fields=[], form_definition_current=None, form_type=None, layout=None ):
self.name = name
self.desc = desc
self.fields = fields
self.form_definition_current = form_definition_current
self.type = form_type
self.layout = layout
- def fields_of_grid(self, grid_index):
- '''
- This method returns the list of fields belonging to the given grid.
- '''
+ def grid_fields( self, grid_index ):
+ # Returns a dictionary whose keys are integers corresponding to field positions
+ # on the grid and whose values are the field.
gridfields = {}
- for i, f in enumerate(self.fields):
- if str(f['layout']) == str(grid_index):
+ for i, f in enumerate( self.fields ):
+ if str( f[ 'layout' ] ) == str( grid_index ):
gridfields[i] = f
return gridfields
def get_widgets( self, user, contents=[], **kwd ):
--- a/lib/galaxy/web/controllers/requests.py
+++ b/lib/galaxy/web/controllers/requests.py
@@ -10,11 +10,10 @@ log = logging.getLogger( __name__ )
class UserRequestsGrid( RequestsGrid ):
operations = [ operation for operation in RequestsGrid.operations ]
- operations.append( grids.GridOperation( "Edit", allow_multiple=False, condition=( lambda item: not item.deleted and item.is_unsubmitted ) ) )
- operations.append( grids.GridOperation( "Delete", allow_multiple=True, condition=( lambda item: not item.deleted and item.is_new ) ) )
+ operations.append( grids.GridOperation( "Edit", allow_multiple=False, condition=( lambda item: item.is_unsubmitted and not item.deleted ) ) )
+ operations.append( grids.GridOperation( "Delete", allow_multiple=True, condition=( lambda item: item.is_new and not item.deleted ) ) )
operations.append( grids.GridOperation( "Undelete", allow_multiple=True, condition=( lambda item: item.deleted ) ) )
def apply_query_filter( self, trans, query, **kwd ):
- # gvk ( 9/28/10 ) TODO: is this method needed?
return query.filter_by( user=trans.user )
class Requests( BaseController ):
@@ -37,9 +36,9 @@ class Requests( BaseController ):
action='edit_basic_request_info',
cntrller='requests',
**kwd ) )
- if operation == "manage_request":
+ if operation == "view_request":
return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
+ action='view_request',
cntrller='requests',
**kwd ) )
if operation == "delete":
@@ -70,12 +69,12 @@ class Requests( BaseController ):
message = "%d requests (highlighted in red) were rejected. Click on the request name for details." % rejected
kwd[ 'status' ] = status
kwd[ 'message' ] = message
- # show the create request button to the user, only when the user has permissions
- # to at least one request_type (sequencer configuration)
+ # Allow the user to create a new request only if they have permission to access a
+ # (sequencer configuration) request type.
if len( trans.user.accessible_request_types( trans ) ):
self.request_grid.global_actions = [ grids.GridAction( "Create new request", dict( controller='requests_common',
- action='create_request',
- cntrller='requests' ) ) ]
+ action='create_request',
+ cntrller='requests' ) ) ]
else:
self.request_grid.global_actions = []
# Render the list view
--- a/templates/requests/common/find_samples.mako
+++ b/templates/requests/common/find_samples.mako
@@ -76,7 +76,7 @@
<i>User: ${sample.request.user.email}</i>
%endif
<div class="toolParamHelp" style="clear: both;">
- <a href="${h.url_for( controller='requests_common', action='manage_request', cntrller=cntrller, id=trans.security.encode_id( sample.request.id ) )}">Sequencing request: ${sample.request.name} | Type: ${sample.request.type.name} | State: ${sample.request.state}</a>
+ <a href="${h.url_for( controller='requests_common', action='edit_samples', cntrller=cntrller, id=trans.security.encode_id( sample.request.id ) )}">Sequencing request: ${sample.request.name} | Type: ${sample.request.type.name} | State: ${sample.request.state}</a></div></div><br/>
--- a/lib/galaxy/web/controllers/forms.py
+++ b/lib/galaxy/web/controllers/forms.py
@@ -86,7 +86,7 @@ class Forms( BaseController ):
status='error',
message="Invalid form ID") )
if operation == "view":
- return self.__view( trans, **kwd )
+ return self.view_form_definition( trans, **kwd )
elif operation == "delete":
return self.__delete( trans, **kwd )
elif operation == "undelete":
@@ -94,10 +94,12 @@ class Forms( BaseController ):
elif operation == "edit":
return self.edit( trans, **kwd )
return self.forms_grid( trans, **kwd )
- def __view(self, trans, **kwd):
+ @web.expose
+ def view_form_definition( self, trans, **kwd ):
+ form_definition_current_id = kwd.get( 'id', None )
try:
- fdc = trans.sa_session.query( trans.app.model.FormDefinitionCurrent )\
- .get( trans.security.decode_id(kwd['id']) )
+ fdc = trans.sa_session.query( trans.app.model.FormDefinitionCurrent ) \
+ .get( trans.security.decode_id( form_definition_current_id ) )
except:
return trans.response.send_redirect( web.url_for( controller='forms',
action='manage',
--- /dev/null
+++ b/templates/requests/common/common.mako
@@ -0,0 +1,332 @@
+<%namespace file="/requests/common/sample_state.mako" import="render_sample_state" />
+
+<%def name="javascripts()">
+ ${self.common_javascripts()}
+</%def>
+
+<%def name="common_javascripts()">
+ <script type="text/javascript">
+ function showContent(vThis)
+ {
+ // http://www.javascriptjunkie.com
+ // alert(vSibling.className + " " + vDef_Key);
+ vParent = vThis.parentNode;
+ vSibling = vParent.nextSibling;
+ while (vSibling.nodeType==3) {
+ // Fix for Mozilla/FireFox Empty Space becomes a TextNode or Something
+ vSibling = vSibling.nextSibling;
+ };
+ if(vSibling.style.display == "none")
+ {
+ vThis.src="/static/images/fugue/toggle.png";
+ vThis.alt = "Hide";
+ vSibling.style.display = "block";
+ } else {
+ vSibling.style.display = "none";
+ vThis.src="/static/images/fugue/toggle-expand.png";
+ vThis.alt = "Show";
+ }
+ return;
+ }
+ $(document).ready(function(){
+ //hide the all of the element with class msg_body
+ $(".msg_body").hide();
+ //toggle the component with class msg_body
+ $(".msg_head").click(function(){
+ $(this).next(".msg_body").slideToggle(0);
+ });
+ });
+
+ function checkAllFields()
+ {
+ var chkAll = document.getElementById('checkAll');
+ var checks = document.getElementsByTagName('input');
+ var boxLength = checks.length;
+ var allChecked = false;
+ var totalChecked = 0;
+ if ( chkAll.checked == true )
+ {
+ for ( i=0; i < boxLength; i++ )
+ {
+ if ( checks[i].name.indexOf( 'select_sample_' ) != -1)
+ {
+ checks[i].checked = true;
+ }
+ }
+ }
+ else
+ {
+ for ( i=0; i < boxLength; i++ )
+ {
+ if ( checks[i].name.indexOf( 'select_sample_' ) != -1)
+ {
+ checks[i].checked = false
+ }
+ }
+ }
+ }
+ </script>
+</%def>
+
+<%def name="render_editable_sample_row( is_admin, sample, current_sample_index, current_sample, encoded_selected_sample_ids )">
+ <%
+ if sample:
+ is_complete = sample.request.is_complete
+ is_submitted = sample.request.is_submitted
+ is_unsubmitted = sample.request.is_unsubmitted
+ else:
+ is_complete = False
+ is_submitted = False
+ is_unsubmitted = False
+ %>
+ <%
+ if is_admin and is_submitted and editing_samples and trans.security.encode_id( sample.id ) in encoded_selected_sample_ids:
+ checked_str = "checked"
+ else:
+ checked_str = ""
+ %>
+ %if is_admin and is_submitted and editing_samples:
+ <td><input type="checkbox" name=select_sample_${sample.id} id="sample_checkbox" value="true" ${checked_str}/><input type="hidden" name=select_sample_${sample.id} id="sample_checkbox" value="true"/></td>
+ %endif
+ <td>
+ <input type="text" name="sample_${current_sample_index}_name" value="${current_sample['name']}" size="10"/>
+ <div class="toolParamHelp" style="clear: both;">
+ <i>${' (required)' }</i>
+ </div>
+ </td>
+ %if sample and is_submitted or is_complete:
+ <td><input type="text" name="sample_${current_sample_index}_barcode" value="${current_sample['barcode']}" size="10"/></td>
+ %endif
+ %if sample:
+ %if is_unsubmitted:
+ <td>Unsubmitted</td>
+ %else:
+ <td><a href="${h.url_for( controller='requests_common', action='sample_events', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${sample.state.name}</a></td>
+ %endif
+ %else:
+ <td></td>
+ %endif
+ <td>${current_sample['library_select_field'].get_html()}</td>
+ <td>${current_sample['folder_select_field'].get_html()}</td>
+ %if is_submitted or is_complete:
+ <%
+ if sample:
+ label = str( len( sample.datasets ) )
+ else:
+ label = 'add'
+ %>
+ <td><a href="${h.url_for( controller='requests_common', action='view_dataset_transfer', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${label}</a></td>
+ <td><a href="${h.url_for( controller='requests_common', action='view_dataset_transfer', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${label}</a></td>
+ %endif
+ %if sample and ( is_admin or is_unsubmitted ):
+ ## Delete button
+ <td><a class="action-button" href="${h.url_for( controller='requests_common', action='delete_sample', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id=current_sample_index )}"><img src="${h.url_for('/static/images/delete_icon.png')}" style="cursor:pointer;"/></a></td>
+ %endif
+</%def>
+
+<%def name="render_samples_grid( cntrller, request, current_samples, action, editing_samples=False, encoded_selected_sample_ids=[], render_buttons=False, grid_header='<h3>Samples</h3>' )">
+ ## Displays the "Samples" grid
+ <%
+ is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
+ is_complete = request.is_complete
+ is_submitted = request.is_submitted
+ is_unsubmitted = request.is_unsubmitted
+ can_add_samples = request.is_unsubmitted
+ can_edit_or_delete_samples = request.samples and ( is_admin or request.is_unsubmitted )
+ %>
+ ${grid_header}
+ %if render_buttons and ( can_add_samples or can_edit_or_delete_samples ):
+ <ul class="manage-table-actions">
+ %if can_add_samples:
+ <li><a class="action-button" href="${h.url_for( controller='requests_common', action='add_sample', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), add_sample_button='Add sample' )}">Add sample</a></li>
+ %endif
+ %if can_edit_or_delete_samples:
+ <li><a class="action-button" href="${h.url_for( controller='requests_common', action='edit_samples', cntrller=cntrller, id=trans.security.encode_id( request.id ), editing_samples='True' )}">Edit samples</a></li>
+ %endif
+ </ul>
+ %endif
+ <table class="grid">
+ <thead>
+ <tr>
+ %if is_admin and is_submitted and editing_samples:
+ <th><input type="checkbox" id="checkAll" name=select_all_samples_checkbox value="true" onclick='checkAllFields(1);'/><input type="hidden" name=select_all_samples_checkbox value="true"/></th>
+ %endif
+ <th>Name</th>
+ %if is_submitted or is_complete:
+ <th>Barcode</th>
+ %endif
+ <th>State</th>
+ <th>Data Library</th>
+ <th>Folder</th>
+ %if is_submitted or is_complete:
+ <th>Datasets Selected</th>
+ <th>Datasets Transferred</th>
+ %endif
+ <th>
+ %if editing_samples:
+ Delete
+ %endif
+ </th>
+ </tr>
+ <thead>
+ <tbody>
+ <% trans.sa_session.refresh( request ) %>
+ ## current_samples is a dictionary whose keys are:
+ ## name, barcode, library, folder, field_values, library_select_field, folder_select_field
+ %for current_sample_index, current_sample in enumerate( current_samples ):
+ <%
+ current_sample_name = current_sample[ 'name' ]
+ current_sample_barcode = current_sample[ 'barcode' ]
+ current_sample_library = current_sample[ 'library' ]
+ if current_sample_library:
+ if cntrller == 'requests':
+ library_cntrller = 'library'
+ elif is_admin:
+ library_cntrller = 'library_admin'
+ else:
+ library_cntrller = None
+ current_sample_folder = current_sample[ 'folder' ]
+ try:
+ sample = request.samples[ current_sample_index ]
+ except:
+ sample = None
+ %>
+ %if editing_samples:
+ <tr>${render_editable_sample_row( is_admin, sample, current_sample_index, current_sample, encoded_selected_sample_ids )}</tr>
+ %elif sample:
+ <tr>
+ <td>${current_sample_name}</td>
+ %if is_submitted or is_complete:
+ <td>${current_sample_barcode}</td>
+ %endif
+ %if is_unsubmitted:
+ <td>Unsubmitted</td>
+ %else:
+ <td><a id="sampleState-${sample.id}" href="${h.url_for( controller='requests_common', action='sample_events', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${render_sample_state( sample )}</a></td>
+ %endif
+ %if current_sample_library and library_cntrller is not None:
+ <td><a href="${h.url_for( controller='library_common', action='browse_library', cntrller=library_cntrller, id=trans.security.encode_id( current_sample_library.id ) )}">${current_sample_library.name}</a></td>
+ %else:
+ <td></td>
+ %endif
+ %if current_sample_folder:
+ <td>${current_sample_folder.name}</td>
+ %else:
+ <td></td>
+ %endif
+ %if is_submitted or is_complete:
+ <td><a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_common', action='view_dataset_transfer', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a></td>
+ <td><a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_common', action='view_dataset_transfer', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.transferred_dataset_files )}</a></td>
+ %endif
+ </tr>
+ %else:
+ <tr>${render_editable_sample_row( is_admin, None, current_sample_index, current_sample, encoded_selected_sample_ids )}</tr>
+ %endif
+ %endfor
+ </tbody>
+ </table>
+</%def>
+
+<%def name="render_sample_form( index, sample_name, sample_values, fields_dict, display_only )">
+ <tr>
+ <td>${sample_name}</td>
+ %for field_index, field in fields_dict.items():
+ <%
+ field_type = field[ 'type' ]
+ %>
+ <td>
+ %if display_only:
+ %if sample_values[field_index]:
+ %if field_type == 'WorkflowField':
+ %if str(sample_values[field_index]) != 'none':
+ <% workflow = trans.sa_session.query( trans.app.model.StoredWorkflow ).get( int( sample_values[ field_index ] ) ) %>
+ <a href="${h.url_for( controller='workflow', action='run', id=trans.security.encode_id( workflow.id ) )}">${workflow.name}</a>
+ %endif
+ %else:
+ ${sample_values[ field_index ]}
+ %endif
+ %else:
+ <i>None</i>
+ %endif
+ %else:
+ %if field_type == 'TextField':
+ <input type="text" name="sample_${index}_field_${field_index}" value="${sample_values[field_index]}" size="7"/>
+ %elif field_type == 'SelectField':
+ <select name="sample_${index}_field_${field_index}" last_selected_value="2">
+ %for option_index, option in enumerate(field['selectlist']):
+ %if option == sample_values[field_index]:
+ <option value="${option}" selected>${option}</option>
+ %else:
+ <option value="${option}">${option}</option>
+ %endif
+ %endfor
+ </select>
+ %elif field_type == 'WorkflowField':
+ <select name="sample_${index}_field_${field_index}">
+ %if str(sample_values[field_index]) == 'none':
+ <option value="none" selected>Select one</option>
+ %else:
+ <option value="none">Select one</option>
+ %endif
+ %for option_index, option in enumerate(request.user.stored_workflows):
+ %if not option.deleted:
+ %if str(option.id) == str(sample_values[field_index]):
+ <option value="${option.id}" selected>${option.name}</option>
+ %else:
+ <option value="${option.id}">${option.name}</option>
+ %endif
+ %endif
+ %endfor
+ </select>
+ %elif field_type == 'CheckboxField':
+ <input type="checkbox" name="sample_${index}_field_${field_index}" value="Yes"/>
+ %endif
+ <div class="toolParamHelp" style="clear: both;">
+ <i>${'('+field['required']+')' }</i>
+ </div>
+ %endif
+ </td>
+ %endfor
+ </tr>
+</%def>
+
+<%def name="render_request_type_sample_form_grids( grid_index, grid_name, fields_dict, editing_samples )">
+ <%
+ if not grid_name:
+ grid_name = "Sample form layout " + grid_index
+ %>
+ <h4><img src="/static/images/fugue/toggle-expand.png" alt="Hide" onclick="showContent(this);" style="cursor:pointer;"/> ${grid_name}</h4>
+ <div style="display:none;">
+ <table class="grid">
+ <thead>
+ <tr>
+ <th>Name</th>
+ %for index, field in fields_dict.items():
+ <th>
+ ${field['label']}
+ ## TODO: help comments in the grid header are UGLY!
+ ## If they are needed display them more appropriately,
+ ## if they are not, delete this commented code.
+ ##<div class="toolParamHelp" style="clear: both;">
+ ## <i>${field['helptext']}</i>
+ ##</div>
+ </th>
+ %endfor
+ <th></th>
+ </tr>
+ <thead>
+ <tbody>
+ <% trans.sa_session.refresh( request ) %>
+ %for sample_index, sample in enumerate( current_samples ):
+ <%
+ if editing_samples or sample_index >= len( request.samples ):
+ display_only = False
+ else:
+ display_only = True
+ %>
+ ${render_sample_form( sample_index, sample['name'], sample['field_values'], fields_dict, display_only )}
+ %endfor
+ </tbody>
+ </table>
+ </div>
+</%def>
--- a/test/base/twilltestcase.py
+++ b/test/base/twilltestcase.py
@@ -1489,17 +1489,17 @@ class TwillTestCase( unittest.TestCase )
for check_str in strings_displayed_after_submit:
self.check_page_for_string( check_str )
def add_samples( self, cntrller, request_id, request_name, sample_value_tuples, strings_displayed=[], strings_displayed_after_submit=[] ):
- self.visit_url( "%s/requests_common/manage_request?cntrller=%s&id=%s" % ( self.url, cntrller, request_id ) )
+ self.visit_url( "%s/requests_common/edit_samples?cntrller=%s&id=%s&editing_samples=False" % ( self.url, cntrller, request_id ) )
for check_str in strings_displayed:
self.check_page_for_string( check_str )
# Simulate clicking the add-sample_button on the form. (gvk: 9/21/10 - TODO : There must be a bug in the mako template
# because twill cannot find any forms on the page, but I cannot find it although I've spent time cleaning up the
# template code and looking for any problems.
- url = "%s/requests_common/manage_request?cntrller=%s&id=%s" % ( self.url, cntrller, request_id )
+ url = "%s/requests_common/edit_samples?cntrller=%s&id=%s&editing_samples=False" % ( self.url, cntrller, request_id )
# This should work, but although twill does not thorw any exceptions, the button click never occurs
- # There are multiple forms on this page, and we'll only be using the form named manage_request.
+ # There are multiple forms on this page, and we'll only be using the form named edit_samples.
# for sample_index, sample_value_tuple in enumerate( sample_value_tuples ):
- # # Add the following form value to the already populated hidden field so that the manage_request
+ # # Add the following form value to the already populated hidden field so that the edit_samples
# # form is the current form
# tc.fv( "1", "id", request_id )
# tc.submit( 'add_sample_button' )
@@ -1530,7 +1530,7 @@ class TwillTestCase( unittest.TestCase )
for check_str in strings_displayed_after_submit:
self.check_page_for_string( check_str )
def reject_request( self, request_id, request_name, comment, strings_displayed=[], strings_displayed_after_submit=[] ):
- self.visit_url( "%s/requests_admin/reject?id=%s" % ( self.url, request_id ) )
+ self.visit_url( "%s/requests_admin/reject_request?id=%s" % ( self.url, request_id ) )
for check_str in strings_displayed:
self.check_page_for_string( check_str )
tc.fv( "1", "comment", comment )
@@ -1540,7 +1540,7 @@ class TwillTestCase( unittest.TestCase )
def add_bar_codes( self, request_id, request_name, bar_codes, samples, strings_displayed_after_submit=[] ):
# We have to simulate the form submission here since twill barfs on the page
# gvk - 9/22/10 - TODO: make sure the mako template produces valid html
- url = "%s/requests_common/manage_request?cntrller=requests_admin&id=%s&managing_samples=True" % ( self.url, request_id )
+ url = "%s/requests_common/edit_samples?cntrller=requests_admin&id=%s&editing_samples=True" % ( self.url, request_id )
for index, field_value in enumerate( bar_codes ):
sample_field_name = "sample_%i_name" % index
sample_field_value = samples[ index ].name.replace( ' ', '+' )
@@ -1555,15 +1555,15 @@ class TwillTestCase( unittest.TestCase )
strings_displayed=[], strings_displayed_after_submit=[] ):
# We have to simulate the form submission here since twill barfs on the page
# gvk - 9/22/10 - TODO: make sure the mako template produces valid html
- url = "%s/requests_common/manage_request?cntrller=requests_admin&id=%s" % ( self.url, request_id )
+ url = "%s/requests_common/edit_samples?cntrller=requests_admin&id=%s" % ( self.url, request_id )
url += "&comment=%s&sample_state_id=%s" % ( comment, self.security.encode_id( new_sample_state_id ) )
# select_sample_%i=true must be included twice for each sample to simulate a CheckboxField checked setting.
for sample_id in sample_ids:
url += "&select_sample_%i=true&select_sample_%i=true" % ( sample_id, sample_id )
url += "&sample_operation=Change%20state&refresh=true"
- url += "&change_state_button=Save"
+ url += "&save_changes_button=Save&editing_samples=True"
self.visit_url( url )
- self.check_page_for_string( 'Sequencing Request "%s"' % request_name )
+ self.check_page_for_string( 'Edit Current Samples of Request "%s"' % request_name )
for sample_id, sample_name in zip( sample_ids, sample_names ):
self.visit_url( "%s/requests_common/sample_events?cntrller=requests_admin&sample_id=%s" % ( self.url, self.security.encode_id( sample_id ) ) )
self.check_page_for_string( 'Events for Sample "%s"' % sample_name )
--- a/templates/requests/common/events.mako
+++ b/templates/requests/common/events.mako
@@ -1,20 +1,36 @@
<%inherit file="/base.mako"/><%namespace file="/message.mako" import="render_msg" />
-<h2>History of Sequencing Request "${request.name}"</h2>
+<%
+ is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
+ can_edit_request = ( is_admin and not request.is_complete ) or request.is_unsubmitted
+ can_add_samples = request.is_unsubmitted
+%>
+
+<br/><br/><ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_common', action='manage_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a>
- </li>
- <li>
- <a class="action-button" href="${h.url_for( controller=cntrller, action='browse_requests' )}">Browse all requests</a>
- </li>
+ <li><a class="action-button" id="request-${request.id}-popup" class="menubutton">Request Actions</a></li>
+ <div popupmenu="request-${request.id}-popup">
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a>
+ %if can_edit_request:
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit</a>
+ %endif
+ %if can_add_samples:
+ <a class="action-button" confirm="More samples cannot be added to this request once it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit</a>
+ %endif
+ %if is_admin and request.is_submitted:
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject</a>
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='get_data', request_id=trans.security.encode_id( request.id ) )}">Select datasets to transfer</a>
+ %endif
+ </div></ul>
%if message:
${render_msg( message, status )}
%endif
+<h2>History of Sequencing Request "${request.name}"</h2>
+
<div class="toolForm"><table class="grid"><thead>
--- a/lib/galaxy/web/controllers/requests_common.py
+++ b/lib/galaxy/web/controllers/requests_common.py
@@ -70,14 +70,14 @@ class RequestsGrid( grids.Grid ):
columns = [
NameColumn( "Name",
key="name",
- link=( lambda item: iff( item.deleted, None, dict( operation="manage_request", id=item.id ) ) ),
+ link=( lambda item: iff( item.deleted, None, dict( operation="view_request", id=item.id ) ) ),
attach_popup=True,
filterable="advanced" ),
DescriptionColumn( "Description",
key='desc',
filterable="advanced" ),
SamplesColumn( "Samples",
- link=( lambda item: iff( item.deleted, None, dict( operation="manage_request", id=item.id ) ) ) ),
+ link=( lambda item: iff( item.deleted, None, dict( operation="edit_samples", id=item.id ) ) ) ),
TypeColumn( "Sequencer",
link=( lambda item: iff( item.deleted, None, dict( operation="view_type", id=item.type.id ) ) ) ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
@@ -148,7 +148,7 @@ class RequestsCommon( BaseController, Us
except TypeError, e:
# We must have an email address rather than an encoded user id
# This is because the galaxy.base.js creates a search+select box
- # when there are more than 20 items in a selectfield
+ # when there are more than 20 items in a SelectField.
user = trans.sa_session.query( trans.model.User ) \
.filter( trans.model.User.table.c.email==util.restore_text( user_id ) ) \
.first()
@@ -178,7 +178,8 @@ class RequestsCommon( BaseController, Us
message=message ,
status='done' ) )
elif params.get( 'add_sample_button', False ):
- return self.__add_sample( trans, cntrller, request, **kwd )
+ request_id = trans.security.encode_id( request.id )
+ return self.add_sample( trans, cntrller, request_id, **kwd )
request_type_select_field = self.__build_request_type_id_select_field( trans, selected_value=request_type_id )
# Widgets to be rendered on the request form
widgets = []
@@ -194,7 +195,7 @@ class RequestsCommon( BaseController, Us
widgets += request_type.request_form.get_widgets( user, **kwd )
# In case there is an error on the form, make sure to populate widget fields with anything the user
# may have already entered.
- self.populate_widgets_from_kwd( trans, widgets, **kwd )
+ widgets = self.populate_widgets_from_kwd( trans, widgets, **kwd )
if request_type is not None or status == 'error':
# Either the user selected a request_type or an error exists on the form.
if is_admin:
@@ -214,6 +215,29 @@ class RequestsCommon( BaseController, Us
message=message,
status=status )
@web.expose
+ @web.require_login( "view request" )
+ def view_request( self, trans, cntrller, **kwd ):
+ params = util.Params( kwd )
+ is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ request_id = params.get( 'id', None )
+ try:
+ request = trans.sa_session.query( trans.model.Request ).get( trans.security.decode_id( request_id ) )
+ except:
+ return invalid_id_redirect( trans, cntrller, request_id )
+ sample_state_id = params.get( 'sample_state_id', None )
+ # Get the user entered sample information
+ current_samples = self.__get_sample_widgets( trans, request, request.samples, **kwd )
+ request_widgets = self.__get_request_widgets( trans, request.id )
+ return trans.fill_template( '/requests/common/view_request.mako',
+ cntrller=cntrller,
+ request=request,
+ request_widgets=request_widgets,
+ current_samples=current_samples,
+ status=status,
+ message=message )
+ @web.expose
@web.require_login( "edit sequencing requests" )
def edit_basic_request_info( self, trans, cntrller, **kwd ):
params = util.Params( kwd )
@@ -226,7 +250,7 @@ class RequestsCommon( BaseController, Us
return invalid_id_redirect( trans, cntrller, request_id )
name = util.restore_text( params.get( 'name', '' ) )
desc = util.restore_text( params.get( 'desc', '' ) )
- if params.get( 'edit_basic_request_info_button', False ) or params.get( 'edit_samples_button', False ):
+ if params.get( 'edit_basic_request_info_button', False ):
if not name:
status = 'error'
message = 'Enter the name of the request'
@@ -244,7 +268,7 @@ class RequestsCommon( BaseController, Us
widgets = widgets + request.type.request_form.get_widgets( request.user, request.values.content, **kwd )
# In case there is an error on the form, make sure to populate widget fields with anything the user
# may have already entered.
- self.populate_widgets_from_kwd( trans, widgets, **kwd )
+ widgets = self.populate_widgets_from_kwd( trans, widgets, **kwd )
return trans.fill_template( 'requests/common/edit_basic_request_info.mako',
cntrller=cntrller,
request_type=request.type,
@@ -371,8 +395,8 @@ class RequestsCommon( BaseController, Us
status=status,
message=message ) )
@web.expose
- @web.require_login( "sequencing request page" )
- def manage_request( self, trans, cntrller, **kwd ):
+ @web.require_login( "manage samples" )
+ def edit_samples( self, trans, cntrller, **kwd ):
params = util.Params( kwd )
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
message = util.restore_text( params.get( 'message', '' ) )
@@ -382,80 +406,64 @@ class RequestsCommon( BaseController, Us
request = trans.sa_session.query( trans.model.Request ).get( trans.security.decode_id( request_id ) )
except:
return invalid_id_redirect( trans, cntrller, request_id )
- sample_state_id = params.get( 'sample_state_id', None )
+ # This method is called when the user is adding new samples as well as
+ # editing existing samples, so we use the editing_samples flag to keep
+ # track of what's occurring.
+ # TODO: CRITICAL: We need another round of code fixes to abstract out
+ # adding samples vs editing samples. We need to eliminate the need for
+ # this editing_samples flag since it is not maintainable. Greg will do
+ # this work as soon as possible.
+ editing_samples = util.string_as_bool( params.get( 'editing_samples', False ) )
+ if params.get( 'cancel_changes_button', False ):
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ action='edit_samples',
+ cntrller=cntrller,
+ id=request_id,
+ editing_samples=editing_samples ) )
+ # Get all libraries for which the current user has permission to add items.
+ libraries = request.user.accessible_libraries( trans, [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ] )
# Get the user entered sample information
- current_samples, managing_samples, libraries = self.__get_sample_info( trans, request, **kwd )
- selected_samples = self.__get_selected_samples( trans, request, **kwd )
- selected_value = params.get( 'sample_operation', 'none' )
- if selected_value != 'none' and not selected_samples:
+ current_samples = self.__get_sample_widgets( trans, request, request.samples, **kwd )
+ encoded_selected_sample_ids = self.__get_encoded_selected_sample_ids( trans, request, **kwd )
+ sample_operation = params.get( 'sample_operation', 'none' )
+ def handle_error( **kwd ):
+ kwd[ 'status' ] = 'error'
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ action='edit_samples',
+ cntrller=cntrller,
+ **kwd ) )
+ if not encoded_selected_sample_ids and sample_operation != 'none':
+ # Probably occurred due to refresh_on_change...is there a better approach?
+ kwd[ 'sample_operation' ] = 'none'
message = 'Select at least one sample before selecting an operation.'
- status = 'error'
- return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
- cntrller=cntrller,
- id=request_id,
- status=status,
- message=message ) )
- sample_operation_select_field = self.__build_sample_operation_select_field( trans, is_admin, request, selected_value )
- sample_operation_selected_value = sample_operation_select_field.get_selected( return_value=True )
+ kwd[ 'message' ] = message
+ handle_error( **kwd )
if params.get( 'import_samples_button', False ):
# Import sample field values from a csv file
return self.__import_samples( trans, cntrller, request, current_samples, libraries, **kwd )
elif params.get( 'add_sample_button', False ):
- return self.__add_sample( trans, cntrller, request, **kwd )
+ return self.add_sample( trans, cntrller, request_id, **kwd )
elif params.get( 'save_samples_button', False ):
- return self.__save_sample( trans, cntrller, request, current_samples, **kwd )
- elif params.get( 'edit_samples_button', False ):
- managing_samples = True
- elif params.get( 'cancel_changes_button', False ):
- return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
- cntrller=cntrller,
- id=request_id ) )
- pass
- elif params.get( 'change_state_button', False ):
- sample_event_comment = util.restore_text( params.get( 'sample_event_comment', '' ) )
- new_state = trans.sa_session.query( trans.model.SampleState ).get( trans.security.decode_id( sample_state_id ) )
- self.update_sample_state(trans, cntrller, selected_samples, new_state, comment=sample_event_comment )
- return trans.response.send_redirect( web.url_for( controller='requests_common',
- cntrller=cntrller,
- action='update_request_state',
- request_id=request_id ) )
- elif params.get( 'cancel_change_state_button', False ):
- return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
- cntrller=cntrller,
- id=request_id ) )
- elif params.get( 'change_lib_button', False ):
- library_id = params.get( 'sample_0_library_id', None )
- try:
- library = trans.sa_session.query( trans.model.Library ).get( trans.security.decode_id( library_id ) )
- except:
- invalid_id_redirect( trans, cntrller, library_id )
- folder_id = params.get( 'sample_0_folder_id', None )
- try:
- folder = trans.sa_session.query( trans.model.LibraryFolder ).get( trans.security.decode_id( folder_id ) )
- except:
- invalid_id_redirect( trans, cntrller, folder_id )
- for sample_id in selected_samples:
- sample = trans.sa_session.query( trans.model.Sample ).get( trans.security.decode_id( sample_id ) )
- sample.library = library
- sample.folder = folder
- trans.sa_session.add( sample )
- trans.sa_session.flush()
- trans.sa_session.refresh( request )
- message = 'Changes made to the selected samples have been saved. '
- return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
- cntrller=cntrller,
- id=request_id,
- status=status,
- message=message ) )
- elif params.get( 'cancel_change_lib_button', False ):
- return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
- cntrller=cntrller,
- id=trans.security.encode_id( request.id ) ) )
+ if encoded_selected_sample_ids:
+ # This gets tricky because we need the list of samples to include the same number
+ # of objects that that current_samples ( i.e., request.samples ) has. We'll first
+ # get the set of samples corresponding to the checked sample ids.
+ samples = []
+ selected_samples = []
+ for encoded_sample_id in encoded_selected_sample_ids:
+ sample = trans.sa_session.query( trans.model.Sample ).get( trans.security.decode_id( encoded_sample_id ) )
+ selected_samples.append( sample )
+ # Now build the list of samples, inserting None for samples that have not been checked.
+ for sample in request.samples:
+ if sample in selected_samples:
+ samples.append( sample )
+ else:
+ samples.append( None )
+ # The __save_samples method requires samples widgets, not sample objects
+ samples = self.__get_sample_widgets( trans, request, samples, **kwd )
+ else:
+ samples = current_samples
+ return self.__save_samples( trans, cntrller, request, samples, **kwd )
request_widgets = self.__get_request_widgets( trans, request.id )
sample_copy = self.__build_copy_sample_select_field( trans, current_samples )
libraries_select_field, folders_select_field = self.__build_library_and_folder_select_fields( trans,
@@ -464,12 +472,13 @@ class RequestsCommon( BaseController, Us
libraries,
None,
**kwd )
- # Build the sample_state_id_select_field SelectField
+ sample_operation_select_field = self.__build_sample_operation_select_field( trans, is_admin, request, sample_operation )
+ sample_state_id = params.get( 'sample_state_id', None )
sample_state_id_select_field = self.__build_sample_state_id_select_field( trans, request, sample_state_id )
- return trans.fill_template( '/requests/common/manage_request.mako',
+ return trans.fill_template( '/requests/common/edit_samples.mako',
cntrller=cntrller,
request=request,
- selected_samples=selected_samples,
+ encoded_selected_sample_ids=encoded_selected_sample_ids,
request_widgets=request_widgets,
current_samples=current_samples,
sample_copy=sample_copy,
@@ -478,7 +487,7 @@ class RequestsCommon( BaseController, Us
libraries_select_field=libraries_select_field,
folders_select_field=folders_select_field,
sample_state_id_select_field=sample_state_id_select_field,
- managing_samples=managing_samples,
+ editing_samples=editing_samples,
status=status,
message=message )
@web.expose
@@ -489,7 +498,7 @@ class RequestsCommon( BaseController, Us
except:
if cntrller == 'api':
trans.response.status = 400
- return "Malformed sample id ( %s ) specified, unable to decode." % str( sample_id )
+ return "Invalid sample id ( %s ) specified, unable to decode." % str( sample_id )
else:
return invalid_id_redirect( trans, cntrller, sample_id )
event = trans.model.SampleEvent( sample, new_state, comment )
@@ -516,7 +525,7 @@ class RequestsCommon( BaseController, Us
if ok_for_now:
request.deleted = True
trans.sa_session.add( request )
- # delete all the samples belonging to this request
+ # Delete all the samples belonging to this request
for s in request.samples:
s.deleted = True
trans.sa_session.add( s )
@@ -546,7 +555,7 @@ class RequestsCommon( BaseController, Us
if ok_for_now:
request.deleted = False
trans.sa_session.add( request )
- # undelete all the samples belonging to this request
+ # Undelete all the samples belonging to this request
for s in request.samples:
s.deleted = False
trans.sa_session.add( s )
@@ -655,9 +664,10 @@ class RequestsCommon( BaseController, Us
if cntrller == 'api':
return 200, message
return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
+ action='edit_samples',
cntrller=cntrller,
id=request_id,
+ editing_samples=True,
status=status,
message=message ) )
final_state = False
@@ -673,8 +683,8 @@ class RequestsCommon( BaseController, Us
event = trans.model.RequestEvent( request, state, comments )
trans.sa_session.add( event )
trans.sa_session.flush()
- # check if an email notification is configured to be sent when the samples
- # are in this state
+ # See if an email notification is configured to be sent when the samples
+ # are in this state.
retval = request.send_email_notification( trans, common_state, final_state )
if retval:
message = comments + retval
@@ -683,113 +693,10 @@ class RequestsCommon( BaseController, Us
if cntrller == 'api':
return 200, message
return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
+ action='edit_samples',
cntrller=cntrller,
- id=trans.security.encode_id(request.id),
- status='done',
- message=message ) )
- def __save_sample( self, trans, cntrller, request, current_samples, **kwd ):
- # Save all the new/unsaved samples entered by the user
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- managing_samples = util.string_as_bool( params.get( 'managing_samples', False ) )
- is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
- selected_value = params.get( 'sample_operation', 'none' )
- # Check for duplicate sample names
- message = ''
- for index in range( len( current_samples ) - len( request.samples ) ):
- sample_index = index + len( request.samples )
- current_sample = current_samples[ sample_index ]
- sample_name = current_sample[ 'name' ]
- if not sample_name.strip():
- message = 'Enter the name of sample number %i' % sample_index
- break
- count = 0
- for i in range( len( current_samples ) ):
- if sample_name == current_samples[ i ][ 'name' ]:
- count += 1
- if count > 1:
- message = "This request has %i samples with the name (%s). Samples belonging to a request must have unique names." % ( count, sample_name )
- break
- if message:
- selected_samples = self.__get_selected_samples( trans, request, **kwd )
- request_widgets = self.__get_request_widgets( trans, request.id )
- sample_copy = self.__build_copy_sample_select_field( trans, current_samples )
- sample_operation_select_field = self.__build_sample_operation_select_field( trans, is_admin, request, selected_value )
- status = 'error'
- return trans.fill_template( '/requests/common/manage_request.mako',
- cntrller=cntrller,
- request=request,
- selected_samples=selected_samples,
- request_widgets=request_widgets,
- current_samples=current_samples,
- sample_copy=sample_copy,
- managing_samples=managing_samples,
- sample_operation_select_field=sample_operation_select_field,
- status=status,
- message=message )
- if not managing_samples:
- for index in range( len( current_samples ) - len( request.samples ) ):
- sample_index = len( request.samples )
- current_sample = current_samples[ sample_index ]
- form_values = trans.model.FormValues( request.type.sample_form, current_sample[ 'field_values' ] )
- trans.sa_session.add( form_values )
- trans.sa_session.flush()
- s = trans.model.Sample( current_sample[ 'name' ],
- '',
- request,
- form_values,
- current_sample[ 'barcode' ],
- current_sample[ 'library' ],
- current_sample[ 'folder' ] )
- trans.sa_session.add( s )
- trans.sa_session.flush()
- else:
- message = 'Changes made to the samples are saved. '
- for sample_index in range( len( current_samples ) ):
- sample = request.samples[ sample_index ]
- current_sample = current_samples[ sample_index ]
- sample.name = current_sample[ 'name' ]
- sample.library = current_sample[ 'library' ]
- sample.folder = current_sample[ 'folder' ]
- if request.is_submitted:
- bc_message = self.__validate_barcode( trans, sample, current_sample[ 'barcode' ] )
- if bc_message:
- status = 'error'
- message += bc_message
- else:
- if not sample.bar_code:
- # If this is a 'new' (still in its first state) sample
- # change the state to the next
- if sample.state.id == request.type.states[0].id:
- event = trans.model.SampleEvent( sample,
- request.type.states[1],
- 'Sample added to the system' )
- trans.sa_session.add( event )
- trans.sa_session.flush()
- # Now check if all the samples' barcode has been entered.
- # If yes then send notification email if configured
- common_state = request.samples_have_common_state
- if common_state:
- if common_state.id == request.type.states[1].id:
- event = trans.model.RequestEvent( request,
- request.states.SUBMITTED,
- "All samples are in %s state." % common_state.name )
- trans.sa_session.add( event )
- trans.sa_session.flush()
- request.send_email_notification( trans, request.type.states[1] )
- sample.bar_code = current_samples[sample_index]['barcode']
- trans.sa_session.add( sample )
- trans.sa_session.flush()
- form_values = trans.sa_session.query( trans.model.FormValues ).get( sample.values.id )
- form_values.content = current_sample[ 'field_values' ]
- trans.sa_session.add( form_values )
- trans.sa_session.flush()
- return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
- cntrller=cntrller,
- id=trans.security.encode_id( request.id ),
+ id=request_id,
+ editing_samples=True,
status=status,
message=message ) )
@web.expose
@@ -876,25 +783,33 @@ class RequestsCommon( BaseController, Us
cntrller=cntrller,
events_list=events_list,
sample=sample )
- def __add_sample( self, trans, cntrller, request, **kwd ):
+ @web.expose
+ @web.require_login( "add sample" )
+ def add_sample( self, trans, cntrller, request_id, **kwd ):
params = util.Params( kwd )
message = util.restore_text( params.get( 'message', '' ) )
status = params.get( 'status', 'done' )
- managing_samples = util.string_as_bool( params.get( 'managing_samples', False ) )
+ try:
+ request = trans.sa_session.query( trans.model.Request ).get( trans.security.decode_id( request_id ) )
+ except:
+ return invalid_id_redirect( trans, cntrller, request_id )
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
# Get the widgets for rendering the request form
request_widgets = self.__get_request_widgets( trans, request.id )
- current_samples, managing_samples, libraries = self.__get_sample_info( trans, request, **kwd )
+ current_samples = self.__get_sample_widgets( trans, request, request.samples, **kwd )
if not current_samples:
# Form field names are zero-based.
sample_index = 0
else:
sample_index = len( current_samples )
if params.get( 'add_sample_button', False ):
+ # Get all libraries for which the current user has permission to add items
+ libraries = request.user.accessible_libraries( trans, [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ] )
num_samples_to_add = int( params.get( 'num_sample_to_copy', 1 ) )
# See if the user has selected a sample to copy.
copy_sample_index = int( params.get( 'copy_sample_index', -1 ) )
for index in range( num_samples_to_add ):
+ id_index = len( current_samples ) + 1
if copy_sample_index != -1:
# The user has selected a sample to copy.
library_id = current_samples[ copy_sample_index][ 'library_select_field' ].get_selected( return_value=True )
@@ -902,7 +817,7 @@ class RequestsCommon( BaseController, Us
name = current_samples[ copy_sample_index ][ 'name' ] + '_%i' % ( len( current_samples ) + 1 )
field_values = [ val for val in current_samples[ copy_sample_index ][ 'field_values' ] ]
else:
- # The user has not selected a sample to copy (may just be adding a sample).
+ # The user has not selected a sample to copy, just adding a new generic sample.
library_id = None
folder_id = None
name = 'Sample_%i' % ( len( current_samples ) + 1 )
@@ -910,7 +825,7 @@ class RequestsCommon( BaseController, Us
# Build the library_select_field and folder_select_field for the new sample being added.
library_select_field, folder_select_field = self.__build_library_and_folder_select_fields( trans,
user=request.user,
- sample_index=len( current_samples ),
+ sample_index=id_index,
libraries=libraries,
sample=None,
library_id=library_id,
@@ -926,101 +841,21 @@ class RequestsCommon( BaseController, Us
field_values=field_values,
library_select_field=library_select_field,
folder_select_field=folder_select_field ) )
- selected_samples = self.__get_selected_samples( trans, request, **kwd )
- selected_value = params.get( 'sample_operation', 'none' )
- sample_operation_select_field = self.__build_sample_operation_select_field( trans, is_admin, request, selected_value )
+ encoded_selected_sample_ids = self.__get_encoded_selected_sample_ids( trans, request, **kwd )
+ sample_operation = params.get( 'sample_operation', 'none' )
+ sample_operation_select_field = self.__build_sample_operation_select_field( trans, is_admin, request, sample_operation )
sample_copy = self.__build_copy_sample_select_field( trans, current_samples )
- return trans.fill_template( '/requests/common/manage_request.mako',
+ return trans.fill_template( '/requests/common/edit_samples.mako',
cntrller=cntrller,
request=request,
- selected_samples=selected_samples,
+ encoded_selected_sample_ids=encoded_selected_sample_ids,
request_widgets=request_widgets,
current_samples=current_samples,
sample_operation_select_field=sample_operation_select_field,
sample_copy=sample_copy,
- managing_samples=managing_samples,
+ editing_samples=False,
message=message,
status=status )
- def __get_sample_info( self, trans, request, **kwd ):
- """
- Retrieves all user entered sample information and returns a
- list of all the samples and their field values.
- """
- params = util.Params( kwd )
- managing_samples = util.string_as_bool( params.get( 'managing_samples', False ) )
- # Bet all data libraries accessible to this user
- libraries = request.user.accessible_libraries( trans, [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ] )
- # Build the list of widgets which will be used to render each sample row on the request page
- current_samples = []
- for index, sample in enumerate( request.samples ):
- library_select_field, folder_select_field = self.__build_library_and_folder_select_fields( trans,
- request.user,
- index,
- libraries,
- sample,
- **kwd )
- current_samples.append( dict( name=sample.name,
- barcode=sample.bar_code,
- library=sample.library,
- folder=sample.folder,
- field_values=sample.values.content,
- library_select_field=library_select_field,
- folder_select_field=folder_select_field ) )
- if not managing_samples:
- sample_index = len( request.samples )
- else:
- sample_index = 0
- while True:
- library_id = params.get( 'sample_%i_library_id' % sample_index, None )
- folder_id = params.get( 'sample_%i_folder_id' % sample_index, None )
- if params.get( 'sample_%i_name' % sample_index, False ):
- # Data library
- try:
- library = trans.sa_session.query( trans.model.Library ).get( trans.security.decode_id( library_id ) )
- #library_id = library.id
- except:
- library = None
- if library is not None:
- # Folder
- try:
- folder = trans.sa_session.query( trans.model.LibraryFolder ).get( trans.security.decode_id( folder_id ) )
- #folder_id = folder.id
- except:
- if library:
- folder = library.root_folder
- else:
- folder = None
- else:
- folder = None
- sample_info = dict( name=util.restore_text( params.get( 'sample_%i_name' % sample_index, '' ) ),
- barcode=util.restore_text( params.get( 'sample_%i_barcode' % sample_index, '' ) ),
- library=library,
- folder=folder)
- sample_info[ 'field_values' ] = []
- for field_index in range( len( request.type.sample_form.fields ) ):
- sample_info[ 'field_values' ].append( util.restore_text( params.get( 'sample_%i_field_%i' % ( sample_index, field_index ), '' ) ) )
- if not managing_samples:
- sample_info[ 'library_select_field' ], sample_info[ 'folder_select_field' ] = self.__build_library_and_folder_select_fields( trans,
- request.user,
- sample_index,
- libraries,
- None,
- library_id,
- folder_id,
- **kwd )
- current_samples.append( sample_info )
- else:
- sample_info[ 'library_select_field' ], sample_info[ 'folder_select_field' ] = self.__build_library_and_folder_select_fields( trans,
- request.user,
- sample_index,
- libraries,
- request.samples[ sample_index ],
- **kwd )
- current_samples[ sample_index ] = sample_info
- sample_index += 1
- else:
- break
- return current_samples, managing_samples, libraries
@web.expose
@web.require_login( "delete sample from sequencing request" )
def delete_sample( self, trans, cntrller, **kwd ):
@@ -1032,7 +867,7 @@ class RequestsCommon( BaseController, Us
request = trans.sa_session.query( trans.model.Request ).get( trans.security.decode_id( request_id ) )
except:
return invalid_id_redirect( trans, cntrller, request_id )
- current_samples, managing_samples, libraries = self.__get_sample_info( trans, request, **kwd )
+ current_samples = self.__get_sample_widgets( trans, request, request.samples, **kwd )
sample_index = int( params.get( 'sample_id', 0 ) )
sample_name = current_samples[sample_index]['name']
sample = request.has_sample( sample_name )
@@ -1042,9 +877,10 @@ class RequestsCommon( BaseController, Us
trans.sa_session.flush()
message = 'Sample (%s) has been deleted.' % sample_name
return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
+ action='edit_samples',
cntrller=cntrller,
id=trans.security.encode_id( request.id ),
+ editing_samples=True,
status=status,
message=message ) )
@web.expose
@@ -1059,12 +895,12 @@ class RequestsCommon( BaseController, Us
sample = trans.sa_session.query( trans.model.Sample ).get( trans.security.decode_id( sample_id ) )
except:
return invalid_id_redirect( trans, cntrller, sample_id )
- # check if a library and folder has been set for this sample yet.
+ # See if a library and folder have been set for this sample.
if not sample.library or not sample.folder:
status = 'error'
message = "Set a data library and folder for sequencing request (%s) to transfer datasets." % sample.name
return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
+ action='edit_samples',
cntrller=cntrller,
id=trans.security.encode_id( sample.request.id ),
status=status,
@@ -1101,7 +937,6 @@ class RequestsCommon( BaseController, Us
SampleName,DataLibrary,DataLibraryFolder,Field1,Field2....
"""
params = util.Params( kwd )
- managing_samples = util.string_as_bool( params.get( 'managing_samples', False ) )
file_obj = params.get( 'file_data', '' )
try:
reader = csv.reader( file_obj.file )
@@ -1137,23 +972,211 @@ class RequestsCommon( BaseController, Us
folder_select_field=folder_select_field,
field_values=row[3:] ) )
except Exception, e:
- status = 'error'
- message = 'Error thrown when importing samples file: %s' % str( e )
+ if str( e ) == "'unicode' object has no attribute 'file'":
+ message = "Select a file"
+ else:
+ message = 'Error attempting to create samples from selected file: %s.' % str( e )
+ message += ' Make sure the selected csv file uses the format: SampleName,DataLibrary,DataLibraryFolder,FieldValue1,FieldValue2...'
return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='manage_request',
+ action='add_sample',
cntrller=cntrller,
- id=trans.security.encode_id( request.id ),
- status=status,
+ request_id=trans.security.encode_id( request.id ),
+ add_sample_button='Add sample',
+ status='error',
message=message ) )
request_widgets = self.__get_request_widgets( trans, request.id )
sample_copy = self.__build_copy_sample_select_field( trans, current_samples )
- return trans.fill_template( '/requests/common/manage_request.mako',
+ return trans.fill_template( '/requests/common/edit_samples.mako',
cntrller=cntrller,
request=request,
request_widgets=request_widgets,
current_samples=current_samples,
sample_copy=sample_copy,
- managing_samples=managing_samples )
+ editing_samples=False )
+ def __save_samples( self, trans, cntrller, request, samples, **kwd ):
+ # Here we handle saving all new samples added by the user as well as saving
+ # changes to any subset of the request's samples.
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ editing_samples = util.string_as_bool( params.get( 'editing_samples', False ) )
+ is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
+ sample_operation = params.get( 'sample_operation', 'none' )
+ # Check for duplicate sample names within the request
+ self.__validate_sample_names( trans, cntrller, request, samples, **kwd )
+ if editing_samples:
+ library = None
+ folder = None
+ def handle_error( **kwd ):
+ kwd[ 'status' ] = 'error'
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ action='edit_samples',
+ cntrller=cntrller,
+ **kwd ) )
+ # Here we handle saving changes to single samples as well as saving changes to
+ # selected sets of samples. If samples are selected, the sample_operation param
+ # will have a value other than 'none', and the samples param will be a list of
+ # encoded sample ids. There are currently only 2 multi-select operations;
+ # 'Change state' and 'Select data library and folder'. If sample_operation is
+ # 'none, then the samples param will be a list of sample objects.
+ if sample_operation == 'Change state':
+ sample_state_id = params.get( 'sample_state_id', None )
+ if sample_state_id in [ None, 'none' ]:
+ message = "Select a new state from the <b>Change current state</b> list before clicking the <b>Save</b> button."
+ kwd[ 'message' ] = message
+ del kwd[ 'save_changes_button' ]
+ handle_error( **kwd )
+ sample_event_comment = util.restore_text( params.get( 'sample_event_comment', '' ) )
+ new_state = trans.sa_session.query( trans.model.SampleState ).get( trans.security.decode_id( sample_state_id ) )
+ # Send the encoded sample_ids to update_sample_state.
+ # TODO: make changes necessary to just send the samples...
+ encoded_selected_sample_ids = self.__get_encoded_selected_sample_ids( trans, request, **kwd )
+ # Make sure all samples have a unique barcode if the state is changing
+ for sample_index in range( len( samples ) ):
+ current_sample = samples[ sample_index ]
+ if current_sample is None:
+ # We have a None value because the user did not select this sample
+ # on which to perform the action.
+ continue
+ request_sample = request.samples[ sample_index ]
+ bc_message = self.__validate_barcode( trans, request_sample, current_sample[ 'barcode' ] )
+ if bc_message:
+ #status = 'error'
+ message += bc_message
+ kwd[ 'message' ] = message
+ del kwd[ 'save_samples_button' ]
+ handle_error( **kwd )
+ self.update_sample_state( trans, cntrller, encoded_selected_sample_ids, new_state, comment=sample_event_comment )
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller=cntrller,
+ action='update_request_state',
+ request_id=trans.security.encode_id( request.id ) ) )
+ elif sample_operation == 'Select data library and folder':
+ library_id = params.get( 'sample_0_library_id', 'none' )
+ folder_id = params.get( 'sample_0_folder_id', 'none' )
+ library, folder = self.__get_library_and_folder( trans, library_id, folder_id )
+ self.__update_samples( trans, request, samples, **kwd )
+ # See if all the samples' barcodes are in the same state,
+ # and if so send email if configured to.
+ common_state = request.samples_have_common_state
+ if common_state and common_state.id == request.type.states[1].id:
+ event = trans.model.RequestEvent( request,
+ request.states.SUBMITTED,
+ "All samples are in %s state." % common_state.name )
+ trans.sa_session.add( event )
+ trans.sa_session.flush()
+ request.send_email_notification( trans, request.type.states[1] )
+ message = 'Changes made to the samples have been saved. '
+ else:
+ # Saving a newly created sample.
+ for index in range( len( samples ) - len( request.samples ) ):
+ sample_index = len( request.samples )
+ current_sample = samples[ sample_index ]
+ form_values = trans.model.FormValues( request.type.sample_form, current_sample[ 'field_values' ] )
+ trans.sa_session.add( form_values )
+ trans.sa_session.flush()
+ s = trans.model.Sample( current_sample[ 'name' ],
+ '',
+ request,
+ form_values,
+ current_sample[ 'barcode' ],
+ current_sample[ 'library' ],
+ current_sample[ 'folder' ] )
+ trans.sa_session.add( s )
+ trans.sa_session.flush()
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ action='edit_samples',
+ cntrller=cntrller,
+ id=trans.security.encode_id( request.id ),
+ editing_samples=editing_samples,
+ status=status,
+ message=message ) )
+ def __update_samples( self, trans, request, sample_widgets, **kwd ):
+ # Determine if the values in kwd require updating the request's samples. The list of
+ # sample_widgets must have the same number of objects as request.samples, but some of
+ # the objects can be None. Those that are not None correspond to samples selected by
+ # the user for performing an action on multiple samples simultaneously.
+ def handle_error( **kwd ):
+ kwd[ 'status' ] = 'error'
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ action='edit_samples',
+ cntrller=cntrller,
+ **kwd ) )
+ params = util.Params( kwd )
+ sample_operation = params.get( 'sample_operation', 'none' )
+ if sample_operation != 'none':
+ # These values will be in kwd if the user checked 1 or more checkboxes for performing this action
+ # on a set of samples.
+ library_id = params.get( 'sample_0_library_id', 'none' )
+ folder_id = params.get( 'sample_0_folder_id', 'none' )
+ for index, obj in enumerate( sample_widgets ):
+ if obj is not None:
+ # obj will be None if the user checked sample check boxes and selected an action
+ # to perform on multiple samples, but did not select certain samples.
+ sample_updated = False
+ # If this sample has values in kwd, then kwd will include a
+ # key whose value is this sample's ( possibly changed ) name. An
+ # example of this key is 'sample_0_name'.
+ for k, v in kwd.items():
+ name_key = 'sample_%i_name' % index
+ if k == name_key:
+ sample_updated = True
+ break
+ if sample_updated:
+ id_index = index + 1
+ if sample_operation == 'none':
+ # We are handling changes to a single sample.
+ library_id = params.get( 'sample_%i_library_id' % id_index, 'none' )
+ folder_id = params.get( 'sample_%i_folder_id' % id_index, 'none' )
+ # Update the corresponding sample's values as well as the sample_widget.
+ sample = request.samples[ index ]
+ sample.name = util.restore_text( params.get( 'sample_%i_name' % index, '' ) )
+ # The bar_code field requires special handling because after a request is submitted, the
+ # state of a sample cannot be changed without a bar_code assocaited with the sample.
+ bar_code = util.restore_text( params.get( 'sample_%i_barcode' % index, '' ) )
+ if not bar_code and not sample.bar_code:
+ # If this is a 'new' (still in its first state) sample, create an event
+ if sample.state.id == request.states[0].id:
+ event = trans.model.SampleEvent( sample,
+ request.type.states[1],
+ 'Sample added to the system' )
+ trans.sa_session.add( event )
+ trans.sa_session.flush()
+ elif bar_code:
+ bc_message = self.__validate_barcode( trans, sample, bar_code )
+ if bc_message:
+ kwd[ 'message' ] = bc_message
+ del kwd[ 'save_samples_button' ]
+ handle_error( **kwd )
+ sample.bar_code = bar_code
+ library, folder = self.__get_library_and_folder( trans, library_id, folder_id )
+ sample.library = library
+ sample.folder = folder
+ field_values = []
+ for field_index in range( len( request.type.sample_form.fields ) ):
+ field_values.append( util.restore_text( params.get( 'sample_%i_field_%i' % ( index, field_index ), '' ) ) )
+ form_values = trans.sa_session.query( trans.model.FormValues ).get( sample.values.id )
+ form_values.content = field_values
+ trans.sa_session.add_all( ( sample, form_values ) )
+ trans.sa_session.flush()
+ def __get_library_and_folder( self, trans, library_id, folder_id ):
+ try:
+ library = trans.sa_session.query( trans.model.Library ).get( trans.security.decode_id( library_id ) )
+ except:
+ library = None
+ if library and folder_id == 'none':
+ folder = library.root_folder
+ elif library and folder_id != 'none':
+ try:
+ folder = trans.sa_session.query( trans.model.LibraryFolder ).get( trans.security.decode_id( folder_id ) )
+ except:
+ if library:
+ folder = library.root_folder
+ else:
+ folder = None
+ else:
+ folder = None
+ return library, folder
# ===== Methods for handling form definition widgets =====
def __get_request_widgets( self, trans, id ):
"""Get the widgets for the request"""
@@ -1179,27 +1202,104 @@ class RequestsCommon( BaseController, Us
value=request.values.content[ index ],
helptext=field[ 'helptext' ] + ' (' + required_label + ')' ) )
return request_widgets
- def __get_samples_widgets( self, trans, request, libraries, **kwd ):
- """Get the widgets for all of the samples currently associated with the request"""
- # The current_samples_widgets list is a list of dictionaries
- current_samples_widgets = []
- for index, sample in enumerate( request.samples ):
- # Build the library_select_field and folder_select_field for each existing sample
- library_select_field, folder_select_field = self.__build_library_and_folder_select_fields( trans,
+ def __get_sample_widgets( self, trans, request, samples, **kwd ):
+ """
+ Returns a list of dictionaries, each representing the widgets that define a sample on a form.
+ The widgets are populated from kwd based on the set of samples received. The set of samples
+ corresponds to a reques.samples list, but if the user checked specific check boxes on the form,
+ those samples that were not check will have None objects in the list of samples. In this case,
+ the corresponding sample_widget is populated from the db rather than kwd.
+ """
+ params = util.Params( kwd )
+ sample_operation = params.get( 'sample_operation', 'none' )
+ # This method is called when the user is adding new samples as well as
+ # editing existing samples, so we use the editing_samples flag to keep
+ # track of what's occurring.
+ editing_samples = util.string_as_bool( params.get( 'editing_samples', False ) )
+ sample_widgets = []
+ if sample_operation != 'none':
+ # The sample_operatin param has a value other than 'none', and a specified
+ # set of samples was received.
+ library_id = util.restore_text( params.get( 'sample_0_library_id', 'none' ) )
+ folder_id = util.restore_text( params.get( 'sample_0_folder_id', 'none' ) )
+ # Build the list of widgets which will be used to render each sample row on the request page
+ if not request:
+ return sample_widgets
+ # Get the list of libraries for which the current user has permission to add items.
+ libraries = request.user.accessible_libraries( trans, [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ] )
+ # Build the list if sample widgets, populating the values from kwd.
+ for index, sample in enumerate( samples ):
+ id_index = index + 1
+ if sample is None:
+ # Id sample is None, then we'll use the sample from the request object since it will
+ # not have updated =values from kwd.
+ sample = request.samples[ index ]
+ name = sample.name
+ bar_code = sample.bar_code
+ library = sample.library
+ folder = sample.folder
+ field_values = sample.values.content,
+ else:
+ # Update the sample attributes from kwd
+ name = util.restore_text( params.get( 'sample_%i_name' % index, sample.name ) )
+ bar_code = util.restore_text( params.get( 'sample_%i_barcode' % index, sample.bar_code ) )
+ library_id = util.restore_text( params.get( 'sample_%i_library_id' % id_index, '' ) )
+ if not library_id and sample.library:
+ library_id = trans.security.encode_id( sample.library.id )
+ folder_id = util.restore_text( params.get( 'sample_%i_folder_id' % id_index, '' ) )
+ if not folder_id and sample.folder:
+ folder_id = trans.security.encode_id( sample.folder.id )
+ library, folder = self.__get_library_and_folder( trans, library_id, folder_id )
+ field_values = []
+ for field_index in range( len( request.type.sample_form.fields ) ):
+ field_values.append( util.restore_text( params.get( 'sample_%i_field_%i' % ( index, field_index ), '' ) ) )
+ library_select_field, folder_select_field = self.__build_library_and_folder_select_fields( trans=trans,
user=request.user,
- sample_index=index,
+ sample_index=id_index,
libraries=libraries,
sample=sample,
+ library_id=library_id,
+ folder_id=folder_id,
**kwd )
- # Append the dictionary for the current sample to the current_samples_widgets list
- current_samples_widgets.append( dict( name=sample.name,
- barcode=sample.bar_code,
- library=sample.library,
- folder=sample.folder,
- field_values=sample.values.content,
- library_select_field=library_select_field,
- folder_select_field=folder_select_field ) )
- return current_samples_widgets
+ sample_widgets.append( dict( name=name,
+ barcode=bar_code,
+ library=library,
+ folder=folder,
+ field_values=field_values,
+ library_select_field=library_select_field,
+ folder_select_field=folder_select_field ) )
+ # There may be additional new samples on the form that have not yet been associated with the request.
+ # TODO: factor this code so it is not duplicating what's above.
+ index = len( samples )
+ while True:
+ name = util.restore_text( params.get( 'sample_%i_name' % index, '' ) )
+ if not name:
+ break
+ id_index = index + 1
+ bar_code = util.restore_text( params.get( 'sample_%i_barcode' % index, '' ) )
+ library_id = util.restore_text( params.get( 'sample_%i_library_id' % id_index, '' ) )
+ folder_id = util.restore_text( params.get( 'sample_%i_folder_id' % id_index, '' ) )
+ library, folder = self.__get_library_and_folder( trans, library_id, folder_id )
+ field_values = []
+ for field_index in range( len( request.type.sample_form.fields ) ):
+ field_values.append( util.restore_text( params.get( 'sample_%i_field_%i' % ( index, field_index ), '' ) ) )
+ library_select_field, folder_select_field = self.__build_library_and_folder_select_fields( trans=trans,
+ user=request.user,
+ sample_index=id_index,
+ libraries=libraries,
+ sample=None,
+ library_id=library_id,
+ folder_id=folder_id,
+ **kwd )
+ sample_widgets.append( dict( name=name,
+ barcode=bar_code,
+ library=library,
+ folder=folder,
+ field_values=field_values,
+ library_select_field=library_select_field,
+ folder_select_field=folder_select_field ) )
+ index += 1
+ return sample_widgets
# ===== Methods for building SelectFields used on various request forms =====
def __build_copy_sample_select_field( self, trans, current_samples ):
copy_sample_index_select_field = SelectField( 'copy_sample_index' )
@@ -1240,26 +1340,30 @@ class RequestsCommon( BaseController, Us
# The libraries dictionary looks like: { library : '1,2' }, library : '3' }. Its keys are the libraries that
# should be displayed for the current user and its values are strings of comma-separated folder ids that should
# NOT be displayed.
- #
- # TODO: all object ids received in the params must be encoded.
params = util.Params( kwd )
library_select_field_name= "sample_%i_library_id" % sample_index
folder_select_field_name = "sample_%i_folder_id" % sample_index
if not library_id:
- library_id = params.get( library_select_field_name, 'none' )
+ library_id = params.get( library_select_field_name, None )
+ if not folder_id:
+ folder_id = params.get( folder_select_field_name, None )
selected_library = None
selected_hidden_folder_ids = []
showable_folders = []
- if sample and sample.library and library_id == 'none':
- library_id = str( sample.library.id )
+ if library_id not in [ None, 'none' ]:
+ # If we have a selected library, get the list of it's folders that are not accessible to the current user
+ for library, hidden_folder_ids in libraries.items():
+ encoded_id = trans.security.encode_id( library.id )
+ if encoded_id == str( library_id ):
+ selected_library = library
+ selected_hidden_folder_ids = hidden_folder_ids.split( ',' )
+ break
+ elif sample and sample.library and library_id == 'none':
+ # The user previously selected a library but is now resetting the selection to 'none'
+ selected_library = None
+ elif sample and sample.library:
+ library_id = trans.security.encode_id( sample.library.id )
selected_library = sample.library
- # If we have a selected library, get the list of it's folders that are not accessible to the current user
- for library, hidden_folder_ids in libraries.items():
- encoded_id = trans.security.encode_id( library.id )
- if encoded_id == str( library_id ):
- selected_library = library
- selected_hidden_folder_ids = hidden_folder_ids.split( ',' )
- break
# sample_%i_library_id SelectField with refresh on change enabled
library_select_field = build_select_field( trans,
libraries.keys(),
@@ -1275,20 +1379,12 @@ class RequestsCommon( BaseController, Us
selected_library,
[ trans.app.security_agent.permitted_actions.LIBRARY_ADD ],
selected_hidden_folder_ids )
- if sample:
- # The user is editing the request, and may have previously selected a folder
- if sample.folder:
- selected_folder_id = sample.folder.id
+ if folder_id:
+ selected_folder_id = folder_id
+ elif sample and sample.folder:
+ selected_folder_id = trans.security.encode_id( sample.folder.id )
else:
- # If a library is selected but not a folder, use the library's root folder
- if sample.library:
- selected_folder_id = sample.library.root_folder.id
- else:
- # The user just selected a folder
- selected_folder_id = params.get( folder_select_field_name, 'none' )
- elif folder_id:
- # TODO: not sure when this would be passed
- selected_folder_id = folder_id
+ selected_folder_id = trans.security.encode_id( selected_library.root_folder.id )
else:
selected_folder_id = 'none'
# TODO: Change the name of the library root folder to "Library root" to clarify to the
@@ -1328,9 +1424,35 @@ class RequestsCommon( BaseController, Us
message += '<b>' + ef + '</b> '
return message
return None
+ def __validate_sample_names( self, trans, cntrller, request, current_samples, **kwd ):
+ # Check for duplicate sample names for all samples of the request.
+ editing_samples = util.string_as_bool( kwd.get( 'editing_samples', False ) )
+ message = ''
+ for index in range( len( current_samples ) - len( request.samples ) ):
+ sample_index = index + len( request.samples )
+ current_sample = current_samples[ sample_index ]
+ sample_name = current_sample[ 'name' ]
+ if not sample_name.strip():
+ message = 'Enter the name of sample number %i' % sample_index
+ break
+ count = 0
+ for i in range( len( current_samples ) ):
+ if sample_name == current_samples[ i ][ 'name' ]:
+ count += 1
+ if count > 1:
+ message = "You tried to add %i samples with the name (%s). Samples belonging to a request must have unique names." % ( count, sample_name )
+ break
+ if message:
+ del kwd[ 'save_samples_button' ]
+ kwd[ 'message' ] = message
+ kwd[ 'status' ] = 'error'
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ action='edit_samples',
+ cntrller=cntrller,
+ **kwd ) )
def __validate_barcode( self, trans, sample, barcode ):
"""
- Makes sure that the barcode about to be assigned to a sample is gobally unique.
+ Makes sure that the barcode about to be assigned to a sample is globally unique.
That is, barcodes must be unique across requests in Galaxy sample tracking.
"""
message = ''
@@ -1338,13 +1460,18 @@ class RequestsCommon( BaseController, Us
for index in range( len( sample.request.samples ) ):
# Check for empty bar code
if not barcode.strip():
- message = 'Fill in the barcode for sample (%s).' % sample.name
- break
+ if sample.state.id == sample.request.type.states[0].id:
+ # The user has not yet filled in the barcode value, but the sample is
+ # 'new', so all is well.
+ break
+ else:
+ message = "Fill in the barcode for sample (%s) before changing it's state." % sample.name
+ break
# TODO: Add a unique constraint to sample.bar_code table column
# Make sure bar code is unique
- for sample_has_bar_code in trans.sa_session.query( trans.model.Sample ) \
- .filter( trans.model.Sample.table.c.bar_code == barcode ):
- if sample_has_bar_code and sample_has_bar_code.id != sample.id:
+ for sample_with_barcode in trans.sa_session.query( trans.model.Sample ) \
+ .filter( trans.model.Sample.table.c.bar_code == barcode ):
+ if sample_with_barcode and sample_with_barcode.id != sample.id:
message = '''The bar code (%s) associated with the sample (%s) belongs to another sample.
Bar codes must be unique across all samples, so use a different bar code
for this sample.''' % ( barcode, sample.name )
@@ -1360,15 +1487,15 @@ class RequestsCommon( BaseController, Us
elif len( email ) > 255:
error = "(%s) exceeds maximum allowable length. " % str( email )
return error
- # ===== Other miscellaneoud utility methods =====
- def __get_selected_samples( self, trans, request, **kwd ):
- selected_samples = []
+ # ===== Other miscellaneous utility methods =====
+ def __get_encoded_selected_sample_ids( self, trans, request, **kwd ):
+ encoded_selected_sample_ids = []
for sample in request.samples:
if CheckboxField.is_checked( kwd.get( 'select_sample_%i' % sample.id, '' ) ):
- selected_samples.append( trans.security.encode_id( sample.id ) )
- return selected_samples
+ encoded_selected_sample_ids.append( trans.security.encode_id( sample.id ) )
+ return encoded_selected_sample_ids
-# ===== Miscellaneoud utility methods outside of the RequestsCommon class =====
+# ===== Miscellaneous utility methods outside of the RequestsCommon class =====
def invalid_id_redirect( trans, cntrller, obj_id, action='browse_requests' ):
status = 'error'
message = "Invalid request id (%s)" % str( obj_id )
--- a/templates/requests/common/dataset_transfer.mako
+++ b/templates/requests/common/dataset_transfer.mako
@@ -1,47 +1,46 @@
<%inherit file="/base.mako"/><%namespace file="/message.mako" import="render_msg" />
+<br/><br/>
+
+<ul class="manage-table-actions">
+ <li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_dataset_transfer', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">Refresh</a></li>
+ <li><a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller=cntrller, id=trans.security.encode_id( sample.library.id ) )}">Target Data Library</a></li>
+ <li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( sample.request.id ) )}">Browse this request</a></li>
+</ul>
+
%if message:
${render_msg( message, status )}
%endif
-<h2>Datasets of Sample "${sample.name}"</h2>
-
-<ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_common', action='view_dataset_transfer', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">Refresh</a>
- </li>
- <li>
- <a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller=cntrller, id=trans.security.encode_id( sample.library.id ) )}">${sample.library.name} Data Library</a>
- </li>
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_common', action='manage_request', cntrller=cntrller, id=trans.security.encode_id( sample.request.id ) )}">Browse this request</a>
- </li>
-</ul>
-
-%if dataset_files:
- <div class="form-row">
- <table class="grid">
- <thead>
- <tr>
- <th>Name</th>
- <th>Size</th>
- <th>Status</th>
- </tr>
- <thead>
- <tbody>
- %for dataset_file in dataset_files:
- <tr>
- <td>${dataset_file.name}</td>
- <td>${dataset_file.size}</td>
- <td>${dataset_file.status}</td>
- </tr>
- %endfor
- </tbody>
- </table>
+<div class="toolForm">
+ <div class="toolFormTitle">Sample "${sample.name}"</div>
+ <div class="toolFormBody">
+ %if dataset_files:
+ <div class="form-row">
+ <table class="grid">
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Size</th>
+ <th>Status</th>
+ </tr>
+ <thead>
+ <tbody>
+ %for dataset_file in dataset_files:
+ <tr>
+ <td>${dataset_file.name}</td>
+ <td>${dataset_file.size}</td>
+ <td>${dataset_file.status}</td>
+ </tr>
+ %endfor
+ </tbody>
+ </table>
+ </div>
+ %else:
+ <div class="form-row">
+ There are no datasets associated with this sample.
+ </div>
+ %endif
</div>
-%else:
- <div class="form-row">
- There are no datasets associated with this sample.
- </div>
-%endif
+</div>
--- a/templates/requests/common/manage_request.mako
+++ /dev/null
@@ -1,615 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-<%namespace file="/requests/common/sample_state.mako" import="render_sample_state" />
-<%namespace file="/requests/common/sample_datasets.mako" import="render_sample_datasets" />
-
-<%def name="stylesheets()">
- ${parent.stylesheets()}
- ${h.css( "library" )}
-</%def>
-
-<%def name="javascripts()">
- ${parent.javascripts()}
- <script type="text/javascript">
- function showContent(vThis)
- {
- // http://www.javascriptjunkie.com
- // alert(vSibling.className + " " + vDef_Key);
- vParent = vThis.parentNode;
- vSibling = vParent.nextSibling;
- while (vSibling.nodeType==3) {
- // Fix for Mozilla/FireFox Empty Space becomes a TextNode or Something
- vSibling = vSibling.nextSibling;
- };
- if(vSibling.style.display == "none")
- {
- vThis.src="/static/images/fugue/toggle.png";
- vThis.alt = "Hide";
- vSibling.style.display = "block";
- } else {
- vSibling.style.display = "none";
- vThis.src="/static/images/fugue/toggle-expand.png";
- vThis.alt = "Show";
- }
- return;
- }
-
- $(document).ready(function(){
- //hide the all of the element with class msg_body
- $(".msg_body").hide();
- //toggle the component with class msg_body
- $(".msg_head").click(function(){
- $(this).next(".msg_body").slideToggle(0);
- });
- });
-
- // Looks for changes in sample states using an async request. Keeps
- // calling itself (via setTimeout) until all samples are in a terminal
- // state.
- var updater = function ( sample_states ) {
- // Check if there are any items left to track
- var empty = true;
- for ( i in sample_states ) {
- empty = false;
- break;
- }
- if ( ! empty ) {
- setTimeout( function() { updater_callback( sample_states ) }, 1000 );
- }
- };
-
- var updater_callback = function ( sample_states ) {
- // Build request data
- var ids = []
- var states = []
- $.each( sample_states, function ( id, state ) {
- ids.push( id );
- states.push( state );
- });
- // Make ajax call
- $.ajax( {
- type: "POST",
- url: "${h.url_for( controller='requests_common', action='sample_state_updates' )}",
- dataType: "json",
- data: { ids: ids.join( "," ), states: states.join( "," ) },
- success : function ( data ) {
- $.each( data, function( id, val ) {
- // Replace HTML
- var cell1 = $("#sampleState-" + id);
- cell1.html( val.html_state );
- var cell2 = $("#sampleDatasets-" + id);
- cell2.html( val.html_datasets );
- sample_states[ parseInt( id ) ] = val.state;
- });
- updater( sample_states );
- },
- error: function() {
- // Just retry, like the old method, should try to be smarter
- updater( sample_states );
- }
- });
- };
-
- function checkAllFields()
- {
- var chkAll = document.getElementById('checkAll');
- var checks = document.getElementsByTagName('input');
- var boxLength = checks.length;
- var allChecked = false;
- var totalChecked = 0;
- if ( chkAll.checked == true )
- {
- for ( i=0; i < boxLength; i++ )
- {
- if ( checks[i].name.indexOf( 'select_sample_' ) != -1)
- {
- checks[i].checked = true;
- }
- }
- }
- else
- {
- for ( i=0; i < boxLength; i++ )
- {
- if ( checks[i].name.indexOf( 'select_sample_' ) != -1)
- {
- checks[i].checked = false
- }
- }
- }
- }
-
- function stopRKey(evt) {
- var evt = (evt) ? evt : ((event) ? event : null);
- var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
- if ((evt.keyCode == 13) && (node.type=="text")) {return false;}
- }
- document.onkeypress = stopRKey
- </script>
-</%def>
-
-<% is_admin = cntrller == 'requests_admin' and trans.user_is_admin() %>
-
-<div class="grid-header">
- <h2>Sequencing Request "${request.name}"</h2>
-
- <ul class="manage-table-actions">
- <li><a class="action-button" id="seqreq-${request.id}-popup" class="menubutton">Sequencing Request Actions</a></li>
- <div popupmenu="seqreq-${request.id}-popup">
- %if request.is_unsubmitted and request.samples:
- <a class="action-button" confirm="More samples cannot be added to this request once it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit</a>
- %endif
- <a class="action-button" href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">History</a>
- %if is_admin:
- %if request.is_submitted:
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject</a>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='get_data', request_id=trans.security.encode_id( request.id ) )}">Select datasets to transfer</a>
- %endif
- %endif
- </div>
- <li><a class="action-button" href="${h.url_for( controller=cntrller, action='browse_requests' )}">Browse requests</a></li>
- </ul>
-
- <div class="toolParamHelp" style="clear: both;">
- <b>Sequencer</b>: ${request.type.name}
- %if is_admin:
- | <b>User</b>: ${request.user.email}
- %endif
- %if request.is_submitted:
- | <b>State</b>: <i>${request.state}</i>
- %else:
- | <b>State</b>: ${request.state}
- %endif
- </div>
-</div>
-
-%if request.samples_without_library_destinations:
- ${render_msg( "Select a target data library and folder for all the samples before starting the sequence run", "warning" )}
-%endif
-
-%if request.is_rejected:
- ${render_msg( "Reason for rejection: " + request.last_comment, "warning" )}
-%endif
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<h4><img src="/static/images/fugue/toggle-expand.png" alt="Show" onclick="showContent(this);" style="cursor:pointer;"/> Request Information</h4>
-<div style="display:none;">
- <div class="form-row">
- <ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit request informaton</a>
- </li>
- </ul>
- </div>
- <table class="grid" border="0">
- <tbody>
- <tr>
- <td valign="top" width="50%">
- <div class="form-row">
- <label>Description:</label>
- ${request.desc}
- </div>
- <div style="clear: both"></div>
- %for index, rd in enumerate( request_widgets ):
- <%
- field_label = rd[ 'label' ]
- field_value = rd[ 'value' ]
- %>
- <div class="form-row">
- <label>${field_label}:</label>
- %if field_label == 'State':
- <a href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">${field_value}</a>
- %else:
- ${field_value}
- %endif
- </div>
- <div style="clear: both"></div>
- %endfor
- </td>
- <td valign="top" width="50%">
- <div class="form-row">
- <label>Date created:</label>
- ${request.create_time}
- </div>
- <div class="form-row">
- <label>Date updated:</label>
- ${request.update_time}
- </div>
- <div class="form-row">
- <label>Email notification recipients:</label>
- <%
- if request.notification:
- emails = ', '.join( request.notification[ 'email' ] )
- else:
- emails = ''
- %>
- ${emails}
- </div>
- <div style="clear: both"></div>
- <div class="form-row">
- <label>Email notification on sample states:</label>
- <%
- if request.notification:
- states = []
- for ss in request.type.states:
- if ss.id in request.notification[ 'sample_states' ]:
- states.append( ss.name )
- states = ', '.join( states )
- else:
- states = ''
- %>
- ${states}
- </div>
- <div style="clear: both"></div>
- </td>
- </tr>
- </tbody>
- </table>
-</div>
-<br/>
-<form id="manage_request" name="manage_request" action="${h.url_for( controller='requests_common', action='manage_request', cntrller=cntrller, id=trans.security.encode_id( request.id ), managing_samples=managing_samples )}" method="post">
- %if current_samples:
- <% sample_operation_selected_value = sample_operation_select_field.get_selected( return_value=True ) %>
- ## first render the basic info grid
- ${render_basic_info_grid()}
- %if not request.is_new and not managing_samples and len( sample_operation_select_field.options ) > 1:
- <div class="form-row" style="background-color:#FAFAFA;">
- For selected samples:
- ${sample_operation_select_field.get_html()}
- </div>
- %if sample_operation_selected_value != 'none' and selected_samples:
- <div class="form-row" style="background-color:#FAFAFA;">
- %if sample_operation_selected_value == trans.model.Sample.bulk_operations.CHANGE_STATE:
- ## sample_operation_selected_value == 'Change state'
- <div class="form-row">
- <label>Change current state</label>
- ${sample_state_id_select_field.get_html()}
- <label>Comments</label>
- <input type="text" name="sample_event_comment" value=""/>
- <div class="toolParamHelp" style="clear: both;">
- Optional
- </div>
- </div>
- <div class="form-row">
- <input type="submit" name="change_state_button" value="Save"/>
- <input type="submit" name="cancel_change_state_button" value="Cancel"/>
- </div>
- %elif sample_operation_selected_value == trans.app.model.Sample.bulk_operations.SELECT_LIBRARY:
- <% libraries_selected_value = libraries_select_field.get_selected( return_value=True ) %>
- <div class="form-row">
- <label>Select data library:</label>
- ${libraries_select_field.get_html()}
- </div>
- %if libraries_selected_value != 'none':
- <div class="form-row">
- <label>Select folder:</label>
- ${folders_select_field.get_html()}
- </div>
- <div class="form-row">
- <input type="submit" name="change_lib_button" value="Save"/>
- <input type="submit" name="cancel_change_lib_button" value="Cancel"/>
- </div>
- %endif
- %endif
- </div>
- %endif
- %endif
- ## Render the other grids
- <% trans.sa_session.refresh( request.type.sample_form ) %>
- %for grid_index, grid_name in enumerate( request.type.sample_form.layout ):
- ${render_grid( grid_index, grid_name, request.type.sample_form.fields_of_grid( grid_index ) )}
- %endfor
- %else:
- <label>There are no samples.</label>
- %endif
- %if request.samples and request.is_submitted:
- <script type="text/javascript">
- // Updater
- updater({${ ",".join( [ '"%s" : "%s"' % ( s.id, s.state.name ) for s in request.samples ] ) }});
- </script>
- %endif
- %if not managing_samples:
- <table class="grid">
- <tbody>
- <tr>
- <div class="form-row">
- %if request.is_unsubmitted:
- <td>
- %if current_samples:
- <label>Copy </label>
- <input type="integer" name="num_sample_to_copy" value="1" size="3"/>
- <label>samples from sample</label>
- ${sample_copy.get_html()}
- %endif
- <input type="submit" name="add_sample_button" value="Add New"/>
- </td>
- %endif
- <td>
- %if current_samples and len( current_samples ) <= len( request.samples ):
- <input type="submit" name="edit_samples_button" value="Edit samples"/>
- %endif
- </td>
- </div>
- </tr>
- </tbody>
- </table>
- %endif
- %if request.samples or current_samples:
- %if managing_samples:
- <div class="form-row">
- <input type="submit" name="save_samples_button" value="Save"/>
- <input type="submit" name="cancel_changes_button" value="Cancel"/>
- </div>
- %elif len( current_samples ) > len( request.samples ):
- <div class="form-row">
- <input type="submit" name="save_samples_button" value="Save"/>
- <input type="submit" name="cancel_changes_button" value="Cancel"/>
- </div>
- %endif
- %endif
-</form>
-<br/>
-%if request.is_unsubmitted:
- <form id="import" name="import" action="${h.url_for( controller='requests_common', action='manage_request', managing_samples=managing_samples, id=trans.security.encode_id( request.id ) )}" enctype="multipart/form-data" method="post" >
- <h4><img src="/static/images/fugue/toggle-expand.png" alt="Show" onclick="showContent(this);" style="cursor:pointer;"/> Import samples</h4>
- <div style="display:none;">
- <input type="file" name="file_data" />
- <input type="submit" name="import_samples_button" value="Import samples"/>
- <br/>
- <div class="toolParamHelp" style="clear: both;">
- The csv file must be in the following format:<br/>
- SampleName,DataLibrary,DataLibraryFolder,FieldValue1,FieldValue2...
- </div>
- </div>
- </form>
-%endif
-
-<%def name="render_grid( grid_index, grid_name, fields_dict )">
- <br/>
- <% if not grid_name:
- grid_name = "Grid "+ grid_index
- %>
- <div>
- %if managing_samples or len( current_samples ) > len( request.samples ):
- <h4><img src="/static/images/fugue/toggle.png" alt="Show" onclick="showContent(this);" style="cursor:pointer;"/> ${grid_name}</h4>
- <div>
- %else:
- <h4><img src="/static/images/fugue/toggle-expand.png" alt="Hide" onclick="showContent(this);" style="cursor:pointer;"/> ${grid_name}</h4>
- <div style="display:none;">
- %endif
- <table class="grid">
- <thead>
- <tr>
- <th>Name</th>
- %for index, field in fields_dict.items():
- <th>
- ${field['label']}
- <div class="toolParamHelp" style="clear: both;">
- <i>${field['helptext']}</i>
- </div>
- </th>
- %endfor
- <th></th>
- </tr>
- <thead>
- <tbody>
- <% trans.sa_session.refresh( request ) %>
- %for sample_index, sample in enumerate( current_samples ):
- %if managing_samples:
- <tr>${render_sample_form( sample_index, sample['name'], sample['field_values'], fields_dict)}</tr>
- %else:
- <tr>
- %if sample_index in range( len( request.samples ) ):
- ${render_sample( sample_index, sample['name'], sample['field_values'], fields_dict )}
- %else:
- ${render_sample_form( sample_index, sample['name'], sample['field_values'], fields_dict)}
- %endif
- </tr>
- %endif
- %endfor
- </tbody>
- </table>
- </div>
- </div>
-</%def>
-
-## This function displays the "Basic Information" grid
-<%def name="render_basic_info_grid()">
- <h3>Sample Information</h3>
- <table class="grid">
- <thead>
- <tr>
- <th><input type="checkbox" id="checkAll" name=select_all_samples_checkbox value="true" onclick='checkAllFields(1);'><input type="hidden" name=select_all_samples_checkbox value="true"></th>
- <th>Name</th>
- <th>Barcode</th>
- <th>State</th>
- <th>Data Library</th>
- <th>Folder</th>
- %if request.is_submitted or request.is_complete:
- <th>Datasets Transferred</th>
- %endif
- <th></th>
- </tr>
- <thead>
- <tbody>
- <% trans.sa_session.refresh( request ) %>
- %for sample_index, info in enumerate( current_samples ):
- <%
- if sample_index in range( len(request.samples ) ):
- sample = request.samples[sample_index]
- else:
- sample = None
- %>
- %if managing_samples:
- <tr>${show_basic_info_form( sample_index, sample, info )}</tr>
- %else:
- <tr>
- %if sample_index in range( len( request.samples ) ):
- %if trans.security.encode_id( sample.id ) in selected_samples:
- <td><input type="checkbox" name=select_sample_${sample.id} id="sample_checkbox" value="true" checked><input type="hidden" name=select_sample_${sample.id} id="sample_checkbox" value="true"></td>
- %else:
- <td><input type="checkbox" name=select_sample_${sample.id} id="sample_checkbox" value="true"><input type="hidden" name=select_sample_${sample.id} id="sample_checkbox" value="true"></td>
- %endif
- <td>${info['name']}</td>
- <td>${info['barcode']}</td>
- %if sample.request.is_unsubmitted:
- <td>Unsubmitted</td>
- %else:
- <td><a id="sampleState-${sample.id}" href="${h.url_for( controller='requests_common', action='sample_events', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${render_sample_state( sample )}</a></td>
- %endif
- %if info['library']:
- %if cntrller == 'requests':
- <td><a href="${h.url_for( controller='library_common', action='browse_library', cntrller='library', id=trans.security.encode_id( info['library'].id ) )}">${info['library'].name}</a></td>
- %elif is_admin:
- <td><a href="${h.url_for( controller='library_common', action='browse_library', cntrller='library_admin', id=trans.security.encode_id( info['library'].id ) )}">${info['library'].name}</a></td>
- %endif
- %else:
- <td></td>
- %endif
- %if info['folder']:
- <td>${info['folder'].name}</td>
- %else:
- <td></td>
- %endif
- %if request.is_submitted or request.is_complete:
- <td><a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_common', action='view_dataset_transfer', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">
- ${render_sample_datasets( sample )}
- </a></td>
- %endif
- %else:
- ${show_basic_info_form( sample_index, sample, info )}
- %endif
- %if request.is_unsubmitted or request.is_rejected:
- <td>
- %if sample:
- %if sample.request.is_unsubmitted:
- <a class="action-button" href="${h.url_for( controller='requests_common', cntrller=cntrller, action='delete_sample', request_id=trans.security.encode_id( request.id ), sample_id=sample_index )}"><img src="${h.url_for('/static/images/delete_icon.png')}" style="cursor:pointer;"/></a>
- %endif
- %endif
- </td>
- %endif
- </tr>
- %endif
- %endfor
- </tbody>
- </table>
-</%def>
-
-<%def name="show_basic_info_form( sample_index, sample, info )">
- <td></td>
- <td>
- <input type="text" name="sample_${sample_index}_name" value="${info['name']}" size="10"/>
- <div class="toolParamHelp" style="clear: both;">
- <i>${' (required)' }</i>
- </div>
- </td>
- %if cntrller == 'requests':
- %if sample:
- %if sample.request.is_unsubmitted:
- <td></td>
- %else:
- <td><input type="text" name="sample_${sample_index}_barcode" value="${info['barcode']}" size="10"/></td>
- %endif
- %else:
- <td></td>
- %endif
- %elif is_admin:
- %if sample:
- %if sample.request.is_unsubmitted:
- <td></td>
- %else:
- <td><input type="text" name="sample_${sample_index}_barcode" value="${info['barcode']}" size="10"/></td>
- %endif
- %else:
- <td></td>
- %endif
- %endif
- %if sample:
- %if sample.request.is_unsubmitted:
- <td>Unsubmitted</td>
- %else:
- <td><a href="${h.url_for( controller='requests_common', action='sample_events', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${sample.state.name}</a></td>
- %endif
- %else:
- <td></td>
- %endif
- <td>${info['library_select_field'].get_html()}</td>
- <td>${info['folder_select_field'].get_html()}</td>
- %if request.is_submitted or request.is_complete:
- <%
- if sample:
- label = str( len( sample.datasets ) )
- else:
- label = 'Add'
- %>
- <td><a href="${h.url_for( controller='requests_common', action='view_dataset_transfer', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${label}</a></td>
- %endif
-</%def>
-
-<%def name="render_sample( index, sample_name, sample_values, fields_dict )">
- <td>
- ${sample_name}
- </td>
- %for field_index, field in fields_dict.items():
- <td>
- %if sample_values[field_index]:
- %if field['type'] == 'WorkflowField':
- %if str(sample_values[field_index]) != 'none':
- <% workflow = trans.sa_session.query( trans.app.model.StoredWorkflow ).get( int(sample_values[field_index]) ) %>
- <a href="${h.url_for( controller='workflow', action='run', id=trans.security.encode_id(workflow.id) )}">${workflow.name}</a>
- %endif
- %else:
- ${sample_values[field_index]}
- %endif
- %else:
- <i>None</i>
- %endif
- </td>
- %endfor
-</%def>
-
-<%def name="render_sample_form( index, sample_name, sample_values, fields_dict )">
- <td>${sample_name}</td>
- %for field_index, field in fields_dict.items():
- <td>
- %if field['type'] == 'TextField':
- <input type="text" name="sample_${index}_field_${field_index}" value="${sample_values[field_index]}" size="7"/>
- %elif field['type'] == 'SelectField':
- <select name="sample_${index}_field_${field_index}" last_selected_value="2">
- %for option_index, option in enumerate(field['selectlist']):
- %if option == sample_values[field_index]:
- <option value="${option}" selected>${option}</option>
- %else:
- <option value="${option}">${option}</option>
- %endif
- %endfor
- </select>
- %elif field['type'] == 'WorkflowField':
- <select name="sample_${index}_field_${field_index}">
- %if str(sample_values[field_index]) == 'none':
- <option value="none" selected>Select one</option>
- %else:
- <option value="none">Select one</option>
- %endif
- %for option_index, option in enumerate(request.user.stored_workflows):
- %if not option.deleted:
- %if str(option.id) == str(sample_values[field_index]):
- <option value="${option.id}" selected>${option.name}</option>
- %else:
- <option value="${option.id}">${option.name}</option>
- %endif
- %endif
- %endfor
- </select>
- %elif field['type'] == 'CheckboxField':
- <input type="checkbox" name="sample_${index}_field_${field_index}" value="Yes"/>
- %endif
- <div class="toolParamHelp" style="clear: both;">
- <i>${'('+field['required']+')' }</i>
- </div>
- </td>
- %endfor
-</%def>
[View Less]
1
0
galaxy-dist commit 9f74170b7781: Fix for multiple hide dataset actions when using workflow outputs.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Dannon Baker <dannonbaker(a)me.com>
# Date 1288377653 14400
# Node ID 9f74170b7781122577b8cf7ffe38f5c986617844
# Parent a2e4d36c4318bc4ce73af9df869ae4071af33d55
Fix for multiple hide dataset actions when using workflow outputs.
--- a/lib/galaxy/web/controllers/workflow.py
+++ b/lib/galaxy/web/controllers/workflow.py
@@ -1299,6 +1299,11 @@ class WorkflowController( …
[View More]BaseController
step_outputs = [s.output_name for s in step.workflow_outputs]
for output in tool.outputs.keys():
if output not in step_outputs:
+ # Necessary, unfortunately, to clean up workflows that might have more than one at this point.
+ for pja in step.post_job_actions:
+ if pja.action_type == "HideDatasetAction" and pja.output_name == output:
+ step.post_job_actions.remove(pja)
+ trans.sa_session.delete(pja)
# Create a PJA for hiding this output.
n_pja = PostJobAction('HideDatasetAction', step, output, {})
else:
[View Less]
1
0
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Dannon Baker <dannonbaker(a)me.com>
# Date 1288377687 14400
# Node ID a22917c97fbe89aa2c0393d30f51d2a2183fd2f8
# Parent 9f74170b7781122577b8cf7ffe38f5c986617844
# Parent cbb895e2b2729d324c1693882de7939360e683a4
Merge.
--- a/test-data/cuffdiff_out5.tracking
+++ /dev/null
@@ -1,2 +0,0 @@
-tracking_id class_code nearest_ref_id gene_short_name tss_id locus q0_FPKM …
[View More]q0_conf_lo q0_conf_hi q1_FPKM q1_conf_lo q1_conf_hi
-TCONS_00000001 c Xkr4 - - chr1:3204754-3204833 0 0 0 67745 0 163551
[View Less]
1
0
galaxy-dist commit 0518ce52d8d3: Allow jobs to be stopped when using track_jobs_in_database/enable_job_running (multiprocess config).
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Nate Coraor <nate(a)bx.psu.edu>
# Date 1288379862 14400
# Node ID 0518ce52d8d3ca15ec6070f2addb4bfe7608c23b
# Parent a22917c97fbe89aa2c0393d30f51d2a2183fd2f8
Allow jobs to be stopped when using track_jobs_in_database/enable_job_running (multiprocess config).
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -813,6 +813,8 @@ class JobStopQueue( …
[View More]object ):
self.sa_session = app.model.context
self.dispatcher = dispatcher
+ self.track_jobs_in_database = app.config.get_bool( 'track_jobs_in_database', False )
+
# Keep track of the pid that started the job manager, only it
# has valid threads
self.parent_pid = os.getpid()
@@ -848,21 +850,29 @@ class JobStopQueue( object ):
Called repeatedly by `monitor` to stop jobs.
"""
# Pull all new jobs from the queue at once
- jobs = []
- try:
- while 1:
- ( job_id, error_msg ) = self.queue.get_nowait()
- if job_id is self.STOP_SIGNAL:
- return
- # Append to watch queue
- jobs.append( ( job_id, error_msg ) )
- except Empty:
- pass
-
- for job_id, error_msg in jobs:
- job = self.sa_session.query( model.Job ).get( job_id )
- self.sa_session.refresh( job )
- # if desired, error the job so we can inform the user.
+ jobs_to_check = []
+ if self.track_jobs_in_database:
+ # Clear the session so we get fresh states for job and all datasets
+ self.sa_session.expunge_all()
+ # Fetch all new jobs
+ newly_deleted_jobs = self.sa_session.query( model.Job ) \
+ .options( lazyload( "external_output_metadata" ), lazyload( "parameters" ) ) \
+ .filter( model.Job.state == model.Job.states.DELETED_NEW ).all()
+ for job in newly_deleted_jobs:
+ jobs_to_check.append( ( job, None ) )
+ else:
+ try:
+ while 1:
+ message = self.queue.get_nowait()
+ if message is self.STOP_SIGNAL:
+ return
+ # Unpack the message
+ job_id, error_msg = message
+ # Get the job object and append to watch queue
+ jobs_to_check.append( ( self.sa_session.query( model.Job ).get( job_id ), error_msg ) )
+ except Empty:
+ pass
+ for job, error_msg in jobs_to_check:
if error_msg is not None:
job.state = job.states.ERROR
job.info = error_msg
@@ -870,9 +880,6 @@ class JobStopQueue( object ):
job.state = job.states.DELETED
self.sa_session.add( job )
self.sa_session.flush()
- # if job is in JobQueue or FooJobRunner's put method,
- # job_runner_name will be unset and the job will be dequeued due to
- # state change above
if job.job_runner_name is not None:
# tell the dispatcher to stop the job
self.dispatcher.stop( job )
@@ -888,7 +895,8 @@ class JobStopQueue( object ):
else:
log.info( "sending stop signal to worker thread" )
self.running = False
- self.queue.put( ( self.STOP_SIGNAL, None ) )
+ if not self.track_jobs_in_database:
+ self.queue.put( self.STOP_SIGNAL )
self.sleeper.wake()
log.info( "job stopper stopped" )
--- a/lib/galaxy/web/controllers/root.py
+++ b/lib/galaxy/web/controllers/root.py
@@ -432,7 +432,8 @@ class RootController( BaseController, Us
if job.state in [ self.app.model.Job.states.QUEUED, self.app.model.Job.states.RUNNING, self.app.model.Job.states.NEW ]:
# Are *all* of the job's other output datasets deleted?
if job.check_if_output_datasets_deleted():
- job.mark_deleted()
+ job.mark_deleted( self.app.config.get_bool( 'enable_job_running', True ),
+ self.app.config.get_bool( 'track_jobs_in_database', False ) )
self.app.job_manager.job_stop_queue.put( job.id )
trans.sa_session.flush()
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -97,7 +97,8 @@ class Job( object ):
RUNNING = 'running',
OK = 'ok',
ERROR = 'error',
- DELETED = 'deleted' )
+ DELETED = 'deleted',
+ DELETED_NEW = 'deleted_new' )
def __init__( self ):
self.session_id = None
self.user_id = None
@@ -152,11 +153,17 @@ class Job( object ):
if not dataset.deleted:
return False
return True
- def mark_deleted( self ):
+ def mark_deleted( self, enable_job_running=True, track_jobs_in_database=False ):
"""
Mark this job as deleted, and mark any output datasets as discarded.
"""
- self.state = Job.states.DELETED
+ # This could be handled with *just* track_jobs_in_database, but I
+ # didn't want to make setting track_jobs_in_database required in
+ # non-runner configs.
+ if not enable_job_running or track_jobs_in_database:
+ self.state = Job.states.DELETED_NEW
+ else:
+ self.state = Job.states.DELETED
self.info = "Job output deleted by user before job completed."
for dataset_assoc in self.output_datasets:
dataset = dataset_assoc.dataset
[View Less]
1
0
galaxy-dist commit 1efe19f6f3d1: Fixes for rerun action to recurse grouping options when checking unvalidated values and cloned HDAs. Better selection of corresponding HDAs from cloned histories, when multiple copies exist.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Daniel Blankenberg <dan(a)bx.psu.edu>
# Date 1288640846 14400
# Node ID 1efe19f6f3d1a75bda9c198633dd8102d3063410
# Parent 2c934a168af968dc84300412220c2f2cb74bf676
Fixes for rerun action to recurse grouping options when checking unvalidated values and cloned HDAs. Better selection of corresponding HDAs from cloned histories, when multiple copies exist.
--- a/lib/…
[View More]galaxy/web/controllers/tool_runner.py
+++ b/lib/galaxy/web/controllers/tool_runner.py
@@ -123,16 +123,6 @@ class ToolRunner( BaseController ):
params_objects = job.get_param_values( trans.app )
except:
raise Exception( "Failed to get paramemeters for dataset id %d " % data.id )
- # Unpack unvalidated values to strings, they'll be validated when the
- # form is submitted (this happens when re-running a job that was
- # initially run by a workflow)
- validated_params = {}
- for name, value in params_objects.items():
- if isinstance( value, UnvalidatedValue ):
- validated_params [ str(name) ] = str(value)
- else:
- validated_params [ str(name) ] = value
- params_objects = validated_params
# Need to remap dataset parameters. Job parameters point to original
# dataset used; parameter should be the analygous dataset in the
# current history.
@@ -141,12 +131,22 @@ class ToolRunner( BaseController ):
for hda in history.datasets:
source_hda = hda.copied_from_history_dataset_association
while source_hda:#should this check library datasets as well?
- hda_source_dict[ source_hda ] = hda
+ #FIXME: could be multiple copies of a hda in a single history, this does a better job of matching on cloned histories,
+ #but is still less than perfect when eg individual datasets are copied between histories
+ if source_hda not in hda_source_dict or source_hda.hid == hda.hid:
+ hda_source_dict[ source_hda ] = hda
source_hda = source_hda.copied_from_history_dataset_association
- for name, value in validated_params.items():
- if isinstance( value, trans.app.model.HistoryDatasetAssociation ):
- if value not in history.datasets:
- validated_params[ name ] = hda_source_dict[ value ]
+ # Unpack unvalidated values to strings, they'll be validated when the
+ # form is submitted (this happens when re-running a job that was
+ # initially run by a workflow)
+ #This needs to be done recursively through grouping parameters
+ def rerun_callback( input, value, prefixed_name, prefixed_label ):
+ if isinstance( value, UnvalidatedValue ):
+ return str( value )
+ if isinstance( input, DataToolParameter ):
+ if value not in history.datasets and value in hda_source_dict:
+ return hda_source_dict[ value ]
+ visit_input_values( tool.inputs, params_objects, rerun_callback )
# Create a fake tool_state for the tool, with the parameters values
state = tool.new_state( trans )
state.inputs = params_objects
[View Less]
1
0
galaxy-dist commit cf7ec71c5613: Shift management of the interaction between workflow outputs and HideDatasetActions to the front end editor.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Dannon Baker <dannonbaker(a)me.com>
# Date 1288645730 14400
# Node ID cf7ec71c561323940ce95c8148d2008508920092
# Parent 1efe19f6f3d1a75bda9c198633dd8102d3063410
Shift management of the interaction between workflow outputs and HideDatasetActions to the front end editor.
This resolves the issue with multiple HideDatasetActions being created.
Existing workflows …
[View More]displaying multiple HideDatasetActions per step on the Run Workflow screen will persist.
These extra HideDatasetActions are harmless, but a simple edit workflow -> save will remove them.
--- a/lib/galaxy/web/controllers/workflow.py
+++ b/lib/galaxy/web/controllers/workflow.py
@@ -1270,13 +1270,6 @@ class WorkflowController( BaseController
workflow_invocation = model.WorkflowInvocation()
workflow_invocation.workflow = workflow
outputs = odict()
- # Find out if there are any workflow outputs defined, as that influences our actions.
- use_workflow_outputs = False
- for step in workflow.steps:
- if step.type == 'tool' or step.type is None:
- if step.workflow_outputs:
- use_workflow_outputs = True
- break
for i, step in enumerate( workflow.steps ):
# Execute module
job = None
@@ -1294,24 +1287,6 @@ class WorkflowController( BaseController
job, out_data = tool.execute( trans, step.state.inputs )
outputs[ step.id ] = out_data
# Create new PJA associations with the created job, to be run on completion.
- if use_workflow_outputs:
- # We're using outputs. Check the step for outputs to be displayed. Create PJAs to hide the rest upon completion.
- step_outputs = [s.output_name for s in step.workflow_outputs]
- for output in tool.outputs.keys():
- if output not in step_outputs:
- # Necessary, unfortunately, to clean up workflows that might have more than one at this point.
- for pja in step.post_job_actions:
- if pja.action_type == "HideDatasetAction" and pja.output_name == output:
- step.post_job_actions.remove(pja)
- trans.sa_session.delete(pja)
- # Create a PJA for hiding this output.
- n_pja = PostJobAction('HideDatasetAction', step, output, {})
- else:
- # Remove any HideDatasetActions, step is flagged for output.
- for pja in step.post_job_actions:
- if pja.action_type == "HideDatasetAction" and pja.output_name == output:
- step.post_job_actions.remove(pja)
- trans.sa_session.delete(pja)
for pja in step.post_job_actions:
if pja.action_type in ActionBox.immediate_actions:
ActionBox.execute(trans.app, trans.sa_session, pja, job)
--- a/static/scripts/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/galaxy.workflow_editor.canvas.js
@@ -475,6 +475,63 @@ function Workflow( canvas_container ) {
wf.remove_node( v );
});
},
+ rectify_workflow_outputs : function() {
+ console.log("RECTIFICATION!");
+ // Find out if we're using workflow_outputs or not.
+ var using_workflow_outputs = false;
+ $.each( this.nodes, function ( k, node ) {
+ if (node.workflow_outputs && node.workflow_outputs.length > 0){
+ using_workflow_outputs = true;
+ }
+ });
+ if (using_workflow_outputs == false){
+ //We're done, leave PJAs alone.
+ return true;
+ }
+ wf = this;
+ $.each(this.nodes, function (k, node ){
+ if (node.type == 'tool'){
+ var node_changed = false;
+ if (node.post_job_actions == null){
+ console.log("CREATED FOR NEW NODE");
+ node.post_job_actions = {};
+ }
+ var pjas_to_rem = [];
+ $.each(node.post_job_actions, function(pja_id, pja){
+ if (pja.action_type == "HideDatasetAction"){
+ pjas_to_rem.push(pja_id);
+ }
+ });
+ if (pjas_to_rem.length > 0 && node == workflow.active_node)
+ $.each(pjas_to_rem, function(i, pja_name){
+ node_changed = true;
+ delete node.post_job_actions[pja_name];
+ })
+ $.each(node.output_terminals, function(ot_id, ot){
+ var create_pja = true;
+ $.each(node.workflow_outputs, function(i, wo_name){
+ if (ot.name == wo_name){
+ create_pja = false;
+ }
+ });
+ if (create_pja == true){
+ node_changed = true;
+ var pja = {
+ action_type : "HideDatasetAction",
+ output_name : ot.name,
+ action_arguments : {}
+ }
+ node.post_job_actions['HideDatasetAction'+ot.name] = null;
+ node.post_job_actions['HideDatasetAction'+ot.name] = pja;
+ }
+ });
+ // lastly, if this is the active node, and we made changes, reload the display at right.
+ if (wf.active_node == node && node_changed == true) {
+ wf.reload_active_node();
+ }
+ }
+ });
+ },
to_simple : function () {
var nodes = {};
$.each( this.nodes, function ( i, node ) {
@@ -491,7 +548,6 @@ function Workflow( canvas_container ) {
if (node.post_job_actions){
$.each( node.post_job_actions, function ( i, act ) {
var pja = {
- job_id : act.id,
action_type : act.action_type,
output_name : act.output_name,
action_arguments : act.action_arguments
@@ -559,6 +615,10 @@ function Workflow( canvas_container ) {
this.active_form_has_changes = false;
}
},
+ reload_active_node : function() {
+ this.clear_active_node();
+ this.activate_node(node);
+ },
clear_active_node : function() {
if ( this.active_node ) {
this.active_node.make_inactive();
--- a/templates/workflow/editor.mako
+++ b/templates/workflow/editor.mako
@@ -627,6 +627,7 @@
}
return;
}
+ workflow.rectify_workflow_outputs();
var savefn = function(callback) {
$.ajax( {
url: "${h.url_for( action='save_workflow' )}",
[View Less]
1
0
galaxy-dist commit cbb895e2b272: If a job's input fails to set metadata, fail the job rather than leaving it in the 'new' state indefinitely.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Nate Coraor <nate(a)bx.psu.edu>
# Date 1288376593 14400
# Node ID cbb895e2b2729d324c1693882de7939360e683a4
# Parent 23844e86e6167c79737a7e0396c39e350e95d1c4
If a job's input fails to set metadata, fail the job rather than leaving it in the 'new' state indefinitely.
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -241,6 +241,9 @@ class JobQueue( …
[View More]object ):
elif idata.state == idata.states.ERROR:
JobWrapper( job, self ).fail( "input data %d is in error state" % ( idata.hid ) )
return JOB_INPUT_ERROR
+ elif idata.state == idata.states.FAILED_METADATA:
+ JobWrapper( job, self ).fail( "input data %d failed to properly set metadata" % ( idata.hid ) )
+ return JOB_INPUT_ERROR
elif idata.state != idata.states.OK and not ( idata.state == idata.states.SETTING_METADATA and job.tool_id is not None and job.tool_id == self.app.datatypes_registry.set_external_metadata_tool.id ):
# need to requeue
return JOB_WAIT
[View Less]
1
0