@defra/forms-engine-plugin 0.1.11 → 0.1.12
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/file-upload.min.js +1 -1
- package/.public/javascripts/file-upload.min.js.map +1 -1
- package/.server/client/javascripts/file-upload.js +45 -4
- package/.server/client/javascripts/file-upload.js.map +1 -1
- package/.server/server/constants.js +2 -0
- package/.server/server/constants.js.map +1 -1
- package/.server/server/index.js +1 -1
- package/.server/server/index.js.map +1 -1
- package/.server/server/plugins/engine/components/AutocompleteField.js +2 -0
- package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
- package/.server/server/plugins/engine/components/CheckboxesField.js +3 -4
- package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
- package/.server/server/plugins/engine/components/ComponentCollection.js +37 -16
- package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
- package/.server/server/plugins/engine/components/DatePartsField.js +36 -2
- package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
- package/.server/server/plugins/engine/components/EmailAddressField.js +19 -3
- package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
- package/.server/server/plugins/engine/components/FileUploadField.js +44 -4
- package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
- package/.server/server/plugins/engine/components/FormComponent.js +14 -2
- package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
- package/.server/server/plugins/engine/components/ListFormComponent.js +16 -3
- package/.server/server/plugins/engine/components/ListFormComponent.js.map +1 -1
- package/.server/server/plugins/engine/components/Markdown.js +24 -0
- package/.server/server/plugins/engine/components/Markdown.js.map +1 -0
- package/.server/server/plugins/engine/components/MonthYearField.js +30 -2
- package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
- package/.server/server/plugins/engine/components/MultilineTextField.js +32 -3
- package/.server/server/plugins/engine/components/MultilineTextField.js.map +1 -1
- package/.server/server/plugins/engine/components/NumberField.js +28 -3
- package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
- package/.server/server/plugins/engine/components/SelectionControlField.js +14 -0
- package/.server/server/plugins/engine/components/SelectionControlField.js.map +1 -1
- package/.server/server/plugins/engine/components/TelephoneNumberField.js +19 -3
- package/.server/server/plugins/engine/components/TelephoneNumberField.js.map +1 -1
- package/.server/server/plugins/engine/components/TextField.js +22 -3
- package/.server/server/plugins/engine/components/TextField.js.map +1 -1
- package/.server/server/plugins/engine/components/UkAddressField.js +29 -0
- package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
- package/.server/server/plugins/engine/components/YesNoField.js +18 -0
- package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
- package/.server/server/plugins/engine/components/helpers.js +16 -0
- package/.server/server/plugins/engine/components/helpers.js.map +1 -1
- package/.server/server/plugins/engine/components/index.js +1 -0
- package/.server/server/plugins/engine/components/index.js.map +1 -1
- package/.server/server/plugins/engine/configureEnginePlugin.js +3 -1
- package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
- package/.server/server/plugins/engine/helpers.js +38 -18
- package/.server/server/plugins/engine/helpers.js.map +1 -1
- package/.server/server/plugins/engine/models/FormModel.js +60 -2
- package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
- package/.server/server/plugins/engine/models/SummaryViewModel.js +3 -2
- package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/human/v1.js +1 -1
- package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/PageController.js +13 -5
- package/.server/server/plugins/engine/pageControllers/PageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +2 -2
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +19 -5
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/validationOptions.js +6 -11
- package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
- package/.server/server/plugins/engine/plugin.js +5 -4
- package/.server/server/plugins/engine/plugin.js.map +1 -1
- package/.server/server/plugins/engine/services/notifyService.js +1 -4
- package/.server/server/plugins/engine/services/notifyService.js.map +1 -1
- package/.server/server/plugins/engine/services/uploadService.js +5 -3
- package/.server/server/plugins/engine/services/uploadService.js.map +1 -1
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/.server/server/plugins/engine/views/components/html.html +1 -1
- package/.server/server/plugins/engine/views/components/markdown.html +5 -0
- package/.server/server/plugins/engine/views/summary.html +7 -1
- package/.server/server/plugins/nunjucks/context.js +6 -5
- package/.server/server/plugins/nunjucks/context.js.map +1 -1
- package/.server/server/plugins/nunjucks/enviroment.test.js +6 -3
- package/.server/server/plugins/nunjucks/enviroment.test.js.map +1 -1
- package/.server/server/utils/type-utils.js +8 -0
- package/.server/server/utils/type-utils.js.map +1 -0
- package/.server/typings/joi/index.d.js.map +1 -1
- package/package.json +3 -3
- package/src/client/javascripts/file-upload.js +60 -4
- package/src/server/constants.js +2 -0
- package/src/server/index.test.ts +34 -29
- package/src/server/index.ts +2 -1
- package/src/server/plugins/engine/components/AutocompleteField.test.ts +71 -3
- package/src/server/plugins/engine/components/AutocompleteField.ts +6 -2
- package/src/server/plugins/engine/components/CheckboxesField.test.ts +40 -8
- package/src/server/plugins/engine/components/CheckboxesField.ts +7 -3
- package/src/server/plugins/engine/components/ComponentCollection.ts +45 -18
- package/src/server/plugins/engine/components/DatePartsField.test.ts +13 -4
- package/src/server/plugins/engine/components/DatePartsField.ts +29 -8
- package/src/server/plugins/engine/components/EmailAddressField.test.ts +51 -1
- package/src/server/plugins/engine/components/EmailAddressField.ts +17 -2
- package/src/server/plugins/engine/components/FileUploadField.test.ts +53 -0
- package/src/server/plugins/engine/components/FileUploadField.ts +52 -3
- package/src/server/plugins/engine/components/FormComponent.ts +24 -2
- package/src/server/plugins/engine/components/ListFormComponent.ts +16 -2
- package/src/server/plugins/engine/components/Markdown.test.ts +48 -0
- package/src/server/plugins/engine/components/Markdown.ts +29 -0
- package/src/server/plugins/engine/components/MonthYearField.test.ts +35 -0
- package/src/server/plugins/engine/components/MonthYearField.ts +34 -9
- package/src/server/plugins/engine/components/MultilineTextField.test.ts +83 -5
- package/src/server/plugins/engine/components/MultilineTextField.ts +37 -2
- package/src/server/plugins/engine/components/NumberField.test.ts +24 -2
- package/src/server/plugins/engine/components/NumberField.ts +23 -3
- package/src/server/plugins/engine/components/RadiosField.test.ts +10 -1
- package/src/server/plugins/engine/components/SelectField.test.ts +2 -1
- package/src/server/plugins/engine/components/SelectionControlField.ts +14 -0
- package/src/server/plugins/engine/components/TelephoneNumberField.test.ts +30 -2
- package/src/server/plugins/engine/components/TelephoneNumberField.ts +17 -2
- package/src/server/plugins/engine/components/TextField.test.ts +33 -1
- package/src/server/plugins/engine/components/TextField.ts +17 -2
- package/src/server/plugins/engine/components/UkAddressField.test.ts +46 -3
- package/src/server/plugins/engine/components/UkAddressField.ts +28 -0
- package/src/server/plugins/engine/components/YesNoField.test.ts +9 -1
- package/src/server/plugins/engine/components/YesNoField.ts +24 -0
- package/src/server/plugins/engine/components/helpers.test.ts +24 -0
- package/src/server/plugins/engine/components/helpers.ts +39 -0
- package/src/server/plugins/engine/components/index.ts +1 -0
- package/src/server/plugins/engine/configureEnginePlugin.ts +13 -3
- package/src/server/plugins/engine/helpers.test.ts +71 -20
- package/src/server/plugins/engine/helpers.ts +46 -19
- package/src/server/plugins/engine/models/FormModel.test.ts +91 -1
- package/src/server/plugins/engine/models/FormModel.ts +86 -3
- package/src/server/plugins/engine/models/SummaryViewModel.test.ts +46 -7
- package/src/server/plugins/engine/models/SummaryViewModel.ts +7 -3
- package/src/server/plugins/engine/outputFormatters/human/v1.test.ts +1 -2
- package/src/server/plugins/engine/outputFormatters/human/v1.ts +1 -1
- package/src/server/plugins/engine/pageControllers/FileUploadPageController.test.ts +1 -0
- package/src/server/plugins/engine/pageControllers/PageController.test.ts +9 -6
- package/src/server/plugins/engine/pageControllers/PageController.ts +15 -5
- package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +2 -2
- package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +21 -6
- package/src/server/plugins/engine/pageControllers/validationOptions.ts +31 -17
- package/src/server/plugins/engine/plugin.ts +9 -5
- package/src/server/plugins/engine/services/notifyService.ts +1 -2
- package/src/server/plugins/engine/services/uploadService.js +10 -6
- package/src/server/plugins/engine/types.ts +10 -1
- package/src/server/plugins/engine/views/components/html.html +1 -1
- package/src/server/plugins/engine/views/components/markdown.html +5 -0
- package/src/server/plugins/engine/views/summary.html +7 -1
- package/src/server/plugins/nunjucks/context.js +4 -4
- package/src/server/plugins/nunjucks/enviroment.test.js +9 -3
- package/src/server/utils/type-utils.ts +15 -0
- package/src/typings/joi/index.d.ts +8 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentCollection.js","names":["joi","FormComponent","isFormState","isFormValue","createComponent","getErrors","validationOptions","opts","ComponentCollection","page","parent","components","fields","guidance","formSchema","stateSchema","constructor","defs","props","schema","map","def","filter","component","isFormComponent","object","required","field","collection","name","concat","keys","error","errors","flatMap","isErrorContext","local","title","missing","key","path","find","item","split","shift","child","label","length","peers","and","isPresent","custom","getFormDataFromState","state","payload","forEach","Object","assign","getFormValueFromState","value","entries","pop","getStateFromValidForm","getContextValueFromState","context","list","getError","push","getViewModel","query","result","type","model","validate","details"],"sources":["../../../../../src/server/plugins/engine/components/ComponentCollection.ts"],"sourcesContent":["import { type ComponentDef } from '@defra/forms-model'\nimport joi, {\n type CustomValidator,\n type ErrorReportCollection,\n type ObjectSchema\n} from 'joi'\n\nimport {\n FormComponent,\n isFormState,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n createComponent,\n type Component,\n type Field,\n type Guidance\n} from '~/src/server/plugins/engine/components/helpers.js'\nimport { type ComponentViewModel } from '~/src/server/plugins/engine/components/types.js'\nimport { getErrors } from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers.js'\nimport { validationOptions as opts } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type FormPayload,\n type FormState,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValidationResult\n} from '~/src/server/plugins/engine/types.js'\nimport { type FormQuery } from '~/src/server/routes/types.js'\n\nexport class ComponentCollection {\n page?: PageControllerClass\n parent?: Component\n\n components: Component[]\n fields: Field[]\n guidance: Guidance[]\n\n formSchema: ObjectSchema<FormPayload>\n stateSchema: ObjectSchema<FormSubmissionState>\n\n constructor(\n defs: ComponentDef[],\n props: {\n page?: PageControllerClass\n parent?: Component\n model: FormModel\n },\n schema?: {\n /**\n * Defines an all-or-nothing relationship between keys where if one\n * of the peers is present, all of them are required as well\n */\n peers?: string[]\n\n /**\n * Defines a custom validation rule for the object schema\n */\n custom?: CustomValidator\n }\n ) {\n const components = defs.map((def) => createComponent(def, props))\n\n const fields = components.filter(\n (component): component is Field => component.isFormComponent\n )\n\n const guidance = components.filter(\n (component): component is Guidance => !component.isFormComponent\n )\n\n let formSchema = joi.object<FormPayload>().required()\n let stateSchema = joi.object<FormSubmissionState>().required()\n\n // Add each field or concat collection\n for (const field of fields) {\n const { collection, name } = field\n\n formSchema = collection\n ? formSchema.concat(collection.formSchema)\n : formSchema.keys({ [name]: field.formSchema })\n\n stateSchema = collection\n ? stateSchema.concat(collection.stateSchema)\n : stateSchema.keys({ [name]: field.stateSchema })\n }\n\n // Add parent field title to collection field errors\n formSchema = formSchema.error((errors) => {\n return errors.flatMap((error) => {\n if (!isErrorContext(error.local) || error.local.title) {\n return error\n }\n\n // Use field key or first missing child field\n let { missing, key = missing?.[0] } = error.local\n\n // But avoid numeric key used by array payloads\n if (typeof key === 'number') {\n key = error.path[0]\n }\n\n // Find the parent field\n const parent = fields.find(\n (item) => item.name === key?.split('__').shift()\n )\n\n // Find the child field\n const child = (parent?.collection?.fields ?? fields).find(\n (item) => item.name === key\n )\n\n // Update error with child label\n if (child && (!error.local.label || error.local.label === 'value')) {\n error.local.label = child.title\n }\n\n // Fix error summary links for missing fields\n if (missing?.length) {\n error.path = missing\n error.local.key = missing[0]\n }\n\n // Update error with parent title\n error.local.title ??= parent?.title\n\n return error\n })\n })\n\n if (schema?.peers) {\n formSchema = formSchema.and(...schema.peers, {\n isPresent: isFormValue\n })\n }\n\n if (schema?.custom) {\n formSchema = formSchema.custom(schema.custom)\n }\n\n this.page = props.page\n this.parent = props.parent\n\n this.components = components\n this.fields = fields\n this.guidance = guidance\n\n this.formSchema = formSchema\n this.stateSchema = stateSchema\n }\n\n get keys() {\n return this.fields.flatMap((field) => {\n const { name, collection } = field\n\n if (collection) {\n const { fields } = collection\n return [name, ...fields.map(({ name }) => name)]\n }\n\n return [name]\n })\n }\n\n getFormDataFromState(state: FormSubmissionState) {\n const payload: FormPayload = {}\n\n this.fields.forEach((component) => {\n Object.assign(payload, component.getFormDataFromState(state))\n })\n\n return payload\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const payload: FormPayload = {}\n\n // Remove name prefix for formatted value\n for (const [name, value] of Object.entries(\n this.getFormDataFromState(state)\n )) {\n const key = name.split('__').pop()\n if (!key) {\n continue\n }\n\n payload[key] = value\n }\n\n return payload\n }\n\n getStateFromValidForm(payload: FormPayload) {\n const state: FormState = {}\n\n this.fields.forEach((component) => {\n Object.assign(state, component.getStateFromValidForm(payload))\n })\n\n return state\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const context: FormState = {}\n\n for (const component of this.fields) {\n context[component.name] = component.getContextValueFromState(state)\n }\n\n return context\n }\n\n getErrors(errors?: FormSubmissionError[]): FormSubmissionError[] | undefined {\n const { fields } = this\n\n const list: FormSubmissionError[] = []\n\n // Add only one error per field\n for (const field of fields) {\n const error = field.getError(errors)\n\n if (error) {\n list.push(error)\n }\n }\n\n if (!list.length) {\n return\n }\n\n return list\n }\n\n getViewModel(\n payload: FormPayload,\n errors?: FormSubmissionError[],\n query: FormQuery = {}\n ) {\n const { components } = this\n\n const result: ComponentViewModel[] = components.map((component) => {\n const { isFormComponent, type } = component\n\n const model =\n component instanceof FormComponent\n ? component.getViewModel(payload, errors, query)\n : component.getViewModel()\n\n return { type, isFormComponent, model }\n })\n\n return result\n }\n\n /**\n * Validate form payload\n */\n validate(value: FormPayload = {}): FormValidationResult<FormPayload> {\n const result = this.formSchema.validate(value, opts)\n const details = result.error?.details\n\n return {\n value: (result.value ?? {}) as typeof value,\n errors: this.page?.getErrors(details) ?? getErrors(details)\n }\n }\n}\n\n/**\n * Check for field local state\n */\nexport function isErrorContext(\n value?: unknown\n): value is ErrorReportCollection['local'] {\n return isFormState(value) && typeof value.label === 'string'\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"ComponentCollection.js","names":["joi","FormComponent","isFormState","isFormValue","createComponent","getErrors","validationOptions","opts","ComponentCollection","page","parent","components","fields","guidance","formSchema","stateSchema","constructor","defs","props","schema","map","def","filter","component","isFormComponent","object","required","field","collection","name","concat","keys","error","errors","flatMap","isErrorContext","local","title","missing","key","path","find","item","split","shift","child","label","length","peers","and","isPresent","custom","getFormDataFromState","state","payload","forEach","Object","assign","getFormValueFromState","value","entries","pop","getStateFromValidForm","getContextValueFromState","context","getFieldErrors","getViewErrors","getViewModel","query","result","type","model","validate","details","callback","list","fieldErrors","push"],"sources":["../../../../../src/server/plugins/engine/components/ComponentCollection.ts"],"sourcesContent":["import { type ComponentDef } from '@defra/forms-model'\nimport joi, {\n type CustomValidator,\n type ErrorReportCollection,\n type ObjectSchema\n} from 'joi'\n\nimport {\n FormComponent,\n isFormState,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n createComponent,\n type Component,\n type Field,\n type Guidance\n} from '~/src/server/plugins/engine/components/helpers.js'\nimport { type ComponentViewModel } from '~/src/server/plugins/engine/components/types.js'\nimport { getErrors } from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers.js'\nimport { validationOptions as opts } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type FormPayload,\n type FormState,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValidationResult\n} from '~/src/server/plugins/engine/types.js'\nimport { type FormQuery } from '~/src/server/routes/types.js'\n\nexport class ComponentCollection {\n page?: PageControllerClass\n parent?: Component\n\n components: Component[]\n fields: Field[]\n guidance: Guidance[]\n\n formSchema: ObjectSchema<FormPayload>\n stateSchema: ObjectSchema<FormSubmissionState>\n\n constructor(\n defs: ComponentDef[],\n props: {\n page?: PageControllerClass\n parent?: Component\n model: FormModel\n },\n schema?: {\n /**\n * Defines an all-or-nothing relationship between keys where if one\n * of the peers is present, all of them are required as well\n */\n peers?: string[]\n\n /**\n * Defines a custom validation rule for the object schema\n */\n custom?: CustomValidator\n }\n ) {\n const components = defs.map((def) => createComponent(def, props))\n\n const fields = components.filter(\n (component): component is Field => component.isFormComponent\n )\n\n const guidance = components.filter(\n (component): component is Guidance => !component.isFormComponent\n )\n\n let formSchema = joi.object<FormPayload>().required()\n let stateSchema = joi.object<FormSubmissionState>().required()\n\n // Add each field or concat collection\n for (const field of fields) {\n const { collection, name } = field\n\n formSchema = collection\n ? formSchema.concat(collection.formSchema)\n : formSchema.keys({ [name]: field.formSchema })\n\n stateSchema = collection\n ? stateSchema.concat(collection.stateSchema)\n : stateSchema.keys({ [name]: field.stateSchema })\n }\n\n // Add parent field title to collection field errors\n formSchema = formSchema.error((errors) => {\n return errors.flatMap((error) => {\n if (!isErrorContext(error.local) || error.local.title) {\n return error\n }\n\n // Use field key or first missing child field\n let { missing, key = missing?.[0] } = error.local\n\n // But avoid numeric key used by array payloads\n if (typeof key === 'number') {\n key = error.path[0]\n }\n\n // Find the parent field\n const parent = fields.find(\n (item) => item.name === key?.split('__').shift()\n )\n\n // Find the child field\n const child = (parent?.collection?.fields ?? fields).find(\n (item) => item.name === key\n )\n\n // Update error with child label\n if (child && (!error.local.label || error.local.label === 'value')) {\n error.local.label = child.title\n }\n\n // Fix error summary links for missing fields\n if (missing?.length) {\n error.path = missing\n error.local.key = missing[0]\n }\n\n // Update error with parent title\n error.local.title ??= parent?.label\n\n return error\n })\n })\n\n if (schema?.peers) {\n formSchema = formSchema.and(...schema.peers, {\n isPresent: isFormValue\n })\n }\n\n if (schema?.custom) {\n formSchema = formSchema.custom(schema.custom)\n }\n\n this.page = props.page\n this.parent = props.parent\n\n this.components = components\n this.fields = fields\n this.guidance = guidance\n\n this.formSchema = formSchema\n this.stateSchema = stateSchema\n }\n\n get keys() {\n return this.fields.flatMap((field) => {\n const { name, collection } = field\n\n if (collection) {\n const { fields } = collection\n return [name, ...fields.map(({ name }) => name)]\n }\n\n return [name]\n })\n }\n\n getFormDataFromState(state: FormSubmissionState) {\n const payload: FormPayload = {}\n\n this.fields.forEach((component) => {\n Object.assign(payload, component.getFormDataFromState(state))\n })\n\n return payload\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const payload: FormPayload = {}\n\n // Remove name prefix for formatted value\n for (const [name, value] of Object.entries(\n this.getFormDataFromState(state)\n )) {\n const key = name.split('__').pop()\n if (!key) {\n continue\n }\n\n payload[key] = value\n }\n\n return payload\n }\n\n getStateFromValidForm(payload: FormPayload) {\n const state: FormState = {}\n\n this.fields.forEach((component) => {\n Object.assign(state, component.getStateFromValidForm(payload))\n })\n\n return state\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const context: FormState = {}\n\n for (const component of this.fields) {\n context[component.name] = component.getContextValueFromState(state)\n }\n\n return context\n }\n\n /**\n * Get all errors for all fields in this collection\n */\n getErrors(errors?: FormSubmissionError[]): FormSubmissionError[] | undefined {\n return this.getFieldErrors((field) => field.getErrors(errors), errors)\n }\n\n /**\n * Get view errors for all fields in this collection.\n * For most fields this means filtering to the first error in the list.\n * Composite fields like UKAddress can choose to return more than one error.\n */\n getViewErrors(\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n return this.getFieldErrors((field) => field.getViewErrors(errors), errors)\n }\n\n getViewModel(\n payload: FormPayload,\n errors?: FormSubmissionError[],\n query: FormQuery = {}\n ) {\n const { components } = this\n\n const result: ComponentViewModel[] = components.map((component) => {\n const { isFormComponent, type } = component\n\n const model =\n component instanceof FormComponent\n ? component.getViewModel(payload, errors, query)\n : component.getViewModel()\n\n return { type, isFormComponent, model }\n })\n\n return result\n }\n\n /**\n * Validate form payload\n */\n validate(value: FormPayload = {}): FormValidationResult<FormPayload> {\n const result = this.formSchema.validate(value, opts)\n const details = result.error?.details\n\n return {\n value: (result.value ?? {}) as typeof value,\n errors: this.page?.getErrors(details) ?? getErrors(details)\n }\n }\n\n /**\n * Helper to get errors from all fields\n */\n private getFieldErrors(\n callback: (field: Field) => FormSubmissionError[] | undefined,\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const { fields } = this\n\n if (!errors?.length) {\n return\n }\n\n const list: FormSubmissionError[] = []\n\n for (const field of fields) {\n const fieldErrors = callback(field)\n\n if (fieldErrors?.length) {\n list.push(...fieldErrors)\n }\n }\n\n if (!list.length) {\n return\n }\n\n return list\n }\n}\n\n/**\n * Check for field local state\n */\nexport function isErrorContext(\n value?: unknown\n): value is ErrorReportCollection['local'] {\n return isFormState(value) && typeof value.label === 'string'\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -4,6 +4,7 @@ import { ComponentCollection } from "./ComponentCollection.js";
|
|
|
4
4
|
import { FormComponent, isFormState, isFormValue } from "./FormComponent.js";
|
|
5
5
|
import { NumberField } from "./NumberField.js";
|
|
6
6
|
import { messageTemplate } from "../pageControllers/validationOptions.js";
|
|
7
|
+
import { convertToLanguageMessages } from "../../../utils/type-utils.js";
|
|
7
8
|
export class DatePartsField extends FormComponent {
|
|
8
9
|
constructor(def, props) {
|
|
9
10
|
super(def, props);
|
|
@@ -12,15 +13,17 @@ export class DatePartsField extends FormComponent {
|
|
|
12
13
|
options
|
|
13
14
|
} = def;
|
|
14
15
|
const isRequired = options.required !== false;
|
|
15
|
-
const customValidationMessages = {
|
|
16
|
+
const customValidationMessages = convertToLanguageMessages({
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
16
18
|
'any.required': messageTemplate.objectMissing,
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
17
20
|
'number.base': messageTemplate.objectMissing,
|
|
18
21
|
'number.precision': messageTemplate.dateFormat,
|
|
19
22
|
'number.integer': messageTemplate.dateFormat,
|
|
20
23
|
'number.unsafe': messageTemplate.dateFormat,
|
|
21
24
|
'number.min': messageTemplate.dateFormat,
|
|
22
25
|
'number.max': messageTemplate.dateFormat
|
|
23
|
-
};
|
|
26
|
+
});
|
|
24
27
|
this.collection = new ComponentCollection([{
|
|
25
28
|
type: ComponentType.NumberField,
|
|
26
29
|
name: `${name}__day`,
|
|
@@ -156,6 +159,37 @@ export class DatePartsField extends FormComponent {
|
|
|
156
159
|
isState(value) {
|
|
157
160
|
return DatePartsField.isDateParts(value);
|
|
158
161
|
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* For error preview page that shows all possible errors on a component
|
|
165
|
+
*/
|
|
166
|
+
getAllPossibleErrors() {
|
|
167
|
+
return {
|
|
168
|
+
baseErrors: [{
|
|
169
|
+
type: 'required',
|
|
170
|
+
template: messageTemplate.required
|
|
171
|
+
}, {
|
|
172
|
+
type: 'dateFormat',
|
|
173
|
+
template: messageTemplate.dateFormat
|
|
174
|
+
}, {
|
|
175
|
+
type: 'dateFormatDay',
|
|
176
|
+
template: '{{#label}} must include a day'
|
|
177
|
+
}, {
|
|
178
|
+
type: 'dateFormatMonth',
|
|
179
|
+
template: '{{#label}} must include a month'
|
|
180
|
+
}, {
|
|
181
|
+
type: 'dateFormatYear',
|
|
182
|
+
template: '{{#label}} must include a year'
|
|
183
|
+
}],
|
|
184
|
+
advancedSettingsErrors: [{
|
|
185
|
+
type: 'dateMin',
|
|
186
|
+
template: messageTemplate.dateMin
|
|
187
|
+
}, {
|
|
188
|
+
type: 'dateMax',
|
|
189
|
+
template: messageTemplate.dateMax
|
|
190
|
+
}]
|
|
191
|
+
};
|
|
192
|
+
}
|
|
159
193
|
static isDateParts(value) {
|
|
160
194
|
return isFormState(value) && NumberField.isNumber(value.day) && NumberField.isNumber(value.month) && NumberField.isNumber(value.year);
|
|
161
195
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatePartsField.js","names":["ComponentType","add","format","isValid","parse","startOfToday","sub","ComponentCollection","FormComponent","isFormState","isFormValue","NumberField","messageTemplate","DatePartsField","constructor","def","props","name","options","isRequired","required","customValidationMessages","objectMissing","dateFormat","collection","type","title","schema","min","max","precision","optionalText","classes","parent","custom","getValidatorDate","peers","formSchema","stateSchema","getFormValueFromState","state","value","isState","undefined","getDisplayStringFromState","year","month","day","getContextValueFromState","Date","getViewModel","payload","errors","viewModel","fieldset","label","hasError","some","error","items","map","model","errorMessage","toString","text","trim","id","legend","isDateParts","isNumber","component","validator","helpers","values","getStateFromValidForm","context","missing","keys","key","date","dateMin","maxDaysInPast","days","dateMax","maxDaysInFuture","limit"],"sources":["../../../../../src/server/plugins/engine/components/DatePartsField.ts"],"sourcesContent":["import { ComponentType, type DatePartsFieldComponent } from '@defra/forms-model'\nimport { add, format, isValid, parse, startOfToday, sub } from 'date-fns'\nimport {\n type Context,\n type CustomValidator,\n type LanguageMessages,\n type ObjectSchema\n} from 'joi'\n\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport {\n FormComponent,\n isFormState,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { NumberField } from '~/src/server/plugins/engine/components/NumberField.js'\nimport { type DateInputItem } from '~/src/server/plugins/engine/components/types.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\n\nexport class DatePartsField extends FormComponent {\n declare options: DatePartsFieldComponent['options']\n declare formSchema: ObjectSchema<FormPayload>\n declare stateSchema: ObjectSchema<FormState>\n declare collection: ComponentCollection\n\n constructor(\n def: DatePartsFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { name, options } = def\n\n const isRequired = options.required !== false\n\n const customValidationMessages: LanguageMessages = {\n 'any.required': messageTemplate.objectMissing,\n 'number.base': messageTemplate.objectMissing,\n 'number.precision': messageTemplate.dateFormat,\n 'number.integer': messageTemplate.dateFormat,\n 'number.unsafe': messageTemplate.dateFormat,\n 'number.min': messageTemplate.dateFormat,\n 'number.max': messageTemplate.dateFormat\n }\n\n this.collection = new ComponentCollection(\n [\n {\n type: ComponentType.NumberField,\n name: `${name}__day`,\n title: 'Day',\n schema: { min: 1, max: 31, precision: 0 },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-2',\n customValidationMessages\n }\n },\n {\n type: ComponentType.NumberField,\n name: `${name}__month`,\n title: 'Month',\n schema: { min: 1, max: 12, precision: 0 },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-2',\n customValidationMessages\n }\n },\n {\n type: ComponentType.NumberField,\n name: `${name}__year`,\n title: 'Year',\n schema: { min: 1000, max: 3000, precision: 0 },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-4',\n customValidationMessages\n }\n }\n ],\n { ...props, parent: this },\n {\n custom: getValidatorDate(this),\n peers: [`${name}__day`, `${name}__month`, `${name}__year`]\n }\n )\n\n this.options = options\n this.formSchema = this.collection.formSchema\n this.stateSchema = this.collection.stateSchema\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const value = super.getFormValueFromState(state)\n return this.isState(value) ? value : undefined\n }\n\n getDisplayStringFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n if (!value) {\n return ''\n }\n\n return format(`${value.year}-${value.month}-${value.day}`, 'd MMMM yyyy')\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n if (\n !value ||\n !isValid(\n parse(\n `${value.year}-${value.month}-${value.day}`,\n 'yyyy-MM-dd',\n new Date()\n )\n )\n ) {\n return null\n }\n\n return format(`${value.year}-${value.month}-${value.day}`, 'yyyy-MM-dd')\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const { collection, name } = this\n\n const viewModel = super.getViewModel(payload, errors)\n let { fieldset, label } = viewModel\n\n // Check for component errors only\n const hasError = errors?.some((error) => error.name === name)\n\n // Use the component collection to generate the subitems\n const items: DateInputItem[] = collection\n .getViewModel(payload, errors)\n .map(({ model }) => {\n let { label, type, value, classes, errorMessage } = model\n\n if (label) {\n label.toString = () => label.text // Date component uses string labels\n }\n\n if (hasError || errorMessage) {\n classes = `${classes} govuk-input--error`.trim()\n }\n\n // Allow any `toString()`-able value so non-numeric\n // values are shown alongside their error messages\n if (!isFormValue(value)) {\n value = undefined\n }\n\n return {\n label,\n id: model.id,\n name: model.name,\n type,\n value,\n classes\n }\n })\n\n fieldset ??= {\n legend: {\n text: label.text,\n classes: 'govuk-fieldset__legend--m'\n }\n }\n\n return {\n ...viewModel,\n fieldset,\n items\n }\n }\n\n isState(value?: FormStateValue | FormState) {\n return DatePartsField.isDateParts(value)\n }\n\n static isDateParts(\n value?: FormStateValue | FormState\n ): value is DatePartsState {\n return (\n isFormState(value) &&\n NumberField.isNumber(value.day) &&\n NumberField.isNumber(value.month) &&\n NumberField.isNumber(value.year)\n )\n }\n}\n\nexport interface DatePartsState extends Record<string, number> {\n day: number\n month: number\n year: number\n}\n\nexport function getValidatorDate(component: DatePartsField) {\n const validator: CustomValidator = (payload: FormPayload, helpers) => {\n const { collection, name, options } = component\n\n const values = component.getFormValueFromState(\n component.getStateFromValidForm(payload)\n )\n\n const context: Context = {\n missing: collection.keys,\n key: name\n }\n\n if (!component.isState(values)) {\n return options.required !== false\n ? helpers.error('object.required', context)\n : payload\n }\n\n const date = parse(\n `${values.year}-${values.month}-${values.day}`,\n 'yyyy-MM-dd',\n new Date()\n )\n\n if (!isValid(date)) {\n return helpers.error('date.format', context)\n }\n\n // Minimum date from today\n const dateMin = options.maxDaysInPast\n ? sub(startOfToday(), { days: options.maxDaysInPast })\n : undefined\n\n // Maximum date from today\n const dateMax = options.maxDaysInFuture\n ? add(startOfToday(), { days: options.maxDaysInFuture })\n : undefined\n\n if (dateMin && date < dateMin) {\n return helpers.error('date.min', { ...context, limit: dateMin })\n }\n\n if (dateMax && date > dateMax) {\n return helpers.error('date.max', { ...context, limit: dateMax })\n }\n\n return payload\n }\n\n return validator\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"DatePartsField.js","names":["ComponentType","add","format","isValid","parse","startOfToday","sub","ComponentCollection","FormComponent","isFormState","isFormValue","NumberField","messageTemplate","convertToLanguageMessages","DatePartsField","constructor","def","props","name","options","isRequired","required","customValidationMessages","objectMissing","dateFormat","collection","type","title","schema","min","max","precision","optionalText","classes","parent","custom","getValidatorDate","peers","formSchema","stateSchema","getFormValueFromState","state","value","isState","undefined","getDisplayStringFromState","year","month","day","getContextValueFromState","Date","getViewModel","payload","errors","viewModel","fieldset","label","hasError","some","error","items","map","model","errorMessage","toString","text","trim","id","legend","isDateParts","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","dateMin","dateMax","isNumber","component","validator","helpers","values","getStateFromValidForm","context","missing","keys","key","date","maxDaysInPast","days","maxDaysInFuture","limit"],"sources":["../../../../../src/server/plugins/engine/components/DatePartsField.ts"],"sourcesContent":["import { ComponentType, type DatePartsFieldComponent } from '@defra/forms-model'\nimport { add, format, isValid, parse, startOfToday, sub } from 'date-fns'\nimport { type Context, type CustomValidator, type ObjectSchema } from 'joi'\n\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport {\n FormComponent,\n isFormState,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { NumberField } from '~/src/server/plugins/engine/components/NumberField.js'\nimport { type DateInputItem } from '~/src/server/plugins/engine/components/types.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type ErrorMessageTemplateList,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\nimport { convertToLanguageMessages } from '~/src/server/utils/type-utils.js'\n\nexport class DatePartsField extends FormComponent {\n declare options: DatePartsFieldComponent['options']\n declare formSchema: ObjectSchema<FormPayload>\n declare stateSchema: ObjectSchema<FormState>\n declare collection: ComponentCollection\n\n constructor(\n def: DatePartsFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { name, options } = def\n\n const isRequired = options.required !== false\n\n const customValidationMessages = convertToLanguageMessages({\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n 'any.required': messageTemplate.objectMissing,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n 'number.base': messageTemplate.objectMissing,\n 'number.precision': messageTemplate.dateFormat,\n 'number.integer': messageTemplate.dateFormat,\n 'number.unsafe': messageTemplate.dateFormat,\n 'number.min': messageTemplate.dateFormat,\n 'number.max': messageTemplate.dateFormat\n })\n\n this.collection = new ComponentCollection(\n [\n {\n type: ComponentType.NumberField,\n name: `${name}__day`,\n title: 'Day',\n schema: { min: 1, max: 31, precision: 0 },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-2',\n customValidationMessages\n }\n },\n {\n type: ComponentType.NumberField,\n name: `${name}__month`,\n title: 'Month',\n schema: { min: 1, max: 12, precision: 0 },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-2',\n customValidationMessages\n }\n },\n {\n type: ComponentType.NumberField,\n name: `${name}__year`,\n title: 'Year',\n schema: { min: 1000, max: 3000, precision: 0 },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-4',\n customValidationMessages\n }\n }\n ],\n { ...props, parent: this },\n {\n custom: getValidatorDate(this),\n peers: [`${name}__day`, `${name}__month`, `${name}__year`]\n }\n )\n\n this.options = options\n this.formSchema = this.collection.formSchema\n this.stateSchema = this.collection.stateSchema\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const value = super.getFormValueFromState(state)\n return this.isState(value) ? value : undefined\n }\n\n getDisplayStringFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n if (!value) {\n return ''\n }\n\n return format(`${value.year}-${value.month}-${value.day}`, 'd MMMM yyyy')\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n if (\n !value ||\n !isValid(\n parse(\n `${value.year}-${value.month}-${value.day}`,\n 'yyyy-MM-dd',\n new Date()\n )\n )\n ) {\n return null\n }\n\n return format(`${value.year}-${value.month}-${value.day}`, 'yyyy-MM-dd')\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const { collection, name } = this\n\n const viewModel = super.getViewModel(payload, errors)\n let { fieldset, label } = viewModel\n\n // Check for component errors only\n const hasError = errors?.some((error) => error.name === name)\n\n // Use the component collection to generate the subitems\n const items: DateInputItem[] = collection\n .getViewModel(payload, errors)\n .map(({ model }) => {\n let { label, type, value, classes, errorMessage } = model\n\n if (label) {\n label.toString = () => label.text // Date component uses string labels\n }\n\n if (hasError || errorMessage) {\n classes = `${classes} govuk-input--error`.trim()\n }\n\n // Allow any `toString()`-able value so non-numeric\n // values are shown alongside their error messages\n if (!isFormValue(value)) {\n value = undefined\n }\n\n return {\n label,\n id: model.id,\n name: model.name,\n type,\n value,\n classes\n }\n })\n\n fieldset ??= {\n legend: {\n text: label.text,\n classes: 'govuk-fieldset__legend--m'\n }\n }\n\n return {\n ...viewModel,\n fieldset,\n items\n }\n }\n\n isState(value?: FormStateValue | FormState) {\n return DatePartsField.isDateParts(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: messageTemplate.required },\n { type: 'dateFormat', template: messageTemplate.dateFormat },\n { type: 'dateFormatDay', template: '{{#label}} must include a day' },\n {\n type: 'dateFormatMonth',\n template: '{{#label}} must include a month'\n },\n { type: 'dateFormatYear', template: '{{#label}} must include a year' }\n ],\n advancedSettingsErrors: [\n { type: 'dateMin', template: messageTemplate.dateMin },\n { type: 'dateMax', template: messageTemplate.dateMax }\n ]\n }\n }\n\n static isDateParts(\n value?: FormStateValue | FormState\n ): value is DatePartsState {\n return (\n isFormState(value) &&\n NumberField.isNumber(value.day) &&\n NumberField.isNumber(value.month) &&\n NumberField.isNumber(value.year)\n )\n }\n}\n\nexport interface DatePartsState extends Record<string, number> {\n day: number\n month: number\n year: number\n}\n\nexport function getValidatorDate(component: DatePartsField) {\n const validator: CustomValidator = (payload: FormPayload, helpers) => {\n const { collection, name, options } = component\n\n const values = component.getFormValueFromState(\n component.getStateFromValidForm(payload)\n )\n\n const context: Context = {\n missing: collection.keys,\n key: name\n }\n\n if (!component.isState(values)) {\n return options.required !== false\n ? helpers.error('object.required', context)\n : payload\n }\n\n const date = parse(\n `${values.year}-${values.month}-${values.day}`,\n 'yyyy-MM-dd',\n new Date()\n )\n\n if (!isValid(date)) {\n return helpers.error('date.format', context)\n }\n\n // Minimum date from today\n const dateMin = options.maxDaysInPast\n ? sub(startOfToday(), { days: options.maxDaysInPast })\n : undefined\n\n // Maximum date from today\n const dateMax = options.maxDaysInFuture\n ? add(startOfToday(), { days: options.maxDaysInFuture })\n : undefined\n\n if (dateMin && date < dateMin) {\n return helpers.error('date.min', { ...context, limit: dateMin })\n }\n\n if (dateMax && date > dateMax) {\n return helpers.error('date.max', { ...context, limit: dateMax })\n }\n\n return payload\n }\n\n return validator\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import joi from 'joi';
|
|
2
2
|
import { FormComponent } from "./FormComponent.js";
|
|
3
|
+
import { messageTemplate } from "../pageControllers/validationOptions.js";
|
|
3
4
|
export class EmailAddressField extends FormComponent {
|
|
4
5
|
constructor(def, props) {
|
|
5
6
|
super(def, props);
|
|
6
7
|
const {
|
|
7
|
-
options
|
|
8
|
-
title
|
|
8
|
+
options
|
|
9
9
|
} = def;
|
|
10
|
-
let formSchema = joi.string().email().trim().label(
|
|
10
|
+
let formSchema = joi.string().email().trim().label(this.label).required();
|
|
11
11
|
if (options.required === false) {
|
|
12
12
|
formSchema = formSchema.allow('');
|
|
13
13
|
}
|
|
@@ -36,5 +36,21 @@ export class EmailAddressField extends FormComponent {
|
|
|
36
36
|
type: 'email'
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* For error preview page that shows all possible errors on a component
|
|
42
|
+
*/
|
|
43
|
+
getAllPossibleErrors() {
|
|
44
|
+
return {
|
|
45
|
+
baseErrors: [{
|
|
46
|
+
type: 'required',
|
|
47
|
+
template: messageTemplate.required
|
|
48
|
+
}, {
|
|
49
|
+
type: 'format',
|
|
50
|
+
template: messageTemplate.format
|
|
51
|
+
}],
|
|
52
|
+
advancedSettingsErrors: []
|
|
53
|
+
};
|
|
54
|
+
}
|
|
39
55
|
}
|
|
40
56
|
//# sourceMappingURL=EmailAddressField.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmailAddressField.js","names":["joi","FormComponent","EmailAddressField","constructor","def","props","options","
|
|
1
|
+
{"version":3,"file":"EmailAddressField.js","names":["joi","FormComponent","messageTemplate","EmailAddressField","constructor","def","props","options","formSchema","string","email","trim","label","required","allow","customValidationMessage","message","messages","customValidationMessages","default","stateSchema","getViewModel","payload","errors","viewModel","attributes","autocomplete","type","getAllPossibleErrors","baseErrors","template","format","advancedSettingsErrors"],"sources":["../../../../../src/server/plugins/engine/components/EmailAddressField.ts"],"sourcesContent":["import { type EmailAddressFieldComponent } from '@defra/forms-model'\nimport joi from 'joi'\n\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type ErrorMessageTemplateList,\n type FormPayload,\n type FormSubmissionError\n} from '~/src/server/plugins/engine/types.js'\n\nexport class EmailAddressField extends FormComponent {\n declare options: EmailAddressFieldComponent['options']\n\n constructor(\n def: EmailAddressFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options } = def\n\n let formSchema = joi.string().email().trim().label(this.label).required()\n\n if (options.required === false) {\n formSchema = formSchema.allow('')\n }\n\n if (options.customValidationMessage) {\n const message = options.customValidationMessage\n\n formSchema = formSchema.messages({\n 'any.required': message,\n 'string.empty': message,\n 'string.email': message\n })\n } else if (options.customValidationMessages) {\n formSchema = formSchema.messages(options.customValidationMessages)\n }\n\n this.formSchema = formSchema.default('')\n this.stateSchema = formSchema.default(null).allow(null)\n this.options = options\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const viewModel = super.getViewModel(payload, errors)\n const { attributes } = viewModel\n\n attributes.autocomplete = 'email'\n\n return {\n ...viewModel,\n type: 'email'\n }\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: messageTemplate.required },\n { type: 'format', template: messageTemplate.format }\n ],\n advancedSettingsErrors: []\n }\n }\n}\n"],"mappings":"AACA,OAAOA,GAAG,MAAM,KAAK;AAErB,SAASC,aAAa;AACtB,SAASC,eAAe;AAOxB,OAAO,MAAMC,iBAAiB,SAASF,aAAa,CAAC;EAGnDG,WAAWA,CACTC,GAA+B,EAC/BC,KAAqD,EACrD;IACA,KAAK,CAACD,GAAG,EAAEC,KAAK,CAAC;IAEjB,MAAM;MAAEC;IAAQ,CAAC,GAAGF,GAAG;IAEvB,IAAIG,UAAU,GAAGR,GAAG,CAACS,MAAM,CAAC,CAAC,CAACC,KAAK,CAAC,CAAC,CAACC,IAAI,CAAC,CAAC,CAACC,KAAK,CAAC,IAAI,CAACA,KAAK,CAAC,CAACC,QAAQ,CAAC,CAAC;IAEzE,IAAIN,OAAO,CAACM,QAAQ,KAAK,KAAK,EAAE;MAC9BL,UAAU,GAAGA,UAAU,CAACM,KAAK,CAAC,EAAE,CAAC;IACnC;IAEA,IAAIP,OAAO,CAACQ,uBAAuB,EAAE;MACnC,MAAMC,OAAO,GAAGT,OAAO,CAACQ,uBAAuB;MAE/CP,UAAU,GAAGA,UAAU,CAACS,QAAQ,CAAC;QAC/B,cAAc,EAAED,OAAO;QACvB,cAAc,EAAEA,OAAO;QACvB,cAAc,EAAEA;MAClB,CAAC,CAAC;IACJ,CAAC,MAAM,IAAIT,OAAO,CAACW,wBAAwB,EAAE;MAC3CV,UAAU,GAAGA,UAAU,CAACS,QAAQ,CAACV,OAAO,CAACW,wBAAwB,CAAC;IACpE;IAEA,IAAI,CAACV,UAAU,GAAGA,UAAU,CAACW,OAAO,CAAC,EAAE,CAAC;IACxC,IAAI,CAACC,WAAW,GAAGZ,UAAU,CAACW,OAAO,CAAC,IAAI,CAAC,CAACL,KAAK,CAAC,IAAI,CAAC;IACvD,IAAI,CAACP,OAAO,GAAGA,OAAO;EACxB;EAEAc,YAAYA,CAACC,OAAoB,EAAEC,MAA8B,EAAE;IACjE,MAAMC,SAAS,GAAG,KAAK,CAACH,YAAY,CAACC,OAAO,EAAEC,MAAM,CAAC;IACrD,MAAM;MAAEE;IAAW,CAAC,GAAGD,SAAS;IAEhCC,UAAU,CAACC,YAAY,GAAG,OAAO;IAEjC,OAAO;MACL,GAAGF,SAAS;MACZG,IAAI,EAAE;IACR,CAAC;EACH;;EAEA;AACF;AACA;EACEC,oBAAoBA,CAAA,EAA6B;IAC/C,OAAO;MACLC,UAAU,EAAE,CACV;QAAEF,IAAI,EAAE,UAAU;QAAEG,QAAQ,EAAE5B,eAAe,CAACW;MAAS,CAAC,EACxD;QAAEc,IAAI,EAAE,QAAQ;QAAEG,QAAQ,EAAE5B,eAAe,CAAC6B;MAAO,CAAC,CACrD;MACDC,sBAAsB,EAAE;IAC1B,CAAC;EACH;AACF","ignoreList":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import joi from 'joi';
|
|
2
2
|
import { FormComponent, isUploadState } from "./FormComponent.js";
|
|
3
|
+
import { messageTemplate } from "../pageControllers/validationOptions.js";
|
|
3
4
|
import { FileStatus, UploadStatus } from "../types.js";
|
|
4
5
|
import { render } from "../../nunjucks/index.js";
|
|
5
6
|
export const uploadIdSchema = joi.string().uuid().required();
|
|
@@ -48,10 +49,9 @@ export class FileUploadField extends FormComponent {
|
|
|
48
49
|
super(def, props);
|
|
49
50
|
const {
|
|
50
51
|
options,
|
|
51
|
-
schema
|
|
52
|
-
title
|
|
52
|
+
schema
|
|
53
53
|
} = def;
|
|
54
|
-
let formSchema = joi.array().label(
|
|
54
|
+
let formSchema = joi.array().label(this.label).single().required();
|
|
55
55
|
if (options.required === false) {
|
|
56
56
|
formSchema = formSchema.optional();
|
|
57
57
|
}
|
|
@@ -169,7 +169,7 @@ export class FileUploadField extends FormComponent {
|
|
|
169
169
|
});
|
|
170
170
|
|
|
171
171
|
// Set up the `accept` attribute
|
|
172
|
-
if ('accept' in options) {
|
|
172
|
+
if ('accept' in options && options.accept) {
|
|
173
173
|
attributes.accept = options.accept;
|
|
174
174
|
}
|
|
175
175
|
const summaryList = {
|
|
@@ -191,5 +191,45 @@ export class FileUploadField extends FormComponent {
|
|
|
191
191
|
isValue(value) {
|
|
192
192
|
return isUploadState(value);
|
|
193
193
|
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* For error preview page that shows all possible errors on a component
|
|
197
|
+
*/
|
|
198
|
+
getAllPossibleErrors() {
|
|
199
|
+
return {
|
|
200
|
+
baseErrors: [{
|
|
201
|
+
type: 'selectRequired',
|
|
202
|
+
template: messageTemplate.selectRequired
|
|
203
|
+
}, {
|
|
204
|
+
type: 'filesMimes',
|
|
205
|
+
template: 'The selected file must be a {{#limit}}'
|
|
206
|
+
}, {
|
|
207
|
+
type: 'filesSize',
|
|
208
|
+
template: 'The selected file must be smaller than 100MB'
|
|
209
|
+
}, {
|
|
210
|
+
type: 'filesEmpty',
|
|
211
|
+
template: 'The selected file is empty'
|
|
212
|
+
}, {
|
|
213
|
+
type: 'filesVirus',
|
|
214
|
+
template: 'The selected file contains a virus'
|
|
215
|
+
}, {
|
|
216
|
+
type: 'filesPartial',
|
|
217
|
+
template: 'The selected file has not fully uploaded'
|
|
218
|
+
}, {
|
|
219
|
+
type: 'filesError',
|
|
220
|
+
template: 'The selected file could not be uploaded – try again'
|
|
221
|
+
}],
|
|
222
|
+
advancedSettingsErrors: [{
|
|
223
|
+
type: 'filesMin',
|
|
224
|
+
template: 'You must upload {{#limit}} files or more'
|
|
225
|
+
}, {
|
|
226
|
+
type: 'filesMax',
|
|
227
|
+
template: 'You can only upload {{#limit}} files or less'
|
|
228
|
+
}, {
|
|
229
|
+
type: 'filesExact',
|
|
230
|
+
template: 'You must upload exactly {{#limit}} files'
|
|
231
|
+
}]
|
|
232
|
+
};
|
|
233
|
+
}
|
|
194
234
|
}
|
|
195
235
|
//# sourceMappingURL=FileUploadField.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileUploadField.js","names":["joi","FormComponent","isUploadState","FileStatus","UploadStatus","render","uploadIdSchema","string","uuid","required","fileSchema","object","fileId","filename","contentLength","number","tempFileSchema","append","fileStatus","valid","complete","rejected","pending","errorMessage","optional","formFileSchema","metadataSchema","keys","retrievalKey","email","tempStatusSchema","uploadStatus","ready","metadata","form","file","numberOfRejectedFiles","formStatusSchema","itemSchema","uploadId","tempItemSchema","status","formItemSchema","FileUploadField","constructor","def","props","options","schema","title","formSchema","array","label","single","length","max","min","items","stateSchema","default","allow","getFormValueFromState","state","name","getFormValue","value","isValue","undefined","getDisplayStringFromState","files","unit","getContextValueFromState","map","getViewModel","payload","errors","query","page","isForceAccess","viewModel","attributes","id","filtered","filter","count","rows","item","index","tag","classes","text","valueHtml","view","context","params","trim","keyHtml","path","href","getHref","push","visuallyHiddenText","key","html","actions","accept","summaryList","upload"],"sources":["../../../../../src/server/plugins/engine/components/FileUploadField.ts"],"sourcesContent":["import { type FileUploadFieldComponent } from '@defra/forms-model'\nimport joi, { type ArraySchema } from 'joi'\n\nimport {\n FormComponent,\n isUploadState\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n FileStatus,\n UploadStatus,\n type FileState,\n type FileUpload,\n type FileUploadMetadata,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type SummaryList,\n type SummaryListAction,\n type SummaryListRow,\n type UploadState,\n type UploadStatusFileResponse,\n type UploadStatusResponse\n} from '~/src/server/plugins/engine/types.js'\nimport { render } from '~/src/server/plugins/nunjucks/index.js'\nimport { type FormQuery } from '~/src/server/routes/types.js'\n\nexport const uploadIdSchema = joi.string().uuid().required()\n\nexport const fileSchema = joi\n .object<FileUpload>({\n fileId: joi.string().uuid().required(),\n filename: joi.string().required(),\n contentLength: joi.number().required()\n })\n .required()\n\nexport const tempFileSchema = fileSchema.append({\n fileStatus: joi\n .string()\n .valid(FileStatus.complete, FileStatus.rejected, FileStatus.pending)\n .required(),\n errorMessage: joi.string().optional()\n})\n\nexport const formFileSchema = fileSchema.append({\n fileStatus: joi.string().valid(FileStatus.complete).required()\n})\n\nexport const metadataSchema = joi\n .object<FileUploadMetadata>()\n .keys({\n retrievalKey: joi.string().email().required()\n })\n .required()\n\nexport const tempStatusSchema = joi\n .object<UploadStatusFileResponse>({\n uploadStatus: joi\n .string()\n .valid(UploadStatus.ready, UploadStatus.pending)\n .required(),\n metadata: metadataSchema,\n form: joi.object().required().keys({\n file: tempFileSchema\n }),\n numberOfRejectedFiles: joi.number().optional()\n })\n .required()\n\nexport const formStatusSchema = joi\n .object<UploadStatusResponse>({\n uploadStatus: joi.string().valid(UploadStatus.ready).required(),\n metadata: metadataSchema,\n form: joi.object().required().keys({\n file: formFileSchema\n }),\n numberOfRejectedFiles: joi.number().valid(0).required()\n })\n .required()\n\nexport const itemSchema = joi.object<FileState>({\n uploadId: uploadIdSchema\n})\n\nexport const tempItemSchema = itemSchema.append({\n status: tempStatusSchema\n})\n\nexport const formItemSchema = itemSchema.append({\n status: formStatusSchema\n})\n\nexport class FileUploadField extends FormComponent {\n declare options: FileUploadFieldComponent['options']\n declare schema: FileUploadFieldComponent['schema']\n declare formSchema: ArraySchema<FileState>\n declare stateSchema: ArraySchema<FileState>\n\n constructor(\n def: FileUploadFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options, schema, title } = def\n\n let formSchema = joi.array<FileState>().label(title).single().required()\n\n if (options.required === false) {\n formSchema = formSchema.optional()\n }\n\n if (typeof schema.length !== 'number') {\n if (typeof schema.max === 'number') {\n formSchema = formSchema.max(schema.max)\n }\n\n if (typeof schema.min === 'number') {\n formSchema = formSchema.min(schema.min)\n }\n } else {\n formSchema = formSchema.length(schema.length)\n }\n\n this.formSchema = formSchema.items(formItemSchema)\n this.stateSchema = formSchema\n .items(formItemSchema)\n .default(null)\n .allow(null)\n\n this.options = options\n this.schema = schema\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const { name } = this\n return this.getFormValue(state[name])\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getDisplayStringFromState(state: FormSubmissionState) {\n const files = this.getFormValueFromState(state)\n if (!files?.length) {\n return ''\n }\n\n const unit = files.length === 1 ? 'file' : 'files'\n return `Uploaded ${files.length} ${unit}`\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const files = this.getFormValueFromState(state)\n return files?.map(({ status }) => status.form.file.fileId) ?? null\n }\n\n getViewModel(\n payload: FormPayload,\n errors?: FormSubmissionError[],\n query: FormQuery = {}\n ) {\n const { options, page } = this\n\n // Allow preview URL direct access\n const isForceAccess = 'force' in query\n\n const viewModel = super.getViewModel(payload, errors)\n const { attributes, id, value } = viewModel\n\n const files = this.getFormValue(value) ?? []\n const filtered = files.filter(\n (file) => file.status.form.file.fileStatus === FileStatus.complete\n )\n const count = filtered.length\n\n const rows: SummaryListRow[] = filtered.map((item, index) => {\n const { status } = item\n const { form } = status\n const { file } = form\n\n const tag = { classes: 'govuk-tag--green', text: 'Uploaded' }\n\n const valueHtml = render\n .view('components/fileuploadfield-value.html', {\n context: { params: { tag } }\n })\n .trim()\n\n const keyHtml = render\n .view('components/fileuploadfield-key.html', {\n context: {\n params: {\n name: file.filename,\n errorMessage: errors && file.errorMessage\n }\n }\n })\n .trim()\n\n const items: SummaryListAction[] = []\n\n // Remove summary list actions from previews\n if (!isForceAccess) {\n const path = `/${item.uploadId}/confirm-delete`\n const href = page?.getHref(`${page.path}${path}`) ?? '#'\n\n items.push({\n href,\n text: 'Remove',\n classes: 'govuk-link--no-visited-state',\n attributes: { id: `${id}__${index}` },\n visuallyHiddenText: file.filename\n })\n }\n\n return {\n key: {\n html: keyHtml\n },\n value: {\n html: valueHtml\n },\n actions: {\n items\n }\n } satisfies SummaryListRow\n })\n\n // Set up the `accept` attribute\n if ('accept' in options) {\n attributes.accept = options.accept\n }\n\n const summaryList: SummaryList = {\n classes: 'govuk-summary-list--long-key',\n rows\n }\n\n return {\n ...viewModel,\n\n // File input can't have a initial value\n value: '',\n\n // Override the component name we send to CDP\n name: 'file',\n\n upload: {\n count,\n summaryList\n }\n }\n }\n\n isValue(value?: FormStateValue | FormState): value is UploadState {\n return isUploadState(value)\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"FileUploadField.js","names":["joi","FormComponent","isUploadState","messageTemplate","FileStatus","UploadStatus","render","uploadIdSchema","string","uuid","required","fileSchema","object","fileId","filename","contentLength","number","tempFileSchema","append","fileStatus","valid","complete","rejected","pending","errorMessage","optional","formFileSchema","metadataSchema","keys","retrievalKey","email","tempStatusSchema","uploadStatus","ready","metadata","form","file","numberOfRejectedFiles","formStatusSchema","itemSchema","uploadId","tempItemSchema","status","formItemSchema","FileUploadField","constructor","def","props","options","schema","formSchema","array","label","single","length","max","min","items","stateSchema","default","allow","getFormValueFromState","state","name","getFormValue","value","isValue","undefined","getDisplayStringFromState","files","unit","getContextValueFromState","map","getViewModel","payload","errors","query","page","isForceAccess","viewModel","attributes","id","filtered","filter","count","rows","item","index","tag","classes","text","valueHtml","view","context","params","trim","keyHtml","path","href","getHref","push","visuallyHiddenText","key","html","actions","accept","summaryList","upload","getAllPossibleErrors","baseErrors","type","template","selectRequired","advancedSettingsErrors"],"sources":["../../../../../src/server/plugins/engine/components/FileUploadField.ts"],"sourcesContent":["import { type FileUploadFieldComponent } from '@defra/forms-model'\nimport joi, { type ArraySchema } from 'joi'\n\nimport {\n FormComponent,\n isUploadState\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n FileStatus,\n UploadStatus,\n type ErrorMessageTemplateList,\n type FileState,\n type FileUpload,\n type FileUploadMetadata,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type SummaryList,\n type SummaryListAction,\n type SummaryListRow,\n type UploadState,\n type UploadStatusFileResponse,\n type UploadStatusResponse\n} from '~/src/server/plugins/engine/types.js'\nimport { render } from '~/src/server/plugins/nunjucks/index.js'\nimport { type FormQuery } from '~/src/server/routes/types.js'\n\nexport const uploadIdSchema = joi.string().uuid().required()\n\nexport const fileSchema = joi\n .object<FileUpload>({\n fileId: joi.string().uuid().required(),\n filename: joi.string().required(),\n contentLength: joi.number().required()\n })\n .required()\n\nexport const tempFileSchema = fileSchema.append({\n fileStatus: joi\n .string()\n .valid(FileStatus.complete, FileStatus.rejected, FileStatus.pending)\n .required(),\n errorMessage: joi.string().optional()\n})\n\nexport const formFileSchema = fileSchema.append({\n fileStatus: joi.string().valid(FileStatus.complete).required()\n})\n\nexport const metadataSchema = joi\n .object<FileUploadMetadata>()\n .keys({\n retrievalKey: joi.string().email().required()\n })\n .required()\n\nexport const tempStatusSchema = joi\n .object<UploadStatusFileResponse>({\n uploadStatus: joi\n .string()\n .valid(UploadStatus.ready, UploadStatus.pending)\n .required(),\n metadata: metadataSchema,\n form: joi.object().required().keys({\n file: tempFileSchema\n }),\n numberOfRejectedFiles: joi.number().optional()\n })\n .required()\n\nexport const formStatusSchema = joi\n .object<UploadStatusResponse>({\n uploadStatus: joi.string().valid(UploadStatus.ready).required(),\n metadata: metadataSchema,\n form: joi.object().required().keys({\n file: formFileSchema\n }),\n numberOfRejectedFiles: joi.number().valid(0).required()\n })\n .required()\n\nexport const itemSchema = joi.object<FileState>({\n uploadId: uploadIdSchema\n})\n\nexport const tempItemSchema = itemSchema.append({\n status: tempStatusSchema\n})\n\nexport const formItemSchema = itemSchema.append({\n status: formStatusSchema\n})\n\nexport class FileUploadField extends FormComponent {\n declare options: FileUploadFieldComponent['options']\n declare schema: FileUploadFieldComponent['schema']\n declare formSchema: ArraySchema<FileState>\n declare stateSchema: ArraySchema<FileState>\n\n constructor(\n def: FileUploadFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options, schema } = def\n\n let formSchema = joi\n .array<FileState>()\n .label(this.label)\n .single()\n .required()\n\n if (options.required === false) {\n formSchema = formSchema.optional()\n }\n\n if (typeof schema.length !== 'number') {\n if (typeof schema.max === 'number') {\n formSchema = formSchema.max(schema.max)\n }\n\n if (typeof schema.min === 'number') {\n formSchema = formSchema.min(schema.min)\n }\n } else {\n formSchema = formSchema.length(schema.length)\n }\n\n this.formSchema = formSchema.items(formItemSchema)\n this.stateSchema = formSchema\n .items(formItemSchema)\n .default(null)\n .allow(null)\n\n this.options = options\n this.schema = schema\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const { name } = this\n return this.getFormValue(state[name])\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getDisplayStringFromState(state: FormSubmissionState) {\n const files = this.getFormValueFromState(state)\n if (!files?.length) {\n return ''\n }\n\n const unit = files.length === 1 ? 'file' : 'files'\n return `Uploaded ${files.length} ${unit}`\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const files = this.getFormValueFromState(state)\n return files?.map(({ status }) => status.form.file.fileId) ?? null\n }\n\n getViewModel(\n payload: FormPayload,\n errors?: FormSubmissionError[],\n query: FormQuery = {}\n ) {\n const { options, page } = this\n\n // Allow preview URL direct access\n const isForceAccess = 'force' in query\n\n const viewModel = super.getViewModel(payload, errors)\n const { attributes, id, value } = viewModel\n\n const files = this.getFormValue(value) ?? []\n const filtered = files.filter(\n (file) => file.status.form.file.fileStatus === FileStatus.complete\n )\n const count = filtered.length\n\n const rows: SummaryListRow[] = filtered.map((item, index) => {\n const { status } = item\n const { form } = status\n const { file } = form\n\n const tag = { classes: 'govuk-tag--green', text: 'Uploaded' }\n\n const valueHtml = render\n .view('components/fileuploadfield-value.html', {\n context: { params: { tag } }\n })\n .trim()\n\n const keyHtml = render\n .view('components/fileuploadfield-key.html', {\n context: {\n params: {\n name: file.filename,\n errorMessage: errors && file.errorMessage\n }\n }\n })\n .trim()\n\n const items: SummaryListAction[] = []\n\n // Remove summary list actions from previews\n if (!isForceAccess) {\n const path = `/${item.uploadId}/confirm-delete`\n const href = page?.getHref(`${page.path}${path}`) ?? '#'\n\n items.push({\n href,\n text: 'Remove',\n classes: 'govuk-link--no-visited-state',\n attributes: { id: `${id}__${index}` },\n visuallyHiddenText: file.filename\n })\n }\n\n return {\n key: {\n html: keyHtml\n },\n value: {\n html: valueHtml\n },\n actions: {\n items\n }\n } satisfies SummaryListRow\n })\n\n // Set up the `accept` attribute\n if ('accept' in options && options.accept) {\n attributes.accept = options.accept\n }\n\n const summaryList: SummaryList = {\n classes: 'govuk-summary-list--long-key',\n rows\n }\n\n return {\n ...viewModel,\n\n // File input can't have a initial value\n value: '',\n\n // Override the component name we send to CDP\n name: 'file',\n\n upload: {\n count,\n summaryList\n }\n }\n }\n\n isValue(value?: FormStateValue | FormState): value is UploadState {\n return isUploadState(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'selectRequired', template: messageTemplate.selectRequired },\n {\n type: 'filesMimes',\n template: 'The selected file must be a {{#limit}}'\n },\n {\n type: 'filesSize',\n template: 'The selected file must be smaller than 100MB'\n },\n { type: 'filesEmpty', template: 'The selected file is empty' },\n { type: 'filesVirus', template: 'The selected file contains a virus' },\n {\n type: 'filesPartial',\n template: 'The selected file has not fully uploaded'\n },\n {\n type: 'filesError',\n template: 'The selected file could not be uploaded – try again'\n }\n ],\n advancedSettingsErrors: [\n {\n type: 'filesMin',\n template: 'You must upload {{#limit}} files or more'\n },\n {\n type: 'filesMax',\n template: 'You can only upload {{#limit}} files or less'\n },\n {\n type: 'filesExact',\n template: 'You must upload exactly {{#limit}} files'\n }\n ]\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -3,6 +3,7 @@ import { optionalText } from "./constants.js";
|
|
|
3
3
|
export class FormComponent extends ComponentBase {
|
|
4
4
|
type;
|
|
5
5
|
hint;
|
|
6
|
+
label;
|
|
6
7
|
isFormComponent = true;
|
|
7
8
|
constructor(def, props) {
|
|
8
9
|
super(def, props);
|
|
@@ -12,6 +13,7 @@ export class FormComponent extends ComponentBase {
|
|
|
12
13
|
} = def;
|
|
13
14
|
this.type = type;
|
|
14
15
|
this.hint = hint;
|
|
16
|
+
this.label = 'shortDescription' in def && def.shortDescription ? def.shortDescription : def.title;
|
|
15
17
|
}
|
|
16
18
|
get keys() {
|
|
17
19
|
const {
|
|
@@ -77,9 +79,13 @@ export class FormComponent extends ComponentBase {
|
|
|
77
79
|
}
|
|
78
80
|
return list;
|
|
79
81
|
}
|
|
80
|
-
|
|
82
|
+
getFirstError(errors) {
|
|
81
83
|
return this.getErrors(errors)?.[0];
|
|
82
84
|
}
|
|
85
|
+
getViewErrors(errors) {
|
|
86
|
+
const firstError = this.getFirstError(errors);
|
|
87
|
+
return firstError && [firstError];
|
|
88
|
+
}
|
|
83
89
|
getViewModel(payload, errors) {
|
|
84
90
|
const {
|
|
85
91
|
hint,
|
|
@@ -99,7 +105,7 @@ export class FormComponent extends ComponentBase {
|
|
|
99
105
|
|
|
100
106
|
// Filter component errors only
|
|
101
107
|
const componentErrors = this.getErrors(errors);
|
|
102
|
-
const componentError = this.
|
|
108
|
+
const componentError = this.getFirstError(componentErrors);
|
|
103
109
|
if (componentErrors) {
|
|
104
110
|
viewModel.errors = componentErrors;
|
|
105
111
|
}
|
|
@@ -143,6 +149,12 @@ export class FormComponent extends ComponentBase {
|
|
|
143
149
|
isState(value) {
|
|
144
150
|
return isFormState(value);
|
|
145
151
|
}
|
|
152
|
+
getAllPossibleErrors() {
|
|
153
|
+
return {
|
|
154
|
+
baseErrors: [],
|
|
155
|
+
advancedSettingsErrors: []
|
|
156
|
+
};
|
|
157
|
+
}
|
|
146
158
|
}
|
|
147
159
|
|
|
148
160
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormComponent.js","names":["ComponentBase","optionalText","FormComponent","type","hint","isFormComponent","constructor","def","props","keys","collection","name","fields","map","getFormDataFromState","state","getFormValue","getFormValueFromState","value","isValue","undefined","getStateFromValidForm","payload","getErrors","errors","list","filter","error","path","includes","length","getError","getViewModel","options","title","viewModel","isRequired","required","hideOptional","label","text","componentErrors","componentError","errorMessage","id","getDisplayStringFromState","toString","getContextValueFromState","isState","values","Object","isFormValue","Array","isArray","isFormState","isRepeatState","every","isRepeatValue","itemId","isUploadState","isUploadValue","uploadId"],"sources":["../../../../../src/server/plugins/engine/components/FormComponent.ts"],"sourcesContent":["import { type FormComponentsDef, type Item } from '@defra/forms-model'\n\nimport { ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'\nimport { optionalText } from '~/src/server/plugins/engine/components/constants.js'\nimport {\n type FileState,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValue,\n type RepeatItemState,\n type RepeatListState,\n type UploadState\n} from '~/src/server/plugins/engine/types.js'\n\nexport class FormComponent extends ComponentBase {\n type: FormComponentsDef['type']\n hint: FormComponentsDef['hint']\n\n isFormComponent = true\n\n constructor(\n def: FormComponentsDef,\n props: ConstructorParameters<typeof ComponentBase>[1]\n ) {\n super(def, props)\n\n const { hint, type } = def\n\n this.type = type\n this.hint = hint\n }\n\n get keys() {\n const { collection, name } = this\n\n if (collection) {\n const { fields } = collection\n return [name, ...fields.map(({ name }) => name)]\n }\n\n return [name]\n }\n\n getFormDataFromState(state: FormSubmissionState): FormPayload {\n const { collection, name } = this\n\n if (collection) {\n return collection.getFormDataFromState(state)\n }\n\n return {\n [name]: this.getFormValue(state[name])\n }\n }\n\n getFormValueFromState(state: FormSubmissionState): FormValue | FormPayload {\n const { collection, name } = this\n\n if (collection) {\n return collection.getFormValueFromState(state)\n }\n\n return this.getFormValue(state[name])\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getStateFromValidForm(payload: FormPayload): FormState {\n const { collection, name } = this\n\n if (collection) {\n return collection.getStateFromValidForm(payload)\n }\n\n return {\n [name]: this.getFormValue(payload[name]) ?? null\n }\n }\n\n getErrors(errors?: FormSubmissionError[]): FormSubmissionError[] | undefined {\n const { name } = this\n\n // Filter component and child errors only\n const list = errors?.filter(\n (error) =>\n error.name === name ||\n error.path.includes(name) ||\n this.keys.includes(error.name)\n )\n\n if (!list?.length) {\n return\n }\n\n return list\n }\n\n getError(errors?: FormSubmissionError[]): FormSubmissionError | undefined {\n return this.getErrors(errors)?.[0]\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const { hint, name, options = {}, title, viewModel } = this\n\n const isRequired = !('required' in options) || options.required !== false\n const hideOptional = 'optionalText' in options && options.optionalText\n const label = `${title}${!isRequired && !hideOptional ? optionalText : ''}`\n\n if (hint) {\n viewModel.hint = {\n text: hint\n }\n }\n\n // Filter component errors only\n const componentErrors = this.getErrors(errors)\n const componentError = this.getError(componentErrors)\n\n if (componentErrors) {\n viewModel.errors = componentErrors\n }\n\n if (componentError) {\n viewModel.errorMessage = {\n text: componentError.text\n }\n }\n\n return {\n ...viewModel,\n label: {\n text: label\n },\n id: name,\n name,\n value: payload[name]\n }\n }\n\n getDisplayStringFromState(state: FormSubmissionState): string {\n const value = this.getFormValueFromState(state)\n return this.isValue(value) ? value.toString() : ''\n }\n\n getContextValueFromState(\n state: FormSubmissionState\n ): Item['value'] | Item['value'][] | null {\n const value = this.getFormValueFromState(state)\n\n // Filter object field values\n if (this.isState(value)) {\n const values = Object.values(value).filter(isFormValue)\n return values.length ? values : null\n }\n\n // Filter array field values\n if (this.isValue(value) && Array.isArray(value)) {\n return value.filter(isFormValue)\n }\n\n return this.isValue(value) ? value : null\n }\n\n isValue(\n value?: FormStateValue | FormState\n ): value is NonNullable<FormStateValue> {\n return isFormValue(value)\n }\n\n isState(value?: FormStateValue | FormState): value is FormState {\n return isFormState(value)\n }\n}\n\n/**\n * Check for form value\n */\nexport function isFormValue(\n value?: unknown\n): value is string | number | boolean {\n return (\n (typeof value === 'string' && value.length > 0) ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n )\n}\n\n/**\n * Check for form state with nested values\n */\nexport function isFormState(value?: unknown): value is FormState {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false\n }\n\n // Skip empty objects\n return !!Object.values(value).length\n}\n\n/**\n * Check for repeat list state\n */\nexport function isRepeatState(value?: unknown): value is RepeatListState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isRepeatValue)\n}\n\n/**\n * Check for repeat list value\n */\nexport function isRepeatValue(value?: unknown): value is RepeatItemState {\n return isFormState(value) && typeof value.itemId === 'string'\n}\n\n/**\n * Check for upload state\n */\nexport function isUploadState(value?: unknown): value is UploadState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isUploadValue)\n}\n\n/**\n * Check for upload state value\n */\nexport function isUploadValue(value?: unknown): value is FileState {\n return isFormState(value) && typeof value.uploadId === 'string'\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"FormComponent.js","names":["ComponentBase","optionalText","FormComponent","type","hint","label","isFormComponent","constructor","def","props","shortDescription","title","keys","collection","name","fields","map","getFormDataFromState","state","getFormValue","getFormValueFromState","value","isValue","undefined","getStateFromValidForm","payload","getErrors","errors","list","filter","error","path","includes","length","getFirstError","getViewErrors","firstError","getViewModel","options","viewModel","isRequired","required","hideOptional","text","componentErrors","componentError","errorMessage","id","getDisplayStringFromState","toString","getContextValueFromState","isState","values","Object","isFormValue","Array","isArray","isFormState","getAllPossibleErrors","baseErrors","advancedSettingsErrors","isRepeatState","every","isRepeatValue","itemId","isUploadState","isUploadValue","uploadId"],"sources":["../../../../../src/server/plugins/engine/components/FormComponent.ts"],"sourcesContent":["import { type FormComponentsDef, type Item } from '@defra/forms-model'\n\nimport { ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'\nimport { optionalText } from '~/src/server/plugins/engine/components/constants.js'\nimport {\n type ErrorMessageTemplateList,\n type FileState,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValue,\n type RepeatItemState,\n type RepeatListState,\n type UploadState\n} from '~/src/server/plugins/engine/types.js'\n\nexport class FormComponent extends ComponentBase {\n type: FormComponentsDef['type']\n hint: FormComponentsDef['hint']\n label: string\n\n isFormComponent = true\n\n constructor(\n def: FormComponentsDef,\n props: ConstructorParameters<typeof ComponentBase>[1]\n ) {\n super(def, props)\n\n const { hint, type } = def\n\n this.type = type\n this.hint = hint\n this.label =\n 'shortDescription' in def && def.shortDescription\n ? def.shortDescription\n : def.title\n }\n\n get keys() {\n const { collection, name } = this\n\n if (collection) {\n const { fields } = collection\n return [name, ...fields.map(({ name }) => name)]\n }\n\n return [name]\n }\n\n getFormDataFromState(state: FormSubmissionState): FormPayload {\n const { collection, name } = this\n\n if (collection) {\n return collection.getFormDataFromState(state)\n }\n\n return {\n [name]: this.getFormValue(state[name])\n }\n }\n\n getFormValueFromState(state: FormSubmissionState): FormValue | FormPayload {\n const { collection, name } = this\n\n if (collection) {\n return collection.getFormValueFromState(state)\n }\n\n return this.getFormValue(state[name])\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getStateFromValidForm(payload: FormPayload): FormState {\n const { collection, name } = this\n\n if (collection) {\n return collection.getStateFromValidForm(payload)\n }\n\n return {\n [name]: this.getFormValue(payload[name]) ?? null\n }\n }\n\n getErrors(errors?: FormSubmissionError[]): FormSubmissionError[] | undefined {\n const { name } = this\n\n // Filter component and child errors only\n const list = errors?.filter(\n (error) =>\n error.name === name ||\n error.path.includes(name) ||\n this.keys.includes(error.name)\n )\n\n if (!list?.length) {\n return\n }\n\n return list\n }\n\n getFirstError(\n errors?: FormSubmissionError[]\n ): FormSubmissionError | undefined {\n return this.getErrors(errors)?.[0]\n }\n\n getViewErrors(\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const firstError = this.getFirstError(errors)\n return firstError && [firstError]\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const { hint, name, options = {}, title, viewModel } = this\n\n const isRequired = !('required' in options) || options.required !== false\n const hideOptional = 'optionalText' in options && options.optionalText\n const label = `${title}${!isRequired && !hideOptional ? optionalText : ''}`\n\n if (hint) {\n viewModel.hint = {\n text: hint\n }\n }\n\n // Filter component errors only\n const componentErrors = this.getErrors(errors)\n const componentError = this.getFirstError(componentErrors)\n\n if (componentErrors) {\n viewModel.errors = componentErrors\n }\n\n if (componentError) {\n viewModel.errorMessage = {\n text: componentError.text\n }\n }\n\n return {\n ...viewModel,\n label: {\n text: label\n },\n id: name,\n name,\n value: payload[name]\n }\n }\n\n getDisplayStringFromState(state: FormSubmissionState): string {\n const value = this.getFormValueFromState(state)\n return this.isValue(value) ? value.toString() : ''\n }\n\n getContextValueFromState(\n state: FormSubmissionState\n ): Item['value'] | Item['value'][] | null {\n const value = this.getFormValueFromState(state)\n\n // Filter object field values\n if (this.isState(value)) {\n const values = Object.values(value).filter(isFormValue)\n return values.length ? values : null\n }\n\n // Filter array field values\n if (this.isValue(value) && Array.isArray(value)) {\n return value.filter(isFormValue)\n }\n\n return this.isValue(value) ? value : null\n }\n\n isValue(\n value?: FormStateValue | FormState\n ): value is NonNullable<FormStateValue> {\n return isFormValue(value)\n }\n\n isState(value?: FormStateValue | FormState): value is FormState {\n return isFormState(value)\n }\n\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [],\n advancedSettingsErrors: []\n }\n }\n}\n\n/**\n * Check for form value\n */\nexport function isFormValue(\n value?: unknown\n): value is string | number | boolean {\n return (\n (typeof value === 'string' && value.length > 0) ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n )\n}\n\n/**\n * Check for form state with nested values\n */\nexport function isFormState(value?: unknown): value is FormState {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false\n }\n\n // Skip empty objects\n return !!Object.values(value).length\n}\n\n/**\n * Check for repeat list state\n */\nexport function isRepeatState(value?: unknown): value is RepeatListState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isRepeatValue)\n}\n\n/**\n * Check for repeat list value\n */\nexport function isRepeatValue(value?: unknown): value is RepeatItemState {\n return isFormState(value) && typeof value.itemId === 'string'\n}\n\n/**\n * Check for upload state\n */\nexport function isUploadState(value?: unknown): value is UploadState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isUploadValue)\n}\n\n/**\n * Check for upload state value\n */\nexport function isUploadValue(value?: unknown): value is FileState {\n return isFormState(value) && typeof value.uploadId === 'string'\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import joi from 'joi';
|
|
2
2
|
import { FormComponent } from "./FormComponent.js";
|
|
3
|
+
import { messageTemplate } from "../pageControllers/validationOptions.js";
|
|
3
4
|
export class ListFormComponent extends FormComponent {
|
|
4
5
|
list;
|
|
5
6
|
listType = 'string';
|
|
@@ -14,8 +15,7 @@ export class ListFormComponent extends FormComponent {
|
|
|
14
15
|
constructor(def, props) {
|
|
15
16
|
super(def, props);
|
|
16
17
|
const {
|
|
17
|
-
options
|
|
18
|
-
title
|
|
18
|
+
options
|
|
19
19
|
} = def;
|
|
20
20
|
const {
|
|
21
21
|
model
|
|
@@ -24,7 +24,7 @@ export class ListFormComponent extends FormComponent {
|
|
|
24
24
|
this.list = model.getList(def.list);
|
|
25
25
|
this.listType = this.list?.type ?? 'string';
|
|
26
26
|
}
|
|
27
|
-
let formSchema = joi[this.listType]().valid(...this.values).label(
|
|
27
|
+
let formSchema = joi[this.listType]().valid(...this.values).label(this.label).required();
|
|
28
28
|
if (options.customValidationMessages) {
|
|
29
29
|
formSchema = formSchema.messages(options.customValidationMessages);
|
|
30
30
|
}
|
|
@@ -83,5 +83,18 @@ export class ListFormComponent extends FormComponent {
|
|
|
83
83
|
items
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* For error preview page that shows all possible errors on a component
|
|
89
|
+
*/
|
|
90
|
+
getAllPossibleErrors() {
|
|
91
|
+
return {
|
|
92
|
+
baseErrors: [{
|
|
93
|
+
type: 'selectRequired',
|
|
94
|
+
template: messageTemplate.selectRequired
|
|
95
|
+
}],
|
|
96
|
+
advancedSettingsErrors: []
|
|
97
|
+
};
|
|
98
|
+
}
|
|
86
99
|
}
|
|
87
100
|
//# sourceMappingURL=ListFormComponent.js.map
|