metadata_presenter 1.4.0 → 1.7.1
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/README.md +12 -0
- data/app/controllers/metadata_presenter/answers_controller.rb +1 -0
- data/app/controllers/metadata_presenter/change_answer_controller.rb +1 -1
- data/app/controllers/metadata_presenter/engine_controller.rb +12 -7
- data/app/models/metadata_presenter/evaluate_conditions.rb +18 -10
- data/app/models/metadata_presenter/flow.rb +4 -0
- data/app/models/metadata_presenter/next_page.rb +6 -6
- data/app/models/metadata_presenter/page.rb +4 -0
- data/app/models/metadata_presenter/page_answers.rb +7 -4
- data/app/models/metadata_presenter/previous_page.rb +38 -0
- data/app/models/metadata_presenter/service.rb +6 -4
- data/app/models/metadata_presenter/traversed_pages.rb +40 -0
- data/app/operators/metadata_presenter/base_operator.rb +10 -0
- data/app/operators/metadata_presenter/is_not_operator.rb +4 -0
- data/app/operators/metadata_presenter/is_operator.rb +4 -0
- data/app/operators/metadata_presenter/operator.rb +7 -4
- data/fixtures/branching.json +331 -2
- data/lib/metadata_presenter/version.rb +1 -1
- data/lib/tasks/metadata_presenter_tasks.rake +89 -4
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e8dfc341688f7dccd859058844f7b475ecc93afb86ab46d1a4d72f89c8f8235
|
4
|
+
data.tar.gz: cfee59590ce4834a7c8eda109cd914f1b0b0157c2d48dc97e44351b552b943fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74d388b6e903201e9d42a71ae17f7457a748b4c7791a5604b8f9ac387b56f3a5f20953a55c84ce0a60efa53ea8ac9580d291001648fa781c0b01c5c56dd43dc1
|
7
|
+
data.tar.gz: b4ac8ca7c331b9a4a93acec7ad58036f42d7f73f5098b247cae77b054352bf588424832e615ebad4e76ee8ec4069723cd9edfdaee65a2ef7ae4f47aaca5369b0
|
data/README.md
CHANGED
@@ -83,3 +83,15 @@ service.
|
|
83
83
|
## Generate documentation
|
84
84
|
|
85
85
|
Run `rake doc` and open the doc/index.html
|
86
|
+
|
87
|
+
## Flow diagrams
|
88
|
+
|
89
|
+
You can generate flow diagrams calling a rake task:
|
90
|
+
|
91
|
+
```
|
92
|
+
brew install graphviz
|
93
|
+
SERVICE_METADATA="some-form-metadata" rails metadata:flow
|
94
|
+
```
|
95
|
+
|
96
|
+
This will generate an image with the flow for that metadata. Open that image
|
97
|
+
and profit!
|
@@ -6,14 +6,19 @@ module MetadataPresenter
|
|
6
6
|
default_form_builder GOVUKDesignSystemFormBuilder::FormBuilder
|
7
7
|
|
8
8
|
def back_link
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
previous_page = PreviousPage.new(
|
10
|
+
service: service,
|
11
|
+
user_data: load_user_data,
|
12
12
|
current_page: @page,
|
13
|
-
referrer: request.
|
14
|
-
)
|
15
|
-
|
16
|
-
|
13
|
+
referrer: request.referrer
|
14
|
+
).page
|
15
|
+
|
16
|
+
if previous_page
|
17
|
+
@back_link ||= File.join(
|
18
|
+
request.script_name,
|
19
|
+
previous_page.url
|
20
|
+
)
|
21
|
+
end
|
17
22
|
end
|
18
23
|
helper_method :back_link
|
19
24
|
|
@@ -4,24 +4,32 @@ module MetadataPresenter
|
|
4
4
|
attr_accessor :service, :flow, :user_data
|
5
5
|
|
6
6
|
def page
|
7
|
-
|
8
|
-
|
7
|
+
evaluated_page_uuid = page_uuid || flow.default_next
|
8
|
+
|
9
|
+
service.find_page_by_uuid(evaluated_page_uuid)
|
10
|
+
end
|
11
|
+
|
12
|
+
def page_uuid
|
13
|
+
@results ||= conditions.map do |condition|
|
14
|
+
evaluated_criterias = condition.criterias.map do |criteria|
|
9
15
|
criteria.service = service
|
10
16
|
|
11
|
-
|
17
|
+
Operator.new(
|
12
18
|
criteria.operator
|
13
|
-
).evaluate(
|
19
|
+
).evaluate(
|
20
|
+
criteria.field_label,
|
21
|
+
user_data[criteria.criteria_component.id]
|
22
|
+
)
|
23
|
+
end
|
14
24
|
|
25
|
+
if condition.condition_type == 'or' && evaluated_criterias.any?
|
26
|
+
condition.next
|
27
|
+
elsif evaluated_criterias.all?
|
15
28
|
condition.next
|
16
29
|
end
|
17
30
|
end
|
18
31
|
|
19
|
-
|
20
|
-
if page_uuid.present?
|
21
|
-
service.find_page_by_uuid(page_uuid.first)
|
22
|
-
else
|
23
|
-
service.find_page_by_uuid(flow.default_next)
|
24
|
-
end
|
32
|
+
@results.flatten.compact.first
|
25
33
|
end
|
26
34
|
|
27
35
|
delegate :conditions, to: :flow
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module MetadataPresenter
|
2
2
|
class NextPage
|
3
3
|
include ActiveModel::Model
|
4
|
-
attr_accessor :service, :session, :current_page_url
|
4
|
+
attr_accessor :service, :session, :user_data, :current_page_url
|
5
5
|
|
6
6
|
def find
|
7
|
-
return check_answers_page if
|
7
|
+
return check_answers_page if return_to_check_your_answer?
|
8
8
|
|
9
9
|
if conditions?
|
10
10
|
evaluate_conditions
|
@@ -18,12 +18,12 @@ module MetadataPresenter
|
|
18
18
|
private
|
19
19
|
|
20
20
|
def check_answers_page
|
21
|
-
session[:
|
21
|
+
session[:return_to_check_your_answer] = nil
|
22
22
|
service.pages.find { |page| page.type == 'page.checkanswers' }
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
26
|
-
session[:
|
25
|
+
def return_to_check_your_answer?
|
26
|
+
session[:return_to_check_your_answer].present?
|
27
27
|
end
|
28
28
|
|
29
29
|
def conditions?
|
@@ -36,7 +36,7 @@ module MetadataPresenter
|
|
36
36
|
EvaluateConditions.new(
|
37
37
|
service: service,
|
38
38
|
flow: next_flow,
|
39
|
-
user_data:
|
39
|
+
user_data: user_data
|
40
40
|
).page
|
41
41
|
end
|
42
42
|
|
@@ -2,6 +2,7 @@ module MetadataPresenter
|
|
2
2
|
class PageAnswers
|
3
3
|
include ActiveModel::Model
|
4
4
|
include ActiveModel::Validations
|
5
|
+
include ActionView::Helpers
|
5
6
|
attr_reader :page, :answers, :uploaded_files
|
6
7
|
|
7
8
|
def initialize(page, answers)
|
@@ -27,8 +28,10 @@ module MetadataPresenter
|
|
27
28
|
date_answer(component.id)
|
28
29
|
elsif component && component.type == 'upload'
|
29
30
|
upload_answer(component.id)
|
31
|
+
elsif component && component.type == 'checkboxes'
|
32
|
+
answers[method_name.to_s].to_a
|
30
33
|
else
|
31
|
-
answers[method_name.to_s]
|
34
|
+
sanitize(answers[method_name.to_s])
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
@@ -38,10 +41,10 @@ module MetadataPresenter
|
|
38
41
|
return {} unless file_details
|
39
42
|
|
40
43
|
if file_details.is_a?(Hash) || file_details.is_a?(ActionController::Parameters)
|
41
|
-
file_details
|
44
|
+
file_details.merge('original_filename' => sanitize(file_details['original_filename']))
|
42
45
|
else
|
43
46
|
{
|
44
|
-
'original_filename' => file_details.original_filename,
|
47
|
+
'original_filename' => sanitize(file_details.original_filename),
|
45
48
|
'content_type' => file_details.content_type,
|
46
49
|
'tempfile' => file_details.tempfile.path.to_s
|
47
50
|
}
|
@@ -60,7 +63,7 @@ module MetadataPresenter
|
|
60
63
|
GOVUKDesignSystemFormBuilder::Elements::Date::SEGMENTS[:month],
|
61
64
|
GOVUKDesignSystemFormBuilder::Elements::Date::SEGMENTS[:year]
|
62
65
|
].map do |segment|
|
63
|
-
answers["#{component_id}(#{segment})"]
|
66
|
+
sanitize(answers["#{component_id}(#{segment})"])
|
64
67
|
end
|
65
68
|
end
|
66
69
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class PreviousPage
|
3
|
+
include ActiveModel::Model
|
4
|
+
attr_accessor :service, :user_data, :current_page, :referrer
|
5
|
+
|
6
|
+
def page
|
7
|
+
# what happens when a user enters in the middle of the flow
|
8
|
+
return if no_current_or_referrer_pages? || service.no_back_link?(current_page)
|
9
|
+
|
10
|
+
if flow.present?
|
11
|
+
return referrer_page if return_to_referrer?
|
12
|
+
|
13
|
+
TraversedPages.new(service, user_data, current_page).last
|
14
|
+
else
|
15
|
+
service.previous_page(current_page: current_page, referrer: referrer)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def flow
|
20
|
+
service.metadata['flow']
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def referrer_page
|
26
|
+
@referrer_page ||= service.find_page_by_url(URI(referrer).path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def return_to_referrer?
|
30
|
+
current_page.standalone? ||
|
31
|
+
(referrer_page && referrer_page.standalone?)
|
32
|
+
end
|
33
|
+
|
34
|
+
def no_current_or_referrer_pages?
|
35
|
+
current_page.blank? || referrer.nil?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -39,6 +39,8 @@ class MetadataPresenter::Service < MetadataPresenter::Metadata
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def previous_page(current_page:, referrer:)
|
42
|
+
return if current_page.nil? || referrer.nil?
|
43
|
+
|
42
44
|
unless no_back_link?(current_page)
|
43
45
|
flow_page(current_page) || referrer_page(referrer)
|
44
46
|
end
|
@@ -54,16 +56,16 @@ class MetadataPresenter::Service < MetadataPresenter::Metadata
|
|
54
56
|
MetadataPresenter::Meta.new(configuration['meta'])
|
55
57
|
end
|
56
58
|
|
59
|
+
def no_back_link?(current_page)
|
60
|
+
current_page == start_page || current_page == confirmation_page
|
61
|
+
end
|
62
|
+
|
57
63
|
private
|
58
64
|
|
59
65
|
def all_pages
|
60
66
|
@all_pages ||= pages + standalone_pages
|
61
67
|
end
|
62
68
|
|
63
|
-
def no_back_link?(current_page)
|
64
|
-
current_page == start_page || current_page == confirmation_page
|
65
|
-
end
|
66
|
-
|
67
69
|
def flow_page(current_page)
|
68
70
|
page_index = pages.index(current_page)
|
69
71
|
pages[page_index - 1] if page_index.present?
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class TraversedPages
|
3
|
+
attr_reader :service, :user_data, :current_page
|
4
|
+
|
5
|
+
def initialize(service, user_data, current_page)
|
6
|
+
@service = service
|
7
|
+
@user_data = user_data
|
8
|
+
@pages = [service.start_page]
|
9
|
+
@current_page = current_page
|
10
|
+
end
|
11
|
+
|
12
|
+
delegate :last, to: :all
|
13
|
+
|
14
|
+
def all
|
15
|
+
page_uuid = service.start_page.uuid
|
16
|
+
|
17
|
+
service.metadata['flow'].size.times do
|
18
|
+
break if page_uuid == current_page.uuid
|
19
|
+
|
20
|
+
flow_object = service.flow(page_uuid)
|
21
|
+
|
22
|
+
if flow_object.branch?
|
23
|
+
page = EvaluateConditions.new(
|
24
|
+
service: service,
|
25
|
+
flow: flow_object,
|
26
|
+
user_data: user_data
|
27
|
+
).page
|
28
|
+
page_uuid = page.uuid
|
29
|
+
else
|
30
|
+
page_uuid = flow_object.default_next
|
31
|
+
page = service.find_page_by_uuid(page_uuid)
|
32
|
+
end
|
33
|
+
|
34
|
+
@pages.push(page) if page && page.uuid != current_page.uuid
|
35
|
+
end
|
36
|
+
|
37
|
+
@pages
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -6,5 +6,15 @@ module MetadataPresenter
|
|
6
6
|
@actual = actual
|
7
7
|
@expected = expected
|
8
8
|
end
|
9
|
+
|
10
|
+
def evaluate?
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
|
14
|
+
# Method signature for collection components (a.k.a checkboxes)
|
15
|
+
#
|
16
|
+
def evaluate_collection?
|
17
|
+
evaluate?
|
18
|
+
end
|
9
19
|
end
|
10
20
|
end
|
@@ -10,10 +10,13 @@ module MetadataPresenter
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def evaluate(actual, expected)
|
13
|
-
klass
|
14
|
-
|
15
|
-
|
16
|
-
.
|
13
|
+
operator = klass.constantize.new(actual, expected)
|
14
|
+
|
15
|
+
if expected.is_a?(Array)
|
16
|
+
operator.evaluate_collection?
|
17
|
+
else
|
18
|
+
operator.evaluate?
|
19
|
+
end
|
17
20
|
rescue NameError
|
18
21
|
raise NoOperator,
|
19
22
|
"Operator '#{operator}' is not implemented. You need to create the class #{klass}"
|
data/fixtures/branching.json
CHANGED
@@ -137,7 +137,7 @@
|
|
137
137
|
"cf8b3e18-dacf-4e91-92e1-018035961003": {
|
138
138
|
"_type": "branch",
|
139
139
|
"next": {
|
140
|
-
"default": "
|
140
|
+
"default": "0c022e95-0748-4dda-8ba5-12fd1d2f596b",
|
141
141
|
"conditions": [
|
142
142
|
{
|
143
143
|
"condition_type": "if",
|
@@ -154,6 +154,124 @@
|
|
154
154
|
]
|
155
155
|
}
|
156
156
|
},
|
157
|
+
"b5efc09c-ece7-45ae-b0b3-8a7905e25040": {
|
158
|
+
"_type": "page",
|
159
|
+
"next": {
|
160
|
+
"default": "0c022e95-0748-4dda-8ba5-12fd1d2f596b"
|
161
|
+
}
|
162
|
+
},
|
163
|
+
"0c022e95-0748-4dda-8ba5-12fd1d2f596b": {
|
164
|
+
"_type": "page",
|
165
|
+
"next": {
|
166
|
+
"default": "618b7537-b42b-4551-ae7d-053afa4d9ca9"
|
167
|
+
}
|
168
|
+
},
|
169
|
+
"618b7537-b42b-4551-ae7d-053afa4d9ca9": {
|
170
|
+
"_type": "branch",
|
171
|
+
"next": {
|
172
|
+
"default": "dc7454f9-4186-48d7-b055-684d57bbcdc7",
|
173
|
+
"conditions": [
|
174
|
+
{
|
175
|
+
"condition_type": "if",
|
176
|
+
"next": "bc666714-c0a2-4674-afe5-faff2e20d847",
|
177
|
+
"criterias": [
|
178
|
+
{
|
179
|
+
"operator": "is",
|
180
|
+
"page": "0c022e95-0748-4dda-8ba5-12fd1d2f596b",
|
181
|
+
"component": "4c409737-80bb-48c7-afa7-6e9360b65004",
|
182
|
+
"field": "3251098f-c8e0-4ac5-a637-95fd2e1c4dc4"
|
183
|
+
}
|
184
|
+
]
|
185
|
+
},
|
186
|
+
{
|
187
|
+
"condition_type": "if",
|
188
|
+
"next": "e2887f44-5e8d-4dc0-b1de-496ab6039430",
|
189
|
+
"criterias": [
|
190
|
+
{
|
191
|
+
"operator": "is_not",
|
192
|
+
"page": "0c022e95-0748-4dda-8ba5-12fd1d2f596b",
|
193
|
+
"component": "4c409737-80bb-48c7-afa7-6e9360b65004",
|
194
|
+
"field": "3251098f-c8e0-4ac5-a637-95fd2e1c4dc4"
|
195
|
+
}
|
196
|
+
]
|
197
|
+
}
|
198
|
+
]
|
199
|
+
}
|
200
|
+
},
|
201
|
+
"bc666714-c0a2-4674-afe5-faff2e20d847": {
|
202
|
+
"_type": "page",
|
203
|
+
"next": {
|
204
|
+
"default": "dc7454f9-4186-48d7-b055-684d57bbcdc7"
|
205
|
+
}
|
206
|
+
},
|
207
|
+
"e2887f44-5e8d-4dc0-b1de-496ab6039430": {
|
208
|
+
"_type": "page",
|
209
|
+
"next": {
|
210
|
+
"default": "dc7454f9-4186-48d7-b055-684d57bbcdc7"
|
211
|
+
}
|
212
|
+
},
|
213
|
+
"dc7454f9-4186-48d7-b055-684d57bbcdc7": {
|
214
|
+
"_type": "page",
|
215
|
+
"next": {
|
216
|
+
"default": "84a347fc-8d4b-486a-9996-6a86fa9544c5"
|
217
|
+
}
|
218
|
+
},
|
219
|
+
"84a347fc-8d4b-486a-9996-6a86fa9544c5": {
|
220
|
+
"_type": "branch",
|
221
|
+
"next": {
|
222
|
+
"default": "e337070b-f636-49a3-a65c-f506675265f0",
|
223
|
+
"conditions": [
|
224
|
+
{
|
225
|
+
"condition_type": "or",
|
226
|
+
"next": "2cc66e51-2c14-4023-86bf-ded49887cdb2",
|
227
|
+
"criterias": [
|
228
|
+
{
|
229
|
+
"operator": "is",
|
230
|
+
"page": "dc7454f9-4186-48d7-b055-684d57bbcdc7",
|
231
|
+
"component": "5ca01e56-94de-4c33-b5fc-74697e5b95cc",
|
232
|
+
"field": "bd14bf31-427e-4267-9926-a18c167fe604"
|
233
|
+
},
|
234
|
+
{
|
235
|
+
"operator": "is",
|
236
|
+
"page": "dc7454f9-4186-48d7-b055-684d57bbcdc7",
|
237
|
+
"component": "5ca01e56-94de-4c33-b5fc-74697e5b95cc",
|
238
|
+
"field": "eb720ef7-bcaf-4c73-8972-6fc80dca6245"
|
239
|
+
}
|
240
|
+
]
|
241
|
+
},
|
242
|
+
{
|
243
|
+
"condition_type": "and",
|
244
|
+
"next": "f6c51f88-7be8-4cb7-bbfc-6c905727a051",
|
245
|
+
"criterias": [
|
246
|
+
{
|
247
|
+
"operator": "is",
|
248
|
+
"page": "68fbb180-9a2a-48f6-9da6-545e28b8d35a",
|
249
|
+
"component": "ac41be35-914e-4b22-8683-f5477716b7d4",
|
250
|
+
"field": "c5571937-9388-4411-b5fa-34ddf9bc4ca0"
|
251
|
+
},
|
252
|
+
{
|
253
|
+
"operator": "is",
|
254
|
+
"page": "dc7454f9-4186-48d7-b055-684d57bbcdc7",
|
255
|
+
"component": "5ca01e56-94de-4c33-b5fc-74697e5b95cc",
|
256
|
+
"field": "0c4192eb-1441-4f10-b00a-0f03b756269e"
|
257
|
+
}
|
258
|
+
]
|
259
|
+
}
|
260
|
+
]
|
261
|
+
}
|
262
|
+
},
|
263
|
+
"2cc66e51-2c14-4023-86bf-ded49887cdb2": {
|
264
|
+
"_type": "page",
|
265
|
+
"next": {
|
266
|
+
"default": "e337070b-f636-49a3-a65c-f506675265f0"
|
267
|
+
}
|
268
|
+
},
|
269
|
+
"f6c51f88-7be8-4cb7-bbfc-6c905727a051": {
|
270
|
+
"_type": "page",
|
271
|
+
"next": {
|
272
|
+
"default": "e337070b-f636-49a3-a65c-f506675265f0"
|
273
|
+
}
|
274
|
+
},
|
157
275
|
"e337070b-f636-49a3-a65c-f506675265f0": {
|
158
276
|
"_type": "page",
|
159
277
|
"next": {
|
@@ -608,6 +726,217 @@
|
|
608
726
|
}
|
609
727
|
]
|
610
728
|
},
|
729
|
+
{
|
730
|
+
"_id": "page.burgers",
|
731
|
+
"url": "burgers",
|
732
|
+
"body": "Body section",
|
733
|
+
"lede": "",
|
734
|
+
"_type": "page.singlequestion",
|
735
|
+
"_uuid": "0c022e95-0748-4dda-8ba5-12fd1d2f596b",
|
736
|
+
"heading": "Question",
|
737
|
+
"components": [
|
738
|
+
{
|
739
|
+
"_id": "burgers_checkboxes_1",
|
740
|
+
"hint": "",
|
741
|
+
"name": "burgers_checkboxes_1",
|
742
|
+
"_type": "checkboxes",
|
743
|
+
"_uuid": "4c409737-80bb-48c7-afa7-6e9360b65004",
|
744
|
+
"items": [
|
745
|
+
{
|
746
|
+
"_id": "burgers_checkboxes_1_item_1",
|
747
|
+
"hint": "",
|
748
|
+
"name": "burgers_checkboxes_1",
|
749
|
+
"_type": "checkbox",
|
750
|
+
"_uuid": "3251098f-c8e0-4ac5-a637-95fd2e1c4dc4",
|
751
|
+
"label": "Beef, cheese, tomato",
|
752
|
+
"value": "value-1",
|
753
|
+
"errors": {},
|
754
|
+
"legend": "Question",
|
755
|
+
"collection": "components",
|
756
|
+
"validation": {
|
757
|
+
"required": true
|
758
|
+
}
|
759
|
+
},
|
760
|
+
{
|
761
|
+
"_id": "burgers_checkboxes_1_item_2",
|
762
|
+
"hint": "",
|
763
|
+
"name": "burgers_checkboxes_1",
|
764
|
+
"_type": "checkbox",
|
765
|
+
"_uuid": "a0717bbd-0b9f-47a0-bf2b-2a9d208e1168",
|
766
|
+
"label": "Chicken, cheese, tomato",
|
767
|
+
"value": "value-2",
|
768
|
+
"errors": {},
|
769
|
+
"legend": "Question",
|
770
|
+
"collection": "components",
|
771
|
+
"validation": {
|
772
|
+
"required": true
|
773
|
+
}
|
774
|
+
},
|
775
|
+
{
|
776
|
+
"_id": "burgers_checkboxes_1_item_3",
|
777
|
+
"hint": "",
|
778
|
+
"name": "burgers_checkboxes_1",
|
779
|
+
"_type": "checkbox",
|
780
|
+
"_uuid": "4c409737-80bb-48c7-afa7-6e9360b65004",
|
781
|
+
"label": "Mozzarella, cheddar, feta",
|
782
|
+
"value": "value-3",
|
783
|
+
"errors": {},
|
784
|
+
"legend": "Question",
|
785
|
+
"collection": "components",
|
786
|
+
"validation": {
|
787
|
+
"required": true
|
788
|
+
}
|
789
|
+
}
|
790
|
+
],
|
791
|
+
"errors": {},
|
792
|
+
"legend": "What would you like on your burger?",
|
793
|
+
"collection": "components",
|
794
|
+
"validation": {
|
795
|
+
"required": false
|
796
|
+
}
|
797
|
+
}
|
798
|
+
]
|
799
|
+
},
|
800
|
+
{
|
801
|
+
"_id": "page.global-warming",
|
802
|
+
"url": "global-warming",
|
803
|
+
"body": "What about the trees?",
|
804
|
+
"lede": "",
|
805
|
+
"_type": "page.content",
|
806
|
+
"_uuid": "bc666714-c0a2-4674-afe5-faff2e20d847",
|
807
|
+
"heading": "Global warming",
|
808
|
+
"components": [
|
809
|
+
{
|
810
|
+
"_id": "global-warming_content_1",
|
811
|
+
"name": "global-warming_content_1",
|
812
|
+
"_type": "content",
|
813
|
+
"_uuid": "957917c3-7473-4c30-b713-5aae77a1c22f",
|
814
|
+
"content": "They will come for you"
|
815
|
+
}
|
816
|
+
],
|
817
|
+
"section_heading": ""
|
818
|
+
},
|
819
|
+
{
|
820
|
+
"_id": "page.we-love-chickens",
|
821
|
+
"url": "we-love-chickens",
|
822
|
+
"body": "Cluck cluck",
|
823
|
+
"lede": "",
|
824
|
+
"_type": "page.content",
|
825
|
+
"_uuid": "e2887f44-5e8d-4dc0-b1de-496ab6039430",
|
826
|
+
"heading": "We love chickens",
|
827
|
+
"components": [
|
828
|
+
{
|
829
|
+
"_id": "global-warming_content_1",
|
830
|
+
"name": "global-warming_content_1",
|
831
|
+
"_type": "content",
|
832
|
+
"_uuid": "49ff5c79-2e63-45fe-bbf7-de0bd061b909",
|
833
|
+
"content": "Cruella ain't got nothing on Cluckeralla"
|
834
|
+
}
|
835
|
+
],
|
836
|
+
"section_heading": ""
|
837
|
+
},
|
838
|
+
{
|
839
|
+
"_id": "page.marvel-series",
|
840
|
+
"url": "marvel-series",
|
841
|
+
"_type": "page.singlequestion",
|
842
|
+
"_uuid": "dc7454f9-4186-48d7-b055-684d57bbcdc7",
|
843
|
+
"components": [
|
844
|
+
{
|
845
|
+
"_id": "marvel-series_radios_1",
|
846
|
+
"hint": "",
|
847
|
+
"name": "marvel-series_radios_1",
|
848
|
+
"_type": "radios",
|
849
|
+
"_uuid": "5ca01e56-94de-4c33-b5fc-74697e5b95cc",
|
850
|
+
"items": [
|
851
|
+
{
|
852
|
+
"_id": "marvel-series_radios_1_item_1",
|
853
|
+
"hint": "",
|
854
|
+
"_type": "radio",
|
855
|
+
"_uuid": "0c4192eb-1441-4f10-b00a-0f03b756269e",
|
856
|
+
"label": "WandaVision"
|
857
|
+
},
|
858
|
+
{
|
859
|
+
"_id": "marvel-series_radios_1_item_2",
|
860
|
+
"hint": "",
|
861
|
+
"_type": "radio",
|
862
|
+
"_uuid": "bd14bf31-427e-4267-9926-a18c167fe604",
|
863
|
+
"label": "The Falcon and the Winter Soldier"
|
864
|
+
},
|
865
|
+
{
|
866
|
+
"_id": "marvel-series_radios_1_item_2",
|
867
|
+
"hint": "",
|
868
|
+
"_type": "radio",
|
869
|
+
"_uuid": "eb720ef7-bcaf-4c73-8972-6fc80dca6245",
|
870
|
+
"label": "Loki"
|
871
|
+
},
|
872
|
+
{
|
873
|
+
"_id": "marvel-series_radios_1_item_3",
|
874
|
+
"hint": "",
|
875
|
+
"_type": "radio",
|
876
|
+
"_uuid": "d762e328-18dc-4861-bca8-d104609b8299",
|
877
|
+
"label": "Hawkeye"
|
878
|
+
}
|
879
|
+
],
|
880
|
+
"errors": {},
|
881
|
+
"legend": "What is the best marvel series?",
|
882
|
+
"validation": {
|
883
|
+
"required": true
|
884
|
+
}
|
885
|
+
}
|
886
|
+
]
|
887
|
+
},
|
888
|
+
{
|
889
|
+
"_id": "page.marvel-quotes",
|
890
|
+
"url": "marvel-quotes",
|
891
|
+
"body": "Marvel quotes",
|
892
|
+
"lede": "",
|
893
|
+
"_type": "page.content",
|
894
|
+
"_uuid": "2cc66e51-2c14-4023-86bf-ded49887cdb2",
|
895
|
+
"heading": "Loki",
|
896
|
+
"components": [
|
897
|
+
{
|
898
|
+
"_id": "marvel-quotes_content_1",
|
899
|
+
"name": "marvel-quotes_content_1",
|
900
|
+
"_type": "content",
|
901
|
+
"_uuid": "5cede2fa-5001-4d6a-965c-30addc3c4496",
|
902
|
+
"content": "I am Loki of Asgard, and I am burdened with glorious purpose."
|
903
|
+
},
|
904
|
+
{
|
905
|
+
"_id": "marvel-quotes_content_2",
|
906
|
+
"name": "marvel-quotes_content_2",
|
907
|
+
"_type": "content",
|
908
|
+
"_uuid": "816b6afd-4649-455a-b10d-62cb5acb4584",
|
909
|
+
"content": "So Who Are You Fighting Now ... Gandalf?"
|
910
|
+
}
|
911
|
+
],
|
912
|
+
"section_heading": ""
|
913
|
+
},
|
914
|
+
{
|
915
|
+
"_id": "page.other-quotes",
|
916
|
+
"url": "other-quotes",
|
917
|
+
"body": "Other quotes",
|
918
|
+
"lede": "",
|
919
|
+
"_type": "page.content",
|
920
|
+
"_uuid": "f6c51f88-7be8-4cb7-bbfc-6c905727a051",
|
921
|
+
"heading": "Other quotes",
|
922
|
+
"components": [
|
923
|
+
{
|
924
|
+
"_id": "other-quotes_content_1",
|
925
|
+
"name": "other-quotes_content_1",
|
926
|
+
"_type": "content",
|
927
|
+
"_uuid": "2535a867-deab-457b-91aa-c006e3c73d63",
|
928
|
+
"content": "- How we doing? - Same as always... - That bad, huh?"
|
929
|
+
},
|
930
|
+
{
|
931
|
+
"_id": "other-quotes_content_2",
|
932
|
+
"name": "other-quotes_content_2",
|
933
|
+
"_type": "content",
|
934
|
+
"_uuid": "816b6afd-4649-455a-b10d-62cb5acb4584",
|
935
|
+
"content": "Are you using your night vision, Vision?"
|
936
|
+
}
|
937
|
+
],
|
938
|
+
"section_heading": ""
|
939
|
+
},
|
611
940
|
{
|
612
941
|
"_id": "page.check-answers",
|
613
942
|
"url": "check-answers",
|
@@ -655,7 +984,7 @@
|
|
655
984
|
"created_by": "099d5bf5-5f7b-444c-86ee-9e189cc1a369",
|
656
985
|
"service_id": "488edccd-8411-4ffb-a38b-6a96c6ac28d6",
|
657
986
|
"version_id": "27dc30c9-f7b8-4dec-973a-bd153f6797df",
|
658
|
-
"service_name": "
|
987
|
+
"service_name": "Branching Fixture",
|
659
988
|
"configuration": {
|
660
989
|
"meta": {
|
661
990
|
"_id": "config.meta",
|
@@ -1,4 +1,89 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require 'metadata_presenter/test_helpers'
|
2
|
+
|
3
|
+
namespace :metadata do
|
4
|
+
include MetadataPresenter::TestHelpers
|
5
|
+
|
6
|
+
desc 'Represent the flow objects in human readable form'
|
7
|
+
task flow: :environment do
|
8
|
+
require 'ruby-graphviz'
|
9
|
+
metadata = ENV['SERVICE_METADATA'] || metadata_fixture('branching')
|
10
|
+
service = MetadataPresenter::Service.new(metadata)
|
11
|
+
|
12
|
+
graph = MetadataPresenter::Graph.new(service)
|
13
|
+
|
14
|
+
graph.draw.generate_image
|
15
|
+
puts "Generated file #{graph.filename}"
|
16
|
+
system("open #{graph.filename}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module MetadataPresenter
|
21
|
+
class Graph
|
22
|
+
attr_reader :service, :filename, :nodes
|
23
|
+
|
24
|
+
delegate :metadata, :start_page, :find_page_by_uuid, :service_slug, to: :service
|
25
|
+
|
26
|
+
def initialize(service)
|
27
|
+
@service = service
|
28
|
+
@graphviz = GraphViz.new(:G, type: :digraph)
|
29
|
+
@filename = Rails.root.join('tmp', "#{service_slug}.png")
|
30
|
+
@nodes = {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def draw
|
34
|
+
draw_nodes
|
35
|
+
draw_edges
|
36
|
+
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def generate_image
|
41
|
+
@graphviz.output(png: filename)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def draw_nodes
|
47
|
+
flow.each do |id, _value|
|
48
|
+
flow_object = service.flow(id)
|
49
|
+
|
50
|
+
if flow_object.branch?
|
51
|
+
full_description = flow_object.conditions.map do |condition|
|
52
|
+
condition.criterias.map do |criteria|
|
53
|
+
criteria.service = service
|
54
|
+
|
55
|
+
"if #{criteria.criteria_component.humanised_title} #{criteria.operator} #{criteria.field_label}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
nodes[id] = @graphviz.add_nodes(full_description.flatten.join(' - '))
|
59
|
+
else
|
60
|
+
current_page = find_page_by_uuid(id)
|
61
|
+
nodes[id] = @graphviz.add_nodes(current_page.url)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def draw_edges
|
67
|
+
flow.each do |id, _value|
|
68
|
+
flow_object = service.flow(id)
|
69
|
+
current_node = nodes[id]
|
70
|
+
node_next = nodes[flow_object.default_next]
|
71
|
+
|
72
|
+
if flow_object.branch?
|
73
|
+
@graphviz.add_edges(current_node, node_next, label: 'Conditions are not met', labelfontsize: 8) if node_next
|
74
|
+
|
75
|
+
flow_object.group_by_page.each do |page_uuid, _conditions|
|
76
|
+
conditions_node = nodes[page_uuid]
|
77
|
+
@graphviz.add_edges(current_node, conditions_node, label: 'Conditions are met', labelfontsize: 8) if conditions_node
|
78
|
+
end
|
79
|
+
elsif node_next
|
80
|
+
@graphviz.add_edges(current_node, node_next)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def flow
|
86
|
+
metadata['flow']
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
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: 1.
|
4
|
+
version: 1.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MoJ Online
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: govuk_design_system_formbuilder
|
@@ -128,6 +128,20 @@ dependencies:
|
|
128
128
|
- - ">="
|
129
129
|
- !ruby/object:Gem::Version
|
130
130
|
version: '0'
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: ruby-graphviz
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
131
145
|
- !ruby/object:Gem::Dependency
|
132
146
|
name: rspec-rails
|
133
147
|
requirement: !ruby/object:Gem::Requirement
|
@@ -277,7 +291,9 @@ files:
|
|
277
291
|
- app/models/metadata_presenter/offline_upload_adapter.rb
|
278
292
|
- app/models/metadata_presenter/page.rb
|
279
293
|
- app/models/metadata_presenter/page_answers.rb
|
294
|
+
- app/models/metadata_presenter/previous_page.rb
|
280
295
|
- app/models/metadata_presenter/service.rb
|
296
|
+
- app/models/metadata_presenter/traversed_pages.rb
|
281
297
|
- app/models/metadata_presenter/uploaded_file.rb
|
282
298
|
- app/operators/metadata_presenter/base_operator.rb
|
283
299
|
- app/operators/metadata_presenter/is_answered_operator.rb
|