metadata_presenter 2.4.2 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/models/metadata_presenter/grid.rb +203 -0
- data/app/models/metadata_presenter/route.rb +76 -0
- data/lib/metadata_presenter/version.rb +1 -1
- data/lib/metadata_presenter.rb +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5bd3891b62938a67dd025d49a96098778ad66221bf62cb2351002906e78aa4b4
|
4
|
+
data.tar.gz: 9dba99d36da50beea7a209d27f3371e4e814776d86d609436ac500c6d91cbd14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8c2dde3ca3e374e0f50eebc881a64fe676f4d6fa0156ab73e26e79e0c9a19292c4c21d55665171441c52af3c56a6472783365df050246ba7e583da89db112ce
|
7
|
+
data.tar.gz: c114dddbf37af9e800c9eb6c4601d6f250175efd1b35f9159a728edb0c3239357f6f35b281bd1280792101d669885e6f48218ffdeca876edbfbf5af5f0f9051e
|
@@ -0,0 +1,203 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class Spacer < OpenStruct
|
3
|
+
end
|
4
|
+
|
5
|
+
class Grid
|
6
|
+
def initialize(service)
|
7
|
+
@service = service
|
8
|
+
@ordered = []
|
9
|
+
@routes = []
|
10
|
+
@traversed = []
|
11
|
+
@coordinates = setup_coordinates
|
12
|
+
end
|
13
|
+
|
14
|
+
ROW_ZERO = 0
|
15
|
+
|
16
|
+
def build
|
17
|
+
@ordered = make_grid
|
18
|
+
add_columns
|
19
|
+
add_rows
|
20
|
+
add_by_coordinates
|
21
|
+
trim_spacers
|
22
|
+
insert_expression_spacers
|
23
|
+
|
24
|
+
@ordered
|
25
|
+
end
|
26
|
+
|
27
|
+
def ordered_flow
|
28
|
+
@ordered_flow ||= begin
|
29
|
+
flow = @ordered.empty? ? build.flatten : @ordered.flatten
|
30
|
+
flow.reject { |obj| obj.is_a?(MetadataPresenter::Spacer) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def ordered_pages
|
35
|
+
ordered_flow.reject(&:branch?)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
attr_reader :service
|
41
|
+
attr_accessor :ordered, :traversed, :routes, :coordinates
|
42
|
+
|
43
|
+
def setup_coordinates
|
44
|
+
service.flow.keys.index_with { |_uuid| { row: nil, column: nil } }
|
45
|
+
end
|
46
|
+
|
47
|
+
def route_from_start
|
48
|
+
@route_from_start ||=
|
49
|
+
MetadataPresenter::Route.new(
|
50
|
+
service: service,
|
51
|
+
traverse_from: service.start_page.uuid
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
def make_grid
|
56
|
+
traverse_all_routes
|
57
|
+
|
58
|
+
rows = @routes.map(&:row).max
|
59
|
+
columns = @routes.map { |r| r.column + r.flow_uuids.count }.max
|
60
|
+
columns.times.map { rows.times.map { MetadataPresenter::Spacer.new } }
|
61
|
+
end
|
62
|
+
|
63
|
+
def traverse_all_routes
|
64
|
+
# Always traverse the route that begins from the start page first and get
|
65
|
+
# the potential routes from any branching points that exist.
|
66
|
+
route_from_start.traverse
|
67
|
+
@routes.append(route_from_start)
|
68
|
+
traversed_routes = route_from_start.routes
|
69
|
+
|
70
|
+
index = 0
|
71
|
+
until traversed_routes.empty?
|
72
|
+
if index > total_potential_routes
|
73
|
+
ActiveSupport::Notifications.instrument(
|
74
|
+
'exceeded_total_potential_routes',
|
75
|
+
message: 'Exceeded total number of potential routes'
|
76
|
+
)
|
77
|
+
break
|
78
|
+
end
|
79
|
+
|
80
|
+
route = traversed_routes.shift
|
81
|
+
@routes.append(route)
|
82
|
+
|
83
|
+
# Every route exiting a branching point needs to be traversed and any
|
84
|
+
# additional routes from other branching points collected and then also
|
85
|
+
# traversed.
|
86
|
+
route.traverse
|
87
|
+
traversed_routes |= route.routes
|
88
|
+
|
89
|
+
index += 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def add_columns
|
94
|
+
@routes.each do |route|
|
95
|
+
route.flow_uuids.each.with_index(route.column) do |uuid, column|
|
96
|
+
column_number = @coordinates[uuid][:column]
|
97
|
+
if column_number.nil? || column > column_number
|
98
|
+
@coordinates[uuid][:column] = column
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def add_rows
|
105
|
+
@routes.each do |route|
|
106
|
+
route.flow_uuids.each do |uuid|
|
107
|
+
next if @traversed.include?(uuid)
|
108
|
+
|
109
|
+
@coordinates[uuid][:row] = route.row if @coordinates[uuid][:row].nil?
|
110
|
+
|
111
|
+
update_route_rows(route, uuid)
|
112
|
+
@traversed.push(uuid)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Each Route object has a starting row. Each Route object has no knowledge
|
118
|
+
# of other potential routes and pages/branches that may or may not exist in
|
119
|
+
# them. The starting row may need to change dependent upon what has been
|
120
|
+
# traversed in other routes.
|
121
|
+
def update_route_rows(route, uuid)
|
122
|
+
flow_object = service.flow_object(uuid)
|
123
|
+
if flow_object.branch? && route.row > ROW_ZERO
|
124
|
+
destinations = routes_exiting_branch(flow_object)
|
125
|
+
destinations.each.with_index(route.row) do |destination_uuid, row|
|
126
|
+
@routes.each do |r|
|
127
|
+
r.row = row if r.traverse_from == destination_uuid
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def add_by_coordinates
|
134
|
+
@coordinates.each do |uuid, position|
|
135
|
+
# If row and column are nil then the object is detached
|
136
|
+
next if position[:row].nil? || position[:column].nil?
|
137
|
+
|
138
|
+
flow_object = service.flow_object(uuid)
|
139
|
+
@ordered[position[:column]][position[:row]] = flow_object
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Find the very last MetadataPresenter::Flow object in every column and
|
144
|
+
# remove any Spacer objects after that.
|
145
|
+
def trim_spacers
|
146
|
+
@ordered.each_with_index do |column, index|
|
147
|
+
last_index_of = column.rindex { |item| item.is_a?(MetadataPresenter::Flow) }
|
148
|
+
@ordered[index] = @ordered[index][0..last_index_of]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Each branch has a certain number of exits that require their own line
|
153
|
+
# and arrow. Insert any spacers into the necessary row in the column after
|
154
|
+
# the one the branch is located in.
|
155
|
+
def insert_expression_spacers
|
156
|
+
service.branches.each do |branch|
|
157
|
+
position = @coordinates[branch.uuid]
|
158
|
+
next if position[:row].nil? || position[:column].nil? # detached branch
|
159
|
+
|
160
|
+
next_column = position[:column] + 1
|
161
|
+
uuids = []
|
162
|
+
exiting_destinations_from_branch(branch).each.with_index(position[:row]) do |uuid, row|
|
163
|
+
if uuids.include?(uuid)
|
164
|
+
@ordered[next_column].insert(row, MetadataPresenter::Spacer.new)
|
165
|
+
end
|
166
|
+
|
167
|
+
uuids.push(uuid) unless uuids.include?(uuid)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# The frontend requires that expressions of type 'or' get there own line and
|
173
|
+
# arrow. 'and' expression types continue to be grouped together.
|
174
|
+
# Return the UUIDs of the destinations exiting a branch and allow duplicates
|
175
|
+
# if the expression type is an 'or'.
|
176
|
+
def exiting_destinations_from_branch(branch)
|
177
|
+
destination_uuids = branch.conditionals.map do |conditional|
|
178
|
+
if conditional.type == 'or'
|
179
|
+
conditional.expressions.map(&:next)
|
180
|
+
else
|
181
|
+
conditional.next
|
182
|
+
end
|
183
|
+
end
|
184
|
+
destination_uuids.flatten
|
185
|
+
end
|
186
|
+
|
187
|
+
# Any destinations exiting the branch that have not already been traversed.
|
188
|
+
def routes_exiting_branch(branch)
|
189
|
+
branch.all_destination_uuids.reject { |uuid| @traversed.include?(uuid) }
|
190
|
+
end
|
191
|
+
|
192
|
+
# Deliberately not including the default next for each branch as when row
|
193
|
+
# zero is created it takes the first available conditional for each branch.
|
194
|
+
# The remaining are then used to create route objects. Therefore the total
|
195
|
+
# number of remaining routes will be the same as the total of all the branch
|
196
|
+
# conditionals.
|
197
|
+
# Add 1 additional route as that represents the route_from_start.
|
198
|
+
def total_potential_routes
|
199
|
+
@total_potential_routes ||=
|
200
|
+
service.branches.sum { |branch| branch.conditionals.size } + 1
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class Route
|
3
|
+
attr_reader :traverse_from
|
4
|
+
attr_accessor :flow_uuids, :routes, :row, :column
|
5
|
+
|
6
|
+
def initialize(service:, traverse_from:, row: 0, column: 0)
|
7
|
+
@service = service
|
8
|
+
@traverse_from = traverse_from
|
9
|
+
@row = row
|
10
|
+
@column = column
|
11
|
+
@routes = []
|
12
|
+
@flow_uuids = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def traverse
|
16
|
+
@flow_uuid = traverse_from
|
17
|
+
|
18
|
+
index = column
|
19
|
+
until @flow_uuid.blank?
|
20
|
+
if index > service.flow.size
|
21
|
+
ActiveSupport::Notifications.instrument(
|
22
|
+
'exceeded_total_flow_objects',
|
23
|
+
message: 'Exceeded total number of flow objects'
|
24
|
+
)
|
25
|
+
break
|
26
|
+
end
|
27
|
+
|
28
|
+
@flow_uuids.push(@flow_uuid) unless @flow_uuids.include?(@flow_uuid)
|
29
|
+
flow_object = service.flow_object(@flow_uuid)
|
30
|
+
|
31
|
+
if flow_object.branch?
|
32
|
+
destinations = destination_uuids(flow_object)
|
33
|
+
# Take the first conditional destination and follow that until the end
|
34
|
+
# of the route.
|
35
|
+
@flow_uuid = destinations.shift
|
36
|
+
|
37
|
+
# The remaining conditional destinations and the branch's default next
|
38
|
+
# (otherwise) will be the starting point for a new Route object to be
|
39
|
+
# traversed.
|
40
|
+
# The default behaviour is that the next destination will be on the row
|
41
|
+
# below this current route's row. This can be changed under certain
|
42
|
+
# conditions in the Grid model.
|
43
|
+
# Each of the destinations need to be placed in the column after the
|
44
|
+
# current column.
|
45
|
+
row_number = row + 1
|
46
|
+
column_number = index + 1
|
47
|
+
destinations.each do |uuid|
|
48
|
+
@routes.push(
|
49
|
+
MetadataPresenter::Route.new(
|
50
|
+
service: service,
|
51
|
+
traverse_from: uuid,
|
52
|
+
row: row_number,
|
53
|
+
column: column_number
|
54
|
+
)
|
55
|
+
)
|
56
|
+
row_number += 1
|
57
|
+
end
|
58
|
+
else
|
59
|
+
@flow_uuid = flow_object.default_next
|
60
|
+
end
|
61
|
+
|
62
|
+
index += 1
|
63
|
+
end
|
64
|
+
|
65
|
+
@flow_uuids
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
attr_reader :service
|
71
|
+
|
72
|
+
def destination_uuids(flow_object)
|
73
|
+
flow_object.conditionals.map(&:next).push(flow_object.default_next)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/metadata_presenter.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metadata_presenter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MoJ Forms
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-09-
|
11
|
+
date: 2021-09-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: govuk_design_system_formbuilder
|
@@ -283,6 +283,7 @@ files:
|
|
283
283
|
- app/models/metadata_presenter/expression.rb
|
284
284
|
- app/models/metadata_presenter/file_uploader.rb
|
285
285
|
- app/models/metadata_presenter/flow.rb
|
286
|
+
- app/models/metadata_presenter/grid.rb
|
286
287
|
- app/models/metadata_presenter/item.rb
|
287
288
|
- app/models/metadata_presenter/meta.rb
|
288
289
|
- app/models/metadata_presenter/meta_item.rb
|
@@ -292,6 +293,7 @@ files:
|
|
292
293
|
- app/models/metadata_presenter/page.rb
|
293
294
|
- app/models/metadata_presenter/page_answers.rb
|
294
295
|
- app/models/metadata_presenter/previous_page.rb
|
296
|
+
- app/models/metadata_presenter/route.rb
|
295
297
|
- app/models/metadata_presenter/service.rb
|
296
298
|
- app/models/metadata_presenter/traversed_pages.rb
|
297
299
|
- app/models/metadata_presenter/uploaded_file.rb
|