@defra/forms-model 3.0.686 → 3.0.688
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/dist/module/__stubs__/examples.js +185 -0
- package/dist/module/__stubs__/examples.js.map +1 -0
- package/dist/module/components/helpers.js +4 -0
- package/dist/module/components/helpers.js.map +1 -1
- package/dist/module/components/types.js.map +1 -1
- package/dist/module/form/form-definition/index.js +6 -0
- package/dist/module/form/form-definition/index.js.map +1 -1
- package/dist/module/form/form-editor/index.js +2 -0
- package/dist/module/form/form-editor/index.js.map +1 -1
- package/dist/module/form/form-editor/translations/translations-config.js +168 -0
- package/dist/module/form/form-editor/translations/translations-config.js.map +1 -0
- package/dist/module/form/form-editor/translations/translations-overview.js +93 -0
- package/dist/module/form/form-editor/translations/translations-overview.js.map +1 -0
- package/dist/module/form/form-editor/translations/translations.js +214 -0
- package/dist/module/form/form-editor/translations/translations.js.map +1 -0
- package/dist/module/form/form-editor/types.js.map +1 -1
- package/dist/module/form/utils/list.js +23 -0
- package/dist/module/form/utils/list.js.map +1 -1
- package/dist/module/form/utils/numbering.js +43 -0
- package/dist/module/form/utils/numbering.js.map +1 -0
- package/dist/module/index.js +2 -0
- package/dist/module/index.js.map +1 -1
- package/dist/types/__stubs__/examples.d.ts +9 -0
- package/dist/types/__stubs__/examples.d.ts.map +1 -0
- package/dist/types/components/helpers.d.ts +2 -1
- package/dist/types/components/helpers.d.ts.map +1 -1
- package/dist/types/components/types.d.ts +8 -0
- package/dist/types/components/types.d.ts.map +1 -1
- package/dist/types/form/form-definition/index.d.ts.map +1 -1
- package/dist/types/form/form-editor/index.d.ts +2 -0
- package/dist/types/form/form-editor/index.d.ts.map +1 -1
- package/dist/types/form/form-editor/translations/translations-config.d.ts +95 -0
- package/dist/types/form/form-editor/translations/translations-config.d.ts.map +1 -0
- package/dist/types/form/form-editor/translations/translations-overview.d.ts +14 -0
- package/dist/types/form/form-editor/translations/translations-overview.d.ts.map +1 -0
- package/dist/types/form/form-editor/translations/translations.d.ts +16 -0
- package/dist/types/form/form-editor/translations/translations.d.ts.map +1 -0
- package/dist/types/form/form-editor/types.d.ts +5 -1
- package/dist/types/form/form-editor/types.d.ts.map +1 -1
- package/dist/types/form/utils/list.d.ts +8 -1
- package/dist/types/form/utils/list.d.ts.map +1 -1
- package/dist/types/form/utils/numbering.d.ts +18 -0
- package/dist/types/form/utils/numbering.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/schemas/component-schema-v2.json +13 -0
- package/schemas/component-schema.json +13 -0
- package/schemas/form-definition-schema.json +39 -0
- package/schemas/form-definition-v2-schema.json +65 -0
- package/schemas/list-schema-v2.json +26 -0
- package/schemas/list-schema.json +26 -0
- package/schemas/page-schema-v2.json +39 -0
- package/schemas/page-schema.json +13 -0
- package/src/__stubs__/examples.js +231 -0
- package/src/components/helpers.ts +14 -0
- package/src/components/types.ts +15 -0
- package/src/form/form-definition/index.ts +19 -0
- package/src/form/form-editor/index.ts +6 -0
- package/src/form/form-editor/translations/translations-config.js +186 -0
- package/src/form/form-editor/translations/translations-overview.js +137 -0
- package/src/form/form-editor/translations/translations.js +297 -0
- package/src/form/form-editor/types.ts +6 -0
- package/src/form/utils/list.ts +34 -1
- package/src/form/utils/numbering.js +47 -0
- package/src/index.ts +2 -0
|
@@ -385,6 +385,19 @@
|
|
|
385
385
|
},
|
|
386
386
|
"title": "Geometry Types"
|
|
387
387
|
},
|
|
388
|
+
"mapLayers": {
|
|
389
|
+
"type": "object",
|
|
390
|
+
"description": "Supported map layers",
|
|
391
|
+
"properties": {
|
|
392
|
+
"sssi": {
|
|
393
|
+
"type": "boolean",
|
|
394
|
+
"description": "Sites of Special Scientific Interest layer",
|
|
395
|
+
"title": "Sssi"
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
"additionalProperties": false,
|
|
399
|
+
"title": "Map Layers"
|
|
400
|
+
},
|
|
388
401
|
"format": {
|
|
389
402
|
"type": "string",
|
|
390
403
|
"description": "Format for telephone number - for TelephoneNumberField only",
|
|
@@ -680,6 +693,19 @@
|
|
|
680
693
|
},
|
|
681
694
|
"title": "Geometry Types"
|
|
682
695
|
},
|
|
696
|
+
"mapLayers": {
|
|
697
|
+
"type": "object",
|
|
698
|
+
"description": "Supported map layers",
|
|
699
|
+
"properties": {
|
|
700
|
+
"sssi": {
|
|
701
|
+
"type": "boolean",
|
|
702
|
+
"description": "Sites of Special Scientific Interest layer",
|
|
703
|
+
"title": "Sssi"
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
"additionalProperties": false,
|
|
707
|
+
"title": "Map Layers"
|
|
708
|
+
},
|
|
683
709
|
"format": {
|
|
684
710
|
"type": "string",
|
|
685
711
|
"description": "Format for telephone number - for TelephoneNumberField only",
|
|
@@ -1059,6 +1085,19 @@
|
|
|
1059
1085
|
},
|
|
1060
1086
|
"title": "Geometry Types"
|
|
1061
1087
|
},
|
|
1088
|
+
"mapLayers": {
|
|
1089
|
+
"type": "object",
|
|
1090
|
+
"description": "Supported map layers",
|
|
1091
|
+
"properties": {
|
|
1092
|
+
"sssi": {
|
|
1093
|
+
"type": "boolean",
|
|
1094
|
+
"description": "Sites of Special Scientific Interest layer",
|
|
1095
|
+
"title": "Sssi"
|
|
1096
|
+
}
|
|
1097
|
+
},
|
|
1098
|
+
"additionalProperties": false,
|
|
1099
|
+
"title": "Map Layers"
|
|
1100
|
+
},
|
|
1062
1101
|
"format": {
|
|
1063
1102
|
"type": "string",
|
|
1064
1103
|
"description": "Format for telephone number - for TelephoneNumberField only",
|
package/schemas/page-schema.json
CHANGED
|
@@ -248,6 +248,19 @@
|
|
|
248
248
|
},
|
|
249
249
|
"title": "Geometry Types"
|
|
250
250
|
},
|
|
251
|
+
"mapLayers": {
|
|
252
|
+
"type": "object",
|
|
253
|
+
"description": "Supported map layers",
|
|
254
|
+
"properties": {
|
|
255
|
+
"sssi": {
|
|
256
|
+
"type": "boolean",
|
|
257
|
+
"description": "Sites of Special Scientific Interest layer",
|
|
258
|
+
"title": "Sssi"
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
"additionalProperties": false,
|
|
262
|
+
"title": "Map Layers"
|
|
263
|
+
},
|
|
251
264
|
"format": {
|
|
252
265
|
"type": "string",
|
|
253
266
|
"description": "Format for telephone number - for TelephoneNumberField only",
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildDeclarationFieldComponent,
|
|
3
|
+
buildLatLongFieldComponent,
|
|
4
|
+
buildMarkdownComponent,
|
|
5
|
+
buildRadiosComponent,
|
|
6
|
+
buildTextFieldComponent
|
|
7
|
+
} from '~/src/__stubs__/components.js'
|
|
8
|
+
import { buildDefinition } from '~/src/__stubs__/form-definition.js'
|
|
9
|
+
import {
|
|
10
|
+
buildQuestionPage,
|
|
11
|
+
buildRepeaterPage,
|
|
12
|
+
buildSummaryPage
|
|
13
|
+
} from '~/src/__stubs__/pages.js'
|
|
14
|
+
|
|
15
|
+
export const formDefinitionWithSinglePage = buildDefinition({
|
|
16
|
+
pages: [
|
|
17
|
+
buildQuestionPage({
|
|
18
|
+
id: 'p1',
|
|
19
|
+
section: 'section',
|
|
20
|
+
components: [
|
|
21
|
+
buildTextFieldComponent({
|
|
22
|
+
id: 'c1',
|
|
23
|
+
name: 'textField',
|
|
24
|
+
title: 'This is your first field',
|
|
25
|
+
hint: 'Help text'
|
|
26
|
+
})
|
|
27
|
+
],
|
|
28
|
+
next: [{ path: '/summary' }]
|
|
29
|
+
}),
|
|
30
|
+
buildSummaryPage({
|
|
31
|
+
id: 'c2'
|
|
32
|
+
})
|
|
33
|
+
]
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
export const formDefinitionWithoutSummary = buildDefinition({
|
|
37
|
+
pages: [
|
|
38
|
+
buildQuestionPage({
|
|
39
|
+
id: 'p1',
|
|
40
|
+
section: 'section',
|
|
41
|
+
components: [
|
|
42
|
+
buildTextFieldComponent({
|
|
43
|
+
id: 'c1',
|
|
44
|
+
name: 'textField',
|
|
45
|
+
title: 'This is your first field',
|
|
46
|
+
hint: 'Help text'
|
|
47
|
+
})
|
|
48
|
+
],
|
|
49
|
+
next: [{ path: '/summary' }]
|
|
50
|
+
})
|
|
51
|
+
]
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
export const formDefinitionWithTwoQuestions = buildDefinition({
|
|
55
|
+
pages: [
|
|
56
|
+
buildQuestionPage({
|
|
57
|
+
id: 'p1',
|
|
58
|
+
section: 'section',
|
|
59
|
+
components: [
|
|
60
|
+
buildTextFieldComponent({
|
|
61
|
+
id: 'q1',
|
|
62
|
+
name: 'textField',
|
|
63
|
+
title: 'This is your first question',
|
|
64
|
+
hint: 'Help text'
|
|
65
|
+
}),
|
|
66
|
+
buildTextFieldComponent({
|
|
67
|
+
id: 'q2',
|
|
68
|
+
name: 'textField',
|
|
69
|
+
title: 'This is your second question',
|
|
70
|
+
hint: 'Help text'
|
|
71
|
+
})
|
|
72
|
+
],
|
|
73
|
+
next: [{ path: '/summary' }]
|
|
74
|
+
}),
|
|
75
|
+
buildSummaryPage({
|
|
76
|
+
id: 'p2'
|
|
77
|
+
})
|
|
78
|
+
]
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
export const formDefinitionWithTwoQuestionsAndGuidance = buildDefinition({
|
|
82
|
+
pages: [
|
|
83
|
+
buildQuestionPage({
|
|
84
|
+
id: 'p1',
|
|
85
|
+
section: 'section',
|
|
86
|
+
components: [
|
|
87
|
+
buildMarkdownComponent({ content: 'My markdown text' }),
|
|
88
|
+
buildTextFieldComponent({
|
|
89
|
+
id: 'q1',
|
|
90
|
+
name: 'textField',
|
|
91
|
+
title: 'This is the first textfield question',
|
|
92
|
+
hint: 'Help text'
|
|
93
|
+
}),
|
|
94
|
+
buildTextFieldComponent({
|
|
95
|
+
id: 'q2',
|
|
96
|
+
name: 'textField',
|
|
97
|
+
title: 'This is the second textfield question',
|
|
98
|
+
hint: 'Help text'
|
|
99
|
+
})
|
|
100
|
+
],
|
|
101
|
+
next: [{ path: '/summary' }]
|
|
102
|
+
}),
|
|
103
|
+
buildSummaryPage({
|
|
104
|
+
id: 'p2'
|
|
105
|
+
})
|
|
106
|
+
]
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
export const formDefinitionWithLocationAndDeclaration = buildDefinition({
|
|
110
|
+
pages: [
|
|
111
|
+
buildQuestionPage({
|
|
112
|
+
id: 'p1',
|
|
113
|
+
section: 'section',
|
|
114
|
+
components: [
|
|
115
|
+
buildLatLongFieldComponent({
|
|
116
|
+
id: 'q1',
|
|
117
|
+
name: 'latLongField',
|
|
118
|
+
title: 'This is the first lat long field question',
|
|
119
|
+
hint: 'Hint text',
|
|
120
|
+
options: {
|
|
121
|
+
instructionText: 'Some instruction text'
|
|
122
|
+
}
|
|
123
|
+
}),
|
|
124
|
+
buildDeclarationFieldComponent({
|
|
125
|
+
id: 'q2',
|
|
126
|
+
name: 'declarationField',
|
|
127
|
+
title: 'This is a declaration question',
|
|
128
|
+
hint: 'Declaration hint text',
|
|
129
|
+
content: 'This is the declaration that needs agreeing to',
|
|
130
|
+
shortDescription: 'Declaration short desc'
|
|
131
|
+
})
|
|
132
|
+
],
|
|
133
|
+
next: [{ path: '/summary' }]
|
|
134
|
+
}),
|
|
135
|
+
buildSummaryPage({
|
|
136
|
+
id: 'p2'
|
|
137
|
+
})
|
|
138
|
+
]
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
export const formDefinitionWithRepeater = buildDefinition({
|
|
142
|
+
pages: [
|
|
143
|
+
buildRepeaterPage({
|
|
144
|
+
id: 'p1',
|
|
145
|
+
section: 'section',
|
|
146
|
+
components: [
|
|
147
|
+
buildTextFieldComponent({
|
|
148
|
+
id: 'q1',
|
|
149
|
+
name: 'TextField',
|
|
150
|
+
title: 'This is the first text field field question',
|
|
151
|
+
hint: 'Hint text',
|
|
152
|
+
shortDescription: 'Short desc'
|
|
153
|
+
})
|
|
154
|
+
],
|
|
155
|
+
next: [{ path: '/summary' }]
|
|
156
|
+
}),
|
|
157
|
+
buildSummaryPage({
|
|
158
|
+
id: 'p2'
|
|
159
|
+
})
|
|
160
|
+
]
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
export const formDefinitionWithNoQuestions = buildDefinition({
|
|
164
|
+
pages: [
|
|
165
|
+
buildQuestionPage({
|
|
166
|
+
id: 'p1',
|
|
167
|
+
section: 'section',
|
|
168
|
+
components: [],
|
|
169
|
+
next: [{ path: '/summary' }]
|
|
170
|
+
}),
|
|
171
|
+
buildSummaryPage({
|
|
172
|
+
id: 'p2'
|
|
173
|
+
})
|
|
174
|
+
]
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
export const formDefinitionWithRadioQuestion = buildDefinition({
|
|
178
|
+
pages: [
|
|
179
|
+
buildQuestionPage({
|
|
180
|
+
id: 'p1',
|
|
181
|
+
section: 'section',
|
|
182
|
+
components: [
|
|
183
|
+
buildRadiosComponent({
|
|
184
|
+
id: 'q1',
|
|
185
|
+
name: 'radioField',
|
|
186
|
+
title: 'This is a radio question',
|
|
187
|
+
hint: 'Help text',
|
|
188
|
+
list: 'my-list-id'
|
|
189
|
+
})
|
|
190
|
+
],
|
|
191
|
+
next: [{ path: '/summary' }]
|
|
192
|
+
}),
|
|
193
|
+
buildSummaryPage({
|
|
194
|
+
id: 'p2'
|
|
195
|
+
})
|
|
196
|
+
],
|
|
197
|
+
lists: [
|
|
198
|
+
{
|
|
199
|
+
name: 'my-list',
|
|
200
|
+
id: 'my-list-id',
|
|
201
|
+
type: 'string',
|
|
202
|
+
title: 'list for radio',
|
|
203
|
+
items: [
|
|
204
|
+
{
|
|
205
|
+
id: 'option-1',
|
|
206
|
+
text: 'Option 1',
|
|
207
|
+
hint: {
|
|
208
|
+
text: 'Option 1 hint'
|
|
209
|
+
},
|
|
210
|
+
value: 'Option1'
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
id: 'option-2',
|
|
214
|
+
text: 'Option 2',
|
|
215
|
+
hint: {
|
|
216
|
+
text: 'Option 2 hint'
|
|
217
|
+
},
|
|
218
|
+
value: 'Option2'
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
id: 'option-3',
|
|
222
|
+
text: 'Option 3',
|
|
223
|
+
hint: {
|
|
224
|
+
text: 'Option 3 hint'
|
|
225
|
+
},
|
|
226
|
+
value: 'Option3'
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
}
|
|
230
|
+
]
|
|
231
|
+
})
|
|
@@ -2,6 +2,7 @@ import { ComponentTypes } from '~/src/components/component-types.js'
|
|
|
2
2
|
import { ComponentType } from '~/src/components/enums.js'
|
|
3
3
|
import {
|
|
4
4
|
type ComponentDef,
|
|
5
|
+
type ComponentsDefWithInstructions,
|
|
5
6
|
type ConditionalComponentType,
|
|
6
7
|
type ConditionalComponentsDef,
|
|
7
8
|
type ContentComponentsDef,
|
|
@@ -145,6 +146,19 @@ export function isListType(
|
|
|
145
146
|
return !!type && allowedTypes.includes(type)
|
|
146
147
|
}
|
|
147
148
|
|
|
149
|
+
export function isTypeWithInstructions(
|
|
150
|
+
type?: ComponentType
|
|
151
|
+
): type is ComponentsDefWithInstructions['type'] {
|
|
152
|
+
const allowedTypes = [
|
|
153
|
+
ComponentType.EastingNorthingField,
|
|
154
|
+
ComponentType.OsGridRefField,
|
|
155
|
+
ComponentType.NationalGridFieldNumberField,
|
|
156
|
+
ComponentType.LatLongField
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
return !!type && allowedTypes.includes(type)
|
|
160
|
+
}
|
|
161
|
+
|
|
148
162
|
/**
|
|
149
163
|
* Filter known form components with input fields
|
|
150
164
|
* (excludes content and selection fields)
|
package/src/components/types.ts
CHANGED
|
@@ -188,12 +188,17 @@ export interface UkAddressFieldComponent extends FormFieldBase {
|
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
export interface MapLayerOptions {
|
|
192
|
+
sssi?: boolean
|
|
193
|
+
}
|
|
194
|
+
|
|
191
195
|
// Precise Location Fields
|
|
192
196
|
export interface EastingNorthingFieldComponent extends FormFieldBase {
|
|
193
197
|
type: ComponentType.EastingNorthingField
|
|
194
198
|
options: FormFieldBase['options'] & {
|
|
195
199
|
condition?: string
|
|
196
200
|
customValidationMessage?: string
|
|
201
|
+
mapLayers?: MapLayerOptions
|
|
197
202
|
}
|
|
198
203
|
schema?: {
|
|
199
204
|
easting?: {
|
|
@@ -212,6 +217,7 @@ export interface OsGridRefFieldComponent extends FormFieldBase {
|
|
|
212
217
|
options: FormFieldBase['options'] & {
|
|
213
218
|
condition?: string
|
|
214
219
|
customValidationMessage?: string
|
|
220
|
+
mapLayers?: MapLayerOptions
|
|
215
221
|
}
|
|
216
222
|
}
|
|
217
223
|
|
|
@@ -228,6 +234,7 @@ export interface LatLongFieldComponent extends FormFieldBase {
|
|
|
228
234
|
options: FormFieldBase['options'] & {
|
|
229
235
|
condition?: string
|
|
230
236
|
customValidationMessage?: string
|
|
237
|
+
mapLayers?: MapLayerOptions
|
|
231
238
|
}
|
|
232
239
|
schema?: {
|
|
233
240
|
latitude?: {
|
|
@@ -290,6 +297,7 @@ export interface GeospatialFieldComponent extends FormFieldBase {
|
|
|
290
297
|
condition?: string
|
|
291
298
|
countries?: GeospatialFieldOptionsCountry[]
|
|
292
299
|
geometryTypes?: GeospatialFieldGeometryTypesEnum[]
|
|
300
|
+
mapLayers?: MapLayerOptions
|
|
293
301
|
}
|
|
294
302
|
schema?: {
|
|
295
303
|
max?: number
|
|
@@ -435,6 +443,13 @@ export type SelectionComponentsDef =
|
|
|
435
443
|
| SelectFieldComponent
|
|
436
444
|
| YesNoFieldComponent
|
|
437
445
|
|
|
446
|
+
// Components that have instruction fields
|
|
447
|
+
export type ComponentsDefWithInstructions =
|
|
448
|
+
| EastingNorthingFieldComponent
|
|
449
|
+
| OsGridRefFieldComponent
|
|
450
|
+
| NationalGridFieldNumberFieldComponent
|
|
451
|
+
| LatLongFieldComponent
|
|
452
|
+
|
|
438
453
|
// Components that have condition support
|
|
439
454
|
export type ConditionalComponentsDef = Exclude<
|
|
440
455
|
ComponentDef,
|
|
@@ -680,6 +680,25 @@ export const componentSchema = Joi.object<ComponentDef>()
|
|
|
680
680
|
'Geometry types for geospatial data - for GeospatialField only'
|
|
681
681
|
)
|
|
682
682
|
}).description('Geometry types - for GeospatialField only'),
|
|
683
|
+
mapLayers: Joi.when('type', {
|
|
684
|
+
is: Joi.string()
|
|
685
|
+
.trim()
|
|
686
|
+
.valid(
|
|
687
|
+
ComponentType.GeospatialField,
|
|
688
|
+
ComponentType.EastingNorthingField,
|
|
689
|
+
ComponentType.LatLongField,
|
|
690
|
+
ComponentType.OsGridRefField
|
|
691
|
+
)
|
|
692
|
+
.required(),
|
|
693
|
+
then: Joi.object()
|
|
694
|
+
.keys({
|
|
695
|
+
sssi: Joi.boolean()
|
|
696
|
+
.optional()
|
|
697
|
+
.description('Sites of Special Scientific Interest layer')
|
|
698
|
+
})
|
|
699
|
+
.optional()
|
|
700
|
+
.description('Supported map layers')
|
|
701
|
+
}).description('Map layers'),
|
|
683
702
|
format: Joi.when('type', {
|
|
684
703
|
is: Joi.string()
|
|
685
704
|
.trim()
|
|
@@ -471,6 +471,11 @@ export const countriesSchema = Joi.array()
|
|
|
471
471
|
.single()
|
|
472
472
|
.description('The country to be included in a geospatial field')
|
|
473
473
|
|
|
474
|
+
export const mapLayersSchema = Joi.array()
|
|
475
|
+
.items(Joi.string().valid('sssi'))
|
|
476
|
+
.single()
|
|
477
|
+
.description('The map layers to be displayed')
|
|
478
|
+
|
|
474
479
|
export const exactFeaturesSchema = Joi.number()
|
|
475
480
|
.empty('')
|
|
476
481
|
.integer()
|
|
@@ -693,6 +698,7 @@ export const questionDetailsFullSchema = {
|
|
|
693
698
|
maxChecksSchema,
|
|
694
699
|
exactChecksSchema,
|
|
695
700
|
countriesSchema,
|
|
701
|
+
mapLayersSchema,
|
|
696
702
|
minFeaturesSchema,
|
|
697
703
|
maxFeaturesSchema,
|
|
698
704
|
exactFeaturesSchema,
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { ComponentType } from '~/src/components/enums.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {object} TranslationRow
|
|
5
|
+
* @property {string} name - the key name
|
|
6
|
+
* @property {string} [type] - type of text
|
|
7
|
+
* @property {string | undefined} englishContent - English text
|
|
8
|
+
* @property {string | undefined} welshContent - Welsh text
|
|
9
|
+
* @property {number} [pageNum] - page number
|
|
10
|
+
* @property {number} [questionNum] - question number
|
|
11
|
+
* @property {number} [itemNum] - list item number
|
|
12
|
+
* @property {string} [label] - label for field
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {{ text: string, href?: string }} ErrorDetailsItem
|
|
17
|
+
* @typedef {Record<string, ErrorDetailsItem>} ErrorDetails
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @template {object} [Schema=object]
|
|
22
|
+
* @typedef {object} ValidationFailure
|
|
23
|
+
* @property {ErrorDetails} formErrors - Formatted errors for error summary
|
|
24
|
+
* @property {Schema} formValues - Form POST payload from Hapi request
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
export const TranslationRowTypes = {
|
|
28
|
+
PageHeading: 'PageHeading',
|
|
29
|
+
PageGuidance: 'PageGuidance',
|
|
30
|
+
RepeatTitle: 'RepeatTitle',
|
|
31
|
+
QuestionText: 'QuestionText',
|
|
32
|
+
QuestionHint: 'QuestionHint',
|
|
33
|
+
ShortDescription: 'ShortDescription',
|
|
34
|
+
ErrorDescription: 'ErrorDescription',
|
|
35
|
+
ListItemText: 'ListItemText',
|
|
36
|
+
ListItemHint: 'ListItemHint',
|
|
37
|
+
InstructionText: 'InstructionText',
|
|
38
|
+
DeclarationBody: 'DeclarationBody',
|
|
39
|
+
PaymentDescription: 'PaymentDescription'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const TEXTAREA_3_ROWS = 'textarea3'
|
|
43
|
+
export const TEXTAREA_5_ROWS = 'textarea5'
|
|
44
|
+
export const TEXTAREA_12_ROWS_WITH_MARKDOWN = 'textarea12markdown'
|
|
45
|
+
export const LIST_ITEM_HINT = 'listitemhint'
|
|
46
|
+
export const LIST_ITEM_WITH_HINT_FOLLOWING = 'listoptionwithhintfollowing'
|
|
47
|
+
|
|
48
|
+
/** @type {Record<string, { jsonPrefix: string, jsonSuffix: string, displayName: string, getLabel: (pageNum: number, questionNum?: number, itemNum?: number) => string }>} */
|
|
49
|
+
export const keyConfig = {
|
|
50
|
+
[TranslationRowTypes.QuestionText]: {
|
|
51
|
+
jsonPrefix: 'components',
|
|
52
|
+
jsonSuffix: 'title',
|
|
53
|
+
displayName: 'Question text',
|
|
54
|
+
getLabel: (pageNum, questionNum) =>
|
|
55
|
+
`Welsh question text - Page ${pageNum}, question ${questionNum}`
|
|
56
|
+
},
|
|
57
|
+
[TranslationRowTypes.QuestionHint]: {
|
|
58
|
+
jsonPrefix: 'components',
|
|
59
|
+
jsonSuffix: 'hint',
|
|
60
|
+
displayName: 'Hint',
|
|
61
|
+
getLabel: (pageNum, questionNum) =>
|
|
62
|
+
`Welsh hint - Page ${pageNum}, question ${questionNum}`
|
|
63
|
+
},
|
|
64
|
+
[TranslationRowTypes.ShortDescription]: {
|
|
65
|
+
jsonPrefix: 'components',
|
|
66
|
+
jsonSuffix: 'shortDescription',
|
|
67
|
+
displayName: 'Short description',
|
|
68
|
+
getLabel: (pageNum, questionNum) =>
|
|
69
|
+
`Welsh short description - Page ${pageNum}, question ${questionNum}`
|
|
70
|
+
},
|
|
71
|
+
[TranslationRowTypes.InstructionText]: {
|
|
72
|
+
jsonPrefix: 'components',
|
|
73
|
+
jsonSuffix: 'instructionText',
|
|
74
|
+
displayName: 'Instruction text',
|
|
75
|
+
getLabel: (pageNum, questionNum) =>
|
|
76
|
+
`Welsh instruction text - Page ${pageNum}, question ${questionNum}`
|
|
77
|
+
},
|
|
78
|
+
[TranslationRowTypes.DeclarationBody]: {
|
|
79
|
+
jsonPrefix: 'components',
|
|
80
|
+
jsonSuffix: 'content',
|
|
81
|
+
displayName: 'Declaration body',
|
|
82
|
+
getLabel: (pageNum, questionNum) =>
|
|
83
|
+
`Welsh declaration body - Page ${pageNum}, question ${questionNum}`
|
|
84
|
+
},
|
|
85
|
+
[TranslationRowTypes.PaymentDescription]: {
|
|
86
|
+
jsonPrefix: 'components',
|
|
87
|
+
jsonSuffix: 'paymentDescription',
|
|
88
|
+
displayName: 'Payment description',
|
|
89
|
+
getLabel: (pageNum, questionNum) =>
|
|
90
|
+
`Welsh payment description - Page ${pageNum}, question ${questionNum}`
|
|
91
|
+
},
|
|
92
|
+
[TranslationRowTypes.ListItemText]: {
|
|
93
|
+
jsonPrefix: 'listItems',
|
|
94
|
+
jsonSuffix: 'text',
|
|
95
|
+
displayName: 'Option',
|
|
96
|
+
getLabel: (pageNum, questionNum, itemNum) =>
|
|
97
|
+
`Welsh option ${itemNum} - Page ${pageNum}, question ${questionNum}`
|
|
98
|
+
},
|
|
99
|
+
[TranslationRowTypes.ListItemHint]: {
|
|
100
|
+
jsonPrefix: 'listItems',
|
|
101
|
+
jsonSuffix: 'hint',
|
|
102
|
+
displayName: 'Option hint',
|
|
103
|
+
getLabel: (pageNum, questionNum, itemNum) =>
|
|
104
|
+
`Welsh hint for option ${itemNum} - Page ${pageNum}, question ${questionNum}`
|
|
105
|
+
},
|
|
106
|
+
[TranslationRowTypes.PageGuidance]: {
|
|
107
|
+
jsonPrefix: 'components',
|
|
108
|
+
jsonSuffix: 'content',
|
|
109
|
+
displayName: 'Guidance text',
|
|
110
|
+
getLabel: (pageNum) => `Welsh guidance text (markdown) - page ${pageNum}`
|
|
111
|
+
},
|
|
112
|
+
[TranslationRowTypes.PageHeading]: {
|
|
113
|
+
jsonPrefix: 'pages',
|
|
114
|
+
jsonSuffix: 'title',
|
|
115
|
+
displayName: 'Page heading',
|
|
116
|
+
getLabel: (pageNum) => `Welsh page heading - page ${pageNum}`
|
|
117
|
+
},
|
|
118
|
+
[TranslationRowTypes.RepeatTitle]: {
|
|
119
|
+
jsonPrefix: 'pages',
|
|
120
|
+
jsonSuffix: 'repeatTitle',
|
|
121
|
+
displayName: 'Repeat name',
|
|
122
|
+
getLabel: (pageNum) => `Welsh repeat name - page ${pageNum}`
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export const IGNORE_FIELDS = [
|
|
127
|
+
ComponentType.Details,
|
|
128
|
+
ComponentType.Html,
|
|
129
|
+
ComponentType.InsetText,
|
|
130
|
+
ComponentType.HiddenField
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Lookup a translation from a list of translation records.
|
|
135
|
+
* @param {string} key - The translation key to look up.
|
|
136
|
+
* @param {Record<string, string> | undefined} translations - The translation values to search.
|
|
137
|
+
*/
|
|
138
|
+
export function lookupTranslation(key, translations) {
|
|
139
|
+
if (!translations) {
|
|
140
|
+
return ''
|
|
141
|
+
}
|
|
142
|
+
return translations[key] ?? ''
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Resolve the underlying content for a translation row from an entity.
|
|
147
|
+
* Involves using the appropriate child properties if necessary.
|
|
148
|
+
* @param {string} keyType - The translation row type being resolved.
|
|
149
|
+
* @param {ComponentDef | Page | Item} entity - The entity that may contain the content to translate.
|
|
150
|
+
* @param {string} jsonSuffix - The property name to read from the entity.
|
|
151
|
+
*/
|
|
152
|
+
export function drillDown(keyType, entity, jsonSuffix) {
|
|
153
|
+
/** @type {Partial<Record<string, (entity: ComponentDef | Page | Item) => string>>} */
|
|
154
|
+
const resolveData = {
|
|
155
|
+
[TranslationRowTypes.InstructionText]: () =>
|
|
156
|
+
// @ts-expect-error - dynamic property lookup
|
|
157
|
+
'options' in entity ? entity.options?.instructionText : '',
|
|
158
|
+
[TranslationRowTypes.ListItemHint]: () =>
|
|
159
|
+
// @ts-expect-error - dynamic property lookup
|
|
160
|
+
'hint' in entity ? entity.hint.text : '',
|
|
161
|
+
[TranslationRowTypes.DeclarationBody]: () =>
|
|
162
|
+
'content' in entity ? entity.content : '',
|
|
163
|
+
[TranslationRowTypes.PaymentDescription]: () =>
|
|
164
|
+
// @ts-expect-error - dynamic property lookup
|
|
165
|
+
'options' in entity ? entity.options?.description : ''
|
|
166
|
+
}
|
|
167
|
+
const func = resolveData[keyType]
|
|
168
|
+
if (func) {
|
|
169
|
+
return func(entity)
|
|
170
|
+
} else {
|
|
171
|
+
const entityWithDynamicProperties = /** @type {Record<string, unknown>} */ (
|
|
172
|
+
/** @type {unknown} */ (entity)
|
|
173
|
+
)
|
|
174
|
+
if (typeof entity === 'object') {
|
|
175
|
+
return jsonSuffix in entityWithDynamicProperties
|
|
176
|
+
? /** @type {string} */ (entityWithDynamicProperties[jsonSuffix])
|
|
177
|
+
: ''
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return entity
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* @import { ComponentDef } from '~/src/components/types.js'
|
|
185
|
+
* @import { Item, Page } from '~/src/form/form-definition/types.js'
|
|
186
|
+
*/
|