@defra/forms-model 3.0.466 → 3.0.467

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.
@@ -3,10 +3,22 @@ import {
3
3
  type AutocompleteFieldComponent,
4
4
  type CheckboxesFieldComponent,
5
5
  type DatePartsFieldComponent,
6
+ type DetailsComponent,
7
+ type EmailAddressFieldComponent,
6
8
  type FileUploadFieldComponent,
9
+ type HtmlComponent,
10
+ type InsetTextComponent,
11
+ type ListComponent,
12
+ type MarkdownComponent,
13
+ type MonthYearFieldComponent,
14
+ type MultilineTextFieldComponent,
7
15
  type NumberFieldComponent,
8
16
  type RadiosFieldComponent,
9
- type TextFieldComponent
17
+ type SelectFieldComponent,
18
+ type TelephoneNumberFieldComponent,
19
+ type TextFieldComponent,
20
+ type UkAddressFieldComponent,
21
+ type YesNoFieldComponent
10
22
  } from '~/src/components/types.js'
11
23
  import { type Item, type List } from '~/src/form/form-definition/types.js'
12
24
 
@@ -17,19 +29,169 @@ import { type Item, type List } from '~/src/form/form-definition/types.js'
17
29
  export function buildTextFieldComponent(
18
30
  partialTextField: Partial<TextFieldComponent> = {}
19
31
  ): TextFieldComponent {
20
- const textFieldComponent: TextFieldComponent = {
32
+ return {
21
33
  id: '407dd0d7-cce9-4f43-8e1f-7d89cb698875',
22
34
  name: 'TextField',
23
35
  title: 'Text field',
24
- type: ComponentType.TextField,
25
36
  hint: '',
26
37
  options: {},
27
- schema: {}
38
+ schema: {},
39
+ ...partialTextField,
40
+ type: ComponentType.TextField
41
+ }
42
+ }
43
+
44
+ export function buildMultilineTextFieldComponent(
45
+ partialMultilineTextField: Partial<MultilineTextFieldComponent> = {}
46
+ ): MultilineTextFieldComponent {
47
+ return {
48
+ id: '72671f23-552e-4504-a06a-693e240880d5',
49
+ name: 'MuTeCo',
50
+ options: {},
51
+ schema: {},
52
+ title: 'Multiline TextField Component',
53
+ ...partialMultilineTextField,
54
+ type: ComponentType.MultilineTextField
55
+ }
56
+ }
57
+
58
+ export function buildYesNoFieldComponent(
59
+ partialYesNoField: Partial<YesNoFieldComponent> = {}
60
+ ): YesNoFieldComponent {
61
+ return {
62
+ title: 'YesNo Field Component',
63
+ id: 'be7f849c-47d8-4f1f-ba15-ab939dc70914',
64
+ name: 'YesNoFieldComponent',
65
+ options: {},
66
+ ...partialYesNoField,
67
+ type: ComponentType.YesNoField
68
+ }
69
+ }
70
+ export function buildMonthYearFieldComponent(
71
+ partialMonthYearField: Partial<MonthYearFieldComponent> = {}
72
+ ): MonthYearFieldComponent {
73
+ return {
74
+ id: 'd4e99aca-6d13-4c1a-a623-9e9e5b27d46d',
75
+ title: 'MonthYearFieldComponent',
76
+ name: 'MonthYearFieldComponent',
77
+ options: {},
78
+ ...partialMonthYearField,
79
+ type: ComponentType.MonthYearField
80
+ }
81
+ }
82
+ export function buildSelectFieldComponent(
83
+ partialSelectField: Partial<SelectFieldComponent> = {}
84
+ ): SelectFieldComponent {
85
+ return {
86
+ id: '7f219cf6-3e16-4549-b8df-789506682147',
87
+ list: '',
88
+ name: '',
89
+ options: {},
90
+ title: '',
91
+ ...partialSelectField,
92
+ type: ComponentType.SelectField
93
+ }
94
+ }
95
+ export function buildUkAddressFieldComponent(
96
+ partialUkAddressField: Partial<UkAddressFieldComponent> = {}
97
+ ): UkAddressFieldComponent {
98
+ return {
99
+ id: 'a7cb7440-9095-44cd-9136-2914232722c8',
100
+ title: 'UkAddressFieldComponent',
101
+ name: 'UkAddressFieldComponent',
102
+ options: {},
103
+ ...partialUkAddressField,
104
+ type: ComponentType.UkAddressField
105
+ }
106
+ }
107
+ export function buildTelephoneNumberFieldComponent(
108
+ partialTelephoneNumberField: Partial<TelephoneNumberFieldComponent> = {}
109
+ ): TelephoneNumberFieldComponent {
110
+ return {
111
+ id: '69907916-beac-4faa-b469-656dad5edced',
112
+ title: 'TelephoneNumberFieldComponent',
113
+ name: 'TelephoneNumberFieldComponent',
114
+ options: {},
115
+ ...partialTelephoneNumberField,
116
+ type: ComponentType.TelephoneNumberField
28
117
  }
118
+ }
119
+ export function buildEmailAddressFieldComponent(
120
+ partialEmailAddressField: Partial<EmailAddressFieldComponent> = {}
121
+ ): EmailAddressFieldComponent {
122
+ return {
123
+ id: '9dcf0781-bf34-48c8-b13b-d13050dc34d9',
124
+ title: 'EmailAddressFieldComponent',
125
+ name: 'EmailAddressFieldComponent',
126
+ options: {},
127
+ ...partialEmailAddressField,
128
+ type: ComponentType.EmailAddressField
129
+ }
130
+ }
29
131
 
132
+ export function buildHtmlComponent(
133
+ partialHtml: Partial<HtmlComponent> = {}
134
+ ): HtmlComponent {
135
+ return {
136
+ id: 'bac683ce-149e-4740-95aa-8289b35bc327',
137
+ title: 'HtmlComponent',
138
+ name: 'HtmlComponent',
139
+ options: {},
140
+ content: '',
141
+ ...partialHtml,
142
+ type: ComponentType.Html
143
+ }
144
+ }
145
+ export function buildInsetTextComponent(
146
+ partialInsetText: Partial<InsetTextComponent> = {}
147
+ ): InsetTextComponent {
148
+ return {
149
+ id: '6b717151-1e86-42b2-97a9-2201b0676e47',
150
+ title: 'InsetText Component',
151
+ name: 'InsetTextComponent',
152
+ content: '',
153
+ options: {},
154
+ ...partialInsetText,
155
+ type: ComponentType.InsetText
156
+ }
157
+ }
158
+ export function buildDetailsComponent(
159
+ partialDetails: Partial<DetailsComponent> = {}
160
+ ): DetailsComponent {
161
+ return {
162
+ id: '245d54df-bb1e-488e-82f6-8f1e42c197e6',
163
+ title: 'Details Component',
164
+ name: 'DetailsComponent',
165
+ content: '',
166
+ options: {},
167
+ ...partialDetails,
168
+ type: ComponentType.Details
169
+ }
170
+ }
171
+ export function buildListComponent(
172
+ partialList: Partial<ListComponent> = {}
173
+ ): ListComponent {
30
174
  return {
31
- ...textFieldComponent,
32
- ...partialTextField
175
+ id: '62f17168-c2ef-4978-bd42-bdaa5704e25f',
176
+ title: 'List Component',
177
+ name: 'ListComponent',
178
+ list: '',
179
+ options: {},
180
+ ...partialList,
181
+ type: ComponentType.List
182
+ }
183
+ }
184
+ export function buildMarkdownComponent(
185
+ partialMarkdown: Partial<MarkdownComponent> = {}
186
+ ): MarkdownComponent {
187
+ return {
188
+ id: '4a2dc88c-be1a-4277-aff8-04220de2e778',
189
+ title: 'Markdown Component',
190
+ name: 'MarkdownComponent',
191
+ options: {},
192
+ content: '',
193
+ ...partialMarkdown,
194
+ type: ComponentType.Markdown
33
195
  }
34
196
  }
35
197
 
@@ -38,19 +200,15 @@ export function buildTextFieldComponent(
38
200
  * @returns {FileUploadFieldComponent}
39
201
  */
40
202
  export function buildFileUploadComponent(
41
- partialFileUploadField: Partial<FileUploadFieldComponent>
203
+ partialFileUploadField: Partial<FileUploadFieldComponent> = {}
42
204
  ): FileUploadFieldComponent {
43
- const fileUploadFieldComponent: FileUploadFieldComponent = {
205
+ return {
44
206
  name: 'FileUploadField',
45
- type: ComponentType.FileUploadField,
46
207
  title: 'File Upload Field',
47
208
  options: {},
48
- schema: {}
49
- }
50
-
51
- return {
52
- ...fileUploadFieldComponent,
53
- ...partialFileUploadField
209
+ schema: {},
210
+ ...partialFileUploadField,
211
+ type: ComponentType.FileUploadField
54
212
  }
55
213
  }
56
214
 
@@ -60,19 +218,15 @@ export function buildFileUploadComponent(
60
218
  * @returns {AutocompleteFieldComponent}
61
219
  */
62
220
  export function buildAutoCompleteComponent(
63
- partialAutoCompleteField: Partial<AutocompleteFieldComponent>
221
+ partialAutoCompleteField: Partial<AutocompleteFieldComponent> = {}
64
222
  ): AutocompleteFieldComponent {
65
- const autocompleteComponent: AutocompleteFieldComponent = {
223
+ return {
66
224
  name: 'AutoCompleteField',
67
225
  title: 'What languages do you speak?',
68
- type: ComponentType.AutocompleteField,
69
226
  list: 'AutoCompleteList',
70
- options: {}
71
- }
72
-
73
- return {
74
- ...autocompleteComponent,
75
- ...partialAutoCompleteField
227
+ options: {},
228
+ ...partialAutoCompleteField,
229
+ type: ComponentType.AutocompleteField
76
230
  }
77
231
  }
78
232
 
@@ -83,17 +237,13 @@ export function buildAutoCompleteComponent(
83
237
  export function buildRadioComponent(
84
238
  partialListComponent: Partial<RadiosFieldComponent> = {}
85
239
  ): RadiosFieldComponent {
86
- const radioFieldComponent: RadiosFieldComponent = {
240
+ return {
87
241
  name: 'RadioField',
88
242
  title: 'Which country do you live in?',
89
- type: ComponentType.RadiosField,
90
243
  list: 'RadioList',
91
- options: {}
92
- }
93
-
94
- return {
95
- ...radioFieldComponent,
96
- ...partialListComponent
244
+ options: {},
245
+ ...partialListComponent,
246
+ type: ComponentType.RadiosField
97
247
  }
98
248
  }
99
249
 
@@ -102,19 +252,15 @@ export function buildRadioComponent(
102
252
  * @returns {CheckboxesFieldComponent}
103
253
  */
104
254
  export function buildCheckboxComponent(
105
- partialListComponent: Partial<CheckboxesFieldComponent>
255
+ partialListComponent: Partial<CheckboxesFieldComponent> = {}
106
256
  ): CheckboxesFieldComponent {
107
- const checkboxesFieldComponent: CheckboxesFieldComponent = {
257
+ return {
108
258
  name: 'FellowshipOfTheRing',
109
259
  title: 'Which are your favourite characters from the fellowship?',
110
- type: ComponentType.CheckboxesField,
111
260
  list: 'CheckboxList',
112
- options: {}
113
- }
114
-
115
- return {
116
- ...checkboxesFieldComponent,
117
- ...partialListComponent
261
+ options: {},
262
+ ...partialListComponent,
263
+ type: ComponentType.CheckboxesField
118
264
  }
119
265
  }
120
266
 
@@ -171,7 +317,7 @@ export function buildList(partialList: Partial<List> = {}): List {
171
317
  }
172
318
 
173
319
  export function buildNumberFieldComponent(
174
- partialComponent: Partial<NumberFieldComponent>
320
+ partialComponent: Partial<NumberFieldComponent> = {}
175
321
  ): NumberFieldComponent {
176
322
  return {
177
323
  name: 'year',
@@ -184,7 +330,7 @@ export function buildNumberFieldComponent(
184
330
  }
185
331
 
186
332
  export function buildDateComponent(
187
- partialComponent: Partial<DatePartsFieldComponent>
333
+ partialComponent: Partial<DatePartsFieldComponent> = {}
188
334
  ): DatePartsFieldComponent {
189
335
  return {
190
336
  name: 'bcdefg',
@@ -196,7 +342,7 @@ export function buildDateComponent(
196
342
  }
197
343
 
198
344
  export function buildRadiosComponent(
199
- partialComponent: Partial<RadiosFieldComponent>
345
+ partialComponent: Partial<RadiosFieldComponent> = {}
200
346
  ): RadiosFieldComponent {
201
347
  return {
202
348
  name: 'cdefgh',
@@ -33,13 +33,13 @@ export function buildQuestionPage(
33
33
  export function buildSummaryPage(
34
34
  partialSummaryPage: Partial<PageSummary> = {}
35
35
  ): PageSummary {
36
- const pageSummary: PageSummary = {
36
+ return {
37
37
  id: '449a45f6-4541-4a46-91bd-8b8931b07b50',
38
38
  title: 'Summary page',
39
+ ...partialSummaryPage,
39
40
  path: ControllerPath.Summary,
40
41
  controller: ControllerType.Summary
41
42
  }
42
- return { ...pageSummary, ...partialSummaryPage }
43
43
  }
44
44
 
45
45
  /**
@@ -50,7 +50,7 @@ export function buildSummaryPage(
50
50
  export function buildFileUploadPage(
51
51
  partialFileUploadPage: Partial<PageFileUpload> = {}
52
52
  ): PageFileUpload {
53
- const fileUploadPage: PageFileUpload = {
53
+ return {
54
54
  id: '85e5c8da-88f5-4009-a821-7d7de1364318',
55
55
  title: '',
56
56
  path: '/supporting-evidence',
@@ -69,13 +69,9 @@ export function buildFileUploadPage(
69
69
  id: '4189b8a1-1a04-4f74-a7a0-dd23012a0ee0'
70
70
  })
71
71
  ],
72
- controller: ControllerType.FileUpload,
73
- next: []
74
- }
75
-
76
- return {
77
- ...fileUploadPage,
78
- ...partialFileUploadPage
72
+ next: [],
73
+ ...partialFileUploadPage,
74
+ controller: ControllerType.FileUpload
79
75
  }
80
76
  }
81
77
 
@@ -87,7 +83,7 @@ export function buildFileUploadPage(
87
83
  export function buildRepeaterPage(
88
84
  partialRepeaterPage: Partial<PageRepeat> = {}
89
85
  ): PageRepeat {
90
- const repeaterPage: PageRepeat = {
86
+ return {
91
87
  title: 'Repeater Page',
92
88
  path: '/repeater-page',
93
89
  components: [
@@ -104,15 +100,11 @@ export function buildRepeaterPage(
104
100
  ],
105
101
  next: [],
106
102
  id: '32888028-61db-40fc-b255-80bc67829d31',
107
- controller: ControllerType.Repeat,
108
103
  repeat: {
109
104
  options: { name: 'fawfed', title: 'Simple question responses' },
110
105
  schema: { min: 1, max: 3 }
111
- }
112
- }
113
-
114
- return {
115
- ...repeaterPage,
116
- ...partialRepeaterPage
106
+ },
107
+ ...partialRepeaterPage,
108
+ controller: ControllerType.Repeat
117
109
  }
118
110
  }
@@ -2,7 +2,11 @@ import Joi, { type LanguageMessages } from 'joi'
2
2
  import { v4 as uuidV4 } from 'uuid'
3
3
 
4
4
  import { ComponentType } from '~/src/components/enums.js'
5
- import { type ComponentDef } from '~/src/components/types.js'
5
+ import {
6
+ type ComponentDef,
7
+ type ContentComponentsDef,
8
+ type FileUploadFieldComponent
9
+ } from '~/src/components/types.js'
6
10
  import {
7
11
  type ConditionData,
8
12
  type ConditionDataV2,
@@ -34,6 +38,7 @@ import {
34
38
  type RepeatSchema,
35
39
  type Section
36
40
  } from '~/src/form/form-definition/types.js'
41
+ import { ControllerType } from '~/src/pages/enums.js'
37
42
  import { hasComponents } from '~/src/pages/helpers.js'
38
43
 
39
44
  const idSchemaOptional = Joi.string().uuid()
@@ -449,6 +454,26 @@ export const componentSchemaV2 = componentSchema
449
454
  })
450
455
  .description('Component schema for V2 forms')
451
456
 
457
+ export const fileUploadComponentSchema = componentSchemaV2.keys({
458
+ type: Joi.string<ComponentType.FileUploadField>()
459
+ .trim()
460
+ .valid(ComponentType.FileUploadField)
461
+ .required()
462
+ .description('Component that can only be a FileUploadField')
463
+ })
464
+
465
+ export const contentComponentSchema = componentSchemaV2.keys({
466
+ type: Joi.string<ComponentType>()
467
+ .trim()
468
+ .valid(ComponentType.Details)
469
+ .valid(ComponentType.Html)
470
+ .valid(ComponentType.Markdown)
471
+ .valid(ComponentType.InsetText)
472
+ .valid(ComponentType.List)
473
+ .required()
474
+ .description('Content only component type (Details, Html, Markdown, etc.)')
475
+ })
476
+
452
477
  const nextSchema = Joi.object<Link>()
453
478
  .description('Navigation link defining where to go after completing a page')
454
479
  .keys({
@@ -549,6 +574,19 @@ const eventsSchema = Joi.object<Events>()
549
574
  .description('Event handler triggered when the page data is saved')
550
575
  })
551
576
 
577
+ export const pageUploadComponentsSchema = Joi.array<
578
+ FileUploadFieldComponent | ContentComponentsDef
579
+ >()
580
+ .items(
581
+ fileUploadComponentSchema.required(),
582
+ contentComponentSchema.optional()
583
+ )
584
+ .unique('name')
585
+ .unique('id')
586
+ .min(1)
587
+ .max(2)
588
+ .description('Components allowed on Page Upload schema')
589
+
552
590
  /**
553
591
  * `/status` is a special route for providing a user's application status.
554
592
  * It should not be configured via the designer.
@@ -619,11 +657,19 @@ export const pageSchemaV2 = pageSchema
619
657
  .description(
620
658
  'Page title displayed at the top of the page (with support for empty titles in V2)'
621
659
  ),
622
- components: Joi.array<ComponentDef>()
623
- .items(componentSchemaV2)
624
- .unique('name')
625
- .unique('id')
626
- .description('Components schema for V2 forms'),
660
+ components: Joi.when('controller', {
661
+ switch: [
662
+ {
663
+ is: Joi.string().trim().valid(ControllerType.FileUpload).required(),
664
+ then: pageUploadComponentsSchema
665
+ }
666
+ ],
667
+ otherwise: Joi.array<ComponentDef>()
668
+ .items(componentSchemaV2)
669
+ .unique('name')
670
+ .unique('id')
671
+ .description('Components schema for V2 forms')
672
+ }),
627
673
  condition: Joi.string()
628
674
  .trim()
629
675
  .valid(conditionIdRef)