diff --git a/external_service_types/applied_biosystems_solid.xml b/external_service_types/applied_biosystems_solid.xml index b5ec6cac4da..ca24a84c44b 100644 --- a/external_service_types/applied_biosystems_solid.xml +++ b/external_service_types/applied_biosystems_solid.xml @@ -3,8 +3,7 @@ 3 - + diff --git a/external_service_types/simple_unknown_sequencer.xml b/external_service_types/simple_unknown_sequencer.xml index 816e08b78a0..b7a01c44332 100644 --- a/external_service_types/simple_unknown_sequencer.xml +++ b/external_service_types/simple_unknown_sequencer.xml @@ -7,8 +7,7 @@ This is only for backward compatibility - +
diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index 666686cd72b..b33c2a68748 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -1717,6 +1717,14 @@ class Request( object, APIItem ): if not sample.library: samples.append( sample ) return samples + @property + def samples_with_bar_code( self ): + # Return all samples that have associated bar code + samples = [] + for sample in self.samples: + if sample.bar_code: + samples.append( sample ) + return samples def send_email_notification( self, trans, common_state, final_state=False ): # Check if an email notification is configured to be sent when the samples # are in this state @@ -1804,18 +1812,19 @@ class ExternalService( object ): def get_external_service_type( self, trans ): return trans.app.external_service_types.all_external_service_types[ self.external_service_type_id ] def load_data_transfer_settings( self, trans ): + trans.app.external_service_types.reload( self.external_service_type_id ) self.data_transfer = {} external_service_type = self.get_external_service_type( trans ) - for data_transfer_type, data_transfer in external_service_type.data_transfer.items(): + for data_transfer_type, data_transfer_obj in external_service_type.data_transfer.items(): if data_transfer_type == self.data_transfer_types.SCP: scp_configs = {} - automatic_transfer = self.form_values.content.get( data_transfer.config.get( 'automatic_transfer', 'false' ), 'false' ) + automatic_transfer = self.form_values.content.get( data_transfer_obj.config.get( 'automatic_transfer', 'false' ), 'false' ) scp_configs[ 'automatic_transfer' ] = util.string_as_bool( automatic_transfer ) - scp_configs[ 'host' ] = self.form_values.content.get( data_transfer.config.get( 'host', '' ), '' ) - scp_configs[ 'user_name' ] = self.form_values.content.get( data_transfer.config.get( 'user_name', '' ), '' ) - scp_configs[ 'password' ] = self.form_values.content.get( data_transfer.config.get( 'password', '' ), '' ) - scp_configs[ 'data_location' ] = self.form_values.content.get( data_transfer.config.get( 'data_location', '' ), '' ) - scp_configs[ 'rename_dataset' ] = self.form_values.content.get( data_transfer.config.get( 'rename_dataset', '' ), '' ) + scp_configs[ 'host' ] = self.form_values.content.get( data_transfer_obj.config.get( 'host', '' ), '' ) + scp_configs[ 'user_name' ] = self.form_values.content.get( data_transfer_obj.config.get( 'user_name', '' ), '' ) + scp_configs[ 'password' ] = self.form_values.content.get( data_transfer_obj.config.get( 'password', '' ), '' ) + scp_configs[ 'data_location' ] = self.form_values.content.get( data_transfer_obj.config.get( 'data_location', '' ), '' ) + scp_configs[ 'rename_dataset' ] = self.form_values.content.get( data_transfer_obj.config.get( 'rename_dataset', '' ), '' ) self.data_transfer[ self.data_transfer_types.SCP ] = scp_configs def populate_actions( self, trans, item, param_dict=None ): return self.get_external_service_type( trans ).actions.populate( self, item, param_dict=param_dict ) diff --git a/lib/galaxy/sample_tracking/data_transfer.py b/lib/galaxy/sample_tracking/data_transfer.py index 7691b2d411a..9112fcd36fc 100644 --- a/lib/galaxy/sample_tracking/data_transfer.py +++ b/lib/galaxy/sample_tracking/data_transfer.py @@ -2,7 +2,6 @@ import logging, sys class DataTransferFactory( object ): type = None - config = {} def parse( self ): pass @@ -11,14 +10,20 @@ class ScpDataTransferFactory( DataTransferFactory ): def __init__( self ): pass def parse( self, config_file, elem ): + self.config = {} # TODO: The 'automatic_transfer' setting is for future use. If set to True, we will need to # ensure the sample has an associated destination data library before it moves to a certain state # ( e.g., Run started ). - self.config[ 'automatic_transfer' ] = elem.get( 'automatic_transfer' ) - self.config[ 'host' ] = elem.get( 'host' ) - self.config[ 'user_name' ] = elem.get( 'user_name' ) - self.config[ 'password' ] = elem.get( 'password' ) - self.config[ 'data_location' ] = elem.get( 'data_location' ) + self.config['automatic_transfer'] = elem.get( 'automatic_transfer' ) + self.config['host'] = elem.get( 'host' ) + self.config['user_name'] = elem.get( 'user_name' ) + self.config['password'] = elem.get( 'password' ) + self.config['data_location'] = elem.get( 'data_location' ) + # 'rename_dataset' is optional and it may not be defined in all external types + # It is only used is AB SOLiD external service type for now + rename_dataset = elem.get( 'rename_dataset', None ) + if rename_dataset: + self.config['rename_dataset'] = rename_dataset # Validate for name, value in self.config.items(): assert value, "'%s' attribute missing in 'data_transfer' element of type 'scp' in external_service_type xml config file: '%s'." % ( name, config_file ) diff --git a/lib/galaxy/sample_tracking/external_service_types.py b/lib/galaxy/sample_tracking/external_service_types.py index 66508d1baed..baee06057cf 100644 --- a/lib/galaxy/sample_tracking/external_service_types.py +++ b/lib/galaxy/sample_tracking/external_service_types.py @@ -60,6 +60,7 @@ class ExternalServiceType( object ): self.config_file = external_service_type_xml_config self.parse( root ) self.visible = visible + root.clear() def parse( self, root ): # Get the name self.name = root.get( "name" ) diff --git a/lib/galaxy/web/controllers/requests_admin.py b/lib/galaxy/web/controllers/requests_admin.py index 2f65d5b60b3..5d34460fe93 100644 --- a/lib/galaxy/web/controllers/requests_admin.py +++ b/lib/galaxy/web/controllers/requests_admin.py @@ -387,7 +387,7 @@ class RequestsAdmin( BaseController, UsesFormDefinitions ): kwd[ 'message' ] = message del kwd[ 'select_datasets_to_transfer_button' ] handle_error( **kwd ) - if sample in sample.request.samples_without_library_destinations: + if not sample.library: # Display an error if a sample has been selected that # has not yet been associated with a destination library. message = 'Select a target data library and folder for the sample before selecting the datasets.' @@ -487,6 +487,7 @@ class RequestsAdmin( BaseController, UsesFormDefinitions ): status=status, message=message ) ) def __save_sample_datasets( self, trans, sample, selected_datasets_to_transfer, external_service ): + external_service.load_data_transfer_settings( trans ) scp_configs = external_service.data_transfer[ trans.model.ExternalService.data_transfer_types.SCP ] sample_dataset_file_names = [] if selected_datasets_to_transfer: diff --git a/lib/galaxy/web/controllers/requests_common.py b/lib/galaxy/web/controllers/requests_common.py index e250cfd38f2..a0476c2e539 100644 --- a/lib/galaxy/web/controllers/requests_common.py +++ b/lib/galaxy/web/controllers/requests_common.py @@ -107,12 +107,29 @@ class RequestsCommon( BaseController, UsesFormDefinitions ): sample = trans.sa_session.query( self.app.model.Sample ).get( id ) if sample.state.name != state: rval[ id ] = { "state": sample.state.name, - "datasets": len( sample.datasets ), "html_state": unicode( trans.fill_template( "requests/common/sample_state.mako", sample=sample), 'utf-8' ) } return rval @web.json + def sample_datasets_updates( self, trans, ids=None, datasets=None ): + # Avoid caching + trans.response.headers['Pragma'] = 'no-cache' + trans.response.headers['Expires'] = '0' + # Create new HTML for any that have changed + rval = {} + if ids is not None and datasets is not None: + ids = map( int, ids.split( "," ) ) + number_of_datasets_list = map(int, datasets.split( "," ) ) + for id, number_of_datasets in zip( ids, number_of_datasets_list ): + sample = trans.sa_session.query( self.app.model.Sample ).get( id ) + if len(sample.datasets) != number_of_datasets: + rval[ id ] = { "datasets": len( sample.datasets ), + "html_datasets": unicode( trans.fill_template( "requests/common/sample_datasets.mako", + sample=sample), + 'utf-8' ) } + return rval + @web.json def dataset_transfer_status_updates( self, trans, ids=None, transfer_status_list=None ): # Avoid caching trans.response.headers['Pragma'] = 'no-cache' diff --git a/templates/requests/common/common.mako b/templates/requests/common/common.mako index 0260c23b538..1425f23b3a5 100644 --- a/templates/requests/common/common.mako +++ b/templates/requests/common/common.mako @@ -98,7 +98,7 @@ data: { ids: ids.join( "," ), states: states.join( "," ) }, success : function ( data ) { $.each( data, function( id, val ) { - // Replace HTML + // Replace sample state HTML var cell1 = $("#sampleState-" + id); cell1.html( val.html_state ); sample_states[ parseInt( id ) ] = val.state; @@ -113,6 +113,54 @@ }; + // Sample Datasets Updater + // + // Looks for changes in the number sample datasets using an async request. Keeps + // calling itself (via setTimeout) until all samples are in a terminal + // state. + var sample_datasets_updater = function ( sample_datasets ) { + // Check if there are any items left to track + var empty = true; + for ( i in sample_datasets ) { + empty = false; + break; + } + if ( ! empty ) { + setTimeout( function() { sample_datasets_updater_callback( sample_datasets ) }, 1000 ); + } + }; + var sample_datasets_updater_callback = function ( sample_datasets ) { + // Build request data + var ids = [] + var datasets = [] + $.each( sample_datasets, function ( id, num_of_datasets ) { + ids.push( id ); + datasets.push( num_of_datasets ); + }); + // Make ajax call + $.ajax( { + type: "POST", + url: "${h.url_for( controller='requests_common', action='sample_datasets_updates' )}", + dataType: "json", + data: { ids: ids.join( "," ), datasets: datasets.join( "," ) }, + success : function ( data ) { + $.each( data, function( id, val ) { + // Replace sample datasets HTML + var cell2 = $("#sampleDatasets-" + id); + cell2.html( val.html_datasets ); + sample_datasets[ parseInt( id ) ] = val.datasets; + + }); + sample_datasets_updater( sample_datasets ); + }, + error: function() { + // Just retry, like the old method, should try to be smarter + sample_datasets_updater( sample_datasets ); + } + }); + }; + + // Sample Dataset Transfer Status Updater // // It is used to update the transfer status on Manage Datasets page for a sample @@ -392,7 +440,7 @@ ## An admin can select the datasets to transfer, while a non-admin can only view what has been selected %if is_admin: ## This link will direct the admin to a page allowing them to manage datasets. - ${len( sample.datasets )} + ${len( sample.datasets )} %elif sample.datasets: ## Since this is a regular user, only display a link if there is at least 1 ## selected dataset for the sample. diff --git a/templates/requests/common/sample_datasets.mako b/templates/requests/common/sample_datasets.mako new file mode 100644 index 00000000000..b98dec42eb5 --- /dev/null +++ b/templates/requests/common/sample_datasets.mako @@ -0,0 +1,5 @@ +<%def name="render_sample_datasets( sample )"> + ${len( sample.datasets )} + + +${render_sample_datasets( sample )} diff --git a/templates/requests/common/view_request.mako b/templates/requests/common/view_request.mako index 0d368420f39..75899c067b7 100644 --- a/templates/requests/common/view_request.mako +++ b/templates/requests/common/view_request.mako @@ -144,12 +144,20 @@ ${states}
- %if request.samples and request.is_submitted: + ## Sample state updater + %if request.samples and request.is_submitted and request.samples_with_bar_code: %endif + ## Number of sample state updater + %if request.samples and request.is_submitted: + + %endif