@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
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { lookupTranslation } from '~/src/form/form-editor/translations/translations-config.js'
|
|
2
|
+
|
|
3
|
+
const formNameKey = 'form.title'
|
|
4
|
+
const contactEmailAddressKey = 'form.contact.email.address'
|
|
5
|
+
const contactEmailResponseKey = 'form.contact.email.responseTime'
|
|
6
|
+
const contactOnlineUrlKey = 'form.contact.online.url'
|
|
7
|
+
const contactOnlineTextKey = 'form.contact.online.text'
|
|
8
|
+
const contactPhoneKey = 'form.contact.phone'
|
|
9
|
+
const submissionGuidanceKey = 'form.submissionGuidance'
|
|
10
|
+
const privacyNoticeUrlKey = 'form.privacyNoticeUrl'
|
|
11
|
+
const privacyNoticeTextKey = 'form.privacyNoticeText'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Determine a field value, either from the user-entered payload (validation) or from a translation lookup
|
|
15
|
+
* @param {string} key
|
|
16
|
+
* @param {Record<string, string>} translations
|
|
17
|
+
* @param {ValidationFailure<any>} [validation]
|
|
18
|
+
* @returns { string | undefined }
|
|
19
|
+
*/
|
|
20
|
+
function getTranslation(key, translations, validation) {
|
|
21
|
+
return validation?.formValues[key] ?? lookupTranslation(key, translations)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Build all translation rows in the form overview section (metatdata values).
|
|
26
|
+
* @param {FormMetadata} metadata
|
|
27
|
+
* @param {FormDefinition} definition
|
|
28
|
+
* @param {Record<string, string>} translations
|
|
29
|
+
* @param {ValidationFailure<any>} [validation]
|
|
30
|
+
* @returns {TranslationRow[]}
|
|
31
|
+
*/
|
|
32
|
+
export function buildOverviewSection(
|
|
33
|
+
metadata,
|
|
34
|
+
definition,
|
|
35
|
+
translations,
|
|
36
|
+
validation
|
|
37
|
+
) {
|
|
38
|
+
/** @type {TranslationRow[]} */
|
|
39
|
+
const rows = []
|
|
40
|
+
|
|
41
|
+
rows.push(
|
|
42
|
+
{
|
|
43
|
+
name: formNameKey,
|
|
44
|
+
englishContent: definition.name,
|
|
45
|
+
welshContent: getTranslation(formNameKey, translations, validation),
|
|
46
|
+
label: 'Welsh form name'
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: contactEmailAddressKey,
|
|
50
|
+
englishContent: metadata.contact?.email?.address ?? 'Not set',
|
|
51
|
+
welshContent: getTranslation(
|
|
52
|
+
contactEmailAddressKey,
|
|
53
|
+
translations,
|
|
54
|
+
validation
|
|
55
|
+
),
|
|
56
|
+
label: 'Welsh support email address'
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: contactEmailResponseKey,
|
|
60
|
+
englishContent: metadata.contact?.email?.responseTime ?? '--',
|
|
61
|
+
welshContent: getTranslation(
|
|
62
|
+
contactEmailResponseKey,
|
|
63
|
+
translations,
|
|
64
|
+
validation
|
|
65
|
+
),
|
|
66
|
+
label: 'Welsh response time message'
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: contactOnlineUrlKey,
|
|
70
|
+
englishContent: metadata.contact?.online?.url ?? 'Not set',
|
|
71
|
+
welshContent: getTranslation(
|
|
72
|
+
contactOnlineUrlKey,
|
|
73
|
+
translations,
|
|
74
|
+
validation
|
|
75
|
+
),
|
|
76
|
+
label: 'Welsh contact link URL'
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: contactOnlineTextKey,
|
|
80
|
+
englishContent: metadata.contact?.online?.text ?? '--',
|
|
81
|
+
welshContent: getTranslation(
|
|
82
|
+
contactOnlineTextKey,
|
|
83
|
+
translations,
|
|
84
|
+
validation
|
|
85
|
+
),
|
|
86
|
+
label: 'Welsh text for the contact link'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: contactPhoneKey,
|
|
90
|
+
englishContent: metadata.contact?.phone ?? 'Not set',
|
|
91
|
+
welshContent: getTranslation(contactPhoneKey, translations, validation),
|
|
92
|
+
label: 'Welsh phone number and opening times'
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: submissionGuidanceKey,
|
|
96
|
+
englishContent: metadata.submissionGuidance ?? 'Not set',
|
|
97
|
+
welshContent: getTranslation(
|
|
98
|
+
submissionGuidanceKey,
|
|
99
|
+
translations,
|
|
100
|
+
validation
|
|
101
|
+
),
|
|
102
|
+
label: 'Welsh information about what happens next'
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if (metadata.privacyNoticeType === 'link') {
|
|
107
|
+
rows.push({
|
|
108
|
+
name: privacyNoticeUrlKey,
|
|
109
|
+
englishContent: metadata.privacyNoticeUrl ?? 'Not set',
|
|
110
|
+
welshContent: getTranslation(
|
|
111
|
+
privacyNoticeUrlKey,
|
|
112
|
+
translations,
|
|
113
|
+
validation
|
|
114
|
+
),
|
|
115
|
+
label: 'Welsh privacy notice URL'
|
|
116
|
+
})
|
|
117
|
+
} else {
|
|
118
|
+
rows.push({
|
|
119
|
+
name: privacyNoticeTextKey,
|
|
120
|
+
englishContent: metadata.privacyNoticeText ?? 'Not set',
|
|
121
|
+
welshContent: getTranslation(
|
|
122
|
+
privacyNoticeTextKey,
|
|
123
|
+
translations,
|
|
124
|
+
validation
|
|
125
|
+
),
|
|
126
|
+
label: 'Welsh privacy notice text'
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return /** @type {TranslationRow[]} */ (rows)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @import { FormMetadata } from '~/src/form/form-metadata/types.js'
|
|
135
|
+
* @import { FormDefinition } from '~/src/form/form-definition/types.js'
|
|
136
|
+
* @import { TranslationRow, ValidationFailure} from '~/src/form/form-editor/translations/translations-config.js'
|
|
137
|
+
*/
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { ComponentType } from '~/src/components/enums.js'
|
|
2
|
+
import { isListType, isTypeWithInstructions } from '~/src/components/helpers.js'
|
|
3
|
+
import {
|
|
4
|
+
IGNORE_FIELDS,
|
|
5
|
+
TranslationRowTypes,
|
|
6
|
+
drillDown,
|
|
7
|
+
keyConfig,
|
|
8
|
+
lookupTranslation
|
|
9
|
+
} from '~/src/form/form-editor/translations/translations-config.js'
|
|
10
|
+
import { buildOverviewSection } from '~/src/form/form-editor/translations/translations-overview.js'
|
|
11
|
+
import { getListFromComponent } from '~/src/form/utils/list.js'
|
|
12
|
+
import { getPageNum, getQuestionNum } from '~/src/form/utils/numbering.js'
|
|
13
|
+
import { ControllerType } from '~/src/pages/enums.js'
|
|
14
|
+
import { hasComponents } from '~/src/pages/helpers.js'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a translation row for a single entity field.
|
|
18
|
+
* @param {ComponentDef | Page | Item} entity - The source entity that contains the English content.
|
|
19
|
+
* @param {string} keyType - The translation row type to build.
|
|
20
|
+
* @param {{ pageNum: number, questionNum?: number, itemNum?: number, translations: Record<string, string>, validation?: ValidationFailure<any> }} options - The row context including numbering and translation values.
|
|
21
|
+
* @returns {TranslationRow} The populated translation row for the entity field.
|
|
22
|
+
*/
|
|
23
|
+
function createRow(
|
|
24
|
+
entity,
|
|
25
|
+
keyType,
|
|
26
|
+
{ pageNum, questionNum, itemNum, translations, validation }
|
|
27
|
+
) {
|
|
28
|
+
const keyProperties = keyConfig[keyType]
|
|
29
|
+
|
|
30
|
+
const innerEnglishContent = drillDown(
|
|
31
|
+
keyType,
|
|
32
|
+
entity,
|
|
33
|
+
keyProperties.jsonSuffix
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
const keyName = `${keyProperties.jsonPrefix}.${entity.id}.${keyProperties.jsonSuffix}`
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
name: keyName,
|
|
40
|
+
type: keyType,
|
|
41
|
+
pageNum,
|
|
42
|
+
questionNum,
|
|
43
|
+
itemNum,
|
|
44
|
+
englishContent: innerEnglishContent,
|
|
45
|
+
welshContent:
|
|
46
|
+
validation?.formValues[keyName] ??
|
|
47
|
+
lookupTranslation(keyName, translations),
|
|
48
|
+
label: keyProperties.getLabel(pageNum, questionNum, itemNum)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const allowedControllerTypesSet = new Set([
|
|
53
|
+
ControllerType.Page,
|
|
54
|
+
ControllerType.Repeat,
|
|
55
|
+
ControllerType.Start,
|
|
56
|
+
ControllerType.FileUpload,
|
|
57
|
+
ControllerType.Terminal
|
|
58
|
+
])
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Build the translation rows for a single page.
|
|
62
|
+
* @param {Page} page - The page definition to inspect for translatable content.
|
|
63
|
+
* @param {number} pageNum - The page number used in the generated labels.
|
|
64
|
+
* @param {Record<string, string>} translations - Existing Welsh translations keyed by translation name.
|
|
65
|
+
* @param {ValidationFailure<any>} [validation] - Optional validation context for posted form values.
|
|
66
|
+
* @returns {TranslationRow[]} The translation rows generated for the page.
|
|
67
|
+
*/
|
|
68
|
+
function buildPage(page, pageNum, translations, validation) {
|
|
69
|
+
if (page.controller && !allowedControllerTypesSet.has(page.controller)) {
|
|
70
|
+
return []
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const translationRows = []
|
|
74
|
+
if (page.title) {
|
|
75
|
+
const keyProperties = keyConfig[TranslationRowTypes.PageHeading]
|
|
76
|
+
|
|
77
|
+
const keyName = `${keyProperties.jsonPrefix}.${page.id}.${keyProperties.jsonSuffix}`
|
|
78
|
+
|
|
79
|
+
translationRows.push({
|
|
80
|
+
name: keyName,
|
|
81
|
+
type: TranslationRowTypes.PageHeading,
|
|
82
|
+
pageNum,
|
|
83
|
+
englishContent: page.title,
|
|
84
|
+
welshContent:
|
|
85
|
+
validation?.formValues[keyName] ??
|
|
86
|
+
lookupTranslation(keyName, translations),
|
|
87
|
+
label: keyProperties.getLabel(pageNum)
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const guidance =
|
|
92
|
+
hasComponents(page) && page.components[0].type === ComponentType.Markdown
|
|
93
|
+
? page.components[0]
|
|
94
|
+
: undefined
|
|
95
|
+
if (guidance) {
|
|
96
|
+
const keyProperties = keyConfig[TranslationRowTypes.PageGuidance]
|
|
97
|
+
const keyName = `${keyProperties.jsonPrefix}.${guidance.id}.${keyProperties.jsonSuffix}`
|
|
98
|
+
|
|
99
|
+
translationRows.push({
|
|
100
|
+
name: keyName,
|
|
101
|
+
type: TranslationRowTypes.PageGuidance,
|
|
102
|
+
pageNum,
|
|
103
|
+
englishContent: guidance.content,
|
|
104
|
+
welshContent:
|
|
105
|
+
validation?.formValues[keyName] ??
|
|
106
|
+
lookupTranslation(keyName, translations),
|
|
107
|
+
label: keyProperties.getLabel(pageNum)
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (page.controller === ControllerType.Repeat) {
|
|
112
|
+
const keyProperties = keyConfig[TranslationRowTypes.RepeatTitle]
|
|
113
|
+
const keyName = `${keyProperties.jsonPrefix}.${page.id}.${keyProperties.jsonSuffix}`
|
|
114
|
+
|
|
115
|
+
translationRows.push({
|
|
116
|
+
name: keyName,
|
|
117
|
+
type: TranslationRowTypes.RepeatTitle,
|
|
118
|
+
pageNum,
|
|
119
|
+
englishContent: page.repeat.options.title,
|
|
120
|
+
welshContent:
|
|
121
|
+
validation?.formValues[keyName] ??
|
|
122
|
+
lookupTranslation(keyName, translations),
|
|
123
|
+
label: keyProperties.getLabel(pageNum)
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return translationRows
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Build the translation rows for a single component.
|
|
132
|
+
* @param {FormDefinition} definition - The overall form definition used to resolve list-based content.
|
|
133
|
+
* @param {ComponentDef} component - The component to inspect for translatable fields.
|
|
134
|
+
* @param {number} pageNum - The page number used in the generated labels.
|
|
135
|
+
* @param {number} questionNum - The question number used in the generated labels.
|
|
136
|
+
* @param {Record<string, string>} translations - Existing Welsh translations keyed by translation name.
|
|
137
|
+
* @param {ValidationFailure<any>} [validation] - Optional validation context for posted form values.
|
|
138
|
+
* @returns {TranslationRow[]} The translation rows generated for the component.
|
|
139
|
+
*/
|
|
140
|
+
function buildComponent(
|
|
141
|
+
definition,
|
|
142
|
+
component,
|
|
143
|
+
pageNum,
|
|
144
|
+
questionNum,
|
|
145
|
+
translations,
|
|
146
|
+
validation
|
|
147
|
+
) {
|
|
148
|
+
if (IGNORE_FIELDS.includes(component.type)) {
|
|
149
|
+
return []
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const rows = []
|
|
153
|
+
|
|
154
|
+
const options = { pageNum, questionNum, translations, validation }
|
|
155
|
+
|
|
156
|
+
const typed = /** @type {InputFieldsComponentsDef} */ (component)
|
|
157
|
+
if (typed.title && component.type !== ComponentType.PaymentField) {
|
|
158
|
+
rows.push(createRow(component, TranslationRowTypes.QuestionText, options))
|
|
159
|
+
}
|
|
160
|
+
if (typed.hint) {
|
|
161
|
+
rows.push(createRow(component, TranslationRowTypes.QuestionHint, options))
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (component.type !== ComponentType.PaymentField) {
|
|
165
|
+
rows.push(
|
|
166
|
+
createRow(component, TranslationRowTypes.ShortDescription, options)
|
|
167
|
+
)
|
|
168
|
+
} else {
|
|
169
|
+
rows.push(
|
|
170
|
+
createRow(component, TranslationRowTypes.PaymentDescription, options)
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (component.type === ComponentType.DeclarationField) {
|
|
175
|
+
rows.push(
|
|
176
|
+
createRow(component, TranslationRowTypes.DeclarationBody, options)
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (component.type === ComponentType.PaymentField) {
|
|
181
|
+
rows.push(
|
|
182
|
+
createRow(component, TranslationRowTypes.PaymentDescription, options)
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (typed.options.instructionText && isTypeWithInstructions(component.type)) {
|
|
187
|
+
rows.push(
|
|
188
|
+
createRow(component, TranslationRowTypes.InstructionText, options)
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (isListType(component.type)) {
|
|
193
|
+
addSelectionOptions(rows, component, definition, options)
|
|
194
|
+
}
|
|
195
|
+
return rows
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Add translation rows for the select item options of a list-based component.
|
|
200
|
+
* @param {any[]} rows - The accumulator for translation rows.
|
|
201
|
+
* @param {ComponentDef} component - The list-based component to inspect.
|
|
202
|
+
* @param {FormDefinition} definition - The form definition that contains the option list data.
|
|
203
|
+
* @param {{ pageNum: number, questionNum?: number, translations: Record<string, string>, validation?: ValidationFailure<any> }} options - The row context including numbering and translation values.
|
|
204
|
+
*/
|
|
205
|
+
function addSelectionOptions(rows, component, definition, options) {
|
|
206
|
+
// Temporary workaround - ignore for Yes/No and use defaults in the plugin,
|
|
207
|
+
// until we create a solution that allows users to override the Yes/No options
|
|
208
|
+
if (component.type === ComponentType.YesNoField) {
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const list = getListFromComponent(component, definition)
|
|
213
|
+
if (list?.items.length) {
|
|
214
|
+
let itemNum = 0
|
|
215
|
+
for (const item of list.items) {
|
|
216
|
+
itemNum++
|
|
217
|
+
const listOptions = {
|
|
218
|
+
...options,
|
|
219
|
+
itemNum
|
|
220
|
+
}
|
|
221
|
+
if (item.hint) {
|
|
222
|
+
rows.push(
|
|
223
|
+
createRow(item, TranslationRowTypes.ListItemText, listOptions),
|
|
224
|
+
createRow(item, TranslationRowTypes.ListItemHint, listOptions)
|
|
225
|
+
)
|
|
226
|
+
} else {
|
|
227
|
+
rows.push(
|
|
228
|
+
createRow(item, TranslationRowTypes.ListItemText, listOptions)
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Build the overview and form translation rows for a form definition.
|
|
237
|
+
* @param {FormMetadata} metadata - The form metadata used to build the overview section.
|
|
238
|
+
* @param {FormDefinition} definition - The form definition containing pages and components.
|
|
239
|
+
* @param {ValidationFailure<any>} [validation] - Optional validation context for posted form values.
|
|
240
|
+
* @returns {{ overviewRows: TranslationRow[], formRows: TranslationRow[] }} The generated overview and form translation rows.
|
|
241
|
+
*/
|
|
242
|
+
export function buildTranslationDataRows(metadata, definition, validation) {
|
|
243
|
+
const translationsJSON = /** @type {Record<string, string>} */ (
|
|
244
|
+
// @ts-expect-error - dynamic language definition
|
|
245
|
+
definition.metadata?.translations?.cy
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
const overviewRows = buildOverviewSection(
|
|
249
|
+
metadata,
|
|
250
|
+
definition,
|
|
251
|
+
translationsJSON,
|
|
252
|
+
validation
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
const formRows = []
|
|
256
|
+
for (const page of definition.pages) {
|
|
257
|
+
const pageId = /** @type {string} */ (page.id)
|
|
258
|
+
const pageNum = getPageNum(definition, pageId)
|
|
259
|
+
const components = hasComponents(page) ? page.components : []
|
|
260
|
+
if (components.length === 0) {
|
|
261
|
+
continue
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
formRows.push(...buildPage(page, pageNum, translationsJSON, validation))
|
|
265
|
+
|
|
266
|
+
for (const component of components) {
|
|
267
|
+
if (component.type === ComponentType.Markdown) {
|
|
268
|
+
continue
|
|
269
|
+
}
|
|
270
|
+
const questionId = /** @type {string} */ (component.id)
|
|
271
|
+
const questionNum = getQuestionNum(definition, pageId, questionId)
|
|
272
|
+
|
|
273
|
+
formRows.push(
|
|
274
|
+
...buildComponent(
|
|
275
|
+
definition,
|
|
276
|
+
component,
|
|
277
|
+
pageNum,
|
|
278
|
+
questionNum,
|
|
279
|
+
translationsJSON,
|
|
280
|
+
validation
|
|
281
|
+
)
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
overviewRows,
|
|
288
|
+
formRows
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @import { ComponentDef, InputFieldsComponentsDef } from '~/src/components/types.js'
|
|
294
|
+
* @import { FormMetadata } from '~/src/form/form-metadata/types.js'
|
|
295
|
+
* @import { FormDefinition, Item, Page } from '~/src/form/form-definition/types.js'
|
|
296
|
+
* @import { TranslationRow, ValidationFailure } from '~/src/form/form-editor/translations/translations-config.js'
|
|
297
|
+
*/
|
|
@@ -423,6 +423,11 @@ export interface FormEditor {
|
|
|
423
423
|
*/
|
|
424
424
|
geometryTypes?: GeospatialFieldGeometryTypesEnum[]
|
|
425
425
|
|
|
426
|
+
/**
|
|
427
|
+
* The layers to include for map-based geospatial questions
|
|
428
|
+
*/
|
|
429
|
+
mapLayers?: string[]
|
|
430
|
+
|
|
426
431
|
/**
|
|
427
432
|
* The format restriction for telephone number questions
|
|
428
433
|
*/
|
|
@@ -519,6 +524,7 @@ export type FormEditorInputQuestion = Pick<
|
|
|
519
524
|
| 'minFeatures'
|
|
520
525
|
| 'maxFeatures'
|
|
521
526
|
| 'telephoneNumberFormat'
|
|
527
|
+
| 'mapLayers'
|
|
522
528
|
>
|
|
523
529
|
|
|
524
530
|
export type FormEditorInputPageSettings = Pick<
|
package/src/form/utils/list.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ComponentType } from '~/src/components/enums.js'
|
|
2
|
+
import { hasListField } from '~/src/components/helpers.js'
|
|
3
|
+
import {
|
|
4
|
+
type ComponentDef,
|
|
5
|
+
type ListComponentsDef
|
|
6
|
+
} from '~/src/components/types.js'
|
|
7
|
+
import { getYesNoList } from '~/src/components/yes-no-helper.js'
|
|
2
8
|
import {
|
|
3
9
|
type FormDefinition,
|
|
4
10
|
type List
|
|
@@ -23,3 +29,30 @@ export function findDefinitionListFromComponent(
|
|
|
23
29
|
|
|
24
30
|
return list
|
|
25
31
|
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Finds the list in the component, if it exists. Handles a Yes/No list which doesn't link to the list in the normal way
|
|
35
|
+
* @param { ComponentDef | undefined } component
|
|
36
|
+
* @param {FormDefinition} definition
|
|
37
|
+
* @returns { List | undefined }
|
|
38
|
+
*/
|
|
39
|
+
export function getListFromComponent(
|
|
40
|
+
component: ComponentDef | undefined,
|
|
41
|
+
definition: FormDefinition
|
|
42
|
+
) {
|
|
43
|
+
if (!component) {
|
|
44
|
+
return undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (component.type === ComponentType.YesNoField) {
|
|
48
|
+
return getYesNoList()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const listId = hasListField(component) ? component.list : undefined
|
|
52
|
+
|
|
53
|
+
if (listId) {
|
|
54
|
+
return definition.lists.find((list) => list.id === listId)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return undefined
|
|
58
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { isFormType } from '~/src/components/helpers.js'
|
|
2
|
+
import {
|
|
3
|
+
getPageFromDefinition,
|
|
4
|
+
hasComponents,
|
|
5
|
+
isSummaryPage
|
|
6
|
+
} from '~/src/pages/helpers.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {FormDefinition} definition
|
|
10
|
+
* @param {string} pageId
|
|
11
|
+
*/
|
|
12
|
+
export function getPageNum(definition, pageId) {
|
|
13
|
+
if (pageId === 'new') {
|
|
14
|
+
return definition.pages.filter((x) => !isSummaryPage(x)).length + 1
|
|
15
|
+
}
|
|
16
|
+
const pageIdx = definition.pages.findIndex((x) => x.id === pageId)
|
|
17
|
+
return pageIdx + 1
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {FormDefinition} definition
|
|
22
|
+
* @param {string} pageId
|
|
23
|
+
*/
|
|
24
|
+
export function getQuestionsOnPage(definition, pageId) {
|
|
25
|
+
const page = getPageFromDefinition(definition, pageId)
|
|
26
|
+
return hasComponents(page) ? page.components : []
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {FormDefinition} definition
|
|
31
|
+
* @param {string} pageId
|
|
32
|
+
* @param {string} questionId
|
|
33
|
+
*/
|
|
34
|
+
export function getQuestionNum(definition, pageId, questionId) {
|
|
35
|
+
const questions = getQuestionsOnPage(definition, pageId).filter(
|
|
36
|
+
(q) => isFormType(q.type) // Exclude non-form components such as Markdown
|
|
37
|
+
)
|
|
38
|
+
if (questionId === 'new') {
|
|
39
|
+
return questions.length + 1
|
|
40
|
+
}
|
|
41
|
+
const questionIdx = questions.findIndex((x) => x.id === questionId)
|
|
42
|
+
return questionIdx === -1 ? questions.length + 1 : questionIdx + 1
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @import { FormDefinition } from '~/src/form/form-definition/types.js'
|
|
47
|
+
*/
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,8 @@ export * from '~/src/form/utils/index.js'
|
|
|
19
19
|
export * from '~/src/form/form-editor/enums.js'
|
|
20
20
|
export * from '~/src/form/form-editor/index.js'
|
|
21
21
|
export * from '~/src/form/form-editor/preview/index.js'
|
|
22
|
+
export * from '~/src/form/form-editor/translations/translations-config.js'
|
|
23
|
+
export * from '~/src/form/form-editor/translations/translations.js'
|
|
22
24
|
export * from '~/src/form/form-manager/types.js'
|
|
23
25
|
export * from '~/src/form/form-manager/errors.js'
|
|
24
26
|
export * from '~/src/manage/dead-letter-queues.js'
|