hof 24.0.0-vite-beta.12 → 24.1.0
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.
- package/.eslintrc.hof-wrapper.js +30 -0
- package/CHANGELOG.md +132 -1
- package/README.md +142 -152
- package/build/tasks/images/index.js +20 -6
- package/build/tasks/vite/index.js +4 -1
- package/build/tasks/vite/vite.config.js +2 -1
- package/build/tasks/watch/index.js +9 -2
- package/components/amount-with-unit-select/fields.js +15 -0
- package/components/amount-with-unit-select/hooks.js +168 -0
- package/components/amount-with-unit-select/index.js +107 -0
- package/components/amount-with-unit-select/templates/amount-with-unit-select.html +20 -0
- package/components/amount-with-unit-select/utils.js +197 -0
- package/components/amount-with-unit-select/validation.js +175 -0
- package/components/date/templates/date.html +1 -1
- package/components/index.js +1 -1
- package/config/builder-defaults.js +9 -2
- package/config/hof-defaults.js +2 -1
- package/controller/controller.js +5 -3
- package/controller/validation/index.js +1 -1
- package/controller/validation/validators.js +0 -1
- package/frontend/govuk-template/build/config.js +2 -0
- package/frontend/govuk-template/build/govuk_template.html +59 -43
- package/frontend/template-mixins/mixins/template-mixins.js +60 -9
- package/frontend/template-mixins/partials/forms/checkbox.html +5 -1
- package/frontend/template-mixins/partials/forms/grouped-inputs-select.html +13 -0
- package/frontend/template-mixins/partials/forms/grouped-inputs-text.html +37 -0
- package/frontend/template-mixins/partials/forms/input-text-date.html +2 -1
- package/frontend/template-mixins/partials/forms/input-text-group.html +1 -1
- package/frontend/template-mixins/partials/forms/textarea-group.html +1 -1
- package/frontend/template-partials/views/layout.html +1 -1
- package/frontend/template-partials/views/partials/cookie-banner.html +50 -32
- package/frontend/template-partials/views/partials/navigation.html +2 -2
- package/frontend/themes/gov-uk/client-js/cookieSettings.js +35 -23
- package/frontend/themes/gov-uk/client-js/session-timeout-dialog.js +5 -3
- package/frontend/themes/gov-uk/styles/_grouped-input.scss +5 -0
- package/frontend/themes/gov-uk/styles/govuk.scss +1 -0
- package/frontend/toolkit/assets/javascript/form-focus.js +4 -0
- package/frontend/toolkit/assets/rebrand/images/govuk-logo.svg +25 -0
- package/index.js +28 -20
- package/lib/encryption.js +43 -17
- package/lib/sessions.js +22 -8
- package/lib/settings.js +1 -1
- package/package.json +30 -25
- package/sandbox/apps/sandbox/fields.js +18 -1
- package/sandbox/apps/sandbox/index.js +4 -0
- package/sandbox/apps/sandbox/sections/summary-data-sections.js +7 -1
- package/sandbox/apps/sandbox/translations/src/en/fields.json +10 -0
- package/sandbox/apps/sandbox/translations/src/en/pages.json +3 -0
- package/sandbox/apps/sandbox/translations/src/en/validation.json +12 -0
- package/sandbox/package.json +6 -3
- package/sandbox/server.js +4 -1
- package/sandbox/yarn.lock +193 -100
- package/utilities/autofill/index.js +169 -145
- package/components/emailer/assets/images/govuk_logotype_email.png +0 -0
- package/components/emailer/assets/images/ho_crest_27px.png +0 -0
- package/components/emailer/assets/images/spacer.gif +0 -0
- package/components/emailer/email-service.js +0 -51
- package/components/emailer/emailer.js +0 -53
- package/components/emailer/index.js +0 -74
- package/components/emailer/transports/debug.js +0 -74
- package/components/emailer/transports/index.js +0 -8
- package/components/emailer/transports/ses.js +0 -36
- package/components/emailer/transports/smtp.js +0 -26
- package/components/emailer/transports/stub.js +0 -5
- package/components/emailer/views/layout.html +0 -63
- package/frontend/govuk-template/govuk_template_generated.html +0 -102
- package/sandbox/apps/sandbox/translations/en/default.json +0 -245
- package/sandbox/public/css/app.css +0 -10036
- package/sandbox/public/images/icons/icon-caret-left.png +0 -0
- package/sandbox/public/images/icons/icon-complete.png +0 -0
- package/sandbox/public/images/icons/icon-cross-remove-sign.png +0 -0
- package/sandbox/public/js/bundle.js +0 -36720
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* NOTE: This file is a wrapper for the default Hof ESLint config.
|
|
5
|
+
* It is used to override rules for specific files in the Hof repo that are
|
|
6
|
+
* not compatible with the default config.
|
|
7
|
+
* This can be removed once the hof-config-eslint default config is updated
|
|
8
|
+
* to support these files.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const baseConfig = require('./node_modules/eslint-config-hof/default.js');
|
|
12
|
+
|
|
13
|
+
module.exports = {
|
|
14
|
+
...baseConfig,
|
|
15
|
+
overrides: [
|
|
16
|
+
...(baseConfig.overrides || []),
|
|
17
|
+
{
|
|
18
|
+
files: [
|
|
19
|
+
'build/tasks/vite/index.js',
|
|
20
|
+
'build/tasks/vite/vite.config.js',
|
|
21
|
+
'test/frontend/toolkit/vitest.config.js'
|
|
22
|
+
],
|
|
23
|
+
rules: {
|
|
24
|
+
'import/no-unresolved': 'off',
|
|
25
|
+
'node/no-missing-import': 'off',
|
|
26
|
+
'node/no-missing-require': 'off'
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
};
|
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,64 @@
|
|
|
1
|
-
##
|
|
1
|
+
## 2026-06-17, Version 24.0.0 (Stable), @gregwolversonHO, @nzorba
|
|
2
|
+
|
|
3
|
+
⚠️ Major release which removes nodemailer dependency and email functionality
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- Removed built-in email functionality from HOF, including the emailer component and transport implementations.
|
|
7
|
+
- Removed `nodemailer` and related transport dependencies from HOF.
|
|
8
|
+
|
|
9
|
+
### Breaking Changes
|
|
10
|
+
- Services that previously relied on HOF email functionality must now implement and maintain their own email sending logic.
|
|
11
|
+
- Services should migrate to [Gov.uk Notify](https://www.notifications.service.gov.uk) to send notification emails
|
|
12
|
+
|
|
13
|
+
## 2026-05-12, Version 23.1.0 (Stable), @gregwolversonHO
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- Replaced nodemailer-ses-transport library with @aws-sdk/client-sesv2 to remove dependency on deprecated aws-sdk-v2 library
|
|
17
|
+
- Replaced usage of nodemailer-ses-transport in the [emailer ses client](./components/emailer/transports/ses.js).
|
|
18
|
+
|
|
19
|
+
## 2026-04-16, Version 23.0.4 (Stable), @PaolaDMadd-Pro
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- Decoupled session timeout keep alive from analytics configuration.
|
|
23
|
+
- Updated CSP defaults to always include `connect-src 'self'` so same-origin keep alive requests are allowed.
|
|
24
|
+
- Updated GA CSP behavior to **extend** `connect-src` with analytics endpoints when `gaTagId` is set, rather than replacing defaults.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
- Improved timeout dialog refresh behavior:
|
|
28
|
+
* On keep alive success, `timeSessionRefreshed` is updated and timeout controller logic is restarted.
|
|
29
|
+
* On keep alive failure a console.error is triggered.
|
|
30
|
+
|
|
31
|
+
### Tests
|
|
32
|
+
- Added integration regression coverage for CSP:
|
|
33
|
+
* `gaTagId` set: GA and region analytics `connect-src` endpoints are present.
|
|
34
|
+
* `gaTagId` not set: default `connect-src 'self'` remains and GA region endpoints are absent.
|
|
35
|
+
- Added frontend Jest coverage for timeout refresh behavior:
|
|
36
|
+
* Success path (`$.get().done`) updates refresh time and calls controller.
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## 2026-03-18, Version 23.0.3 (Stable), @vinodhasamiyappan-ho
|
|
40
|
+
|
|
41
|
+
### Security
|
|
42
|
+
- Upgraded WebdriverIO from v4 to v5, resolving security vulnerabilities caused by transitive dependencies (`minimist@0.0.10`, `form-data@~2.3.2`) in `webdriverio@4.14.4`.
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
- Migrated to WebdriverIO v5 (`webdriverio@5.23.0`), requiring the following compatibility updates:
|
|
46
|
+
- Refactored all functional tests to use async/await and the new WebdriverIO v5 command API.
|
|
47
|
+
- Updated test utilities and browser setup for async execution and modern WebdriverIO patterns.
|
|
48
|
+
- Removed deprecated synchronous and promise-chaining test code.
|
|
49
|
+
- Improved test isolation and reliability by ensuring each test runs with a fresh app and browser instance.
|
|
50
|
+
- Enhanced sessionDialog Jest tests with new and improved negative test scenarios
|
|
51
|
+
|
|
52
|
+
## 2026-03-17, Version 23.0.2 (Stable), @vivekkumar-ho
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
- Improved session secret validation so missing or blank values now fail fast with a clearer startup error.
|
|
56
|
+
- Reused the validated session secret consistently across cookie parsing, session encryption, and Redis session storage.
|
|
57
|
+
|
|
58
|
+
## 2025-03-04, Version 23.0.1 (Stable), @PaolaDMadd-Pro @Rhodine-orleans-lindsay
|
|
59
|
+
### ⚠️ Versioning Notice
|
|
60
|
+
v23.0.1 is published as a patch due to a prior publishing issue.
|
|
61
|
+
This is the official major release that replaces a previously published beta-tagged v23.0.0, and it should be treated as such in terms of features and breaking changes.
|
|
2
62
|
### Changed
|
|
3
63
|
- Replaced Browserify with Vite
|
|
4
64
|
- removed browserify dependencies including in tests
|
|
@@ -6,8 +66,79 @@
|
|
|
6
66
|
- Updated readme.md
|
|
7
67
|
- Potential **breaking changes**:
|
|
8
68
|
- Node version required for Vite is `20.19.0 || >=22.12.0`
|
|
69
|
+
- Updated engine requirements to use node to `>=20.19.0`
|
|
9
70
|
- Vite uses Rollup in production and requires optional rollup dependencies to be loaded. Setting `--ignore-optional flag` in Dockerfiles will result in "Module not found" errors in CI/CD or Docker.
|
|
10
71
|
|
|
72
|
+
## 2026-02-23, Version 22.14.1 (Stable), @vivekkumar-ho
|
|
73
|
+
|
|
74
|
+
### Security
|
|
75
|
+
|
|
76
|
+
- Upgraded Jest to address a security issue: uncontrolled resource consumption in `braces`.
|
|
77
|
+
- Previous dependency chain (via transitive deps) could pin `braces` to `2.3.2` (from `jest@26.6.3` → `micromatch@3.1.10` → `braces@^2.3.1`), while the earliest fixed `braces` version is `3.0.3`.
|
|
78
|
+
- Jest upgrade updates the transitive dependency chain so `braces` can be resolved to a fixed version (`>= 3.0.3`).
|
|
79
|
+
- Updates patch and minor dependency versions
|
|
80
|
+
|
|
81
|
+
## 2026-01-27, v22.14.0 (Stable), @rayhannurrohmanho
|
|
82
|
+
|
|
83
|
+
### Added
|
|
84
|
+
- Created the amountWithUnitSelect component.
|
|
85
|
+
- Separated the amountWithUnitSelect component logic into into hooks, utils, and validators - all documented via JSDoc.
|
|
86
|
+
- Created templates and partials for the amountWithUnitSelect component.
|
|
87
|
+
- Configured template mixin for amountWithUnitSelect component.
|
|
88
|
+
- Added sandbox example for the amountWithUnitSelect component.
|
|
89
|
+
- Documented the amountWithUnitSelect component in readme.
|
|
90
|
+
- Added tests for the amountWithUnitSelect components.
|
|
91
|
+
|
|
92
|
+
### Changed
|
|
93
|
+
- Added optional parent key ('pKey') parameter to the template-mixins.js 'optionGroup' function to allow the assignment of a group component's parent's properties.
|
|
94
|
+
- Modified validation to check if a "groupedFieldsWithOptions" property exists (and is set to true) for a component with "options" before the "equals" validator is applied to the component.
|
|
95
|
+
|
|
96
|
+
## 2025-12-09, Version 22.13.0 (Stable), @Rhodine-orleans-lindsay
|
|
97
|
+
### Changed
|
|
98
|
+
- Updated cookie banner view to follow GOV.UK design system. Updated cookieSettings.js to allow for different confirmation text based on whether cookies were accepted or rejected
|
|
99
|
+
- Added inputmode='numeric' to date component
|
|
100
|
+
- Added span for checkbox error messages
|
|
101
|
+
- Updated imported javascript
|
|
102
|
+
- Added data-module attribute for govuk-skip-link for screen readers
|
|
103
|
+
- Removed aria-polite=live for character-count and removed pattern attribute for date input
|
|
104
|
+
- Replaced deprecated govuk-header__link--service-name with govuk-header__service-name
|
|
105
|
+
- Added a modifier for phone text input styles that accept sequences of digits
|
|
106
|
+
- Added govuk-template--rebranded class to govuk template html to enable govuk rebrand styles:
|
|
107
|
+
- Updated header and footer to follow GOV.UK design system as part of rebrand
|
|
108
|
+
|
|
109
|
+
## 2025-11-20, Version 22.12.0 (Stable), @dk4g @jamiecarterHO
|
|
110
|
+
|
|
111
|
+
### Infrastructure
|
|
112
|
+
- Updated CI/CD pipeline to test against Node.js 20.x, 22.x, and 24.x
|
|
113
|
+
- Updated Redis testing versions to 7 and 8
|
|
114
|
+
- Added `NODE_VERSION` environment variable for consistent Node.js version across jobs
|
|
115
|
+
- Updated release process to use Node.js 24 for tagging and publishing operations
|
|
116
|
+
|
|
117
|
+
### Security
|
|
118
|
+
- Replaced deprecated `crypto.createCipher`/`crypto.createDecipher` with `crypto.createCipheriv`/`crypto.createDecipheriv`
|
|
119
|
+
- Added proper initialisation vector (IV) handling for enhanced security
|
|
120
|
+
- Enforced 32-byte session secret requirement for AES-256 encryption compatibility
|
|
121
|
+
- Removed insecure default session secret ('changethis') - now requires explicit configuration
|
|
122
|
+
|
|
123
|
+
### Migration Notes
|
|
124
|
+
- **Session Reset Required**: Due to enhanced encryption security, existing user sessions will be invalidated and users will need to re-authenticate after this update
|
|
125
|
+
- **Session Secret**: You must now set a unique `SESSION_SECRET` environment variable of exactly 32 bytes for encryption compatibility.
|
|
126
|
+
For testing purposes, you can use the following command to generate a random value. For production environments, consult a security expert or refer to official cryptographic guidelines to generate a secure secret
|
|
127
|
+
`node -e "console.log(require('crypto').randomBytes(16).toString('hex'))"`
|
|
128
|
+
|
|
129
|
+
## 2025-11-15, Version 22.11.0 (Stable), @Rhodine-orleans-lindsay
|
|
130
|
+
|
|
131
|
+
### Changed
|
|
132
|
+
- Updated custom session-timeout handling so that custom behaviours are not blocked by a `404` middleware error.
|
|
133
|
+
|
|
134
|
+
### Added
|
|
135
|
+
- Added a `CUSTOM_SESSION_EXPIRY` environment variable so that a time other than the redis session ttl can be used for the session timeout. **IMPORTANT**: The `CUSTOM_SESSION_EXPIRY` variable must always be a time before the redis session ttl would expire so that behaviours can run before the `SESSION_TIMEOUT` middleware is triggered.
|
|
136
|
+
- Added a `USE_CUSTOM_SESSION_TIMEOUT` that is `false` by default. When set to `true` the '/session-timeout' page can run before the session expires without triggering a `404` middleware error.
|
|
137
|
+
|
|
138
|
+
- 🎬 Action:
|
|
139
|
+
- For custom session timeout handling that is not linked to the redis session ttl, The following variables must be set: `CUSTOM_SESSION_EXPIRY` to the relevant expiry time e.g.600 and `USE_CUSTOM_SESSION_TIMEOUT` to true.
|
|
140
|
+
- If a behaviour is required on the '/session-timeout` step, the '/session-timeout' step must be set in the project's index.js, along with any relevant behaviours.
|
|
141
|
+
|
|
11
142
|
## 2025-10-10, Version 22.10.4 (Stable), @dk4g
|
|
12
143
|
### Security
|
|
13
144
|
- Upgraded axios version to address a security vulnerability
|
package/README.md
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
[](https://badge.fury.io/js/hof)
|
|
5
5
|
[](https://snyk.io/test/npm/hof)
|
|
6
6
|
|
|
7
|
+
> **WARNING - Breaking change from v24.0.0:** HOF no longer includes built-in email functionality and no longer depends on `nodemailer`.
|
|
8
|
+
> Services must provide and maintain their own email sending implementation using [GOV.UK Notify](https://docs.notifications.service.gov.uk/node.html).
|
|
9
|
+
|
|
7
10
|
HOF (Home Office Forms) is a framework designed to assist developers in creating form-based workflows in a rapid, repeatable and secure way. It aims to reduce simple applications as much as possible to being configuration-only.
|
|
8
11
|
|
|
9
12
|
## Server Settings
|
|
@@ -60,7 +63,8 @@ It is recommended to alias `hof-build` to an npm script in your package.json.
|
|
|
60
63
|
|
|
61
64
|
## Tasks
|
|
62
65
|
|
|
63
|
-
- `vite` - compiles client-side js with vite
|
|
66
|
+
- `vite` - compiles client-side js with vite.
|
|
67
|
+
Requires node version `^20.19.0 || >=22.12.0`.
|
|
64
68
|
- `sass` - compiles sass
|
|
65
69
|
- `images` - copies images from ./assets/images directory to ./public/images
|
|
66
70
|
- `translate` - compiles translation files
|
|
@@ -70,6 +74,20 @@ Note: For SASS compilation it's possible to additionally configure the following
|
|
|
70
74
|
- `quietDeps` - This controls whether you get deprecation warning shown in the console output, if set to false (default) SASS deprecation warnings will be shown in the console, if set to true then deprecation warnings will not be shown in the console output.
|
|
71
75
|
- `sourceMaps` - This controls whether the build will output css sourcemaps to help with debugging. These will be output to the same directory as the css output as a .map file. This option is not currently available in production.
|
|
72
76
|
|
|
77
|
+
Vite outputs JavaScript sourcemaps as a .js.map file to the same directory as the js bundle.
|
|
78
|
+
|
|
79
|
+
Debugging example (in hof.settings or your build config)
|
|
80
|
+
```js
|
|
81
|
+
"build": {
|
|
82
|
+
"sass": {
|
|
83
|
+
"sourceMaps": true
|
|
84
|
+
},
|
|
85
|
+
"js": {
|
|
86
|
+
"sourceMaps": true
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
73
91
|
## Watch
|
|
74
92
|
|
|
75
93
|
You can additionally run a `watch` task to start a server instance, which will automatically restart based on changes to files. This will also re-perform the tasks above when relevant files change.
|
|
@@ -104,6 +122,13 @@ Alternatively you can define a path to a local config file by passing a `--confi
|
|
|
104
122
|
```
|
|
105
123
|
hof-build --config /path/to/my/config.js
|
|
106
124
|
```
|
|
125
|
+
Any task can be disabled by setting its configuration to `false` (or any falsy value).
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
module.exports = {
|
|
129
|
+
sass: false,
|
|
130
|
+
};
|
|
131
|
+
```
|
|
107
132
|
|
|
108
133
|
### Configuration options
|
|
109
134
|
|
|
@@ -845,7 +870,7 @@ Kubernetes healthcheck URLs are provided as defaults if no overrides are supplie
|
|
|
845
870
|
|----------|-------------|---------|---------|
|
|
846
871
|
| `SHOW_COOKIES_BANNER` | Controls whether the cookies banner is displayed | Auto-detected based on GA tags | `true`, `false` |
|
|
847
872
|
|
|
848
|
-
**
|
|
873
|
+
**Behaviour:**
|
|
849
874
|
- If `SHOW_COOKIES_BANNER` is explicitly set, that value is used
|
|
850
875
|
- If not set, banner is automatically shown when `GA_TAG` or `GA_4_TAG` is present
|
|
851
876
|
- If no GA tags are configured, banner is hidden by default
|
|
@@ -990,6 +1015,85 @@ Using the translation key `fields.field-name.label` will return different values
|
|
|
990
1015
|
|
|
991
1016
|
# HOF Components
|
|
992
1017
|
|
|
1018
|
+
## AmountWithUnitSelect Component
|
|
1019
|
+
|
|
1020
|
+
> **Available from version 22.14.0**
|
|
1021
|
+
|
|
1022
|
+
A component for handling the rendering, processing, and validation of a text input (amount) field and a select-dropdown input field (unit) used in HOF applications.
|
|
1023
|
+
|
|
1024
|
+
### Usage
|
|
1025
|
+
|
|
1026
|
+
In your fields config:
|
|
1027
|
+
|
|
1028
|
+
```js
|
|
1029
|
+
const amountWithUnitSelectComponent = require("hof").components.amountWithUnitSelect;
|
|
1030
|
+
|
|
1031
|
+
module.exports = {
|
|
1032
|
+
"amountWithUnitSelect-field": amountWithUnitSelectComponent("amountWithUnitSelect", {
|
|
1033
|
+
mixin: 'input-amount-with-unit-select',
|
|
1034
|
+
amountLabel: "Amount:", // If not specified, defaults to 'Amount'
|
|
1035
|
+
unitLabel: "Unit:", // If not specified, defaults to 'Unit'
|
|
1036
|
+
options: [
|
|
1037
|
+
{ "null": "Select..." }, // If a null option is not specified, a default null option with the label 'Select...' is included in the options
|
|
1038
|
+
{ "label": "untranslated option label 1", "value": "1" },
|
|
1039
|
+
{ "label": "untranslated option label 2", "value": "2" }
|
|
1040
|
+
],
|
|
1041
|
+
hint: "E.g: 5 Kilogram",
|
|
1042
|
+
legend: 'Enter An Amount',
|
|
1043
|
+
isPageHeading: 'true',
|
|
1044
|
+
amountOptional: 'false', // If not specified, defaults to false if the required validator is not applied, otherwise true
|
|
1045
|
+
unitOptional: 'true', // If not specified, defaults to false if the required validator is not applied, otherwise true
|
|
1046
|
+
validate: ['alphanum']
|
|
1047
|
+
}),
|
|
1048
|
+
};
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
The above example will create a new AmountWithUnitSelect component with the key `'amountWithUnitSelect-field'`.
|
|
1052
|
+
It will set the AmountWithUnitSelect component's text input label to `'Amount:'` (instead of the default `'Amount'`) and the select input label to `'Unit:'` (instead of the default `'Unit'`).
|
|
1053
|
+
The component's Select input will have the dropdown options `'Select...'` (mapping to the value `'null'`), `'untranslated option label 1'` (mapping to the value `'1'`), and `'untranslated option label 2'` (mapping to the value `'2'`).
|
|
1054
|
+
The component's hint text will be set to `'E.G: 5 Kilogram'`, the field title/legend will be set to `'Enter An Amount'`, and the page heading will be the field's title.
|
|
1055
|
+
In terms of validation, the text input (amount) will have the `'required'` validator applied, but the select input (unit) will not (a value will not be required to be selected), and the text field will have the `'alphanum'` validator applied.
|
|
1056
|
+
|
|
1057
|
+
### Configuration
|
|
1058
|
+
|
|
1059
|
+
The following optional configuration options are supported:
|
|
1060
|
+
|
|
1061
|
+
- `validate {String|Array}` – Validators to use on the text input field. The `'alphanum'` and `'required'` validators are likely to be used.
|
|
1062
|
+
- `template` – An absolute path to an alternate template.
|
|
1063
|
+
- `amountLabel {String}` – A custom label for the text input field (amount). Defaults to `'Amount'` if omitted. This can also be specified and defined in the field translations.
|
|
1064
|
+
- `unitLabel {String}` – A custom label for the select input field (unit). Defaults to `'Unit'` if omitted. This can also be specified and defined in the field translations.
|
|
1065
|
+
- `options {Array}` – A list of labels and corresponding values (options) for the select input field to present. Each option has the format `{ "label": "", "value": ""}`. The default/null option is defined with the format `{ "null": "Select" }` (where the text `'Select'` is the label and can be modified). If the null option is not defined, a default null option will be included in the options with the label `'Select...'`. This can also be specified and defined in the field translations.
|
|
1066
|
+
- `hint {String}` – Hint text displayed for both fields. This can also be specified and defined in the field translations.
|
|
1067
|
+
- `legend {String}` – Legend text displayed for both fields. This can also be specified and defined in the field translations.
|
|
1068
|
+
- `isPageHeading {Boolean}` – Sets the legend as the page heading on single-page questions.
|
|
1069
|
+
- `amountOptional {Boolean}` – The text input (amount) defaults to `''` (empty string) if omitted. Defaults to `false`. If the `'required'` validator is defined in the `validate` configuration option, then this configuration is ignored (both fields are made mandatory).
|
|
1070
|
+
- `unitOptional {Boolean}` – The select input (unit) defaults to `null` if omitted. Defaults to `false`. If the `'required'` validator is defined in the `validate` configuration option, then this configuration is ignored (both fields are made mandatory).
|
|
1071
|
+
|
|
1072
|
+
### Validation Error Messages
|
|
1073
|
+
|
|
1074
|
+
In Validation.json (within the translations):
|
|
1075
|
+
|
|
1076
|
+
```js
|
|
1077
|
+
"amountWithUnitSelect": {
|
|
1078
|
+
"default": "Enter the amount in the correct format; for example, 10 Litres",
|
|
1079
|
+
"alphanum": "The amount must not contain any special characters",
|
|
1080
|
+
"required": "Enter an amount and a unit value"
|
|
1081
|
+
},
|
|
1082
|
+
"amountWithUnitSelect-unit": {
|
|
1083
|
+
"default": "A valid value must be selected as the amount unit",
|
|
1084
|
+
"required": "A unit must be selected for the amount"
|
|
1085
|
+
},
|
|
1086
|
+
"amountWithUnitSelect-amount": {
|
|
1087
|
+
"alphanum": "The amount must not be an alphanum"
|
|
1088
|
+
}
|
|
1089
|
+
```
|
|
1090
|
+
|
|
1091
|
+
Validation error messages can be defined for a specific child component that errored by adding a JSON object with a key that has the component's name (I.E. `'amountWithUnitSelect'`) followed by a hyphen and the child component's name (I.E. '-amount' or '-unit'). So to define an error message, for the `'required'` validation error, for specifically the unit component, an `'amountWithUnitSelect-unit'` object can be created (like in the example above) with a validator's name and the error message to show for it respectively, set as a key:value pair in the object (E.G. `"required": "A unit must be selected for the amount" within "amountWithUnitSelect-unit"` - like in the example).
|
|
1092
|
+
Validation error messages defined specifically for child components, for a given type of validation error, (such as `'required'` for `'amountWithUnitSelect-unit'`) will take precedence over error messages defined for the same validation error in the parent. So in this case, the `"required": "Enter an amount and a unit value"` validation message defined in the `"amountWithUnitSelect"` JSON object in the above example will not show when the `"amountWithUnitSelect-unit"` `'required'` validation error message is defined. If there was no `'required'` error message defined for, say, the `"amountWithUnitSelect-amount"` object (like in the example above), the `"amountWithUnitSelect"` object's `'required'` error message would show if the `'required'` validation error is triggered on the 'amount' child component (I.E. When an amount value is not provided).
|
|
1093
|
+
The `'default'` catch all validation error message can also be defined in a similar manner for the child components to override the parent component's defined `'default'` error message.
|
|
1094
|
+
|
|
1095
|
+
So the example above will create a scenario where `'required'` validation errors triggered on the 'unit' field will display the error message `"A unit must be selected for the amount"` (specified in the `"amountWithUnitSelect-unit"` JSON object). Any `'required'` validation errors triggered on the 'amount' field will display the error message `"Enter an amount and a unit value"` (specified in the `"amountWithUnitSelect"` JSON object - as there is no `'required'` error message defined specifically for the 'amount' field (withing `"amountWithUnitSelect-amount"`)).
|
|
1096
|
+
|
|
993
1097
|
## Date Component
|
|
994
1098
|
|
|
995
1099
|
A component for handling the rendering and processing of 3-input date fields used in HOF Applications.
|
|
@@ -1151,162 +1255,17 @@ Translations for field labels are looked for in the following order:
|
|
|
1151
1255
|
- `fields.${key}.label`
|
|
1152
1256
|
- `fields.${key}.legend`
|
|
1153
1257
|
|
|
1154
|
-
## Emailer Component
|
|
1155
|
-
|
|
1156
|
-
HOF behaviour to send emails
|
|
1157
|
-
|
|
1158
|
-
### Usage
|
|
1159
|
-
|
|
1160
|
-
```js
|
|
1161
|
-
const EmailBehaviour = require('hof').components.emailer;
|
|
1162
|
-
|
|
1163
|
-
// configure email behaviour
|
|
1164
|
-
const emailer = EmailBehaviour({
|
|
1165
|
-
transport: 'ses',
|
|
1166
|
-
transportOptions: {
|
|
1167
|
-
accessKeyId: '...',
|
|
1168
|
-
secretAccessKey: '...'
|
|
1169
|
-
},
|
|
1170
|
-
template: path.resolve(__dirname, './views/emails/confirm.html'),
|
|
1171
|
-
from: 'confirmation@homeoffice.gov.uk',
|
|
1172
|
-
recipient: 'customer-email',
|
|
1173
|
-
subject: 'Application Successful'
|
|
1174
|
-
});
|
|
1175
|
-
|
|
1176
|
-
// in steps config
|
|
1177
|
-
steps: {
|
|
1178
|
-
...
|
|
1179
|
-
'/confirm': {
|
|
1180
|
-
behaviours: ['complete', emailer],
|
|
1181
|
-
next: '/confirmation',
|
|
1182
|
-
...
|
|
1183
|
-
},
|
|
1184
|
-
...
|
|
1185
|
-
}
|
|
1186
|
-
```
|
|
1187
|
-
|
|
1188
|
-
### Options
|
|
1189
|
-
|
|
1190
|
-
In addition to the options passed to `hof-emailer`, the following options can be used:
|
|
1191
|
-
|
|
1192
|
-
- `recipient` - _Required_ - defines the address to which email will be sent. This can be set either as a key to retrieve an email address from the session, or explicitly to an email address.
|
|
1193
|
-
- `template` - _Required_ - defines the mustache template used to render the email content.
|
|
1194
|
-
- `subject` - defines the subject line of the email.
|
|
1195
|
-
- `parse` - parses the session model into an object used to populate the template.
|
|
1196
|
-
|
|
1197
|
-
`recipient` and `subject` options can also be defined as functions, which will be passed a copy of the session model and a translation function as arguments, and should return a string value.
|
|
1198
|
-
|
|
1199
|
-
```js
|
|
1200
|
-
// use a translated value for the email subject line
|
|
1201
|
-
const emailer = EmailBehaviour({
|
|
1202
|
-
// ...
|
|
1203
|
-
subject: (model, translate) => translate("email.success.subject"),
|
|
1204
|
-
});
|
|
1205
|
-
```
|
|
1206
|
-
|
|
1207
|
-
## HOF Emailer
|
|
1208
|
-
|
|
1209
|
-
An emailer service for HOF applications.
|
|
1210
|
-
|
|
1211
|
-
### Installation
|
|
1212
|
-
|
|
1213
|
-
```bash
|
|
1214
|
-
$ npm install hof-emailer --save
|
|
1215
|
-
```
|
|
1216
|
-
|
|
1217
|
-
### Usage
|
|
1218
|
-
|
|
1219
|
-
```js
|
|
1220
|
-
// first create an emailer instance
|
|
1221
|
-
const Emailer = require("hof").components.email.emailer;
|
|
1222
|
-
const emailer = new Emailer({
|
|
1223
|
-
from: "sender@example.com",
|
|
1224
|
-
transport: "smtp",
|
|
1225
|
-
transportOptions: {
|
|
1226
|
-
host: "my.smtp.host",
|
|
1227
|
-
port: 25,
|
|
1228
|
-
},
|
|
1229
|
-
});
|
|
1230
|
-
|
|
1231
|
-
// then you can use your emailer to send emails
|
|
1232
|
-
const to = "recipient@example.com";
|
|
1233
|
-
const body = "This is the email body";
|
|
1234
|
-
const subject = "Important email!";
|
|
1235
|
-
emailer.send(to, body, subject).then(() => {
|
|
1236
|
-
console.log(`Email sent to ${to}!`);
|
|
1237
|
-
});
|
|
1238
|
-
```
|
|
1239
|
-
|
|
1240
|
-
### Options
|
|
1241
|
-
|
|
1242
|
-
- `from`: <String>: Address to send emails from. Required.
|
|
1243
|
-
- `transport`: <String>: Select what mechanism to use to send emails. Defaults: 'smtp'.
|
|
1244
|
-
- `transportOptions`: <Object>: Set the options for the chosen transport, as defined below. Required.
|
|
1245
|
-
- `layout`: <String>: Optional path to use a custom layout for email content.
|
|
1246
|
-
|
|
1247
|
-
### Transports
|
|
1248
|
-
|
|
1249
|
-
The following transport options are available:
|
|
1250
|
-
|
|
1251
|
-
#### `smtp`
|
|
1252
|
-
|
|
1253
|
-
[nodemailer](https://github.com/nodemailer/nodemailer)
|
|
1254
|
-
|
|
1255
|
-
##### Options
|
|
1256
|
-
|
|
1257
|
-
- `host` <String>: Address of the mailserver. Required.
|
|
1258
|
-
- `port` <String|Number>: Port of the mailserver. Required.
|
|
1259
|
-
- `ignoreTLS` <Boolean>: Defaults to false.
|
|
1260
|
-
- `secure` <Boolean>: Defaults to true.
|
|
1261
|
-
- `auth.user` <String>: Mailserver authorisation username.
|
|
1262
|
-
- `auth.pass` <String>: Mailserver authorisation password.
|
|
1263
|
-
|
|
1264
|
-
#### `ses`
|
|
1265
|
-
|
|
1266
|
-
[nodemailer-ses-transport](https://github.com/andris9/nodemailer-ses-transport)
|
|
1267
|
-
|
|
1268
|
-
##### Options
|
|
1269
|
-
|
|
1270
|
-
- `accessKeyId` <String>: AWS accessKeyId. Required.
|
|
1271
|
-
- `secretAccessKey` <String>: AWS accessKeyId. Required.
|
|
1272
|
-
- `sessionToken` <String>
|
|
1273
|
-
- `region` <String>. Defaults to 'eu-west-1'.
|
|
1274
|
-
- `httpOptions` <String>
|
|
1275
|
-
- `rateLimit` <String>
|
|
1276
|
-
- `maxConnections` <String>
|
|
1277
|
-
|
|
1278
|
-
#### `debug`
|
|
1279
|
-
|
|
1280
|
-
A development option to write the html content of the email to a file for inspection.
|
|
1281
|
-
|
|
1282
|
-
`transport: 'debug'`
|
|
1283
|
-
|
|
1284
|
-
##### debug options
|
|
1285
|
-
|
|
1286
|
-
- `dir` <String>: The location to save html to. Default: `./.emails`. This directory will be created if it does not exist.
|
|
1287
|
-
- `open` <Boolean>: If set to true, will automatically open the created html file in a browser.
|
|
1288
|
-
|
|
1289
|
-
##### debug example
|
|
1290
|
-
|
|
1291
|
-
```
|
|
1292
|
-
transport: 'debug'
|
|
1293
|
-
transportOptions: {
|
|
1294
|
-
dir: './emails',
|
|
1295
|
-
open: true
|
|
1296
|
-
}
|
|
1297
|
-
```
|
|
1298
|
-
|
|
1299
|
-
#### `stub`
|
|
1300
|
-
|
|
1301
|
-
Disables sending email. No options are required.
|
|
1302
|
-
|
|
1303
1258
|
## Session Timeout Warning Component
|
|
1304
1259
|
HOF component for customising session timeout related pages
|
|
1305
1260
|
This feature allows you to customise the content related to the session timeout warning, including the messages displayed in the session timeout warning dialog and on the exit page after a user exits the form due to a session timeout.
|
|
1306
1261
|
|
|
1307
1262
|
### Usage
|
|
1308
1263
|
|
|
1309
|
-
To
|
|
1264
|
+
By default, the session timeout is set to the redis session ttl. To bypass this and display the session timeout message before the redis session ttl the following environment variables must be set:
|
|
1265
|
+
`CUSTOM_SESSION_EXPIRY` - e.g. `600`. Configure to expire before the project's redis session ttl.
|
|
1266
|
+
`USE_CUSTOM_SESSION_TIMEOUT` - `false` by default. When set to `true` the '/session-timeout' page can run before the session expires without triggering a `404` middleware error.
|
|
1267
|
+
|
|
1268
|
+
To enable and customise the session timeout behaviour, you need to set the component and translations in your project's `hof.settings.json` file:
|
|
1310
1269
|
```json
|
|
1311
1270
|
"behaviours": [
|
|
1312
1271
|
"hof/components/session-timeout-warning"
|
|
@@ -1326,6 +1285,36 @@ By default, the framework uses the standard content provided by HOF. If you wish
|
|
|
1326
1285
|
"saveExitFormContent": true // allows you to customise the content on the save-and-exit page
|
|
1327
1286
|
```
|
|
1328
1287
|
|
|
1288
|
+
To override the default session-timeout page completely, the path to the session-timeout.html should be set in the views property in the hof.settings.json file e.g.
|
|
1289
|
+
```json
|
|
1290
|
+
"behaviours": [
|
|
1291
|
+
"hof/components/session-timeout-warning"
|
|
1292
|
+
],
|
|
1293
|
+
"translations": "./apps/common/translations",
|
|
1294
|
+
"views": ["./apps/common/views"], // allows you to override the HOF default session-timeout page and use a custom one from the specified views
|
|
1295
|
+
...
|
|
1296
|
+
```
|
|
1297
|
+
or in the project's `server.js` e.g.
|
|
1298
|
+
```js
|
|
1299
|
+
settings.views = path.resolve(__dirname, './apps/common/views');
|
|
1300
|
+
```
|
|
1301
|
+
|
|
1302
|
+
|
|
1303
|
+
### Session Timeout Keep-alive and CSP
|
|
1304
|
+
|
|
1305
|
+
From version 23.0.4 , session timeout keep alive is now independent of analytics tags.
|
|
1306
|
+
|
|
1307
|
+
- Default CSP always includes: `connect-src 'self'`
|
|
1308
|
+
- If `GA_TAG` (`gaTagId`) is configured:
|
|
1309
|
+
- Google Analytics endpoints are added to `connect-src`.
|
|
1310
|
+
- If `GA_TAG` is not configured: Only default same-origin `connect-src` is used (no GA region endpoints).
|
|
1311
|
+
|
|
1312
|
+
### Timeout Dialog Behavior
|
|
1313
|
+
When a user clicks **Stay on this page** in the timeout dialog:
|
|
1314
|
+
|
|
1315
|
+
- If keep-alive succeeds: session refresh timestamp is updated and the timeout countdown/controller is restarted.
|
|
1316
|
+
|
|
1317
|
+
|
|
1329
1318
|
### Customising content in `pages.json`
|
|
1330
1319
|
Once the variables are set, you can customise the session timeout warning and exit messages in your project's pages.json:
|
|
1331
1320
|
|
|
@@ -1603,6 +1592,7 @@ currency
|
|
|
1603
1592
|
select
|
|
1604
1593
|
input-text
|
|
1605
1594
|
input-date
|
|
1595
|
+
input-amount-with-unit-select
|
|
1606
1596
|
input-text-compound
|
|
1607
1597
|
input-text-code
|
|
1608
1598
|
input-number
|
|
@@ -4,20 +4,34 @@
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const chalk = require('chalk');
|
|
6
6
|
const spawn = require('../../lib/spawn');
|
|
7
|
-
const mkdir = require('../../lib/mkdir');
|
|
8
7
|
|
|
9
8
|
module.exports = config => {
|
|
10
9
|
if (!config.images) {
|
|
11
10
|
return Promise.resolve();
|
|
12
11
|
}
|
|
12
|
+
const imagesOutput = config.images.out;
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
.
|
|
18
|
-
|
|
14
|
+
// Due to govuk rebrand logo, images are copied from multiple sources & mapping can cause 'File exists' error.
|
|
15
|
+
// Remove if exists as a file
|
|
16
|
+
if (fs.existsSync(imagesOutput) && !fs.lstatSync(imagesOutput).isDirectory()) {
|
|
17
|
+
fs.unlinkSync(imagesOutput);
|
|
18
|
+
}
|
|
19
|
+
// Ensure directory exists
|
|
20
|
+
if (!fs.existsSync(imagesOutput)) {
|
|
21
|
+
fs.mkdirSync(imagesOutput, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
const srcs = Array.isArray(config.images.src) ? config.images.src : [config.images.src];
|
|
24
|
+
|
|
25
|
+
return Promise.all(srcs.map(src => {
|
|
26
|
+
if (!fs.existsSync(src)) {
|
|
27
|
+
console.log(`${chalk.yellow('warning')}: Skipping missing images folder: ${src}`);
|
|
28
|
+
return Promise.resolve();
|
|
29
|
+
}
|
|
30
|
+
return spawn('cp', ['-r', `${src}/.`, imagesOutput]);
|
|
31
|
+
}))
|
|
19
32
|
.catch(e => {
|
|
20
33
|
if (e.code !== 'ENOENT') {
|
|
34
|
+
console.error(`${chalk.red('error')}: Failed to copy images - ${e.message}`);
|
|
21
35
|
throw e;
|
|
22
36
|
} else {
|
|
23
37
|
console.log(`${chalk.yellow('warning')}: no images directory found at ${config.images.src}`);
|
|
@@ -26,7 +26,7 @@ export default defineConfig({
|
|
|
26
26
|
// Vite does not process and optimise static images and assets files, it uses a src/ folder.
|
|
27
27
|
// the images and assets folders are therefore loaded at runtime from the public/ folder.
|
|
28
28
|
// This should be resolved with the v5/nunjucks work so we can ignore these warnings for now.
|
|
29
|
-
//
|
|
29
|
+
// TODO: Remove this when v5/nunjucks is implemented.
|
|
30
30
|
{
|
|
31
31
|
name: 'suppress-resolve-warnings',
|
|
32
32
|
apply: 'build',
|
|
@@ -51,6 +51,7 @@ export default defineConfig({
|
|
|
51
51
|
build: {
|
|
52
52
|
outDir: publicDirectory,
|
|
53
53
|
emptyOutDir: false,
|
|
54
|
+
sourcemap: false,
|
|
54
55
|
rollupOptions: {
|
|
55
56
|
input: {
|
|
56
57
|
index: entryFile
|
|
@@ -32,7 +32,14 @@ module.exports = config => {
|
|
|
32
32
|
}, {});
|
|
33
33
|
|
|
34
34
|
function triggersTask(file) {
|
|
35
|
-
return Object.keys(matchers).filter(key =>
|
|
35
|
+
return Object.keys(matchers).filter(key => {
|
|
36
|
+
const pattern = matchers[key];
|
|
37
|
+
// Only call minimatch if pattern is a non-empty string or array of strings
|
|
38
|
+
if (Array.isArray(pattern)) {
|
|
39
|
+
return pattern.some(p => typeof p === 'string' && p.length > 0 && match(file, p));
|
|
40
|
+
}
|
|
41
|
+
return typeof pattern === 'string' && pattern.length > 0 && match(file, pattern);
|
|
42
|
+
});
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
function restart() {
|
|
@@ -94,7 +101,7 @@ module.exports = config => {
|
|
|
94
101
|
process.stdin.setEncoding('utf8');
|
|
95
102
|
process.stdin.on('data', data => {
|
|
96
103
|
const dataType = (data + '').trim().toLowerCase();
|
|
97
|
-
if (dataType
|
|
104
|
+
if (dataType === config.watch.restart) {
|
|
98
105
|
restart();
|
|
99
106
|
}
|
|
100
107
|
});
|