From ed0f7d3facec7c541ffd7326f3a7e6b78fe3a846 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Thu, 14 Aug 2025 14:08:05 +0100 Subject: [PATCH 01/37] Adding some documentation! --- config/initializers/settings.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/initializers/settings.rb b/config/initializers/settings.rb index 73f35f132b..df0493dfeb 100644 --- a/config/initializers/settings.rb +++ b/config/initializers/settings.rb @@ -12,6 +12,8 @@ def configuration_filename private :configuration_filename def instance # rubocop:todo Metrics/AbcSize + # @instance is a Hashie::Mash object that contains all the settings loaded from the YAML file. + # It allows for method calls like Settings.pipelines, Settings.purposes, etc. return @instance if @instance.present? # Ideally we'd do Hashie::Mash.load(File.read(configuration_filename)) here @@ -23,6 +25,8 @@ def instance # rubocop:todo Metrics/AbcSize # To view a list of pipeline groups and respective pipelines: # e.g. Settings.pipelines.group_by(&:pipeline_group).transform_values { |pipelines| pipelines.map(&:name) } + + # This line has specifically been set to customise the behaviour of loading the pipelines. @instance.pipelines = ConfigLoader::PipelinesLoader.new.pipelines @instance @@ -38,6 +42,9 @@ def instance # rubocop:todo Metrics/AbcSize # rubocop:enable Style/StderrPuts end + # This line is making it possible to access configuration using + # the Settings. syntax. For example, Settings.pipelines, Settings.purposes, etc. + # It delegates all method calls to the instance of Settings. delegate_missing_to :instance def reinitialize From 5b9431e5f5a5965d24996fe9c4ef3fad2a38e7a9 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Thu, 14 Aug 2025 14:09:56 +0100 Subject: [PATCH 02/37] [skip ci] Adding some documentation! --- config/initializers/settings.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/initializers/settings.rb b/config/initializers/settings.rb index df0493dfeb..1949eb24e9 100644 --- a/config/initializers/settings.rb +++ b/config/initializers/settings.rb @@ -11,6 +11,9 @@ def configuration_filename end private :configuration_filename + # When invoked, this method will return a Hashie::Mash object that contains all the settings loaded from + # the YAML file. + # For example, you can access settings like `Settings.pipelines`, `Settings.purposes`, etc. def instance # rubocop:todo Metrics/AbcSize # @instance is a Hashie::Mash object that contains all the settings loaded from the YAML file. # It allows for method calls like Settings.pipelines, Settings.purposes, etc. From 87503b4b9def689d2bf9574740cd781b935dffd2 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Thu, 14 Aug 2025 14:18:59 +0100 Subject: [PATCH 03/37] [skip ci] Adding some documentation! --- config/initializers/settings.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/settings.rb b/config/initializers/settings.rb index 1949eb24e9..d0840d4ab7 100644 --- a/config/initializers/settings.rb +++ b/config/initializers/settings.rb @@ -47,7 +47,7 @@ def instance # rubocop:todo Metrics/AbcSize # This line is making it possible to access configuration using # the Settings. syntax. For example, Settings.pipelines, Settings.purposes, etc. - # It delegates all method calls to the instance of Settings. + # It delegates all method calls to the Mash (which is @instance here). delegate_missing_to :instance def reinitialize From 7484922e8bec9acad591634264efcb9458ab97a8 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Fri, 15 Aug 2025 13:29:46 +0100 Subject: [PATCH 04/37] Starting Settions and Configuration V2 mixins. --- config/initializers/configurationV2.rb | 39 +++++++++++++++++++++++++ config/initializers/settingsV2.rb | 40 ++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 config/initializers/configurationV2.rb create mode 100644 config/initializers/settingsV2.rb diff --git a/config/initializers/configurationV2.rb b/config/initializers/configurationV2.rb new file mode 100644 index 0000000000..36bcdd3be7 --- /dev/null +++ b/config/initializers/configurationV2.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module ConfigurationV2 + # Configuration for the application, including loaders for various configurations. + + def initialize(config_hash) + config_hash.with_indifferent_access.each do |key, value| + + end + end + + class Item + include Enumerable + + attr_reader :children, :configuration + + def initialize(configuration, children = {}) + @children = children + @configuration = configuration + + children.each do |key, child| + if child.is_a?(ActiveSupport::HashWithIndifferentAccess) + next if respond_to?(key) + + child_item = Item.new(configuration, child) + define_singleton_method(key) { child_item } + else + define_singleton_method(key) { child } + end + end + end + + def each(...) + children.each(...) + end + end + + +end \ No newline at end of file diff --git a/config/initializers/settingsV2.rb b/config/initializers/settingsV2.rb new file mode 100644 index 0000000000..ce299779f9 --- /dev/null +++ b/config/initializers/settingsV2.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module SettingsV2 + + CONFIGURATION_TYPES = [ + :searches, + :transfer_templates, + :printers, + :purposes, + :purpose_uuids, + :robots, + :default_pmb_templates, + :default_sprint_templates, + :default_printer_type_names, + :submission_templates + ]* + + CONFIGURATION_TYPES.each do |config| + # proc needs to return the configuration value + self.class.send(:define_method, config, proc { configuration.send(config) }) + end + + def self.load_yaml + config = Rails.root.join('config', 'settings', "#{Rails.env}.yml") + return unless File.exist?(config) + + config_file_descriptor = File.open(configuration_filename, 'r:bom|utf-8') + # Returns a Hash with the configuration data + config_data = YAML.safe_load(config_file_descriptor, permitted_classes: [Symbol], aliases: true) + raise "Configuration file #{config} is not valid YAML." if config_data.blank? + + config_data.with_indifferent_access + end + + def self.configuration + @configuration ||= ConfigurationV2.new(load_yaml) + end + + +end \ No newline at end of file From e9a64dfc4a35b2a4f22bb6c21b7bf751c5e2bc62 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Mon, 18 Aug 2025 09:38:38 +0100 Subject: [PATCH 05/37] Fix linting issues --- ...configurationV2.rb => configuration_v2.rb} | 13 ++++--- .../{settingsV2.rb => settings_v2.rb} | 39 +++++++++---------- 2 files changed, 25 insertions(+), 27 deletions(-) rename config/initializers/{configurationV2.rb => configuration_v2.rb} (78%) rename config/initializers/{settingsV2.rb => settings_v2.rb} (58%) diff --git a/config/initializers/configurationV2.rb b/config/initializers/configuration_v2.rb similarity index 78% rename from config/initializers/configurationV2.rb rename to config/initializers/configuration_v2.rb index 36bcdd3be7..5d6f9e9252 100644 --- a/config/initializers/configurationV2.rb +++ b/config/initializers/configuration_v2.rb @@ -1,19 +1,21 @@ # frozen_string_literal: true +# Parent configuration mixin. module ConfigurationV2 # Configuration for the application, including loaders for various configurations. def initialize(config_hash) - config_hash.with_indifferent_access.each do |key, value| - - end + # config_hash.with_indifferent_access.each do |key, value| + # end end + # Configuration item. class Item include Enumerable attr_reader :children, :configuration + # rubocop:disable Metrics/MethodLength def initialize(configuration, children = {}) @children = children @configuration = configuration @@ -29,11 +31,10 @@ def initialize(configuration, children = {}) end end end + # rubocop:enable Metrics/MethodLength def each(...) children.each(...) end end - - -end \ No newline at end of file +end diff --git a/config/initializers/settingsV2.rb b/config/initializers/settings_v2.rb similarity index 58% rename from config/initializers/settingsV2.rb rename to config/initializers/settings_v2.rb index ce299779f9..a0e7f9ef22 100644 --- a/config/initializers/settingsV2.rb +++ b/config/initializers/settings_v2.rb @@ -1,24 +1,23 @@ # frozen_string_literal: true +# Parent settings mixin. module SettingsV2 - - CONFIGURATION_TYPES = [ - :searches, - :transfer_templates, - :printers, - :purposes, - :purpose_uuids, - :robots, - :default_pmb_templates, - :default_sprint_templates, - :default_printer_type_names, - :submission_templates - ]* - - CONFIGURATION_TYPES.each do |config| - # proc needs to return the configuration value - self.class.send(:define_method, config, proc { configuration.send(config) }) - end + CONFIGURATION_TYPES = %i[ + searches + transfer_templates + printers + purposes + purpose_uuids + robots + default_pmb_templates + default_sprint_templates + default_printer_type_names + submission_templates + ] * + CONFIGURATION_TYPES.each do |config| + # proc needs to return the configuration value + self.class.send(:define_method, config, proc { configuration.send(config) }) + end def self.load_yaml config = Rails.root.join('config', 'settings', "#{Rails.env}.yml") @@ -35,6 +34,4 @@ def self.load_yaml def self.configuration @configuration ||= ConfigurationV2.new(load_yaml) end - - -end \ No newline at end of file +end From 1fbe0030c17d44371009b3b4ca178e0c7c7ee03a Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Mon, 18 Aug 2025 09:41:09 +0100 Subject: [PATCH 06/37] Fix linting issues --- config/initializers/settings_v2.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/config/initializers/settings_v2.rb b/config/initializers/settings_v2.rb index a0e7f9ef22..8c8470801a 100644 --- a/config/initializers/settings_v2.rb +++ b/config/initializers/settings_v2.rb @@ -13,11 +13,12 @@ module SettingsV2 default_sprint_templates default_printer_type_names submission_templates - ] * - CONFIGURATION_TYPES.each do |config| - # proc needs to return the configuration value - self.class.send(:define_method, config, proc { configuration.send(config) }) - end + ].freeze + + CONFIGURATION_TYPES.each do |config| + # proc needs to return the configuration value + self.class.send(:define_method, config, proc { configuration.send(config) }) + end def self.load_yaml config = Rails.root.join('config', 'settings', "#{Rails.env}.yml") From 239458f641ca8b2a0792b36d3b10410b43c8b5dc Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Mon, 18 Aug 2025 11:57:19 +0100 Subject: [PATCH 07/37] Redoing the settings module --- config/initializers/configuration_v2.rb | 40 --------- config/initializers/custom_configuration.rb | 44 ++++++++++ config/initializers/settings.rb | 94 ++++++++------------- config/initializers/settings_v2.rb | 38 --------- 4 files changed, 80 insertions(+), 136 deletions(-) delete mode 100644 config/initializers/configuration_v2.rb create mode 100644 config/initializers/custom_configuration.rb delete mode 100644 config/initializers/settings_v2.rb diff --git a/config/initializers/configuration_v2.rb b/config/initializers/configuration_v2.rb deleted file mode 100644 index 5d6f9e9252..0000000000 --- a/config/initializers/configuration_v2.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -# Parent configuration mixin. -module ConfigurationV2 - # Configuration for the application, including loaders for various configurations. - - def initialize(config_hash) - # config_hash.with_indifferent_access.each do |key, value| - # end - end - - # Configuration item. - class Item - include Enumerable - - attr_reader :children, :configuration - - # rubocop:disable Metrics/MethodLength - def initialize(configuration, children = {}) - @children = children - @configuration = configuration - - children.each do |key, child| - if child.is_a?(ActiveSupport::HashWithIndifferentAccess) - next if respond_to?(key) - - child_item = Item.new(configuration, child) - define_singleton_method(key) { child_item } - else - define_singleton_method(key) { child } - end - end - end - # rubocop:enable Metrics/MethodLength - - def each(...) - children.each(...) - end - end -end diff --git a/config/initializers/custom_configuration.rb b/config/initializers/custom_configuration.rb new file mode 100644 index 0000000000..049c6d7c0f --- /dev/null +++ b/config/initializers/custom_configuration.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +# Parent configuration mixin. +module Settings + # Configuration for the application, including loaders for various configurations. + + # Custom configuration class that can be used to build a configuration + class CustomConfiguration + def initialize(config_hash) + config_hash.with_indifferent_access.each do |key, value| + define_singleton_method(key) { Item.new(key, value) } + end + end + + # Configuration item. + class Item + include Enumerable + + attr_reader :children, :configuration + + # rubocop:disable Metrics/MethodLength + def initialize(configuration, children = {}) + @children = children + @configuration = configuration + + children.each do |key, child| + if child.is_a?(ActiveSupport::HashWithIndifferentAccess) + next if respond_to?(key) + + child_item = Item.new(configuration, child) + define_singleton_method(key) { child_item } + else + define_singleton_method(key) { child } + end + end + end + # rubocop:enable Metrics/MethodLength + + def each(...) + children.each(...) + end + end + end +end diff --git a/config/initializers/settings.rb b/config/initializers/settings.rb index d0840d4ab7..87cb8f42f9 100644 --- a/config/initializers/settings.rb +++ b/config/initializers/settings.rb @@ -1,66 +1,44 @@ # frozen_string_literal: true -require 'config_loader/pipelines_loader' - -# Global setting object loaded from `config/settings/_environment_.yml` which is -# generated on running `rake config:generate` -class Settings - class << self - def configuration_filename - Rails.root.join('config', 'settings', "#{Rails.env}.yml") - end - private :configuration_filename - - # When invoked, this method will return a Hashie::Mash object that contains all the settings loaded from - # the YAML file. - # For example, you can access settings like `Settings.pipelines`, `Settings.purposes`, etc. - def instance # rubocop:todo Metrics/AbcSize - # @instance is a Hashie::Mash object that contains all the settings loaded from the YAML file. - # It allows for method calls like Settings.pipelines, Settings.purposes, etc. - return @instance if @instance.present? - - # Ideally we'd do Hashie::Mash.load(File.read(configuration_filename)) here - # but the creates an immutable setting object that messes with tests. - # Immutability is good here though, so we should probably fix that. - # Added flag onto safe_load to allow read of anchors (aliases) in yml files. - config_file_descriptor = File.open(configuration_filename, 'r:bom|utf-8') - @instance = Hashie::Mash.new(YAML.safe_load(config_file_descriptor, permitted_classes: [Symbol], aliases: true)) - - # To view a list of pipeline groups and respective pipelines: - # e.g. Settings.pipelines.group_by(&:pipeline_group).transform_values { |pipelines| pipelines.map(&:name) } - - # This line has specifically been set to customise the behaviour of loading the pipelines. - @instance.pipelines = ConfigLoader::PipelinesLoader.new.pipelines +# Parent settings mixin. +module Settings + CONFIGURATION_TYPES = %i[ + searches + transfer_templates + printers + purposes + purpose_uuids + robots + default_pmb_templates + default_sprint_templates + default_printer_type_names + submission_templates + ].freeze + + CONFIGURATION_TYPES.each do |config| + # Accessor methods + self.class.send(:define_method, config, proc { + Settings.configuration.send(config) + }) + # Mutator methods + self.class.send(:define_method, "#{config}=", proc { |value| + Settings.configuration.send("#{config}=", value) + }) + end - @instance - rescue Errno::ENOENT - # This before we've fully initialized and is intended to report issues to - # the user. - # rubocop:disable Style/StderrPuts - star_length = [96, 12 + configuration_filename.to_s.length].max - $stderr.puts('*' * star_length) - $stderr.puts "WARNING! No #{configuration_filename}" - $stderr.puts "You need to run 'rake config:generate' and can ignore this message if that's what you are doing!" - $stderr.puts('*' * star_length) - # rubocop:enable Style/StderrPuts - end + def self.load_yaml + config = Rails.root.join('config', 'settings', "#{Rails.env}.yml") + return unless File.exist?(config) - # This line is making it possible to access configuration using - # the Settings. syntax. For example, Settings.pipelines, Settings.purposes, etc. - # It delegates all method calls to the Mash (which is @instance here). - delegate_missing_to :instance + config_file_descriptor = File.open(config, 'r:bom|utf-8') + # Returns a Hash with the configuration data + config_data = YAML.safe_load(config_file_descriptor, permitted_classes: [Symbol], aliases: true) + raise "Configuration file #{config} is not valid YAML." if config_data.blank? - def reinitialize - @instance = nil - self - end + config_data.with_indifferent_access end -end -Rails.application.config.to_prepare do - # By re-initializing here we gain: - # - Clear hot-reloading of classes like PipelineList when in development mode - # - Reloading of the settings in development mode, meaning you don't need to - # restart following a rake config:generate - Settings.reinitialize.instance + def self.configuration + @configuration ||= CustomConfiguration.new(load_yaml) + end end diff --git a/config/initializers/settings_v2.rb b/config/initializers/settings_v2.rb deleted file mode 100644 index 8c8470801a..0000000000 --- a/config/initializers/settings_v2.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -# Parent settings mixin. -module SettingsV2 - CONFIGURATION_TYPES = %i[ - searches - transfer_templates - printers - purposes - purpose_uuids - robots - default_pmb_templates - default_sprint_templates - default_printer_type_names - submission_templates - ].freeze - - CONFIGURATION_TYPES.each do |config| - # proc needs to return the configuration value - self.class.send(:define_method, config, proc { configuration.send(config) }) - end - - def self.load_yaml - config = Rails.root.join('config', 'settings', "#{Rails.env}.yml") - return unless File.exist?(config) - - config_file_descriptor = File.open(configuration_filename, 'r:bom|utf-8') - # Returns a Hash with the configuration data - config_data = YAML.safe_load(config_file_descriptor, permitted_classes: [Symbol], aliases: true) - raise "Configuration file #{config} is not valid YAML." if config_data.blank? - - config_data.with_indifferent_access - end - - def self.configuration - @configuration ||= ConfigurationV2.new(load_yaml) - end -end From 0f356ff1f7b33019f9085f05279054619bae1429 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Mon, 18 Aug 2025 15:36:06 +0100 Subject: [PATCH 08/37] Redoing the settings module --- config/initializers/custom_configuration.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/config/initializers/custom_configuration.rb b/config/initializers/custom_configuration.rb index 049c6d7c0f..7682bea092 100644 --- a/config/initializers/custom_configuration.rb +++ b/config/initializers/custom_configuration.rb @@ -7,8 +7,11 @@ module Settings # Custom configuration class that can be used to build a configuration class CustomConfiguration def initialize(config_hash) - config_hash.with_indifferent_access.each do |key, value| + @children = config_hash.with_indifferent_access + + @children.each do |key, value| define_singleton_method(key) { Item.new(key, value) } + define_singleton_method("#{key}=") { |new_value| @children[key] = new_value } end end @@ -32,6 +35,7 @@ def initialize(configuration, children = {}) else define_singleton_method(key) { child } end + define_singleton_method("#{key}=") { |new_value| @children[key] = new_value } end end # rubocop:enable Metrics/MethodLength From d9f17e63336c83567af0495f8c995f09857ad90b Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Mon, 18 Aug 2025 15:44:15 +0100 Subject: [PATCH 09/37] [skip ci] Adding comments --- config/initializers/custom_configuration.rb | 22 +++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/config/initializers/custom_configuration.rb b/config/initializers/custom_configuration.rb index 7682bea092..f21b4ad71c 100644 --- a/config/initializers/custom_configuration.rb +++ b/config/initializers/custom_configuration.rb @@ -4,18 +4,36 @@ module Settings # Configuration for the application, including loaders for various configurations. - # Custom configuration class that can be used to build a configuration + # This will create class-level functions so that they could be accessed like + # Settings.searches, Settings.transfer_templates, etc. class CustomConfiguration def initialize(config_hash) @children = config_hash.with_indifferent_access + # When you invoke, Settings.configuration.searches in settings.rb, it would invoke static + # methods declared through this block. @children.each do |key, value| + # For every getter method, it creates a method that returns an Item instance + # with the key and value from the configuration hash. define_singleton_method(key) { Item.new(key, value) } + # For every setter method, it creates a method that sets the value in the children hash. + # This allows you to do Settings.configuration.searches = new_value. define_singleton_method("#{key}=") { |new_value| @children[key] = new_value } end end - # Configuration item. + # Configuration item. It recursively builds a structure + # that allows for nested configurations to be accessed easily. + # It includes Enumerable to allow iteration over its children. + # + # Each child can be a nested configuration or a simple value. + # This allows for a flexible and dynamic configuration structure. + # + # @example + # config = Settings.configuration + # config.searches.some_child.some_grandchild + # config.searches.some_child.some_grandchild = new_value + # class Item include Enumerable From 741672a2e35060cadc4f411644ff6a9b1080fd62 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Mon, 18 Aug 2025 16:05:02 +0100 Subject: [PATCH 10/37] [skip ci] Adding more configuration stuff --- config/initializers/settings.rb | 2 ++ config/settings/test.yml | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/config/initializers/settings.rb b/config/initializers/settings.rb index 87cb8f42f9..6ed68fc48e 100644 --- a/config/initializers/settings.rb +++ b/config/initializers/settings.rb @@ -13,6 +13,8 @@ module Settings default_sprint_templates default_printer_type_names submission_templates + pipelines + poolings ].freeze CONFIGURATION_TYPES.each do |config| diff --git a/config/settings/test.yml b/config/settings/test.yml index 3034a3623e..7067f22eb8 100644 --- a/config/settings/test.yml +++ b/config/settings/test.yml @@ -7,5 +7,11 @@ :purposes: {} :purpose_uuids: {} :robots: {} -:locations: {} +:default_pmb_templates: {} +:default_sprint_templates: {} +:default_printer_type_names: [] +:submission_templates: {} :qc_purposes: [] +:locations: {} +:pipelines: {} +:poolings: {} \ No newline at end of file From 31e5575d9a633d97f8ccf1f45d3cacc7e78dacd7 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Tue, 19 Aug 2025 09:28:49 +0100 Subject: [PATCH 11/37] [skip ci] Adding more configuration stuff --- config/initializers/custom_configuration.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/initializers/custom_configuration.rb b/config/initializers/custom_configuration.rb index f21b4ad71c..9678beb895 100644 --- a/config/initializers/custom_configuration.rb +++ b/config/initializers/custom_configuration.rb @@ -58,6 +58,12 @@ def initialize(configuration, children = {}) end # rubocop:enable Metrics/MethodLength + delegate :[]=, to: :@children + + def fetch(key, default = nil) + @children.fetch(key, default) + end + def each(...) children.each(...) end From 887a18325b10361a2befea6fd30b45b71b63c96f Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Tue, 19 Aug 2025 09:30:21 +0100 Subject: [PATCH 12/37] [skip ci] Adding more configuration stuff --- config/settings/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/settings/test.yml b/config/settings/test.yml index 7067f22eb8..80293ca9ae 100644 --- a/config/settings/test.yml +++ b/config/settings/test.yml @@ -14,4 +14,4 @@ :qc_purposes: [] :locations: {} :pipelines: {} -:poolings: {} \ No newline at end of file +:poolings: {} From a68b52d1a743e6a610cf9dc7992717043eeaca2b Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Tue, 19 Aug 2025 10:55:15 +0100 Subject: [PATCH 13/37] Refactor search_helper to use children method for accessing purposes --- app/helpers/search_helper.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 15f8dd83dd..854f96f3a9 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -2,20 +2,20 @@ module SearchHelper # rubocop:todo Style/Documentation def stock_plate_uuids - Settings.purposes.select { |_uuid, config| config.input_plate }.keys + Settings.purposes.children.select { |_uuid, config| config.input_plate }.keys end def self.stock_plate_names - Settings.purposes.values.select(&:input_plate).map(&:name) + Settings.purposes.children.values.select(&:input_plate).map(&:name) end # Returns purpose names of stock plates using stock_plate flag instead of input_plate. def self.stock_plate_names_with_flag - Settings.purposes.values.select(&:stock_plate).map(&:name) + Settings.purposes.children.values.select(&:stock_plate).map(&:name) end def self.purpose_config_for_purpose_name(purpose_name) - Settings.purposes.values.find { |obj| obj[:name] == purpose_name } + Settings.purposes.children.values.find { |obj| obj[:name] == purpose_name } end def self.alternative_workline_reference_name(labware) @@ -26,12 +26,13 @@ def self.alternative_workline_reference_name(labware) end def self.merger_plate_names - Settings.purposes.values.select(&:merger_plate).map(&:name) + Settings.purposes.children.values.select(&:merger_plate).map(&:name) end def purpose_options(type) Settings .purposes + .children .select { |_uuid, settings| settings[:asset_type] == type } .map { |uuid, settings| [settings[:name], uuid] } end From f50a9f46e1aa9fad1fdd5fdee5419828dece9c6d Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Tue, 19 Aug 2025 14:17:06 +0100 Subject: [PATCH 14/37] Enhance CustomConfiguration to dynamically define getter and setter methods for nested configuration access; add initial settings_spec for pipelines --- config/initializers/custom_configuration.rb | 14 ++++++++ config/initializers/settings.rb | 10 +++++- spec/initializers/settings_spec.rb | 39 +++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 spec/initializers/settings_spec.rb diff --git a/config/initializers/custom_configuration.rb b/config/initializers/custom_configuration.rb index 9678beb895..a38dfd71a4 100644 --- a/config/initializers/custom_configuration.rb +++ b/config/initializers/custom_configuration.rb @@ -44,6 +44,20 @@ def initialize(configuration, children = {}) @children = children @configuration = configuration + # Dynamically defines getter and setter methods for each child key in the configuration. + # + # For each key-value pair in the children hash: + # - If the value is a nested hash (ActiveSupport::HashWithIndifferentAccess), + # it creates a getter method that returns a new Item instance, allowing for recursive access. + # - If the value is a simple value, it creates a getter method that returns the value directly. + # - For every key, it also creates a setter method to update the value in the children hash. + # + # This enables flexible, dot-notation access and assignment for deeply nested configuration structures. + # + # Example: + # config = Settings.configuration + # config.searches.some_child.some_grandchild # Access nested value + # config.searches.some_child.some_grandchild = val # Set nested value children.each do |key, child| if child.is_a?(ActiveSupport::HashWithIndifferentAccess) next if respond_to?(key) diff --git a/config/initializers/settings.rb b/config/initializers/settings.rb index 6ed68fc48e..98cab22b68 100644 --- a/config/initializers/settings.rb +++ b/config/initializers/settings.rb @@ -13,7 +13,6 @@ module Settings default_sprint_templates default_printer_type_names submission_templates - pipelines poolings ].freeze @@ -28,6 +27,15 @@ module Settings }) end + # Delegates Settings.pipelines to the PipelinesLoader + def self.pipelines + @pipelines ||= ConfigLoader::PipelinesLoader.new.pipelines + end + + def self.pipelines=(value) + @pipelines = value + end + def self.load_yaml config = Rails.root.join('config', 'settings', "#{Rails.env}.yml") return unless File.exist?(config) diff --git a/spec/initializers/settings_spec.rb b/spec/initializers/settings_spec.rb new file mode 100644 index 0000000000..b77d53936d --- /dev/null +++ b/spec/initializers/settings_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Settings, skip: 'Skipping as WIP' do + let(:yaml_data) do + { + 'searches' => %w[search1 search2], + 'transfer_templates' => ['template1'], + 'printers' => ['printer1'], + 'purposes' => ['purpose1'], + 'purpose_uuids' => ['uuid1'], + 'robots' => ['robot1'], + 'default_pmb_templates' => ['pmb1'], + 'default_sprint_templates' => ['sprint1'], + 'default_printer_type_names' => ['type1'], + 'submission_templates' => ['submission1'], + 'poolings' => ['pooling1'] + } + end + + before do + allow(Rails).to receive_messages(root: Pathname.new(File.dirname(__FILE__)), env: 'test') + file_double = StringIO.new(yaml_data.to_yaml) + allow(File).to receive_messages(exist?: true, open: file_double) + stub_const('CustomConfiguration', Struct.new(*Settings::CONFIGURATION_TYPES) do + def initialize(hash) + hash.each { |k, v| send("#{k}=", v) } + end + end) + described_class.instance_variable_set(:@configuration, nil) + end + + describe 'Settings configuration setting the pipelines' do + it 'when invoked, returns the pipelines properly' do + skip 'WIP' + end + end +end From f9d574fd26f0ea66254907728d9db7a10112e61f Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Tue, 19 Aug 2025 15:59:57 +0100 Subject: [PATCH 15/37] Refactor CreationBehaviour and Settings to improve configuration handling; add config.yml for testing --- .../concerns/presenters/creation_behaviour.rb | 10 +- config/initializers/settings.rb | 3 + spec/data/config.yml | 109 ++++++++++++++++++ spec/initializers/settings_spec.rb | 39 ++----- 4 files changed, 126 insertions(+), 35 deletions(-) create mode 100644 spec/data/config.yml diff --git a/app/models/concerns/presenters/creation_behaviour.rb b/app/models/concerns/presenters/creation_behaviour.rb index 6e0771d6bc..6691f047a0 100644 --- a/app/models/concerns/presenters/creation_behaviour.rb +++ b/app/models/concerns/presenters/creation_behaviour.rb @@ -34,9 +34,9 @@ def construct_buttons(scope) parent_uuid: uuid, parent: labware, purpose_uuid: purpose_uuid, - name: purpose_settings.name, - type: purpose_settings.asset_type, - filters: purpose_settings.filters || {} + name: purpose_settings[:name], + type: purpose_settings[:asset_type], + filters: purpose_settings[:filters] || {} ) end .force @@ -62,6 +62,8 @@ def suggested_purpose_options end def compatible_purposes - Settings.purposes.lazy.select { |uuid, _purpose_settings| LabwareCreators.class_for(uuid).support_parent?(labware) } + Settings.purposes.children.lazy.select do |uuid, _purpose_settings| + LabwareCreators.class_for(uuid).support_parent?(labware) + end end end diff --git a/config/initializers/settings.rb b/config/initializers/settings.rb index 98cab22b68..d68315a9a4 100644 --- a/config/initializers/settings.rb +++ b/config/initializers/settings.rb @@ -16,6 +16,9 @@ module Settings poolings ].freeze + # This loop declares Settings. method declarations + # using metaprogramming. For example, when it will add purposes method for Settings, and + # when it is invoked, it will use the CustomConfiguration class to send the value for it. CONFIGURATION_TYPES.each do |config| # Accessor methods self.class.send(:define_method, config, proc { diff --git a/spec/data/config.yml b/spec/data/config.yml new file mode 100644 index 0000000000..92153b095d --- /dev/null +++ b/spec/data/config.yml @@ -0,0 +1,109 @@ +# The current file has been automatically generated by running the task: +# > rake config:generate +# It is recommended if you need to do any changes in config to modify the +# required config file under config/pipelines or config/purposes and rerun +# the task +--- +:searches: + Find assets by barcode: 7e660cbc-6951-11f0-8c10-ded867e19c6b + Find project by name: 7e668c82-6951-11f0-8c10-ded867e19c6b + Find study by name: 7e66e272-6951-11f0-8c10-ded867e19c6b +:transfer_templates: + 384 plate to tube: 7c673a8a-6951-11f0-8c10-ded867e19c6b + Transfer columns 1-1: 7d590ff4-6951-11f0-8c10-ded867e19c6b +:printers: + :plate_a: g316bc + :plate_b: g311bc2 + :tube_rack: heron-bc2 + :tube: g311bc1 + :limit: 5 + :default_count: 2 +:purposes: + 9e42476c-6951-11f0-b542-ded867e19c6b: + :name: LBC 5p GEX Dil + :default_printer_type: :plate_a + :presenter_class: Presenters::NormalisedBinnedPlatePresenter + :creator_class: LabwareCreators::NormalisedBinnedPlate + :label_class: Labels::PlateLabel + :file_links: + - name: Download Hamilton Cherrypick to 5 prime Dilution CSV + id: hamilton_cherrypick_to_5p_gex_dilution + - name: Download Concentration (ng/ul) CSV + id: concentrations_ngul + :state_changer_class: StateChangers::PlateStateChanger + :submission: {} + :printer_type: 96 Well Plate + :pmb_template: sqsc_96plate_label_template_code39 + :sprint_template: plate_96.yml.erb + :asset_type: plate + :dilutions: + :target_amount_ng: 50 + :target_volume: 20 + :minimum_source_volume: 0.2 + :bins: + - colour: 1 + pcr_cycles: 16 + max: 26 + - colour: 2 + pcr_cycles: 14 + min: 26 +:purpose_uuids: + LBC 5p GEX Dil: 9e42476c-6951-11f0-b542-ded867e19c6b + LBC 5p GEX Frag 2XP: 9e5190f0-6951-11f0-b542-ded867e19c6b + LBC 5p GEX LigXP: 9e5424dc-6951-11f0-b542-ded867e19c6b +:robots: + bravo-lb-cherrypick-to-lb-shear: + :name: bravo LB Cherrypick => LB Shear + :verify_robot: false + :require_robot: false + :beds: + '580000007860': + :purpose: LB Cherrypick + :states: + - passed + :label: Bed 7 + :shared_parent: false + '580000009659': + :purpose: LB Shear + :states: + - pending + :label: Bed 9 + :parent: '580000007860' + :target_state: passed + bravo-lb-shear-to-lb-post-shear: + :name: bravo LB Shear => LB Post Shear + :verify_robot: false + :require_robot: false + :beds: + '580000009659': + :purpose: LB Shear + :states: + - passed + :label: Bed 9 + :shared_parent: false + '580000007860': + :purpose: LB Post Shear + :states: + - pending + :label: Bed 7 + :parent: '580000009659' + :target_state: passed +:default_pmb_templates: + :plate_double: plate_6mm_double_code39 + :plate_a: sqsc_96plate_label_template_code39 + :tube_rack: sqsc_96plate_label_template_code39 + :tube: tube_label_template_1d +:default_sprint_templates: + :plate_double: plate_384.yml.erb + :plate_a: plate_96.yml.erb + :tube_rack: plate_96.yml.erb + :tube: tube_label_template_1d.yml.erb +:default_printer_type_names: + :plate_double: 384 Well Plate Double + :plate_a: 96 Well Plate + :tube_rack: 96 Well Plate + :tube: 1D Tube +:submission_templates: + Limber - Cardinal: 7b7a63e0-6951-11f0-8c10-ded867e19c6b + Limber - Cardinal cell banking: 7b7bc1e0-6951-11f0-8c10-ded867e19c6b +poolings: diff --git a/spec/initializers/settings_spec.rb b/spec/initializers/settings_spec.rb index b77d53936d..614a08e4ed 100644 --- a/spec/initializers/settings_spec.rb +++ b/spec/initializers/settings_spec.rb @@ -2,38 +2,15 @@ require 'rails_helper' -RSpec.describe Settings, skip: 'Skipping as WIP' do - let(:yaml_data) do - { - 'searches' => %w[search1 search2], - 'transfer_templates' => ['template1'], - 'printers' => ['printer1'], - 'purposes' => ['purpose1'], - 'purpose_uuids' => ['uuid1'], - 'robots' => ['robot1'], - 'default_pmb_templates' => ['pmb1'], - 'default_sprint_templates' => ['sprint1'], - 'default_printer_type_names' => ['type1'], - 'submission_templates' => ['submission1'], - 'poolings' => ['pooling1'] - } - end - +# rubocop:disable RSpec/EmptyExampleGroup +RSpec.describe Settings, skip: 'WIP' do before do - allow(Rails).to receive_messages(root: Pathname.new(File.dirname(__FILE__)), env: 'test') - file_double = StringIO.new(yaml_data.to_yaml) - allow(File).to receive_messages(exist?: true, open: file_double) - stub_const('CustomConfiguration', Struct.new(*Settings::CONFIGURATION_TYPES) do - def initialize(hash) - hash.each { |k, v| send("#{k}=", v) } - end - end) + config = Rails.root.join('spec/data/config.yml') + config_file_descriptor = File.open(config, 'r:bom|utf-8') + # Returns a Hash with the configuration data + config_data = YAML.safe_load(config_file_descriptor, permitted_classes: [Symbol], aliases: true) + allow(described_class).to receive(:load_yaml).and_return(config_data) described_class.instance_variable_set(:@configuration, nil) end - - describe 'Settings configuration setting the pipelines' do - it 'when invoked, returns the pipelines properly' do - skip 'WIP' - end - end end +# rubocop:enable RSpec/EmptyExampleGroup From ed2ac0c2d0ab257a5db963e0220c5167b9bbdfc5 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Tue, 19 Aug 2025 16:05:35 +0100 Subject: [PATCH 16/37] Refactor accessor method in Settings module to handle children for configuration values --- config/initializers/settings.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/initializers/settings.rb b/config/initializers/settings.rb index d68315a9a4..3ec2a80810 100644 --- a/config/initializers/settings.rb +++ b/config/initializers/settings.rb @@ -22,7 +22,8 @@ module Settings CONFIGURATION_TYPES.each do |config| # Accessor methods self.class.send(:define_method, config, proc { - Settings.configuration.send(config) + value = Settings.configuration.send(config) + value.respond_to?(:children) ? value.children : value }) # Mutator methods self.class.send(:define_method, "#{config}=", proc { |value| From 950887b02fb0aa355a41a3e629adfdb337873ad6 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Tue, 19 Aug 2025 16:09:40 +0100 Subject: [PATCH 17/37] Refactor compatible_purposes method to use lazy enumeration for improved performance --- app/models/concerns/presenters/creation_behaviour.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/concerns/presenters/creation_behaviour.rb b/app/models/concerns/presenters/creation_behaviour.rb index 6691f047a0..1b38f06723 100644 --- a/app/models/concerns/presenters/creation_behaviour.rb +++ b/app/models/concerns/presenters/creation_behaviour.rb @@ -62,7 +62,7 @@ def suggested_purpose_options end def compatible_purposes - Settings.purposes.children.lazy.select do |uuid, _purpose_settings| + Settings.purposes.lazy.select do |uuid, _purpose_settings| LabwareCreators.class_for(uuid).support_parent?(labware) end end From f50a9bb9fe407a99592d68cd9b5fbf34f52d4fa1 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Tue, 19 Aug 2025 16:18:00 +0100 Subject: [PATCH 18/37] Refactor search_helper to remove unnecessary children method calls for accessing purposes --- app/helpers/search_helper.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 854f96f3a9..15f8dd83dd 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -2,20 +2,20 @@ module SearchHelper # rubocop:todo Style/Documentation def stock_plate_uuids - Settings.purposes.children.select { |_uuid, config| config.input_plate }.keys + Settings.purposes.select { |_uuid, config| config.input_plate }.keys end def self.stock_plate_names - Settings.purposes.children.values.select(&:input_plate).map(&:name) + Settings.purposes.values.select(&:input_plate).map(&:name) end # Returns purpose names of stock plates using stock_plate flag instead of input_plate. def self.stock_plate_names_with_flag - Settings.purposes.children.values.select(&:stock_plate).map(&:name) + Settings.purposes.values.select(&:stock_plate).map(&:name) end def self.purpose_config_for_purpose_name(purpose_name) - Settings.purposes.children.values.find { |obj| obj[:name] == purpose_name } + Settings.purposes.values.find { |obj| obj[:name] == purpose_name } end def self.alternative_workline_reference_name(labware) @@ -26,13 +26,12 @@ def self.alternative_workline_reference_name(labware) end def self.merger_plate_names - Settings.purposes.children.values.select(&:merger_plate).map(&:name) + Settings.purposes.values.select(&:merger_plate).map(&:name) end def purpose_options(type) Settings .purposes - .children .select { |_uuid, settings| settings[:asset_type] == type } .map { |uuid, settings| [settings[:name], uuid] } end From b25ba844500244abfc7e3372aa994b24f9452424 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Wed, 20 Aug 2025 11:20:29 +0100 Subject: [PATCH 19/37] Changing test.yml --- app/helpers/search_helper.rb | 2 +- config/settings/test.yml | 30 ++++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 15f8dd83dd..1f29ed085a 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -2,7 +2,7 @@ module SearchHelper # rubocop:todo Style/Documentation def stock_plate_uuids - Settings.purposes.select { |_uuid, config| config.input_plate }.keys + Settings.purposes.select { |_uuid, config| config[:input_plate] }.keys end def self.stock_plate_names diff --git a/config/settings/test.yml b/config/settings/test.yml index 80293ca9ae..d7ac1efa59 100644 --- a/config/settings/test.yml +++ b/config/settings/test.yml @@ -1,15 +1,37 @@ --- :searches: {} -:transfer_templates: {} +:transfer_templates: + 'Custom pooling': custom-pooling + 'Pool wells based on submission': custom-transfer-template + 'Transfer between specific tubes': transfer-between-specific-tubes + 'Transfer columns 1-12': transfer-1-12 + 'Transfer from tube to tube by submission': tube-to-tube-by-sub + 'Transfer wells to MX library tubes by submission': transfer-to-mx-tubes-on-submission + 'Whole plate to tube': whole-plate-to-tube :printers: limit: 5 default_count: 2 :purposes: {} :purpose_uuids: {} :robots: {} -:default_pmb_templates: {} -:default_sprint_templates: {} -:default_printer_type_names: [] +:default_pmb_templates: + pmb_templates: + :plate_double: plate_6mm_double_code39 + :plate_a: sqsc_96plate_label_template_code39 + :tube_rack: sqsc_96plate_label_template_code39 + :tube: tube_label_template_1d +:default_sprint_templates: + sprint_templates: + :plate_double: plate_384.yml.erb + :plate_a: plate_96.yml.erb + :tube_rack: plate_96.yml.erb + :tube: tube_label_template_1d.yml.erb +:default_printer_type_names: + printer_type_names: + :plate_double: 384 Well Plate Double + :plate_a: 96 Well Plate + :tube_rack: 96 Well Plate + :tube: 1D Tube :submission_templates: {} :qc_purposes: [] :locations: {} From a8b79101679fe5abb10e6bac7a83a1d56cae509b Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Wed, 20 Aug 2025 11:29:55 +0100 Subject: [PATCH 20/37] Changing the metaprogramming logic to dynamically add mutator methods --- config/initializers/settings.rb | 27 ++++++++++++++++++++------- config/settings/test.yml | 30 ++++-------------------------- 2 files changed, 24 insertions(+), 33 deletions(-) diff --git a/config/initializers/settings.rb b/config/initializers/settings.rb index 3ec2a80810..41309b47a2 100644 --- a/config/initializers/settings.rb +++ b/config/initializers/settings.rb @@ -20,14 +20,27 @@ module Settings # using metaprogramming. For example, when it will add purposes method for Settings, and # when it is invoked, it will use the CustomConfiguration class to send the value for it. CONFIGURATION_TYPES.each do |config| - # Accessor methods - self.class.send(:define_method, config, proc { - value = Settings.configuration.send(config) - value.respond_to?(:children) ? value.children : value - }) - # Mutator methods + # Accessor + unless respond_to?(config) + self.class.send(:define_method, config, proc { + value = Settings.configuration.send(config) + value.respond_to?(:children) ? value.children : value + }) + end + # Mutator + next if respond_to?("#{config}=") + self.class.send(:define_method, "#{config}=", proc { |value| - Settings.configuration.send("#{config}=", value) + config_value = Settings.configuration.send(config) + if config_value.respond_to?(:children) + if config_value.children.is_a?(Hash) && value.is_a?(Hash) + config_value.children.replace(value) + else + Settings.configuration.send("#{config}=", value) + end + else + Settings.configuration.send("#{config}=", value) + end }) end diff --git a/config/settings/test.yml b/config/settings/test.yml index d7ac1efa59..80293ca9ae 100644 --- a/config/settings/test.yml +++ b/config/settings/test.yml @@ -1,37 +1,15 @@ --- :searches: {} -:transfer_templates: - 'Custom pooling': custom-pooling - 'Pool wells based on submission': custom-transfer-template - 'Transfer between specific tubes': transfer-between-specific-tubes - 'Transfer columns 1-12': transfer-1-12 - 'Transfer from tube to tube by submission': tube-to-tube-by-sub - 'Transfer wells to MX library tubes by submission': transfer-to-mx-tubes-on-submission - 'Whole plate to tube': whole-plate-to-tube +:transfer_templates: {} :printers: limit: 5 default_count: 2 :purposes: {} :purpose_uuids: {} :robots: {} -:default_pmb_templates: - pmb_templates: - :plate_double: plate_6mm_double_code39 - :plate_a: sqsc_96plate_label_template_code39 - :tube_rack: sqsc_96plate_label_template_code39 - :tube: tube_label_template_1d -:default_sprint_templates: - sprint_templates: - :plate_double: plate_384.yml.erb - :plate_a: plate_96.yml.erb - :tube_rack: plate_96.yml.erb - :tube: tube_label_template_1d.yml.erb -:default_printer_type_names: - printer_type_names: - :plate_double: 384 Well Plate Double - :plate_a: 96 Well Plate - :tube_rack: 96 Well Plate - :tube: 1D Tube +:default_pmb_templates: {} +:default_sprint_templates: {} +:default_printer_type_names: [] :submission_templates: {} :qc_purposes: [] :locations: {} From d01d39fd91256531c7bf1da831122356242e5181 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Wed, 20 Aug 2025 11:31:07 +0100 Subject: [PATCH 21/37] Changing the metaprogramming logic to dynamically add mutator methods --- config/initializers/settings.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/initializers/settings.rb b/config/initializers/settings.rb index 41309b47a2..0c133b9dea 100644 --- a/config/initializers/settings.rb +++ b/config/initializers/settings.rb @@ -30,11 +30,14 @@ module Settings # Mutator next if respond_to?("#{config}=") + # rubocop:disable Lint/DuplicateBranch self.class.send(:define_method, "#{config}=", proc { |value| config_value = Settings.configuration.send(config) if config_value.respond_to?(:children) if config_value.children.is_a?(Hash) && value.is_a?(Hash) config_value.children.replace(value) + elsif config_value.children.is_a?(Array) && value.is_a?(Array) + config_value.children.replace(value) else Settings.configuration.send("#{config}=", value) end @@ -42,6 +45,7 @@ module Settings Settings.configuration.send("#{config}=", value) end }) + # rubocop:enable Lint/DuplicateBranch end # Delegates Settings.pipelines to the PipelinesLoader From 27a16c525a6832f7b653a1fe843ede4ceb36af98 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Wed, 20 Aug 2025 13:36:40 +0100 Subject: [PATCH 22/37] Updating search helper --- app/helpers/search_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 1f29ed085a..eff47efcf2 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -6,12 +6,12 @@ def stock_plate_uuids end def self.stock_plate_names - Settings.purposes.values.select(&:input_plate).map(&:name) + Settings.purposes.values.select { |item| item[:input_plate] == true }.pluck(:name) end # Returns purpose names of stock plates using stock_plate flag instead of input_plate. def self.stock_plate_names_with_flag - Settings.purposes.values.select(&:stock_plate).map(&:name) + Settings.purposes.values.select { |item| item[:stock_plate] == true }.pluck(:name) end def self.purpose_config_for_purpose_name(purpose_name) From 497b7189fcc129ede52ae3efae69bd1e4197916c Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Wed, 20 Aug 2025 13:59:27 +0100 Subject: [PATCH 23/37] Trying to fix the donor pooling yaml frustratingly!!! --- .../config/poolings/donor_pooling.yml | 192 +++++++++--------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/spec/fixtures/config/poolings/donor_pooling.yml b/spec/fixtures/config/poolings/donor_pooling.yml index ecc363fddb..b45d2a3855 100644 --- a/spec/fixtures/config/poolings/donor_pooling.yml +++ b/spec/fixtures/config/poolings/donor_pooling.yml @@ -3,99 +3,99 @@ donor_pooling: # Maping between number of samples to number of pools. number_of_pools: - 96: 8 - 95: 8 - 94: 8 - 93: 8 - 92: 8 - 91: 8 - 90: 8 - 89: 8 - 88: 8 - 87: 7 - 86: 7 - 85: 7 - 84: 7 - 83: 7 - 82: 7 - 81: 7 - 80: 7 - 79: 7 - 78: 7 - 77: 7 - 76: 6 - 75: 6 - 74: 6 - 73: 6 - 72: 6 - 71: 6 - 70: 6 - 69: 6 - 68: 6 - 67: 6 - 66: 6 - 65: 5 - 64: 5 - 63: 5 - 62: 5 - 61: 5 - 60: 5 - 59: 5 - 58: 5 - 57: 5 - 56: 5 - 55: 5 - 54: 5 - 53: 5 - 52: 4 - 51: 4 - 50: 4 - 49: 4 - 48: 4 - 47: 4 - 46: 4 - 45: 4 - 44: 4 - 43: 4 - 42: 4 - 41: 4 - 40: 4 - 39: 3 - 38: 3 - 37: 3 - 36: 3 - 35: 3 - 34: 3 - 33: 3 - 32: 3 - 31: 3 - 30: 3 - 29: 3 - 28: 3 - 27: 3 - 26: 2 - 25: 2 - 24: 2 - 23: 2 - 22: 2 - 21: 2 - 20: 1 - 19: 1 - 18: 1 - 17: 1 - 16: 1 - 15: 1 - 14: 1 - 13: 1 - 12: 1 - 11: 1 - 10: 1 - 9: 1 - 8: 1 - 7: 1 - 6: 1 - 5: 1 - 4: 1 - 3: 1 - 2: 1 - 1: 1 + "96": 8, + "95": 8, + "94": 8, + "93": 8, + "92": 8, + "91": 8, + "90": 8, + "89": 8, + "88": 8, + "87": 7, + "86": 7, + "85": 7, + "84": 7, + "83": 7, + "82": 7, + "81": 7, + "80": 7, + "79": 7, + "78": 7, + "77": 7, + "76": 6, + "75": 6, + "74": 6, + "73": 6, + "72": 6, + "71": 6, + "70": 6, + "69": 6, + "68": 6, + "67": 6, + "66": 6, + "65": 5, + "64": 5, + "63": 5, + "62": 5, + "61": 5, + "60": 5, + "59": 5, + "58": 5, + "57": 5, + "56": 5, + "55": 5, + "54": 5, + "53": 5, + "52": 4, + "51": 4, + "50": 4, + "49": 4, + "48": 4, + "47": 4, + "46": 4, + "45": 4, + "44": 4, + "43": 4, + "42": 4, + "41": 4, + "40": 4, + "39": 3, + "38": 3, + "37": 3, + "36": 3, + "35": 3, + "34": 3, + "33": 3, + "32": 3, + "31": 3, + "30": 3, + "29": 3, + "28": 3, + "27": 3, + "26": 2, + "25": 2, + "24": 2, + "23": 2, + "22": 2, + "21": 2, + "20": 1, + "19": 1, + "18": 1, + "17": 1, + "16": 1, + "15": 1, + "14": 1, + "13": 1, + "12": 1, + "11": 1, + "10": 1, + "9": 1, + "8": 1, + "7": 1, + "6": 1, + "5": 1, + "4": 1, + "3": 1, + "2": 1, + "1": 1 From 831e592be09108ec2c6ffa8f16a92e182b2969ac Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Wed, 20 Aug 2025 15:19:31 +0100 Subject: [PATCH 24/37] Fixing yet another config issue. --- .../presenters/submission_behaviour.rb | 2 +- .../labware_creators/multi_stamp_tubes.rb | 2 +- app/models/presenters/presenter.rb | 2 +- app/models/presenters/tube_presenter.rb | 4 +- .../config/poolings/donor_pooling.yml | 192 +++++++++--------- 5 files changed, 101 insertions(+), 101 deletions(-) diff --git a/app/models/concerns/presenters/submission_behaviour.rb b/app/models/concerns/presenters/submission_behaviour.rb index 3940061d43..954bd9702e 100644 --- a/app/models/concerns/presenters/submission_behaviour.rb +++ b/app/models/concerns/presenters/submission_behaviour.rb @@ -3,7 +3,7 @@ # Include in a presenter to add support for creating a submission module Presenters::SubmissionBehaviour def each_submission_option - purpose_config.submission_options.each do |button_text, options| + purpose_config[:submission_options].each do |button_text, options| submission_options = options.to_hash submission_options[:asset_groups] = asset_groups submission_options[:labware_barcode] = labware.labware_barcode.human diff --git a/app/models/labware_creators/multi_stamp_tubes.rb b/app/models/labware_creators/multi_stamp_tubes.rb index 6c4d00958d..a0b18bb612 100644 --- a/app/models/labware_creators/multi_stamp_tubes.rb +++ b/app/models/labware_creators/multi_stamp_tubes.rb @@ -125,7 +125,7 @@ def request_hash(transfer) # Returns: a hash containing the submission parameters # Adds: errors if there is more than one submission specified def configured_params - submission_options_from_config = purpose_config.submission_options + submission_options_from_config = purpose_config[:submission_options] # if there's more than one appropriate submission, we can't know which one to choose, # so don't create one. diff --git a/app/models/presenters/presenter.rb b/app/models/presenters/presenter.rb index 2fe917878d..c78d4362a9 100644 --- a/app/models/presenters/presenter.rb +++ b/app/models/presenters/presenter.rb @@ -57,7 +57,7 @@ def content_title end def default_printer - @default_printer ||= Settings.printers[purpose_config.default_printer_type] + @default_printer ||= Settings.printers[purpose_config[:default_printer_type]] end def default_label_count diff --git a/app/models/presenters/tube_presenter.rb b/app/models/presenters/tube_presenter.rb index 40d9b24598..a73a519feb 100644 --- a/app/models/presenters/tube_presenter.rb +++ b/app/models/presenters/tube_presenter.rb @@ -46,9 +46,9 @@ def custom_metadata_fields end def sequencescape_submission - return nil if purpose_config.submission.empty? + return nil if purpose_config[:submission].empty? - s = SequencescapeSubmission.new(purpose_config.submission.to_hash.merge(assets: [labware.uuid])) + s = SequencescapeSubmission.new(purpose_config[:submission].to_hash.merge(assets: [labware.uuid])) yield s if block_given? s end diff --git a/spec/fixtures/config/poolings/donor_pooling.yml b/spec/fixtures/config/poolings/donor_pooling.yml index b45d2a3855..b7a5818d86 100644 --- a/spec/fixtures/config/poolings/donor_pooling.yml +++ b/spec/fixtures/config/poolings/donor_pooling.yml @@ -3,99 +3,99 @@ donor_pooling: # Maping between number of samples to number of pools. number_of_pools: - "96": 8, - "95": 8, - "94": 8, - "93": 8, - "92": 8, - "91": 8, - "90": 8, - "89": 8, - "88": 8, - "87": 7, - "86": 7, - "85": 7, - "84": 7, - "83": 7, - "82": 7, - "81": 7, - "80": 7, - "79": 7, - "78": 7, - "77": 7, - "76": 6, - "75": 6, - "74": 6, - "73": 6, - "72": 6, - "71": 6, - "70": 6, - "69": 6, - "68": 6, - "67": 6, - "66": 6, - "65": 5, - "64": 5, - "63": 5, - "62": 5, - "61": 5, - "60": 5, - "59": 5, - "58": 5, - "57": 5, - "56": 5, - "55": 5, - "54": 5, - "53": 5, - "52": 4, - "51": 4, - "50": 4, - "49": 4, - "48": 4, - "47": 4, - "46": 4, - "45": 4, - "44": 4, - "43": 4, - "42": 4, - "41": 4, - "40": 4, - "39": 3, - "38": 3, - "37": 3, - "36": 3, - "35": 3, - "34": 3, - "33": 3, - "32": 3, - "31": 3, - "30": 3, - "29": 3, - "28": 3, - "27": 3, - "26": 2, - "25": 2, - "24": 2, - "23": 2, - "22": 2, - "21": 2, - "20": 1, - "19": 1, - "18": 1, - "17": 1, - "16": 1, - "15": 1, - "14": 1, - "13": 1, - "12": 1, - "11": 1, - "10": 1, - "9": 1, - "8": 1, - "7": 1, - "6": 1, - "5": 1, - "4": 1, - "3": 1, - "2": 1, - "1": 1 + '96': 8, + '95': 8, + '94': 8, + '93': 8, + '92': 8, + '91': 8, + '90': 8, + '89': 8, + '88': 8, + '87': 7, + '86': 7, + '85': 7, + '84': 7, + '83': 7, + '82': 7, + '81': 7, + '80': 7, + '79': 7, + '78': 7, + '77': 7, + '76': 6, + '75': 6, + '74': 6, + '73': 6, + '72': 6, + '71': 6, + '70': 6, + '69': 6, + '68': 6, + '67': 6, + '66': 6, + '65': 5, + '64': 5, + '63': 5, + '62': 5, + '61': 5, + '60': 5, + '59': 5, + '58': 5, + '57': 5, + '56': 5, + '55': 5, + '54': 5, + '53': 5, + '52': 4, + '51': 4, + '50': 4, + '49': 4, + '48': 4, + '47': 4, + '46': 4, + '45': 4, + '44': 4, + '43': 4, + '42': 4, + '41': 4, + '40': 4, + '39': 3, + '38': 3, + '37': 3, + '36': 3, + '35': 3, + '34': 3, + '33': 3, + '32': 3, + '31': 3, + '30': 3, + '29': 3, + '28': 3, + '27': 3, + '26': 2, + '25': 2, + '24': 2, + '23': 2, + '22': 2, + '21': 2, + '20': 1, + '19': 1, + '18': 1, + '17': 1, + '16': 1, + '15': 1, + '14': 1, + '13': 1, + '12': 1, + '11': 1, + '10': 1, + '9': 1, + '8': 1, + '7': 1, + '6': 1, + '5': 1, + '4': 1, + '3': 1, + '2': 1, + '1': 1 From 77b16ff401de9efe9a0db58655b4bd60b183a557 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Thu, 21 Aug 2025 09:11:15 +0100 Subject: [PATCH 25/37] Fixing yet another config issue. --- app/models/concerns/presenters/creation_behaviour.rb | 2 +- app/models/presenters/plate_presenter.rb | 2 +- config/settings/test.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/concerns/presenters/creation_behaviour.rb b/app/models/concerns/presenters/creation_behaviour.rb index 1b38f06723..52161cbe80 100644 --- a/app/models/concerns/presenters/creation_behaviour.rb +++ b/app/models/concerns/presenters/creation_behaviour.rb @@ -23,7 +23,7 @@ def compatible_tube_rack_purposes # Eventually this will end up on our labware_creators/creations module def purposes_of_type(type) - compatible_purposes.select { |_uuid, purpose| purpose.asset_type == type } + compatible_purposes.select { |_uuid, purpose| purpose[:asset_type] == type } end def construct_buttons(scope) diff --git a/app/models/presenters/plate_presenter.rb b/app/models/presenters/plate_presenter.rb index 7ae03673d0..e68593984d 100644 --- a/app/models/presenters/plate_presenter.rb +++ b/app/models/presenters/plate_presenter.rb @@ -110,7 +110,7 @@ def csv_file_links links = purpose_config .fetch(:file_links, []) - .select { |link| can_be_enabled?(link&.states) } + .select { |link| can_be_enabled?(link & [:states]) } .map do |link| [ link.name, diff --git a/config/settings/test.yml b/config/settings/test.yml index 80293ca9ae..b84ce4173b 100644 --- a/config/settings/test.yml +++ b/config/settings/test.yml @@ -9,7 +9,7 @@ :robots: {} :default_pmb_templates: {} :default_sprint_templates: {} -:default_printer_type_names: [] +:default_printer_type_names: {} :submission_templates: {} :qc_purposes: [] :locations: {} From d17c47eaca57b84b52557ccb33ce8d6f343c43de Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Thu, 21 Aug 2025 09:26:44 +0100 Subject: [PATCH 26/37] Fixing yet another config issue. --- app/models/presenters/tube_presenter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/presenters/tube_presenter.rb b/app/models/presenters/tube_presenter.rb index a73a519feb..5a37ada3d0 100644 --- a/app/models/presenters/tube_presenter.rb +++ b/app/models/presenters/tube_presenter.rb @@ -72,7 +72,7 @@ def transfer_volumes? def csv_file_links purpose_config .fetch(:file_links, []) - .select { |link| can_be_enabled?(link&.states) } + .select { |link| can_be_enabled?(link & [:states]) } .map do |link| format_extension = link.format || 'csv' [ From acf5e2ecc9ffd03619f25931fff8da96cd639ac0 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Thu, 21 Aug 2025 09:32:56 +0100 Subject: [PATCH 27/37] Fixing yet another config issue. --- app/models/presenters/tube_presenter.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/presenters/tube_presenter.rb b/app/models/presenters/tube_presenter.rb index 5a37ada3d0..0727d2e909 100644 --- a/app/models/presenters/tube_presenter.rb +++ b/app/models/presenters/tube_presenter.rb @@ -72,15 +72,15 @@ def transfer_volumes? def csv_file_links purpose_config .fetch(:file_links, []) - .select { |link| can_be_enabled?(link & [:states]) } + .select { |link| can_be_enabled?(link[:states]) } .map do |link| - format_extension = link.format || 'csv' + format_extension = link[:format] || 'csv' [ - link.name, + link[:name], [ :limber_tube, :tubes_export, - { id: link.id, limber_tube_id: human_barcode, format: format_extension, **link.params || {} } + { id: link[:id], limber_tube_id: human_barcode, format: format_extension, **link[:params] || {} } ] ] end From 90c0e170d4a28fff00d858a28cc52f57b20a6618 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Thu, 21 Aug 2025 09:33:18 +0100 Subject: [PATCH 28/37] Fixing yet another config issue. --- app/models/presenters/plate_presenter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/presenters/plate_presenter.rb b/app/models/presenters/plate_presenter.rb index e68593984d..74e5bfcd3d 100644 --- a/app/models/presenters/plate_presenter.rb +++ b/app/models/presenters/plate_presenter.rb @@ -113,11 +113,11 @@ def csv_file_links .select { |link| can_be_enabled?(link & [:states]) } .map do |link| [ - link.name, + link[:name], [ :limber_plate, :export, - { id: link.id, limber_plate_id: human_barcode, format: :csv, **link.params || {} } + { id: link[:id], limber_plate_id: human_barcode, format: :csv, **link[:params] || {} } ] ] end From 20c1e74f6fc56c341b04839b1cbd7bbad13f1b98 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Thu, 21 Aug 2025 09:51:34 +0100 Subject: [PATCH 29/37] Fixing yet another config issue. --- app/models/presenters/plate_presenter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/presenters/plate_presenter.rb b/app/models/presenters/plate_presenter.rb index 74e5bfcd3d..6bad80f164 100644 --- a/app/models/presenters/plate_presenter.rb +++ b/app/models/presenters/plate_presenter.rb @@ -110,7 +110,7 @@ def csv_file_links links = purpose_config .fetch(:file_links, []) - .select { |link| can_be_enabled?(link & [:states]) } + .select { |link| can_be_enabled?(link[:states]) } .map do |link| [ link[:name], From 1fe05e65a34b32ebc2c3f6eb29e0e4103f4ba565 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Thu, 21 Aug 2025 16:16:15 +0100 Subject: [PATCH 30/37] Fixing yet another config issue. --- app/models/concerns/presenters/robot_controlled.rb | 3 +-- .../stamped_plate_adding_randomised_controls.rb | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/models/concerns/presenters/robot_controlled.rb b/app/models/concerns/presenters/robot_controlled.rb index 5ac31bb738..72036022fc 100644 --- a/app/models/concerns/presenters/robot_controlled.rb +++ b/app/models/concerns/presenters/robot_controlled.rb @@ -17,8 +17,7 @@ def suitable_robots end def suitable_for_labware?(config) - config - .beds + config[:beds] .detect { |_bed, bed_config| bed_config.purpose == purpose_name && bed_config.states.include?(labware.state) } .present? end diff --git a/app/models/labware_creators/stamped_plate_adding_randomised_controls.rb b/app/models/labware_creators/stamped_plate_adding_randomised_controls.rb index 0f85990334..428c0bb42d 100644 --- a/app/models/labware_creators/stamped_plate_adding_randomised_controls.rb +++ b/app/models/labware_creators/stamped_plate_adding_randomised_controls.rb @@ -79,9 +79,9 @@ def generate_control_locations_from_purpose_config control_locations = [] list_of_controls.count.times do |control_index| control = list_of_controls[control_index] - if control.fixed_location? + if control[:fixed_location].present? # use the location specified in the purpose config for this control - control_locations.push(control.fixed_location) + control_locations.push(control[:fixed_location]) else # sample a random parent well and fetch its location (child not created yet) control_locations.push(parent.wells.sample.position['name']) @@ -92,13 +92,13 @@ def generate_control_locations_from_purpose_config def check_control_rules_from_config(control_locations) list_of_rules.each do |rule| - case rule.type + case rule[:type] when 'not' # locations must not match this combination of wells (order is important) - return false if control_locations == rule.value + return false if control_locations == rule[:value] when 'well_exclusions' # locations must not be in this list well locations (exclusions) - return false if control_locations.any? { |location| rule.value.include?(location) } + return false if control_locations.any? { |location| rule[:value].include?(location) } else # check for unrecognised rule type raise StandardError, "Unrecognised control locations rule type from purpose config #{rule.type}" From 5ad1a96dabf623a71c9fa298825951f790702b2d Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Tue, 26 Aug 2025 14:07:29 +0100 Subject: [PATCH 31/37] Fixing yet another config issue. --- config/initializers/settings.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/initializers/settings.rb b/config/initializers/settings.rb index 0c133b9dea..1d7ce35395 100644 --- a/config/initializers/settings.rb +++ b/config/initializers/settings.rb @@ -69,6 +69,8 @@ def self.load_yaml config_data.with_indifferent_access end + # Returns an instance of CustomConfiguration that provides access to the + # configuration data loaded from the YAML file. def self.configuration @configuration ||= CustomConfiguration.new(load_yaml) end From d6150bcbb57f1d8f643b71dc3836811597c2b15b Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Wed, 27 Aug 2025 09:00:09 +0100 Subject: [PATCH 32/37] Trying CI out again --- config/initializers/settings.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/config/initializers/settings.rb b/config/initializers/settings.rb index 1d7ce35395..a331427cc5 100644 --- a/config/initializers/settings.rb +++ b/config/initializers/settings.rb @@ -69,6 +69,7 @@ def self.load_yaml config_data.with_indifferent_access end + # Returns an instance of CustomConfiguration that provides access to the # configuration data loaded from the YAML file. def self.configuration From 0eab969e74df0fd4f0c24739cb2626e2ebfd1445 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Wed, 27 Aug 2025 09:15:08 +0100 Subject: [PATCH 33/37] Fix prettier --- config/initializers/settings.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/config/initializers/settings.rb b/config/initializers/settings.rb index a331427cc5..1d7ce35395 100644 --- a/config/initializers/settings.rb +++ b/config/initializers/settings.rb @@ -69,7 +69,6 @@ def self.load_yaml config_data.with_indifferent_access end - # Returns an instance of CustomConfiguration that provides access to the # configuration data loaded from the YAML file. def self.configuration From 1adecd11352090152f9c17d52a632f8caf535f41 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Wed, 27 Aug 2025 09:16:19 +0100 Subject: [PATCH 34/37] Fixing yet another config issue --- app/models/concerns/presenters/robot_controlled.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/concerns/presenters/robot_controlled.rb b/app/models/concerns/presenters/robot_controlled.rb index 72036022fc..f636d29ea2 100644 --- a/app/models/concerns/presenters/robot_controlled.rb +++ b/app/models/concerns/presenters/robot_controlled.rb @@ -18,7 +18,7 @@ def suitable_robots def suitable_for_labware?(config) config[:beds] - .detect { |_bed, bed_config| bed_config.purpose == purpose_name && bed_config.states.include?(labware.state) } + .detect { |_bed, bed_config| bed_config[:purpose] == purpose_name && bed_config[:states].include?(labware.state) } .present? end From 07634e98e4ae09f5f3686b148b21b555e36e3edb Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Wed, 27 Aug 2025 09:17:03 +0100 Subject: [PATCH 35/37] Fixing a linting issue --- app/models/concerns/presenters/robot_controlled.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/concerns/presenters/robot_controlled.rb b/app/models/concerns/presenters/robot_controlled.rb index f636d29ea2..98e9b25d61 100644 --- a/app/models/concerns/presenters/robot_controlled.rb +++ b/app/models/concerns/presenters/robot_controlled.rb @@ -18,7 +18,9 @@ def suitable_robots def suitable_for_labware?(config) config[:beds] - .detect { |_bed, bed_config| bed_config[:purpose] == purpose_name && bed_config[:states].include?(labware.state) } + .detect do |_bed, bed_config| + bed_config[:purpose] == purpose_name && bed_config[:states].include?(labware.state) + end .present? end From 9de6f715ce1b3365e9ce130b75ef34716890d83c Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Wed, 27 Aug 2025 09:26:58 +0100 Subject: [PATCH 36/37] Fixing yet another config issue --- app/models/presenters/tube_rack_presenter.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/models/presenters/tube_rack_presenter.rb b/app/models/presenters/tube_rack_presenter.rb index d11d4ac325..4229738d1f 100644 --- a/app/models/presenters/tube_rack_presenter.rb +++ b/app/models/presenters/tube_rack_presenter.rb @@ -42,9 +42,10 @@ def tube_failing_applicable? def csv_file_links purpose_config .fetch(:file_links, []) - .select { |link| can_be_enabled?(link&.states) } + .select { |link| can_be_enabled?(link[:states]) } .map do |link| - [link.name, [:limber_tube_rack, :tube_racks_export, { id: link.id, limber_tube_rack_id: uuid, format: :csv }]] + [link[:name], + [:limber_tube_rack, :tube_racks_export, { id: link[:id], limber_tube_rack_id: uuid, format: :csv }]] end end From c0104e1a807593b7f565acf3b282ea91537ee34e Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Wed, 27 Aug 2025 09:53:18 +0100 Subject: [PATCH 37/37] Fixing yet another config issue --- app/models/labware_creators/merged_plate.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/labware_creators/merged_plate.rb b/app/models/labware_creators/merged_plate.rb index 61776dda96..622fb0d0cc 100644 --- a/app/models/labware_creators/merged_plate.rb +++ b/app/models/labware_creators/merged_plate.rb @@ -29,7 +29,7 @@ def labware_wells # @return [Array] Purpose name strings. # def expected_source_purposes - Settings.purposes.dig(@purpose_uuid, :merged_plate).source_purposes + Settings.purposes.dig(@purpose_uuid, :merged_plate)[:source_purposes] end # @@ -38,7 +38,7 @@ def expected_source_purposes # @return [String] Some descriptive text. # def help_text - Settings.purposes.dig(@purpose_uuid, :merged_plate).help_text + Settings.purposes.dig(@purpose_uuid, :merged_plate)[:help_text] end def barcodes=(barcodes)