@defra/forms-model 3.0.643 → 3.0.645
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/form/form-audit/index.js +5 -4
- package/dist/module/form/form-audit/index.js.map +1 -1
- package/dist/module/form/form-definition/constants.js +3 -0
- package/dist/module/form/form-definition/constants.js.map +1 -0
- package/dist/module/form/form-definition/index.js +6 -9
- package/dist/module/form/form-definition/index.js.map +1 -1
- package/dist/module/form/form-editor/index.js +4 -1
- package/dist/module/form/form-editor/index.js.map +1 -1
- package/dist/module/form/form-metadata/index.js +4 -3
- package/dist/module/form/form-metadata/index.js.map +1 -1
- package/dist/module/form/form-metrics/enums.js +7 -0
- package/dist/module/form/form-metrics/enums.js.map +1 -0
- package/dist/module/form/form-metrics/types.js +2 -0
- package/dist/module/form/form-metrics/types.js.map +1 -0
- package/dist/module/form/utils/index.js +1 -0
- package/dist/module/form/utils/index.js.map +1 -1
- package/dist/module/form/utils/prevent-unicode.js +20 -0
- package/dist/module/form/utils/prevent-unicode.js.map +1 -0
- package/dist/module/index.js +2 -0
- package/dist/module/index.js.map +1 -1
- package/dist/module/pages/helpers.js +38 -2
- package/dist/module/pages/helpers.js.map +1 -1
- package/dist/module/pages/index.js +1 -1
- package/dist/module/pages/index.js.map +1 -1
- package/dist/types/form/form-definition/constants.d.ts +3 -0
- package/dist/types/form/form-definition/constants.d.ts.map +1 -0
- package/dist/types/form/form-definition/index.d.ts +1 -2
- 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-metadata/index.d.ts.map +1 -1
- package/dist/types/form/form-metrics/enums.d.ts +6 -0
- package/dist/types/form/form-metrics/enums.d.ts.map +1 -0
- package/dist/types/form/form-metrics/types.d.ts +32 -0
- package/dist/types/form/form-metrics/types.d.ts.map +1 -0
- package/dist/types/form/utils/index.d.ts +1 -0
- package/dist/types/form/utils/index.d.ts.map +1 -1
- package/dist/types/form/utils/prevent-unicode.d.ts +10 -0
- package/dist/types/form/utils/prevent-unicode.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/pages/helpers.d.ts +9 -0
- package/dist/types/pages/helpers.d.ts.map +1 -1
- package/dist/types/pages/index.d.ts +1 -1
- package/dist/types/pages/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/form/form-audit/index.ts +4 -4
- package/src/form/form-definition/constants.ts +2 -0
- package/src/form/form-definition/index.ts +13 -14
- package/src/form/form-editor/index.ts +11 -1
- package/src/form/form-metadata/index.ts +7 -8
- package/src/form/form-metrics/enums.ts +5 -0
- package/src/form/form-metrics/types.ts +39 -0
- package/src/form/utils/index.ts +1 -0
- package/src/form/utils/prevent-unicode.js +19 -0
- package/src/index.ts +2 -0
- package/src/pages/helpers.ts +43 -0
- package/src/pages/index.ts +2 -0
|
@@ -52,9 +52,9 @@ import {
|
|
|
52
52
|
type FormUploadedMessageData,
|
|
53
53
|
type FormsBackupRequestedMessageData
|
|
54
54
|
} from '~/src/form/form-audit/types.js'
|
|
55
|
+
import { emailAddressNoUnicodeSchema } from '~/src/form/form-editor/index.js'
|
|
55
56
|
import {
|
|
56
57
|
contactSchema,
|
|
57
|
-
emailAddressSchema,
|
|
58
58
|
emailResponseTimeSchema,
|
|
59
59
|
idSchema,
|
|
60
60
|
notificationEmailAddressSchema,
|
|
@@ -181,7 +181,7 @@ export const formSupportOnlineChanges = Joi.object<FormSupportOnlineChanges>()
|
|
|
181
181
|
|
|
182
182
|
export const formSupportEmailChanges = Joi.object<FormSupportEmailChanges>()
|
|
183
183
|
.keys({
|
|
184
|
-
address:
|
|
184
|
+
address: emailAddressNoUnicodeSchema.optional(),
|
|
185
185
|
responseTime: emailResponseTimeSchema.optional()
|
|
186
186
|
})
|
|
187
187
|
.description('Changes schema for FORM_SUPPORT_EMAIL_UPDATED event')
|
|
@@ -238,7 +238,7 @@ export const entitlementMessageData = Joi.object<EntitlementMessageData>().keys(
|
|
|
238
238
|
{
|
|
239
239
|
userId: Joi.string().required(),
|
|
240
240
|
displayName: Joi.string().required(),
|
|
241
|
-
email:
|
|
241
|
+
email: emailAddressNoUnicodeSchema.required(),
|
|
242
242
|
roles: Joi.array().items(Joi.string())
|
|
243
243
|
}
|
|
244
244
|
)
|
|
@@ -260,7 +260,7 @@ export const excelGenerationMessageData =
|
|
|
260
260
|
.keys({
|
|
261
261
|
formId: Joi.string().required(),
|
|
262
262
|
formName: Joi.string().required(),
|
|
263
|
-
notificationEmail:
|
|
263
|
+
notificationEmail: emailAddressNoUnicodeSchema.required()
|
|
264
264
|
})
|
|
265
265
|
.required()
|
|
266
266
|
.description(
|
|
@@ -25,6 +25,10 @@ import {
|
|
|
25
25
|
type RelativeDateValueData,
|
|
26
26
|
type RelativeDateValueDataV2
|
|
27
27
|
} from '~/src/conditions/types.js'
|
|
28
|
+
import {
|
|
29
|
+
MAX_NUMBER_OF_REPEAT_ITEMS,
|
|
30
|
+
MIN_NUMBER_OF_REPEAT_ITEMS
|
|
31
|
+
} from '~/src/form/form-definition/constants.js'
|
|
28
32
|
import {
|
|
29
33
|
isConditionListItemRefValueData,
|
|
30
34
|
isFormDefinition
|
|
@@ -47,6 +51,7 @@ import {
|
|
|
47
51
|
type RepeatSchema,
|
|
48
52
|
type Section
|
|
49
53
|
} from '~/src/form/form-definition/types.js'
|
|
54
|
+
import { emailAddressNoUnicodeSchema } from '~/src/form/form-editor/index.js'
|
|
50
55
|
import { checkErrors } from '~/src/form/form-manager/errors.js'
|
|
51
56
|
import {
|
|
52
57
|
FormDefinitionError,
|
|
@@ -348,9 +353,6 @@ const conditionSchema = Joi.object<ConditionData>()
|
|
|
348
353
|
)
|
|
349
354
|
})
|
|
350
355
|
|
|
351
|
-
export const MIN_NUMBER_OF_REPEAT_ITEMS = 1
|
|
352
|
-
export const MAX_NUMBER_OF_REPEAT_ITEMS = 200
|
|
353
|
-
|
|
354
356
|
export const conditionDataSchemaV2 = Joi.object<ConditionDataV2>()
|
|
355
357
|
.description('Condition definition')
|
|
356
358
|
.keys({
|
|
@@ -1041,13 +1043,7 @@ const feedbackSchema = Joi.object<FormDefinition['feedback']>()
|
|
|
1041
1043
|
.description(
|
|
1042
1044
|
'URL to an external feedback form when not using built-in feedback'
|
|
1043
1045
|
),
|
|
1044
|
-
emailAddress:
|
|
1045
|
-
.trim()
|
|
1046
|
-
.email({
|
|
1047
|
-
tlds: {
|
|
1048
|
-
allow: false
|
|
1049
|
-
}
|
|
1050
|
-
})
|
|
1046
|
+
emailAddress: emailAddressNoUnicodeSchema
|
|
1051
1047
|
.optional()
|
|
1052
1048
|
.description('Email address where feedback is sent')
|
|
1053
1049
|
})
|
|
@@ -1155,8 +1151,7 @@ export const formDefinitionSchema = Joi.object<FormDefinition>()
|
|
|
1155
1151
|
.optional()
|
|
1156
1152
|
.description('Phase banner configuration'),
|
|
1157
1153
|
options: optionsSchema.optional().description('Options for the form'),
|
|
1158
|
-
outputEmail:
|
|
1159
|
-
.trim()
|
|
1154
|
+
outputEmail: emailAddressNoUnicodeSchema
|
|
1160
1155
|
.email({ tlds: { allow: ['uk'] } })
|
|
1161
1156
|
.optional()
|
|
1162
1157
|
.description('Email address where form submissions are sent'),
|
|
@@ -1165,8 +1160,7 @@ export const formDefinitionSchema = Joi.object<FormDefinition>()
|
|
|
1165
1160
|
.description('Configuration for submission output format'),
|
|
1166
1161
|
outputs: Joi.array()
|
|
1167
1162
|
.items({
|
|
1168
|
-
emailAddress:
|
|
1169
|
-
.trim()
|
|
1163
|
+
emailAddress: emailAddressNoUnicodeSchema
|
|
1170
1164
|
.email({ tlds: { allow: ['uk'] } })
|
|
1171
1165
|
.description('Email address where form submissions are sent'),
|
|
1172
1166
|
audience: Joi.string()
|
|
@@ -1244,6 +1238,11 @@ export const formDefinitionV2Schema = formDefinitionSchema
|
|
|
1244
1238
|
})
|
|
1245
1239
|
.description('Form definition schema for V2')
|
|
1246
1240
|
|
|
1241
|
+
export {
|
|
1242
|
+
MAX_NUMBER_OF_REPEAT_ITEMS,
|
|
1243
|
+
MIN_NUMBER_OF_REPEAT_ITEMS
|
|
1244
|
+
} from '~/src/form/form-definition/constants.js'
|
|
1245
|
+
|
|
1247
1246
|
// Maintain compatibility with legacy named export
|
|
1248
1247
|
// E.g. `import { Schema } from '@defra/forms-model'`
|
|
1249
1248
|
export const Schema = formDefinitionSchema
|
|
@@ -5,7 +5,7 @@ import { ComponentType } from '~/src/components/enums.js'
|
|
|
5
5
|
import {
|
|
6
6
|
MAX_NUMBER_OF_REPEAT_ITEMS,
|
|
7
7
|
MIN_NUMBER_OF_REPEAT_ITEMS
|
|
8
|
-
} from '~/src/form/form-definition/
|
|
8
|
+
} from '~/src/form/form-definition/constants.js'
|
|
9
9
|
import {
|
|
10
10
|
type FormEditorInputCheckAnswersSettings,
|
|
11
11
|
type FormEditorInputPage,
|
|
@@ -16,6 +16,16 @@ import {
|
|
|
16
16
|
type GovukFieldUsePostcodeLookup,
|
|
17
17
|
type GovukStringField
|
|
18
18
|
} from '~/src/form/form-editor/types.js'
|
|
19
|
+
import { preventUnicodeInEmail } from '~/src/form/utils/prevent-unicode.js'
|
|
20
|
+
|
|
21
|
+
export const emailAddressNoUnicodeSchema = Joi.string()
|
|
22
|
+
.trim()
|
|
23
|
+
.email()
|
|
24
|
+
.custom((value, helpers) => preventUnicodeInEmail(value, helpers))
|
|
25
|
+
.description('Email address preventing unicode characters')
|
|
26
|
+
|
|
27
|
+
export const UNICODE_EMAIL_ERROR_MESSAGE =
|
|
28
|
+
'The email address you entered includes invalid characters, for example, long dashes'
|
|
19
29
|
|
|
20
30
|
export enum QuestionTypeSubGroup {
|
|
21
31
|
WrittenAnswerSubGroup = 'writtenAnswerSub',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Joi from 'joi'
|
|
2
2
|
|
|
3
|
+
import { emailAddressNoUnicodeSchema } from '~/src/form/form-editor/index.js'
|
|
3
4
|
import {
|
|
4
5
|
type FormMetadata,
|
|
5
6
|
type FormMetadataAuthor,
|
|
@@ -53,7 +54,7 @@ export const teamNameSchema = Joi.string()
|
|
|
53
54
|
.required()
|
|
54
55
|
.description('Name of the team responsible for the form')
|
|
55
56
|
|
|
56
|
-
export const teamEmailSchema =
|
|
57
|
+
export const teamEmailSchema = emailAddressNoUnicodeSchema
|
|
57
58
|
.email({ tlds: { allow: ['uk'] } })
|
|
58
59
|
.trim()
|
|
59
60
|
.required()
|
|
@@ -63,9 +64,7 @@ export const phoneSchema = Joi.string()
|
|
|
63
64
|
.trim()
|
|
64
65
|
.description('Phone number for form-related inquiries')
|
|
65
66
|
|
|
66
|
-
export const emailAddressSchema =
|
|
67
|
-
.email()
|
|
68
|
-
.trim()
|
|
67
|
+
export const emailAddressSchema = emailAddressNoUnicodeSchema
|
|
69
68
|
.required()
|
|
70
69
|
.description('Email address for form-related inquiries')
|
|
71
70
|
|
|
@@ -132,10 +131,10 @@ export const termsAndConditionsAgreedSchema = Joi.boolean().description(
|
|
|
132
131
|
'Whether the data protection terms and conditions have been agreed to'
|
|
133
132
|
)
|
|
134
133
|
|
|
135
|
-
export const notificationEmailAddressSchema =
|
|
136
|
-
.
|
|
137
|
-
|
|
138
|
-
|
|
134
|
+
export const notificationEmailAddressSchema =
|
|
135
|
+
emailAddressNoUnicodeSchema.description(
|
|
136
|
+
'Email address to receive form submission notifications'
|
|
137
|
+
)
|
|
139
138
|
|
|
140
139
|
export const authoredAtSchema = Joi.date()
|
|
141
140
|
.iso()
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type FormStatus } from '~/src/common/enums.js'
|
|
2
|
+
import { type FormMetricType } from '~/src/form/form-metrics/enums.js'
|
|
3
|
+
|
|
4
|
+
export interface FormHeadlineDetail {
|
|
5
|
+
count: number
|
|
6
|
+
countSevenDaysAgo: number
|
|
7
|
+
countThirtyDaysAgo: number
|
|
8
|
+
countOneYearAgo: number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface FormHeadlineMetric {
|
|
12
|
+
type: FormMetricType.HeadlineMetric
|
|
13
|
+
headlineCounts: Record<string, FormHeadlineDetail>
|
|
14
|
+
updatedAt: Date
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface FormOverviewMetric {
|
|
18
|
+
type: FormMetricType.OverviewMetric
|
|
19
|
+
formId: string
|
|
20
|
+
formStatus: FormStatus
|
|
21
|
+
summaryMetrics: Record<string, number | string | string[]>
|
|
22
|
+
featureCounts: Record<string, number>
|
|
23
|
+
submissionsCount: number
|
|
24
|
+
updatedAt: Date
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface FormTimelineMetric {
|
|
28
|
+
type: FormMetricType.TimelineMetric
|
|
29
|
+
formId: string
|
|
30
|
+
formStatus: FormStatus
|
|
31
|
+
metricName: string
|
|
32
|
+
metricValue: number
|
|
33
|
+
createdAt: Date
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type FormMetric =
|
|
37
|
+
| FormHeadlineMetric
|
|
38
|
+
| FormOverviewMetric
|
|
39
|
+
| FormTimelineMetric
|
package/src/form/utils/index.ts
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom Joi validator to prevent Unicode characters in say an email address.
|
|
3
|
+
* Although Joi has Joi.email({ allowUnicode: false }), we can't differentiate from a general
|
|
4
|
+
* email format error or a Unicode error - hance the custom validator to allow a different error message
|
|
5
|
+
* @param {unknown} value
|
|
6
|
+
* @param {CustomHelpers<string>} helpers
|
|
7
|
+
*/
|
|
8
|
+
export function preventUnicodeInEmail(value, helpers) {
|
|
9
|
+
if (!value || typeof value !== 'string') {
|
|
10
|
+
return helpers.error('string.empty')
|
|
11
|
+
}
|
|
12
|
+
const invalidCharsRegex = /[^a-zA-Z0-9.!#$%&'*+/=?^_`{|}~@-]/
|
|
13
|
+
const invalid = invalidCharsRegex.exec(value)
|
|
14
|
+
return invalid ? helpers.error('string.unicode') : value
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @import { type CustomHelpers } from 'joi'
|
|
19
|
+
*/
|
package/src/index.ts
CHANGED
|
@@ -10,6 +10,8 @@ export * from '~/src/form/form-definition/index.js'
|
|
|
10
10
|
export * from '~/src/form/form-definition/types.js'
|
|
11
11
|
export * from '~/src/form/form-definition/helpers.js'
|
|
12
12
|
export * from '~/src/form/form-metadata/index.js'
|
|
13
|
+
export * from '~/src/form/form-metrics/enums.js'
|
|
14
|
+
export * from '~/src/form/form-metrics/types.js'
|
|
13
15
|
export * from '~/src/form/form-submission/index.js'
|
|
14
16
|
export * from '~/src/form/form-submission/enums.js'
|
|
15
17
|
export * from '~/src/form/utils/index.js'
|
package/src/pages/helpers.ts
CHANGED
|
@@ -135,6 +135,47 @@ export function includesPaymentField(components: ComponentDef[]): boolean {
|
|
|
135
135
|
)
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Helper function to determine if a payment question already exists in the form
|
|
140
|
+
*/
|
|
141
|
+
export function hasPaymentQuestionInForm(definition: FormDefinition) {
|
|
142
|
+
if (definition.pages.length === 0) {
|
|
143
|
+
return false
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
for (const page of definition.pages) {
|
|
147
|
+
const hasPayment = hasComponents(page)
|
|
148
|
+
? includesPaymentField(page.components)
|
|
149
|
+
: false
|
|
150
|
+
if (hasPayment) {
|
|
151
|
+
return true
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return false
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Helper function to determine if a specific question type exists in the form
|
|
159
|
+
*/
|
|
160
|
+
export function hasSpecificQuestionTypeInForm(
|
|
161
|
+
definition: FormDefinition,
|
|
162
|
+
componentType: ComponentType
|
|
163
|
+
) {
|
|
164
|
+
if (definition.pages.length === 0) {
|
|
165
|
+
return false
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
for (const page of definition.pages) {
|
|
169
|
+
const hasPayment = hasComponents(page)
|
|
170
|
+
? page.components.some((component) => component.type === componentType)
|
|
171
|
+
: false
|
|
172
|
+
if (hasPayment) {
|
|
173
|
+
return true
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return false
|
|
177
|
+
}
|
|
178
|
+
|
|
138
179
|
const SHOW_REPEATER_CONTROLLERS = [ControllerType.Page, ControllerType.Repeat]
|
|
139
180
|
|
|
140
181
|
export function showRepeaterSettings(page: Page): boolean {
|
|
@@ -207,6 +248,7 @@ export function replaceCustomControllers(definition: FormDefinition) {
|
|
|
207
248
|
const standardControllers = new Set(
|
|
208
249
|
Object.values(ControllerType)
|
|
209
250
|
.filter((x) => x !== ControllerType.SummaryWithConfirmationEmail)
|
|
251
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion
|
|
210
252
|
.map((x) => x.toString())
|
|
211
253
|
)
|
|
212
254
|
|
|
@@ -215,6 +257,7 @@ export function replaceCustomControllers(definition: FormDefinition) {
|
|
|
215
257
|
pages: definition.pages.map((page) => {
|
|
216
258
|
if (
|
|
217
259
|
!standardControllers.has(
|
|
260
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion
|
|
218
261
|
(page.controller ?? ControllerType.Page).toString()
|
|
219
262
|
)
|
|
220
263
|
) {
|
package/src/pages/index.ts
CHANGED