labimotion 2.3.2 → 2.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -0
- data/lib/labimotion/apis/generic_dataset_api.rb +3 -1
- data/lib/labimotion/apis/generic_element_api.rb +9 -2
- data/lib/labimotion/apis/segment_api.rb +5 -1
- data/lib/labimotion/constants.rb +1 -1
- data/lib/labimotion/entities/generic_klass_entity.rb +11 -0
- data/lib/labimotion/libs/release_metadata.rb +56 -0
- data/lib/labimotion/version.rb +1 -1
- data/lib/labimotion.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3b0302788cd4be249920160317e9a4bc999fe5446a61cadb5d356620da18290b
|
|
4
|
+
data.tar.gz: 8abc1cf487e158576fe998ae09f75cff30f44ac653525a27393e60cb46de1849
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6b03a637a3cc878f8560b806da47301d9edfee557b59d83cb4944cee48df1aca4c35d13a74604f45ab5459a522d443095ecd01a02f35ae61b3ad577015e891b6
|
|
7
|
+
data.tar.gz: 1c7f622321fc6f0d4bac046a9f0b14c94d56dffe3b1cda9e0ee64ca6b0cfd63a09bcf12f41680843e1b4a0313265558658edd0ff64dd62dfd2a04afff27321ca
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* `number`, `integer` and `system-defined` columns accept numbers only. A cell holding anything else is cleared with a warning rather than stored as text, which also cleans up text those columns already hold.
|
|
9
9
|
* Import warnings name the cell they came from (`Cell I6: ...`), so the user can go straight to it in the spreadsheet.
|
|
10
10
|
* Bug fixes:
|
|
11
|
+
* New records and element Reload build from the release's metadata (labimotion#326, port of labimotion#321 and labimotion#324, [chem-generic-ui#1438](https://github.com/cllde8/chem-generic-ui/issues/1438), port of [chem-generic-ui#1430](https://github.com/cllde8/chem-generic-ui/issues/1430)). A klass's `metadata` follows every save, drafts included, so a new element, segment or dataset, and an element brought up to the release by Reload, combined the released layers with the draft's layer groups and restrictions. Klass payloads now carry `metadata_release`: the metadata of the klass's active release, read from its revision row, or `null` when no revision matches the klass's uuid. Sent by `generic_elements/klass`, `segments/list_segment_klass` (nested element klasses included), `generic_dataset/klasses`, and on the nested `element_klass` of the element `GET`, create and update responses, with one revision query per klass family; every other payload is unchanged. A client reading `metadata_release ?? metadata` builds from one version. Read-only: no migration.
|
|
11
12
|
* A copied element, segment or dataset keeps the template release its properties were built on (labimotion#301, labimotion#303). Saves used to stamp every new segment and every dataset save with the klass's current `uuid` and `properties_release`, and an element with whatever the client sent, so a copy of a v1.0.0 record was labelled v2.0.0 and the client never offered Reload. `Labimotion::KlassVersion` now resolves the submitted `properties['klass_uuid']` against the klass's current release and its `*_klasses_revisions`, deleted revisions included, and stores that uuid together with the matching `properties_release`. A new record whose uuid is missing or unknown follows the current release; an existing record keeps its stored uuid when none is sent, then the uuid its stored `properties_release` names, and follows the current release only when it has neither, and a uuid this instance never released (a record imported from an instance with its own release history) keeps the release stored with the record. A new element whose properties carry no uuid follows the template the client built it on; a new segment does the same, and a copied one falls back to the `klass_uuid` of the row it was copied from. The collection import stamps the release the archive names instead of the importing instance's current one: it tries the uuid inside the archived `properties_release`, then `properties['klass_uuid']`, then the `klass_uuid` column, and stores the first one this instance knows with the local release; when none resolves, the archived release keeps the uuid it names (or, naming none, the first uuid the archive carries), and the imported properties carry the same `klass_uuid` as the column. A `klass_uuid` that is not a string is ignored, and a dataset whose klass changed follows the new klass and ignores the client's release. Element create returns 404 when the template is missing or deleted, element update resolves a soft-deleted template (`with_deleted`) before writing anything, and segments and datasets of a deleted template are skipped on save. A new record whose `klass_uuid` this instance cannot resolve keeps it with the `properties_release` the client sent, only when that release names the same uuid. No migration and no client change.
|
|
12
13
|
* `fetch_for_user`: the shared-records branch joined `collection_shares` directly on the element model (an association that only exists on `Collection`), raising `ActiveRecord::ConfigurationError` — rescued into empty search results. Now joins through `collections`. Fixed for both the basic elements (`ElementFetchable`) and the generic element (`Labimotion::Element`), so `search_by_like` and `search_basic_by_like` return shared records again.
|
|
13
14
|
* Dependencies:
|
|
@@ -13,7 +13,9 @@ module Labimotion
|
|
|
13
13
|
desc 'get dataset klasses'
|
|
14
14
|
get do
|
|
15
15
|
list = klass_list(true, false)
|
|
16
|
-
|
|
16
|
+
# New datasets are built from these klasses, so they need the release's metadata.
|
|
17
|
+
present list.sort_by(&:place), with: Labimotion::DatasetKlassEntity, root: 'klass',
|
|
18
|
+
metadata_releases: Labimotion::ReleaseMetadata.map_for(list)
|
|
17
19
|
end
|
|
18
20
|
end
|
|
19
21
|
|
|
@@ -39,7 +39,9 @@ module Labimotion
|
|
|
39
39
|
end
|
|
40
40
|
get do
|
|
41
41
|
ek = Labimotion::ElementKlass.find_by(name: params[:name])
|
|
42
|
-
|
|
42
|
+
# The ELN builds a new element from this klass, so it needs the release's metadata.
|
|
43
|
+
present ek, with: Labimotion::ElementKlassEntity, root: 'klass',
|
|
44
|
+
metadata_releases: Labimotion::ReleaseMetadata.map_for([ek])
|
|
43
45
|
rescue StandardError => e
|
|
44
46
|
Labimotion.log_exception(e, current_user)
|
|
45
47
|
{ klass: [] }
|
|
@@ -474,7 +476,10 @@ module Labimotion
|
|
|
474
476
|
element: Labimotion::ElementEntity.represent(
|
|
475
477
|
element,
|
|
476
478
|
detail_levels: ElementDetailLevelCalculator.new(user: current_user, element: element).detail_levels,
|
|
477
|
-
policy: @element_policy
|
|
479
|
+
policy: @element_policy,
|
|
480
|
+
# Reload brings the record up to the release, so it needs the release's metadata,
|
|
481
|
+
# not the latest save's.
|
|
482
|
+
metadata_releases: Labimotion::ReleaseMetadata.map_for([element.element_klass])
|
|
478
483
|
),
|
|
479
484
|
attachments: Entities::AttachmentEntity.represent(element&.attachments)
|
|
480
485
|
}
|
|
@@ -495,6 +500,7 @@ module Labimotion
|
|
|
495
500
|
with: Labimotion::ElementEntity,
|
|
496
501
|
root: :element,
|
|
497
502
|
detail_levels: ElementDetailLevelCalculator.new(user: current_user, element: element).detail_levels,
|
|
503
|
+
metadata_releases: Labimotion::ReleaseMetadata.map_for([element.element_klass])
|
|
498
504
|
)
|
|
499
505
|
rescue StandardError => e
|
|
500
506
|
Labimotion.log_exception(e, current_user)
|
|
@@ -518,6 +524,7 @@ module Labimotion
|
|
|
518
524
|
element: Labimotion::ElementEntity.represent(
|
|
519
525
|
element,
|
|
520
526
|
detail_levels: ElementDetailLevelCalculator.new(user: current_user, element: element).detail_levels,
|
|
527
|
+
metadata_releases: Labimotion::ReleaseMetadata.map_for([element.element_klass])
|
|
521
528
|
),
|
|
522
529
|
attachments: Entities::AttachmentEntity.represent(element&.attachments),
|
|
523
530
|
}
|
|
@@ -26,7 +26,11 @@ module Labimotion
|
|
|
26
26
|
end
|
|
27
27
|
get do
|
|
28
28
|
list = klass_list(nil, params[:is_active], false)
|
|
29
|
-
|
|
29
|
+
# New segments are built from these klasses. The nested element klasses read the same
|
|
30
|
+
# map, since they are serialized with the same options.
|
|
31
|
+
metadata_releases = Labimotion::ReleaseMetadata.map_for(list.to_a + list.map(&:element_klass))
|
|
32
|
+
present list, with: Labimotion::SegmentKlassEntity, root: 'klass', displayed_in_list: false,
|
|
33
|
+
metadata_releases: metadata_releases
|
|
30
34
|
end
|
|
31
35
|
end
|
|
32
36
|
|
data/lib/labimotion/constants.rb
CHANGED
|
@@ -32,7 +32,7 @@ module Labimotion
|
|
|
32
32
|
module Tpa
|
|
33
33
|
# Segments and layers sent along with reaction variations to a third-party
|
|
34
34
|
# app (see ExportTpaSegments), as segment-klass label => layer keys.
|
|
35
|
-
SEGMENT_LAYERS = { 'Mol interactions' => %w[binding_props bind_partners].freeze }.freeze
|
|
35
|
+
SEGMENT_LAYERS = { 'Mol interactions' => %w[general binding_props bind_partners].freeze }.freeze
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
end
|
|
@@ -10,5 +10,16 @@ module Labimotion
|
|
|
10
10
|
expose :properties_release, **DISPLAYED_IN_LIST_CONDITION, anonymize_with: {}
|
|
11
11
|
expose :metadata, **DISPLAYED_IN_LIST_CONDITION, anonymize_with: {}
|
|
12
12
|
expose_timestamps(timestamp_fields: %i[released_at created_at updated_at sync_time])
|
|
13
|
+
|
|
14
|
+
# The klass's own `metadata` follows every save, drafts included, so a client building a
|
|
15
|
+
# record from `properties_release` reads this instead: the metadata that release was cut
|
|
16
|
+
# with, or nil when no revision matches the klass's uuid (never released, or imported
|
|
17
|
+
# without one). Exposed only where the endpoint preloaded the map, so no other payload pays
|
|
18
|
+
# a revision query per row.
|
|
19
|
+
expose :metadata_release, **DISPLAYED_IN_LIST_CONDITION, if: :metadata_releases
|
|
20
|
+
|
|
21
|
+
def metadata_release
|
|
22
|
+
options[:metadata_releases][Labimotion::ReleaseMetadata.key_of(object)]
|
|
23
|
+
end
|
|
13
24
|
end
|
|
14
25
|
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# `underscore`, `constantize` and `index_by` are ActiveSupport core extensions, not plain
|
|
4
|
+
# Ruby. A booted host always has them; declaring them here keeps this file from depending on
|
|
5
|
+
# load order.
|
|
6
|
+
require 'active_support/core_ext/enumerable'
|
|
7
|
+
require 'active_support/core_ext/string/inflections'
|
|
8
|
+
|
|
9
|
+
module Labimotion
|
|
10
|
+
## ReleaseMetadata
|
|
11
|
+
# Builds the `metadata_releases:` option the klass entities read: each klass's metadata as
|
|
12
|
+
# of its active release. The klass row's own `metadata` follows every save, drafts included,
|
|
13
|
+
# so a client building a record from `properties_release` needs the copy kept on the revision.
|
|
14
|
+
# The active revision is the one whose uuid equals the klass's, which changes only on release.
|
|
15
|
+
class ReleaseMetadata
|
|
16
|
+
# A klass with no revision matching its uuid (never released, or imported without one)
|
|
17
|
+
# is left out of the map, and the entity reads it as nil.
|
|
18
|
+
def self.map_for(klasses)
|
|
19
|
+
Array(klasses).compact.group_by(&:class).each_with_object({}) do |(model, group), map|
|
|
20
|
+
map.merge!(map_for_family(model, group))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Family as well as id: a segment klass payload nests its element klass, and ids repeat
|
|
25
|
+
# across the klass tables.
|
|
26
|
+
def self.key_of(klass)
|
|
27
|
+
"#{klass.class.name.split('::').last}:#{klass.id}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.map_for_family(model, klasses)
|
|
31
|
+
by_pair = klasses.reject { |klass| klass.uuid.nil? }.index_by { |klass| [klass.id, klass.uuid] }
|
|
32
|
+
return {} if by_pair.empty?
|
|
33
|
+
|
|
34
|
+
revisions_for(model, by_pair.keys).each_with_object({}) do |(klass_id, uuid, metadata), map|
|
|
35
|
+
# The IN lists cross-match: a revision of one listed klass can carry the uuid of
|
|
36
|
+
# another. Only the exact pair is that klass's active release.
|
|
37
|
+
klass = by_pair[[klass_id, uuid]]
|
|
38
|
+
map[key_of(klass)] = metadata unless klass.nil?
|
|
39
|
+
end
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
# The release metadata is an addition to a list that must still render, and a failing
|
|
42
|
+
# family must not blank the families that resolved.
|
|
43
|
+
Labimotion.log_exception(e)
|
|
44
|
+
{}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# The revision model and its foreign key are named after the klass model.
|
|
48
|
+
def self.revisions_for(model, pairs)
|
|
49
|
+
foreign_key = "#{model.name.underscore.split('/').last}_id"
|
|
50
|
+
"#{model.name}esRevision".constantize
|
|
51
|
+
.where(foreign_key => pairs.map(&:first), uuid: pairs.map(&:last))
|
|
52
|
+
.pluck(foreign_key, :uuid, :metadata)
|
|
53
|
+
end
|
|
54
|
+
private_class_method :map_for_family, :revisions_for
|
|
55
|
+
end
|
|
56
|
+
end
|
data/lib/labimotion/version.rb
CHANGED
data/lib/labimotion.rb
CHANGED
|
@@ -95,6 +95,7 @@ module Labimotion
|
|
|
95
95
|
autoload :SampleAssociation, 'labimotion/libs/sample_association'
|
|
96
96
|
autoload :PropertiesHandler, 'labimotion/libs/properties_handler'
|
|
97
97
|
autoload :KlassVersion, 'labimotion/libs/klass_version'
|
|
98
|
+
autoload :ReleaseMetadata, 'labimotion/libs/release_metadata'
|
|
98
99
|
autoload :AttachmentHandler, 'labimotion/libs/attachment_handler'
|
|
99
100
|
autoload :VocabularyHandler, 'labimotion/libs/vocabulary_handler'
|
|
100
101
|
autoload :XlsxExporter, 'labimotion/libs/xlsx_exporter'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: labimotion
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.3.
|
|
4
|
+
version: 2.3.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chia-Lin Lin
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2026-10-
|
|
12
|
+
date: 2026-10-19 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: caxlsx
|
|
@@ -140,6 +140,7 @@ files:
|
|
|
140
140
|
- lib/labimotion/libs/klass_version.rb
|
|
141
141
|
- lib/labimotion/libs/nmr_mapper.rb
|
|
142
142
|
- lib/labimotion/libs/properties_handler.rb
|
|
143
|
+
- lib/labimotion/libs/release_metadata.rb
|
|
143
144
|
- lib/labimotion/libs/sample_association.rb
|
|
144
145
|
- lib/labimotion/libs/template_hub.rb
|
|
145
146
|
- lib/labimotion/libs/template_matcher.rb
|