@defra/forms-engine-plugin 2.1.7 → 2.1.9

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.
Files changed (50) hide show
  1. package/.server/server/plugins/engine/components/CheckboxesField.d.ts +2 -0
  2. package/.server/server/plugins/engine/components/CheckboxesField.js +13 -7
  3. package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
  4. package/.server/server/plugins/engine/components/DatePartsField.d.ts +2 -0
  5. package/.server/server/plugins/engine/components/DatePartsField.js +11 -5
  6. package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
  7. package/.server/server/plugins/engine/components/FileUploadField.d.ts +2 -0
  8. package/.server/server/plugins/engine/components/FileUploadField.js +9 -3
  9. package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
  10. package/.server/server/plugins/engine/components/FormComponent.d.ts +2 -0
  11. package/.server/server/plugins/engine/components/FormComponent.js +11 -4
  12. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  13. package/.server/server/plugins/engine/components/ListFormComponent.d.ts +1 -0
  14. package/.server/server/plugins/engine/components/ListFormComponent.js +6 -4
  15. package/.server/server/plugins/engine/components/ListFormComponent.js.map +1 -1
  16. package/.server/server/plugins/engine/components/MonthYearField.d.ts +2 -0
  17. package/.server/server/plugins/engine/components/MonthYearField.js +9 -3
  18. package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
  19. package/.server/server/plugins/engine/components/UkAddressField.d.ts +3 -1
  20. package/.server/server/plugins/engine/components/UkAddressField.js +12 -5
  21. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  22. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +27 -12
  23. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
  24. package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +1 -4
  25. package/.server/server/plugins/engine/outputFormatters/machine/v2.js +10 -9
  26. package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
  27. package/.server/server/plugins/engine/types/index.d.ts +0 -1
  28. package/.server/server/plugins/engine/types/index.js.map +1 -1
  29. package/.server/server/plugins/engine/types/schema.d.ts +2 -1
  30. package/.server/server/plugins/engine/types/schema.js +13 -2
  31. package/.server/server/plugins/engine/types/schema.js.map +1 -1
  32. package/.server/server/plugins/engine/types.d.ts +24 -3
  33. package/.server/server/plugins/engine/types.js +4 -0
  34. package/.server/server/plugins/engine/types.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/server/plugins/engine/components/CheckboxesField.ts +18 -7
  37. package/src/server/plugins/engine/components/DatePartsField.ts +17 -6
  38. package/src/server/plugins/engine/components/FileUploadField.ts +14 -3
  39. package/src/server/plugins/engine/components/FormComponent.ts +17 -5
  40. package/src/server/plugins/engine/components/ListFormComponent.ts +10 -3
  41. package/src/server/plugins/engine/components/MonthYearField.ts +14 -4
  42. package/src/server/plugins/engine/components/UkAddressField.ts +16 -6
  43. package/src/server/plugins/engine/outputFormatters/adapter/v1.test.ts +192 -2
  44. package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +38 -12
  45. package/src/server/plugins/engine/outputFormatters/machine/v2.test.ts +2 -0
  46. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +18 -28
  47. package/src/server/plugins/engine/types/index.ts +0 -2
  48. package/src/server/plugins/engine/types/schema.test.ts +68 -60
  49. package/src/server/plugins/engine/types/schema.ts +23 -2
  50. package/src/server/plugins/engine/types.ts +33 -3
@@ -65,12 +65,9 @@ export class CheckboxesField extends SelectionControlField {
65
65
  return this.isValue(value) ? value : undefined
66
66
  }
67
67
 
68
- getDisplayStringFromState(state: FormSubmissionState) {
68
+ getDisplayStringFromFormValue(selected: (string | number | boolean)[]) {
69
69
  const { items } = this
70
70
 
71
- // Selected checkbox values
72
- const selected = this.getFormValueFromState(state) ?? []
73
-
74
71
  // Map selected values to text
75
72
  return items
76
73
  .filter((item) => selected.includes(item.value))
@@ -78,9 +75,9 @@ export class CheckboxesField extends SelectionControlField {
78
75
  .join(', ')
79
76
  }
80
77
 
81
- getContextValueFromState(state: FormSubmissionState) {
82
- const values = this.getFormValueFromState(state)
83
-
78
+ getContextValueFromFormValue(
79
+ values: (string | number | boolean)[] | undefined
80
+ ): (string | number | boolean)[] {
84
81
  /**
85
82
  * For evaluation context purposes, optional {@link CheckboxesField}
86
83
  * with an undefined value (i.e. nothing selected) should default to [].
@@ -95,6 +92,20 @@ export class CheckboxesField extends SelectionControlField {
95
92
  return values ?? []
96
93
  }
97
94
 
95
+ getDisplayStringFromState(state: FormSubmissionState) {
96
+ // Selected checkbox values
97
+ const selected = this.getFormValueFromState(state) ?? []
98
+
99
+ // Map selected values to text
100
+ return this.getDisplayStringFromFormValue(selected)
101
+ }
102
+
103
+ getContextValueFromState(state: FormSubmissionState) {
104
+ const values = this.getFormValueFromState(state)
105
+
106
+ return this.getContextValueFromFormValue(values)
107
+ }
108
+
98
109
  isValue(value?: FormStateValue | FormState): value is Item['value'][] {
99
110
  if (!Array.isArray(value)) {
100
111
  return false
@@ -109,19 +109,24 @@ export class DatePartsField extends FormComponent {
109
109
  return this.isState(value) ? value : undefined
110
110
  }
111
111
 
112
- getDisplayStringFromState(state: FormSubmissionState) {
113
- const value = this.getFormValueFromState(state)
114
-
115
- if (!value) {
112
+ getDisplayStringFromFormValue(formValue: DatePartsState | undefined) {
113
+ if (!formValue) {
116
114
  return ''
117
115
  }
118
116
 
119
- return format(`${value.year}-${value.month}-${value.day}`, 'd MMMM yyyy')
117
+ return format(
118
+ `${formValue.year}-${formValue.month}-${formValue.day}`,
119
+ 'd MMMM yyyy'
120
+ )
120
121
  }
121
122
 
122
- getContextValueFromState(state: FormSubmissionState) {
123
+ getDisplayStringFromState(state: FormSubmissionState) {
123
124
  const value = this.getFormValueFromState(state)
124
125
 
126
+ return this.getDisplayStringFromFormValue(value)
127
+ }
128
+
129
+ getContextValueFromFormValue(value: DatePartsState | undefined) {
125
130
  if (
126
131
  !value ||
127
132
  !isValid(
@@ -139,6 +144,12 @@ export class DatePartsField extends FormComponent {
139
144
  return format(`${value.year}-${value.month}-${value.day}`, 'yyyy-MM-dd')
140
145
  }
141
146
 
147
+ getContextValueFromState(state: FormSubmissionState) {
148
+ const value = this.getFormValueFromState(state)
149
+
150
+ return this.getContextValueFromFormValue(value)
151
+ }
152
+
142
153
  getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {
143
154
  const { collection, name } = this
144
155
 
@@ -149,8 +149,7 @@ export class FileUploadField extends FormComponent {
149
149
  return this.isValue(value) ? value : undefined
150
150
  }
151
151
 
152
- getDisplayStringFromState(state: FormSubmissionState) {
153
- const files = this.getFormValueFromState(state)
152
+ getDisplayStringFromFormValue(files: FileState[] | undefined): string {
154
153
  if (!files?.length) {
155
154
  return ''
156
155
  }
@@ -159,11 +158,23 @@ export class FileUploadField extends FormComponent {
159
158
  return `Uploaded ${files.length} ${unit}`
160
159
  }
161
160
 
162
- getContextValueFromState(state: FormSubmissionState) {
161
+ getDisplayStringFromState(state: FormSubmissionState) {
163
162
  const files = this.getFormValueFromState(state)
163
+
164
+ return this.getDisplayStringFromFormValue(files)
165
+ }
166
+
167
+ getContextValueFromFormValue(
168
+ files: UploadState | undefined
169
+ ): string[] | null {
164
170
  return files?.map(({ status }) => status.form.file.fileId) ?? null
165
171
  }
166
172
 
173
+ getContextValueFromState(state: FormSubmissionState) {
174
+ const files = this.getFormValueFromState(state)
175
+ return this.getContextValueFromFormValue(files)
176
+ }
177
+
167
178
  getViewModel(
168
179
  payload: FormPayload,
169
180
  errors?: FormSubmissionError[],
@@ -157,17 +157,21 @@ export class FormComponent extends ComponentBase {
157
157
  }
158
158
  }
159
159
 
160
- getDisplayStringFromState(state: FormSubmissionState): string {
161
- const value = this.getFormValueFromState(state)
160
+ getDisplayStringFromFormValue(value: FormValue | FormPayload): string {
161
+ // Map selected values to text
162
162
  // eslint-disable-next-line @typescript-eslint/no-base-to-string
163
163
  return this.isValue(value) ? value.toString() : ''
164
164
  }
165
165
 
166
- getContextValueFromState(
167
- state: FormSubmissionState
168
- ): Item['value'] | Item['value'][] | null {
166
+ getDisplayStringFromState(state: FormSubmissionState): string {
169
167
  const value = this.getFormValueFromState(state)
168
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
169
+ return this.getDisplayStringFromFormValue(value)
170
+ }
170
171
 
172
+ getContextValueFromFormValue(
173
+ value: FormValue | FormPayload
174
+ ): Item['value'] | Item['value'][] | null {
171
175
  // Filter object field values
172
176
  if (this.isState(value)) {
173
177
  const values = Object.values(value).filter(isFormValue)
@@ -182,6 +186,14 @@ export class FormComponent extends ComponentBase {
182
186
  return this.isValue(value) ? value : null
183
187
  }
184
188
 
189
+ getContextValueFromState(
190
+ state: FormSubmissionState
191
+ ): Item['value'] | Item['value'][] | null {
192
+ const value = this.getFormValueFromState(state)
193
+
194
+ return this.getContextValueFromFormValue(value)
195
+ }
196
+
185
197
  isValue(
186
198
  value?: FormStateValue | FormState
187
199
  ): value is NonNullable<FormStateValue> {
@@ -99,11 +99,11 @@ export class ListFormComponent extends FormComponent {
99
99
  return selected.at(0)?.value
100
100
  }
101
101
 
102
- getDisplayStringFromState(state: FormSubmissionState) {
102
+ getDisplayStringFromFormValue(
103
+ value: string | number | boolean | Item['value'][] | undefined
104
+ ): string {
103
105
  const { items } = this
104
106
 
105
- // Allow for array values via subclass
106
- const value = this.getFormValueFromState(state)
107
107
  const values = [value ?? []].flat()
108
108
 
109
109
  return items
@@ -112,6 +112,13 @@ export class ListFormComponent extends FormComponent {
112
112
  .join(', ')
113
113
  }
114
114
 
115
+ getDisplayStringFromState(state: FormSubmissionState) {
116
+ // Allow for array values via subclass
117
+ const value = this.getFormValueFromState(state)
118
+
119
+ return this.getDisplayStringFromFormValue(value)
120
+ }
121
+
115
122
  getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {
116
123
  const { items: listItems } = this
117
124
 
@@ -103,9 +103,7 @@ export class MonthYearField extends FormComponent {
103
103
  return MonthYearField.isMonthYear(value) ? value : undefined
104
104
  }
105
105
 
106
- getDisplayStringFromState(state: FormSubmissionState) {
107
- const value = this.getFormValueFromState(state)
108
-
106
+ getDisplayStringFromFormValue(value: MonthYearState | undefined): string {
109
107
  if (!value) {
110
108
  return ''
111
109
  }
@@ -117,9 +115,15 @@ export class MonthYearField extends FormComponent {
117
115
  return `${monthString} ${value.year}`
118
116
  }
119
117
 
120
- getContextValueFromState(state: FormSubmissionState) {
118
+ getDisplayStringFromState(state: FormSubmissionState) {
121
119
  const value = this.getFormValueFromState(state)
122
120
 
121
+ return this.getDisplayStringFromFormValue(value)
122
+ }
123
+
124
+ getContextValueFromFormValue(
125
+ value: MonthYearState | undefined
126
+ ): string | null {
123
127
  if (
124
128
  !value ||
125
129
  !isValid(
@@ -137,6 +141,12 @@ export class MonthYearField extends FormComponent {
137
141
  return format(`${value.year}-${value.month}-01`, 'yyyy-MM')
138
142
  }
139
143
 
144
+ getContextValueFromState(state: FormSubmissionState) {
145
+ const value = this.getFormValueFromState(state)
146
+
147
+ return this.getContextValueFromFormValue(value)
148
+ }
149
+
140
150
  getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {
141
151
  const { collection, name } = this
142
152
 
@@ -110,18 +110,28 @@ export class UkAddressField extends FormComponent {
110
110
  return this.isState(value) ? value : undefined
111
111
  }
112
112
 
113
- getDisplayStringFromState(state: FormSubmissionState) {
114
- return this.getContextValueFromState(state)?.join(', ') ?? ''
113
+ getContextValueFromFormValue(value: UkAddressState | undefined) {
114
+ if (!value) {
115
+ return null
116
+ }
117
+
118
+ return Object.values(value).filter(Boolean)
115
119
  }
116
120
 
117
121
  getContextValueFromState(state: FormSubmissionState) {
118
122
  const value = this.getFormValueFromState(state)
119
123
 
120
- if (!value) {
121
- return null
122
- }
124
+ return this.getContextValueFromFormValue(value)
125
+ }
123
126
 
124
- return Object.values(value).filter(Boolean)
127
+ getDisplayStringFromFormValue(value: UkAddressState | undefined): string {
128
+ return this.getContextValueFromFormValue(value)?.join(', ') ?? ''
129
+ }
130
+
131
+ getDisplayStringFromState(state: FormSubmissionState) {
132
+ const value = this.getFormValueFromState(state)
133
+
134
+ return this.getDisplayStringFromFormValue(value)
125
135
  }
126
136
 
127
137
  /**
@@ -1,4 +1,7 @@
1
- import { type FormMetadata } from '@defra/forms-model'
1
+ import {
2
+ type FormMetadata,
3
+ type SubmitResponsePayload
4
+ } from '@defra/forms-model'
2
5
 
3
6
  import { FileUploadField } from '~/src/server/plugins/engine/components/FileUploadField.js'
4
7
  import { type Field } from '~/src/server/plugins/engine/components/helpers/components.js'
@@ -26,7 +29,7 @@ const submitResponse = {
26
29
  files: {
27
30
  main: '00000000-0000-0000-0000-000000000000',
28
31
  repeaters: {
29
- pizza: '11111111-1111-1111-1111-111111111111'
32
+ exampleRepeat: '11111111-1111-1111-1111-111111111111'
30
33
  }
31
34
  }
32
35
  }
@@ -258,15 +261,26 @@ describe('Adapter v1 formatter', () => {
258
261
  exampleFile1: [
259
262
  {
260
263
  fileId: '123-456-789',
264
+ fileName: 'foobar.txt',
261
265
  userDownloadLink: 'https://forms-designer/file-download/123-456-789'
262
266
  },
263
267
  {
264
268
  fileId: '456-789-123',
269
+ fileName: 'bazbuzz.txt',
265
270
  userDownloadLink: 'https://forms-designer/file-download/456-789-123'
266
271
  }
267
272
  ]
268
273
  }
269
274
  })
275
+
276
+ expect(parsedBody.result).toEqual({
277
+ files: {
278
+ main: '00000000-0000-0000-0000-000000000000',
279
+ repeaters: {
280
+ exampleRepeat: '11111111-1111-1111-1111-111111111111'
281
+ }
282
+ }
283
+ })
270
284
  })
271
285
 
272
286
  it('should handle preview form status correctly', () => {
@@ -385,6 +399,14 @@ describe('Adapter v1 formatter', () => {
385
399
  expect(parsedBody.data.main).toEqual({})
386
400
  expect(parsedBody.data.repeaters).toEqual({})
387
401
  expect(parsedBody.data.files).toEqual({})
402
+ expect(parsedBody.result).toEqual({
403
+ files: {
404
+ main: '00000000-0000-0000-0000-000000000000',
405
+ repeaters: {
406
+ exampleRepeat: '11111111-1111-1111-1111-111111111111'
407
+ }
408
+ }
409
+ })
388
410
  })
389
411
 
390
412
  it('should handle different form statuses', () => {
@@ -503,4 +525,172 @@ describe('Adapter v1 formatter', () => {
503
525
  expect(parsedBody.meta.formSlug).toBe('')
504
526
  expect(parsedBody.meta.notificationEmail).toBe('only-email@example.com')
505
527
  })
528
+
529
+ it('should include CSV file IDs from submitResponse.result.files', () => {
530
+ const formStatus = {
531
+ isPreview: false,
532
+ state: FormStatus.Live
533
+ }
534
+
535
+ const body = format(context, items, model, submitResponse, formStatus)
536
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
537
+
538
+ expect(parsedBody.data.main).toEqual({
539
+ exampleField: 'hello world',
540
+ exampleField2: 'hello world'
541
+ })
542
+
543
+ expect(parsedBody.data.repeaters.exampleRepeat).toEqual([
544
+ {
545
+ subItem1_1: 'hello world',
546
+ subItem1_2: 'hello world'
547
+ },
548
+ {
549
+ subItem2_1: 'hello world'
550
+ }
551
+ ])
552
+
553
+ expect(parsedBody.data.files.exampleFile1).toEqual([
554
+ {
555
+ fileId: '123-456-789',
556
+ fileName: 'foobar.txt',
557
+ userDownloadLink: 'https://forms-designer/file-download/123-456-789'
558
+ },
559
+ {
560
+ fileId: '456-789-123',
561
+ fileName: 'bazbuzz.txt',
562
+ userDownloadLink: 'https://forms-designer/file-download/456-789-123'
563
+ }
564
+ ])
565
+
566
+ expect(parsedBody.result).toEqual({
567
+ files: {
568
+ main: '00000000-0000-0000-0000-000000000000',
569
+ repeaters: {
570
+ exampleRepeat: '11111111-1111-1111-1111-111111111111'
571
+ }
572
+ }
573
+ })
574
+ })
575
+
576
+ it('should handle submitResponse without CSV file IDs gracefully', () => {
577
+ const submitResponseWithoutFiles = {
578
+ message: 'Submit completed',
579
+ result: {
580
+ files: {
581
+ main: '',
582
+ repeaters: {}
583
+ }
584
+ }
585
+ }
586
+
587
+ const formStatus = {
588
+ isPreview: false,
589
+ state: FormStatus.Live
590
+ }
591
+
592
+ const body = format(
593
+ context,
594
+ items,
595
+ model,
596
+ submitResponseWithoutFiles,
597
+ formStatus
598
+ )
599
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
600
+
601
+ expect(parsedBody.data.main).toEqual({
602
+ exampleField: 'hello world',
603
+ exampleField2: 'hello world'
604
+ })
605
+
606
+ expect(parsedBody.data.repeaters.exampleRepeat).toEqual([
607
+ {
608
+ subItem1_1: 'hello world',
609
+ subItem1_2: 'hello world'
610
+ },
611
+ {
612
+ subItem2_1: 'hello world'
613
+ }
614
+ ])
615
+ })
616
+
617
+ it('should handle submitResponse with only main CSV file ID', () => {
618
+ const submitResponseWithMainOnly = {
619
+ message: 'Submit completed',
620
+ result: {
621
+ files: {
622
+ main: 'main-only-file-id',
623
+ repeaters: {}
624
+ }
625
+ }
626
+ }
627
+
628
+ const formStatus = {
629
+ isPreview: false,
630
+ state: FormStatus.Live
631
+ }
632
+
633
+ const body = format(
634
+ context,
635
+ items,
636
+ model,
637
+ submitResponseWithMainOnly,
638
+ formStatus
639
+ )
640
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
641
+
642
+ expect(parsedBody.data.main).toEqual({
643
+ exampleField: 'hello world',
644
+ exampleField2: 'hello world'
645
+ })
646
+
647
+ expect(parsedBody.data.repeaters.exampleRepeat).toEqual([
648
+ {
649
+ subItem1_1: 'hello world',
650
+ subItem1_2: 'hello world'
651
+ },
652
+ {
653
+ subItem2_1: 'hello world'
654
+ }
655
+ ])
656
+
657
+ expect(parsedBody.result).toEqual({
658
+ files: {
659
+ main: 'main-only-file-id',
660
+ repeaters: {}
661
+ }
662
+ })
663
+ })
664
+
665
+ it('should handle submitResponse with missing repeaters property', () => {
666
+ const submitResponseWithoutRepeaters = {
667
+ message: 'Submit completed',
668
+ result: {
669
+ files: {
670
+ main: 'main-only-file-id'
671
+ }
672
+ }
673
+ }
674
+
675
+ const formStatus = {
676
+ isPreview: false,
677
+ state: FormStatus.Live
678
+ }
679
+
680
+ const body = format(
681
+ context,
682
+ items,
683
+ model,
684
+ submitResponseWithoutRepeaters as unknown as SubmitResponsePayload,
685
+ formStatus
686
+ )
687
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
688
+
689
+ expect(parsedBody.result).toEqual({
690
+ files: {
691
+ main: 'main-only-file-id',
692
+ repeaters: {}
693
+ }
694
+ })
695
+ })
506
696
  })
@@ -10,7 +10,9 @@ import { format as machineV2 } from '~/src/server/plugins/engine/outputFormatter
10
10
  import { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'
11
11
  import {
12
12
  type FormAdapterSubmissionMessageData,
13
+ type FormAdapterSubmissionMessageMeta,
13
14
  type FormAdapterSubmissionMessagePayload,
15
+ type FormAdapterSubmissionMessageResult,
14
16
  type FormContext
15
17
  } from '~/src/server/plugins/engine/types.js'
16
18
  import { FormStatus } from '~/src/server/routes/types.js'
@@ -34,20 +36,44 @@ export function format(
34
36
  data: FormAdapterSubmissionMessageData
35
37
  }
36
38
 
39
+ const csvFiles = extractCsvFiles(submitResponse)
40
+
41
+ const transformedData = v2DataParsed.data
42
+
43
+ const meta: FormAdapterSubmissionMessageMeta = {
44
+ schemaVersion: FormAdapterSubmissionSchemaVersion.V1,
45
+ timestamp: new Date(),
46
+ referenceNumber: context.referenceNumber,
47
+ formName: model.name,
48
+ formId: formMetadata?.id ?? '',
49
+ formSlug: formMetadata?.slug ?? '',
50
+ status: formStatus.isPreview ? FormStatus.Draft : FormStatus.Live,
51
+ isPreview: formStatus.isPreview,
52
+ notificationEmail: formMetadata?.notificationEmail ?? ''
53
+ }
54
+ const data: FormAdapterSubmissionMessageData = transformedData
55
+
56
+ const result: FormAdapterSubmissionMessageResult = {
57
+ files: csvFiles
58
+ }
59
+
37
60
  const payload: FormAdapterSubmissionMessagePayload = {
38
- meta: {
39
- schemaVersion: FormAdapterSubmissionSchemaVersion.V1,
40
- timestamp: new Date(),
41
- referenceNumber: context.referenceNumber,
42
- formName: model.name,
43
- formId: formMetadata?.id ?? '',
44
- formSlug: formMetadata?.slug ?? '',
45
- status: formStatus.isPreview ? FormStatus.Draft : FormStatus.Live,
46
- isPreview: formStatus.isPreview,
47
- notificationEmail: formMetadata?.notificationEmail ?? ''
48
- },
49
- data: v2DataParsed.data
61
+ meta,
62
+ data,
63
+ result
50
64
  }
51
65
 
52
66
  return JSON.stringify(payload)
53
67
  }
68
+
69
+ function extractCsvFiles(
70
+ submitResponse: SubmitResponsePayload
71
+ ): FormAdapterSubmissionMessageResult['files'] {
72
+ const result =
73
+ submitResponse.result as Partial<FormAdapterSubmissionMessageResult>
74
+
75
+ return {
76
+ main: result.files?.main ?? '',
77
+ repeaters: result.files?.repeaters ?? {}
78
+ }
79
+ }
@@ -249,10 +249,12 @@ describe('getPersonalisation', () => {
249
249
  exampleFile1: [
250
250
  {
251
251
  fileId: '123-456-789',
252
+ fileName: 'foobar.txt',
252
253
  userDownloadLink: 'https://forms-designer/file-download/123-456-789'
253
254
  },
254
255
  {
255
256
  fileId: '456-789-123',
257
+ fileName: 'bazbuzz.txt',
256
258
  userDownloadLink: 'https://forms-designer/file-download/456-789-123'
257
259
  }
258
260
  ]
@@ -1,12 +1,7 @@
1
1
  import { type SubmitResponsePayload } from '@defra/forms-model'
2
2
 
3
3
  import { config } from '~/src/config/index.js'
4
- import { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js'
5
4
  import { FileUploadField } from '~/src/server/plugins/engine/components/index.js'
6
- import {
7
- type DatePartsState,
8
- type MonthYearState
9
- } from '~/src/server/plugins/engine/components/types.js'
10
5
  import { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'
11
6
  import { type FormModel } from '~/src/server/plugins/engine/models/index.js'
12
7
  import {
@@ -15,9 +10,10 @@ import {
15
10
  type DetailItemRepeat
16
11
  } from '~/src/server/plugins/engine/models/types.js'
17
12
  import {
13
+ type FileUploadFieldDetailitem,
14
+ type FormAdapterFile,
18
15
  type FormContext,
19
- type FormPayload,
20
- type FormValue
16
+ type RichFormValue
21
17
  } from '~/src/server/plugins/engine/types.js'
22
18
 
23
19
  const designerUrl = config.get('designerUrl')
@@ -69,7 +65,8 @@ export function format(
69
65
  * fileComponentName: [
70
66
  * {
71
67
  * fileId: '123-456-789',
72
- * link: 'https://forms-designer/file-download/123-456-789'
68
+ * fileName: 'example.pdf',
69
+ * userDownloadLink: 'https://forms-designer/file-download/123-456-789'
73
70
  * }
74
71
  * ]
75
72
  * }
@@ -79,7 +76,10 @@ function categoriseData(items: DetailItem[]) {
79
76
  const output: {
80
77
  main: Record<string, RichFormValue>
81
78
  repeaters: Record<string, Record<string, RichFormValue>[]>
82
- files: Record<string, Record<string, string>[]>
79
+ files: Record<
80
+ string,
81
+ { fileId: string; fileName: string; userDownloadLink: string }[]
82
+ >
83
83
  } = { main: {}, repeaters: {}, files: {} }
84
84
 
85
85
  items.forEach((item) => {
@@ -126,13 +126,17 @@ function extractRepeaters(item: DetailItemRepeat) {
126
126
  * @param item - the file upload item in the form
127
127
  * @returns the file upload data
128
128
  */
129
- function extractFileUploads(item: FileUploadFieldDetailitem) {
130
- const fileUploadState = item.field.getContextValueFromState(item.state) ?? []
129
+ function extractFileUploads(
130
+ item: FileUploadFieldDetailitem
131
+ ): FormAdapterFile[] {
132
+ const fileUploadState = item.field.getFormValueFromState(item.state) ?? []
131
133
 
132
- return fileUploadState.map((fileId) => {
134
+ return fileUploadState.map((fileState) => {
135
+ const { file } = fileState.status.form
133
136
  return {
134
- fileId,
135
- userDownloadLink: `${designerUrl}/file-download/${fileId}`
137
+ fileId: file.fileId,
138
+ fileName: file.filename,
139
+ userDownloadLink: `${designerUrl}/file-download/${file.fileId}`
136
140
  }
137
141
  })
138
142
  }
@@ -142,17 +146,3 @@ function isFileUploadFieldItem(
142
146
  ): item is FileUploadFieldDetailitem {
143
147
  return item.field instanceof FileUploadField
144
148
  }
145
-
146
- /**
147
- * A detail item specifically for files
148
- */
149
- type FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {
150
- field: FileUploadField
151
- }
152
-
153
- export type RichFormValue =
154
- | FormValue
155
- | FormPayload
156
- | DatePartsState
157
- | MonthYearState
158
- | UkAddressState
@@ -87,7 +87,5 @@ export type {
87
87
  Services
88
88
  } from '~/src/server/types.js'
89
89
 
90
- export type { RichFormValue } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'
91
-
92
90
  export * from '~/src/server/plugins/engine/types/schema.js'
93
91
  export { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'