@defra/forms-engine-plugin 5.0.0-alpha.3 → 5.0.0-alpha.6
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/.public/javascripts/application.min.js +1 -1
- package/.public/javascripts/application.min.js.map +1 -1
- package/.public/javascripts/shared.min.js +1 -1
- package/.public/javascripts/shared.min.js.map +1 -1
- package/.server/client/javascripts/file-upload.js +5 -3
- package/.server/client/javascripts/file-upload.js.map +1 -1
- package/.server/client/javascripts/geospatial-map.js +31 -26
- package/.server/client/javascripts/geospatial-map.js.map +1 -1
- package/.server/client/javascripts/location-map.js +9 -1
- package/.server/client/javascripts/location-map.js.map +1 -1
- package/.server/client/javascripts/sssi-dataset.d.ts +18 -20
- package/.server/client/javascripts/sssi-dataset.js +37 -40
- package/.server/client/javascripts/sssi-dataset.js.map +1 -1
- package/.server/server/constants.d.ts +1 -0
- package/.server/server/constants.js +1 -0
- package/.server/server/constants.js.map +1 -1
- package/.server/server/plugins/engine/components/AutocompleteField.d.ts +1 -0
- package/.server/server/plugins/engine/components/ComponentBase.d.ts +1 -0
- package/.server/server/plugins/engine/components/ComponentBase.js +2 -0
- package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
- package/.server/server/plugins/engine/components/ComponentCollection.js +2 -1
- package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
- package/.server/server/plugins/engine/components/DatePartsField.d.ts +1 -0
- package/.server/server/plugins/engine/components/DeclarationField.d.ts +1 -0
- package/.server/server/plugins/engine/components/DeclarationField.js +1 -1
- package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
- package/.server/server/plugins/engine/components/Details.d.ts +1 -0
- package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +2 -0
- package/.server/server/plugins/engine/components/EmailAddressField.d.ts +1 -0
- package/.server/server/plugins/engine/components/FileUploadField.js +2 -2
- package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
- package/.server/server/plugins/engine/components/FormComponent.d.ts +1 -0
- package/.server/server/plugins/engine/components/FormComponent.js +2 -2
- package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
- package/.server/server/plugins/engine/components/GeospatialField.d.ts +1 -0
- package/.server/server/plugins/engine/components/Html.d.ts +1 -0
- package/.server/server/plugins/engine/components/InsetText.d.ts +1 -0
- package/.server/server/plugins/engine/components/LatLongField.d.ts +2 -0
- package/.server/server/plugins/engine/components/List.d.ts +1 -0
- package/.server/server/plugins/engine/components/ListFormComponent.d.ts +1 -0
- package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +2 -0
- package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +2 -0
- package/.server/server/plugins/engine/components/Markdown.d.ts +1 -0
- package/.server/server/plugins/engine/components/Markdown.js +1 -1
- package/.server/server/plugins/engine/components/Markdown.js.map +1 -1
- package/.server/server/plugins/engine/components/MonthYearField.d.ts +1 -0
- package/.server/server/plugins/engine/components/MultilineTextField.d.ts +1 -0
- package/.server/server/plugins/engine/components/NotificationBanner.d.ts +1 -0
- package/.server/server/plugins/engine/components/NumberField.d.ts +1 -0
- package/.server/server/plugins/engine/components/PaymentField.d.ts +1 -0
- package/.server/server/plugins/engine/components/SelectField.d.ts +1 -0
- package/.server/server/plugins/engine/components/SelectionControlField.d.ts +1 -0
- package/.server/server/plugins/engine/components/TelephoneNumberField.d.ts +1 -0
- package/.server/server/plugins/engine/components/UkAddressField.d.ts +1 -0
- package/.server/server/plugins/engine/components/types.d.ts +1 -0
- package/.server/server/plugins/engine/components/types.js.map +1 -1
- package/.server/server/plugins/engine/i18n/translations/cy.json +37 -1
- package/.server/server/plugins/engine/i18n/translations/en-GB.json +9 -1
- package/.server/server/plugins/engine/i18n/types.d.ts +1 -0
- package/.server/server/plugins/engine/i18n/types.js.map +1 -1
- package/.server/server/plugins/engine/models/SummaryViewModel.js +7 -3
- package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +3 -5
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +20 -7
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +3 -4
- package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +5 -2
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
- package/.server/server/plugins/engine/services/notifyService.d.ts +1 -1
- package/.server/server/plugins/engine/services/notifyService.js +1 -1
- package/.server/server/plugins/engine/services/notifyService.js.map +1 -1
- package/.server/server/plugins/engine/views/components/fileuploadfield.html +1 -1
- package/.server/server/types.d.ts +1 -1
- package/.server/server/types.js.map +1 -1
- package/package.json +2 -2
- package/src/client/javascripts/file-upload.js +10 -3
- package/src/client/javascripts/geospatial-map.js +32 -30
- package/src/client/javascripts/location-map.js +7 -1
- package/src/client/javascripts/sssi-dataset.js +39 -42
- package/src/server/constants.js +1 -0
- package/src/server/plugins/engine/components/ComponentBase.ts +2 -0
- package/src/server/plugins/engine/components/ComponentCollection.ts +4 -5
- package/src/server/plugins/engine/components/DeclarationField.ts +1 -2
- package/src/server/plugins/engine/components/FileUploadField.ts +2 -2
- package/src/server/plugins/engine/components/FormComponent.ts +2 -4
- package/src/server/plugins/engine/components/Markdown.ts +2 -3
- package/src/server/plugins/engine/components/types.ts +1 -0
- package/src/server/plugins/engine/i18n/translations/cy.json +37 -1
- package/src/server/plugins/engine/i18n/translations/en-GB.json +9 -1
- package/src/server/plugins/engine/i18n/types.ts +1 -0
- package/src/server/plugins/engine/models/SummaryViewModel.ts +4 -4
- package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +3 -6
- package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +16 -6
- package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +2 -2
- package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +7 -1
- package/src/server/plugins/engine/services/notifyService.ts +1 -0
- package/src/server/plugins/engine/views/components/fileuploadfield.html +1 -1
- package/src/server/types.ts +1 -0
|
@@ -60,6 +60,8 @@
|
|
|
60
60
|
"totalAmount": "Total amount",
|
|
61
61
|
"reference": "Reference",
|
|
62
62
|
"dateOfPayment": "Date of payment",
|
|
63
|
+
"fileUpload_one": "Uploaded [[count]] file",
|
|
64
|
+
"fileUpload_other": "Uploaded [[count]] files",
|
|
63
65
|
"submissionFailed": "There was a problem and your form was not submitted. Try submitting the form again",
|
|
64
66
|
"submissionFailedContactSuffix": " or you can [[contactUsLink]] and quote your reference number to arrange a refund",
|
|
65
67
|
"contactUsLinkText": "contact us (opens in new tab)",
|
|
@@ -89,7 +91,12 @@
|
|
|
89
91
|
|
|
90
92
|
"fileUpload": {
|
|
91
93
|
"upload": "Upload file",
|
|
92
|
-
"maxFilesReached": "You have reached the maximum number of files. Please remove a file to upload more."
|
|
94
|
+
"maxFilesReached": "You have reached the maximum number of files. Please remove a file to upload more.",
|
|
95
|
+
"remove": "Remove",
|
|
96
|
+
"removeFileTitle": "Are you sure you want to remove this file?",
|
|
97
|
+
"removeFileBody": "You cannot recover removed files.",
|
|
98
|
+
"removeFileButton": "Remove file",
|
|
99
|
+
"cancel": "Cancel"
|
|
93
100
|
},
|
|
94
101
|
|
|
95
102
|
"exit": {
|
|
@@ -262,6 +269,7 @@
|
|
|
262
269
|
},
|
|
263
270
|
|
|
264
271
|
"fileUploadField": {
|
|
272
|
+
"uploading": "Uploading…",
|
|
265
273
|
"uploaded": "Uploaded",
|
|
266
274
|
"uploadFailed": "There was a problem with your uploaded files. Re-upload them before submitting the form again.",
|
|
267
275
|
"uploadedFilesHeading": "Uploaded files",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../../../../src/server/plugins/engine/i18n/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Item,\n type Page,\n type Section\n} from '@defra/forms-model'\n\n/**\n * Structure of the `translations` block in a form definition.\n * Also used to derive the valid property keys for the typed tX functions.\n */\nexport type FormDefinitionTranslations = Record<\n string,\n {\n pages: Record<string, Partial<{ title: string; repeatTitle: string }>>\n // ComponentDef is a discriminated union; Pick across the full union is not feasible.\n // The four keys below are the complete set of translatable component properties.\n components: Record<\n string,\n Partial<{\n title: string\n hint: string\n content: string\n shortDescription: string\n paymentDescription: string\n }>\n >\n sections: Record<string, Partial<Pick<Section, 'title'>>>\n listItems: Record<string, Partial<Pick<Item, 'text' | 'hint'>>>\n form: Record<string, string>\n }\n>\n\ntype EntityTranslations = FormDefinitionTranslations[string]\n\n/**\n * Scoped translator returned by model.createTranslator(language).\n * t — plugin namespace (UI strings, buttons, errors, sub-field labels)\n * tForm — form namespace: form attributes, currently only form name\n * tPage — form namespace: page titles\n * tComponent — form namespace: component titles, hints, shortDescriptions\n * tSection — form namespace: section titles\n * tListItem — form namespace: list item text\n * language - current language\n */\nexport interface Translator {\n t: (key: string, opts?: Record<string, unknown>) => string\n tForm: (prop: string) => string\n tPage: (page: Page, prop: keyof EntityTranslations['pages'][string]) => string\n tComponent: (\n component: ComponentDef,\n prop: keyof EntityTranslations['components'][string]\n ) => string\n tSection: (\n section: Section,\n prop: keyof EntityTranslations['sections'][string]\n ) => string\n tListItem: (\n item: Item,\n prop: keyof EntityTranslations['listItems'][string]\n ) => string\n language: string\n}\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../../../../src/server/plugins/engine/i18n/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Item,\n type Page,\n type Section\n} from '@defra/forms-model'\n\n/**\n * Structure of the `translations` block in a form definition.\n * Also used to derive the valid property keys for the typed tX functions.\n */\nexport type FormDefinitionTranslations = Record<\n string,\n {\n pages: Record<string, Partial<{ title: string; repeatTitle: string }>>\n // ComponentDef is a discriminated union; Pick across the full union is not feasible.\n // The four keys below are the complete set of translatable component properties.\n components: Record<\n string,\n Partial<{\n title: string\n hint: string\n content: string\n shortDescription: string\n errorDescription: string\n paymentDescription: string\n }>\n >\n sections: Record<string, Partial<Pick<Section, 'title'>>>\n listItems: Record<string, Partial<Pick<Item, 'text' | 'hint'>>>\n form: Record<string, string>\n }\n>\n\ntype EntityTranslations = FormDefinitionTranslations[string]\n\n/**\n * Scoped translator returned by model.createTranslator(language).\n * t — plugin namespace (UI strings, buttons, errors, sub-field labels)\n * tForm — form namespace: form attributes, currently only form name\n * tPage — form namespace: page titles\n * tComponent — form namespace: component titles, hints, shortDescriptions\n * tSection — form namespace: section titles\n * tListItem — form namespace: list item text\n * language - current language\n */\nexport interface Translator {\n t: (key: string, opts?: Record<string, unknown>) => string\n tForm: (prop: string) => string\n tPage: (page: Page, prop: keyof EntityTranslations['pages'][string]) => string\n tComponent: (\n component: ComponentDef,\n prop: keyof EntityTranslations['components'][string]\n ) => string\n tSection: (\n section: Section,\n prop: keyof EntityTranslations['sections'][string]\n ) => string\n tListItem: (\n item: Item,\n prop: keyof EntityTranslations['listItems'][string]\n ) => string\n language: string\n}\n"],"mappings":"","ignoreList":[]}
|
|
@@ -164,12 +164,16 @@ function ItemRepeat(page, state, options, translator) {
|
|
|
164
164
|
repeat
|
|
165
165
|
} = page;
|
|
166
166
|
const {
|
|
167
|
-
name
|
|
168
|
-
title
|
|
167
|
+
name
|
|
169
168
|
} = repeat.options;
|
|
169
|
+
const {
|
|
170
|
+
t,
|
|
171
|
+
tPage
|
|
172
|
+
} = translator;
|
|
173
|
+
const title = tPage(page.pageDef, 'repeatTitle') || repeat.options.title;
|
|
170
174
|
const values = page.getListFromState(state);
|
|
171
175
|
const count = values.length;
|
|
172
|
-
const value = count === 0 ? '' :
|
|
176
|
+
const value = count === 0 ? '' : t('pages.repeater.pageTitle', {
|
|
173
177
|
count
|
|
174
178
|
});
|
|
175
179
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SummaryViewModel.js","names":["SchemaVersion","PaymentField","getAnswer","evaluateTemplate","getError","getPageHref","RepeatPageController","validationOptions","opts","SummaryViewModel","page","pageTitle","declaration","details","checkAnswers","context","name","backLink","feedbackLink","phaseTag","errors","serviceUrl","hasMissingNotificationEmail","components","allowSaveAndExit","paymentState","paymentDetails","t","_translator","paymentRequired","paymentPreAuthorized","constructor","request","translator","model","basePath","def","sections","isForceAccess","title","schema","V2","result","makeFilteredSchema","relevantPages","validate","relevantState","stripUnknown","error","map","summaryDetails","detail","rows","items","item","push","href","text","classes","visuallyHiddenText","label","key","value","html","actions","undefined","summaryList","state","forEach","section","sectionPages","filter","collection","path","ItemRepeat","getSummaryPath","field","fields","ItemField","length","sectionTitle","tSection","options","repeat","values","getListFromState","count","returnUrl","subItems","repeatState","fieldDef","id","type","shortDescription","rawLabel","tComponent","translatedLabel","rawTitle","translatedTitle","optional","required","getFirstError","format"],"sources":["../../../../../src/server/plugins/engine/models/SummaryViewModel.ts"],"sourcesContent":["import {\n SchemaVersion,\n type ComponentDef,\n type Section\n} from '@defra/forms-model'\n\nimport { PaymentField } from '~/src/server/plugins/engine/components/PaymentField.js'\nimport { type PaymentState } from '~/src/server/plugins/engine/components/PaymentField.types.js'\nimport {\n getAnswer,\n type Field\n} from '~/src/server/plugins/engine/components/helpers/components.js'\nimport {\n type BackLink,\n type ComponentViewModel\n} from '~/src/server/plugins/engine/components/types.js'\nimport {\n evaluateTemplate,\n getError,\n getPageHref\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport {\n type Detail,\n type DetailItem,\n type DetailItemField,\n type DetailItemRepeat\n} from '~/src/server/plugins/engine/models/types.js'\nimport { RepeatPageController } from '~/src/server/plugins/engine/pageControllers/RepeatPageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport { validationOptions as opts } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type CheckAnswers,\n type FormContext,\n type FormContextRequest,\n type FormState,\n type FormSubmissionError,\n type SummaryListAction,\n type SummaryListRow\n} from '~/src/server/plugins/engine/types.js'\n\nexport class SummaryViewModel {\n /**\n * Responsible for parsing state values to the govuk-frontend summary list template\n */\n\n page: PageControllerClass\n pageTitle: string\n declaration?: string\n details: Detail[]\n checkAnswers: CheckAnswers[]\n context: FormContext\n name: string | undefined\n backLink?: BackLink\n feedbackLink?: string\n phaseTag?: string\n errors?: FormSubmissionError[]\n serviceUrl: string\n hasMissingNotificationEmail?: boolean\n components?: ComponentViewModel[]\n allowSaveAndExit = false\n paymentState?: PaymentState\n paymentDetails?: CheckAnswers\n t: (key: string, opts?: Record<string, unknown>) => string\n private readonly _translator!: Translator\n paymentRequired?: boolean\n paymentPreAuthorized?: boolean\n\n constructor(\n request: FormContextRequest,\n page: PageControllerClass,\n context: FormContext,\n translator: Translator\n ) {\n const { model } = page\n const { basePath, def, sections } = model\n const { isForceAccess } = context\n\n const { t } = translator\n this.t = t\n this._translator = translator\n\n this.page = page\n this.pageTitle = page.title\n if (def.schema === SchemaVersion.V2 && !page.title) {\n this.pageTitle = t('pages.summary.title')\n }\n\n this.serviceUrl = `/${basePath}`\n this.name = def.name\n this.declaration = def.declaration\n this.context = context\n\n const result = model\n .makeFilteredSchema(this.context.relevantPages)\n .validate(this.context.relevantState, { ...opts, stripUnknown: true })\n\n // Format errors\n this.errors = result.error?.details.map(getError)\n this.details = this.summaryDetails(request, sections, translator)\n\n // Format check answers\n this.checkAnswers = this.details.map((detail): CheckAnswers => {\n const { title } = detail\n\n const rows = detail.items.map((item): SummaryListRow => {\n const items: SummaryListAction[] = []\n\n // Remove summary list actions from previews\n if (!isForceAccess) {\n items.push({\n href: item.href,\n text: t('pages.summary.change'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: item.label\n })\n }\n\n return {\n key: {\n text: evaluateTemplate(item.title, context)\n },\n value: {\n classes: 'app-prose-scope',\n html: item.value || t('pages.summary.notProvided')\n },\n actions: {\n items\n }\n }\n })\n\n return {\n title: title ? { text: title } : undefined,\n summaryList: { rows }\n }\n })\n }\n\n private summaryDetails(\n request: FormContextRequest,\n sections: Section[],\n translator: Translator\n ) {\n const { context, errors } = this\n const { relevantPages, state } = context\n\n const details: Detail[] = []\n\n ;[...sections, undefined].forEach((section) => {\n const items: DetailItem[] = []\n\n const sectionPages = relevantPages.filter(\n (page) => page.section === section\n )\n\n sectionPages.forEach((page) => {\n const { collection, path } = page\n\n if (page instanceof RepeatPageController) {\n items.push(\n ItemRepeat(\n page,\n state,\n {\n path: page.getSummaryPath(request),\n errors\n },\n translator\n )\n )\n } else {\n for (const field of collection.fields) {\n // PaymentField is rendered in its own section, skip it here\n if (field instanceof PaymentField) {\n continue\n }\n items.push(\n ItemField(page, state, field, { path, errors }, translator)\n )\n }\n }\n })\n\n if (items.length) {\n const sectionTitle = section\n ? translator.tSection(section, 'title') || section.title\n : undefined\n details.push({\n name: section?.name,\n title: sectionTitle,\n items\n })\n }\n })\n\n return details\n }\n}\n\n/**\n * Creates a repeater detail item\n * @see {@link DetailItemField}\n */\nfunction ItemRepeat(\n page: RepeatPageController,\n state: FormState,\n options: {\n path: string\n errors?: FormSubmissionError[]\n },\n translator: Translator\n): DetailItemRepeat {\n const { collection, repeat } = page\n const { name, title } = repeat.options\n\n const values = page.getListFromState(state)\n const count = values.length\n const value =\n count === 0 ? '' : translator.t('pages.repeater.pageTitle', { count })\n\n return {\n name,\n label: title,\n title,\n value,\n href: getPageHref(page, options.path, {\n returnUrl: getPageHref(page, page.getSummaryPath())\n }),\n state,\n page,\n\n // Repeater field detail items\n subItems: values.map((repeatState) =>\n collection.fields.map((field) =>\n ItemField(page, repeatState, field, options, translator)\n )\n )\n }\n}\n\n/**\n * Creates a form field detail item\n * @see {@link DetailItemField}\n */\nexport function ItemField(\n page: PageControllerClass,\n state: FormState,\n field: Field,\n options: {\n path: string\n errors?: FormSubmissionError[]\n },\n translator: Translator\n): DetailItemField {\n // FormComponent doesn't expose shortDescription/title as raw def properties,\n // so build a lookup object with English values to let tComponent's GUID lookup fire.\n const fieldDef = {\n id: field.id,\n type: field.type,\n shortDescription: field.label,\n title: field.title\n } as unknown as ComponentDef\n const rawLabel = translator.tComponent(fieldDef, 'shortDescription')\n const translatedLabel = rawLabel !== '' ? rawLabel : field.label\n const rawTitle = translator.tComponent(fieldDef, 'title')\n const translatedTitle = rawTitle !== '' ? rawTitle : field.title\n const optional =\n field.options.required === false\n ? ` ${translator.t('common.optional')}`\n : ''\n return {\n name: field.name,\n label: translatedTitle,\n title: `${translatedLabel}${optional}`,\n error: field.getFirstError(translator, options.errors),\n value: getAnswer(field, state, translator, { format: 'summary' }),\n href: getPageHref(page, options.path, {\n returnUrl: getPageHref(page, page.getSummaryPath())\n }),\n state,\n page,\n field\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"SummaryViewModel.js","names":["SchemaVersion","PaymentField","getAnswer","evaluateTemplate","getError","getPageHref","RepeatPageController","validationOptions","opts","SummaryViewModel","page","pageTitle","declaration","details","checkAnswers","context","name","backLink","feedbackLink","phaseTag","errors","serviceUrl","hasMissingNotificationEmail","components","allowSaveAndExit","paymentState","paymentDetails","t","_translator","paymentRequired","paymentPreAuthorized","constructor","request","translator","model","basePath","def","sections","isForceAccess","title","schema","V2","result","makeFilteredSchema","relevantPages","validate","relevantState","stripUnknown","error","map","summaryDetails","detail","rows","items","item","push","href","text","classes","visuallyHiddenText","label","key","value","html","actions","undefined","summaryList","state","forEach","section","sectionPages","filter","collection","path","ItemRepeat","getSummaryPath","field","fields","ItemField","length","sectionTitle","tSection","options","repeat","tPage","pageDef","values","getListFromState","count","returnUrl","subItems","repeatState","fieldDef","id","type","shortDescription","rawLabel","tComponent","translatedLabel","rawTitle","translatedTitle","optional","required","getFirstError","format"],"sources":["../../../../../src/server/plugins/engine/models/SummaryViewModel.ts"],"sourcesContent":["import {\n SchemaVersion,\n type ComponentDef,\n type Section\n} from '@defra/forms-model'\n\nimport { PaymentField } from '~/src/server/plugins/engine/components/PaymentField.js'\nimport { type PaymentState } from '~/src/server/plugins/engine/components/PaymentField.types.js'\nimport {\n getAnswer,\n type Field\n} from '~/src/server/plugins/engine/components/helpers/components.js'\nimport {\n type BackLink,\n type ComponentViewModel\n} from '~/src/server/plugins/engine/components/types.js'\nimport {\n evaluateTemplate,\n getError,\n getPageHref\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport {\n type Detail,\n type DetailItem,\n type DetailItemField,\n type DetailItemRepeat\n} from '~/src/server/plugins/engine/models/types.js'\nimport { RepeatPageController } from '~/src/server/plugins/engine/pageControllers/RepeatPageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport { validationOptions as opts } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type CheckAnswers,\n type FormContext,\n type FormContextRequest,\n type FormState,\n type FormSubmissionError,\n type SummaryListAction,\n type SummaryListRow\n} from '~/src/server/plugins/engine/types.js'\n\nexport class SummaryViewModel {\n /**\n * Responsible for parsing state values to the govuk-frontend summary list template\n */\n\n page: PageControllerClass\n pageTitle: string\n declaration?: string\n details: Detail[]\n checkAnswers: CheckAnswers[]\n context: FormContext\n name: string | undefined\n backLink?: BackLink\n feedbackLink?: string\n phaseTag?: string\n errors?: FormSubmissionError[]\n serviceUrl: string\n hasMissingNotificationEmail?: boolean\n components?: ComponentViewModel[]\n allowSaveAndExit = false\n paymentState?: PaymentState\n paymentDetails?: CheckAnswers\n t: (key: string, opts?: Record<string, unknown>) => string\n private readonly _translator!: Translator\n paymentRequired?: boolean\n paymentPreAuthorized?: boolean\n\n constructor(\n request: FormContextRequest,\n page: PageControllerClass,\n context: FormContext,\n translator: Translator\n ) {\n const { model } = page\n const { basePath, def, sections } = model\n const { isForceAccess } = context\n\n const { t } = translator\n this.t = t\n this._translator = translator\n\n this.page = page\n this.pageTitle = page.title\n if (def.schema === SchemaVersion.V2 && !page.title) {\n this.pageTitle = t('pages.summary.title')\n }\n\n this.serviceUrl = `/${basePath}`\n this.name = def.name\n this.declaration = def.declaration\n this.context = context\n\n const result = model\n .makeFilteredSchema(this.context.relevantPages)\n .validate(this.context.relevantState, { ...opts, stripUnknown: true })\n\n // Format errors\n this.errors = result.error?.details.map(getError)\n this.details = this.summaryDetails(request, sections, translator)\n\n // Format check answers\n this.checkAnswers = this.details.map((detail): CheckAnswers => {\n const { title } = detail\n\n const rows = detail.items.map((item): SummaryListRow => {\n const items: SummaryListAction[] = []\n\n // Remove summary list actions from previews\n if (!isForceAccess) {\n items.push({\n href: item.href,\n text: t('pages.summary.change'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: item.label\n })\n }\n\n return {\n key: {\n text: evaluateTemplate(item.title, context)\n },\n value: {\n classes: 'app-prose-scope',\n html: item.value || t('pages.summary.notProvided')\n },\n actions: {\n items\n }\n }\n })\n\n return {\n title: title ? { text: title } : undefined,\n summaryList: { rows }\n }\n })\n }\n\n private summaryDetails(\n request: FormContextRequest,\n sections: Section[],\n translator: Translator\n ) {\n const { context, errors } = this\n const { relevantPages, state } = context\n\n const details: Detail[] = []\n\n ;[...sections, undefined].forEach((section) => {\n const items: DetailItem[] = []\n\n const sectionPages = relevantPages.filter(\n (page) => page.section === section\n )\n\n sectionPages.forEach((page) => {\n const { collection, path } = page\n\n if (page instanceof RepeatPageController) {\n items.push(\n ItemRepeat(\n page,\n state,\n {\n path: page.getSummaryPath(request),\n errors\n },\n translator\n )\n )\n } else {\n for (const field of collection.fields) {\n // PaymentField is rendered in its own section, skip it here\n if (field instanceof PaymentField) {\n continue\n }\n items.push(\n ItemField(page, state, field, { path, errors }, translator)\n )\n }\n }\n })\n\n if (items.length) {\n const sectionTitle = section\n ? translator.tSection(section, 'title') || section.title\n : undefined\n details.push({\n name: section?.name,\n title: sectionTitle,\n items\n })\n }\n })\n\n return details\n }\n}\n\n/**\n * Creates a repeater detail item\n * @see {@link DetailItemField}\n */\nfunction ItemRepeat(\n page: RepeatPageController,\n state: FormState,\n options: {\n path: string\n errors?: FormSubmissionError[]\n },\n translator: Translator\n): DetailItemRepeat {\n const { collection, repeat } = page\n const { name } = repeat.options\n const { t, tPage } = translator\n const title = tPage(page.pageDef, 'repeatTitle') || repeat.options.title\n const values = page.getListFromState(state)\n const count = values.length\n const value = count === 0 ? '' : t('pages.repeater.pageTitle', { count })\n\n return {\n name,\n label: title,\n title,\n value,\n href: getPageHref(page, options.path, {\n returnUrl: getPageHref(page, page.getSummaryPath())\n }),\n state,\n page,\n\n // Repeater field detail items\n subItems: values.map((repeatState) =>\n collection.fields.map((field) =>\n ItemField(page, repeatState, field, options, translator)\n )\n )\n }\n}\n\n/**\n * Creates a form field detail item\n * @see {@link DetailItemField}\n */\nexport function ItemField(\n page: PageControllerClass,\n state: FormState,\n field: Field,\n options: {\n path: string\n errors?: FormSubmissionError[]\n },\n translator: Translator\n): DetailItemField {\n // FormComponent doesn't expose shortDescription/title as raw def properties,\n // so build a lookup object with English values to let tComponent's GUID lookup fire.\n const fieldDef = {\n id: field.id,\n type: field.type,\n shortDescription: field.label,\n title: field.title\n } as unknown as ComponentDef\n const rawLabel = translator.tComponent(fieldDef, 'shortDescription')\n const translatedLabel = rawLabel !== '' ? rawLabel : field.label\n const rawTitle = translator.tComponent(fieldDef, 'title')\n const translatedTitle = rawTitle !== '' ? rawTitle : field.title\n const optional =\n field.options.required === false\n ? ` ${translator.t('common.optional')}`\n : ''\n return {\n name: field.name,\n label: translatedTitle,\n title: `${translatedLabel}${optional}`,\n error: field.getFirstError(translator, options.errors),\n value: getAnswer(field, state, translator, { format: 'summary' }),\n href: getPageHref(page, options.path, {\n returnUrl: getPageHref(page, page.getSummaryPath())\n }),\n state,\n page,\n field\n }\n}\n"],"mappings":"AAAA,SACEA,aAAa,QAGR,oBAAoB;AAE3B,SAASC,YAAY;AAErB,SACEC,SAAS;AAOX,SACEC,gBAAgB,EAChBC,QAAQ,EACRC,WAAW;AASb,SAASC,oBAAoB;AAE7B,SAASC,iBAAiB,IAAIC,IAAI;AAWlC,OAAO,MAAMC,gBAAgB,CAAC;EAC5B;AACF;AACA;;EAEEC,IAAI;EACJC,SAAS;EACTC,WAAW;EACXC,OAAO;EACPC,YAAY;EACZC,OAAO;EACPC,IAAI;EACJC,QAAQ;EACRC,YAAY;EACZC,QAAQ;EACRC,MAAM;EACNC,UAAU;EACVC,2BAA2B;EAC3BC,UAAU;EACVC,gBAAgB,GAAG,KAAK;EACxBC,YAAY;EACZC,cAAc;EACdC,CAAC;EACgBC,WAAW;EAC5BC,eAAe;EACfC,oBAAoB;EAEpBC,WAAWA,CACTC,OAA2B,EAC3BtB,IAAyB,EACzBK,OAAoB,EACpBkB,UAAsB,EACtB;IACA,MAAM;MAAEC;IAAM,CAAC,GAAGxB,IAAI;IACtB,MAAM;MAAEyB,QAAQ;MAAEC,GAAG;MAAEC;IAAS,CAAC,GAAGH,KAAK;IACzC,MAAM;MAAEI;IAAc,CAAC,GAAGvB,OAAO;IAEjC,MAAM;MAAEY;IAAE,CAAC,GAAGM,UAAU;IACxB,IAAI,CAACN,CAAC,GAAGA,CAAC;IACV,IAAI,CAACC,WAAW,GAAGK,UAAU;IAE7B,IAAI,CAACvB,IAAI,GAAGA,IAAI;IAChB,IAAI,CAACC,SAAS,GAAGD,IAAI,CAAC6B,KAAK;IAC3B,IAAIH,GAAG,CAACI,MAAM,KAAKxC,aAAa,CAACyC,EAAE,IAAI,CAAC/B,IAAI,CAAC6B,KAAK,EAAE;MAClD,IAAI,CAAC5B,SAAS,GAAGgB,CAAC,CAAC,qBAAqB,CAAC;IAC3C;IAEA,IAAI,CAACN,UAAU,GAAG,IAAIc,QAAQ,EAAE;IAChC,IAAI,CAACnB,IAAI,GAAGoB,GAAG,CAACpB,IAAI;IACpB,IAAI,CAACJ,WAAW,GAAGwB,GAAG,CAACxB,WAAW;IAClC,IAAI,CAACG,OAAO,GAAGA,OAAO;IAEtB,MAAM2B,MAAM,GAAGR,KAAK,CACjBS,kBAAkB,CAAC,IAAI,CAAC5B,OAAO,CAAC6B,aAAa,CAAC,CAC9CC,QAAQ,CAAC,IAAI,CAAC9B,OAAO,CAAC+B,aAAa,EAAE;MAAE,GAAGtC,IAAI;MAAEuC,YAAY,EAAE;IAAK,CAAC,CAAC;;IAExE;IACA,IAAI,CAAC3B,MAAM,GAAGsB,MAAM,CAACM,KAAK,EAAEnC,OAAO,CAACoC,GAAG,CAAC7C,QAAQ,CAAC;IACjD,IAAI,CAACS,OAAO,GAAG,IAAI,CAACqC,cAAc,CAAClB,OAAO,EAAEK,QAAQ,EAAEJ,UAAU,CAAC;;IAEjE;IACA,IAAI,CAACnB,YAAY,GAAG,IAAI,CAACD,OAAO,CAACoC,GAAG,CAAEE,MAAM,IAAmB;MAC7D,MAAM;QAAEZ;MAAM,CAAC,GAAGY,MAAM;MAExB,MAAMC,IAAI,GAAGD,MAAM,CAACE,KAAK,CAACJ,GAAG,CAAEK,IAAI,IAAqB;QACtD,MAAMD,KAA0B,GAAG,EAAE;;QAErC;QACA,IAAI,CAACf,aAAa,EAAE;UAClBe,KAAK,CAACE,IAAI,CAAC;YACTC,IAAI,EAAEF,IAAI,CAACE,IAAI;YACfC,IAAI,EAAE9B,CAAC,CAAC,sBAAsB,CAAC;YAC/B+B,OAAO,EAAE,8BAA8B;YACvCC,kBAAkB,EAAEL,IAAI,CAACM;UAC3B,CAAC,CAAC;QACJ;QAEA,OAAO;UACLC,GAAG,EAAE;YACHJ,IAAI,EAAEtD,gBAAgB,CAACmD,IAAI,CAACf,KAAK,EAAExB,OAAO;UAC5C,CAAC;UACD+C,KAAK,EAAE;YACLJ,OAAO,EAAE,iBAAiB;YAC1BK,IAAI,EAAET,IAAI,CAACQ,KAAK,IAAInC,CAAC,CAAC,2BAA2B;UACnD,CAAC;UACDqC,OAAO,EAAE;YACPX;UACF;QACF,CAAC;MACH,CAAC,CAAC;MAEF,OAAO;QACLd,KAAK,EAAEA,KAAK,GAAG;UAAEkB,IAAI,EAAElB;QAAM,CAAC,GAAG0B,SAAS;QAC1CC,WAAW,EAAE;UAAEd;QAAK;MACtB,CAAC;IACH,CAAC,CAAC;EACJ;EAEQF,cAAcA,CACpBlB,OAA2B,EAC3BK,QAAmB,EACnBJ,UAAsB,EACtB;IACA,MAAM;MAAElB,OAAO;MAAEK;IAAO,CAAC,GAAG,IAAI;IAChC,MAAM;MAAEwB,aAAa;MAAEuB;IAAM,CAAC,GAAGpD,OAAO;IAExC,MAAMF,OAAiB,GAAG,EAAE;IAE3B,CAAC,GAAGwB,QAAQ,EAAE4B,SAAS,CAAC,CAACG,OAAO,CAAEC,OAAO,IAAK;MAC7C,MAAMhB,KAAmB,GAAG,EAAE;MAE9B,MAAMiB,YAAY,GAAG1B,aAAa,CAAC2B,MAAM,CACtC7D,IAAI,IAAKA,IAAI,CAAC2D,OAAO,KAAKA,OAC7B,CAAC;MAEDC,YAAY,CAACF,OAAO,CAAE1D,IAAI,IAAK;QAC7B,MAAM;UAAE8D,UAAU;UAAEC;QAAK,CAAC,GAAG/D,IAAI;QAEjC,IAAIA,IAAI,YAAYJ,oBAAoB,EAAE;UACxC+C,KAAK,CAACE,IAAI,CACRmB,UAAU,CACRhE,IAAI,EACJyD,KAAK,EACL;YACEM,IAAI,EAAE/D,IAAI,CAACiE,cAAc,CAAC3C,OAAO,CAAC;YAClCZ;UACF,CAAC,EACDa,UACF,CACF,CAAC;QACH,CAAC,MAAM;UACL,KAAK,MAAM2C,KAAK,IAAIJ,UAAU,CAACK,MAAM,EAAE;YACrC;YACA,IAAID,KAAK,YAAY3E,YAAY,EAAE;cACjC;YACF;YACAoD,KAAK,CAACE,IAAI,CACRuB,SAAS,CAACpE,IAAI,EAAEyD,KAAK,EAAES,KAAK,EAAE;cAAEH,IAAI;cAAErD;YAAO,CAAC,EAAEa,UAAU,CAC5D,CAAC;UACH;QACF;MACF,CAAC,CAAC;MAEF,IAAIoB,KAAK,CAAC0B,MAAM,EAAE;QAChB,MAAMC,YAAY,GAAGX,OAAO,GACxBpC,UAAU,CAACgD,QAAQ,CAACZ,OAAO,EAAE,OAAO,CAAC,IAAIA,OAAO,CAAC9B,KAAK,GACtD0B,SAAS;QACbpD,OAAO,CAAC0C,IAAI,CAAC;UACXvC,IAAI,EAAEqD,OAAO,EAAErD,IAAI;UACnBuB,KAAK,EAAEyC,YAAY;UACnB3B;QACF,CAAC,CAAC;MACJ;IACF,CAAC,CAAC;IAEF,OAAOxC,OAAO;EAChB;AACF;;AAEA;AACA;AACA;AACA;AACA,SAAS6D,UAAUA,CACjBhE,IAA0B,EAC1ByD,KAAgB,EAChBe,OAGC,EACDjD,UAAsB,EACJ;EAClB,MAAM;IAAEuC,UAAU;IAAEW;EAAO,CAAC,GAAGzE,IAAI;EACnC,MAAM;IAAEM;EAAK,CAAC,GAAGmE,MAAM,CAACD,OAAO;EAC/B,MAAM;IAAEvD,CAAC;IAAEyD;EAAM,CAAC,GAAGnD,UAAU;EAC/B,MAAMM,KAAK,GAAG6C,KAAK,CAAC1E,IAAI,CAAC2E,OAAO,EAAE,aAAa,CAAC,IAAIF,MAAM,CAACD,OAAO,CAAC3C,KAAK;EACxE,MAAM+C,MAAM,GAAG5E,IAAI,CAAC6E,gBAAgB,CAACpB,KAAK,CAAC;EAC3C,MAAMqB,KAAK,GAAGF,MAAM,CAACP,MAAM;EAC3B,MAAMjB,KAAK,GAAG0B,KAAK,KAAK,CAAC,GAAG,EAAE,GAAG7D,CAAC,CAAC,0BAA0B,EAAE;IAAE6D;EAAM,CAAC,CAAC;EAEzE,OAAO;IACLxE,IAAI;IACJ4C,KAAK,EAAErB,KAAK;IACZA,KAAK;IACLuB,KAAK;IACLN,IAAI,EAAEnD,WAAW,CAACK,IAAI,EAAEwE,OAAO,CAACT,IAAI,EAAE;MACpCgB,SAAS,EAAEpF,WAAW,CAACK,IAAI,EAAEA,IAAI,CAACiE,cAAc,CAAC,CAAC;IACpD,CAAC,CAAC;IACFR,KAAK;IACLzD,IAAI;IAEJ;IACAgF,QAAQ,EAAEJ,MAAM,CAACrC,GAAG,CAAE0C,WAAW,IAC/BnB,UAAU,CAACK,MAAM,CAAC5B,GAAG,CAAE2B,KAAK,IAC1BE,SAAS,CAACpE,IAAI,EAAEiF,WAAW,EAAEf,KAAK,EAAEM,OAAO,EAAEjD,UAAU,CACzD,CACF;EACF,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAAS6C,SAASA,CACvBpE,IAAyB,EACzByD,KAAgB,EAChBS,KAAY,EACZM,OAGC,EACDjD,UAAsB,EACL;EACjB;EACA;EACA,MAAM2D,QAAQ,GAAG;IACfC,EAAE,EAAEjB,KAAK,CAACiB,EAAE;IACZC,IAAI,EAAElB,KAAK,CAACkB,IAAI;IAChBC,gBAAgB,EAAEnB,KAAK,CAAChB,KAAK;IAC7BrB,KAAK,EAAEqC,KAAK,CAACrC;EACf,CAA4B;EAC5B,MAAMyD,QAAQ,GAAG/D,UAAU,CAACgE,UAAU,CAACL,QAAQ,EAAE,kBAAkB,CAAC;EACpE,MAAMM,eAAe,GAAGF,QAAQ,KAAK,EAAE,GAAGA,QAAQ,GAAGpB,KAAK,CAAChB,KAAK;EAChE,MAAMuC,QAAQ,GAAGlE,UAAU,CAACgE,UAAU,CAACL,QAAQ,EAAE,OAAO,CAAC;EACzD,MAAMQ,eAAe,GAAGD,QAAQ,KAAK,EAAE,GAAGA,QAAQ,GAAGvB,KAAK,CAACrC,KAAK;EAChE,MAAM8D,QAAQ,GACZzB,KAAK,CAACM,OAAO,CAACoB,QAAQ,KAAK,KAAK,GAC5B,IAAIrE,UAAU,CAACN,CAAC,CAAC,iBAAiB,CAAC,EAAE,GACrC,EAAE;EACR,OAAO;IACLX,IAAI,EAAE4D,KAAK,CAAC5D,IAAI;IAChB4C,KAAK,EAAEwC,eAAe;IACtB7D,KAAK,EAAE,GAAG2D,eAAe,GAAGG,QAAQ,EAAE;IACtCrD,KAAK,EAAE4B,KAAK,CAAC2B,aAAa,CAACtE,UAAU,EAAEiD,OAAO,CAAC9D,MAAM,CAAC;IACtD0C,KAAK,EAAE5D,SAAS,CAAC0E,KAAK,EAAET,KAAK,EAAElC,UAAU,EAAE;MAAEuE,MAAM,EAAE;IAAU,CAAC,CAAC;IACjEhD,IAAI,EAAEnD,WAAW,CAACK,IAAI,EAAEwE,OAAO,CAACT,IAAI,EAAE;MACpCgB,SAAS,EAAEpF,WAAW,CAACK,IAAI,EAAEA,IAAI,CAACiE,cAAc,CAAC,CAAC;IACpD,CAAC,CAAC;IACFR,KAAK;IACLzD,IAAI;IACJkE;EACF,CAAC;AACH","ignoreList":[]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EN_GB } from "../../../../constants.js";
|
|
1
2
|
import { getFormVersion } from "../../helpers.js";
|
|
2
3
|
import { categoriseData } from "../machine/v2.js";
|
|
3
4
|
import { FormAdapterSubmissionSchemaVersion } from "../../types/enums.js";
|
|
@@ -17,15 +18,12 @@ export function format(context, items, model, submitResponse, formStatus, formMe
|
|
|
17
18
|
formSlug: formMetadata?.slug ?? '',
|
|
18
19
|
status: formStatus.state,
|
|
19
20
|
isPreview: formStatus.isPreview,
|
|
20
|
-
notificationEmail: formMetadata?.notificationEmail ?? ''
|
|
21
|
+
notificationEmail: formMetadata?.notificationEmail ?? '',
|
|
22
|
+
language: context.translator?.language ?? EN_GB
|
|
21
23
|
};
|
|
22
24
|
if (versionMetadata) {
|
|
23
25
|
meta.versionMetadata = versionMetadata;
|
|
24
26
|
}
|
|
25
|
-
const definitionLanguage = model.def.metadata?.language;
|
|
26
|
-
if (typeof definitionLanguage === 'string') {
|
|
27
|
-
meta.language = definitionLanguage;
|
|
28
|
-
}
|
|
29
27
|
const main = Object.fromEntries(Object.entries(v2Main).map(([key, value]) => {
|
|
30
28
|
if (value === undefined) {
|
|
31
29
|
return [key, null];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"v1.js","names":["getFormVersion","categoriseData","FormAdapterSubmissionSchemaVersion","format","context","items","model","submitResponse","formStatus","formMetadata","csvFiles","extractCsvFiles","main","v2Main","v2Data","versionMetadata","def","meta","schemaVersion","V1","timestamp","Date","referenceNumber","formName","name","formId","id","formSlug","slug","status","state","isPreview","notificationEmail","
|
|
1
|
+
{"version":3,"file":"v1.js","names":["EN_GB","getFormVersion","categoriseData","FormAdapterSubmissionSchemaVersion","format","context","items","model","submitResponse","formStatus","formMetadata","csvFiles","extractCsvFiles","main","v2Main","v2Data","versionMetadata","def","meta","schemaVersion","V1","timestamp","Date","referenceNumber","formName","name","formId","id","formSlug","slug","status","state","isPreview","notificationEmail","language","translator","Object","fromEntries","entries","map","key","value","undefined","data","result","files","payload","JSON","stringify","repeaters"],"sources":["../../../../../../src/server/plugins/engine/outputFormatters/adapter/v1.ts"],"sourcesContent":["import {\n type FormMetadata,\n type SubmitResponsePayload\n} from '@defra/forms-model'\n\nimport { EN_GB } from '~/src/server/constants.js'\nimport {\n getFormVersion,\n type checkFormStatus\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/FormModel.js'\nimport { type DetailItem } from '~/src/server/plugins/engine/models/types.js'\nimport { categoriseData } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'\nimport { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'\nimport {\n type FormAdapterSubmissionMessageData,\n type FormAdapterSubmissionMessageMeta,\n type FormAdapterSubmissionMessagePayload,\n type FormAdapterSubmissionMessageResult,\n type FormContext\n} from '~/src/server/plugins/engine/types.js'\n\nexport function format(\n context: FormContext,\n items: DetailItem[],\n model: FormModel,\n submitResponse: SubmitResponsePayload,\n formStatus: ReturnType<typeof checkFormStatus>,\n formMetadata?: FormMetadata\n): string {\n const csvFiles = extractCsvFiles(submitResponse)\n\n const { main: v2Main, ...v2Data } = categoriseData(items)\n\n const versionMetadata = getFormVersion(model.def)\n\n const meta: FormAdapterSubmissionMessageMeta = {\n schemaVersion: FormAdapterSubmissionSchemaVersion.V1,\n timestamp: new Date(),\n referenceNumber: context.referenceNumber,\n formName: model.name,\n formId: formMetadata?.id ?? '',\n formSlug: formMetadata?.slug ?? '',\n status: formStatus.state,\n isPreview: formStatus.isPreview,\n notificationEmail: formMetadata?.notificationEmail ?? '',\n language: context.translator?.language ?? EN_GB\n }\n\n if (versionMetadata) {\n meta.versionMetadata = versionMetadata\n }\n\n const main = Object.fromEntries(\n Object.entries(v2Main).map(([key, value]) => {\n if (value === undefined) {\n return [key, null]\n }\n\n return [key, value]\n })\n )\n\n const data: FormAdapterSubmissionMessageData = {\n main,\n ...v2Data\n }\n\n const result: FormAdapterSubmissionMessageResult = {\n files: csvFiles\n }\n\n const payload: FormAdapterSubmissionMessagePayload = {\n meta,\n data,\n result\n }\n\n return JSON.stringify(payload)\n}\n\nfunction extractCsvFiles(\n submitResponse: SubmitResponsePayload\n): FormAdapterSubmissionMessageResult['files'] {\n const result =\n submitResponse.result as Partial<FormAdapterSubmissionMessageResult>\n\n return {\n main: result.files?.main ?? '',\n repeaters: result.files?.repeaters ?? {}\n }\n}\n"],"mappings":"AAKA,SAASA,KAAK;AACd,SACEC,cAAc;AAKhB,SAASC,cAAc;AACvB,SAASC,kCAAkC;AAS3C,OAAO,SAASC,MAAMA,CACpBC,OAAoB,EACpBC,KAAmB,EACnBC,KAAgB,EAChBC,cAAqC,EACrCC,UAA8C,EAC9CC,YAA2B,EACnB;EACR,MAAMC,QAAQ,GAAGC,eAAe,CAACJ,cAAc,CAAC;EAEhD,MAAM;IAAEK,IAAI,EAAEC,MAAM;IAAE,GAAGC;EAAO,CAAC,GAAGb,cAAc,CAACI,KAAK,CAAC;EAEzD,MAAMU,eAAe,GAAGf,cAAc,CAACM,KAAK,CAACU,GAAG,CAAC;EAEjD,MAAMC,IAAsC,GAAG;IAC7CC,aAAa,EAAEhB,kCAAkC,CAACiB,EAAE;IACpDC,SAAS,EAAE,IAAIC,IAAI,CAAC,CAAC;IACrBC,eAAe,EAAElB,OAAO,CAACkB,eAAe;IACxCC,QAAQ,EAAEjB,KAAK,CAACkB,IAAI;IACpBC,MAAM,EAAEhB,YAAY,EAAEiB,EAAE,IAAI,EAAE;IAC9BC,QAAQ,EAAElB,YAAY,EAAEmB,IAAI,IAAI,EAAE;IAClCC,MAAM,EAAErB,UAAU,CAACsB,KAAK;IACxBC,SAAS,EAAEvB,UAAU,CAACuB,SAAS;IAC/BC,iBAAiB,EAAEvB,YAAY,EAAEuB,iBAAiB,IAAI,EAAE;IACxDC,QAAQ,EAAE7B,OAAO,CAAC8B,UAAU,EAAED,QAAQ,IAAIlC;EAC5C,CAAC;EAED,IAAIgB,eAAe,EAAE;IACnBE,IAAI,CAACF,eAAe,GAAGA,eAAe;EACxC;EAEA,MAAMH,IAAI,GAAGuB,MAAM,CAACC,WAAW,CAC7BD,MAAM,CAACE,OAAO,CAACxB,MAAM,CAAC,CAACyB,GAAG,CAAC,CAAC,CAACC,GAAG,EAAEC,KAAK,CAAC,KAAK;IAC3C,IAAIA,KAAK,KAAKC,SAAS,EAAE;MACvB,OAAO,CAACF,GAAG,EAAE,IAAI,CAAC;IACpB;IAEA,OAAO,CAACA,GAAG,EAAEC,KAAK,CAAC;EACrB,CAAC,CACH,CAAC;EAED,MAAME,IAAsC,GAAG;IAC7C9B,IAAI;IACJ,GAAGE;EACL,CAAC;EAED,MAAM6B,MAA0C,GAAG;IACjDC,KAAK,EAAElC;EACT,CAAC;EAED,MAAMmC,OAA4C,GAAG;IACnD5B,IAAI;IACJyB,IAAI;IACJC;EACF,CAAC;EAED,OAAOG,IAAI,CAACC,SAAS,CAACF,OAAO,CAAC;AAChC;AAEA,SAASlC,eAAeA,CACtBJ,cAAqC,EACQ;EAC7C,MAAMoC,MAAM,GACVpC,cAAc,CAACoC,MAAqD;EAEtE,OAAO;IACL/B,IAAI,EAAE+B,MAAM,CAACC,KAAK,EAAEhC,IAAI,IAAI,EAAE;IAC9BoC,SAAS,EAAEL,MAAM,CAACC,KAAK,EAAEI,SAAS,IAAI,CAAC;EACzC,CAAC;AACH","ignoreList":[]}
|
|
@@ -133,24 +133,26 @@ export class FileUploadPageController extends QuestionPageController {
|
|
|
133
133
|
const {
|
|
134
134
|
filename
|
|
135
135
|
} = fileToRemove.status.form.file;
|
|
136
|
+
const translator = this.getTranslator(request);
|
|
136
137
|
const {
|
|
137
138
|
t
|
|
138
|
-
} =
|
|
139
|
+
} = translator;
|
|
139
140
|
return h.view(this.fileDeleteViewName, {
|
|
140
141
|
...viewModel,
|
|
141
142
|
context,
|
|
142
143
|
backLink: this.getBackLink(request, context, t),
|
|
143
|
-
pageTitle:
|
|
144
|
+
pageTitle: t('pages.fileUpload.removeFileTitle'),
|
|
144
145
|
itemTitle: filename,
|
|
145
146
|
confirmation: {
|
|
146
|
-
text: '
|
|
147
|
+
text: t('pages.fileUpload.removeFileBody')
|
|
147
148
|
},
|
|
148
149
|
buttonConfirm: {
|
|
149
|
-
text: '
|
|
150
|
+
text: t('pages.fileUpload.removeFileButton')
|
|
150
151
|
},
|
|
151
152
|
buttonCancel: {
|
|
152
|
-
text: '
|
|
153
|
-
}
|
|
153
|
+
text: t('pages.fileUpload.cancel')
|
|
154
|
+
},
|
|
155
|
+
t
|
|
154
156
|
});
|
|
155
157
|
};
|
|
156
158
|
}
|
|
@@ -219,6 +221,9 @@ export class FileUploadPageController extends QuestionPageController {
|
|
|
219
221
|
const {
|
|
220
222
|
state
|
|
221
223
|
} = context;
|
|
224
|
+
const {
|
|
225
|
+
t
|
|
226
|
+
} = translator;
|
|
222
227
|
const upload = this.getUploadFromState(state);
|
|
223
228
|
const viewModel = super.getViewModel(request, context, translator);
|
|
224
229
|
const {
|
|
@@ -229,6 +234,13 @@ export class FileUploadPageController extends QuestionPageController {
|
|
|
229
234
|
const [formComponent] = components.filter(({
|
|
230
235
|
model
|
|
231
236
|
}) => model.id === fileUpload.name);
|
|
237
|
+
formComponent.model.upload = {
|
|
238
|
+
count: formComponent.model.upload?.count ?? 0,
|
|
239
|
+
summaryList: formComponent.model.upload?.summaryList ?? {
|
|
240
|
+
rows: []
|
|
241
|
+
},
|
|
242
|
+
uploadingLabel: t('components.fileUploadField.uploading')
|
|
243
|
+
};
|
|
232
244
|
const index = components.indexOf(formComponent);
|
|
233
245
|
const proxyUrl = getProxyUrlForLocalDevelopment(upload?.uploadUrl);
|
|
234
246
|
return {
|
|
@@ -239,7 +251,8 @@ export class FileUploadPageController extends QuestionPageController {
|
|
|
239
251
|
// Split out components before/after
|
|
240
252
|
componentsBefore: components.slice(0, index),
|
|
241
253
|
components: components.slice(index),
|
|
242
|
-
proxyUrl
|
|
254
|
+
proxyUrl,
|
|
255
|
+
t
|
|
243
256
|
};
|
|
244
257
|
}
|
|
245
258
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileUploadPageController.js","names":["ComponentType","Boom","wait","StatusCodes","FileUploadField","tempItemSchema","getCacheService","getError","getExponentialBackoffDelay","QuestionPageController","getProxyUrlForLocalDevelopment","getUploadStatus","initiateUpload","FileStatus","UploadStatus","MAX_UPLOADS","CDP_UPLOAD_TIMEOUT_MS","prepareStatus","status","file","form","isPending","fileStatus","pending","errorMessage","prepareFileState","fileState","FileUploadPageController","fileUpload","fileDeleteViewName","constructor","model","pageDef","collection","fileUploads","fields","filter","field","type","at","length","badImplementation","path","indexOf","name","viewName","getStateKeys","component","pagePath","page","getFormDataFromState","request","state","payload","files","getFilesFromState","undefined","getState","refreshUpload","uploadState","upload","getUploadFromState","makeGetItemDeleteRouteHandler","context","h","viewModel","params","fileToRemove","find","fileId","itemId","notFound","filename","t","getTranslator","view","backLink","getBackLink","pageTitle","itemTitle","confirmation","text","buttonConfirm","buttonCancel","makePostItemDeleteRouteHandler","confirm","getFormParams","checkRemovedFiles","proceed","getErrors","details","errors","forEach","error","isUploadError","isUploadRootError","push","value","href","getViewModel","translator","components","formComponent","id","index","proxyUrl","uploadUrl","formAction","uploadId","componentsBefore","slice","checkUploadStatus","depth","initiateAndStoreNewUpload","statusResponse","err","isBoom","output","statusCode","NOT_FOUND","valueOf","badRequest","uploadStatus","initiated","Error","logger","gatewayTimeout","toFixed","delay","info","validationResult","validate","stripUnknown","processUploadedFiles","validatedItem","validatedStatus","rawFile","uploadedFiles","Array","isArray","allErrors","complete","perFileState","unshift","cacheService","server","setFlash","some","f","mergeState","filesUpdated","options","schema","getFormMetadata","services","formsService","max","Math","min","formMetadata","slug","notificationEmail","newUpload","accept"],"sources":["../../../../../src/server/plugins/engine/pageControllers/FileUploadPageController.ts"],"sourcesContent":["import { ComponentType, type PageFileUpload } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport { wait } from '@hapi/hoek'\nimport { StatusCodes } from 'http-status-codes'\nimport { type ValidationErrorItem } from 'joi'\n\nimport {\n FileUploadField,\n tempItemSchema\n} from '~/src/server/plugins/engine/components/FileUploadField.js'\nimport { type FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n getCacheService,\n getError,\n getExponentialBackoffDelay\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport { getProxyUrlForLocalDevelopment } from '~/src/server/plugins/engine/pageControllers/helpers/index.js'\nimport {\n getUploadStatus,\n initiateUpload\n} from '~/src/server/plugins/engine/services/uploadService.js'\nimport {\n FileStatus,\n UploadStatus,\n type AnyFormRequest,\n type FeaturedFormPageViewModel,\n type FileState,\n type FileUpload,\n type FormContext,\n type FormContextRequest,\n type FormSubmissionError,\n type FormSubmissionState,\n type ItemDeletePageViewModel,\n type UploadInitiateResponse,\n type UploadStatusFileResponse\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nconst MAX_UPLOADS = 25\nconst CDP_UPLOAD_TIMEOUT_MS = 60000 // 1 minute\n\nexport function prepareStatus(status: UploadStatusFileResponse) {\n const file = status.form.file\n const isPending = file.fileStatus === FileStatus.pending\n\n if (!file.errorMessage && isPending) {\n file.errorMessage = 'The selected file has not fully uploaded'\n }\n\n return status\n}\n\nfunction prepareFileState(fileState: FileState) {\n prepareStatus(fileState.status)\n\n return fileState\n}\n\nexport class FileUploadPageController extends QuestionPageController {\n declare pageDef: PageFileUpload\n\n fileUpload: FileUploadField\n fileDeleteViewName = 'item-delete'\n\n constructor(model: FormModel, pageDef: PageFileUpload) {\n super(model, pageDef)\n\n const { collection } = this\n\n // Get the file upload fields from the collection\n const fileUploads = collection.fields.filter(\n (field): field is FileUploadField =>\n field.type === ComponentType.FileUploadField\n )\n\n const fileUpload = fileUploads.at(0)\n\n // Assert we have exactly 1 file upload component\n if (!fileUpload || fileUploads.length > 1) {\n throw Boom.badImplementation(\n `Expected 1 FileUploadFieldComponent in FileUploadPageController '${pageDef.path}'`\n )\n }\n\n // Assert the file upload component is the first form component\n if (collection.fields.indexOf(fileUpload) !== 0) {\n throw Boom.badImplementation(\n `Expected '${fileUpload.name}' to be the first form component in FileUploadPageController '${pageDef.path}'`\n )\n }\n\n // Assign the file upload component to the controller\n this.fileUpload = fileUpload\n this.viewName = 'file-upload'\n }\n\n /**\n * Get supplementary state keys for clearing file upload state.\n * Returns the nested upload path for FileUploadField components only.\n * @param component - The component to get supplementary state keys for\n * @returns Array containing the nested upload path, e.g., [\"upload['/page-path']\"]\n * or ['upload'] if no page path is available. Returns empty array for non-FileUploadField components.\n */\n getStateKeys(component: FormComponent): string[] {\n // Only return upload keys for FileUploadField components\n if (!(component instanceof FileUploadField)) {\n return []\n }\n\n const pagePath = component.page?.path\n return pagePath ? [`upload['${pagePath}']`] : ['upload']\n }\n\n getFormDataFromState(\n request: FormContextRequest | undefined,\n state: FormSubmissionState\n ) {\n const { fileUpload } = this\n\n const payload = super.getFormDataFromState(request, state)\n const files = this.getFilesFromState(state)\n\n // Append the files to the payload\n payload[fileUpload.name] = files.length ? files : undefined\n\n return payload\n }\n\n async getState(request: AnyFormRequest) {\n const { fileUpload } = this\n\n // Get the actual state\n const state = await super.getState(request)\n const files = this.getFilesFromState(state)\n\n // Overwrite the files with those in the upload state\n state[fileUpload.name] = files\n\n return this.refreshUpload(request, state)\n }\n\n /**\n * Get the uploaded files from state.\n */\n getFilesFromState(state: FormSubmissionState) {\n const { path } = this\n\n const uploadState = state.upload?.[path]\n return uploadState?.files ?? []\n }\n\n /**\n * Get the initiated upload from state.\n */\n getUploadFromState(state: FormSubmissionState) {\n const { path } = this\n\n const uploadState = state.upload?.[path]\n return uploadState?.upload\n }\n\n makeGetItemDeleteRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { viewModel } = this\n const { params } = request\n const { state } = context\n\n const files = this.getFilesFromState(state)\n\n const fileToRemove = files.find(\n ({ status }) => status.form.file.fileId === params.itemId\n )\n\n if (!fileToRemove) {\n throw Boom.notFound('File to delete not found')\n }\n\n const { filename } = fileToRemove.status.form.file\n\n const { t } = this.getTranslator(request)\n\n return h.view(this.fileDeleteViewName, {\n ...viewModel,\n context,\n backLink: this.getBackLink(request, context, t),\n pageTitle: `Are you sure you want to remove this file?`,\n itemTitle: filename,\n confirmation: { text: 'You cannot recover removed files.' },\n buttonConfirm: { text: 'Remove file' },\n buttonCancel: { text: 'Cancel' }\n } satisfies ItemDeletePageViewModel)\n }\n }\n\n makePostItemDeleteRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { state } = context\n\n const { confirm } = this.getFormParams(request)\n\n // Check for any removed files in the POST payload\n if (confirm) {\n await this.checkRemovedFiles(request, state)\n return this.proceed(request, h, path)\n }\n\n return this.proceed(request, h)\n }\n }\n\n getErrors(details?: ValidationErrorItem[]) {\n const { fileUpload } = this\n\n if (details) {\n const errors: FormSubmissionError[] = []\n\n details.forEach((error) => {\n const isUploadError = error.path[0] === fileUpload.name\n const isUploadRootError = isUploadError && error.path.length === 1\n\n if (!isUploadError || isUploadRootError) {\n // The error is for the root of the upload or another\n // field on the page so defer to the getError helper\n errors.push(getError(error))\n } else {\n const { context, path, type } = error\n\n if (type === 'object.unknown' && path.at(-1) === 'errorMessage') {\n const value = context?.value as string | undefined\n\n if (value) {\n const name = fileUpload.name\n const text = typeof value === 'string' ? value : 'Unknown error'\n const href = `#${name}`\n\n errors.push({ path, href, name, text })\n }\n }\n }\n })\n\n return errors\n }\n }\n\n getViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): FeaturedFormPageViewModel {\n const { fileUpload } = this\n const { state } = context\n\n const upload = this.getUploadFromState(state)\n\n const viewModel = super.getViewModel(request, context, translator)\n const { components } = viewModel\n\n // Featured form component\n const [formComponent] = components.filter(\n ({ model }) => model.id === fileUpload.name\n )\n\n const index = components.indexOf(formComponent)\n\n const proxyUrl = getProxyUrlForLocalDevelopment(upload?.uploadUrl)\n\n return {\n ...viewModel,\n formAction: upload?.uploadUrl,\n uploadId: upload?.uploadId,\n formComponent,\n\n // Split out components before/after\n componentsBefore: components.slice(0, index),\n components: components.slice(index),\n proxyUrl\n }\n }\n\n /**\n * Refreshes the CDP upload and files in the\n * state and checks for any removed files.\n *\n * If an upload exists and hasn't been consumed\n * it gets re-used, otherwise we initiate a new one.\n * @param request - the hapi request\n * @param state - the form state\n */\n private async refreshUpload(\n request: AnyFormRequest,\n state: FormSubmissionState\n ) {\n state = await this.checkUploadStatus(request, state)\n\n return state\n }\n\n /**\n * If an upload exists and hasn't been consumed\n * it gets re-used, otherwise a new one is initiated.\n * @param request - the hapi request\n * @param state - the form state\n * @param depth - the number of retries so far\n */\n private async checkUploadStatus(\n request: AnyFormRequest,\n state: FormSubmissionState,\n depth = 1\n ): Promise<FormSubmissionState> {\n const upload = this.getUploadFromState(state)\n const files = this.getFilesFromState(state)\n\n // If no upload exists, initiate a new one.\n if (!upload?.uploadId) {\n return this.initiateAndStoreNewUpload(request, state)\n }\n\n const uploadId = upload.uploadId\n\n let statusResponse\n\n try {\n statusResponse = await getUploadStatus(uploadId)\n } catch (err) {\n // if the user loads a file upload page and queries the cached upload, after the upload has\n // expired in CDP, we will get a 404 from the getUploadStatus endpoint.\n // In this case we want to initiate a new upload and return that state, so the form\n // doesn't blow up for the end user.\n if (\n Boom.isBoom(err) &&\n err.output.statusCode === StatusCodes.NOT_FOUND.valueOf()\n ) {\n return this.initiateAndStoreNewUpload(request, state)\n }\n throw err\n }\n\n if (!statusResponse) {\n throw Boom.badRequest(\n `Unexpected empty response from getUploadStatus for ${uploadId}`\n )\n }\n\n // Re-use the upload if it is still in the \"initiated\" state.\n if (statusResponse.uploadStatus === UploadStatus.initiated) {\n return state\n }\n\n if (statusResponse.uploadStatus === UploadStatus.pending) {\n // Using exponential backoff delays:\n // Depth 1: 2000ms, Depth 2: 4000ms, Depth 3: 8000ms, Depth 4: 16000ms, Depth 5+: 30000ms (capped)\n // A depth of 5 (or more) implies cumulative delays roughly reaching 55 seconds.\n if (depth >= 5) {\n const err = new Error(\n `Exceeded cumulative retry delay for ${uploadId} (depth: ${depth}). Re-initiating a new upload.`\n )\n request.logger.error(\n err,\n `[uploadTimeout] Exceeded cumulative retry delay for uploadId: ${uploadId} at depth: ${depth} - re-initiating new upload`\n )\n await this.initiateAndStoreNewUpload(request, state)\n throw Boom.gatewayTimeout(\n `Timed out waiting for ${uploadId} after cumulative retries exceeding ${((CDP_UPLOAD_TIMEOUT_MS - 5000) / 1000).toFixed(0)} seconds`\n )\n }\n const delay = getExponentialBackoffDelay(depth)\n request.logger.info(\n `[uploadRetry] Waiting ${delay / 1000} seconds for uploadId: ${uploadId} to complete (retry depth: ${depth})`\n )\n await wait(delay)\n return this.checkUploadStatus(request, state, depth + 1)\n }\n\n // Only add to files state if the file validates.\n // This secures against html tampering of the file input\n // (e.g. changing it to a simple text field or similar).\n const validationResult = tempItemSchema.validate(\n { uploadId, status: statusResponse },\n { stripUnknown: true }\n )\n const error = validationResult.error\n\n if (error) {\n return this.initiateAndStoreNewUpload(request, state)\n }\n\n // CDP returns form.file as a single object for one file,\n // or an array for multiple files. The Joi schema normalises\n // both to an array via .single().\n await this.processUploadedFiles(\n request,\n state,\n validationResult.value,\n files,\n upload\n )\n\n return this.initiateAndStoreNewUpload(request, state)\n }\n\n /**\n * Processes the uploaded files from a CDP status response.\n * Complete files are added to state, rejected/pending files\n * have their error messages flashed.\n * @param request - the hapi request\n * @param state - the form state\n * @param validatedItem - the Joi-validated upload item\n * @param files - the current files array from state\n * @param upload - the current upload initiation response\n */\n private async processUploadedFiles(\n request: AnyFormRequest,\n state: FormSubmissionState,\n validatedItem: FileState,\n files: FileState[],\n upload: UploadInitiateResponse | undefined\n ) {\n const { uploadId } = validatedItem\n const validatedStatus = validatedItem.status\n const rawFile = validatedStatus.form.file as unknown as\n | FileUpload\n | FileUpload[]\n const uploadedFiles = Array.isArray(rawFile) ? rawFile : [rawFile]\n\n const allErrors: FormSubmissionError[] = []\n\n for (const file of uploadedFiles) {\n if (file.fileStatus === FileStatus.complete) {\n const perFileState: FileState = {\n uploadId,\n status: {\n ...validatedStatus,\n form: { file }\n } as FileState['status']\n }\n files.unshift(prepareFileState(perFileState))\n } else {\n // Collect the error for rejected/pending files.\n const { fileUpload } = this\n const name = fileUpload.name\n const text = file.errorMessage ?? 'Unknown error'\n allErrors.push({ path: [name], href: `#${name}`, name, text })\n }\n }\n\n if (allErrors.length) {\n const cacheService = getCacheService(request.server)\n cacheService.setFlash(request, { errors: allErrors })\n }\n\n if (uploadedFiles.some((f) => f.fileStatus === FileStatus.complete)) {\n await this.mergeState(request, state, {\n upload: { [this.path]: { files, upload } }\n })\n }\n }\n\n /**\n * Checks the payload for a file getting removed\n * and removes it from the upload files if found\n * @param request - the hapi request\n * @param state - the form state\n * @returns updated state if any files have been removed\n */\n private async checkRemovedFiles(\n request: FormRequestPayload,\n state: FormSubmissionState\n ) {\n const { path } = this\n const { params } = request\n\n const upload = this.getUploadFromState(state)\n const files = this.getFilesFromState(state)\n\n const filesUpdated = files.filter(\n ({ status }) => status.form.file.fileId !== params.itemId\n )\n\n if (filesUpdated.length === files.length) {\n return\n }\n\n await this.mergeState(request, state, {\n upload: { [path]: { files: filesUpdated, upload } }\n })\n }\n\n /**\n * Initiates a CDP file upload and stores in the upload state\n * @param request - the hapi request\n * @param state - the form state\n */\n private async initiateAndStoreNewUpload(\n request: AnyFormRequest,\n state: FormSubmissionState\n ) {\n const { fileUpload, href, path } = this\n const { options, schema } = fileUpload\n const { getFormMetadata } = this.model.services.formsService\n\n const files = this.getFilesFromState(state)\n\n // Reset the upload in state\n let upload: UploadInitiateResponse | undefined\n\n // Don't initiate anymore after minimum of `schema.max` or MAX_UPLOADS\n const max = Math.min(schema.max ?? MAX_UPLOADS, MAX_UPLOADS)\n\n if (files.length < max) {\n const formMetadata = await getFormMetadata(request.params.slug)\n const notificationEmail =\n formMetadata.notificationEmail ?? 'defraforms@defra.gov.uk'\n\n const newUpload = await initiateUpload(\n href,\n notificationEmail,\n options.accept\n )\n\n if (newUpload === undefined) {\n throw Boom.badRequest('Unexpected empty response from initiateUpload')\n }\n\n upload = newUpload\n }\n\n return this.mergeState(request, state, {\n upload: { [path]: { files, upload } }\n })\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"FileUploadPageController.js","names":["ComponentType","Boom","wait","StatusCodes","FileUploadField","tempItemSchema","getCacheService","getError","getExponentialBackoffDelay","QuestionPageController","getProxyUrlForLocalDevelopment","getUploadStatus","initiateUpload","FileStatus","UploadStatus","MAX_UPLOADS","CDP_UPLOAD_TIMEOUT_MS","prepareStatus","status","file","form","isPending","fileStatus","pending","errorMessage","prepareFileState","fileState","FileUploadPageController","fileUpload","fileDeleteViewName","constructor","model","pageDef","collection","fileUploads","fields","filter","field","type","at","length","badImplementation","path","indexOf","name","viewName","getStateKeys","component","pagePath","page","getFormDataFromState","request","state","payload","files","getFilesFromState","undefined","getState","refreshUpload","uploadState","upload","getUploadFromState","makeGetItemDeleteRouteHandler","context","h","viewModel","params","fileToRemove","find","fileId","itemId","notFound","filename","translator","getTranslator","t","view","backLink","getBackLink","pageTitle","itemTitle","confirmation","text","buttonConfirm","buttonCancel","makePostItemDeleteRouteHandler","confirm","getFormParams","checkRemovedFiles","proceed","getErrors","details","errors","forEach","error","isUploadError","isUploadRootError","push","value","href","getViewModel","components","formComponent","id","count","summaryList","rows","uploadingLabel","index","proxyUrl","uploadUrl","formAction","uploadId","componentsBefore","slice","checkUploadStatus","depth","initiateAndStoreNewUpload","statusResponse","err","isBoom","output","statusCode","NOT_FOUND","valueOf","badRequest","uploadStatus","initiated","Error","logger","gatewayTimeout","toFixed","delay","info","validationResult","validate","stripUnknown","processUploadedFiles","validatedItem","validatedStatus","rawFile","uploadedFiles","Array","isArray","allErrors","complete","perFileState","unshift","cacheService","server","setFlash","some","f","mergeState","filesUpdated","options","schema","getFormMetadata","services","formsService","max","Math","min","formMetadata","slug","notificationEmail","newUpload","accept"],"sources":["../../../../../src/server/plugins/engine/pageControllers/FileUploadPageController.ts"],"sourcesContent":["import { ComponentType, type PageFileUpload } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport { wait } from '@hapi/hoek'\nimport { StatusCodes } from 'http-status-codes'\nimport { type ValidationErrorItem } from 'joi'\n\nimport {\n FileUploadField,\n tempItemSchema\n} from '~/src/server/plugins/engine/components/FileUploadField.js'\nimport { type FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n getCacheService,\n getError,\n getExponentialBackoffDelay\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport { getProxyUrlForLocalDevelopment } from '~/src/server/plugins/engine/pageControllers/helpers/index.js'\nimport {\n getUploadStatus,\n initiateUpload\n} from '~/src/server/plugins/engine/services/uploadService.js'\nimport {\n FileStatus,\n UploadStatus,\n type AnyFormRequest,\n type FeaturedFormPageViewModel,\n type FileState,\n type FileUpload,\n type FormContext,\n type FormContextRequest,\n type FormSubmissionError,\n type FormSubmissionState,\n type ItemDeletePageViewModel,\n type UploadInitiateResponse,\n type UploadStatusFileResponse\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nconst MAX_UPLOADS = 25\nconst CDP_UPLOAD_TIMEOUT_MS = 60000 // 1 minute\n\nexport function prepareStatus(status: UploadStatusFileResponse) {\n const file = status.form.file\n const isPending = file.fileStatus === FileStatus.pending\n\n if (!file.errorMessage && isPending) {\n file.errorMessage = 'The selected file has not fully uploaded'\n }\n\n return status\n}\n\nfunction prepareFileState(fileState: FileState) {\n prepareStatus(fileState.status)\n\n return fileState\n}\n\nexport class FileUploadPageController extends QuestionPageController {\n declare pageDef: PageFileUpload\n\n fileUpload: FileUploadField\n fileDeleteViewName = 'item-delete'\n\n constructor(model: FormModel, pageDef: PageFileUpload) {\n super(model, pageDef)\n\n const { collection } = this\n\n // Get the file upload fields from the collection\n const fileUploads = collection.fields.filter(\n (field): field is FileUploadField =>\n field.type === ComponentType.FileUploadField\n )\n\n const fileUpload = fileUploads.at(0)\n\n // Assert we have exactly 1 file upload component\n if (!fileUpload || fileUploads.length > 1) {\n throw Boom.badImplementation(\n `Expected 1 FileUploadFieldComponent in FileUploadPageController '${pageDef.path}'`\n )\n }\n\n // Assert the file upload component is the first form component\n if (collection.fields.indexOf(fileUpload) !== 0) {\n throw Boom.badImplementation(\n `Expected '${fileUpload.name}' to be the first form component in FileUploadPageController '${pageDef.path}'`\n )\n }\n\n // Assign the file upload component to the controller\n this.fileUpload = fileUpload\n this.viewName = 'file-upload'\n }\n\n /**\n * Get supplementary state keys for clearing file upload state.\n * Returns the nested upload path for FileUploadField components only.\n * @param component - The component to get supplementary state keys for\n * @returns Array containing the nested upload path, e.g., [\"upload['/page-path']\"]\n * or ['upload'] if no page path is available. Returns empty array for non-FileUploadField components.\n */\n getStateKeys(component: FormComponent): string[] {\n // Only return upload keys for FileUploadField components\n if (!(component instanceof FileUploadField)) {\n return []\n }\n\n const pagePath = component.page?.path\n return pagePath ? [`upload['${pagePath}']`] : ['upload']\n }\n\n getFormDataFromState(\n request: FormContextRequest | undefined,\n state: FormSubmissionState\n ) {\n const { fileUpload } = this\n\n const payload = super.getFormDataFromState(request, state)\n const files = this.getFilesFromState(state)\n\n // Append the files to the payload\n payload[fileUpload.name] = files.length ? files : undefined\n\n return payload\n }\n\n async getState(request: AnyFormRequest) {\n const { fileUpload } = this\n\n // Get the actual state\n const state = await super.getState(request)\n const files = this.getFilesFromState(state)\n\n // Overwrite the files with those in the upload state\n state[fileUpload.name] = files\n\n return this.refreshUpload(request, state)\n }\n\n /**\n * Get the uploaded files from state.\n */\n getFilesFromState(state: FormSubmissionState) {\n const { path } = this\n\n const uploadState = state.upload?.[path]\n return uploadState?.files ?? []\n }\n\n /**\n * Get the initiated upload from state.\n */\n getUploadFromState(state: FormSubmissionState) {\n const { path } = this\n\n const uploadState = state.upload?.[path]\n return uploadState?.upload\n }\n\n makeGetItemDeleteRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { viewModel } = this\n const { params } = request\n const { state } = context\n\n const files = this.getFilesFromState(state)\n\n const fileToRemove = files.find(\n ({ status }) => status.form.file.fileId === params.itemId\n )\n\n if (!fileToRemove) {\n throw Boom.notFound('File to delete not found')\n }\n\n const { filename } = fileToRemove.status.form.file\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n return h.view(this.fileDeleteViewName, {\n ...viewModel,\n context,\n backLink: this.getBackLink(request, context, t),\n pageTitle: t('pages.fileUpload.removeFileTitle'),\n itemTitle: filename,\n confirmation: { text: t('pages.fileUpload.removeFileBody') },\n buttonConfirm: { text: t('pages.fileUpload.removeFileButton') },\n buttonCancel: { text: t('pages.fileUpload.cancel') },\n t\n } satisfies ItemDeletePageViewModel)\n }\n }\n\n makePostItemDeleteRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { state } = context\n\n const { confirm } = this.getFormParams(request)\n\n // Check for any removed files in the POST payload\n if (confirm) {\n await this.checkRemovedFiles(request, state)\n return this.proceed(request, h, path)\n }\n\n return this.proceed(request, h)\n }\n }\n\n getErrors(details?: ValidationErrorItem[]) {\n const { fileUpload } = this\n\n if (details) {\n const errors: FormSubmissionError[] = []\n\n details.forEach((error) => {\n const isUploadError = error.path[0] === fileUpload.name\n const isUploadRootError = isUploadError && error.path.length === 1\n\n if (!isUploadError || isUploadRootError) {\n // The error is for the root of the upload or another\n // field on the page so defer to the getError helper\n errors.push(getError(error))\n } else {\n const { context, path, type } = error\n\n if (type === 'object.unknown' && path.at(-1) === 'errorMessage') {\n const value = context?.value as string | undefined\n\n if (value) {\n const name = fileUpload.name\n const text = typeof value === 'string' ? value : 'Unknown error'\n const href = `#${name}`\n\n errors.push({ path, href, name, text })\n }\n }\n }\n })\n\n return errors\n }\n }\n\n getViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): FeaturedFormPageViewModel {\n const { fileUpload } = this\n const { state } = context\n const { t } = translator\n\n const upload = this.getUploadFromState(state)\n\n const viewModel = super.getViewModel(request, context, translator)\n const { components } = viewModel\n\n // Featured form component\n const [formComponent] = components.filter(\n ({ model }) => model.id === fileUpload.name\n )\n\n formComponent.model.upload = {\n count: formComponent.model.upload?.count ?? 0,\n summaryList: formComponent.model.upload?.summaryList ?? { rows: [] },\n uploadingLabel: t('components.fileUploadField.uploading')\n }\n\n const index = components.indexOf(formComponent)\n\n const proxyUrl = getProxyUrlForLocalDevelopment(upload?.uploadUrl)\n\n return {\n ...viewModel,\n formAction: upload?.uploadUrl,\n uploadId: upload?.uploadId,\n formComponent,\n\n // Split out components before/after\n componentsBefore: components.slice(0, index),\n components: components.slice(index),\n proxyUrl,\n t\n }\n }\n\n /**\n * Refreshes the CDP upload and files in the\n * state and checks for any removed files.\n *\n * If an upload exists and hasn't been consumed\n * it gets re-used, otherwise we initiate a new one.\n * @param request - the hapi request\n * @param state - the form state\n */\n private async refreshUpload(\n request: AnyFormRequest,\n state: FormSubmissionState\n ) {\n state = await this.checkUploadStatus(request, state)\n\n return state\n }\n\n /**\n * If an upload exists and hasn't been consumed\n * it gets re-used, otherwise a new one is initiated.\n * @param request - the hapi request\n * @param state - the form state\n * @param depth - the number of retries so far\n */\n private async checkUploadStatus(\n request: AnyFormRequest,\n state: FormSubmissionState,\n depth = 1\n ): Promise<FormSubmissionState> {\n const upload = this.getUploadFromState(state)\n const files = this.getFilesFromState(state)\n\n // If no upload exists, initiate a new one.\n if (!upload?.uploadId) {\n return this.initiateAndStoreNewUpload(request, state)\n }\n\n const uploadId = upload.uploadId\n\n let statusResponse\n\n try {\n statusResponse = await getUploadStatus(uploadId)\n } catch (err) {\n // if the user loads a file upload page and queries the cached upload, after the upload has\n // expired in CDP, we will get a 404 from the getUploadStatus endpoint.\n // In this case we want to initiate a new upload and return that state, so the form\n // doesn't blow up for the end user.\n if (\n Boom.isBoom(err) &&\n err.output.statusCode === StatusCodes.NOT_FOUND.valueOf()\n ) {\n return this.initiateAndStoreNewUpload(request, state)\n }\n throw err\n }\n\n if (!statusResponse) {\n throw Boom.badRequest(\n `Unexpected empty response from getUploadStatus for ${uploadId}`\n )\n }\n\n // Re-use the upload if it is still in the \"initiated\" state.\n if (statusResponse.uploadStatus === UploadStatus.initiated) {\n return state\n }\n\n if (statusResponse.uploadStatus === UploadStatus.pending) {\n // Using exponential backoff delays:\n // Depth 1: 2000ms, Depth 2: 4000ms, Depth 3: 8000ms, Depth 4: 16000ms, Depth 5+: 30000ms (capped)\n // A depth of 5 (or more) implies cumulative delays roughly reaching 55 seconds.\n if (depth >= 5) {\n const err = new Error(\n `Exceeded cumulative retry delay for ${uploadId} (depth: ${depth}). Re-initiating a new upload.`\n )\n request.logger.error(\n err,\n `[uploadTimeout] Exceeded cumulative retry delay for uploadId: ${uploadId} at depth: ${depth} - re-initiating new upload`\n )\n await this.initiateAndStoreNewUpload(request, state)\n throw Boom.gatewayTimeout(\n `Timed out waiting for ${uploadId} after cumulative retries exceeding ${((CDP_UPLOAD_TIMEOUT_MS - 5000) / 1000).toFixed(0)} seconds`\n )\n }\n const delay = getExponentialBackoffDelay(depth)\n request.logger.info(\n `[uploadRetry] Waiting ${delay / 1000} seconds for uploadId: ${uploadId} to complete (retry depth: ${depth})`\n )\n await wait(delay)\n return this.checkUploadStatus(request, state, depth + 1)\n }\n\n // Only add to files state if the file validates.\n // This secures against html tampering of the file input\n // (e.g. changing it to a simple text field or similar).\n const validationResult = tempItemSchema.validate(\n { uploadId, status: statusResponse },\n { stripUnknown: true }\n )\n const error = validationResult.error\n\n if (error) {\n return this.initiateAndStoreNewUpload(request, state)\n }\n\n // CDP returns form.file as a single object for one file,\n // or an array for multiple files. The Joi schema normalises\n // both to an array via .single().\n await this.processUploadedFiles(\n request,\n state,\n validationResult.value,\n files,\n upload\n )\n\n return this.initiateAndStoreNewUpload(request, state)\n }\n\n /**\n * Processes the uploaded files from a CDP status response.\n * Complete files are added to state, rejected/pending files\n * have their error messages flashed.\n * @param request - the hapi request\n * @param state - the form state\n * @param validatedItem - the Joi-validated upload item\n * @param files - the current files array from state\n * @param upload - the current upload initiation response\n */\n private async processUploadedFiles(\n request: AnyFormRequest,\n state: FormSubmissionState,\n validatedItem: FileState,\n files: FileState[],\n upload: UploadInitiateResponse | undefined\n ) {\n const { uploadId } = validatedItem\n const validatedStatus = validatedItem.status\n const rawFile = validatedStatus.form.file as unknown as\n | FileUpload\n | FileUpload[]\n const uploadedFiles = Array.isArray(rawFile) ? rawFile : [rawFile]\n\n const allErrors: FormSubmissionError[] = []\n\n for (const file of uploadedFiles) {\n if (file.fileStatus === FileStatus.complete) {\n const perFileState: FileState = {\n uploadId,\n status: {\n ...validatedStatus,\n form: { file }\n } as FileState['status']\n }\n files.unshift(prepareFileState(perFileState))\n } else {\n // Collect the error for rejected/pending files.\n const { fileUpload } = this\n const name = fileUpload.name\n const text = file.errorMessage ?? 'Unknown error'\n allErrors.push({ path: [name], href: `#${name}`, name, text })\n }\n }\n\n if (allErrors.length) {\n const cacheService = getCacheService(request.server)\n cacheService.setFlash(request, { errors: allErrors })\n }\n\n if (uploadedFiles.some((f) => f.fileStatus === FileStatus.complete)) {\n await this.mergeState(request, state, {\n upload: { [this.path]: { files, upload } }\n })\n }\n }\n\n /**\n * Checks the payload for a file getting removed\n * and removes it from the upload files if found\n * @param request - the hapi request\n * @param state - the form state\n * @returns updated state if any files have been removed\n */\n private async checkRemovedFiles(\n request: FormRequestPayload,\n state: FormSubmissionState\n ) {\n const { path } = this\n const { params } = request\n\n const upload = this.getUploadFromState(state)\n const files = this.getFilesFromState(state)\n\n const filesUpdated = files.filter(\n ({ status }) => status.form.file.fileId !== params.itemId\n )\n\n if (filesUpdated.length === files.length) {\n return\n }\n\n await this.mergeState(request, state, {\n upload: { [path]: { files: filesUpdated, upload } }\n })\n }\n\n /**\n * Initiates a CDP file upload and stores in the upload state\n * @param request - the hapi request\n * @param state - the form state\n */\n private async initiateAndStoreNewUpload(\n request: AnyFormRequest,\n state: FormSubmissionState\n ) {\n const { fileUpload, href, path } = this\n const { options, schema } = fileUpload\n const { getFormMetadata } = this.model.services.formsService\n\n const files = this.getFilesFromState(state)\n\n // Reset the upload in state\n let upload: UploadInitiateResponse | undefined\n\n // Don't initiate anymore after minimum of `schema.max` or MAX_UPLOADS\n const max = Math.min(schema.max ?? MAX_UPLOADS, MAX_UPLOADS)\n\n if (files.length < max) {\n const formMetadata = await getFormMetadata(request.params.slug)\n const notificationEmail =\n formMetadata.notificationEmail ?? 'defraforms@defra.gov.uk'\n\n const newUpload = await initiateUpload(\n href,\n notificationEmail,\n options.accept\n )\n\n if (newUpload === undefined) {\n throw Boom.badRequest('Unexpected empty response from initiateUpload')\n }\n\n upload = newUpload\n }\n\n return this.mergeState(request, state, {\n upload: { [path]: { files, upload } }\n })\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -326,11 +326,10 @@ export class RepeatPageController extends QuestionPageController {
|
|
|
326
326
|
errors
|
|
327
327
|
} = context;
|
|
328
328
|
const {
|
|
329
|
-
t
|
|
329
|
+
t,
|
|
330
|
+
tPage
|
|
330
331
|
} = translator;
|
|
331
|
-
const
|
|
332
|
-
title
|
|
333
|
-
} = repeat.options;
|
|
332
|
+
const title = tPage(this.pageDef, 'repeatTitle') || repeat.options.title;
|
|
334
333
|
const summaryList = {
|
|
335
334
|
classes: 'govuk-summary-list--long-actions',
|
|
336
335
|
rows: []
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RepeatPageController.js","names":["randomUUID","Boom","Joi","isRepeatState","redirectPath","QuestionPageController","FormAction","RepeatPageController","listSummaryViewName","listDeleteViewName","repeat","allowSaveAndExit","constructor","model","pageDef","options","schema","itemId","string","uuid","required","collection","formSchema","append","stateSchema","object","keys","name","array","items","min","max","label","title","getFormParams","request","params","payload","getFormDataFromState","state","list","getListFromState","getItemId","item","getItemFromList","getStateFromValidForm","badRequest","itemState","updated","newList","push","indexOf","proceed","h","nextPath","getSummaryPath","find","values","makeGetRouteHandler","context","path","query","summaryPath","returnUrl","force","length","makeGetListSummaryRouteHandler","translator","getTranslator","t","viewModel","getListSummaryViewModel","view","makePostListSummaryRouteHandler","action","hasErrorMin","Continue","hasErrorMax","AddAnother","count","errors","href","text","SaveAndExit","handleSaveAndExit","getNextPath","makeGetItemDeleteRouteHandler","notFound","backLink","getBackLink","pageTitle","itemTitle","buttonConfirm","buttonCancel","makePostItemDeleteRouteHandler","confirm","splice","update","mergeState","getViewModel","tPage","itemNumber","repeatCaption","sectionTitle","isForceAccess","summaryList","classes","rows","Array","isArray","forEach","index","getHref","visuallyHiddenText","itemDisplayText","fields","getDisplayStringFromState","key","value","actions","repeatTitle","showTitle","checkAnswers","shouldShowSaveAndExit","server"],"sources":["../../../../../src/server/plugins/engine/pageControllers/RepeatPageController.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\n\nimport { type PageRepeat, type Repeat } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport Joi from 'joi'\n\nimport { isRepeatState } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { redirectPath } from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport {\n type FormContext,\n type FormContextRequest,\n type FormPageViewModel,\n type FormPayload,\n type FormSubmissionState,\n type ItemDeletePageViewModel,\n type RepeatItemState,\n type RepeatListState,\n type RepeaterSummaryPageViewModel,\n type SummaryList,\n type SummaryListAction\n} from '~/src/server/plugins/engine/types.js'\nimport {\n FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nexport class RepeatPageController extends QuestionPageController {\n declare pageDef: PageRepeat\n\n listSummaryViewName = 'repeat-list-summary'\n listDeleteViewName = 'item-delete'\n repeat: Repeat\n allowSaveAndExit = true\n\n constructor(model: FormModel, pageDef: PageRepeat) {\n super(model, pageDef)\n\n this.repeat = pageDef.repeat\n\n const { options, schema } = this.repeat\n const itemId = Joi.string().uuid().required()\n\n this.collection.formSchema = this.collection.formSchema.append({ itemId })\n this.collection.stateSchema = Joi.object<RepeatItemState>().keys({\n [options.name]: Joi.array()\n .items(this.collection.stateSchema.append({ itemId }))\n .min(schema.min)\n .max(schema.max)\n .label(`${options.title} list`)\n .required()\n })\n }\n\n get keys() {\n const { repeat } = this\n return [repeat.options.name, ...super.keys]\n }\n\n getFormParams(request?: FormContextRequest) {\n const params = super.getFormParams(request)\n\n // Apply an itemId to the form payload\n if (request?.payload) {\n params.itemId = request.params.itemId ?? randomUUID()\n }\n\n return params\n }\n\n getFormDataFromState(\n request: FormContextRequest | undefined,\n state: FormSubmissionState\n ) {\n const { repeat } = this\n\n const params = this.getFormParams(request)\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n\n // Create payload with repeater list state\n if (!itemId) {\n return {\n ...params,\n [repeat.options.name]: list\n }\n }\n\n // Create payload with repeater item state\n const item = this.getItemFromList(list, itemId)\n\n return {\n ...params,\n ...item\n }\n }\n\n getStateFromValidForm(\n request: FormContextRequest,\n state: FormSubmissionState,\n payload: FormPayload\n ) {\n const itemId = this.getItemId(request)\n\n if (!itemId) {\n throw Boom.badRequest('No item ID found')\n }\n\n const list = this.getListFromState(state)\n const item = this.getItemFromList(list, itemId)\n\n const itemState = super.getStateFromValidForm(request, state, payload)\n const updated: RepeatItemState = { ...itemState, itemId }\n const newList = [...list]\n\n if (!item) {\n // Adding a new item\n newList.push(updated)\n } else {\n // Update an existing item\n newList[list.indexOf(item)] = updated\n }\n\n return {\n [this.repeat.options.name]: newList\n }\n }\n\n proceed(request: FormContextRequest, h: FormResponseToolkit) {\n const nextPath = this.getSummaryPath(request)\n return super.proceed(request, h, nextPath)\n }\n\n getItemFromList(list: RepeatListState, itemId?: string) {\n return list.find((item) => item.itemId === itemId)\n }\n\n getListFromState(state: FormSubmissionState) {\n const { name } = this.repeat.options\n const values = state[name]\n\n return isRepeatState(values) ? values : []\n }\n\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { query } = request\n const { state } = context\n\n const itemId = this.getItemId(request)\n const list = this.getListFromState(state)\n\n if (!itemId) {\n const summaryPath = this.getSummaryPath(request)\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl,\n force: query.force\n })\n\n // Only redirect to new item when list is empty\n return super.proceed(request, h, list.length ? summaryPath : nextPath)\n }\n\n return super.makeGetRouteHandler()(request, context, h)\n }\n }\n\n makeGetListSummaryRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { query } = request\n const { state } = context\n\n const list = this.getListFromState(state)\n\n if (!list.length) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n const viewModel = this.getListSummaryViewModel(\n request,\n context,\n list,\n translator\n )\n\n return h.view(this.listSummaryViewName, {\n ...viewModel,\n t\n })\n }\n }\n\n makePostListSummaryRouteHandler() {\n return (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path, repeat } = this\n const { query } = request\n const { schema } = repeat\n const { state } = context\n\n const list = this.getListFromState(state)\n\n if (!list.length) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n const { action } = this.getFormParams(request)\n\n const hasErrorMin =\n action === FormAction.Continue && list.length < schema.min\n\n const hasErrorMax =\n (action === FormAction.AddAnother && list.length >= schema.max) ||\n (action === FormAction.Continue && list.length > schema.max)\n\n // Show error if repeat limits apply\n if (hasErrorMin || hasErrorMax) {\n const count = hasErrorMax ? schema.max : schema.min\n\n context.errors = [\n {\n path: [],\n href: '',\n name: '',\n text: hasErrorMax\n ? t('pages.repeater.tooMany', { count })\n : t('pages.repeater.tooFew', { count })\n }\n ]\n\n const viewModel = this.getListSummaryViewModel(\n request,\n context,\n list,\n translator\n )\n\n return h.view(this.listSummaryViewName, {\n ...viewModel,\n t\n })\n }\n\n if (action === FormAction.AddAnother) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n // Check if this is a save-and-exit action\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n const nextPath = this.getNextPath(context)\n return super.proceed(request, h, nextPath)\n }\n }\n\n makeGetItemDeleteRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { viewModel } = this\n const { state } = context\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n if (!item || list.length === 1) {\n throw Boom.notFound(\n item\n ? t('pages.repeater.lastItemCannotBeRemoved')\n : t('pages.repeater.itemToRemoveNotFound')\n )\n }\n\n const { title } = this.repeat.options\n\n return h.view(this.listDeleteViewName, {\n ...viewModel,\n context,\n backLink: this.getBackLink(request, context, t),\n pageTitle: t('pages.repeater.removeAnswer'),\n itemTitle: `${title} ${list.indexOf(item) + 1}`,\n buttonConfirm: { text: t('pages.repeater.remove') },\n buttonCancel: { text: t('pages.repeater.cancel') },\n t\n } satisfies ItemDeletePageViewModel)\n }\n }\n\n makePostItemDeleteRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { repeat } = this\n const { state } = context\n\n const { confirm } = this.getFormParams(request)\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const { t } = this.getTranslator(request)\n\n if (!item || list.length === 1) {\n throw Boom.notFound(\n item\n ? t('pages.repeater.lastItemCannotBeRemoved')\n : t('pages.repeater.itemToRemoveNotFound')\n )\n }\n\n // Remove the item from the list\n if (confirm) {\n list.splice(list.indexOf(item), 1)\n\n const update = {\n [repeat.options.name]: list\n }\n\n await this.mergeState(request, state, update)\n }\n\n return this.proceed(request, h)\n }\n }\n\n getViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): FormPageViewModel {\n const { state } = context\n const { tPage } = translator\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const viewModel = super.getViewModel(request, context, translator)\n const itemNumber = item ? list.indexOf(item) + 1 : list.length + 1\n const title =\n tPage(this.pageDef, 'repeatTitle') || this.pageDef.repeat.options.title\n const repeatCaption = `${title} ${itemNumber}`\n\n return {\n ...viewModel,\n\n sectionTitle: viewModel.sectionTitle\n ? `${viewModel.sectionTitle}: ${repeatCaption}`\n : repeatCaption\n }\n }\n\n getListSummaryViewModel(\n request: FormContextRequest,\n context: FormContext,\n list: RepeatListState,\n translator: Translator\n ): RepeaterSummaryPageViewModel {\n const { collection, href, repeat } = this\n const { query } = request\n const { isForceAccess, errors } = context\n\n const { t } = translator\n\n const { title } = repeat.options\n\n const summaryList: SummaryList = {\n classes: 'govuk-summary-list--long-actions',\n rows: []\n }\n\n let count = 0\n\n if (Array.isArray(list)) {\n count = list.length\n\n const summaryPath = this.getSummaryPath(request)\n\n list.forEach((item, index) => {\n const items: SummaryListAction[] = []\n\n // Remove summary list actions from previews\n if (!isForceAccess) {\n items.push({\n href: redirectPath(`${href}/${item.itemId}`, {\n returnUrl: query.returnUrl ?? this.getHref(summaryPath)\n }),\n text: t('pages.repeater.change'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: t('pages.repeater.visuallyHiddenItem', {\n index: index + 1\n })\n })\n\n if (count > 1) {\n items.push({\n href: redirectPath(`${href}/${item.itemId}/confirm-delete`, {\n returnUrl: query.returnUrl\n }),\n text: t('pages.repeater.remove'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: t('pages.repeater.visuallyHiddenItem', {\n index: index + 1\n })\n })\n }\n }\n\n const itemDisplayText = collection.fields.length\n ? collection.fields[0].getDisplayStringFromState(item, translator)\n : ''\n\n summaryList.rows.push({\n key: {\n text: `${title} ${index + 1}`\n },\n value: {\n text: itemDisplayText || t('pages.repeater.notProvided')\n },\n actions: {\n items\n }\n })\n })\n }\n\n return {\n ...this.viewModel,\n backLink: this.getBackLink(request, context, t),\n repeatTitle: title,\n pageTitle: t('pages.repeater.pageTitle', { count }),\n showTitle: true,\n context,\n errors,\n checkAnswers: [{ summaryList }],\n allowSaveAndExit: this.shouldShowSaveAndExit(request.server)\n }\n }\n\n getSummaryPath(request?: FormContextRequest) {\n const { path } = this\n\n const summaryPath = super.getSummaryPath()\n\n if (!request) {\n return summaryPath\n }\n\n const { query } = request\n\n return redirectPath(`${path}${summaryPath}`, {\n returnUrl: query.returnUrl\n })\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"RepeatPageController.js","names":["randomUUID","Boom","Joi","isRepeatState","redirectPath","QuestionPageController","FormAction","RepeatPageController","listSummaryViewName","listDeleteViewName","repeat","allowSaveAndExit","constructor","model","pageDef","options","schema","itemId","string","uuid","required","collection","formSchema","append","stateSchema","object","keys","name","array","items","min","max","label","title","getFormParams","request","params","payload","getFormDataFromState","state","list","getListFromState","getItemId","item","getItemFromList","getStateFromValidForm","badRequest","itemState","updated","newList","push","indexOf","proceed","h","nextPath","getSummaryPath","find","values","makeGetRouteHandler","context","path","query","summaryPath","returnUrl","force","length","makeGetListSummaryRouteHandler","translator","getTranslator","t","viewModel","getListSummaryViewModel","view","makePostListSummaryRouteHandler","action","hasErrorMin","Continue","hasErrorMax","AddAnother","count","errors","href","text","SaveAndExit","handleSaveAndExit","getNextPath","makeGetItemDeleteRouteHandler","notFound","backLink","getBackLink","pageTitle","itemTitle","buttonConfirm","buttonCancel","makePostItemDeleteRouteHandler","confirm","splice","update","mergeState","getViewModel","tPage","itemNumber","repeatCaption","sectionTitle","isForceAccess","summaryList","classes","rows","Array","isArray","forEach","index","getHref","visuallyHiddenText","itemDisplayText","fields","getDisplayStringFromState","key","value","actions","repeatTitle","showTitle","checkAnswers","shouldShowSaveAndExit","server"],"sources":["../../../../../src/server/plugins/engine/pageControllers/RepeatPageController.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\n\nimport { type PageRepeat, type Repeat } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport Joi from 'joi'\n\nimport { isRepeatState } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { redirectPath } from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport {\n type FormContext,\n type FormContextRequest,\n type FormPageViewModel,\n type FormPayload,\n type FormSubmissionState,\n type ItemDeletePageViewModel,\n type RepeatItemState,\n type RepeatListState,\n type RepeaterSummaryPageViewModel,\n type SummaryList,\n type SummaryListAction\n} from '~/src/server/plugins/engine/types.js'\nimport {\n FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nexport class RepeatPageController extends QuestionPageController {\n declare pageDef: PageRepeat\n\n listSummaryViewName = 'repeat-list-summary'\n listDeleteViewName = 'item-delete'\n repeat: Repeat\n allowSaveAndExit = true\n\n constructor(model: FormModel, pageDef: PageRepeat) {\n super(model, pageDef)\n\n this.repeat = pageDef.repeat\n\n const { options, schema } = this.repeat\n const itemId = Joi.string().uuid().required()\n\n this.collection.formSchema = this.collection.formSchema.append({ itemId })\n this.collection.stateSchema = Joi.object<RepeatItemState>().keys({\n [options.name]: Joi.array()\n .items(this.collection.stateSchema.append({ itemId }))\n .min(schema.min)\n .max(schema.max)\n .label(`${options.title} list`)\n .required()\n })\n }\n\n get keys() {\n const { repeat } = this\n return [repeat.options.name, ...super.keys]\n }\n\n getFormParams(request?: FormContextRequest) {\n const params = super.getFormParams(request)\n\n // Apply an itemId to the form payload\n if (request?.payload) {\n params.itemId = request.params.itemId ?? randomUUID()\n }\n\n return params\n }\n\n getFormDataFromState(\n request: FormContextRequest | undefined,\n state: FormSubmissionState\n ) {\n const { repeat } = this\n\n const params = this.getFormParams(request)\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n\n // Create payload with repeater list state\n if (!itemId) {\n return {\n ...params,\n [repeat.options.name]: list\n }\n }\n\n // Create payload with repeater item state\n const item = this.getItemFromList(list, itemId)\n\n return {\n ...params,\n ...item\n }\n }\n\n getStateFromValidForm(\n request: FormContextRequest,\n state: FormSubmissionState,\n payload: FormPayload\n ) {\n const itemId = this.getItemId(request)\n\n if (!itemId) {\n throw Boom.badRequest('No item ID found')\n }\n\n const list = this.getListFromState(state)\n const item = this.getItemFromList(list, itemId)\n\n const itemState = super.getStateFromValidForm(request, state, payload)\n const updated: RepeatItemState = { ...itemState, itemId }\n const newList = [...list]\n\n if (!item) {\n // Adding a new item\n newList.push(updated)\n } else {\n // Update an existing item\n newList[list.indexOf(item)] = updated\n }\n\n return {\n [this.repeat.options.name]: newList\n }\n }\n\n proceed(request: FormContextRequest, h: FormResponseToolkit) {\n const nextPath = this.getSummaryPath(request)\n return super.proceed(request, h, nextPath)\n }\n\n getItemFromList(list: RepeatListState, itemId?: string) {\n return list.find((item) => item.itemId === itemId)\n }\n\n getListFromState(state: FormSubmissionState) {\n const { name } = this.repeat.options\n const values = state[name]\n\n return isRepeatState(values) ? values : []\n }\n\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { query } = request\n const { state } = context\n\n const itemId = this.getItemId(request)\n const list = this.getListFromState(state)\n\n if (!itemId) {\n const summaryPath = this.getSummaryPath(request)\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl,\n force: query.force\n })\n\n // Only redirect to new item when list is empty\n return super.proceed(request, h, list.length ? summaryPath : nextPath)\n }\n\n return super.makeGetRouteHandler()(request, context, h)\n }\n }\n\n makeGetListSummaryRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { query } = request\n const { state } = context\n\n const list = this.getListFromState(state)\n\n if (!list.length) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n const viewModel = this.getListSummaryViewModel(\n request,\n context,\n list,\n translator\n )\n\n return h.view(this.listSummaryViewName, {\n ...viewModel,\n t\n })\n }\n }\n\n makePostListSummaryRouteHandler() {\n return (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path, repeat } = this\n const { query } = request\n const { schema } = repeat\n const { state } = context\n\n const list = this.getListFromState(state)\n\n if (!list.length) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n const { action } = this.getFormParams(request)\n\n const hasErrorMin =\n action === FormAction.Continue && list.length < schema.min\n\n const hasErrorMax =\n (action === FormAction.AddAnother && list.length >= schema.max) ||\n (action === FormAction.Continue && list.length > schema.max)\n\n // Show error if repeat limits apply\n if (hasErrorMin || hasErrorMax) {\n const count = hasErrorMax ? schema.max : schema.min\n\n context.errors = [\n {\n path: [],\n href: '',\n name: '',\n text: hasErrorMax\n ? t('pages.repeater.tooMany', { count })\n : t('pages.repeater.tooFew', { count })\n }\n ]\n\n const viewModel = this.getListSummaryViewModel(\n request,\n context,\n list,\n translator\n )\n\n return h.view(this.listSummaryViewName, {\n ...viewModel,\n t\n })\n }\n\n if (action === FormAction.AddAnother) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n // Check if this is a save-and-exit action\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n const nextPath = this.getNextPath(context)\n return super.proceed(request, h, nextPath)\n }\n }\n\n makeGetItemDeleteRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { viewModel } = this\n const { state } = context\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n if (!item || list.length === 1) {\n throw Boom.notFound(\n item\n ? t('pages.repeater.lastItemCannotBeRemoved')\n : t('pages.repeater.itemToRemoveNotFound')\n )\n }\n\n const { title } = this.repeat.options\n\n return h.view(this.listDeleteViewName, {\n ...viewModel,\n context,\n backLink: this.getBackLink(request, context, t),\n pageTitle: t('pages.repeater.removeAnswer'),\n itemTitle: `${title} ${list.indexOf(item) + 1}`,\n buttonConfirm: { text: t('pages.repeater.remove') },\n buttonCancel: { text: t('pages.repeater.cancel') },\n t\n } satisfies ItemDeletePageViewModel)\n }\n }\n\n makePostItemDeleteRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { repeat } = this\n const { state } = context\n\n const { confirm } = this.getFormParams(request)\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const { t } = this.getTranslator(request)\n\n if (!item || list.length === 1) {\n throw Boom.notFound(\n item\n ? t('pages.repeater.lastItemCannotBeRemoved')\n : t('pages.repeater.itemToRemoveNotFound')\n )\n }\n\n // Remove the item from the list\n if (confirm) {\n list.splice(list.indexOf(item), 1)\n\n const update = {\n [repeat.options.name]: list\n }\n\n await this.mergeState(request, state, update)\n }\n\n return this.proceed(request, h)\n }\n }\n\n getViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): FormPageViewModel {\n const { state } = context\n const { tPage } = translator\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const viewModel = super.getViewModel(request, context, translator)\n const itemNumber = item ? list.indexOf(item) + 1 : list.length + 1\n const title =\n tPage(this.pageDef, 'repeatTitle') || this.pageDef.repeat.options.title\n const repeatCaption = `${title} ${itemNumber}`\n\n return {\n ...viewModel,\n\n sectionTitle: viewModel.sectionTitle\n ? `${viewModel.sectionTitle}: ${repeatCaption}`\n : repeatCaption\n }\n }\n\n getListSummaryViewModel(\n request: FormContextRequest,\n context: FormContext,\n list: RepeatListState,\n translator: Translator\n ): RepeaterSummaryPageViewModel {\n const { collection, href, repeat } = this\n const { query } = request\n const { isForceAccess, errors } = context\n\n const { t, tPage } = translator\n\n const title = tPage(this.pageDef, 'repeatTitle') || repeat.options.title\n\n const summaryList: SummaryList = {\n classes: 'govuk-summary-list--long-actions',\n rows: []\n }\n\n let count = 0\n\n if (Array.isArray(list)) {\n count = list.length\n\n const summaryPath = this.getSummaryPath(request)\n\n list.forEach((item, index) => {\n const items: SummaryListAction[] = []\n\n // Remove summary list actions from previews\n if (!isForceAccess) {\n items.push({\n href: redirectPath(`${href}/${item.itemId}`, {\n returnUrl: query.returnUrl ?? this.getHref(summaryPath)\n }),\n text: t('pages.repeater.change'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: t('pages.repeater.visuallyHiddenItem', {\n index: index + 1\n })\n })\n\n if (count > 1) {\n items.push({\n href: redirectPath(`${href}/${item.itemId}/confirm-delete`, {\n returnUrl: query.returnUrl\n }),\n text: t('pages.repeater.remove'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: t('pages.repeater.visuallyHiddenItem', {\n index: index + 1\n })\n })\n }\n }\n\n const itemDisplayText = collection.fields.length\n ? collection.fields[0].getDisplayStringFromState(item, translator)\n : ''\n\n summaryList.rows.push({\n key: {\n text: `${title} ${index + 1}`\n },\n value: {\n text: itemDisplayText || t('pages.repeater.notProvided')\n },\n actions: {\n items\n }\n })\n })\n }\n\n return {\n ...this.viewModel,\n backLink: this.getBackLink(request, context, t),\n repeatTitle: title,\n pageTitle: t('pages.repeater.pageTitle', { count }),\n showTitle: true,\n context,\n errors,\n checkAnswers: [{ summaryList }],\n allowSaveAndExit: this.shouldShowSaveAndExit(request.server)\n }\n }\n\n getSummaryPath(request?: FormContextRequest) {\n const { path } = this\n\n const summaryPath = super.getSummaryPath()\n\n if (!request) {\n return summaryPath\n }\n\n const { query } = request\n\n return redirectPath(`${path}${summaryPath}`, {\n returnUrl: query.returnUrl\n })\n }\n}\n"],"mappings":"AAAA,SAASA,UAAU,QAAQ,QAAQ;AAGnC,OAAOC,IAAI,MAAM,YAAY;AAC7B,OAAOC,GAAG,MAAM,KAAK;AAErB,SAASC,aAAa;AACtB,SAASC,YAAY;AAGrB,SAASC,sBAAsB;AAc/B,SACEC,UAAU;AAMZ,OAAO,MAAMC,oBAAoB,SAASF,sBAAsB,CAAC;EAG/DG,mBAAmB,GAAG,qBAAqB;EAC3CC,kBAAkB,GAAG,aAAa;EAClCC,MAAM;EACNC,gBAAgB,GAAG,IAAI;EAEvBC,WAAWA,CAACC,KAAgB,EAAEC,OAAmB,EAAE;IACjD,KAAK,CAACD,KAAK,EAAEC,OAAO,CAAC;IAErB,IAAI,CAACJ,MAAM,GAAGI,OAAO,CAACJ,MAAM;IAE5B,MAAM;MAAEK,OAAO;MAAEC;IAAO,CAAC,GAAG,IAAI,CAACN,MAAM;IACvC,MAAMO,MAAM,GAAGf,GAAG,CAACgB,MAAM,CAAC,CAAC,CAACC,IAAI,CAAC,CAAC,CAACC,QAAQ,CAAC,CAAC;IAE7C,IAAI,CAACC,UAAU,CAACC,UAAU,GAAG,IAAI,CAACD,UAAU,CAACC,UAAU,CAACC,MAAM,CAAC;MAAEN;IAAO,CAAC,CAAC;IAC1E,IAAI,CAACI,UAAU,CAACG,WAAW,GAAGtB,GAAG,CAACuB,MAAM,CAAkB,CAAC,CAACC,IAAI,CAAC;MAC/D,CAACX,OAAO,CAACY,IAAI,GAAGzB,GAAG,CAAC0B,KAAK,CAAC,CAAC,CACxBC,KAAK,CAAC,IAAI,CAACR,UAAU,CAACG,WAAW,CAACD,MAAM,CAAC;QAAEN;MAAO,CAAC,CAAC,CAAC,CACrDa,GAAG,CAACd,MAAM,CAACc,GAAG,CAAC,CACfC,GAAG,CAACf,MAAM,CAACe,GAAG,CAAC,CACfC,KAAK,CAAC,GAAGjB,OAAO,CAACkB,KAAK,OAAO,CAAC,CAC9Bb,QAAQ,CAAC;IACd,CAAC,CAAC;EACJ;EAEA,IAAIM,IAAIA,CAAA,EAAG;IACT,MAAM;MAAEhB;IAAO,CAAC,GAAG,IAAI;IACvB,OAAO,CAACA,MAAM,CAACK,OAAO,CAACY,IAAI,EAAE,GAAG,KAAK,CAACD,IAAI,CAAC;EAC7C;EAEAQ,aAAaA,CAACC,OAA4B,EAAE;IAC1C,MAAMC,MAAM,GAAG,KAAK,CAACF,aAAa,CAACC,OAAO,CAAC;;IAE3C;IACA,IAAIA,OAAO,EAAEE,OAAO,EAAE;MACpBD,MAAM,CAACnB,MAAM,GAAGkB,OAAO,CAACC,MAAM,CAACnB,MAAM,IAAIjB,UAAU,CAAC,CAAC;IACvD;IAEA,OAAOoC,MAAM;EACf;EAEAE,oBAAoBA,CAClBH,OAAuC,EACvCI,KAA0B,EAC1B;IACA,MAAM;MAAE7B;IAAO,CAAC,GAAG,IAAI;IAEvB,MAAM0B,MAAM,GAAG,IAAI,CAACF,aAAa,CAACC,OAAO,CAAC;IAC1C,MAAMK,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;IACzC,MAAMtB,MAAM,GAAG,IAAI,CAACyB,SAAS,CAACP,OAAO,CAAC;;IAEtC;IACA,IAAI,CAAClB,MAAM,EAAE;MACX,OAAO;QACL,GAAGmB,MAAM;QACT,CAAC1B,MAAM,CAACK,OAAO,CAACY,IAAI,GAAGa;MACzB,CAAC;IACH;;IAEA;IACA,MAAMG,IAAI,GAAG,IAAI,CAACC,eAAe,CAACJ,IAAI,EAAEvB,MAAM,CAAC;IAE/C,OAAO;MACL,GAAGmB,MAAM;MACT,GAAGO;IACL,CAAC;EACH;EAEAE,qBAAqBA,CACnBV,OAA2B,EAC3BI,KAA0B,EAC1BF,OAAoB,EACpB;IACA,MAAMpB,MAAM,GAAG,IAAI,CAACyB,SAAS,CAACP,OAAO,CAAC;IAEtC,IAAI,CAAClB,MAAM,EAAE;MACX,MAAMhB,IAAI,CAAC6C,UAAU,CAAC,kBAAkB,CAAC;IAC3C;IAEA,MAAMN,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;IACzC,MAAMI,IAAI,GAAG,IAAI,CAACC,eAAe,CAACJ,IAAI,EAAEvB,MAAM,CAAC;IAE/C,MAAM8B,SAAS,GAAG,KAAK,CAACF,qBAAqB,CAACV,OAAO,EAAEI,KAAK,EAAEF,OAAO,CAAC;IACtE,MAAMW,OAAwB,GAAG;MAAE,GAAGD,SAAS;MAAE9B;IAAO,CAAC;IACzD,MAAMgC,OAAO,GAAG,CAAC,GAAGT,IAAI,CAAC;IAEzB,IAAI,CAACG,IAAI,EAAE;MACT;MACAM,OAAO,CAACC,IAAI,CAACF,OAAO,CAAC;IACvB,CAAC,MAAM;MACL;MACAC,OAAO,CAACT,IAAI,CAACW,OAAO,CAACR,IAAI,CAAC,CAAC,GAAGK,OAAO;IACvC;IAEA,OAAO;MACL,CAAC,IAAI,CAACtC,MAAM,CAACK,OAAO,CAACY,IAAI,GAAGsB;IAC9B,CAAC;EACH;EAEAG,OAAOA,CAACjB,OAA2B,EAAEkB,CAAsB,EAAE;IAC3D,MAAMC,QAAQ,GAAG,IAAI,CAACC,cAAc,CAACpB,OAAO,CAAC;IAC7C,OAAO,KAAK,CAACiB,OAAO,CAACjB,OAAO,EAAEkB,CAAC,EAAEC,QAAQ,CAAC;EAC5C;EAEAV,eAAeA,CAACJ,IAAqB,EAAEvB,MAAe,EAAE;IACtD,OAAOuB,IAAI,CAACgB,IAAI,CAAEb,IAAI,IAAKA,IAAI,CAAC1B,MAAM,KAAKA,MAAM,CAAC;EACpD;EAEAwB,gBAAgBA,CAACF,KAA0B,EAAE;IAC3C,MAAM;MAAEZ;IAAK,CAAC,GAAG,IAAI,CAACjB,MAAM,CAACK,OAAO;IACpC,MAAM0C,MAAM,GAAGlB,KAAK,CAACZ,IAAI,CAAC;IAE1B,OAAOxB,aAAa,CAACsD,MAAM,CAAC,GAAGA,MAAM,GAAG,EAAE;EAC5C;EAEAC,mBAAmBA,CAAA,EAAG;IACpB,OAAO,OACLvB,OAAoB,EACpBwB,OAAoB,EACpBN,CAAsB,KACnB;MACH,MAAM;QAAEO;MAAK,CAAC,GAAG,IAAI;MACrB,MAAM;QAAEC;MAAM,CAAC,GAAG1B,OAAO;MACzB,MAAM;QAAEI;MAAM,CAAC,GAAGoB,OAAO;MAEzB,MAAM1C,MAAM,GAAG,IAAI,CAACyB,SAAS,CAACP,OAAO,CAAC;MACtC,MAAMK,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;MAEzC,IAAI,CAACtB,MAAM,EAAE;QACX,MAAM6C,WAAW,GAAG,IAAI,CAACP,cAAc,CAACpB,OAAO,CAAC;QAChD,MAAMmB,QAAQ,GAAGlD,YAAY,CAAC,GAAGwD,IAAI,IAAI5D,UAAU,CAAC,CAAC,EAAE,EAAE;UACvD+D,SAAS,EAAEF,KAAK,CAACE,SAAS;UAC1BC,KAAK,EAAEH,KAAK,CAACG;QACf,CAAC,CAAC;;QAEF;QACA,OAAO,KAAK,CAACZ,OAAO,CAACjB,OAAO,EAAEkB,CAAC,EAAEb,IAAI,CAACyB,MAAM,GAAGH,WAAW,GAAGR,QAAQ,CAAC;MACxE;MAEA,OAAO,KAAK,CAACI,mBAAmB,CAAC,CAAC,CAACvB,OAAO,EAAEwB,OAAO,EAAEN,CAAC,CAAC;IACzD,CAAC;EACH;EAEAa,8BAA8BA,CAAA,EAAG;IAC/B,OAAO,CACL/B,OAAoB,EACpBwB,OAAoB,EACpBN,CAAsB,KACnB;MACH,MAAM;QAAEO;MAAK,CAAC,GAAG,IAAI;MACrB,MAAM;QAAEC;MAAM,CAAC,GAAG1B,OAAO;MACzB,MAAM;QAAEI;MAAM,CAAC,GAAGoB,OAAO;MAEzB,MAAMnB,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;MAEzC,IAAI,CAACC,IAAI,CAACyB,MAAM,EAAE;QAChB,MAAMX,QAAQ,GAAGlD,YAAY,CAAC,GAAGwD,IAAI,IAAI5D,UAAU,CAAC,CAAC,EAAE,EAAE;UACvD+D,SAAS,EAAEF,KAAK,CAACE;QACnB,CAAC,CAAC;QAEF,OAAO,KAAK,CAACX,OAAO,CAACjB,OAAO,EAAEkB,CAAC,EAAEC,QAAQ,CAAC;MAC5C;MAEA,MAAMa,UAAU,GAAG,IAAI,CAACC,aAAa,CAACjC,OAAO,CAAC;MAC9C,MAAM;QAAEkC;MAAE,CAAC,GAAGF,UAAU;MAExB,MAAMG,SAAS,GAAG,IAAI,CAACC,uBAAuB,CAC5CpC,OAAO,EACPwB,OAAO,EACPnB,IAAI,EACJ2B,UACF,CAAC;MAED,OAAOd,CAAC,CAACmB,IAAI,CAAC,IAAI,CAAChE,mBAAmB,EAAE;QACtC,GAAG8D,SAAS;QACZD;MACF,CAAC,CAAC;IACJ,CAAC;EACH;EAEAI,+BAA+BA,CAAA,EAAG;IAChC,OAAO,CACLtC,OAA2B,EAC3BwB,OAAoB,EACpBN,CAAsB,KACnB;MACH,MAAM;QAAEO,IAAI;QAAElD;MAAO,CAAC,GAAG,IAAI;MAC7B,MAAM;QAAEmD;MAAM,CAAC,GAAG1B,OAAO;MACzB,MAAM;QAAEnB;MAAO,CAAC,GAAGN,MAAM;MACzB,MAAM;QAAE6B;MAAM,CAAC,GAAGoB,OAAO;MAEzB,MAAMnB,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;MAEzC,IAAI,CAACC,IAAI,CAACyB,MAAM,EAAE;QAChB,MAAMX,QAAQ,GAAGlD,YAAY,CAAC,GAAGwD,IAAI,IAAI5D,UAAU,CAAC,CAAC,EAAE,EAAE;UACvD+D,SAAS,EAAEF,KAAK,CAACE;QACnB,CAAC,CAAC;QAEF,OAAO,KAAK,CAACX,OAAO,CAACjB,OAAO,EAAEkB,CAAC,EAAEC,QAAQ,CAAC;MAC5C;MAEA,MAAMa,UAAU,GAAG,IAAI,CAACC,aAAa,CAACjC,OAAO,CAAC;MAC9C,MAAM;QAAEkC;MAAE,CAAC,GAAGF,UAAU;MAExB,MAAM;QAAEO;MAAO,CAAC,GAAG,IAAI,CAACxC,aAAa,CAACC,OAAO,CAAC;MAE9C,MAAMwC,WAAW,GACfD,MAAM,KAAKpE,UAAU,CAACsE,QAAQ,IAAIpC,IAAI,CAACyB,MAAM,GAAGjD,MAAM,CAACc,GAAG;MAE5D,MAAM+C,WAAW,GACdH,MAAM,KAAKpE,UAAU,CAACwE,UAAU,IAAItC,IAAI,CAACyB,MAAM,IAAIjD,MAAM,CAACe,GAAG,IAC7D2C,MAAM,KAAKpE,UAAU,CAACsE,QAAQ,IAAIpC,IAAI,CAACyB,MAAM,GAAGjD,MAAM,CAACe,GAAI;;MAE9D;MACA,IAAI4C,WAAW,IAAIE,WAAW,EAAE;QAC9B,MAAME,KAAK,GAAGF,WAAW,GAAG7D,MAAM,CAACe,GAAG,GAAGf,MAAM,CAACc,GAAG;QAEnD6B,OAAO,CAACqB,MAAM,GAAG,CACf;UACEpB,IAAI,EAAE,EAAE;UACRqB,IAAI,EAAE,EAAE;UACRtD,IAAI,EAAE,EAAE;UACRuD,IAAI,EAAEL,WAAW,GACbR,CAAC,CAAC,wBAAwB,EAAE;YAAEU;UAAM,CAAC,CAAC,GACtCV,CAAC,CAAC,uBAAuB,EAAE;YAAEU;UAAM,CAAC;QAC1C,CAAC,CACF;QAED,MAAMT,SAAS,GAAG,IAAI,CAACC,uBAAuB,CAC5CpC,OAAO,EACPwB,OAAO,EACPnB,IAAI,EACJ2B,UACF,CAAC;QAED,OAAOd,CAAC,CAACmB,IAAI,CAAC,IAAI,CAAChE,mBAAmB,EAAE;UACtC,GAAG8D,SAAS;UACZD;QACF,CAAC,CAAC;MACJ;MAEA,IAAIK,MAAM,KAAKpE,UAAU,CAACwE,UAAU,EAAE;QACpC,MAAMxB,QAAQ,GAAGlD,YAAY,CAAC,GAAGwD,IAAI,IAAI5D,UAAU,CAAC,CAAC,EAAE,EAAE;UACvD+D,SAAS,EAAEF,KAAK,CAACE;QACnB,CAAC,CAAC;QAEF,OAAO,KAAK,CAACX,OAAO,CAACjB,OAAO,EAAEkB,CAAC,EAAEC,QAAQ,CAAC;MAC5C;;MAEA;MACA,IAAIoB,MAAM,KAAKpE,UAAU,CAAC6E,WAAW,EAAE;QACrC,OAAO,IAAI,CAACC,iBAAiB,CAACjD,OAAO,EAAEwB,OAAO,EAAEN,CAAC,CAAC;MACpD;MAEA,MAAMC,QAAQ,GAAG,IAAI,CAAC+B,WAAW,CAAC1B,OAAO,CAAC;MAC1C,OAAO,KAAK,CAACP,OAAO,CAACjB,OAAO,EAAEkB,CAAC,EAAEC,QAAQ,CAAC;IAC5C,CAAC;EACH;EAEAgC,6BAA6BA,CAAA,EAAG;IAC9B,OAAO,CACLnD,OAAoB,EACpBwB,OAAoB,EACpBN,CAAsB,KACnB;MACH,MAAM;QAAEiB;MAAU,CAAC,GAAG,IAAI;MAC1B,MAAM;QAAE/B;MAAM,CAAC,GAAGoB,OAAO;MAEzB,MAAMnB,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;MACzC,MAAMtB,MAAM,GAAG,IAAI,CAACyB,SAAS,CAACP,OAAO,CAAC;MACtC,MAAMQ,IAAI,GAAG,IAAI,CAACC,eAAe,CAACJ,IAAI,EAAEvB,MAAM,CAAC;MAE/C,MAAMkD,UAAU,GAAG,IAAI,CAACC,aAAa,CAACjC,OAAO,CAAC;MAC9C,MAAM;QAAEkC;MAAE,CAAC,GAAGF,UAAU;MAExB,IAAI,CAACxB,IAAI,IAAIH,IAAI,CAACyB,MAAM,KAAK,CAAC,EAAE;QAC9B,MAAMhE,IAAI,CAACsF,QAAQ,CACjB5C,IAAI,GACA0B,CAAC,CAAC,wCAAwC,CAAC,GAC3CA,CAAC,CAAC,qCAAqC,CAC7C,CAAC;MACH;MAEA,MAAM;QAAEpC;MAAM,CAAC,GAAG,IAAI,CAACvB,MAAM,CAACK,OAAO;MAErC,OAAOsC,CAAC,CAACmB,IAAI,CAAC,IAAI,CAAC/D,kBAAkB,EAAE;QACrC,GAAG6D,SAAS;QACZX,OAAO;QACP6B,QAAQ,EAAE,IAAI,CAACC,WAAW,CAACtD,OAAO,EAAEwB,OAAO,EAAEU,CAAC,CAAC;QAC/CqB,SAAS,EAAErB,CAAC,CAAC,6BAA6B,CAAC;QAC3CsB,SAAS,EAAE,GAAG1D,KAAK,IAAIO,IAAI,CAACW,OAAO,CAACR,IAAI,CAAC,GAAG,CAAC,EAAE;QAC/CiD,aAAa,EAAE;UAAEV,IAAI,EAAEb,CAAC,CAAC,uBAAuB;QAAE,CAAC;QACnDwB,YAAY,EAAE;UAAEX,IAAI,EAAEb,CAAC,CAAC,uBAAuB;QAAE,CAAC;QAClDA;MACF,CAAmC,CAAC;IACtC,CAAC;EACH;EAEAyB,8BAA8BA,CAAA,EAAG;IAC/B,OAAO,OACL3D,OAA2B,EAC3BwB,OAAoB,EACpBN,CAAsB,KACnB;MACH,MAAM;QAAE3C;MAAO,CAAC,GAAG,IAAI;MACvB,MAAM;QAAE6B;MAAM,CAAC,GAAGoB,OAAO;MAEzB,MAAM;QAAEoC;MAAQ,CAAC,GAAG,IAAI,CAAC7D,aAAa,CAACC,OAAO,CAAC;MAE/C,MAAMK,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;MACzC,MAAMtB,MAAM,GAAG,IAAI,CAACyB,SAAS,CAACP,OAAO,CAAC;MACtC,MAAMQ,IAAI,GAAG,IAAI,CAACC,eAAe,CAACJ,IAAI,EAAEvB,MAAM,CAAC;MAE/C,MAAM;QAAEoD;MAAE,CAAC,GAAG,IAAI,CAACD,aAAa,CAACjC,OAAO,CAAC;MAEzC,IAAI,CAACQ,IAAI,IAAIH,IAAI,CAACyB,MAAM,KAAK,CAAC,EAAE;QAC9B,MAAMhE,IAAI,CAACsF,QAAQ,CACjB5C,IAAI,GACA0B,CAAC,CAAC,wCAAwC,CAAC,GAC3CA,CAAC,CAAC,qCAAqC,CAC7C,CAAC;MACH;;MAEA;MACA,IAAI0B,OAAO,EAAE;QACXvD,IAAI,CAACwD,MAAM,CAACxD,IAAI,CAACW,OAAO,CAACR,IAAI,CAAC,EAAE,CAAC,CAAC;QAElC,MAAMsD,MAAM,GAAG;UACb,CAACvF,MAAM,CAACK,OAAO,CAACY,IAAI,GAAGa;QACzB,CAAC;QAED,MAAM,IAAI,CAAC0D,UAAU,CAAC/D,OAAO,EAAEI,KAAK,EAAE0D,MAAM,CAAC;MAC/C;MAEA,OAAO,IAAI,CAAC7C,OAAO,CAACjB,OAAO,EAAEkB,CAAC,CAAC;IACjC,CAAC;EACH;EAEA8C,YAAYA,CACVhE,OAA2B,EAC3BwB,OAAoB,EACpBQ,UAAsB,EACH;IACnB,MAAM;MAAE5B;IAAM,CAAC,GAAGoB,OAAO;IACzB,MAAM;MAAEyC;IAAM,CAAC,GAAGjC,UAAU;IAE5B,MAAM3B,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;IACzC,MAAMtB,MAAM,GAAG,IAAI,CAACyB,SAAS,CAACP,OAAO,CAAC;IACtC,MAAMQ,IAAI,GAAG,IAAI,CAACC,eAAe,CAACJ,IAAI,EAAEvB,MAAM,CAAC;IAE/C,MAAMqD,SAAS,GAAG,KAAK,CAAC6B,YAAY,CAAChE,OAAO,EAAEwB,OAAO,EAAEQ,UAAU,CAAC;IAClE,MAAMkC,UAAU,GAAG1D,IAAI,GAAGH,IAAI,CAACW,OAAO,CAACR,IAAI,CAAC,GAAG,CAAC,GAAGH,IAAI,CAACyB,MAAM,GAAG,CAAC;IAClE,MAAMhC,KAAK,GACTmE,KAAK,CAAC,IAAI,CAACtF,OAAO,EAAE,aAAa,CAAC,IAAI,IAAI,CAACA,OAAO,CAACJ,MAAM,CAACK,OAAO,CAACkB,KAAK;IACzE,MAAMqE,aAAa,GAAG,GAAGrE,KAAK,IAAIoE,UAAU,EAAE;IAE9C,OAAO;MACL,GAAG/B,SAAS;MAEZiC,YAAY,EAAEjC,SAAS,CAACiC,YAAY,GAChC,GAAGjC,SAAS,CAACiC,YAAY,KAAKD,aAAa,EAAE,GAC7CA;IACN,CAAC;EACH;EAEA/B,uBAAuBA,CACrBpC,OAA2B,EAC3BwB,OAAoB,EACpBnB,IAAqB,EACrB2B,UAAsB,EACQ;IAC9B,MAAM;MAAE9C,UAAU;MAAE4D,IAAI;MAAEvE;IAAO,CAAC,GAAG,IAAI;IACzC,MAAM;MAAEmD;IAAM,CAAC,GAAG1B,OAAO;IACzB,MAAM;MAAEqE,aAAa;MAAExB;IAAO,CAAC,GAAGrB,OAAO;IAEzC,MAAM;MAAEU,CAAC;MAAE+B;IAAM,CAAC,GAAGjC,UAAU;IAE/B,MAAMlC,KAAK,GAAGmE,KAAK,CAAC,IAAI,CAACtF,OAAO,EAAE,aAAa,CAAC,IAAIJ,MAAM,CAACK,OAAO,CAACkB,KAAK;IAExE,MAAMwE,WAAwB,GAAG;MAC/BC,OAAO,EAAE,kCAAkC;MAC3CC,IAAI,EAAE;IACR,CAAC;IAED,IAAI5B,KAAK,GAAG,CAAC;IAEb,IAAI6B,KAAK,CAACC,OAAO,CAACrE,IAAI,CAAC,EAAE;MACvBuC,KAAK,GAAGvC,IAAI,CAACyB,MAAM;MAEnB,MAAMH,WAAW,GAAG,IAAI,CAACP,cAAc,CAACpB,OAAO,CAAC;MAEhDK,IAAI,CAACsE,OAAO,CAAC,CAACnE,IAAI,EAAEoE,KAAK,KAAK;QAC5B,MAAMlF,KAA0B,GAAG,EAAE;;QAErC;QACA,IAAI,CAAC2E,aAAa,EAAE;UAClB3E,KAAK,CAACqB,IAAI,CAAC;YACT+B,IAAI,EAAE7E,YAAY,CAAC,GAAG6E,IAAI,IAAItC,IAAI,CAAC1B,MAAM,EAAE,EAAE;cAC3C8C,SAAS,EAAEF,KAAK,CAACE,SAAS,IAAI,IAAI,CAACiD,OAAO,CAAClD,WAAW;YACxD,CAAC,CAAC;YACFoB,IAAI,EAAEb,CAAC,CAAC,uBAAuB,CAAC;YAChCqC,OAAO,EAAE,8BAA8B;YACvCO,kBAAkB,EAAE5C,CAAC,CAAC,mCAAmC,EAAE;cACzD0C,KAAK,EAAEA,KAAK,GAAG;YACjB,CAAC;UACH,CAAC,CAAC;UAEF,IAAIhC,KAAK,GAAG,CAAC,EAAE;YACblD,KAAK,CAACqB,IAAI,CAAC;cACT+B,IAAI,EAAE7E,YAAY,CAAC,GAAG6E,IAAI,IAAItC,IAAI,CAAC1B,MAAM,iBAAiB,EAAE;gBAC1D8C,SAAS,EAAEF,KAAK,CAACE;cACnB,CAAC,CAAC;cACFmB,IAAI,EAAEb,CAAC,CAAC,uBAAuB,CAAC;cAChCqC,OAAO,EAAE,8BAA8B;cACvCO,kBAAkB,EAAE5C,CAAC,CAAC,mCAAmC,EAAE;gBACzD0C,KAAK,EAAEA,KAAK,GAAG;cACjB,CAAC;YACH,CAAC,CAAC;UACJ;QACF;QAEA,MAAMG,eAAe,GAAG7F,UAAU,CAAC8F,MAAM,CAAClD,MAAM,GAC5C5C,UAAU,CAAC8F,MAAM,CAAC,CAAC,CAAC,CAACC,yBAAyB,CAACzE,IAAI,EAAEwB,UAAU,CAAC,GAChE,EAAE;QAENsC,WAAW,CAACE,IAAI,CAACzD,IAAI,CAAC;UACpBmE,GAAG,EAAE;YACHnC,IAAI,EAAE,GAAGjD,KAAK,IAAI8E,KAAK,GAAG,CAAC;UAC7B,CAAC;UACDO,KAAK,EAAE;YACLpC,IAAI,EAAEgC,eAAe,IAAI7C,CAAC,CAAC,4BAA4B;UACzD,CAAC;UACDkD,OAAO,EAAE;YACP1F;UACF;QACF,CAAC,CAAC;MACJ,CAAC,CAAC;IACJ;IAEA,OAAO;MACL,GAAG,IAAI,CAACyC,SAAS;MACjBkB,QAAQ,EAAE,IAAI,CAACC,WAAW,CAACtD,OAAO,EAAEwB,OAAO,EAAEU,CAAC,CAAC;MAC/CmD,WAAW,EAAEvF,KAAK;MAClByD,SAAS,EAAErB,CAAC,CAAC,0BAA0B,EAAE;QAAEU;MAAM,CAAC,CAAC;MACnD0C,SAAS,EAAE,IAAI;MACf9D,OAAO;MACPqB,MAAM;MACN0C,YAAY,EAAE,CAAC;QAAEjB;MAAY,CAAC,CAAC;MAC/B9F,gBAAgB,EAAE,IAAI,CAACgH,qBAAqB,CAACxF,OAAO,CAACyF,MAAM;IAC7D,CAAC;EACH;EAEArE,cAAcA,CAACpB,OAA4B,EAAE;IAC3C,MAAM;MAAEyB;IAAK,CAAC,GAAG,IAAI;IAErB,MAAME,WAAW,GAAG,KAAK,CAACP,cAAc,CAAC,CAAC;IAE1C,IAAI,CAACpB,OAAO,EAAE;MACZ,OAAO2B,WAAW;IACpB;IAEA,MAAM;MAAED;IAAM,CAAC,GAAG1B,OAAO;IAEzB,OAAO/B,YAAY,CAAC,GAAGwD,IAAI,GAAGE,WAAW,EAAE,EAAE;MAC3CC,SAAS,EAAEF,KAAK,CAACE;IACnB,CAAC,CAAC;EACJ;AACF","ignoreList":[]}
|