metadata_presenter 2.7.2 → 2.11.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48503ea21820959e21824490a615c78e27fd5b7eece419141b8105a0e91f4ad6
4
- data.tar.gz: ad0c43095f40f524e6cec36e339a0deadc490f50d0686324cb9666827fa979ca
3
+ metadata.gz: 6cca8a3428e516ba176e5a898a1d1a76cd57fa836041f0c3fc492a8cd394e88a
4
+ data.tar.gz: 9940b709ccce5e211444fe6b7cf84dfeed78f1c13591c9291b797a3eca4ac609
5
5
  SHA512:
6
- metadata.gz: 35b20dc2f7539ae53d0360845513bb0c0859281c54c4dd21542a650636a5fb545132322e325bdc4511e176d60c629f78b46d1cd4a4fc6791c2fe573c9beb9316
7
- data.tar.gz: 482185c1044b0013f3875255c4a94482de1882adbecb749352f4cb797c9d5a762ede00f4d3c4348c4d8c124ee5f36ddbd85fc7905ea53765965c0cafe69ff3fb
6
+ metadata.gz: 1b9c3ae006ca76d0386db74a2fb39d106884dc0cd285457c05be6f3d3f75e2a30cc79511112d3881c532ba7e6e3c087e5e83e4116a708cf3cd81b4ea345de813
7
+ data.tar.gz: 659da027fb5c27df2c007dfd961bfce0148879aec3833f72c53f4d195080bde041b29c53260c397430e5425383a2c7a364e1ed8fd4d22bbabdb33417ecb896ed
@@ -0,0 +1,18 @@
1
+ module MetadataPresenter
2
+ module BranchDestinations
3
+ # The frontend requires that expressions of type 'or' get there own line and
4
+ # arrow. 'and' expression types continue to be grouped together.
5
+ # Return the UUIDs of the destinations exiting a branch and allow duplicates
6
+ # if the expression type is an 'or'.
7
+ def exiting_destinations_from_branch(branch)
8
+ destination_uuids = branch.conditionals.map do |conditional|
9
+ if conditional.type == 'or'
10
+ conditional.expressions.map { |_| conditional.next }
11
+ else
12
+ conditional.next
13
+ end
14
+ end
15
+ destination_uuids.flatten.push(branch.default_next)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module MetadataPresenter
2
+ class ColumnNumber
3
+ def initialize(uuid:, coordinates:, new_column:)
4
+ @uuid = uuid
5
+ @coordinates = coordinates
6
+ @new_column = new_column
7
+ end
8
+
9
+ def number
10
+ use_new_column? ? new_column : existing_column
11
+ end
12
+
13
+ private
14
+
15
+ attr_reader :uuid, :coordinates, :new_column
16
+
17
+ def use_new_column?
18
+ existing_column.nil? || new_column > existing_column
19
+ end
20
+
21
+ def existing_column
22
+ @existing_column ||= @coordinates.uuid_column(uuid)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,59 @@
1
+ module MetadataPresenter
2
+ class Coordinates
3
+ def initialize(flow)
4
+ @flow = flow
5
+ @positions = setup_positions
6
+ end
7
+
8
+ attr_reader :positions
9
+
10
+ def set_column(uuid, number)
11
+ positions[uuid][:column] = number
12
+ end
13
+
14
+ def set_row(uuid, number)
15
+ positions[uuid][:row] = number
16
+ end
17
+
18
+ def uuid_column(uuid)
19
+ positions[uuid][:column]
20
+ end
21
+
22
+ def uuid_row(uuid)
23
+ positions[uuid][:row]
24
+ end
25
+
26
+ def uuid_at_position(column, row)
27
+ positions.find do |uuid, position|
28
+ if position[:column] == column && position[:row] == row
29
+ return uuid
30
+ end
31
+ end
32
+ end
33
+
34
+ def position(uuid)
35
+ positions[uuid]
36
+ end
37
+
38
+ def occupied?(column, row, new_object_uuid)
39
+ positions.any? do |uuid, position|
40
+ position[:column] == column &&
41
+ position[:row] == row &&
42
+ new_object_uuid != uuid
43
+ end
44
+ end
45
+
46
+ def positions_in_column(column_number)
47
+ positions.select { |_, position| position[:column] == column_number }
48
+ end
49
+
50
+ private
51
+
52
+ attr_reader :flow
53
+ attr_writer :positions
54
+
55
+ def setup_positions
56
+ flow.keys.index_with { |_uuid| { row: nil, column: nil } }
57
+ end
58
+ end
59
+ end
@@ -12,6 +12,7 @@ module MetadataPresenter
12
12
  end
13
13
 
14
14
  class Grid
15
+ include BranchDestinations
15
16
  attr_reader :start_from
16
17
 
17
18
  def initialize(service, start_from: nil, main_flow: [])
@@ -21,7 +22,7 @@ module MetadataPresenter
21
22
  @ordered = []
22
23
  @routes = []
23
24
  @traversed = []
24
- @coordinates = setup_coordinates
25
+ @coordinates = MetadataPresenter::Coordinates.new(service.flow)
25
26
  end
26
27
 
27
28
  ROW_ZERO = 0
@@ -30,8 +31,8 @@ module MetadataPresenter
30
31
  return @ordered unless @ordered.empty?
31
32
 
32
33
  @ordered = make_grid
33
- add_columns
34
- add_rows
34
+ set_column_numbers
35
+ set_row_numbers
35
36
  add_by_coordinates
36
37
  insert_expression_spacers
37
38
  trim_pointers unless main_flow.empty?
@@ -62,10 +63,6 @@ module MetadataPresenter
62
63
  attr_reader :service, :main_flow
63
64
  attr_accessor :ordered, :traversed, :routes, :coordinates
64
65
 
65
- def setup_coordinates
66
- service.flow.keys.index_with { |_uuid| { row: nil, column: nil } }
67
- end
68
-
69
66
  def route_from_start
70
67
  @route_from_start ||=
71
68
  MetadataPresenter::Route.new(
@@ -83,7 +80,12 @@ module MetadataPresenter
83
80
  end
84
81
 
85
82
  def max_potential_rows
86
- @max_potential_rows ||= @routes.map(&:row).max + 1
83
+ @max_potential_rows ||= begin
84
+ destinations_count = service.branches.map do |branch|
85
+ exiting_destinations_from_branch(branch).count
86
+ end
87
+ destinations_count.sum
88
+ end
87
89
  end
88
90
 
89
91
  def max_potential_columns
@@ -121,30 +123,47 @@ module MetadataPresenter
121
123
  end
122
124
  end
123
125
 
124
- def add_columns
126
+ def set_column_numbers
125
127
  @routes.each do |route|
126
- route.flow_uuids.each.with_index(route.column) do |uuid, column|
127
- column_number = @coordinates[uuid][:column]
128
- if column_number.nil? || column > column_number
129
- @coordinates[uuid][:column] = column
130
- end
128
+ route.flow_uuids.each.with_index(route.column) do |uuid, new_column|
129
+ column_number = MetadataPresenter::ColumnNumber.new(
130
+ uuid: uuid,
131
+ new_column: new_column,
132
+ coordinates: @coordinates
133
+ ).number
134
+ @coordinates.set_column(uuid, column_number)
131
135
  end
132
136
  end
133
137
  end
134
138
 
135
- def add_rows
139
+ def set_row_numbers
136
140
  @routes.each do |route|
137
- route.flow_uuids.each do |uuid|
138
- next if @traversed.include?(uuid)
141
+ next if @traversed.include?(route.traverse_from) && appears_later_in_flow?(route)
139
142
 
140
- @coordinates[uuid][:row] = route.row if @coordinates[uuid][:row].nil?
143
+ current_row = route.row
144
+ route.flow_uuids.each do |uuid|
145
+ row_number = MetadataPresenter::RowNumber.new(
146
+ uuid: uuid,
147
+ route: route,
148
+ current_row: current_row,
149
+ coordinates: @coordinates,
150
+ service: service
151
+ ).number
152
+ @coordinates.set_row(uuid, row_number)
141
153
 
142
154
  update_route_rows(route, uuid)
143
- @traversed.push(uuid)
155
+ @traversed.push(uuid) unless @traversed.include?(uuid)
156
+ current_row = row_number
144
157
  end
145
158
  end
146
159
  end
147
160
 
161
+ # New routes can be linked to later. We need to also traverse these to see
162
+ # if anything should be moved to a different row.
163
+ def appears_later_in_flow?(route)
164
+ @coordinates.uuid_column(route.traverse_from) > route.column
165
+ end
166
+
148
167
  # Each Route object has a starting row. Each Route object has no knowledge
149
168
  # of other potential routes and pages/branches that may or may not exist in
150
169
  # them. The starting row may need to change dependent upon what has been
@@ -162,7 +181,8 @@ module MetadataPresenter
162
181
  end
163
182
 
164
183
  def add_by_coordinates
165
- @coordinates.each do |uuid, position|
184
+ service.flow.each_key do |uuid|
185
+ position = coordinates.position(uuid)
166
186
  next if detached?(position)
167
187
 
168
188
  @ordered[position[:column]][position[:row]] = get_flow_object(uuid)
@@ -202,12 +222,12 @@ module MetadataPresenter
202
222
  # Find the very last MetadataPresenter::Flow object in every column and
203
223
  # remove any Spacer objects after that.
204
224
  def trim_spacers
205
- @ordered.each_with_index do |column, index|
225
+ @ordered.each_with_index do |column, column_number|
206
226
  last_index_of = column.rindex { |item| !item.is_a?(MetadataPresenter::Spacer) }
207
- trimmed_column = @ordered[index][0..last_index_of]
227
+ trimmed_column = @ordered[column_number][0..last_index_of]
208
228
 
209
229
  # We do not need any columns that only contain Spacer objects
210
- @ordered[index] = only_spacers?(trimmed_column) ? [] : trimmed_column
230
+ @ordered[column_number] = only_spacers?(trimmed_column) ? [] : trimmed_column
211
231
  end
212
232
  end
213
233
 
@@ -220,37 +240,23 @@ module MetadataPresenter
220
240
  # the one the branch is located in.
221
241
  def insert_expression_spacers
222
242
  service.branches.each do |branch|
223
- position = @coordinates[branch.uuid]
224
- next if position[:row].nil? || position[:column].nil? # detached branch
243
+ next if coordinates.uuid_column(branch.uuid).nil?
225
244
 
226
- next_column = position[:column] + 1
227
- uuids = []
228
- exiting_destinations_from_branch(branch).each.with_index(position[:row]) do |uuid, row|
229
- if uuids.include?(uuid)
245
+ previous_uuid = ''
246
+ next_column = coordinates.uuid_column(branch.uuid) + 1
247
+ exiting_destinations_from_branch(branch).each_with_index do |uuid, row|
248
+ if uuid == previous_uuid
230
249
  @ordered[next_column].insert(row, MetadataPresenter::Spacer.new)
231
250
  end
232
-
233
- uuids.push(uuid) unless uuids.include?(uuid)
234
- end
235
- end
236
- end
237
-
238
- # The frontend requires that expressions of type 'or' get there own line and
239
- # arrow. 'and' expression types continue to be grouped together.
240
- # Return the UUIDs of the destinations exiting a branch and allow duplicates
241
- # if the expression type is an 'or'.
242
- def exiting_destinations_from_branch(branch)
243
- destination_uuids = branch.conditionals.map do |conditional|
244
- if conditional.type == 'or'
245
- conditional.expressions.map(&:next)
246
- else
247
- conditional.next
251
+ previous_uuid = uuid
248
252
  end
249
253
  end
250
- destination_uuids.flatten
251
254
  end
252
255
 
253
256
  # Any destinations exiting the branch that have not already been traversed.
257
+ # This removes any branch destinations that already exist on other rows. If
258
+ # that is the case then the arrow will flow towards whatever row that object
259
+ # is located.
254
260
  def routes_exiting_branch(branch)
255
261
  branch.all_destination_uuids.reject { |uuid| @traversed.include?(uuid) }
256
262
  end
@@ -0,0 +1,71 @@
1
+ module MetadataPresenter
2
+ class RowNumber
3
+ include BranchDestinations
4
+
5
+ def initialize(uuid:, route:, current_row:, coordinates:, service:)
6
+ @uuid = uuid
7
+ @route = route
8
+ @current_row = current_row
9
+ @coordinates = coordinates
10
+ @service = service
11
+ end
12
+
13
+ ROW_ZERO = 0
14
+
15
+ def number
16
+ return route.row if first_row? && existing_row.nil?
17
+
18
+ return ROW_ZERO if place_on_row_zero?
19
+
20
+ if object_above.branch? && uuid != object_above.uuid
21
+ coordinates.uuid_row(object_above.uuid) + number_of_destinations
22
+ else
23
+ existing_row.nil? ? current_row : [current_row, existing_row].max
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :uuid, :route, :current_row, :coordinates, :service
30
+
31
+ def existing_row
32
+ @existing_row ||= coordinates.uuid_row(uuid)
33
+ end
34
+
35
+ def first_row?
36
+ @first_row ||= route.row.zero?
37
+ end
38
+
39
+ def object_above
40
+ @object_above ||=
41
+ service.flow_object(coordinates.uuid_at_position(uuid_column, row_above))
42
+ end
43
+
44
+ # Takes into account the 'or' type of conditionals which requires an
45
+ # additional spacer
46
+ def number_of_destinations
47
+ exiting_destinations_from_branch(object_above).count
48
+ end
49
+
50
+ def uuid_column
51
+ @uuid_column ||= coordinates.uuid_column(uuid)
52
+ end
53
+
54
+ def row_above
55
+ @row_above ||= route.row - 1
56
+ end
57
+
58
+ # If an object has already been positioned on row 0 then leave it there.
59
+ # If the object is a checkanswers or confirmation type then always place it
60
+ # on row 0.
61
+ def place_on_row_zero?
62
+ cya_or_confirmation_page? || coordinates.uuid_row(uuid) == ROW_ZERO
63
+ end
64
+
65
+ def cya_or_confirmation_page?
66
+ %w[page.checkanswers page.confirmation].include?(
67
+ service.find_page_by_uuid(uuid)&.type
68
+ )
69
+ end
70
+ end
71
+ end
@@ -1,4 +1,5 @@
1
1
  {
2
+ "_uuid": "",
2
3
  "_type": "",
3
4
  "next": "",
4
5
  "expressions": []
@@ -27,6 +27,7 @@
27
27
  "default": "0b297048-aa4d-49b6-ac74-18e069118185",
28
28
  "conditionals": [
29
29
  {
30
+ "_uuid": "ecd60ac9-c3ea-47b1-8f79-c4e42df9a9dd",
30
31
  "_type": "if",
31
32
  "next": "e8708909-922e-4eaf-87a5-096f7a713fcb",
32
33
  "expressions": [
@@ -60,6 +61,7 @@
60
61
  "default": "05c3306c-0a39-42d2-9e0f-93fd49248f4e",
61
62
  "conditionals": [
62
63
  {
64
+ "_uuid": "51b4eda2-a08d-4ab3-a8cb-565091f39424",
63
65
  "_type": "if",
64
66
  "next": "d4342dfd-0d09-4a91-a0ea-d7fd67e706cc",
65
67
  "expressions": [
@@ -72,6 +74,7 @@
72
74
  ]
73
75
  },
74
76
  {
77
+ "_uuid": "0a799cea-f5a4-4b89-9ffe-78515b5cb1d7",
75
78
  "_type": "if",
76
79
  "next": "91e9f7c6-2f75-4b7d-9eb5-0cf352f7be66",
77
80
  "expressions": [
@@ -111,6 +114,7 @@
111
114
  "default": "ef2cafe3-37e2-4533-9b0c-09a970cd38d4",
112
115
  "conditionals": [
113
116
  {
117
+ "_uuid": "0d3410db-1d05-4a32-bafb-65b52408b89b",
114
118
  "_type": "if",
115
119
  "next": "8002df6e-29ab-4cdf-b520-1d7bb931a28f",
116
120
  "expressions": [
@@ -144,6 +148,7 @@
144
148
  "default": "0c022e95-0748-4dda-8ba5-12fd1d2f596b",
145
149
  "conditionals": [
146
150
  {
151
+ "_uuid": "88b97d53-1da7-4464-a0a5-633a9ffd3d3d",
147
152
  "_type": "if",
148
153
  "next": "b5efc09c-ece7-45ae-b0b3-8a7905e25040",
149
154
  "expressions": [
@@ -177,6 +182,7 @@
177
182
  "default": "dc7454f9-4186-48d7-b055-684d57bbcdc7",
178
183
  "conditionals": [
179
184
  {
185
+ "_uuid": "8a0c225f-b078-4728-a181-c3bdd343801c",
180
186
  "_type": "if",
181
187
  "next": "bc666714-c0a2-4674-afe5-faff2e20d847",
182
188
  "expressions": [
@@ -189,6 +195,7 @@
189
195
  ]
190
196
  },
191
197
  {
198
+ "_uuid": "7d1b29ac-f310-4246-bab9-957c9b2a20f2",
192
199
  "_type": "if",
193
200
  "next": "e2887f44-5e8d-4dc0-b1de-496ab6039430",
194
201
  "expressions": [
@@ -228,6 +235,7 @@
228
235
  "default": "48357db5-7c06-4e85-94b1-5e1c9d8f39eb",
229
236
  "conditionals": [
230
237
  {
238
+ "_uuid": "15e8076f-75ac-4310-89b3-d2b5962babd4",
231
239
  "_type": "or",
232
240
  "next": "2cc66e51-2c14-4023-86bf-ded49887cdb2",
233
241
  "expressions": [
@@ -246,6 +254,7 @@
246
254
  ]
247
255
  },
248
256
  {
257
+ "_uuid": "0811ac93-a73e-4a2d-a8f1-68cc8a52ca69",
249
258
  "_type": "and",
250
259
  "next": "f6c51f88-7be8-4cb7-bbfc-6c905727a051",
251
260
  "expressions": [
@@ -291,6 +300,7 @@
291
300
  "default": "941137d7-a1da-43fd-994a-98a4f9ea6d46",
292
301
  "conditionals": [
293
302
  {
303
+ "_uuid": "5ce78103-3935-4c57-9278-79bf2b8b93b1",
294
304
  "_type": "and",
295
305
  "next": "56e80942-d0a4-405a-85cd-bd1b100013d6",
296
306
  "expressions": [
@@ -315,6 +325,7 @@
315
325
  ]
316
326
  },
317
327
  {
328
+ "_uuid": "d45c65c7-a9b4-4128-8562-89bd4f0167ec",
318
329
  "_type": "or",
319
330
  "next": "6324cca4-7770-4765-89b9-1cdc41f49c8b",
320
331
  "expressions": [