ecoportal-api-v2 1.1.6 → 1.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +54 -15
- data/CHANGELOG.md +17 -2
- data/lib/ecoportal/api/common/concerns/benchmarkable.rb +160 -0
- data/lib/ecoportal/api/common/concerns.rb +10 -0
- data/lib/ecoportal/api/common/content/array_model.rb +82 -79
- data/lib/ecoportal/api/common/content/class_helpers.rb +25 -26
- data/lib/ecoportal/api/common/content/collection_model.rb +108 -84
- data/lib/ecoportal/api/common/content/double_model.rb +125 -87
- data/lib/ecoportal/api/common.v2.rb +1 -0
- data/lib/ecoportal/api/v2/page/component.rb +60 -64
- data/lib/ecoportal/api/v2/page/components.rb +9 -9
- data/lib/ecoportal/api/v2/page/force.rb +5 -6
- data/lib/ecoportal/api/v2/page.rb +13 -14
- data/lib/ecoportal/api/v2_version.rb +1 -1
- metadata +4 -2
@@ -6,12 +6,8 @@ module Ecoportal
|
|
6
6
|
# which differs of `attr_*` ruby native class methods because `pass*`
|
7
7
|
# completelly **links** the methods **to a subjacent `Hash` model**
|
8
8
|
class DoubleModel < Common::BaseModel
|
9
|
-
NOT_USED = Common::Content::ClassHelpers::NOT_USED
|
10
|
-
extend Common::Content::ClassHelpers
|
11
|
-
include Common::Content::ModelHelpers
|
12
|
-
|
13
9
|
class UnlinkedModel < StandardError
|
14
|
-
def initialize
|
10
|
+
def initialize(msg = "Something went wrong when linking the document.", from: nil, key: nil)
|
15
11
|
msg += " From: #{from}." if from
|
16
12
|
msg += " key: #{key}." if key
|
17
13
|
super(msg)
|
@@ -21,6 +17,10 @@ module Ecoportal
|
|
21
17
|
class NoKeyMethod < StandardError
|
22
18
|
end
|
23
19
|
|
20
|
+
NOT_USED = Common::Content::ClassHelpers::NOT_USED
|
21
|
+
extend Common::Content::ClassHelpers
|
22
|
+
include Common::Content::ModelHelpers
|
23
|
+
|
24
24
|
class << self
|
25
25
|
attr_reader :key
|
26
26
|
|
@@ -38,6 +38,16 @@ module Ecoportal
|
|
38
38
|
uid(length)
|
39
39
|
end
|
40
40
|
|
41
|
+
def read_only?
|
42
|
+
@read_only = false if @read_only.nil?
|
43
|
+
@read_only
|
44
|
+
end
|
45
|
+
|
46
|
+
# Be able to define if a class should be read-only
|
47
|
+
def read_only!
|
48
|
+
@read_only = true
|
49
|
+
end
|
50
|
+
|
41
51
|
# Same as `attr_reader` but links to a subjacent `Hash` model property
|
42
52
|
# @note it does **not** create an _instance variable_
|
43
53
|
# @param methods [Array<Symbol>] the method that exposes the value
|
@@ -108,7 +118,7 @@ module Ecoportal
|
|
108
118
|
# as well as its `key` in the underlying `Hash` model.
|
109
119
|
# @param default [Value] the default value that
|
110
120
|
# this `key` will be written in the model when it doesn't exixt
|
111
|
-
def passforced(method, default
|
121
|
+
def passforced(method, default:, read_only: false)
|
112
122
|
model_forced_keys[method.to_s.freeze] = default
|
113
123
|
passthrough(method, read_only: read_only)
|
114
124
|
end
|
@@ -116,8 +126,9 @@ module Ecoportal
|
|
116
126
|
# Ensures `doc` has the `model_forced_keys`. If it doesn't, it adds those missing
|
117
127
|
# with the defined `default` values
|
118
128
|
def enforce!(doc)
|
119
|
-
return unless doc
|
120
|
-
return if
|
129
|
+
return unless doc.is_a?(Hash)
|
130
|
+
return if model_forced_keys.empty?
|
131
|
+
|
121
132
|
model_forced_keys.each do |key, default|
|
122
133
|
doc[key] = default unless doc.key?(key)
|
123
134
|
end
|
@@ -129,8 +140,8 @@ module Ecoportal
|
|
129
140
|
# as well as its `key` in the underlying `Hash` model.
|
130
141
|
# @param read_only [Boolean] should it only define the reader?
|
131
142
|
def passthrough(*methods, read_only: false)
|
132
|
-
pass_reader
|
133
|
-
pass_writer
|
143
|
+
pass_reader(*methods)
|
144
|
+
pass_writer(*methods) unless read_only
|
134
145
|
self
|
135
146
|
end
|
136
147
|
|
@@ -141,9 +152,7 @@ module Ecoportal
|
|
141
152
|
# @param read_only [Boolean] should it only define the reader?
|
142
153
|
def passdate(*methods, read_only: false)
|
143
154
|
pass_reader(*methods) {|value| to_time(value)}
|
144
|
-
unless read_only
|
145
|
-
pass_writer(*methods) {|value| to_time(value)&.iso8601}
|
146
|
-
end
|
155
|
+
pass_writer(*methods) {|value| to_time(value)&.iso8601} unless read_only
|
147
156
|
self
|
148
157
|
end
|
149
158
|
|
@@ -153,9 +162,7 @@ module Ecoportal
|
|
153
162
|
# @param read_only [Boolean] should it only define the reader?
|
154
163
|
def passboolean(*methods, read_only: false)
|
155
164
|
pass_reader(*methods) {|value| value}
|
156
|
-
unless read_only
|
157
|
-
pass_writer(*methods) {|value| !!value}
|
158
|
-
end
|
165
|
+
pass_writer(*methods) {|value| !!value} unless read_only
|
159
166
|
self
|
160
167
|
end
|
161
168
|
|
@@ -176,7 +183,7 @@ module Ecoportal
|
|
176
183
|
|
177
184
|
define_method method do
|
178
185
|
return instance_variable_get(var) if instance_variable_defined?(var)
|
179
|
-
new_obj = dim_class.new(parent: self, key: method, read_only:
|
186
|
+
new_obj = dim_class.new(parent: self, key: method, read_only: read_only?)
|
180
187
|
variable_set(var, new_obj)
|
181
188
|
end
|
182
189
|
end
|
@@ -187,7 +194,7 @@ module Ecoportal
|
|
187
194
|
# @param key [Symbol] the `key` that embeds it to the underlying `Hash` model
|
188
195
|
# @nullable [Boolean] to specify if this object can be `nil`
|
189
196
|
# @param klass [Class, String] the class of the embedded object
|
190
|
-
def embeds_one(method, key: method, nullable: false
|
197
|
+
def embeds_one(method, klass:, key: method, nullable: false)
|
191
198
|
embed(method, key: key, nullable: nullable, multiple: false, klass: klass)
|
192
199
|
end
|
193
200
|
|
@@ -202,73 +209,83 @@ module Ecoportal
|
|
202
209
|
# @param read_only [Boolean] whether or not should try to **work around** items `klass` missing a `key`
|
203
210
|
# - If set to `true` this is meant only for read purposes (won't be able to successufully insert)
|
204
211
|
def embeds_many(method, key: method, klass: nil, enum_class: nil,
|
205
|
-
order_matters: false, order_key: nil, read_only:
|
212
|
+
order_matters: false, order_key: nil, read_only: read_only?)
|
206
213
|
if enum_class
|
207
214
|
eclass = enum_class
|
208
215
|
elsif klass
|
209
216
|
eclass = new_class("#{method}::#{klass}", inherits: Common::Content::CollectionModel) do |dim_class|
|
210
|
-
|
217
|
+
# NOTE: new_class may resolve the namespace of the class to an already existing class
|
218
|
+
dim_class.klass ||= klass
|
211
219
|
dim_class.order_matters = order_matters
|
212
220
|
dim_class.order_key = order_key
|
221
|
+
dim_class.read_only! if read_only
|
213
222
|
end
|
214
223
|
else
|
215
224
|
raise "You should either specify the 'klass' of the elements or the 'enum_class'"
|
216
225
|
end
|
217
|
-
|
226
|
+
|
227
|
+
embed(
|
228
|
+
method, key: key,
|
229
|
+
multiple: true, klass: eclass,
|
230
|
+
read_only: read_only
|
231
|
+
) do |instance_with_called_method|
|
218
232
|
# keep reference to the original class to resolve the `klass` dependency
|
219
233
|
# See stackoverflow: https://stackoverflow.com/a/73709529/4352306
|
220
234
|
referrer_class = instance_with_called_method.class
|
221
|
-
eclass.klass
|
235
|
+
eclass.klass = {referrer_class => klass} if klass
|
236
|
+
# This helps `resolve_class` to correctly resolve a symbol
|
237
|
+
# by using referrer_class as a base module to resolve it
|
222
238
|
end
|
223
239
|
end
|
224
240
|
|
225
241
|
private
|
226
242
|
|
227
|
-
def embed(
|
243
|
+
def embed(
|
244
|
+
method, klass:, key: method,
|
245
|
+
nullable: false, multiple: false, read_only: read_only?,
|
246
|
+
&embed_block
|
247
|
+
)
|
228
248
|
method = method.to_s.freeze
|
229
249
|
var = instance_variable_name(method).freeze
|
230
|
-
|
250
|
+
obj_k = key.to_s.freeze
|
231
251
|
|
232
252
|
# retrieving method (getter)
|
233
253
|
define_method(method) do
|
234
|
-
|
254
|
+
# set item klass as referrer to klass (to allow resolve symbol)
|
255
|
+
embed_block&.call(self)
|
235
256
|
return instance_variable_get(var) if instance_variable_defined?(var)
|
236
|
-
unless nullable
|
237
|
-
doc[k] ||= multiple ? [] : {}
|
238
|
-
end
|
239
|
-
return variable_set(var, nil) unless doc[k]
|
240
257
|
|
241
|
-
|
258
|
+
doc[obj_k] ||= (multiple ? [] : {}) unless nullable
|
259
|
+
return variable_set(var, nil) unless doc[obj_k]
|
242
260
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
embedded_class.new(doc[k], parent: self, key: k, read_only: self._read_only || read_only).tap do |obj|
|
255
|
-
variable_set(var, obj)
|
261
|
+
embedded_class = self.class.resolve_class(klass)
|
262
|
+
setup_items_key(embedded_class, doc[obj_k]) if multiple && read_only
|
263
|
+
|
264
|
+
embedded_class.new(
|
265
|
+
doc[obj_k],
|
266
|
+
parent: self,
|
267
|
+
key: obj_k,
|
268
|
+
read_only: read_only? || read_only
|
269
|
+
).tap do |collection|
|
270
|
+
variable_set(var, collection)
|
256
271
|
end
|
257
272
|
end
|
258
273
|
end
|
259
274
|
|
260
275
|
# The list of keys that will be forced in the model
|
261
276
|
def model_forced_keys
|
262
|
-
@
|
277
|
+
@model_forced_keys ||= {}
|
263
278
|
end
|
264
279
|
end
|
265
280
|
|
266
|
-
inheritable_class_vars :
|
281
|
+
inheritable_class_vars :model_forced_keys, :key, :read_only
|
267
282
|
|
268
|
-
# `_key` refers to the
|
283
|
+
# `_key` refers to the `_parent`'s property that links to this model
|
284
|
+
# @note while `key` refers to the value of theproperty of this model
|
285
|
+
# that is key (identifies an item in a set of elements)
|
269
286
|
attr_reader :_parent, :_key, :_read_only
|
270
287
|
|
271
|
-
def initialize(doc = {}, parent: self, key: nil, read_only:
|
288
|
+
def initialize(doc = {}, parent: self, key: nil, read_only: self.class.read_only?) # rubocop:disable Lint/MissingSuper
|
272
289
|
@_dim_vars = []
|
273
290
|
@_parent = parent || self
|
274
291
|
@_key = key || self
|
@@ -281,10 +298,16 @@ module Ecoportal
|
|
281
298
|
@original_doc = JSON.parse(@doc.to_json)
|
282
299
|
end
|
283
300
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
301
|
+
return unless key_method? && doc && doc.is_a?(Hash)
|
302
|
+
|
303
|
+
self.key = doc[key_method]
|
304
|
+
#puts "\n$(#{self.key}<=>#{self.class})"
|
305
|
+
end
|
306
|
+
|
307
|
+
# @note `read_only` allows for some optimizations, such as storing values
|
308
|
+
# in instance variables, for optimization purposes
|
309
|
+
def read_only?
|
310
|
+
@_read_only
|
288
311
|
end
|
289
312
|
|
290
313
|
def root
|
@@ -294,15 +317,20 @@ module Ecoportal
|
|
294
317
|
|
295
318
|
# @return [String] the `value` of the `key` method (i.e. `id` value)
|
296
319
|
def key
|
297
|
-
raise NoKeyMethod
|
298
|
-
|
320
|
+
raise NoKeyMethod, "No key_method defined for #{self.class}" unless key_method?
|
321
|
+
|
322
|
+
method(key_method).call
|
299
323
|
end
|
300
324
|
|
301
325
|
# @param [String] the `value` of the `key` method (i.e. `id` value)
|
302
326
|
def key=(value)
|
303
|
-
raise NoKeyMethod
|
304
|
-
|
305
|
-
|
327
|
+
raise NoKeyMethod, "No key_method defined for #{self.class}" unless key_method?
|
328
|
+
|
329
|
+
method("#{key_method}=").call(value)
|
330
|
+
end
|
331
|
+
|
332
|
+
def resolved_doc_key
|
333
|
+
[_doc_key(_key)]
|
306
334
|
end
|
307
335
|
|
308
336
|
# Offers a method for child classes to transform the key,
|
@@ -320,25 +348,22 @@ module Ecoportal
|
|
320
348
|
# @return [nil, Hash] the underlying `Hash` model as is (carrying current changes)
|
321
349
|
def doc
|
322
350
|
return @doc if doc_var?
|
351
|
+
|
323
352
|
raise UnlinkedModel.new(from: "#{self.class}#doc", key: _key) unless linked?
|
324
|
-
if is_root?
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
_parent.doc.dig(*[_doc_key(_key)].flatten)
|
330
|
-
end
|
353
|
+
return @doc if is_root?
|
354
|
+
|
355
|
+
# transform parent's `_key` to this object into a
|
356
|
+
# path key that can rerieve from the parents's doc
|
357
|
+
_parent.doc.dig(*resolved_doc_key.flatten)
|
331
358
|
end
|
332
359
|
|
333
360
|
# The `original_doc` holds the model as is now on server-side.
|
334
361
|
# @return [nil, Hash] the underlying `Hash` model as after last `consolidate!` changes
|
335
362
|
def original_doc
|
336
363
|
raise UnlinkedModel.new(from: "#{self.class}#original_doc", key: _key) unless linked?
|
337
|
-
if is_root?
|
338
|
-
|
339
|
-
|
340
|
-
_parent.original_doc.dig(*[_doc_key(_key)].flatten)
|
341
|
-
end
|
364
|
+
return @original_doc if is_root?
|
365
|
+
|
366
|
+
_parent.original_doc.dig(*resolved_doc_key.flatten)
|
342
367
|
end
|
343
368
|
|
344
369
|
def as_json
|
@@ -359,7 +384,7 @@ module Ecoportal
|
|
359
384
|
# @return [Boolean] stating if there are changes
|
360
385
|
def dirty?
|
361
386
|
au = as_update
|
362
|
-
!((au == {}) ||
|
387
|
+
!((au == {}) || au.nil?)
|
363
388
|
end
|
364
389
|
|
365
390
|
# It makes `original_doc` to be like `doc`
|
@@ -379,7 +404,7 @@ module Ecoportal
|
|
379
404
|
if key
|
380
405
|
keys = [key].flatten.compact
|
381
406
|
odoc = original_doc.dig(*keys)
|
382
|
-
odoc
|
407
|
+
odoc &&= JSON.parse(odoc.to_json)
|
383
408
|
dig_set(doc, keys, odoc)
|
384
409
|
else
|
385
410
|
replace_doc(JSON.parse(original_doc.to_json))
|
@@ -393,13 +418,11 @@ module Ecoportal
|
|
393
418
|
|
394
419
|
def replace_doc(new_doc)
|
395
420
|
raise UnlinkedModel.new(from: "#{self.class}#replace_doc", key: _key) unless linked?
|
396
|
-
if is_root?
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
#variables_remove!
|
402
|
-
end
|
421
|
+
return (@doc = new_doc) if is_root?
|
422
|
+
|
423
|
+
dig_set(_parent.doc, resolved_doc_key.flatten, new_doc)
|
424
|
+
_parent.variable_remove!(_key) unless new_doc
|
425
|
+
#variables_remove!
|
403
426
|
end
|
404
427
|
|
405
428
|
protected
|
@@ -408,6 +431,9 @@ module Ecoportal
|
|
408
431
|
!!defined?(@doc)
|
409
432
|
end
|
410
433
|
|
434
|
+
# Both requisites
|
435
|
+
# @note that for optimization purposes, `@doc` var may be used when
|
436
|
+
# the object is `read_only?`
|
411
437
|
def is_root?
|
412
438
|
_parent == self && doc_var?
|
413
439
|
end
|
@@ -418,11 +444,9 @@ module Ecoportal
|
|
418
444
|
|
419
445
|
def replace_original_doc(new_doc)
|
420
446
|
raise UnlinkedModel.new(from: "#{self.class}#replace_original_doc", key: _key) unless linked?
|
421
|
-
if is_root?
|
422
|
-
|
423
|
-
|
424
|
-
dig_set(_parent.original_doc, [_doc_key(_key)].flatten, new_doc)
|
425
|
-
end
|
447
|
+
return (@original_doc = new_doc) if is_root?
|
448
|
+
|
449
|
+
dig_set(_parent.original_doc, resolved_doc_key.flatten, new_doc)
|
426
450
|
end
|
427
451
|
|
428
452
|
# Helper to track down persistent variables
|
@@ -435,16 +459,16 @@ module Ecoportal
|
|
435
459
|
# Helper to remove tracked down instance variables
|
436
460
|
def variable_remove!(key)
|
437
461
|
var = instance_variable_name(key)
|
438
|
-
unless
|
439
|
-
|
440
|
-
|
441
|
-
|
462
|
+
return unless @_dim_vars.include?(var)
|
463
|
+
|
464
|
+
@_dim_vars.delete(var)
|
465
|
+
remove_instance_variable(var)
|
442
466
|
end
|
443
467
|
|
444
468
|
# Removes all the persistent variables
|
445
469
|
def variables_remove!
|
446
470
|
#puts "going to remove vars: #{@_dim_vars} on #{self.class} (parent: #{identify_parent(self._parent)})"
|
447
|
-
@_dim_vars.dup.map {|
|
471
|
+
@_dim_vars.dup.map {|var| variable_remove!(var)}
|
448
472
|
end
|
449
473
|
|
450
474
|
private
|
@@ -482,6 +506,20 @@ module Ecoportal
|
|
482
506
|
self.class.key
|
483
507
|
end
|
484
508
|
|
509
|
+
# It allows to work-around missing item_key
|
510
|
+
def setup_items_key(embedded_class, obj_doc)
|
511
|
+
# only if is going to be a collection
|
512
|
+
return unless obj_doc.is_a?(Array) && embedded_class < Common::Content::CollectionModel
|
513
|
+
return unless (item_class = embedded_class.klass)
|
514
|
+
# if already has key don't need to work around
|
515
|
+
return if item_class&.key
|
516
|
+
|
517
|
+
# apply work around
|
518
|
+
item_class.passkey :id
|
519
|
+
obj_doc.each_with_index do |item_doc, idx|
|
520
|
+
item_doc["id"] = idx.to_s unless item_doc.key?("id")
|
521
|
+
end
|
522
|
+
end
|
485
523
|
end
|
486
524
|
end
|
487
525
|
end
|
@@ -30,65 +30,64 @@ module Ecoportal
|
|
30
30
|
class << self
|
31
31
|
def new_doc(type: nil)
|
32
32
|
{
|
33
|
-
"id"
|
33
|
+
"id" => new_uuid
|
34
34
|
}.tap do |base_doc|
|
35
35
|
if type
|
36
36
|
base_doc.merge!({"type" => type})
|
37
|
-
if klass = get_class(base_doc)
|
37
|
+
if (klass = get_class(base_doc))
|
38
38
|
base_doc.merge!(klass.new_doc || {})
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
def get_class(doc)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
44
|
+
def get_class(doc) # rubocop:disable Metrics/AbcSize
|
45
|
+
return nil unless doc.is_a?(Hash)
|
46
|
+
case doc["type"]
|
47
|
+
when "tag_field"
|
48
|
+
tag_field_class
|
49
|
+
when "geo"
|
50
|
+
geo_field_class
|
51
|
+
when "select"
|
52
|
+
selection_field_class
|
53
|
+
when "date"
|
54
|
+
date_field_class
|
55
|
+
when "number"
|
56
|
+
number_field_class
|
57
|
+
when "gauge"
|
58
|
+
gauge_field_class
|
59
|
+
when "plain_text"
|
60
|
+
plain_text_field_class
|
61
|
+
when "rich_text"
|
62
|
+
rich_text_field_class
|
63
|
+
when "people"
|
64
|
+
people_field_class
|
65
|
+
when "contractor_entities"
|
66
|
+
contractor_entities_field_class
|
67
|
+
when "checklist"
|
68
|
+
checklist_field_class
|
69
|
+
when "page_action", "checklist_task"
|
70
|
+
action_field_class
|
71
|
+
when "actions_list"
|
72
|
+
actions_field_class
|
73
|
+
when "file"
|
74
|
+
files_field_class
|
75
|
+
when "image_gallery"
|
76
|
+
images_field_class
|
77
|
+
when "signature"
|
78
|
+
signature_field_class
|
79
|
+
when "cross_reference"
|
80
|
+
reference_field_class
|
81
|
+
when "law"
|
82
|
+
law_field_class
|
83
|
+
when "mailbox"
|
84
|
+
mailbox_field_class
|
85
|
+
when "chart"
|
86
|
+
chart_field_class
|
87
|
+
when "frequency_rate_chart"
|
88
|
+
chart_fr_field_class
|
89
|
+
else
|
90
|
+
self
|
92
91
|
end
|
93
92
|
end
|
94
93
|
end
|
@@ -103,7 +102,7 @@ module Ecoportal
|
|
103
102
|
passarray :refs
|
104
103
|
|
105
104
|
def ooze
|
106
|
-
|
105
|
+
_parent.ooze
|
107
106
|
end
|
108
107
|
|
109
108
|
def ref_backend
|
@@ -111,9 +110,9 @@ module Ecoportal
|
|
111
110
|
end
|
112
111
|
|
113
112
|
def ref(any_length: false)
|
114
|
-
|
115
|
-
|
116
|
-
|
113
|
+
digest = self.class.hash_label(label, any_length: any_length)
|
114
|
+
return unless digest
|
115
|
+
[type, digest].join(".")
|
117
116
|
end
|
118
117
|
|
119
118
|
# Looks up the section that this component belongs to.
|
@@ -159,7 +158,7 @@ module Ecoportal
|
|
159
158
|
|
160
159
|
# @return [Boolean] `true` if the component is bound to any force, `false` otherwise
|
161
160
|
def bindings?
|
162
|
-
forces.count
|
161
|
+
forces.count&.positive?
|
163
162
|
end
|
164
163
|
|
165
164
|
# If the field has bindings they are replaced by this new field
|
@@ -168,10 +167,10 @@ module Ecoportal
|
|
168
167
|
if fld.section
|
169
168
|
fld.move(section: self.section, before: self)
|
170
169
|
else
|
171
|
-
|
170
|
+
section.add(fld, before: self)
|
172
171
|
end
|
173
172
|
replace_bindings(fld)
|
174
|
-
|
173
|
+
delete!
|
175
174
|
end
|
176
175
|
|
177
176
|
def replace_bindings(fld)
|
@@ -180,12 +179,12 @@ module Ecoportal
|
|
180
179
|
|
181
180
|
def delete!
|
182
181
|
bindings.each {|b| b.delete!}
|
183
|
-
|
184
|
-
|
182
|
+
unattach!
|
183
|
+
_parent.delete!(self)
|
185
184
|
end
|
186
185
|
|
187
186
|
def move(section:, before: nil, after: nil, side: nil)
|
188
|
-
|
187
|
+
unattach!
|
189
188
|
section.add_component(self, before: before, after: after, side: side)
|
190
189
|
end
|
191
190
|
|
@@ -212,9 +211,7 @@ module Ecoportal
|
|
212
211
|
when :hide_reports
|
213
212
|
self.hidden_on_reports = true
|
214
213
|
when Hash
|
215
|
-
if cnf.key?(:global)
|
216
|
-
self.global_binding = cnf[:global]
|
217
|
-
end
|
214
|
+
self.global_binding = cnf[:global] if cnf.key?(:global)
|
218
215
|
else
|
219
216
|
unused.push(cnf)
|
220
217
|
end
|
@@ -222,7 +219,6 @@ module Ecoportal
|
|
222
219
|
raise "Unsupported configuration options '#{unused}' for #{self.class}" unless unused.empty?
|
223
220
|
end
|
224
221
|
end
|
225
|
-
|
226
222
|
end
|
227
223
|
end
|
228
224
|
end
|
@@ -5,28 +5,28 @@ module Ecoportal
|
|
5
5
|
class Components < Common::Content::CollectionModel
|
6
6
|
class_resolver :component_class, "Ecoportal::API::V2::Page::Component"
|
7
7
|
|
8
|
-
|
8
|
+
klass do |doc|
|
9
9
|
component_class.get_class(doc).tap do |klass|
|
10
10
|
klass.key = :id
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
order_matters = true
|
14
|
+
#self.order_matters = true
|
15
15
|
|
16
16
|
def ooze
|
17
|
-
|
17
|
+
_parent.ooze
|
18
18
|
end
|
19
19
|
|
20
20
|
# @return [Ecoportal::API::V2::Page::Component] the field with `id`
|
21
21
|
def get_by_id(id)
|
22
|
-
|
22
|
+
find do |comp|
|
23
23
|
comp.id == id
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
27
|
# @return [Array<Ecoportal::API::V2::Page::Component>] the fields of that `type`
|
28
28
|
def get_by_type(type)
|
29
|
-
|
29
|
+
select do |comp|
|
30
30
|
comp.type.downcase == type.to_s.strip.downcase
|
31
31
|
end
|
32
32
|
end
|
@@ -53,19 +53,19 @@ module Ecoportal
|
|
53
53
|
def add(doc: nil, label: doc && doc["label"], type: doc && doc["type"])
|
54
54
|
fld_doc = doc ? JSON.parse(doc.to_json) : component_class.new_doc(type: type)
|
55
55
|
upsert!(fld_doc) do |fld|
|
56
|
-
fld.label
|
57
|
-
yield(fld)
|
56
|
+
fld.label = label unless doc
|
57
|
+
yield(fld) if block_given?
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
61
|
# @return [Array<Ecoportal::API::V2::Page::Component>] **orphaned** fields (with no section).
|
62
62
|
def unattached
|
63
|
-
|
63
|
+
reject(&:attached?)
|
64
64
|
end
|
65
65
|
|
66
66
|
# @return [Array<Ecoportal::API::V2::Page::Component>] fields belonging to more than one section.
|
67
67
|
def multi_section
|
68
|
-
select
|
68
|
+
select(&:multi_section?)
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|