@defra/forms-engine-plugin 0.0.3 → 0.0.4

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 (328) hide show
  1. package/.public/assets/fonts/bold-affa96571d-v2.woff +0 -0
  2. package/.public/assets/fonts/bold-b542beb274-v2.woff2 +0 -0
  3. package/.public/assets/fonts/light-94a07e06a1-v2.woff2 +0 -0
  4. package/.public/assets/fonts/light-f591b13f7d-v2.woff +0 -0
  5. package/.public/assets/images/favicon.ico +0 -0
  6. package/.public/assets/images/favicon.svg +1 -0
  7. package/.public/assets/images/govuk-crest.svg +1 -0
  8. package/.public/assets/images/govuk-icon-180.png +0 -0
  9. package/.public/assets/images/govuk-icon-192.png +0 -0
  10. package/.public/assets/images/govuk-icon-512.png +0 -0
  11. package/.public/assets/images/govuk-icon-mask.svg +1 -0
  12. package/.public/assets/images/govuk-opengraph-image.png +0 -0
  13. package/.public/assets/manifest.json +39 -0
  14. package/.public/assets-manifest.json +24 -0
  15. package/.public/javascripts/application.0fd8c18.min.js +3 -0
  16. package/.public/javascripts/application.0fd8c18.min.js.LICENSE.txt +58 -0
  17. package/.public/javascripts/application.0fd8c18.min.js.map +1 -0
  18. package/.public/javascripts/file-upload.b2f18f5.min.js +2 -0
  19. package/.public/javascripts/file-upload.b2f18f5.min.js.map +1 -0
  20. package/.public/javascripts/vendor/accessible-autocomplete.275d332.min.js +2 -0
  21. package/.public/javascripts/vendor/accessible-autocomplete.275d332.min.js.map +1 -0
  22. package/.public/stylesheets/application.e340021.min.css +14 -0
  23. package/.public/stylesheets/application.e340021.min.css.map +1 -0
  24. package/package.json +6 -2
  25. package/.browserslistrc +0 -16
  26. package/.editorconfig +0 -9
  27. package/.eslintrc.cjs +0 -266
  28. package/.github/dependabot.yml +0 -85
  29. package/.github/workflows/check-pull-request.yml +0 -209
  30. package/.github/workflows/pr-notifier.yml +0 -98
  31. package/.github/workflows/publish.yml +0 -111
  32. package/.husky/pre-commit +0 -1
  33. package/.lintstagedrc.js +0 -4
  34. package/.nvmrc +0 -1
  35. package/.prettierignore +0 -8
  36. package/.prettierrc.cjs +0 -26
  37. package/Dockerfile +0 -61
  38. package/Procfile +0 -1
  39. package/babel.config.cjs +0 -55
  40. package/compose/aws.env +0 -4
  41. package/compose/start-localstack.sh +0 -26
  42. package/docker-compose.yaml +0 -86
  43. package/globals.d.ts +0 -1
  44. package/jest.config.cjs +0 -54
  45. package/jest.environment.js +0 -4
  46. package/jest.setup.cjs +0 -14
  47. package/postcss.config.js +0 -26
  48. package/sonar-project.properties +0 -17
  49. package/src/client/javascripts/application.js +0 -87
  50. package/src/client/javascripts/file-upload.js +0 -386
  51. package/src/client/stylesheets/_code.scss +0 -33
  52. package/src/client/stylesheets/_govuk-frontend.scss +0 -4
  53. package/src/client/stylesheets/_prose.scss +0 -56
  54. package/src/client/stylesheets/_service-banner.scss +0 -24
  55. package/src/client/stylesheets/_summary-list.scss +0 -28
  56. package/src/client/stylesheets/_tag-env.scss +0 -24
  57. package/src/client/stylesheets/application.scss +0 -14
  58. package/src/common/cookies.js +0 -58
  59. package/src/common/cookies.test.js +0 -23
  60. package/src/common/types.js +0 -5
  61. package/src/config/index.ts +0 -271
  62. package/src/index.ts +0 -31
  63. package/src/server/common/helpers/logging/logger-options.test.ts +0 -50
  64. package/src/server/common/helpers/logging/logger-options.ts +0 -46
  65. package/src/server/common/helpers/logging/logger.ts +0 -7
  66. package/src/server/common/helpers/logging/request-logger.ts +0 -9
  67. package/src/server/common/helpers/logging/request-tracing.js +0 -10
  68. package/src/server/common/helpers/redis-client.js +0 -70
  69. package/src/server/constants.js +0 -1
  70. package/src/server/forms/README.md +0 -10
  71. package/src/server/forms/components.json +0 -1015
  72. package/src/server/forms/report-a-terrorist.json +0 -270
  73. package/src/server/forms/runner-components-test.json +0 -365
  74. package/src/server/forms/test.json +0 -581
  75. package/src/server/index.test.ts +0 -582
  76. package/src/server/index.ts +0 -140
  77. package/src/server/plugins/blankie.test.ts +0 -73
  78. package/src/server/plugins/blankie.ts +0 -48
  79. package/src/server/plugins/crumb.ts +0 -20
  80. package/src/server/plugins/engine/README.md +0 -87
  81. package/src/server/plugins/engine/components/AutocompleteField.test.ts +0 -294
  82. package/src/server/plugins/engine/components/AutocompleteField.ts +0 -49
  83. package/src/server/plugins/engine/components/CheckboxesField.test.ts +0 -379
  84. package/src/server/plugins/engine/components/CheckboxesField.ts +0 -106
  85. package/src/server/plugins/engine/components/ComponentBase.ts +0 -97
  86. package/src/server/plugins/engine/components/ComponentCollection.ts +0 -278
  87. package/src/server/plugins/engine/components/DatePartsField.test.ts +0 -822
  88. package/src/server/plugins/engine/components/DatePartsField.ts +0 -264
  89. package/src/server/plugins/engine/components/Details.test.ts +0 -49
  90. package/src/server/plugins/engine/components/Details.ts +0 -30
  91. package/src/server/plugins/engine/components/EmailAddressField.test.ts +0 -395
  92. package/src/server/plugins/engine/components/EmailAddressField.ts +0 -55
  93. package/src/server/plugins/engine/components/FileUploadField.test.ts +0 -778
  94. package/src/server/plugins/engine/components/FileUploadField.ts +0 -262
  95. package/src/server/plugins/engine/components/FormComponent.ts +0 -249
  96. package/src/server/plugins/engine/components/Html.test.ts +0 -48
  97. package/src/server/plugins/engine/components/Html.ts +0 -29
  98. package/src/server/plugins/engine/components/InsetText.test.ts +0 -48
  99. package/src/server/plugins/engine/components/InsetText.ts +0 -27
  100. package/src/server/plugins/engine/components/List.test.ts +0 -76
  101. package/src/server/plugins/engine/components/List.ts +0 -72
  102. package/src/server/plugins/engine/components/ListFormComponent.ts +0 -140
  103. package/src/server/plugins/engine/components/MonthYearField.test.ts +0 -567
  104. package/src/server/plugins/engine/components/MonthYearField.ts +0 -222
  105. package/src/server/plugins/engine/components/MultilineTextField.test.ts +0 -558
  106. package/src/server/plugins/engine/components/MultilineTextField.ts +0 -138
  107. package/src/server/plugins/engine/components/NumberField.test.ts +0 -701
  108. package/src/server/plugins/engine/components/NumberField.ts +0 -163
  109. package/src/server/plugins/engine/components/RadiosField.test.ts +0 -288
  110. package/src/server/plugins/engine/components/RadiosField.ts +0 -24
  111. package/src/server/plugins/engine/components/SelectField.test.ts +0 -288
  112. package/src/server/plugins/engine/components/SelectField.ts +0 -47
  113. package/src/server/plugins/engine/components/SelectionControlField.ts +0 -43
  114. package/src/server/plugins/engine/components/TelephoneNumberField.test.ts +0 -356
  115. package/src/server/plugins/engine/components/TelephoneNumberField.ts +0 -67
  116. package/src/server/plugins/engine/components/TextField.test.ts +0 -489
  117. package/src/server/plugins/engine/components/TextField.ts +0 -96
  118. package/src/server/plugins/engine/components/UkAddressField.test.ts +0 -623
  119. package/src/server/plugins/engine/components/UkAddressField.ts +0 -172
  120. package/src/server/plugins/engine/components/YesNoField.test.ts +0 -248
  121. package/src/server/plugins/engine/components/YesNoField.ts +0 -31
  122. package/src/server/plugins/engine/components/constants.ts +0 -1
  123. package/src/server/plugins/engine/components/helpers.ts +0 -330
  124. package/src/server/plugins/engine/components/index.ts +0 -24
  125. package/src/server/plugins/engine/components/types.ts +0 -117
  126. package/src/server/plugins/engine/configureEnginePlugin.ts +0 -47
  127. package/src/server/plugins/engine/helpers.test.ts +0 -791
  128. package/src/server/plugins/engine/helpers.ts +0 -379
  129. package/src/server/plugins/engine/index.ts +0 -7
  130. package/src/server/plugins/engine/models/FormModel.test.ts +0 -42
  131. package/src/server/plugins/engine/models/FormModel.ts +0 -443
  132. package/src/server/plugins/engine/models/RepeatingSummaryViewModel.ts +0 -0
  133. package/src/server/plugins/engine/models/Section.ts +0 -0
  134. package/src/server/plugins/engine/models/SummaryViewModel.test.ts +0 -209
  135. package/src/server/plugins/engine/models/SummaryViewModel.ts +0 -220
  136. package/src/server/plugins/engine/models/index.ts +0 -2
  137. package/src/server/plugins/engine/models/types.ts +0 -114
  138. package/src/server/plugins/engine/outputFormatters/human/v1.test.ts +0 -143
  139. package/src/server/plugins/engine/outputFormatters/human/v1.ts +0 -73
  140. package/src/server/plugins/engine/outputFormatters/index.test.ts +0 -17
  141. package/src/server/plugins/engine/outputFormatters/index.ts +0 -44
  142. package/src/server/plugins/engine/outputFormatters/machine/v1.test.ts +0 -229
  143. package/src/server/plugins/engine/outputFormatters/machine/v1.ts +0 -140
  144. package/src/server/plugins/engine/outputFormatters/machine/v2.test.ts +0 -229
  145. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +0 -153
  146. package/src/server/plugins/engine/pageControllers/FileUploadPageController.test.ts +0 -1108
  147. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +0 -446
  148. package/src/server/plugins/engine/pageControllers/PageController.test.ts +0 -205
  149. package/src/server/plugins/engine/pageControllers/PageController.ts +0 -176
  150. package/src/server/plugins/engine/pageControllers/QuestionPageController.test.ts +0 -1264
  151. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +0 -561
  152. package/src/server/plugins/engine/pageControllers/README.md +0 -28
  153. package/src/server/plugins/engine/pageControllers/RepeatPageController.test.ts +0 -264
  154. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +0 -458
  155. package/src/server/plugins/engine/pageControllers/StartPageController.ts +0 -18
  156. package/src/server/plugins/engine/pageControllers/StatusPageController.ts +0 -50
  157. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +0 -261
  158. package/src/server/plugins/engine/pageControllers/TerminalController.test.ts +0 -28
  159. package/src/server/plugins/engine/pageControllers/TerminalPageController.ts +0 -19
  160. package/src/server/plugins/engine/pageControllers/helpers.test.ts +0 -198
  161. package/src/server/plugins/engine/pageControllers/helpers.ts +0 -101
  162. package/src/server/plugins/engine/pageControllers/index.ts +0 -10
  163. package/src/server/plugins/engine/pageControllers/validationOptions.ts +0 -89
  164. package/src/server/plugins/engine/plugin.ts +0 -673
  165. package/src/server/plugins/engine/services/formSubmissionService.js +0 -46
  166. package/src/server/plugins/engine/services/formsService.js +0 -46
  167. package/src/server/plugins/engine/services/formsService.test.js +0 -90
  168. package/src/server/plugins/engine/services/index.js +0 -3
  169. package/src/server/plugins/engine/services/notifyService.test.ts +0 -132
  170. package/src/server/plugins/engine/services/notifyService.ts +0 -64
  171. package/src/server/plugins/engine/services/uploadService.js +0 -60
  172. package/src/server/plugins/engine/types.ts +0 -315
  173. package/src/server/plugins/engine/views/components/autocompletefield.html +0 -5
  174. package/src/server/plugins/engine/views/components/checkboxesfield.html +0 -5
  175. package/src/server/plugins/engine/views/components/datepartsfield.html +0 -5
  176. package/src/server/plugins/engine/views/components/details.html +0 -6
  177. package/src/server/plugins/engine/views/components/emailaddressfield.html +0 -5
  178. package/src/server/plugins/engine/views/components/fileuploadfield-key.html +0 -8
  179. package/src/server/plugins/engine/views/components/fileuploadfield-value.html +0 -3
  180. package/src/server/plugins/engine/views/components/fileuploadfield.html +0 -24
  181. package/src/server/plugins/engine/views/components/html.html +0 -3
  182. package/src/server/plugins/engine/views/components/insettext.html +0 -7
  183. package/src/server/plugins/engine/views/components/list.html +0 -36
  184. package/src/server/plugins/engine/views/components/monthyearfield.html +0 -5
  185. package/src/server/plugins/engine/views/components/multilinetextfield.html +0 -10
  186. package/src/server/plugins/engine/views/components/numberfield.html +0 -5
  187. package/src/server/plugins/engine/views/components/radiosfield.html +0 -5
  188. package/src/server/plugins/engine/views/components/selectfield.html +0 -5
  189. package/src/server/plugins/engine/views/components/telephonenumberfield.html +0 -5
  190. package/src/server/plugins/engine/views/components/textfield.html +0 -5
  191. package/src/server/plugins/engine/views/components/ukaddressfield.html +0 -25
  192. package/src/server/plugins/engine/views/components/yesnofield.html +0 -5
  193. package/src/server/plugins/engine/views/file-upload.html +0 -45
  194. package/src/server/plugins/engine/views/index.html +0 -39
  195. package/src/server/plugins/engine/views/item-delete.html +0 -56
  196. package/src/server/plugins/engine/views/partials/components.html +0 -6
  197. package/src/server/plugins/engine/views/partials/conditional-components.html +0 -3
  198. package/src/server/plugins/engine/views/partials/debug.html +0 -44
  199. package/src/server/plugins/engine/views/partials/form.html +0 -15
  200. package/src/server/plugins/engine/views/partials/heading.html +0 -16
  201. package/src/server/plugins/engine/views/partials/preview-banner.html +0 -32
  202. package/src/server/plugins/engine/views/partials/preview-banner.test.js +0 -122
  203. package/src/server/plugins/engine/views/partials/warn-missing-notification-email.html +0 -10
  204. package/src/server/plugins/engine/views/repeat-list-summary.html +0 -53
  205. package/src/server/plugins/errorPages.ts +0 -58
  206. package/src/server/plugins/nunjucks/context.js +0 -88
  207. package/src/server/plugins/nunjucks/context.test.js +0 -142
  208. package/src/server/plugins/nunjucks/enviroment.test.js +0 -201
  209. package/src/server/plugins/nunjucks/environment.js +0 -116
  210. package/src/server/plugins/nunjucks/filters/answer.js +0 -27
  211. package/src/server/plugins/nunjucks/filters/answer.test.js +0 -89
  212. package/src/server/plugins/nunjucks/filters/evaluate.js +0 -21
  213. package/src/server/plugins/nunjucks/filters/field.js +0 -28
  214. package/src/server/plugins/nunjucks/filters/field.test.js +0 -75
  215. package/src/server/plugins/nunjucks/filters/highlight.js +0 -11
  216. package/src/server/plugins/nunjucks/filters/href.js +0 -30
  217. package/src/server/plugins/nunjucks/filters/href.test.js +0 -80
  218. package/src/server/plugins/nunjucks/filters/index.js +0 -8
  219. package/src/server/plugins/nunjucks/filters/inspect.js +0 -15
  220. package/src/server/plugins/nunjucks/filters/page.js +0 -24
  221. package/src/server/plugins/nunjucks/filters/page.test.js +0 -65
  222. package/src/server/plugins/nunjucks/index.js +0 -3
  223. package/src/server/plugins/nunjucks/plugin.js +0 -40
  224. package/src/server/plugins/nunjucks/render.js +0 -42
  225. package/src/server/plugins/nunjucks/types.js +0 -40
  226. package/src/server/plugins/pulse.ts +0 -11
  227. package/src/server/plugins/router.ts +0 -201
  228. package/src/server/plugins/session.ts +0 -28
  229. package/src/server/routes/health.js +0 -13
  230. package/src/server/routes/health.test.js +0 -35
  231. package/src/server/routes/index.test.ts +0 -125
  232. package/src/server/routes/index.ts +0 -2
  233. package/src/server/routes/public.ts +0 -47
  234. package/src/server/routes/types.ts +0 -48
  235. package/src/server/schemas/index.ts +0 -34
  236. package/src/server/secure-context.js +0 -43
  237. package/src/server/services/cacheService.test.ts +0 -276
  238. package/src/server/services/cacheService.ts +0 -131
  239. package/src/server/services/httpService.test.js +0 -491
  240. package/src/server/services/httpService.ts +0 -50
  241. package/src/server/services/index.ts +0 -1
  242. package/src/server/types.ts +0 -54
  243. package/src/server/utils/notify.test.ts +0 -37
  244. package/src/server/utils/notify.ts +0 -50
  245. package/src/server/utils/secure-context/get-trust-store-certs.js +0 -11
  246. package/src/server/utils/secure-context/get-trust-store-certs.test.js +0 -19
  247. package/src/server/utils/utils.js +0 -24
  248. package/src/server/utils/utils.test.js +0 -54
  249. package/src/server/views/404.html +0 -16
  250. package/src/server/views/500.html +0 -19
  251. package/src/server/views/components/debug/macro.njk +0 -3
  252. package/src/server/views/components/debug/template.njk +0 -13
  253. package/src/server/views/components/service-banner/macro.njk +0 -3
  254. package/src/server/views/components/service-banner/template.njk +0 -20
  255. package/src/server/views/components/service-banner/template.test.js +0 -43
  256. package/src/server/views/components/tag-env/macro.njk +0 -3
  257. package/src/server/views/components/tag-env/template.njk +0 -30
  258. package/src/server/views/components/tag-env/template.test.js +0 -66
  259. package/src/server/views/confirmation.html +0 -19
  260. package/src/server/views/help/accessibility-statement.html +0 -58
  261. package/src/server/views/help/cookie-preferences.html +0 -57
  262. package/src/server/views/help/cookies.html +0 -71
  263. package/src/server/views/help/get-support.html +0 -37
  264. package/src/server/views/help/privacy-notice.html +0 -68
  265. package/src/server/views/help/terms-and-conditions.html +0 -83
  266. package/src/server/views/layout.html +0 -199
  267. package/src/server/views/summary.html +0 -50
  268. package/src/typings/hapi/index.d.ts +0 -95
  269. package/src/typings/hapi-tracing/index.d.ts +0 -6
  270. package/src/typings/index.d.ts +0 -3
  271. package/src/typings/joi/index.d.ts +0 -22
  272. package/stylelint.config.js +0 -10
  273. package/test/client/javascripts/file-upload.test.js +0 -1197
  274. package/test/condition/checkboxes.test.js +0 -112
  275. package/test/condition/radios.test.js +0 -112
  276. package/test/condition/text.test.js +0 -103
  277. package/test/fixtures/assets-manifest.json +0 -4
  278. package/test/fixtures/form.js +0 -86
  279. package/test/fixtures/index.js +0 -2
  280. package/test/fixtures/list.js +0 -92
  281. package/test/form/cookies.test.js +0 -338
  282. package/test/form/csrf.test.js +0 -87
  283. package/test/form/definitions/basic.js +0 -101
  284. package/test/form/definitions/blank.js +0 -10
  285. package/test/form/definitions/checkboxes.json +0 -88
  286. package/test/form/definitions/components.json +0 -452
  287. package/test/form/definitions/conditional-reveal.js +0 -140
  288. package/test/form/definitions/conditions-basic.js +0 -187
  289. package/test/form/definitions/conditions-complex.js +0 -338
  290. package/test/form/definitions/conditions-dates.js +0 -78
  291. package/test/form/definitions/conditions-escaping.js +0 -143
  292. package/test/form/definitions/demo-cph-number.js +0 -3099
  293. package/test/form/definitions/feedback.json +0 -45
  294. package/test/form/definitions/fields-optional.js +0 -402
  295. package/test/form/definitions/fields-required.js +0 -402
  296. package/test/form/definitions/file-upload-basic.js +0 -44
  297. package/test/form/definitions/file-upload.js +0 -66
  298. package/test/form/definitions/minimal.js +0 -39
  299. package/test/form/definitions/phase-alpha.json +0 -33
  300. package/test/form/definitions/phase-default.json +0 -26
  301. package/test/form/definitions/radios.json +0 -88
  302. package/test/form/definitions/repeat-mixed.js +0 -54
  303. package/test/form/definitions/repeat.js +0 -70
  304. package/test/form/definitions/status.json +0 -126
  305. package/test/form/definitions/templates.js +0 -183
  306. package/test/form/definitions/test.json +0 -581
  307. package/test/form/definitions/text.json +0 -75
  308. package/test/form/definitions/titles.json +0 -170
  309. package/test/form/definitions.test.js +0 -47
  310. package/test/form/exit-page.test.js +0 -210
  311. package/test/form/feedback.test.js +0 -68
  312. package/test/form/fields-optional.test.js +0 -237
  313. package/test/form/fields-required.test.js +0 -294
  314. package/test/form/file-upload.test.js +0 -313
  315. package/test/form/govuk-notify.test.js +0 -449
  316. package/test/form/journey-basic.test.js +0 -444
  317. package/test/form/persist-files.test.js +0 -227
  318. package/test/form/phase-banner.test.js +0 -71
  319. package/test/form/repeat.test.js +0 -628
  320. package/test/form/summary-submission-email.test.js +0 -95
  321. package/test/form/template.test.js +0 -288
  322. package/test/form/titles.test.js +0 -204
  323. package/test/helpers/component-helpers.js +0 -74
  324. package/test/utils/get-cookie.js +0 -42
  325. package/test/utils/get-form-definitions.js +0 -18
  326. package/tmp.pdf +0 -1
  327. package/tsconfig.json +0 -28
  328. package/webpack.config.js +0 -208
@@ -1,561 +0,0 @@
1
- import {
2
- ComponentType,
3
- ControllerType,
4
- Engine,
5
- hasComponents,
6
- hasNext,
7
- hasRepeater,
8
- type Link,
9
- type Page
10
- } from '@defra/forms-model'
11
- import { type ResponseToolkit, type RouteOptions } from '@hapi/hapi'
12
- import { type ValidationErrorItem } from 'joi'
13
-
14
- import { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'
15
- import { optionalText } from '~/src/server/plugins/engine/components/constants.js'
16
- import { type BackLink } from '~/src/server/plugins/engine/components/types.js'
17
- import {
18
- getErrors,
19
- normalisePath,
20
- proceed
21
- } from '~/src/server/plugins/engine/helpers.js'
22
- import { type FormModel } from '~/src/server/plugins/engine/models/index.js'
23
- import { PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'
24
- import {
25
- type FormContext,
26
- type FormContextRequest,
27
- type FormPageViewModel,
28
- type FormParams,
29
- type FormPayload,
30
- type FormState,
31
- type FormStateValue,
32
- type FormSubmissionState
33
- } from '~/src/server/plugins/engine/types.js'
34
- import {
35
- type FormRequest,
36
- type FormRequestPayload,
37
- type FormRequestPayloadRefs,
38
- type FormRequestRefs
39
- } from '~/src/server/routes/types.js'
40
- import {
41
- actionSchema,
42
- crumbSchema,
43
- paramsSchema
44
- } from '~/src/server/schemas/index.js'
45
- import { merge } from '~/src/server/services/cacheService.js'
46
-
47
- export class QuestionPageController extends PageController {
48
- collection: ComponentCollection
49
- errorSummaryTitle = 'There is a problem'
50
-
51
- constructor(model: FormModel, pageDef: Page) {
52
- super(model, pageDef)
53
-
54
- // Components collection
55
- this.collection = new ComponentCollection(
56
- hasComponents(pageDef) ? pageDef.components : [],
57
- { model, page: this }
58
- )
59
-
60
- this.collection.formSchema = this.collection.formSchema.keys({
61
- crumb: crumbSchema,
62
- action: actionSchema
63
- })
64
- }
65
-
66
- get next(): Link[] {
67
- const { def, pageDef } = this
68
-
69
- if (!hasNext(pageDef)) {
70
- return []
71
- }
72
-
73
- // Remove stale links
74
- return pageDef.next.filter(({ path }) => {
75
- const linkPath = normalisePath(path)
76
-
77
- return def.pages.some((page) => {
78
- const pagePath = normalisePath(page.path)
79
- return pagePath === linkPath
80
- })
81
- })
82
- }
83
-
84
- get allowContinue(): boolean {
85
- if (this.model.engine === Engine.V2) {
86
- return this.pageDef.controller !== ControllerType.Terminal
87
- }
88
-
89
- return this.next.length > 0
90
- }
91
-
92
- getItemId(request?: FormContextRequest) {
93
- const { itemId } = this.getFormParams(request)
94
- return itemId ?? request?.params.itemId
95
- }
96
-
97
- /**
98
- * Used for mapping form payloads and errors to govuk-frontend's template api, so a page can be rendered
99
- * @param request - the hapi request
100
- * @param context - the form context
101
- */
102
- getViewModel(
103
- request: FormContextRequest,
104
- context: FormContext
105
- ): FormPageViewModel {
106
- const { collection, viewModel } = this
107
- const { query } = request
108
- const { payload, errors } = context
109
-
110
- let { pageTitle, showTitle } = viewModel
111
-
112
- const components = collection.getViewModel(payload, errors, query)
113
- const formComponents = components.filter(
114
- ({ isFormComponent }) => isFormComponent
115
- )
116
-
117
- // Single form component? Hide title and customise label or legend instead
118
- if (formComponents.length === 1) {
119
- const { model } = formComponents[0]
120
- const { fieldset, label } = model
121
-
122
- // Set as page heading when not following other content
123
- const isPageHeading = formComponents[0] === components[0]
124
-
125
- // Check for legend or label
126
- const labelOrLegend = fieldset?.legend ?? label
127
-
128
- // Use legend or label as page heading
129
- if (labelOrLegend) {
130
- const size = isPageHeading ? 'l' : 'm'
131
-
132
- labelOrLegend.classes =
133
- labelOrLegend === label
134
- ? `govuk-label--${size}`
135
- : `govuk-fieldset__legend--${size}`
136
-
137
- if (isPageHeading) {
138
- labelOrLegend.isPageHeading = isPageHeading
139
-
140
- // Check for optional in label
141
- const isOptional =
142
- this.collection.fields.at(0)?.options.required === false
143
-
144
- if (pageTitle) {
145
- labelOrLegend.text = isOptional
146
- ? `${pageTitle}${optionalText}`
147
- : pageTitle
148
- }
149
-
150
- pageTitle = pageTitle || labelOrLegend.text
151
- }
152
- }
153
-
154
- showTitle = !isPageHeading
155
- } else if (formComponents.length > 1) {
156
- // When there is more than one form component,
157
- // adjust the label/legends to give equal prominence
158
- for (const { model } of formComponents) {
159
- if (model.fieldset?.legend) {
160
- model.fieldset.legend.classes = 'govuk-fieldset__legend--m'
161
- }
162
- if (model.label) {
163
- model.label.classes = 'govuk-label--m'
164
- }
165
- }
166
- }
167
-
168
- return {
169
- ...viewModel,
170
- backLink: this.getBackLink(request, context),
171
- context,
172
- showTitle,
173
- components,
174
- errors
175
- }
176
- }
177
-
178
- getRelevantPath(
179
- request: FormRequest | FormRequestPayload,
180
- context: FormContext
181
- ) {
182
- const { paths } = context
183
-
184
- const startPath = this.getStartPath()
185
- const relevantPath = paths.at(-1) ?? startPath
186
-
187
- return !paths.length
188
- ? startPath // First possible path
189
- : relevantPath // Last possible path
190
- }
191
-
192
- /**
193
- * Apply conditions to evaluation state to determine next page path
194
- */
195
- getNextPath(context: FormContext) {
196
- const { model, next, path } = this
197
- const { evaluationState } = context
198
-
199
- const summaryPath = this.getSummaryPath()
200
- const statusPath = this.getStatusPath()
201
-
202
- // Walk from summary page (no next links) to status page
203
- let defaultPath = path === summaryPath ? statusPath : undefined
204
-
205
- if (model.engine === Engine.V2) {
206
- if (this.pageDef.controller !== ControllerType.Terminal) {
207
- const { pages } = this.model
208
- const pageIndex = pages.indexOf(this)
209
-
210
- // The "next" page is the first found after the current which is
211
- // either unconditional or has a condition that evaluates to "true"
212
- const nextPage = pages.slice(pageIndex + 1).find((page) => {
213
- const { condition } = page
214
-
215
- if (condition) {
216
- const conditionResult = condition.fn(evaluationState)
217
-
218
- if (!conditionResult) {
219
- return false
220
- }
221
- }
222
-
223
- return true
224
- })
225
-
226
- return nextPage?.path ?? defaultPath
227
- } else {
228
- return defaultPath
229
- }
230
- }
231
-
232
- const nextLink = next.find((link) => {
233
- const { condition } = link
234
-
235
- if (condition) {
236
- return model.conditions[condition]?.fn(evaluationState) ?? false
237
- }
238
-
239
- defaultPath = link.path
240
- return false
241
- })
242
-
243
- return nextLink?.path ?? defaultPath
244
- }
245
-
246
- /**
247
- * Gets the form payload (from state) for this page only
248
- */
249
- getFormDataFromState(
250
- request: FormContextRequest | undefined,
251
- state: FormSubmissionState
252
- ): FormPayload {
253
- const { collection } = this
254
-
255
- // Form params from request
256
- const params = this.getFormParams(request)
257
-
258
- // Form payload from state
259
- const payload = collection.getFormDataFromState(state)
260
-
261
- return {
262
- ...params,
263
- ...payload
264
- }
265
- }
266
-
267
- /**
268
- * Gets form params (from payload) for this page only
269
- */
270
- getFormParams(request?: FormContextRequest): FormParams {
271
- const { payload } = request ?? {}
272
-
273
- const result = paramsSchema.validate(payload, {
274
- abortEarly: false,
275
- stripUnknown: true
276
- })
277
-
278
- return result.value as FormParams
279
- }
280
-
281
- getStateFromValidForm(
282
- request: FormContextRequest,
283
- state: FormSubmissionState,
284
- payload: FormPayload
285
- ): FormState {
286
- return this.collection.getStateFromValidForm(payload)
287
- }
288
-
289
- getErrors(details?: ValidationErrorItem[]) {
290
- return getErrors(details)
291
- }
292
-
293
- async getState(request: FormRequest | FormRequestPayload) {
294
- const { query } = request
295
-
296
- // Skip get for preview URL direct access
297
- if ('force' in query) {
298
- return {}
299
- }
300
-
301
- const { cacheService } = request.services([])
302
- return cacheService.getState(request)
303
- }
304
-
305
- async setState(
306
- request: FormRequest | FormRequestPayload,
307
- state: FormSubmissionState
308
- ) {
309
- const { query } = request
310
-
311
- // Skip set for preview URL direct access
312
- if ('force' in query) {
313
- return state
314
- }
315
-
316
- const { cacheService } = request.services([])
317
- return cacheService.setState(request, state)
318
- }
319
-
320
- async mergeState(
321
- request: FormRequest | FormRequestPayload,
322
- state: FormSubmissionState,
323
- update: object
324
- ) {
325
- const { query } = request
326
-
327
- // Merge state before set
328
- const updated = merge(state, update)
329
-
330
- // Skip set for preview URL direct access
331
- if ('force' in query) {
332
- return updated
333
- }
334
-
335
- const { cacheService } = request.services([])
336
- return cacheService.setState(request, updated)
337
- }
338
-
339
- filterConditionalComponents(
340
- viewModel: FormPageViewModel,
341
- model: FormModel,
342
- evaluationState: Partial<Record<string, FormStateValue>>
343
- ) {
344
- // Filter our components based on their conditions using our evaluated state
345
- let filtered = viewModel.components.filter((component) => {
346
- if (
347
- (!!component.model.content ||
348
- component.type === ComponentType.Details) &&
349
- component.model.condition
350
- ) {
351
- const condition = model.conditions[component.model.condition]
352
- return condition?.fn(evaluationState)
353
- }
354
- return true
355
- })
356
-
357
- /**
358
- * For conditional reveal components (which we no longer support until GDS resolves the related accessibility issues {@link https://github.com/alphagov/govuk-frontend/issues/1991}
359
- */
360
- filtered = filtered.map((component) => {
361
- const evaluatedComponent = component
362
- const content = evaluatedComponent.model.content
363
- if (Array.isArray(content)) {
364
- evaluatedComponent.model.content = content.filter((item) =>
365
- item.condition
366
- ? model.conditions[item.condition]?.fn(evaluationState)
367
- : true
368
- )
369
- }
370
- // apply condition to items for radios, checkboxes etc
371
- const items = evaluatedComponent.model.items
372
-
373
- if (Array.isArray(items)) {
374
- evaluatedComponent.model.items = items.filter((item) =>
375
- item.condition
376
- ? model.conditions[item.condition]?.fn(evaluationState)
377
- : true
378
- )
379
- }
380
-
381
- return evaluatedComponent
382
- })
383
-
384
- return filtered
385
- }
386
-
387
- makeGetRouteHandler() {
388
- return async (
389
- request: FormRequest,
390
- context: FormContext,
391
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
392
- ) => {
393
- const { collection, model, viewName } = this
394
- const { evaluationState } = context
395
-
396
- const viewModel = this.getViewModel(request, context)
397
- viewModel.errors = collection.getErrors(viewModel.errors)
398
-
399
- /**
400
- * Content components can be hidden based on a condition. If the condition evaluates to true, it is safe to be kept, otherwise discard it
401
- */
402
-
403
- // Filter our components based on their conditions using our evaluated state
404
- viewModel.components = this.filterConditionalComponents(
405
- viewModel,
406
- model,
407
- evaluationState
408
- )
409
-
410
- viewModel.hasMissingNotificationEmail =
411
- await this.hasMissingNotificationEmail(request, context)
412
-
413
- return h.view(viewName, viewModel)
414
- }
415
- }
416
-
417
- async hasMissingNotificationEmail(
418
- request: FormRequest,
419
- context: FormContext
420
- ) {
421
- const { path } = this
422
- const { params } = request
423
- const { isForceAccess } = context
424
-
425
- const startPath = this.getStartPath()
426
- const summaryPath = this.getSummaryPath()
427
- const { formsService } = this.model.services
428
- const { getFormMetadata } = formsService
429
-
430
- // Warn the user if the form has no notification email set only on start page and summary page
431
- if ([startPath, summaryPath].includes(path) && !isForceAccess) {
432
- const { notificationEmail } = await getFormMetadata(params.slug)
433
- return !notificationEmail
434
- }
435
-
436
- return false
437
- }
438
-
439
- /**
440
- * Get the back link for a given progress.
441
- */
442
- protected getBackLink(
443
- request: FormContextRequest,
444
- context: FormContext
445
- ): BackLink | undefined {
446
- const { pageDef } = this
447
- const { path, query } = request
448
- const { returnUrl } = query
449
- const { paths } = context
450
-
451
- const itemId = this.getItemId(request)
452
-
453
- // Check answers back link
454
- if (returnUrl) {
455
- return {
456
- text:
457
- hasRepeater(pageDef) && itemId
458
- ? 'Go back to add another'
459
- : 'Go back to check answers',
460
- href: returnUrl
461
- }
462
- }
463
-
464
- // Item delete pages etc
465
- const backPath =
466
- itemId && !path.endsWith(itemId)
467
- ? paths.at(-1) // Back to main page
468
- : paths.at(-2) // Back to previous page
469
-
470
- // No back link
471
- if (!backPath) {
472
- return
473
- }
474
-
475
- // Default back link
476
- return {
477
- text: 'Back',
478
- href: this.getHref(backPath)
479
- }
480
- }
481
-
482
- makePostRouteHandler() {
483
- return async (
484
- request: FormRequestPayload,
485
- context: FormContext,
486
- h: Pick<ResponseToolkit, 'redirect' | 'view'>
487
- ) => {
488
- const { collection, viewName, model } = this
489
- const { isForceAccess, state, evaluationState } = context
490
-
491
- /**
492
- * If there are any errors, render the page with the parsed errors
493
- * @todo Refactor to match POST REDIRECT GET pattern
494
- */
495
- if (context.errors || isForceAccess) {
496
- const viewModel = this.getViewModel(request, context)
497
- viewModel.errors = collection.getErrors(viewModel.errors)
498
-
499
- // Filter our components based on their conditions using our evaluated state
500
- viewModel.components = this.filterConditionalComponents(
501
- viewModel,
502
- model,
503
- evaluationState
504
- )
505
-
506
- return h.view(viewName, viewModel)
507
- }
508
-
509
- // Save and proceed
510
- await this.setState(request, state)
511
- return this.proceed(request, h, this.getNextPath(context))
512
- }
513
- }
514
-
515
- proceed(
516
- request: FormContextRequest,
517
- h: Pick<ResponseToolkit, 'redirect' | 'view'>,
518
- nextPath?: string
519
- ) {
520
- const nextUrl = nextPath
521
- ? this.getHref(nextPath) // Redirect to next page
522
- : this.href // Redirect to current page (refresh)
523
-
524
- return proceed(request, h, nextUrl)
525
- }
526
-
527
- /**
528
- * {@link https://hapi.dev/api/?v=20.1.2#route-options}
529
- */
530
- get getRouteOptions(): RouteOptions<FormRequestRefs> {
531
- return {
532
- ext: {
533
- onPostHandler: {
534
- method(_request, h) {
535
- return h.continue
536
- }
537
- }
538
- }
539
- }
540
- }
541
-
542
- /**
543
- * {@link https://hapi.dev/api/?v=20.1.2#route-options}
544
- */
545
- get postRouteOptions(): RouteOptions<FormRequestPayloadRefs> {
546
- return {
547
- payload: {
548
- parse: true,
549
- maxBytes: Number.MAX_SAFE_INTEGER,
550
- failAction: 'ignore'
551
- },
552
- ext: {
553
- onPostHandler: {
554
- method(_request, h) {
555
- return h.continue
556
- }
557
- }
558
- }
559
- }
560
- }
561
- }
@@ -1,28 +0,0 @@
1
- # Page Controllers
2
-
3
- Form pages could have specific controllers and this is specified inside the Form JSON, please see below a sample where the page summary is specifying it's controller via `controller` property.
4
-
5
- ```javascript
6
- {
7
- "pages": [
8
- {
9
- "path": "/summary",
10
- "controller": "./pages/summary.js", // legacy controller path
11
- "title": "Summary",
12
- "components": [],
13
- "next": []
14
- },
15
- {
16
- "path": "/summary",
17
- "controller": "SummaryPageController", // we now use the controller class name
18
- "title": "Summary",
19
- "components": [],
20
- "next": []
21
- }
22
- ]
23
- }
24
- ```
25
-
26
- Previously controllers were dynamically loaded from the file system, this is why you see a path such as `./pages/summary.js`. This feature has never been used since the application was forked and so it has been deprecated.
27
-
28
- To keep backward compatibility with legacy forms JSON we have the `getPageController` helper dealing with the possibility of a controller value being a file path or a class name (see `helpers.ts`)