@defra/forms-engine-plugin 0.1.10 → 0.1.12

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.
Files changed (247) hide show
  1. package/.public/javascripts/file-upload.min.js +1 -1
  2. package/.public/javascripts/file-upload.min.js.map +1 -1
  3. package/.public/stylesheets/application.min.css +1 -1
  4. package/.public/stylesheets/application.min.css.map +1 -1
  5. package/.server/client/javascripts/file-upload.js +45 -4
  6. package/.server/client/javascripts/file-upload.js.map +1 -1
  7. package/.server/client/stylesheets/application.scss +10 -0
  8. package/.server/config/index.js +3 -14
  9. package/.server/config/index.js.map +1 -1
  10. package/.server/server/constants.js +2 -0
  11. package/.server/server/constants.js.map +1 -1
  12. package/.server/server/devserver/dxt-devtool-baselayout.html +71 -0
  13. package/.server/server/forms/register-as-a-unicorn-breeder.json +393 -0
  14. package/.server/server/forms/register-as-a-unicorn-breeder.yaml +251 -0
  15. package/.server/server/index.js +12 -17
  16. package/.server/server/index.js.map +1 -1
  17. package/.server/server/plugins/engine/components/AutocompleteField.js +2 -0
  18. package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
  19. package/.server/server/plugins/engine/components/CheckboxesField.js +3 -4
  20. package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
  21. package/.server/server/plugins/engine/components/ComponentCollection.js +37 -16
  22. package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
  23. package/.server/server/plugins/engine/components/DatePartsField.js +36 -2
  24. package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
  25. package/.server/server/plugins/engine/components/EmailAddressField.js +19 -3
  26. package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
  27. package/.server/server/plugins/engine/components/FileUploadField.js +44 -4
  28. package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
  29. package/.server/server/plugins/engine/components/FormComponent.js +14 -2
  30. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  31. package/.server/server/plugins/engine/components/ListFormComponent.js +16 -3
  32. package/.server/server/plugins/engine/components/ListFormComponent.js.map +1 -1
  33. package/.server/server/plugins/engine/components/Markdown.js +24 -0
  34. package/.server/server/plugins/engine/components/Markdown.js.map +1 -0
  35. package/.server/server/plugins/engine/components/MonthYearField.js +30 -2
  36. package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
  37. package/.server/server/plugins/engine/components/MultilineTextField.js +32 -3
  38. package/.server/server/plugins/engine/components/MultilineTextField.js.map +1 -1
  39. package/.server/server/plugins/engine/components/NumberField.js +28 -3
  40. package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
  41. package/.server/server/plugins/engine/components/SelectionControlField.js +14 -0
  42. package/.server/server/plugins/engine/components/SelectionControlField.js.map +1 -1
  43. package/.server/server/plugins/engine/components/TelephoneNumberField.js +19 -3
  44. package/.server/server/plugins/engine/components/TelephoneNumberField.js.map +1 -1
  45. package/.server/server/plugins/engine/components/TextField.js +22 -3
  46. package/.server/server/plugins/engine/components/TextField.js.map +1 -1
  47. package/.server/server/plugins/engine/components/UkAddressField.js +29 -0
  48. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  49. package/.server/server/plugins/engine/components/YesNoField.js +18 -0
  50. package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
  51. package/.server/server/plugins/engine/components/helpers.js +16 -0
  52. package/.server/server/plugins/engine/components/helpers.js.map +1 -1
  53. package/.server/server/plugins/engine/components/index.js +1 -0
  54. package/.server/server/plugins/engine/components/index.js.map +1 -1
  55. package/.server/server/plugins/engine/configureEnginePlugin.js +19 -3
  56. package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
  57. package/.server/server/plugins/engine/helpers.js +38 -18
  58. package/.server/server/plugins/engine/helpers.js.map +1 -1
  59. package/.server/server/plugins/engine/models/FormModel.js +60 -2
  60. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  61. package/.server/server/plugins/engine/models/SummaryViewModel.js +3 -2
  62. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
  63. package/.server/server/plugins/engine/outputFormatters/human/v1.js +1 -1
  64. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
  65. package/.server/server/plugins/engine/pageControllers/PageController.js +13 -5
  66. package/.server/server/plugins/engine/pageControllers/PageController.js.map +1 -1
  67. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +2 -2
  68. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  69. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +19 -5
  70. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  71. package/.server/server/plugins/engine/pageControllers/validationOptions.js +6 -11
  72. package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
  73. package/.server/server/plugins/engine/plugin.js +32 -20
  74. package/.server/server/plugins/engine/plugin.js.map +1 -1
  75. package/.server/server/plugins/engine/services/formsService.js +15 -29
  76. package/.server/server/plugins/engine/services/formsService.js.map +1 -1
  77. package/.server/server/plugins/engine/services/localFormsService.js +52 -0
  78. package/.server/server/plugins/engine/services/localFormsService.js.map +1 -0
  79. package/.server/server/plugins/engine/services/notifyService.js +1 -4
  80. package/.server/server/plugins/engine/services/notifyService.js.map +1 -1
  81. package/.server/server/plugins/engine/services/uploadService.js +5 -3
  82. package/.server/server/plugins/engine/services/uploadService.js.map +1 -1
  83. package/.server/server/plugins/engine/types.js.map +1 -1
  84. package/.server/server/plugins/engine/views/components/html.html +1 -1
  85. package/.server/server/plugins/engine/views/components/markdown.html +5 -0
  86. package/.server/server/plugins/engine/views/confirmation.html +1 -1
  87. package/.server/server/plugins/engine/views/file-upload.html +1 -1
  88. package/.server/server/plugins/engine/views/index.html +1 -1
  89. package/.server/server/plugins/engine/views/item-delete.html +1 -1
  90. package/.server/server/plugins/engine/views/repeat-list-summary.html +1 -1
  91. package/.server/server/plugins/engine/views/summary.html +8 -2
  92. package/.server/server/plugins/errorPages.js +4 -26
  93. package/.server/server/plugins/errorPages.js.map +1 -1
  94. package/.server/server/plugins/nunjucks/context.js +43 -33
  95. package/.server/server/plugins/nunjucks/context.js.map +1 -1
  96. package/.server/server/plugins/nunjucks/context.test.js +23 -28
  97. package/.server/server/plugins/nunjucks/context.test.js.map +1 -1
  98. package/.server/server/plugins/nunjucks/enviroment.test.js +6 -3
  99. package/.server/server/plugins/nunjucks/enviroment.test.js.map +1 -1
  100. package/.server/server/plugins/nunjucks/types.js +3 -4
  101. package/.server/server/plugins/nunjucks/types.js.map +1 -1
  102. package/.server/server/routes/index.js +0 -1
  103. package/.server/server/routes/index.js.map +1 -1
  104. package/.server/server/utils/type-utils.js +8 -0
  105. package/.server/server/utils/type-utils.js.map +1 -0
  106. package/.server/typings/hapi/index.d.js.map +1 -1
  107. package/.server/typings/joi/index.d.js.map +1 -1
  108. package/package.json +4 -3
  109. package/src/client/javascripts/file-upload.js +60 -4
  110. package/src/client/stylesheets/application.scss +10 -0
  111. package/src/config/index.ts +4 -17
  112. package/src/server/constants.js +2 -0
  113. package/src/server/devserver/dxt-devtool-baselayout.html +71 -0
  114. package/src/server/forms/register-as-a-unicorn-breeder.json +393 -0
  115. package/src/server/forms/register-as-a-unicorn-breeder.yaml +251 -0
  116. package/src/server/index.test.ts +38 -66
  117. package/src/server/index.ts +15 -17
  118. package/src/server/plugins/engine/components/AutocompleteField.test.ts +71 -3
  119. package/src/server/plugins/engine/components/AutocompleteField.ts +6 -2
  120. package/src/server/plugins/engine/components/CheckboxesField.test.ts +40 -8
  121. package/src/server/plugins/engine/components/CheckboxesField.ts +7 -3
  122. package/src/server/plugins/engine/components/ComponentCollection.ts +45 -18
  123. package/src/server/plugins/engine/components/DatePartsField.test.ts +13 -4
  124. package/src/server/plugins/engine/components/DatePartsField.ts +29 -8
  125. package/src/server/plugins/engine/components/EmailAddressField.test.ts +51 -1
  126. package/src/server/plugins/engine/components/EmailAddressField.ts +17 -2
  127. package/src/server/plugins/engine/components/FileUploadField.test.ts +53 -0
  128. package/src/server/plugins/engine/components/FileUploadField.ts +52 -3
  129. package/src/server/plugins/engine/components/FormComponent.ts +24 -2
  130. package/src/server/plugins/engine/components/ListFormComponent.ts +16 -2
  131. package/src/server/plugins/engine/components/Markdown.test.ts +48 -0
  132. package/src/server/plugins/engine/components/Markdown.ts +29 -0
  133. package/src/server/plugins/engine/components/MonthYearField.test.ts +35 -0
  134. package/src/server/plugins/engine/components/MonthYearField.ts +34 -9
  135. package/src/server/plugins/engine/components/MultilineTextField.test.ts +83 -5
  136. package/src/server/plugins/engine/components/MultilineTextField.ts +37 -2
  137. package/src/server/plugins/engine/components/NumberField.test.ts +24 -2
  138. package/src/server/plugins/engine/components/NumberField.ts +23 -3
  139. package/src/server/plugins/engine/components/RadiosField.test.ts +10 -1
  140. package/src/server/plugins/engine/components/SelectField.test.ts +2 -1
  141. package/src/server/plugins/engine/components/SelectionControlField.ts +14 -0
  142. package/src/server/plugins/engine/components/TelephoneNumberField.test.ts +30 -2
  143. package/src/server/plugins/engine/components/TelephoneNumberField.ts +17 -2
  144. package/src/server/plugins/engine/components/TextField.test.ts +33 -1
  145. package/src/server/plugins/engine/components/TextField.ts +17 -2
  146. package/src/server/plugins/engine/components/UkAddressField.test.ts +46 -3
  147. package/src/server/plugins/engine/components/UkAddressField.ts +28 -0
  148. package/src/server/plugins/engine/components/YesNoField.test.ts +9 -1
  149. package/src/server/plugins/engine/components/YesNoField.ts +24 -0
  150. package/src/server/plugins/engine/components/helpers.test.ts +24 -0
  151. package/src/server/plugins/engine/components/helpers.ts +39 -0
  152. package/src/server/plugins/engine/components/index.ts +1 -0
  153. package/src/server/plugins/engine/configureEnginePlugin.ts +32 -4
  154. package/src/server/plugins/engine/helpers.test.ts +71 -20
  155. package/src/server/plugins/engine/helpers.ts +46 -19
  156. package/src/server/plugins/engine/models/FormModel.test.ts +91 -1
  157. package/src/server/plugins/engine/models/FormModel.ts +86 -3
  158. package/src/server/plugins/engine/models/SummaryViewModel.test.ts +46 -7
  159. package/src/server/plugins/engine/models/SummaryViewModel.ts +7 -3
  160. package/src/server/plugins/engine/outputFormatters/human/v1.test.ts +1 -2
  161. package/src/server/plugins/engine/outputFormatters/human/v1.ts +1 -1
  162. package/src/server/plugins/engine/pageControllers/FileUploadPageController.test.ts +1 -0
  163. package/src/server/plugins/engine/pageControllers/PageController.test.ts +9 -6
  164. package/src/server/plugins/engine/pageControllers/PageController.ts +15 -5
  165. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +2 -2
  166. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +21 -6
  167. package/src/server/plugins/engine/pageControllers/validationOptions.ts +31 -17
  168. package/src/server/plugins/engine/plugin.ts +52 -22
  169. package/src/server/plugins/engine/services/formsService.js +17 -35
  170. package/src/server/plugins/engine/services/localFormsService.js +49 -0
  171. package/src/server/plugins/engine/services/notifyService.ts +1 -2
  172. package/src/server/plugins/engine/services/uploadService.js +10 -6
  173. package/src/server/plugins/engine/types.ts +10 -1
  174. package/src/server/plugins/engine/views/components/html.html +1 -1
  175. package/src/server/plugins/engine/views/components/markdown.html +5 -0
  176. package/src/server/plugins/engine/views/confirmation.html +1 -1
  177. package/src/server/plugins/engine/views/file-upload.html +1 -1
  178. package/src/server/plugins/engine/views/index.html +1 -1
  179. package/src/server/plugins/engine/views/item-delete.html +1 -1
  180. package/src/server/plugins/engine/views/repeat-list-summary.html +1 -1
  181. package/src/server/plugins/engine/views/summary.html +8 -2
  182. package/src/server/plugins/errorPages.ts +4 -26
  183. package/src/server/plugins/nunjucks/context.js +44 -34
  184. package/src/server/plugins/nunjucks/context.test.js +24 -27
  185. package/src/server/plugins/nunjucks/enviroment.test.js +9 -3
  186. package/src/server/plugins/nunjucks/types.js +3 -4
  187. package/src/server/routes/index.ts +0 -1
  188. package/src/server/utils/type-utils.ts +15 -0
  189. package/src/typings/hapi/index.d.ts +3 -9
  190. package/src/typings/joi/index.d.ts +8 -0
  191. package/.server/common/cookies.js +0 -55
  192. package/.server/common/cookies.js.map +0 -1
  193. package/.server/common/cookies.test.js +0 -15
  194. package/.server/common/cookies.test.js.map +0 -1
  195. package/.server/common/types.js +0 -6
  196. package/.server/common/types.js.map +0 -1
  197. package/.server/server/forms/README.md +0 -10
  198. package/.server/server/forms/report-a-terrorist.json +0 -270
  199. package/.server/server/forms/runner-components-test.json +0 -365
  200. package/.server/server/forms/test.json +0 -581
  201. package/.server/server/forms/test.yaml +0 -363
  202. package/.server/server/plugins/blankie.js +0 -29
  203. package/.server/server/plugins/blankie.js.map +0 -1
  204. package/.server/server/plugins/engine/services/formsService.test.js +0 -71
  205. package/.server/server/plugins/engine/services/formsService.test.js.map +0 -1
  206. package/.server/server/plugins/engine/views/layout.html +0 -199
  207. package/.server/server/plugins/router.js +0 -169
  208. package/.server/server/plugins/router.js.map +0 -1
  209. package/.server/server/routes/health.js +0 -15
  210. package/.server/server/routes/health.js.map +0 -1
  211. package/.server/server/routes/health.test.js +0 -32
  212. package/.server/server/routes/health.test.js.map +0 -1
  213. package/.server/server/utils/file-form-service.test.js +0 -52
  214. package/.server/server/utils/file-form-service.test.js.map +0 -1
  215. package/.server/server/views/404.html +0 -16
  216. package/.server/server/views/500.html +0 -19
  217. package/.server/server/views/help/accessibility-statement.html +0 -58
  218. package/.server/server/views/help/cookie-preferences.html +0 -57
  219. package/.server/server/views/help/cookies.html +0 -71
  220. package/.server/server/views/help/get-support.html +0 -37
  221. package/.server/server/views/help/privacy-notice.html +0 -68
  222. package/.server/server/views/help/terms-and-conditions.html +0 -83
  223. package/src/common/cookies.js +0 -58
  224. package/src/common/cookies.test.js +0 -23
  225. package/src/common/types.js +0 -5
  226. package/src/server/forms/README.md +0 -10
  227. package/src/server/forms/report-a-terrorist.json +0 -270
  228. package/src/server/forms/runner-components-test.json +0 -365
  229. package/src/server/forms/test.json +0 -581
  230. package/src/server/forms/test.yaml +0 -363
  231. package/src/server/plugins/blankie.test.ts +0 -73
  232. package/src/server/plugins/blankie.ts +0 -48
  233. package/src/server/plugins/engine/services/formsService.test.js +0 -90
  234. package/src/server/plugins/engine/views/layout.html +0 -199
  235. package/src/server/plugins/router.ts +0 -201
  236. package/src/server/routes/health.js +0 -13
  237. package/src/server/routes/health.test.js +0 -35
  238. package/src/server/routes/index.test.ts +0 -125
  239. package/src/server/utils/file-form-service.test.js +0 -79
  240. package/src/server/views/404.html +0 -16
  241. package/src/server/views/500.html +0 -19
  242. package/src/server/views/help/accessibility-statement.html +0 -58
  243. package/src/server/views/help/cookie-preferences.html +0 -57
  244. package/src/server/views/help/cookies.html +0 -71
  245. package/src/server/views/help/get-support.html +0 -37
  246. package/src/server/views/help/privacy-notice.html +0 -68
  247. package/src/server/views/help/terms-and-conditions.html +0 -83
@@ -1,199 +0,0 @@
1
- {% extends "govuk/template.njk" %}
2
-
3
- {% from "govuk/components/back-link/macro.njk" import govukBackLink -%}
4
- {% from "govuk/components/footer/macro.njk" import govukFooter -%}
5
- {% from "govuk/components/phase-banner/macro.njk" import govukPhaseBanner -%}
6
- {% from "govuk/components/skip-link/macro.njk" import govukSkipLink -%}
7
- {% from "govuk/macros/attributes.njk" import govukAttributes -%}
8
- {% from "components/service-banner/macro.njk" import appServiceBanner -%}
9
- {% from "components/tag-env/macro.njk" import appTagEnv -%}
10
- {% from "govuk/components/cookie-banner/macro.njk" import govukCookieBanner -%}
11
- {% from "govuk/components/notification-banner/macro.njk" import govukNotificationBanner -%}
12
-
13
- {% set productName %}
14
- {% if config.cdpEnvironment !== "prod" %}
15
- {{ appTagEnv({ env: config.cdpEnvironment }) }}
16
- {% endif %}
17
- {% endset %}
18
-
19
- {% block head %}
20
- <meta name="application-name" content="@defra/forms-runner" {{- govukAttributes({
21
- "data-environment": {
22
- value: config.cdpEnvironment,
23
- optional: true
24
- },
25
- "data-version": {
26
- value: config.serviceVersion,
27
- optional: true
28
- }
29
- }) }}>
30
-
31
- <link rel="preload" as="font" href="{{ assetPath }}/fonts/bold-b542beb274-v2.woff2" type="font/woff2" crossorigin="anonymous">
32
- <link rel="preload" as="font" href="{{ assetPath }}/fonts/light-94a07e06a1-v2.woff2" type="font/woff2" crossorigin="anonymous">
33
- <link rel="stylesheet" href="{{ getAssetPath("stylesheets/application.scss") }}">
34
- {% endblock %}
35
-
36
- {% block pageTitle -%}
37
- {{ "Error: " if errors | length }}{{ pageTitle | evaluate }} - {{ name if name else config.serviceName }} - GOV.UK
38
- {%- endblock %}
39
-
40
- {% block skipLink %}
41
- {{ govukSkipLink({
42
- href: '#main-content',
43
- text: 'Skip to main content'
44
- }) }}
45
- {% endblock %}
46
-
47
- {% block header %}
48
- {% if config.googleAnalyticsTrackingId and slug %}
49
- <form method="post" action="/help/cookie-preferences/{{ slug }}?returnUrl={{ currentPath | urlencode }}">
50
- <input type="hidden" name="crumb" value="{{ crumb }}">
51
-
52
- {% set acceptHtml %}
53
- <p class="govuk-body">You’ve accepted analytics cookies. You can <a class="govuk-link" href="/help/cookies/{{ slug }}">change your cookie settings</a> at any time.</p>
54
- {% endset %}
55
-
56
- {% set rejectedHtml %}
57
- <p class="govuk-body">You’ve rejected analytics cookies. You can <a class="govuk-link" href="/help/cookies/{{ slug }}">change your cookie settings</a> at any time.</p>
58
- {% endset %}
59
-
60
- {% if cookieConsent.analytics !== true and cookieConsent.analytics !== false and cookieConsent.dismissed !== true %}
61
- {% set html %}
62
- <p class="govuk-body">We use some essential cookies to make this service work.</p>
63
- <p class="govuk-body">We’d like to set analytics cookies so we can understand how people use the service and make improvements.</p>
64
- {% endset %}
65
-
66
- {{ govukCookieBanner({
67
- ariaLabel: "Cookies on " + config.serviceName,
68
- messages: [
69
- {
70
- headingText: config.serviceName,
71
- html: html,
72
- actions: [
73
- {
74
- text: "Accept analytics cookies",
75
- type: "submit",
76
- name: "cookies[analytics]",
77
- value: "yes"
78
- },
79
- {
80
- text: "Reject analytics cookies",
81
- type: "submit",
82
- name: "cookies[analytics]",
83
- value: "no"
84
- },
85
- {
86
- text: "View cookies",
87
- href: "/help/cookies/" + slug
88
- }
89
- ]
90
- }
91
- ]
92
- }) }}
93
- {% elif cookieConsent.dismissed === false %}
94
- {{ govukCookieBanner({
95
- ariaLabel: "Cookies on " + config.serviceName,
96
- messages: [
97
- {
98
- html: acceptHtml if cookieConsent.analytics === true else rejectedHtml,
99
- actions: [
100
- {
101
- text: "Hide cookie message",
102
- type: "submit",
103
- name: "cookies[dismissed]",
104
- value: "yes"
105
- }
106
- ]
107
- }
108
- ]
109
- }) }}
110
- {% endif %}
111
-
112
- </form>
113
- {% endif %}
114
-
115
- {% if config.serviceBannerText | length %}
116
- {{ appServiceBanner({
117
- title: "Service status",
118
- text: config.serviceBannerText
119
- }) }}
120
- {% endif %}
121
-
122
- {{ govukHeader({
123
- homepageUrl: currentPath if context.isForceAccess else "https://www.gov.uk",
124
- containerClasses: "govuk-width-container",
125
- productName: productName | safe | trim,
126
- serviceName: name if name else config.serviceName,
127
- serviceUrl: currentPath if context.isForceAccess else serviceUrl
128
- }) }}
129
- {% endblock %}
130
-
131
- {% block beforeContent %}
132
- {% set feedbackLink = feedbackLink or config.feedbackLink -%}
133
- {% set phaseTag = phaseTag or config.phaseTag -%}
134
-
135
- {% if phaseTag and feedbackLink %}
136
- {% set feedbackLinkHtml -%}
137
- <a href="{{ currentPath if context.isForceAccess else feedbackLink }}" class="govuk-link" {%- if not context.isForceAccess %} target="_blank" rel="noopener noreferrer" {%- endif %}>
138
- {%- if "mailto:" in feedbackLink -%}
139
- give your feedback by email
140
- {%- else -%}
141
- give your feedback (opens in new tab)
142
- {%- endif -%}
143
- </a>
144
- {%- endset %}
145
-
146
- {{ govukPhaseBanner({
147
- tag: { text: phaseTag | capitalize },
148
- html: "This is a new service. Help us improve it and " + feedbackLinkHtml | safe + "."
149
- }) }}
150
- {% endif %}
151
- {% if backLink %}
152
- {{ govukBackLink(backLink) }}
153
- {% endif %}
154
- {% endblock %}
155
-
156
- {% block content %}
157
- <h1 class="govuk-heading-l">Default page template</h1>
158
- {% endblock %}
159
-
160
- {% block bodyEnd %}
161
- <script type="module" nonce="{{ cspNonce }}" src="{{ getAssetPath("application.js") }}"></script>
162
-
163
- {% if config.googleAnalyticsTrackingId and cookieConsent.analytics === true %}
164
- <script id="ga-tag-js-main" nonce="{{ cspNonce }}" src="https://www.googletagmanager.com/gtag/js?id={{ config.googleAnalyticsTrackingId }}" defer></script>
165
- <script id="ga-tag-js-init" nonce="{{ cspNonce }}">
166
- window.dataLayer = window.dataLayer || [];
167
- function gtag(){dataLayer.push(arguments);}
168
- gtag('js', new Date());
169
- gtag('config', '{{ config.googleAnalyticsTrackingId }}');
170
- </script>
171
- {% endif %}
172
- {% endblock %}
173
-
174
- {% block footer %}
175
- {% set meta = {
176
- items: [
177
- {
178
- href: '/help/get-support/' + slug,
179
- text: 'Get help with this form'
180
- },
181
- {
182
- href: '/help/privacy/' + slug,
183
- text: 'Privacy'
184
- },
185
- {
186
- href: '/help/cookies/' + slug,
187
- text: 'Cookies'
188
- },
189
- {
190
- href: '/help/accessibility-statement/' + slug,
191
- text: 'Accessibility Statement'
192
- }
193
- ]
194
- } if slug %}
195
-
196
- {% if not context.isForceAccess %}
197
- {{ govukFooter({ meta: meta }) }}
198
- {% endif %}
199
- {% endblock %}
@@ -1,201 +0,0 @@
1
- import { slugSchema } from '@defra/forms-model'
2
- import Boom from '@hapi/boom'
3
- import { type ServerRegisterPluginObject } from '@hapi/hapi'
4
- import humanizeDuration from 'humanize-duration'
5
- import Joi from 'joi'
6
-
7
- import {
8
- defaultConsent,
9
- parseCookieConsent,
10
- serialiseCookieConsent
11
- } from '~/src/common/cookies.js'
12
- import { type CookieConsent } from '~/src/common/types.js'
13
- import { config } from '~/src/config/index.js'
14
- import { isPathRelative } from '~/src/server/plugins/engine/helpers.js'
15
- import { getFormMetadata } from '~/src/server/plugins/engine/services/formsService.js'
16
- import { healthRoute, publicRoutes } from '~/src/server/routes/index.js'
17
- import { crumbSchema } from '~/src/server/schemas/index.js'
18
-
19
- const routes = [...publicRoutes, healthRoute]
20
-
21
- export default {
22
- plugin: {
23
- name: 'router',
24
- register: (server) => {
25
- server.route(routes)
26
-
27
- // Shared help routes params schema & options
28
- const params = Joi.object()
29
- .keys({
30
- slug: slugSchema
31
- })
32
- .required()
33
-
34
- const options = {
35
- validate: {
36
- params
37
- }
38
- }
39
-
40
- server.route<{ Params: { slug: string } }>({
41
- method: 'get',
42
- path: '/help/get-support/{slug}',
43
- async handler(request, h) {
44
- const { slug } = request.params
45
- const form = await getFormMetadata(slug)
46
-
47
- return h.view('help/get-support', { form })
48
- },
49
- options
50
- })
51
-
52
- server.route<{ Params: { slug: string } }>({
53
- method: 'get',
54
- path: '/help/privacy/{slug}',
55
- async handler(request, h) {
56
- const { slug } = request.params
57
- const form = await getFormMetadata(slug)
58
-
59
- return h.view('help/privacy-notice', { form })
60
- },
61
- options
62
- })
63
-
64
- server.route<{ Params: { slug: string } }>({
65
- method: 'get',
66
- path: '/help/cookies/{slug}',
67
- handler(_request, h) {
68
- const sessionTimeout = config.get('sessionTimeout')
69
-
70
- const sessionDurationPretty = humanizeDuration(sessionTimeout)
71
-
72
- return h.view('help/cookies', {
73
- googleAnalyticsContainerId: config
74
- .get('googleAnalyticsTrackingId')
75
- .replace(/^G-/, ''),
76
- sessionDurationPretty
77
- })
78
- },
79
- options
80
- })
81
-
82
- server.route<{
83
- Params: { slug: string }
84
- Payload: {
85
- crumb?: string
86
- 'cookies[analytics]'?: string
87
- 'cookies[dismissed]'?: string
88
- }
89
- Query: { returnUrl?: string }
90
- }>({
91
- method: 'post',
92
- path: '/help/cookie-preferences/{slug}',
93
- handler(request, h) {
94
- const { params, payload, query } = request
95
- const { slug } = params
96
- let { returnUrl } = query
97
-
98
- if (returnUrl && !isPathRelative(returnUrl)) {
99
- throw Boom.badRequest('Return URL must be relative')
100
- }
101
-
102
- const analyticsDecision = (
103
- payload['cookies[analytics]'] ?? ''
104
- ).toLowerCase()
105
-
106
- const dismissedDecision = (
107
- payload['cookies[dismissed]'] ?? ''
108
- ).toLowerCase()
109
-
110
- // move the parser into our JS code so we can delegate to the frontend in a future iteration
111
- let cookieConsent: CookieConsent
112
-
113
- if (typeof request.state.cookieConsent === 'string') {
114
- cookieConsent = parseCookieConsent(request.state.cookieConsent)
115
- } else {
116
- cookieConsent = defaultConsent
117
- }
118
-
119
- if (analyticsDecision) {
120
- cookieConsent.analytics = analyticsDecision === 'yes'
121
- cookieConsent.dismissed = false
122
- }
123
-
124
- if (dismissedDecision) {
125
- cookieConsent.dismissed = dismissedDecision === 'yes'
126
- }
127
-
128
- if (!returnUrl) {
129
- cookieConsent.dismissed = true // this page already has a confirmation message, don't show another
130
- returnUrl = `/help/cookie-preferences/${slug}`
131
- }
132
-
133
- const serialisedCookieConsent = serialiseCookieConsent(cookieConsent)
134
- h.state('cookieConsent', serialisedCookieConsent)
135
-
136
- return h.redirect(returnUrl)
137
- },
138
- options: {
139
- validate: {
140
- params,
141
- payload: Joi.object({
142
- crumb: crumbSchema,
143
- 'cookies[analytics]': Joi.string().valid('yes', 'no').optional(),
144
- 'cookies[dismissed]': Joi.string().valid('yes', 'no').optional()
145
- }),
146
- query: Joi.object({
147
- returnUrl: Joi.string().optional()
148
- })
149
- }
150
- }
151
- })
152
-
153
- server.route({
154
- method: 'get',
155
- path: '/',
156
- handler() {
157
- throw Boom.notFound()
158
- }
159
- })
160
-
161
- server.route<{ Params: { slug: string } }>({
162
- method: 'get',
163
- path: '/help/cookie-preferences/{slug}',
164
- handler(request, h) {
165
- const { params } = request
166
- const { slug } = params
167
- let cookieConsentDismissed = false
168
-
169
- if (typeof request.state.cookieConsent === 'string') {
170
- const cookieConsent = parseCookieConsent(
171
- request.state.cookieConsent
172
- )
173
-
174
- cookieConsentDismissed = cookieConsent.dismissed
175
- }
176
-
177
- // if the user has come back to this page after updating their preferences
178
- // override the 'dismissed' behaviour to show a success notification instead of
179
- // the cookie banner
180
- const showConsentSuccess =
181
- cookieConsentDismissed &&
182
- request.info.referrer.endsWith(`/help/cookie-preferences/${slug}`)
183
-
184
- return h.view('help/cookie-preferences', {
185
- cookieConsentUpdated: showConsentSuccess
186
- })
187
- },
188
- options
189
- })
190
-
191
- server.route<{ Params: { slug: string } }>({
192
- method: 'get',
193
- path: '/help/accessibility-statement/{slug}',
194
- handler(_request, h) {
195
- return h.view('help/accessibility-statement')
196
- },
197
- options
198
- })
199
- }
200
- }
201
- } satisfies ServerRegisterPluginObject<void>
@@ -1,13 +0,0 @@
1
- import { StatusCodes } from 'http-status-codes'
2
-
3
- export default /** @type {ServerRoute} */ ({
4
- method: 'GET',
5
- path: '/health',
6
- handler(_, h) {
7
- return h.response({ message: 'success' }).code(StatusCodes.OK)
8
- }
9
- })
10
-
11
- /**
12
- * @import { ServerRoute } from '@hapi/hapi'
13
- */
@@ -1,35 +0,0 @@
1
- import { createServer } from '~/src/server/index.js'
2
-
3
- describe('Health check route', () => {
4
- const startServer = async () => {
5
- const server = await createServer()
6
- await server.initialize()
7
- return server
8
- }
9
-
10
- /** @type {Server} */
11
- let server
12
-
13
- afterEach(async () => {
14
- await server.stop()
15
- })
16
-
17
- test('/health route response is correct', async () => {
18
- server = await startServer()
19
-
20
- const options = {
21
- method: 'GET',
22
- url: '/health'
23
- }
24
-
25
- const { result } = await server.inject(options)
26
-
27
- expect(result).toMatchObject({
28
- message: 'success'
29
- })
30
- })
31
- })
32
-
33
- /**
34
- * @import { Server } from '@hapi/hapi'
35
- */
@@ -1,125 +0,0 @@
1
- import { type Server } from '@hapi/hapi'
2
- import { StatusCodes } from 'http-status-codes'
3
-
4
- import { config } from '~/src/config/index.js'
5
- import { createServer } from '~/src/server/index.js'
6
- import { getFormMetadata } from '~/src/server/plugins/engine/services/formsService.js'
7
- import * as fixtures from '~/test/fixtures/index.js'
8
- import { renderResponse } from '~/test/helpers/component-helpers.js'
9
-
10
- jest.mock('~/src/server/plugins/engine/services/formsService.js')
11
-
12
- describe('Routes', () => {
13
- let server: Server
14
-
15
- beforeAll(async () => {
16
- server = await createServer()
17
- await server.initialize()
18
- })
19
-
20
- afterAll(async () => {
21
- await server.stop()
22
- })
23
-
24
- test('cookies page is served with 24 hour duration', async () => {
25
- config.set('sessionTimeout', 86400000)
26
-
27
- const options = {
28
- method: 'GET',
29
- url: '/help/cookies/slug'
30
- }
31
-
32
- const { container } = await renderResponse(server, options)
33
-
34
- const $heading = container.getByRole('heading', {
35
- name: 'Cookies',
36
- level: 1
37
- })
38
-
39
- const $googleAnalyticsRowheader = container.getByRole('rowheader', {
40
- name: '_ga_123456789'
41
- })
42
-
43
- const $sessionDurationRow = container.getByRole('row', {
44
- name: 'session Remembers the information you enter When you close the browser, or after 1 day'
45
- })
46
-
47
- expect($heading).toBeInTheDocument()
48
- expect($heading).toHaveClass('govuk-heading-l')
49
- expect($googleAnalyticsRowheader).toBeInTheDocument()
50
- expect($sessionDurationRow).toBeInTheDocument()
51
- })
52
-
53
- test('accessibility statement page is served', async () => {
54
- const options = {
55
- method: 'GET',
56
- url: '/help/accessibility-statement/slug'
57
- }
58
-
59
- const { container } = await renderResponse(server, options)
60
-
61
- const $heading = container.getByRole('heading', {
62
- name: 'Accessibility statement for this form',
63
- level: 1
64
- })
65
-
66
- expect($heading).toBeInTheDocument()
67
- expect($heading).toHaveClass('govuk-heading-l')
68
- })
69
-
70
- test('Help page is served', async () => {
71
- jest.mocked(getFormMetadata).mockResolvedValue(fixtures.form.metadata)
72
-
73
- const options = {
74
- method: 'GET',
75
- url: '/help/get-support/slug'
76
- }
77
-
78
- const res = await server.inject(options)
79
-
80
- expect(res.statusCode).toBe(StatusCodes.OK)
81
- })
82
-
83
- test('Service banner is not shown by default', async () => {
84
- const { container } = await renderResponse(server, {
85
- method: 'GET',
86
- url: '/'
87
- })
88
-
89
- const $banner = container.queryByRole('complementary', {
90
- name: 'Service status'
91
- })
92
-
93
- expect($banner).not.toBeInTheDocument()
94
- })
95
-
96
- test('Service banner is not shown when empty', async () => {
97
- config.set('serviceBannerText', '')
98
-
99
- const { container } = await renderResponse(server, {
100
- method: 'GET',
101
- url: '/'
102
- })
103
-
104
- const $banner = container.queryByRole('complementary', {
105
- name: 'Service status'
106
- })
107
-
108
- expect($banner).not.toBeInTheDocument()
109
- })
110
-
111
- test('Service banner is shown when configured', async () => {
112
- config.set('serviceBannerText', 'Hello world')
113
-
114
- const { container } = await renderResponse(server, {
115
- method: 'GET',
116
- url: '/'
117
- })
118
-
119
- const $banner = container.getByRole('complementary', {
120
- name: 'Service status'
121
- })
122
-
123
- expect($banner).toHaveTextContent('Hello world')
124
- })
125
- })
@@ -1,79 +0,0 @@
1
- import { FormStatus } from '~/src/server/routes/types.js'
2
- import { FileFormService } from '~/src/server/utils/file-form-service.js'
3
-
4
- // Create the metadata which is shared for all forms
5
- const now = new Date()
6
- const user = { id: 'user', displayName: 'Username' }
7
- const author = {
8
- createdAt: now,
9
- createdBy: user,
10
- updatedAt: now,
11
- updatedBy: user
12
- }
13
-
14
- const metadata = {
15
- id: '95e92559-968d-44ae-8666-2b1ad3dffd31',
16
- slug: 'example-form',
17
- title: 'Example form',
18
- organisation: 'Defra',
19
- teamName: 'Team name',
20
- teamEmail: 'team@defra.gov.uk',
21
- submissionGuidance: "Thanks for your submission, we'll be in touch",
22
- notificationEmail: 'email@domain.com',
23
- ...author,
24
- live: author
25
- }
26
-
27
- describe('File Form Service', () => {
28
- it('should load JSON files from disk', async () => {
29
- const loader = new FileFormService()
30
-
31
- const definition = await loader.addForm(
32
- 'src/server/forms/test.json',
33
- metadata
34
- )
35
-
36
- const formsService = loader.toFormsService()
37
- expect(await formsService.getFormMetadata(metadata.slug)).toBe(metadata)
38
- expect(
39
- await formsService.getFormDefinition(metadata.id, FormStatus.Draft)
40
- ).toBe(definition)
41
-
42
- expect(() => loader.getFormMetadata('invalid-slug')).toThrow(
43
- "Form metadata 'invalid-slug' not found"
44
- )
45
- expect(() => loader.getFormDefinition('invalid-id')).toThrow(
46
- "Form definition 'invalid-id' not found"
47
- )
48
- })
49
-
50
- it('should load YAML files from disk', async () => {
51
- const loader = new FileFormService()
52
-
53
- const definition = await loader.addForm(
54
- 'src/server/forms/test.yaml',
55
- metadata
56
- )
57
-
58
- const formsService = loader.toFormsService()
59
- expect(await formsService.getFormMetadata(metadata.slug)).toBe(metadata)
60
- expect(
61
- await formsService.getFormDefinition(metadata.id, FormStatus.Draft)
62
- ).toBe(definition)
63
-
64
- expect(() => loader.getFormMetadata('invalid-slug')).toThrow(
65
- "Form metadata 'invalid-slug' not found"
66
- )
67
- expect(() => loader.getFormDefinition('invalid-id')).toThrow(
68
- "Form definition 'invalid-id' not found"
69
- )
70
- })
71
-
72
- it("should throw if the file isn't JSON or YAML", async () => {
73
- const loader = new FileFormService()
74
-
75
- await expect(
76
- loader.addForm('src/server/forms/test.txt', metadata)
77
- ).rejects.toThrow("Invalid file extension '.txt'")
78
- })
79
- })
@@ -1,16 +0,0 @@
1
- {% extends 'layout.html' %}
2
-
3
- {% block content %}
4
- <div class="govuk-width-container">
5
- <div class="govuk-main-wrapper">
6
- <div class="govuk-grid-row">
7
- <div class="govuk-grid-column-two-thirds">
8
- <h1 class="govuk-heading-l">Page not found</h1>
9
- <p class="govuk-body">If you typed the web address, check it is correct.</p>
10
- <p class="govuk-body">If you pasted the web address, check you copied the entire address.</p>
11
- <p class="govuk-body">If the web address is correct or you selected a link or button, <a href="https://www.gov.uk/guidance/contact-defra" class="govuk-link">contact the Defra Helpline</a> if you need to speak to someone about your form.</p>
12
- </div>
13
- </div>
14
- </div>
15
- </div>
16
- {% endblock %}
@@ -1,19 +0,0 @@
1
- {% extends 'layout.html' %}
2
-
3
- {% block content %}
4
- <div class="govuk-width-container">
5
- <div class="govuk-main-wrapper">
6
- <div class="govuk-grid-row">
7
- <div class="govuk-grid-column-two-thirds">
8
- <h1 class="govuk-heading-l">Sorry, there is a problem with the service</h1>
9
- <p class="govuk-body">You can:</p>
10
- <ul class="govuk-list govuk-list--bullet">
11
- <li>try your browser back button as your data may be saved</li>
12
- <li><a class="govuk-link" href="https://www.gov.uk/guidance/contact-defra">contact the Defra Helpline</a> if you
13
- have any questions</li>
14
- </ul>
15
- </div>
16
- </div>
17
- </div>
18
- </div>
19
- {% endblock %}