@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,4 +1,6 @@
1
1
  export const MAX_POLLING_DURATION = 300 // 5 minutes
2
+ const ARIA_DESCRIBEDBY = 'aria-describedby'
3
+ const ERROR_SUMMARY_TITLE_ID = 'error-summary-title'
2
4
 
3
5
  /**
4
6
  * Creates or updates status announcer for screen readers
@@ -127,7 +129,7 @@ function renderSummary(selectedFile, statusText, form) {
127
129
  const fileInput = form.querySelector('input[type="file"]')
128
130
 
129
131
  if (fileInput) {
130
- fileInput.setAttribute('aria-describedby', 'statusInformation')
132
+ fileInput.setAttribute(ARIA_DESCRIBEDBY, 'statusInformation')
131
133
  }
132
134
 
133
135
  const summaryList = findOrCreateSummaryList(
@@ -150,17 +152,30 @@ function renderSummary(selectedFile, statusText, form) {
150
152
 
151
153
  /**
152
154
  * Shows an error message using the GOV.UK error summary component
155
+ * and adds inline error styling to the file input
153
156
  * @param {string} message - The error message to display
154
157
  * @param {HTMLElement | null} errorSummary - The error summary container
155
158
  * @param {HTMLInputElement} fileInput - The file input element
156
159
  * @returns {void}
157
160
  */
158
161
  function showError(message, errorSummary, fileInput) {
162
+ const topErrorSummary = document.querySelector('.govuk-error-summary')
163
+
164
+ if (topErrorSummary) {
165
+ const titleElement = document.getElementById(ERROR_SUMMARY_TITLE_ID)
166
+ if (titleElement) {
167
+ fileInput.setAttribute(ARIA_DESCRIBEDBY, ERROR_SUMMARY_TITLE_ID)
168
+ } else {
169
+ fileInput.removeAttribute(ARIA_DESCRIBEDBY)
170
+ }
171
+ return
172
+ }
173
+
159
174
  if (errorSummary) {
160
175
  errorSummary.innerHTML = `
161
176
  <div class="govuk-error-summary" data-module="govuk-error-summary">
162
177
  <div role="alert">
163
- <h2 class="govuk-error-summary__title" id="error-summary-title">
178
+ <h2 class="govuk-error-summary__title" id="${ERROR_SUMMARY_TITLE_ID}">
164
179
  There is a problem
165
180
  </h2>
166
181
  <div class="govuk-error-summary__body">
@@ -173,7 +188,30 @@ function showError(message, errorSummary, fileInput) {
173
188
  </div>
174
189
  </div>
175
190
  `
176
- fileInput.setAttribute('aria-describedby', 'error-summary-title')
191
+
192
+ fileInput.setAttribute(ARIA_DESCRIBEDBY, ERROR_SUMMARY_TITLE_ID)
193
+ }
194
+
195
+ const formGroup = fileInput.closest('.govuk-form-group')
196
+ if (formGroup) {
197
+ formGroup.classList.add('govuk-form-group--error')
198
+ fileInput.classList.add('govuk-file-upload--error')
199
+
200
+ const inputId = fileInput.id
201
+ let errorMessage = document.getElementById(`${inputId}-error`)
202
+
203
+ if (!errorMessage) {
204
+ errorMessage = document.createElement('p')
205
+ errorMessage.id = `${inputId}-error`
206
+ errorMessage.className = 'govuk-error-message'
207
+ errorMessage.innerHTML = `<span class="govuk-visually-hidden">Error:</span> ${message}`
208
+ formGroup.insertBefore(errorMessage, fileInput)
209
+ }
210
+
211
+ fileInput.setAttribute(
212
+ ARIA_DESCRIBEDBY,
213
+ `error-summary-title ${inputId}-error`
214
+ )
177
215
  }
178
216
  }
179
217
 
@@ -190,6 +228,18 @@ function reloadPage() {
190
228
  window.location.href = window.location.pathname
191
229
  }
192
230
 
231
+ /**
232
+ * Build the upload status URL given the current pathname and the upload ID.
233
+ * @param {string} pathname – e.g. window.location.pathname
234
+ * @param {string} uploadId
235
+ * @returns {string} e.g. "/form/upload-status/abc123"
236
+ */
237
+ export function buildUploadStatusUrl(pathname, uploadId) {
238
+ const pathSegments = pathname.split('/').filter((segment) => segment)
239
+ const prefix = pathSegments.length > 0 ? `/${pathSegments[0]}` : ''
240
+ return `${prefix}/upload-status/${uploadId}`
241
+ }
242
+
193
243
  /**
194
244
  * Polls the upload status endpoint until the file is ready or timeout occurs
195
245
  * @param {string} uploadId - The upload ID to check
@@ -205,7 +255,12 @@ function pollUploadStatus(uploadId) {
205
255
  return
206
256
  }
207
257
 
208
- fetch(`/upload-status/${uploadId}`, {
258
+ const uploadStatusUrl = buildUploadStatusUrl(
259
+ window.location.pathname,
260
+ uploadId
261
+ )
262
+
263
+ fetch(uploadStatusUrl, {
209
264
  headers: {
210
265
  Accept: 'application/json'
211
266
  }
@@ -343,6 +398,7 @@ export function initFileUpload() {
343
398
  if (errorSummary) {
344
399
  errorSummary.innerHTML = ''
345
400
  }
401
+
346
402
  if (fileInput.files && fileInput.files.length > 0) {
347
403
  selectedFile = fileInput.files[0]
348
404
  }
@@ -12,3 +12,13 @@
12
12
  .autocomplete__option {
13
13
  @include govuk-typography-common;
14
14
  }
15
+
16
+ // An example of some user-supplied styling
17
+ // Not great practice but it illustrates the point
18
+ .govuk-header {
19
+ background: #008531;
20
+ }
21
+
22
+ .govuk-header__container {
23
+ border-bottom: 10px solid #003d16;
24
+ }
@@ -179,12 +179,6 @@ export const config = convict({
179
179
  /**
180
180
  * API integrations
181
181
  */
182
- managerUrl: {
183
- format: String,
184
- default: 'http://localhost:3001',
185
- env: 'MANAGER_URL'
186
- } as SchemaObj<string>,
187
-
188
182
  designerUrl: {
189
183
  format: String,
190
184
  default: 'http://localhost:3000',
@@ -253,19 +247,12 @@ export const config = convict({
253
247
  env: 'STAGING_PREFIX'
254
248
  },
255
249
 
256
- serviceBannerText: {
257
- doc: 'Service banner text used to show a maintenance message on all pages when set',
258
- format: String,
259
- default: '',
260
- env: 'SERVICE_BANNER_TEXT'
261
- },
262
-
263
- googleAnalyticsTrackingId: {
264
- doc: 'Google analytics tracking ID to be used when a user has opted in to additional cookies',
250
+ submissionEmailAddress: {
251
+ doc: 'Email address to send the form to (local devtool only)',
265
252
  format: String,
266
253
  default: '',
267
- env: 'GOOGLE_ANALYTICS_TRACKING_ID'
268
- }
254
+ env: 'SUBMISSION_EMAIL_ADDRESS'
255
+ } as SchemaObj<string>
269
256
  })
270
257
 
271
258
  config.validate({ allowed: 'strict' })
@@ -1 +1,3 @@
1
1
  export const PREVIEW_PATH_PREFIX = '/preview'
2
+ export const ERROR_PREVIEW_PATH_PREFIX = '/error-preview'
3
+ export const FORM_PREFIX = ''
@@ -0,0 +1,71 @@
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
+ {{ appTagEnv({ env: "devtool" }) }}
15
+ {% endset %}
16
+
17
+ {% block head %}
18
+ <link rel="preload" as="font" href="{{ assetPath }}/fonts/bold-b542beb274-v2.woff2" type="font/woff2" crossorigin="anonymous">
19
+ <link rel="preload" as="font" href="{{ assetPath }}/fonts/light-94a07e06a1-v2.woff2" type="font/woff2" crossorigin="anonymous">
20
+ <link rel="stylesheet" href="{{ getDxtAssetPath("stylesheets/application.scss") }}">
21
+ {% endblock %}
22
+
23
+ {% block pageTitle -%}
24
+ {{ "Error: " if errors | length }}{{ pageTitle | evaluate }} - {{ name if name else config.serviceName }} - GOV.UK
25
+ {%- endblock %}
26
+
27
+ {% block skipLink %}
28
+ {{ govukSkipLink({
29
+ href: '#main-content',
30
+ text: 'Skip to main content'
31
+ }) }}
32
+ {% endblock %}
33
+
34
+ {% block header %}
35
+ {{ govukHeader({
36
+ homepageUrl: currentPath if context.isForceAccess else "https://defra.github.io/forms-engine-plugin/",
37
+ containerClasses: "govuk-width-container",
38
+ productName: productName | safe | trim,
39
+ serviceName: "Digital Express Toolkit",
40
+ serviceUrl: currentPath if context.isForceAccess else serviceUrl
41
+ }) }}
42
+ {% endblock %}
43
+
44
+ {% block beforeContent %}
45
+ {% if backLink %}
46
+ {{ govukBackLink(backLink) }}
47
+ {% endif %}
48
+ {% endblock %}
49
+
50
+ {% block content %}
51
+ <h1 class="govuk-heading-l">Default page template</h1>
52
+ {% endblock %}
53
+
54
+ {% block bodyEnd %}
55
+ <script type="module" nonce="{{ cspNonce }}" src="{{ getDxtAssetPath("application.js") }}"></script>
56
+ {% endblock %}
57
+
58
+ {% block footer %}
59
+ {% set meta = {
60
+ items: [
61
+ {
62
+ href: 'https://defra.github.io/forms-engine-plugin/',
63
+ text: 'DXT documentation'
64
+ }
65
+ ]
66
+ } if slug %}
67
+
68
+ {% if not context.isForceAccess %}
69
+ {{ govukFooter({ meta: meta }) }}
70
+ {% endif %}
71
+ {% endblock %}
@@ -0,0 +1,393 @@
1
+ {
2
+ "name": "Register as a unicorn breeder",
3
+ "pages": [
4
+ {
5
+ "path": "/whats-your-name",
6
+ "title": "What's your name?",
7
+ "components": [
8
+ {
9
+ "type": "TextField",
10
+ "name": "textField",
11
+ "title": "Name",
12
+ "hint": "This is a single line text box. We use it to ask for information that's likely to be 1 sentence",
13
+ "options": {
14
+ "required": true
15
+ },
16
+ "schema": {}
17
+ }
18
+ ],
19
+ "next": [
20
+ {
21
+ "path": "/whats-your-email-address"
22
+ }
23
+ ],
24
+ "section": "section"
25
+ },
26
+ {
27
+ "title": "Summary",
28
+ "path": "/summary",
29
+ "controller": "./pages/summary.js",
30
+ "components": [],
31
+ "next": []
32
+ },
33
+ {
34
+ "path": "/whats-your-email-address",
35
+ "title": "What's your email address?",
36
+ "components": [
37
+ {
38
+ "name": "MaTzaT",
39
+ "options": {
40
+ "required": true
41
+ },
42
+ "type": "EmailAddressField",
43
+ "title": "Email adress",
44
+ "schema": {},
45
+ "hint": "This is an email address. An email address must contain an at sign @"
46
+ }
47
+ ],
48
+ "next": [
49
+ {
50
+ "path": "/whats-your-phone-number"
51
+ }
52
+ ],
53
+ "section": "section"
54
+ },
55
+ {
56
+ "path": "/whats-your-phone-number",
57
+ "title": "What's your phone number?",
58
+ "components": [
59
+ {
60
+ "name": "BdKgCe",
61
+ "options": {
62
+ "required": true
63
+ },
64
+ "type": "TelephoneNumberField",
65
+ "title": "Phone number",
66
+ "schema": {},
67
+ "hint": "This is a telephone number. This field can only contain numbers and the + symbol"
68
+ }
69
+ ],
70
+ "next": [
71
+ {
72
+ "path": "/whats-your-address"
73
+ }
74
+ ],
75
+ "section": "section"
76
+ },
77
+ {
78
+ "path": "/whats-your-address",
79
+ "title": "What's your address?",
80
+ "components": [
81
+ {
82
+ "name": "wZLWPy",
83
+ "options": {
84
+ "required": true
85
+ },
86
+ "type": "UkAddressField",
87
+ "title": "Address",
88
+ "schema": {},
89
+ "hint": "This is a UK address. Users must enter address line 1, town and a postcode"
90
+ }
91
+ ],
92
+ "next": [
93
+ {
94
+ "path": "/do-you-want-your-unicorn-breeder-certificate-sent-to-this-address"
95
+ }
96
+ ],
97
+ "section": "section"
98
+ },
99
+ {
100
+ "path": "/do-you-want-your-unicorn-breeder-certificate-sent-to-this-address",
101
+ "title": "Do you want your unicorn breeder certificate sent to this address?",
102
+ "components": [
103
+ {
104
+ "name": "dBfuID",
105
+ "options": {},
106
+ "type": "YesNoField",
107
+ "title": "Send certificate to same address",
108
+ "schema": {},
109
+ "hint": "This is a yes or no question. We can branch to different questions based on the answer",
110
+ "values": {
111
+ "type": "listRef"
112
+ }
113
+ }
114
+ ],
115
+ "next": [
116
+ {
117
+ "path": "/what-address-do-you-want-the-certificate-sent-to",
118
+ "condition": "oyGPwP"
119
+ },
120
+ {
121
+ "path": "/when-does-your-unicorn-insurance-policy-start",
122
+ "condition": ""
123
+ }
124
+ ],
125
+ "section": "section"
126
+ },
127
+ {
128
+ "path": "/what-address-do-you-want-the-certificate-sent-to",
129
+ "title": "What address do you want the certificate sent to?",
130
+ "components": [
131
+ {
132
+ "name": "AegFro",
133
+ "options": {},
134
+ "type": "UkAddressField",
135
+ "title": "Address to send certificate",
136
+ "schema": {},
137
+ "hint": "This is a simple branch to an extra question - it's shown to users who select 'no' when asked if this is the address where the certificate should be sent"
138
+ }
139
+ ],
140
+ "next": [
141
+ {
142
+ "path": "/when-does-your-unicorn-insurance-policy-start"
143
+ }
144
+ ],
145
+ "section": "section"
146
+ },
147
+ {
148
+ "title": "When does your unicorn insurance policy start?",
149
+ "path": "/when-does-your-unicorn-insurance-policy-start",
150
+ "section": "Regnsa",
151
+ "next": [
152
+ {
153
+ "path": "/upload-your-insurance-certificate"
154
+ }
155
+ ],
156
+ "components": [
157
+ {
158
+ "name": "mjAccr",
159
+ "options": {},
160
+ "type": "DatePartsField",
161
+ "title": "Unicorn insurance policy start date",
162
+ "schema": {},
163
+ "hint": "This is a date. We can add custom validation to the field based on your requirements. For example, the date entered must be before or after a certain date"
164
+ }
165
+ ]
166
+ },
167
+ {
168
+ "title": "How many unicorns do you expect to breed each year?",
169
+ "path": "/how-many-unicorns-do-you-expect-to-breed-each-year",
170
+ "section": "susaYr",
171
+ "next": [
172
+ {
173
+ "path": "/what-type-of-unicorns-will-you-breed"
174
+ }
175
+ ],
176
+ "components": [
177
+ {
178
+ "name": "aitzzV",
179
+ "options": {},
180
+ "type": "RadiosField",
181
+ "list": "IeFOkf",
182
+ "title": "Number of unicorns",
183
+ "schema": {},
184
+ "hint": "This is a radio button. Users can only select one option from the list",
185
+ "values": {
186
+ "type": "listRef"
187
+ }
188
+ }
189
+ ]
190
+ },
191
+ {
192
+ "title": "What type of unicorns will you breed?",
193
+ "path": "/what-type-of-unicorns-will-you-breed",
194
+ "section": "susaYr",
195
+ "next": [
196
+ {
197
+ "path": "/where-will-you-keep-the-unicorns"
198
+ }
199
+ ],
200
+ "components": [
201
+ {
202
+ "name": "DyfjJC",
203
+ "options": {},
204
+ "type": "CheckboxesField",
205
+ "list": "fXiZrL",
206
+ "title": "Type of unicorn",
207
+ "schema": {},
208
+ "hint": "This is a check box. Users can select more than one option",
209
+ "values": {
210
+ "type": "listRef"
211
+ }
212
+ }
213
+ ]
214
+ },
215
+ {
216
+ "title": "Where will you keep the unicorns?",
217
+ "path": "/where-will-you-keep-the-unicorns",
218
+ "section": "susaYr",
219
+ "next": [
220
+ {
221
+ "path": "/how-many-members-of-staff-will-look-after-the-unicorns"
222
+ }
223
+ ],
224
+ "components": [
225
+ {
226
+ "name": "bClCvo",
227
+ "options": {},
228
+ "schema": {},
229
+ "type": "MultilineTextField",
230
+ "title": "Where you keep the unicorn",
231
+ "hint": "This is a multi-line text box. We use it when you expect the response to be more than 1 sentence long"
232
+ }
233
+ ]
234
+ },
235
+ {
236
+ "title": "How many members of staff will look after the unicorns?",
237
+ "path": "/how-many-members-of-staff-will-look-after-the-unicorns",
238
+ "section": "susaYr",
239
+ "next": [
240
+ {
241
+ "path": "/summary"
242
+ }
243
+ ],
244
+ "components": [
245
+ {
246
+ "name": "zhJMaM",
247
+ "options": {
248
+ "classes": "govuk-!-width-one-quarter"
249
+ },
250
+ "type": "NumberField",
251
+ "title": "Number of staff",
252
+ "schema": {},
253
+ "hint": "This is a number field. The answer must be a number. We can use custom validation to set decimal places, minimum and maximum values"
254
+ }
255
+ ]
256
+ },
257
+ {
258
+ "title": "Upload your insurance certificate",
259
+ "path": "/upload-your-insurance-certificate",
260
+ "controller": "FileUploadPageController",
261
+ "section": "Regnsa",
262
+ "next": [
263
+ {
264
+ "path": "/how-many-unicorns-do-you-expect-to-breed-each-year"
265
+ }
266
+ ],
267
+ "components": [
268
+ {
269
+ "name": "dLzALM",
270
+ "title": "Documents",
271
+ "type": "FileUploadField",
272
+ "hint": "We can specify the format and number of uploaded files",
273
+ "options": {
274
+ "required": false
275
+ },
276
+ "schema": {
277
+ "min": 1,
278
+ "max": 3
279
+ }
280
+ }
281
+ ]
282
+ }
283
+ ],
284
+ "conditions": [
285
+ {
286
+ "displayName": "Address is different",
287
+ "name": "IrVmYz",
288
+ "value": {
289
+ "name": "Address is different",
290
+ "conditions": [
291
+ {
292
+ "field": {
293
+ "name": "dBfuID",
294
+ "type": "YesNoField",
295
+ "display": "Contact details: Send certificate to same address"
296
+ },
297
+ "operator": "is",
298
+ "value": {
299
+ "type": "Value",
300
+ "value": "false",
301
+ "display": "false"
302
+ }
303
+ }
304
+ ]
305
+ }
306
+ },
307
+ {
308
+ "displayName": "Address is not the same",
309
+ "name": "oyGPwP",
310
+ "value": {
311
+ "name": "Address is not the same",
312
+ "conditions": [
313
+ {
314
+ "field": {
315
+ "name": "dBfuID",
316
+ "type": "YesNoField",
317
+ "display": "Contact details: Send certificate to same address"
318
+ },
319
+ "operator": "is",
320
+ "value": {
321
+ "type": "Value",
322
+ "value": "false",
323
+ "display": "No"
324
+ }
325
+ }
326
+ ]
327
+ }
328
+ }
329
+ ],
330
+ "sections": [
331
+ {
332
+ "name": "section",
333
+ "title": "Contact details",
334
+ "hideTitle": false
335
+ },
336
+ {
337
+ "title": "Unicorn details",
338
+ "name": "susaYr",
339
+ "hideTitle": false
340
+ },
341
+ {
342
+ "title": "Insurance details",
343
+ "name": "Regnsa",
344
+ "hideTitle": false
345
+ }
346
+ ],
347
+ "lists": [
348
+ {
349
+ "title": "number of unicorns",
350
+ "name": "IeFOkf",
351
+ "type": "string",
352
+ "items": [
353
+ {
354
+ "text": "1 to 5",
355
+ "value": "1 to 5"
356
+ },
357
+ {
358
+ "text": "6 to 10",
359
+ "value": "6 to 10"
360
+ },
361
+ {
362
+ "text": "11 or more",
363
+ "value": "11 or more"
364
+ }
365
+ ]
366
+ },
367
+ {
368
+ "title": "Type of unicorn",
369
+ "name": "fXiZrL",
370
+ "type": "string",
371
+ "items": [
372
+ {
373
+ "text": "Flying",
374
+ "value": "Flying"
375
+ },
376
+ {
377
+ "text": "Fire breathing",
378
+ "value": "Fire breathing"
379
+ },
380
+ {
381
+ "text": "Aquatic",
382
+ "value": "Aquatic"
383
+ },
384
+ {
385
+ "text": "Rainbow",
386
+ "value": "Rainbow"
387
+ }
388
+ ]
389
+ }
390
+ ],
391
+ "outputEmail": "defraforms@defra.gov.uk",
392
+ "startPage": "/whats-your-name"
393
+ }