@defra/forms-engine-plugin 0.1.9 → 0.1.11
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/.public/stylesheets/application.min.css +1 -1
- package/.public/stylesheets/application.min.css.map +1 -1
- package/.server/client/stylesheets/application.scss +10 -0
- package/.server/config/index.js +3 -14
- package/.server/config/index.js.map +1 -1
- package/.server/server/devserver/dxt-devtool-baselayout.html +71 -0
- package/.server/server/forms/register-as-a-unicorn-breeder.json +393 -0
- package/.server/server/forms/register-as-a-unicorn-breeder.yaml +251 -0
- package/.server/server/index.js +11 -16
- package/.server/server/index.js.map +1 -1
- package/.server/server/plugins/engine/configureEnginePlugin.js +16 -2
- package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
- package/.server/server/plugins/engine/plugin.js +27 -16
- package/.server/server/plugins/engine/plugin.js.map +1 -1
- package/.server/server/plugins/engine/services/formsService.js +15 -29
- package/.server/server/plugins/engine/services/formsService.js.map +1 -1
- package/.server/server/plugins/engine/services/localFormsService.js +52 -0
- package/.server/server/plugins/engine/services/localFormsService.js.map +1 -0
- package/.server/server/plugins/engine/views/confirmation.html +1 -1
- package/.server/server/plugins/engine/views/file-upload.html +1 -1
- package/.server/server/plugins/engine/views/index.html +1 -1
- package/.server/server/plugins/engine/views/item-delete.html +1 -1
- package/.server/server/plugins/engine/views/repeat-list-summary.html +1 -1
- package/.server/server/plugins/engine/views/summary.html +1 -1
- package/.server/server/plugins/errorPages.js +4 -26
- package/.server/server/plugins/errorPages.js.map +1 -1
- package/.server/server/plugins/nunjucks/context.js +37 -28
- package/.server/server/plugins/nunjucks/context.js.map +1 -1
- package/.server/server/plugins/nunjucks/context.test.js +23 -28
- package/.server/server/plugins/nunjucks/context.test.js.map +1 -1
- package/.server/server/plugins/nunjucks/types.js +3 -4
- package/.server/server/plugins/nunjucks/types.js.map +1 -1
- package/.server/server/routes/index.js +0 -1
- package/.server/server/routes/index.js.map +1 -1
- package/.server/server/utils/file-form-service.js +134 -0
- package/.server/server/utils/file-form-service.js.map +1 -0
- package/.server/typings/hapi/index.d.js.map +1 -1
- package/README.md +3 -1
- package/package.json +7 -3
- package/src/client/stylesheets/application.scss +10 -0
- package/src/config/index.ts +4 -17
- package/src/server/devserver/dxt-devtool-baselayout.html +71 -0
- package/src/server/forms/register-as-a-unicorn-breeder.json +393 -0
- package/src/server/forms/register-as-a-unicorn-breeder.yaml +251 -0
- package/src/server/index.test.ts +4 -37
- package/src/server/index.ts +13 -16
- package/src/server/plugins/engine/components/AutocompleteField.test.ts +5 -5
- package/src/server/plugins/engine/components/CheckboxesField.test.ts +7 -7
- package/src/server/plugins/engine/components/List.test.ts +3 -0
- package/src/server/plugins/engine/components/RadiosField.test.ts +5 -5
- package/src/server/plugins/engine/components/SelectField.test.ts +5 -5
- package/src/server/plugins/engine/configureEnginePlugin.ts +19 -1
- package/src/server/plugins/engine/pageControllers/QuestionPageController.test.ts +4 -0
- package/src/server/plugins/engine/plugin.ts +43 -17
- package/src/server/plugins/engine/services/formsService.js +17 -35
- package/src/server/plugins/engine/services/localFormsService.js +49 -0
- package/src/server/plugins/engine/views/confirmation.html +1 -1
- package/src/server/plugins/engine/views/file-upload.html +1 -1
- package/src/server/plugins/engine/views/index.html +1 -1
- package/src/server/plugins/engine/views/item-delete.html +1 -1
- package/src/server/plugins/engine/views/repeat-list-summary.html +1 -1
- package/src/server/plugins/engine/views/summary.html +1 -1
- package/src/server/plugins/errorPages.ts +4 -26
- package/src/server/plugins/nunjucks/context.js +41 -31
- package/src/server/plugins/nunjucks/context.test.js +24 -27
- package/src/server/plugins/nunjucks/types.js +3 -4
- package/src/server/routes/index.ts +0 -1
- package/src/server/utils/file-form-service.js +144 -0
- package/src/typings/hapi/index.d.ts +3 -9
- package/.server/common/cookies.js +0 -55
- package/.server/common/cookies.js.map +0 -1
- package/.server/common/cookies.test.js +0 -15
- package/.server/common/cookies.test.js.map +0 -1
- package/.server/common/types.js +0 -6
- package/.server/common/types.js.map +0 -1
- package/.server/server/forms/README.md +0 -10
- package/.server/server/forms/report-a-terrorist.json +0 -270
- package/.server/server/forms/runner-components-test.json +0 -365
- package/.server/server/forms/test.json +0 -581
- package/.server/server/plugins/blankie.js +0 -29
- package/.server/server/plugins/blankie.js.map +0 -1
- package/.server/server/plugins/engine/services/formsService.test.js +0 -71
- package/.server/server/plugins/engine/services/formsService.test.js.map +0 -1
- package/.server/server/plugins/engine/views/layout.html +0 -199
- package/.server/server/plugins/router.js +0 -169
- package/.server/server/plugins/router.js.map +0 -1
- package/.server/server/routes/health.js +0 -15
- package/.server/server/routes/health.js.map +0 -1
- package/.server/server/routes/health.test.js +0 -32
- package/.server/server/routes/health.test.js.map +0 -1
- package/.server/server/views/404.html +0 -16
- package/.server/server/views/500.html +0 -19
- package/.server/server/views/help/accessibility-statement.html +0 -58
- package/.server/server/views/help/cookie-preferences.html +0 -57
- package/.server/server/views/help/cookies.html +0 -71
- package/.server/server/views/help/get-support.html +0 -37
- package/.server/server/views/help/privacy-notice.html +0 -68
- package/.server/server/views/help/terms-and-conditions.html +0 -83
- package/src/common/cookies.js +0 -58
- package/src/common/cookies.test.js +0 -23
- package/src/common/types.js +0 -5
- package/src/server/forms/README.md +0 -10
- package/src/server/forms/report-a-terrorist.json +0 -270
- package/src/server/forms/runner-components-test.json +0 -365
- package/src/server/forms/test.json +0 -581
- package/src/server/plugins/blankie.test.ts +0 -73
- package/src/server/plugins/blankie.ts +0 -48
- package/src/server/plugins/engine/services/formsService.test.js +0 -90
- package/src/server/plugins/engine/views/layout.html +0 -199
- package/src/server/plugins/router.ts +0 -201
- package/src/server/routes/health.js +0 -13
- package/src/server/routes/health.test.js +0 -35
- package/src/server/routes/index.test.ts +0 -125
- package/src/server/views/404.html +0 -16
- package/src/server/views/500.html +0 -19
- package/src/server/views/help/accessibility-statement.html +0 -58
- package/src/server/views/help/cookie-preferences.html +0 -57
- package/src/server/views/help/cookies.html +0 -71
- package/src/server/views/help/get-support.html +0 -37
- package/src/server/views/help/privacy-notice.html +0 -68
- package/src/server/views/help/terms-and-conditions.html +0 -83
package/src/server/index.ts
CHANGED
|
@@ -15,14 +15,13 @@ import { config } from '~/src/config/index.js'
|
|
|
15
15
|
import { requestLogger } from '~/src/server/common/helpers/logging/request-logger.js'
|
|
16
16
|
import { requestTracing } from '~/src/server/common/helpers/logging/request-tracing.js'
|
|
17
17
|
import { buildRedisClient } from '~/src/server/common/helpers/redis-client.js'
|
|
18
|
-
import { configureBlankiePlugin } from '~/src/server/plugins/blankie.js'
|
|
19
18
|
import { configureCrumbPlugin } from '~/src/server/plugins/crumb.js'
|
|
20
|
-
import { configureEnginePlugin } from '~/src/server/plugins/engine/
|
|
19
|
+
import { configureEnginePlugin } from '~/src/server/plugins/engine/configureEnginePlugin.js'
|
|
21
20
|
import pluginErrorPages from '~/src/server/plugins/errorPages.js'
|
|
22
21
|
import { plugin as pluginViews } from '~/src/server/plugins/nunjucks/index.js'
|
|
23
22
|
import pluginPulse from '~/src/server/plugins/pulse.js'
|
|
24
|
-
import pluginRouter from '~/src/server/plugins/router.js'
|
|
25
23
|
import pluginSession from '~/src/server/plugins/session.js'
|
|
24
|
+
import { publicRoutes } from '~/src/server/routes/index.js'
|
|
26
25
|
import { prepareSecureContext } from '~/src/server/secure-context.js'
|
|
27
26
|
import { type RouteConfig } from '~/src/server/types.js'
|
|
28
27
|
|
|
@@ -82,15 +81,13 @@ export async function createServer(routeConfig?: RouteConfig) {
|
|
|
82
81
|
prepareSecureContext(server)
|
|
83
82
|
}
|
|
84
83
|
|
|
85
|
-
const pluginEngine = await configureEnginePlugin(routeConfig)
|
|
86
84
|
const pluginCrumb = configureCrumbPlugin(routeConfig)
|
|
87
|
-
const
|
|
85
|
+
const pluginEngine = await configureEnginePlugin(routeConfig)
|
|
88
86
|
|
|
89
87
|
await server.register(pluginSession)
|
|
90
88
|
await server.register(pluginPulse)
|
|
91
89
|
await server.register(inert)
|
|
92
90
|
await server.register(Scooter)
|
|
93
|
-
await server.register(pluginBlankie)
|
|
94
91
|
await server.register(pluginCrumb)
|
|
95
92
|
|
|
96
93
|
server.ext('onPreResponse', (request: Request, h: ResponseToolkit) => {
|
|
@@ -117,19 +114,19 @@ export async function createServer(routeConfig?: RouteConfig) {
|
|
|
117
114
|
|
|
118
115
|
await server.register(pluginViews)
|
|
119
116
|
await server.register(pluginEngine)
|
|
120
|
-
|
|
117
|
+
|
|
118
|
+
await server.register({
|
|
119
|
+
plugin: {
|
|
120
|
+
name: 'router',
|
|
121
|
+
register: (server) => {
|
|
122
|
+
server.route(publicRoutes)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
|
|
121
127
|
await server.register(pluginErrorPages)
|
|
122
128
|
await server.register(blipp)
|
|
123
129
|
await server.register(requestTracing)
|
|
124
130
|
|
|
125
|
-
server.state('cookieConsent', {
|
|
126
|
-
ttl: 365 * 24 * 60 * 60 * 1000, // 1 year in ms
|
|
127
|
-
clearInvalid: true,
|
|
128
|
-
isHttpOnly: false,
|
|
129
|
-
isSecure: config.get('isProduction'),
|
|
130
|
-
path: '/',
|
|
131
|
-
encoding: 'none' // handle this inside the application so we can share frontend/backend cookie modification
|
|
132
|
-
})
|
|
133
|
-
|
|
134
131
|
return server
|
|
135
132
|
}
|
|
@@ -172,7 +172,7 @@ describe.each([
|
|
|
172
172
|
|
|
173
173
|
describe('State', () => {
|
|
174
174
|
it.each([...options.examples])('returns text from state', (item) => {
|
|
175
|
-
const state1 = getFormState(item.
|
|
175
|
+
const state1 = getFormState(item.value)
|
|
176
176
|
const state2 = getFormState(null)
|
|
177
177
|
|
|
178
178
|
const answer1 = getAnswer(field, state1)
|
|
@@ -183,7 +183,7 @@ describe.each([
|
|
|
183
183
|
})
|
|
184
184
|
|
|
185
185
|
it.each([...options.examples])('returns payload from state', (item) => {
|
|
186
|
-
const state1 = getFormState(item.
|
|
186
|
+
const state1 = getFormState(item.value)
|
|
187
187
|
const state2 = getFormState(null)
|
|
188
188
|
|
|
189
189
|
const payload1 = field.getFormDataFromState(state1)
|
|
@@ -194,7 +194,7 @@ describe.each([
|
|
|
194
194
|
})
|
|
195
195
|
|
|
196
196
|
it.each([...options.examples])('returns value from state', (item) => {
|
|
197
|
-
const state1 = getFormState(item.
|
|
197
|
+
const state1 = getFormState(item.value)
|
|
198
198
|
const state2 = getFormState(null)
|
|
199
199
|
|
|
200
200
|
const value1 = field.getFormValueFromState(state1)
|
|
@@ -207,7 +207,7 @@ describe.each([
|
|
|
207
207
|
it.each([...options.examples])(
|
|
208
208
|
'returns context for conditions and form submission',
|
|
209
209
|
(item) => {
|
|
210
|
-
const state1 = getFormState(item.
|
|
210
|
+
const state1 = getFormState(item.value)
|
|
211
211
|
const state2 = getFormState(null)
|
|
212
212
|
|
|
213
213
|
const value1 = field.getContextValueFromState(state1)
|
|
@@ -225,7 +225,7 @@ describe.each([
|
|
|
225
225
|
const value1 = field.getStateFromValidForm(payload1)
|
|
226
226
|
const value2 = field.getStateFromValidForm(payload2)
|
|
227
227
|
|
|
228
|
-
expect(value1).toEqual(getFormState(item.
|
|
228
|
+
expect(value1).toEqual(getFormState(item.value))
|
|
229
229
|
expect(value2).toEqual(getFormState(null))
|
|
230
230
|
})
|
|
231
231
|
})
|
|
@@ -240,7 +240,7 @@ describe.each([
|
|
|
240
240
|
it.each([...options.examples])(
|
|
241
241
|
'returns text from state (single)',
|
|
242
242
|
(item) => {
|
|
243
|
-
const state1 = getFormState([item.
|
|
243
|
+
const state1 = getFormState([item.value])
|
|
244
244
|
const state2 = getFormState(null)
|
|
245
245
|
|
|
246
246
|
const answer1 = getAnswer(field, state1)
|
|
@@ -260,7 +260,7 @@ describe.each([
|
|
|
260
260
|
const item1 = options.examples[0]
|
|
261
261
|
const item2 = options.examples[2]
|
|
262
262
|
|
|
263
|
-
const state = getFormState([item1.
|
|
263
|
+
const state = getFormState([item1.value, item2.value])
|
|
264
264
|
const answer = getAnswer(field, state)
|
|
265
265
|
|
|
266
266
|
expect(answer).toBe(outdent`
|
|
@@ -272,7 +272,7 @@ describe.each([
|
|
|
272
272
|
})
|
|
273
273
|
|
|
274
274
|
it.each([...options.examples])('returns payload from state', (item) => {
|
|
275
|
-
const state1 = getFormState([item.
|
|
275
|
+
const state1 = getFormState([item.value])
|
|
276
276
|
const state2 = getFormState(null)
|
|
277
277
|
|
|
278
278
|
const payload1 = field.getFormDataFromState(state1)
|
|
@@ -283,7 +283,7 @@ describe.each([
|
|
|
283
283
|
})
|
|
284
284
|
|
|
285
285
|
it.each([...options.examples])('returns value from state', (item) => {
|
|
286
|
-
const state1 = getFormState([item.
|
|
286
|
+
const state1 = getFormState([item.value])
|
|
287
287
|
const state2 = getFormState(null)
|
|
288
288
|
|
|
289
289
|
const value1 = field.getFormValueFromState(state1)
|
|
@@ -296,13 +296,13 @@ describe.each([
|
|
|
296
296
|
it.each([...options.examples])(
|
|
297
297
|
'returns context for conditions and form submission',
|
|
298
298
|
(item) => {
|
|
299
|
-
const state1 = getFormState([item.
|
|
299
|
+
const state1 = getFormState([item.value])
|
|
300
300
|
const state2 = getFormState(null)
|
|
301
301
|
|
|
302
302
|
const value1 = field.getContextValueFromState(state1)
|
|
303
303
|
const value2 = field.getContextValueFromState(state2)
|
|
304
304
|
|
|
305
|
-
expect(value1).toEqual([item.
|
|
305
|
+
expect(value1).toEqual([item.value])
|
|
306
306
|
expect(value2).toEqual([])
|
|
307
307
|
}
|
|
308
308
|
)
|
|
@@ -314,7 +314,7 @@ describe.each([
|
|
|
314
314
|
const value1 = field.getStateFromValidForm(payload1)
|
|
315
315
|
const value2 = field.getStateFromValidForm(payload2)
|
|
316
316
|
|
|
317
|
-
expect(value1).toEqual(getFormState([item.
|
|
317
|
+
expect(value1).toEqual(getFormState([item.value]))
|
|
318
318
|
expect(value2).toEqual(getFormState(null))
|
|
319
319
|
})
|
|
320
320
|
})
|
|
@@ -52,18 +52,21 @@ describe('List', () => {
|
|
|
52
52
|
it('returns list items', () => {
|
|
53
53
|
expect(guidance).toHaveProperty('items', [
|
|
54
54
|
{
|
|
55
|
+
id: '52fc51fc-c75a-4b08-9c9e-6bd99b9bc49b',
|
|
55
56
|
text: '1 day',
|
|
56
57
|
value: 1,
|
|
57
58
|
description:
|
|
58
59
|
'Valid for 24 hours from the start time that you select'
|
|
59
60
|
},
|
|
60
61
|
{
|
|
62
|
+
id: '56b7b34f-23b3-4446-ac8e-b2443d18588e',
|
|
61
63
|
text: '8 day',
|
|
62
64
|
value: 8,
|
|
63
65
|
description:
|
|
64
66
|
'Valid for 8 consecutive days from the start time that you select'
|
|
65
67
|
},
|
|
66
68
|
{
|
|
69
|
+
id: '1af54fbc-eec2-4e1e-bd53-2415abf62677',
|
|
67
70
|
text: '12 months',
|
|
68
71
|
value: 365,
|
|
69
72
|
description:
|
|
@@ -170,7 +170,7 @@ describe.each([
|
|
|
170
170
|
|
|
171
171
|
describe('State', () => {
|
|
172
172
|
it.each([...options.examples])('returns text from state', (item) => {
|
|
173
|
-
const state1 = getFormState(item.
|
|
173
|
+
const state1 = getFormState(item.value)
|
|
174
174
|
const state2 = getFormState(null)
|
|
175
175
|
|
|
176
176
|
const answer1 = getAnswer(field, state1)
|
|
@@ -181,7 +181,7 @@ describe.each([
|
|
|
181
181
|
})
|
|
182
182
|
|
|
183
183
|
it.each([...options.examples])('returns payload from state', (item) => {
|
|
184
|
-
const state1 = getFormState(item.
|
|
184
|
+
const state1 = getFormState(item.value)
|
|
185
185
|
const state2 = getFormState(null)
|
|
186
186
|
|
|
187
187
|
const payload1 = field.getFormDataFromState(state1)
|
|
@@ -192,7 +192,7 @@ describe.each([
|
|
|
192
192
|
})
|
|
193
193
|
|
|
194
194
|
it.each([...options.examples])('returns value from state', (item) => {
|
|
195
|
-
const state1 = getFormState(item.
|
|
195
|
+
const state1 = getFormState(item.value)
|
|
196
196
|
const state2 = getFormState(null)
|
|
197
197
|
|
|
198
198
|
const value1 = field.getFormValueFromState(state1)
|
|
@@ -205,7 +205,7 @@ describe.each([
|
|
|
205
205
|
it.each([...options.examples])(
|
|
206
206
|
'returns context for conditions and form submission',
|
|
207
207
|
(item) => {
|
|
208
|
-
const state1 = getFormState(item.
|
|
208
|
+
const state1 = getFormState(item.value)
|
|
209
209
|
const state2 = getFormState(null)
|
|
210
210
|
|
|
211
211
|
const value1 = field.getContextValueFromState(state1)
|
|
@@ -223,7 +223,7 @@ describe.each([
|
|
|
223
223
|
const value1 = field.getStateFromValidForm(payload1)
|
|
224
224
|
const value2 = field.getStateFromValidForm(payload2)
|
|
225
225
|
|
|
226
|
-
expect(value1).toEqual(getFormState(item.
|
|
226
|
+
expect(value1).toEqual(getFormState(item.value))
|
|
227
227
|
expect(value2).toEqual(getFormState(null))
|
|
228
228
|
})
|
|
229
229
|
})
|
|
@@ -171,7 +171,7 @@ describe.each([
|
|
|
171
171
|
|
|
172
172
|
describe('State', () => {
|
|
173
173
|
it.each([...options.examples])('returns text from state', (item) => {
|
|
174
|
-
const state1 = getFormState(item.
|
|
174
|
+
const state1 = getFormState(item.value)
|
|
175
175
|
const state2 = getFormState(null)
|
|
176
176
|
|
|
177
177
|
const answer1 = getAnswer(field, state1)
|
|
@@ -182,7 +182,7 @@ describe.each([
|
|
|
182
182
|
})
|
|
183
183
|
|
|
184
184
|
it.each([...options.examples])('returns payload from state', (item) => {
|
|
185
|
-
const state1 = getFormState(item.
|
|
185
|
+
const state1 = getFormState(item.value)
|
|
186
186
|
const state2 = getFormState(null)
|
|
187
187
|
|
|
188
188
|
const payload1 = field.getFormDataFromState(state1)
|
|
@@ -193,7 +193,7 @@ describe.each([
|
|
|
193
193
|
})
|
|
194
194
|
|
|
195
195
|
it.each([...options.examples])('returns value from state', (item) => {
|
|
196
|
-
const state1 = getFormState(item.
|
|
196
|
+
const state1 = getFormState(item.value)
|
|
197
197
|
const state2 = getFormState(null)
|
|
198
198
|
|
|
199
199
|
const value1 = field.getFormValueFromState(state1)
|
|
@@ -206,7 +206,7 @@ describe.each([
|
|
|
206
206
|
it.each([...options.examples])(
|
|
207
207
|
'returns context for conditions and form submission',
|
|
208
208
|
(item) => {
|
|
209
|
-
const state1 = getFormState(item.
|
|
209
|
+
const state1 = getFormState(item.value)
|
|
210
210
|
const state2 = getFormState(null)
|
|
211
211
|
|
|
212
212
|
const value1 = field.getContextValueFromState(state1)
|
|
@@ -224,7 +224,7 @@ describe.each([
|
|
|
224
224
|
const value1 = field.getStateFromValidForm(payload1)
|
|
225
225
|
const value2 = field.getStateFromValidForm(payload2)
|
|
226
226
|
|
|
227
|
-
expect(value1).toEqual(getFormState(item.
|
|
227
|
+
expect(value1).toEqual(getFormState(item.value))
|
|
228
228
|
expect(value2).toEqual(getFormState(null))
|
|
229
229
|
})
|
|
230
230
|
})
|
|
@@ -8,6 +8,10 @@ import {
|
|
|
8
8
|
plugin,
|
|
9
9
|
type PluginOptions
|
|
10
10
|
} from '~/src/server/plugins/engine/plugin.js'
|
|
11
|
+
import { findPackageRoot } from '~/src/server/plugins/engine/plugin.js'
|
|
12
|
+
import * as defaultServices from '~/src/server/plugins/engine/services/index.js'
|
|
13
|
+
import { formsService } from '~/src/server/plugins/engine/services/localFormsService.js'
|
|
14
|
+
import { devtoolContext } from '~/src/server/plugins/nunjucks/context.js'
|
|
11
15
|
import { type RouteConfig } from '~/src/server/types.js'
|
|
12
16
|
|
|
13
17
|
export const configureEnginePlugin = async ({
|
|
@@ -27,7 +31,21 @@ export const configureEnginePlugin = async ({
|
|
|
27
31
|
|
|
28
32
|
return {
|
|
29
33
|
plugin,
|
|
30
|
-
options: {
|
|
34
|
+
options: {
|
|
35
|
+
model,
|
|
36
|
+
services: services ?? {
|
|
37
|
+
// services for testing, else use the disk loader option for running this service locally
|
|
38
|
+
...defaultServices,
|
|
39
|
+
formsService: await formsService()
|
|
40
|
+
},
|
|
41
|
+
controllers,
|
|
42
|
+
cacheName: 'session',
|
|
43
|
+
nunjucks: {
|
|
44
|
+
baseLayoutPath: 'dxt-devtool-baselayout.html',
|
|
45
|
+
paths: [join(findPackageRoot(), 'src/server/devserver')] // custom layout to make it really clear this is not the same as the runner
|
|
46
|
+
},
|
|
47
|
+
viewContext: devtoolContext
|
|
48
|
+
}
|
|
31
49
|
}
|
|
32
50
|
}
|
|
33
51
|
|
|
@@ -443,6 +443,7 @@ describe('QuestionPageController', () => {
|
|
|
443
443
|
expect(filtered[1].model.label?.text).toBe('Select from the list')
|
|
444
444
|
expect(filtered[1].model.items).toEqual([
|
|
445
445
|
{
|
|
446
|
+
id: expect.any(String),
|
|
446
447
|
checked: false,
|
|
447
448
|
condition: 'isBarnOwl',
|
|
448
449
|
selected: false,
|
|
@@ -450,6 +451,7 @@ describe('QuestionPageController', () => {
|
|
|
450
451
|
value: '1'
|
|
451
452
|
},
|
|
452
453
|
{
|
|
454
|
+
id: expect.any(String),
|
|
453
455
|
checked: false,
|
|
454
456
|
condition: 'isBarnOwl',
|
|
455
457
|
selected: false,
|
|
@@ -499,6 +501,7 @@ describe('QuestionPageController', () => {
|
|
|
499
501
|
expect(filtered[1].model.label?.text).toBe('Select from the list')
|
|
500
502
|
expect(filtered[1].model.items).toEqual([
|
|
501
503
|
{
|
|
504
|
+
id: expect.any(String),
|
|
502
505
|
checked: false,
|
|
503
506
|
condition: 'notBarnOwl',
|
|
504
507
|
selected: false,
|
|
@@ -506,6 +509,7 @@ describe('QuestionPageController', () => {
|
|
|
506
509
|
value: '3'
|
|
507
510
|
},
|
|
508
511
|
{
|
|
512
|
+
id: expect.any(String),
|
|
509
513
|
checked: false,
|
|
510
514
|
condition: 'notBarnOwl',
|
|
511
515
|
selected: false,
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { existsSync } from 'fs'
|
|
2
|
+
import { dirname, join } from 'path'
|
|
3
|
+
import { fileURLToPath } from 'url'
|
|
4
|
+
|
|
1
5
|
import { hasFormComponents, slugSchema } from '@defra/forms-model'
|
|
2
6
|
import Boom from '@hapi/boom'
|
|
3
7
|
import {
|
|
@@ -11,6 +15,7 @@ import vision from '@hapi/vision'
|
|
|
11
15
|
import { isEqual } from 'date-fns'
|
|
12
16
|
import Joi from 'joi'
|
|
13
17
|
import nunjucks, { type Environment } from 'nunjucks'
|
|
18
|
+
import resolvePkg from 'resolve'
|
|
14
19
|
|
|
15
20
|
import { PREVIEW_PATH_PREFIX } from '~/src/server/constants.js'
|
|
16
21
|
import {
|
|
@@ -25,7 +30,6 @@ import {
|
|
|
25
30
|
redirectPath
|
|
26
31
|
} from '~/src/server/plugins/engine/helpers.js'
|
|
27
32
|
import {
|
|
28
|
-
PLUGIN_PATH,
|
|
29
33
|
VIEW_PATH,
|
|
30
34
|
context,
|
|
31
35
|
prepareNunjucksEnvironment
|
|
@@ -65,6 +69,20 @@ import * as httpService from '~/src/server/services/httpService.js'
|
|
|
65
69
|
import { CacheService } from '~/src/server/services/index.js'
|
|
66
70
|
import { type Services } from '~/src/server/types.js'
|
|
67
71
|
|
|
72
|
+
export function findPackageRoot() {
|
|
73
|
+
const currentFileName = fileURLToPath(import.meta.url)
|
|
74
|
+
const currentDirectoryName = dirname(currentFileName)
|
|
75
|
+
|
|
76
|
+
let dir = currentDirectoryName
|
|
77
|
+
while (dir !== '/') {
|
|
78
|
+
if (existsSync(join(dir, 'package.json'))) {
|
|
79
|
+
return dir
|
|
80
|
+
}
|
|
81
|
+
dir = dirname(dir)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
throw new Error('package.json not found in parent directories')
|
|
85
|
+
}
|
|
68
86
|
export interface PluginOptions {
|
|
69
87
|
model?: FormModel
|
|
70
88
|
services?: Services
|
|
@@ -73,6 +91,13 @@ export interface PluginOptions {
|
|
|
73
91
|
viewPaths?: string[]
|
|
74
92
|
filters?: Record<string, FilterFunction>
|
|
75
93
|
pluginPath?: string
|
|
94
|
+
nunjucks: {
|
|
95
|
+
baseLayoutPath: string
|
|
96
|
+
paths: string[]
|
|
97
|
+
}
|
|
98
|
+
viewContext: (
|
|
99
|
+
request: FormRequest | FormRequestPayload | null
|
|
100
|
+
) => Record<string, unknown>
|
|
76
101
|
}
|
|
77
102
|
|
|
78
103
|
export const plugin = {
|
|
@@ -85,23 +110,25 @@ export const plugin = {
|
|
|
85
110
|
services = defaultServices,
|
|
86
111
|
controllers,
|
|
87
112
|
cacheName,
|
|
88
|
-
viewPaths,
|
|
89
113
|
filters,
|
|
90
|
-
|
|
114
|
+
nunjucks: nunjucksOptions,
|
|
115
|
+
viewContext
|
|
91
116
|
} = options
|
|
92
117
|
const { formsService } = services
|
|
93
118
|
const cacheService = new CacheService(server, cacheName)
|
|
94
119
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
120
|
+
const packageRoot = findPackageRoot()
|
|
121
|
+
const govukFrontendPath = dirname(
|
|
122
|
+
resolvePkg.sync('govuk-frontend/package.json')
|
|
123
|
+
)
|
|
99
124
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
125
|
+
const viewPathResolved = join(packageRoot, VIEW_PATH)
|
|
126
|
+
|
|
127
|
+
const paths = [
|
|
128
|
+
...nunjucksOptions.paths,
|
|
129
|
+
viewPathResolved,
|
|
130
|
+
join(govukFrontendPath, 'dist')
|
|
131
|
+
]
|
|
105
132
|
|
|
106
133
|
await server.register({
|
|
107
134
|
plugin: vision,
|
|
@@ -127,10 +154,7 @@ export const plugin = {
|
|
|
127
154
|
) => {
|
|
128
155
|
// Nunjucks also needs an additional path configuration
|
|
129
156
|
// to use the templates and macros from `govuk-frontend`
|
|
130
|
-
const environment = nunjucks.configure(
|
|
131
|
-
...path,
|
|
132
|
-
'node_modules/govuk-frontend/dist'
|
|
133
|
-
])
|
|
157
|
+
const environment = nunjucks.configure(paths)
|
|
134
158
|
|
|
135
159
|
// Applies custom filters and globals for nunjucks
|
|
136
160
|
// that are required by the `forms-engine-plugin`
|
|
@@ -142,12 +166,14 @@ export const plugin = {
|
|
|
142
166
|
}
|
|
143
167
|
}
|
|
144
168
|
},
|
|
145
|
-
path,
|
|
169
|
+
path: paths,
|
|
146
170
|
// Provides global context used with all templates
|
|
147
171
|
context
|
|
148
172
|
}
|
|
149
173
|
})
|
|
150
174
|
|
|
175
|
+
server.expose('baseLayoutPath', nunjucksOptions.baseLayoutPath)
|
|
176
|
+
server.expose('viewContext', viewContext)
|
|
151
177
|
server.expose('cacheService', cacheService)
|
|
152
178
|
|
|
153
179
|
server.app.model = model
|
|
@@ -1,46 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { FormStatus } from '~/src/server/routes/types.js'
|
|
5
|
-
import { getJson } from '~/src/server/services/httpService.js'
|
|
1
|
+
const error = Error(
|
|
2
|
+
'Not implemented. Consider setting up a form loader or providing a service implementation.'
|
|
3
|
+
)
|
|
6
4
|
|
|
5
|
+
// eslint-disable-next-line jsdoc/require-returns-check
|
|
7
6
|
/**
|
|
8
|
-
*
|
|
9
|
-
* @param {string}
|
|
7
|
+
* Dummy function to get form metadata.
|
|
8
|
+
* @param {string} _slug - the slug of the form
|
|
9
|
+
* @returns {Promise<FormMetadata>}
|
|
10
10
|
*/
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const { payload: metadata } = await getJsonByType(
|
|
15
|
-
`${config.get('managerUrl')}/forms/slug/${slug}`
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
// Run it through the schema to coerce dates
|
|
19
|
-
const result = formMetadataSchema.validate(metadata)
|
|
20
|
-
|
|
21
|
-
if (result.error) {
|
|
22
|
-
throw result.error
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return result.value
|
|
11
|
+
export function getFormMetadata(_slug) {
|
|
12
|
+
throw error
|
|
26
13
|
}
|
|
27
14
|
|
|
15
|
+
// eslint-disable-next-line jsdoc/require-returns-check
|
|
28
16
|
/**
|
|
29
|
-
*
|
|
30
|
-
* @param {string}
|
|
31
|
-
* @param {FormStatus}
|
|
17
|
+
* Dummy function to get form metadata.
|
|
18
|
+
* @param {string} _id - the id of the form
|
|
19
|
+
* @param {FormStatus} _state - the state of the form
|
|
20
|
+
* @returns {Promise<FormDefinition | undefined>}
|
|
32
21
|
*/
|
|
33
|
-
export
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const suffix = state === FormStatus.Draft ? `/${state}` : ''
|
|
37
|
-
const { payload: definition } = await getJsonByType(
|
|
38
|
-
`${config.get('managerUrl')}/forms/${id}/definition${suffix}`
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
return definition
|
|
22
|
+
export function getFormDefinition(_id, _state) {
|
|
23
|
+
throw error
|
|
42
24
|
}
|
|
43
25
|
|
|
44
26
|
/**
|
|
45
|
-
* @import { FormDefinition, FormMetadata } from '@defra/forms-model'
|
|
27
|
+
* @import { FormStatus, FormDefinition, FormMetadata } from '@defra/forms-model'
|
|
46
28
|
*/
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { config } from '~/src/config/index.js'
|
|
2
|
+
import { FileFormService } from '~/src/server/utils/file-form-service.js'
|
|
3
|
+
|
|
4
|
+
// Create shared form metadata
|
|
5
|
+
const now = new Date()
|
|
6
|
+
const user = { id: 'user', displayName: 'Username' }
|
|
7
|
+
const author = {
|
|
8
|
+
createdAt: now,
|
|
9
|
+
createdBy: user,
|
|
10
|
+
updatedAt: now,
|
|
11
|
+
updatedBy: user
|
|
12
|
+
}
|
|
13
|
+
const metadata = {
|
|
14
|
+
organisation: 'Defra',
|
|
15
|
+
teamName: 'Team name',
|
|
16
|
+
teamEmail: 'team@defra.gov.uk',
|
|
17
|
+
submissionGuidance: "Thanks for your submission, we'll be in touch",
|
|
18
|
+
notificationEmail: config.get('submissionEmailAddress'),
|
|
19
|
+
...author,
|
|
20
|
+
live: author
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Return an function rather than the service directly. This is to prevent consumer applications
|
|
25
|
+
* blowing up as they won't have these files on disk. We can defer the execution until when it's
|
|
26
|
+
* needed, i.e. the createServer function of the devtool.
|
|
27
|
+
*/
|
|
28
|
+
export const formsService = async () => {
|
|
29
|
+
// Instantiate the file loader form service
|
|
30
|
+
const loader = new FileFormService()
|
|
31
|
+
|
|
32
|
+
// Add a Json form
|
|
33
|
+
await loader.addForm('src/server/forms/register-as-a-unicorn-breeder.json', {
|
|
34
|
+
...metadata,
|
|
35
|
+
id: '95e92559-968d-44ae-8666-2b1ad3dffd31',
|
|
36
|
+
title: 'Register as a unicorn breeder',
|
|
37
|
+
slug: 'register-as-a-unicorn-breeder'
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
// Add a Yaml form
|
|
41
|
+
await loader.addForm('src/server/forms/register-as-a-unicorn-breeder.yaml', {
|
|
42
|
+
...metadata,
|
|
43
|
+
id: '641aeafd-13dd-40fa-9186-001703800efb',
|
|
44
|
+
title: 'Register as a unicorn breeder (yaml)',
|
|
45
|
+
slug: 'register-as-a-unicorn-breeder-yaml' // if we needed to validate any JSON logic, make it available for convenience
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
return loader.toFormsService()
|
|
49
|
+
}
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
{% block bodyEnd %}
|
|
36
36
|
{{ super() }}
|
|
37
37
|
<script type="module" nonce="{{ cspNonce }}">
|
|
38
|
-
import { initFileUpload } from '{{
|
|
38
|
+
import { initFileUpload } from '{{ getDxtAssetPath("file-upload.js") }}';
|
|
39
39
|
if (document.readyState === 'loading') {
|
|
40
40
|
document.addEventListener('DOMContentLoaded', initFileUpload);
|
|
41
41
|
} else {
|