Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
af8d255
added wafer size to ultima requests and pipeline
andrewsparkes Mar 24, 2026
ede2885
adding ug200 request type
andrewsparkes Mar 25, 2026
5ab4f98
change to schema
andrewsparkes Mar 25, 2026
9b57642
Added inflection for UG200
andrewsparkes Mar 25, 2026
2d737b3
added UG200 task descriptors (draft may change)
andrewsparkes Mar 25, 2026
4a746a7
fixed tests
andrewsparkes Mar 25, 2026
16e939c
fixed tests
andrewsparkes Mar 25, 2026
a988ce7
modified ug200 sequencing request to remove read length and add ot re…
andrewsparkes Mar 27, 2026
72a640d
wip the submission template yml
andrewsparkes Mar 27, 2026
7a1a074
Merge branch 'develop' into Y26-085-submission_template-for-ultima-ug…
andrewsparkes Mar 27, 2026
ac9574d
for ug200 changed readlength for ot recipe
andrewsparkes Mar 27, 2026
573135f
fixed incorrect it text
andrewsparkes Mar 27, 2026
5dbd4a9
test(validators): split UG200 checks into dedicated ultima_ug200 vali…
yoldas Apr 7, 2026
e8b64f2
fix(submissions): apply selection defaults for blank values
yoldas Apr 7, 2026
fcbcd9c
docs(remove todo commit about selection defaults)
yoldas Apr 7, 2026
bd33b3a
test(submissions): apply selection defaults for blank values
yoldas Apr 7, 2026
ac0602b
fix(records): correct OTRecipeInformationTypeForUltimaUG200 association
yoldas Apr 7, 2026
7a2d52d
chore(records): rename ultima_ug200 files to wip
yoldas Apr 7, 2026
9e6b11e
fix(records): make task section names unique insider record loader fo…
yoldas Apr 7, 2026
db7c961
fix(records): make descriptor section names unique within the record …
yoldas Apr 7, 2026
42f363d
feat(config): add UG200 specific request types because of purpose dep…
yoldas Apr 7, 2026
9e1df90
feat(config): update request type keys of the Limber-Htp - Ultima PCR…
yoldas Apr 7, 2026
82926a0
style(config): prettier format spacing and indentation
yoldas Apr 7, 2026
83e3f30
feat(config): add UPF2 Cherrypicked purpose required by Limber Ultima…
yoldas Apr 7, 2026
7c27119
feat(config): add ultima ug200 tube purposes
yoldas Apr 7, 2026
3a8b09a
test(ci): fix flaky tests and add missing assertions
yoldas Apr 7, 2026
54ca292
Merge branch 'develop' into Y26-085-submission_template-for-ultima-ug…
yoldas Apr 7, 2026
f8397ad
Update config/default_records/request_types/026_ultima_ug200_request_…
yoldas Apr 9, 2026
e429b98
refactor: remove redundant method and constant from UltimaUG200Validator
yoldas Apr 9, 2026
72bbf8b
Merge branch 'develop' into Y26-085-submission_template-for-ultima-ug…
yoldas Apr 13, 2026
2d2137b
remove UPF2 Balanced Pool and UPF2 Balanced Norm from sequencescape …
yoldas Apr 13, 2026
084c97f
Merge remote-tracking branch 'refs/remotes/origin/Y26-085-submission_…
yoldas Apr 13, 2026
b5e7c9c
add UG200 to the submission template names
yoldas Apr 13, 2026
489243c
Merge branch 'develop' into Y26-085-submission_template-for-ultima-ug…
yoldas Apr 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/helpers/submissions_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ def submission_link(submission, options)
def field_selection_tag(request_options, field_info, name_format, enforce_required)
select_tag(
name_format % field_info.key,
options_for_select(field_info.selection.map(&:to_s), request_options[field_info.key]),
options_for_select(field_info.selection.map(&:to_s),
request_options[field_info.key].presence || field_info.default_value),
class: 'custom-select',
required: enforce_required && field_info.required,
read_only: field_info.selection.size == 1
Expand Down
6 changes: 4 additions & 2 deletions app/models/bulk_submission.rb
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,8 @@ def process # rubocop:todo Metrics/CyclomaticComplexity
'scrna core cells per chip well',
'% phix requested',
'low diversity',
'ot recipe'
'ot recipe',
'wafer size'
].freeze

ALIAS_FIELDS = { 'plate barcode' => 'barcode', 'tube barcode' => 'barcode' }.freeze
Expand Down Expand Up @@ -360,7 +361,8 @@ def extract_request_options(details)
['scrna core cells per chip well', 'cells_per_chip_well'],
['% phix requested', 'percent_phix_requested'],
['low diversity', 'low_diversity'],
['ot recipe', 'ot_recipe']
['ot recipe', 'ot_recipe'],
['wafer size', 'wafer_size']
].each do |source_key, target_key|
assign_value_if_source_present(details, source_key, request_options, target_key)
end
Expand Down
2 changes: 1 addition & 1 deletion app/models/ultima_sequencing_pipeline.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

# Specialized sequencing pipeline for Ultima
# Specialized sequencing pipeline for Ultima UG100
class UltimaSequencingPipeline < SequencingPipeline
def ot_recipe_consistent_for_batch?(batch)
ot_recipe_list = batch.requests.filter_map { |request| request.request_metadata.ot_recipe }
Expand Down
13 changes: 13 additions & 0 deletions app/models/ultima_ug200_sequencing_pipeline.rb
Comment thread
yoldas marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

# Specialized sequencing pipeline for Ultima UG200
class UltimaUG200SequencingPipeline < UltimaSequencingPipeline
def wafer_size_consistent_for_batch?(batch)
wafer_size_list = batch.requests.filter_map { |request| request.request_metadata.wafer_size }

# There are some requests that don't have the wafer_size attribute
return false if wafer_size_list.size != batch.requests.size

(wafer_size_list.uniq.size == 1)
end
end
43 changes: 43 additions & 0 deletions app/models/ultima_ug200_sequencing_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

# Request class specific to the Ultima UG200 sequencing platform.
# Includes wafer size and OT recipe.
class UltimaUG200SequencingRequest < SequencingRequest
include Api::Messages::UseqWaferIo::LaneExtensions

FREE = 'Free'
FLEX = 'Flex'
OT_RECIPE_OPTIONS = [FREE, FLEX].freeze

has_metadata as: Request do
# Defining the sequencing request metadata here again, as 'has_metadata'
# does not automatically append these custom attributes to the request.
#
# The has_metadata call dynamically defines an inner Metadata class and
# takes the attributes from the block and adds them to the Metadata class.
# There is an assumption that the inner Metadata class is available in a
# sequencing request class defintion. Calling has_metadata again does not
# inherit the attributes given in the block supplied in the superclass.
# They need to be supplied again for this class for a proper inner Metadata
# class definition. In a future refactoring these attributes can be moved a
# class attribute and subclasses can merge its own attibutes to that. A
# common method can set up the inner Metadata class in the subclasses.
custom_attribute(:fragment_size_required_from, integer: true, minimum: 1)
custom_attribute(:fragment_size_required_to, integer: true, minimum: 1)

custom_attribute(:ot_recipe, default: FREE, in: OT_RECIPE_OPTIONS, required: true)
enum :ot_recipe, { Free: 0, Flex: 1 }
custom_attribute(:wafer_size, default: '10TB', validator: true, required: true, selection: true)
end

# Delegate to request_metadata so the attributes are visible to the validator in the RSpec tests.
# This delegation has no real effect outside of the tests.
delegate :wafer_size, :ot_recipe, to: :request_metadata

# Generates unique wafer ID, concatenation of batch_for_opentrons,
# id_pool_lims, and request_order.
# @return [String] unique wafer ID for LIMS
def id_wafer_lims
"#{batch.id}_#{source_labware.human_barcode}_#{position}"
end
end
24 changes: 24 additions & 0 deletions app/validators/ultima_ug200_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true
class UltimaUG200Validator < UltimaValidator
WAFER_SIZE_CONSISTENT_MSG = 'Wafer size must be the same for both requests.'

# Used in _pipeline_limit.html to display custom validation warnings
def self.validation_info
'Wafer Size and OT Recipe must be the same for both requests.'
end

# Validates that a batch contains the two requests.
def validate(record)
validate_exactly_two_requests(record)
requests_have_same_ot_recipe(record)
requests_have_same_wafer_size(record)
end

private

def requests_have_same_wafer_size(record)
return if record.pipeline.wafer_size_consistent_for_batch?(record)

record.errors.add(:base, WAFER_SIZE_CONSISTENT_MSG)
end
end
1 change: 1 addition & 0 deletions app/views/bulk_submissions/_guidance.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,5 @@ used to split a submission up into orders, and as a result must have the same re
<dt>% PhiX requested</dt><dd>Required percentage of PhiX needed.</dd>
<dt>Low Diversity</dt><dd>Low Diversity value being "Yes" or "No"</dd>
<dt>OT Recipe</dt><dd>OT (OpenTron liquid handler) Recipe value being "Free" or "Flex"</dd>
<dt>Wafer Size</dt><dd>Wafer size value being "5TB", "10TB" or "20TB"</dd>
</dl>
19 changes: 19 additions & 0 deletions config/bulk_submission_excel/columns.yml
Original file line number Diff line number Diff line change
Expand Up @@ -367,3 +367,22 @@ ot_recipe:
range_name: :ot_recipe
conditional_formattings:
empty_cell:
wafer_size:
heading: "Wafer Size"
unlocked: true
attribute: :wafer_size
validation:
options:
type: :list
formula1: "$A$1:$A$2"
allowBlank: false
showInputMessage: true
showErrorMessage: true
errorStyle: :stop
errorTitle: "Wafer Size"
error: "You must enter a value from the list provided."
promptTitle: "Wafer Size"
prompt: "Select a value type from the approved list"
range_name: :wafer_size
conditional_formattings:
empty_cell:
5 changes: 5 additions & 0 deletions config/bulk_submission_excel/ranges.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,8 @@ ot_recipe:
options:
- "Free"
- "Flex"
wafer_size:
options:
- "5TB"
- "10TB"
- "20TB"
Comment thread
yoldas marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
# Section names must be unique inside the record loader folder.
"OTR carrier Lot # UG200":
name: "OTR carrier Lot #"
task: Opentrons
workflow: Ultima UG200
kind: Text
required: false
sorter: 0
OTR carrier expiry UG200:
name: OTR carrier expiry
task: Opentrons
workflow: Ultima UG200
kind: Date
required: false
sorter: 1
"Reaction Mix 7 Lot # UG200":
name: "Reaction Mix 7 Lot #"
task: Opentrons
workflow: Ultima UG200
kind: Text
required: false
sorter: 2
Reaction Mix 7 expiry UG200:
name: Reaction Mix 7 expiry
task: Opentrons
workflow: Ultima UG200
kind: Date
required: false
sorter: 3
"NFW Lot # UG200":
name: "NFW Lot #"
task: Opentrons
workflow: Ultima UG200
kind: Text
required: false
sorter: 4
NFW expiry UG200:
name: NFW expiry
task: Opentrons
workflow: Ultima UG200
kind: Date
required: false
sorter: 5
"Oil Lot # UG200":
name: "Oil Lot #"
task: Opentrons
workflow: Ultima UG200
kind: Text
required: false
sorter: 6
Oil expiry UG200:
name: Oil expiry
task: Opentrons
workflow: Ultima UG200
kind: Date
required: false
sorter: 7
Pipette carousel UG200:
name: Pipette carousel
task: Opentrons
workflow: Ultima UG200
kind: Text
required: false
sorter: 8
Opentrons Inst. Name UG200:
name: Opentrons Inst. Name
task: Opentrons
workflow: Ultima UG200
kind: Text
required: true
sorter: 9
Assign Control Bead Tube UG200:
name: Assign Control Bead Tube
task: Amp
workflow: Ultima UG200
kind: Text
required: false
sorter: 0
UG AMP Inst. Name UG200:
name: UG AMP Inst. Name
task: Amp
workflow: Ultima UG200
kind: Text
required: true
sorter: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
FragmentSizeRequiredFromInformationTypeForUltimaUG200:
pipeline_name: Ultima UG200
request_information_type_key: fragment_size_required_from

FragmentSizeRequiredToInformationTypeForUltimaUG200:
pipeline_name: Ultima UG200
request_information_type_key: fragment_size_required_to

WaferSizeInformationTypeForUltimaUG200:
pipeline_name: Ultima UG200
request_information_type_key: wafer_size

OTRecipeInformationTypeForUltimaUG200:
pipeline_name: Ultima UG200
request_information_type_key: ot_recipe
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
Ultima UG200:
name: Ultima UG200 Sequencing
sti_type: UltimaUG200SequencingPipeline
validator_class_name: UltimaUG200Validator
sorter: 10
max_size: 2
summary: 1
externally_managed: 0
group_name: Sequencing
control_request_type_id: 0
min_size: 1
request_type_keys:
- ultima_ug200_sequencing
workflow:
name: Ultima UG200
item_limit: 2
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
# 96 well input plates
UPF2 Cherrypicked:
type: PlatePurpose::Input
stock_plate: true
default_state: passed
cherrypickable_target: true
target_type: Plate
size: 96
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
wafer_size:
name: Wafer size
key: wafer_size
label: Wafer size
width: 5
hide_in_inbox: 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
WaferSizeRequestedUltimaUG200Sequencing:
request_type_key: ultima_ug200_sequencing
request_option: wafer_size
valid_options:
- 5TB
- 10TB
- 20TB
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Request types for Ultima UG200 sequencing platform.
---
limber_ultima_ug200_htp_pcr_free:
name: Limber Ultima UG200 HTP PCR Free
order: 1
request_class_name: IlluminaHtp::Requests::StdLibraryRequest
asset_type: Well
for_multiplexing: false
billable: true
product_line_name: Ultima # same as UG100
acceptable_purposes:
- UPF2 Cherrypicked
library_types:
- Ultima High Throughput PCR Free 96 # same as UG100
limber_multiplexing_ultima_ug200:
name: Limber Multiplexing Ultima UG200
asset_type: Well
order: 2
request_class_name: Request::Multiplexing
for_multiplexing: true
product_line_name: Ultima # same as UG100
target_purpose_name: UPF2 EqVol Norm
ultima_ug200_sequencing:
name: Ultima UG200 sequencing
asset_type: LibraryTube
order: 2
initial_state: pending
billable: true
product_line_name: Ultima # same as UG100
request_class_name: UltimaUG200SequencingRequest
request_purpose: standard
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# This submission template is associated with the Ultima PCR Free Library preparation pipeline
# and the Ultima UG200 sequencing platform.
---
Limber-Htp - Ultima UG200 PCR Free - Ultima UG200 sequencing:
submission_class_name: "LinearSubmission"
related_records:
request_type_keys:
["limber_ultima_ug200_htp_pcr_free", "limber_multiplexing_ultima_ug200", "ultima_ug200_sequencing"]
order_role: PCR Free
product_line_name: Ultima # same as UG100
product_catalogue_name: GenericNoPCR
Limber-Htp - Ultima UG200 PCR Free - Ultima UG200 sequencing Automated:
submission_class_name: "LinearSubmission"
related_records:
request_type_keys: ["ultima_ug200_sequencing"]
order_role: PCR Free
product_line_name: Ultima # same as UG100
product_catalogue_name: GenericNoPCR
14 changes: 14 additions & 0 deletions config/default_records/tasks/005_ultima_ug200_tasks.wip.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
# Section names must be unique inside the record loader folder.
Opentrons UG200:
name: Opentrons
workflow: Ultima UG200
sorted: 0
lab_activity: true
sti_type: SetDescriptorsTask
Amp UG200:
name: Amp
workflow: Ultima UG200
sorted: 1
lab_activity: true
sti_type: SetDescriptorsTask
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
UPF2 EqVol Norm:
# Even though this is Ultima, not Illumina, the MX tube has the same behaviour
type: IlluminaHtp::MxTubePurpose
target_type: MultiplexedLibraryTube
stock_plate: false
1 change: 1 addition & 0 deletions config/initializers/inflections.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
inflect.acronym 'ENA' # European Nucleotide Archive
inflect.acronym 'HTTP' # HyperText Transfer Protocol
inflect.acronym 'EBI' # European Bioinformatics Institute
inflect.acronym 'UG200' # Ultima UG200
end

# These inflection rules are supported but not enabled by default:
Expand Down
Loading
Loading