Class: Labimotion::LinkedElement
- Inherits:
-
Object
- Object
- Labimotion::LinkedElement
- Defined in:
- lib/labimotion/libs/linked_element.rb
Overview
Resolves the "inline attributes" of an element linked from a generic drag_element field.
A drag_element link target is identified by the stored value's el_klass:
* a generic element klass name -> the target is a Labimotion::Element and
its selectable attributes are its own property fields (layer + field);
* a permit-target key (reaction, sample, molecule, wellplate, screen,
research_plan, device_description, cell_line) -> the target is a standard
ELN model and its selectable attributes are a curated set of database columns.
Used both to list the attributes a user can pick (#available) and to refresh the current values of a previously stored selection (#resolve).
Constant Summary collapse
- SOURCE_PROPERTY =
'property'- SOURCE_COLUMN =
'column'- IS_DEFAULT =
Marks an attribute injected from the user's stored default rather than picked on this element. Stripped again before properties are persisted, so a default never silently becomes an explicit per-instance selection.
'is_default'- MODELS =
el_klass (permit-target key) => model class name
{ 'reaction' => '::Reaction', 'sample' => '::Sample', 'molecule' => '::Molecule', 'wellplate' => '::Wellplate', 'screen' => '::Screen', 'research_plan' => '::ResearchPlan', 'device_description' => '::DeviceDescription', 'cell_line' => '::CelllineSample' }.freeze
- PERMIT_TARGET_LABELS =
Display names for the above, for screens that list the linkable types.
{ 'reaction' => 'Reaction', 'sample' => 'Sample', 'molecule' => 'Molecule', 'wellplate' => 'Wellplate', 'screen' => 'Screen', 'research_plan' => 'Research Plan', 'device_description' => 'Device Description', 'cell_line' => 'Cell Line' }.freeze
- COLUMNS =
Curated, scalar columns exposed per type: [column/method, label, unit_column?]
{ 'reaction' => [ %w[name Name], %w[short_label], ['status', 'Status'], ['role', 'Role'], ['rxno', 'Reaction Type'], ['conditions', 'Conditions'], ['duration', 'Duration'], %w[solvent Solvent] ], 'sample' => [ %w[name Name], %w[short_label], ['external_label', 'External Label'], ['sum_formula', 'Sum Formula'], ['molecular_mass', 'Molecular Mass'], %w[purity Purity], %w[density Density], ['real_amount_value', 'Real Amount', 'real_amount_unit'], ['target_amount_value', 'Target Amount', 'target_amount_unit'], %w[location Location] ], 'molecule' => [ ['iupac_name', 'IUPAC Name'], ['sum_formular', 'Sum Formula'], ['molecular_weight', 'Molecular Weight'], ['exact_molecular_weight', 'Exact Molecular Weight'], ['cano_smiles', 'Canonical SMILES'], ['melting_point', 'Melting Point'], ['boiling_point', 'Boiling Point'], %w[density Density] ], 'wellplate' => [ %w[name Name], %w[short_label], ['description', 'Description'], %w[width Width], %w[height Height] ], 'screen' => [ %w[name Name], ['description', 'Description'], %w[result Result], %w[collaborator Collaborator], ['conditions', 'Conditions'], %w[requirements Requirements] ], 'research_plan' => [ %w[name Name], %w[short_label] ], 'device_description' => [ %w[name Name], %w[short_label], ['serial_number', 'Serial Number'], ['device_class', 'Device Class'], ['operation_mode', 'Operation Mode'], ['application_name', 'Application Name'], ['vendor_url', 'Vendor URL'], %w[institute Institute], %w[building Building], %w[room Room] ], 'cell_line' => [ ['material_name', 'Cell line name'], ['name', 'Name of specific sample'], %w[short_label], %w[description Description], %w[amount Amount unit], %w[passage Passage], %w[contamination Contamination] ] }.freeze
- PROPERTY_TYPES =
Property field types whose value is a scalar worth surfacing inline.
%w[ text textarea number integer select select-multi checkbox datetime system-defined formula-field text-formula ontology-select ].freeze
Class Method Summary collapse
-
.available_for_klass(el_klass) ⇒ Object
The attributes a user can pick for a klass with no element instance to read values from — the settings screen picks defaults before any link exists.
-
.permit_targets ⇒ Object
The standard ELN types a drag field can link, for a settings screen that has to enumerate them.
-
.strip_defaults(properties) ⇒ Object
Remove attributes injected from a user's default (marked IS_DEFAULT by PropertiesEntity) from a properties hash on its way to the database.
Instance Method Summary collapse
-
#available ⇒ Object
All attributes the user can pick, each with its current value.
- #column_based? ⇒ Boolean
- #generic? ⇒ Boolean
-
#initialize(el_klass, el_id, el_type = nil) ⇒ LinkedElement
constructor
A new instance of LinkedElement.
- #record ⇒ Object
-
#resolve(selected) ⇒ Object
Refresh the values/labels of a previously stored selection.
-
#target_key ⇒ Object
drag_element keeps the linked class in
el_klass; drag_sample / drag_molecule keep it inel_type(and may omit el_klass).
Constructor Details
#initialize(el_klass, el_id, el_type = nil) ⇒ LinkedElement
Returns a new instance of LinkedElement.
98 99 100 101 102 |
# File 'lib/labimotion/libs/linked_element.rb', line 98 def initialize(el_klass, el_id, el_type = nil) @el_klass = el_klass.to_s @el_type = el_type.to_s @el_id = el_id end |
Class Method Details
.available_for_klass(el_klass) ⇒ Object
The attributes a user can pick for a klass with no element instance to read values from — the settings screen picks defaults before any link exists. Same shape as #available, minus 'value'/'value_system'.
164 165 166 167 168 169 170 |
# File 'lib/labimotion/libs/linked_element.rb', line 164 def self.available_for_klass(el_klass) el_klass = el_klass.to_s return column_attributes_for_klass(el_klass) if MODELS.key?(el_klass) klass = Labimotion::ElementKlass.find_by(name: el_klass) klass.present? ? property_attributes_for_klass(klass) : [] end |
.permit_targets ⇒ Object
The standard ELN types a drag field can link, for a settings screen that has to enumerate them. MODELS is the authority here, not the wider permit-target list: 'element' and 'generic_grid' are permit targets but not linkable types.
218 219 220 |
# File 'lib/labimotion/libs/linked_element.rb', line 218 def self.permit_targets MODELS.keys.map { |key| { 'key' => key, 'label' => PERMIT_TARGET_LABELS[key] || key.humanize } } end |
.strip_defaults(properties) ⇒ Object
Remove attributes injected from a user's default (marked IS_DEFAULT by PropertiesEntity) from a properties hash on its way to the database. They are display-only: persisting them would freeze today's default into the element as an explicit per-instance selection, and a later change to the default would then stop reaching this link.
177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/labimotion/libs/linked_element.rb', line 177 def self.strip_defaults(properties) layers = properties.is_a?(Hash) ? properties[Labimotion::Prop::LAYERS] : nil return properties unless layers.is_a?(Hash) layers.each_value do |layer| fields = layer.is_a?(Hash) ? layer[Labimotion::Prop::FIELDS] : nil next unless fields.is_a?(Array) fields.each { |field| strip_field_defaults(field) } end properties end |
Instance Method Details
#available ⇒ Object
All attributes the user can pick, each with its current value.
139 140 141 142 143 144 |
# File 'lib/labimotion/libs/linked_element.rb', line 139 def available return generic_attributes if generic? return column_attributes if column_based? [] end |
#column_based? ⇒ Boolean
119 120 121 |
# File 'lib/labimotion/libs/linked_element.rb', line 119 def column_based? MODELS.key?(target_key) end |
#generic? ⇒ Boolean
123 124 125 |
# File 'lib/labimotion/libs/linked_element.rb', line 123 def generic? generic_klass?(target_key) end |
#record ⇒ Object
127 128 129 130 131 132 133 134 135 136 |
# File 'lib/labimotion/libs/linked_element.rb', line 127 def record return @record if defined?(@record) @record = if column_based? MODELS[target_key].safe_constantize&.find_by(id: @el_id) elsif generic? Labimotion::Element.find_by(id: @el_id) end end |
#resolve(selected) ⇒ Object
Refresh the values/labels of a previously stored selection. Selections whose source attribute no longer exists are kept but flagged as missing; for an unknown/unsupported el_klass the selection is returned untouched.
149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/labimotion/libs/linked_element.rb', line 149 def resolve(selected) return selected unless selected.is_a?(Array) return selected unless generic? || column_based? index = available.index_by { |a| [a['source'], a['key']] } selected.map do |attr| next attr unless attr.is_a?(Hash) index[[attr['source'], attr['key']]] || attr.merge('value' => nil, 'missing' => true) end end |
#target_key ⇒ Object
drag_element keeps the linked class in el_klass; drag_sample / drag_molecule
keep it in el_type (and may omit el_klass). Resolve one effective dispatch key.
106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/labimotion/libs/linked_element.rb', line 106 def target_key return @target_key if defined?(@target_key) @target_key = if MODELS.key?(@el_klass) || generic_klass?(@el_klass) @el_klass elsif MODELS.key?(@el_type) @el_type else '' end end |