@defra/forms-engine-plugin 4.0.7 → 4.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.server/server/forms/components.json +7 -0
- package/.server/server/forms/page-events.yaml +1 -1
- package/.server/server/forms/register-as-a-unicorn-breeder.yaml +12 -1
- package/.server/server/plugins/engine/components/ComponentBase.d.ts +1 -1
- package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
- package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
- package/.server/server/plugins/engine/components/DeclarationField.d.ts +81 -0
- package/.server/server/plugins/engine/components/DeclarationField.js +123 -0
- package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -0
- package/.server/server/plugins/engine/components/helpers/components.d.ts +1 -1
- package/.server/server/plugins/engine/components/helpers/components.js +3 -0
- package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
- package/.server/server/plugins/engine/components/index.d.ts +1 -0
- 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/models/SummaryViewModel.js +4 -0
- package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/validationOptions.js +1 -0
- package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
- package/.server/server/plugins/engine/views/components/declarationfield.html +14 -0
- package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
- package/.server/server/plugins/nunjucks/filters/index.d.ts +1 -0
- package/.server/server/plugins/nunjucks/filters/index.js +1 -0
- package/.server/server/plugins/nunjucks/filters/index.js.map +1 -1
- package/.server/server/plugins/nunjucks/filters/merge.d.ts +7 -0
- package/.server/server/plugins/nunjucks/filters/merge.js +16 -0
- package/.server/server/plugins/nunjucks/filters/merge.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/merge.test.js +19 -0
- package/.server/server/plugins/nunjucks/filters/merge.test.js.map +1 -0
- package/package.json +2 -2
- package/src/server/forms/components.json +7 -0
- package/src/server/forms/page-events.yaml +1 -1
- package/src/server/forms/register-as-a-unicorn-breeder.yaml +12 -1
- package/src/server/index.test.ts +1 -0
- package/src/server/plugins/engine/components/ComponentBase.ts +1 -0
- package/src/server/plugins/engine/components/ComponentCollection.ts +1 -0
- package/src/server/plugins/engine/components/DeclarationField.test.ts +426 -0
- package/src/server/plugins/engine/components/DeclarationField.ts +167 -0
- package/src/server/plugins/engine/components/helpers/components.ts +5 -0
- package/src/server/plugins/engine/components/index.ts +1 -0
- package/src/server/plugins/engine/models/SummaryViewModel.test.ts +76 -3
- package/src/server/plugins/engine/models/SummaryViewModel.ts +5 -1
- package/src/server/plugins/engine/pageControllers/validationOptions.ts +4 -0
- package/src/server/plugins/engine/views/components/declarationfield.html +14 -0
- package/src/server/plugins/nunjucks/filters/index.js +1 -0
- package/src/server/plugins/nunjucks/filters/merge.js +16 -0
- package/src/server/plugins/nunjucks/filters/merge.test.js +15 -0
|
@@ -120,6 +120,13 @@
|
|
|
120
120
|
"content": "### This is a H3 in markdown\n\n[An internal link](http://localhost:3009/fictional-page)\n\n[An external link](https://defra.gov.uk/fictional-page)",
|
|
121
121
|
"options": {},
|
|
122
122
|
"schema": {}
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"type": "DeclarationField",
|
|
126
|
+
"name": "declaration",
|
|
127
|
+
"title": "Declaration",
|
|
128
|
+
"content": "By submitting this form, I agree to:\n\n- Provide accurate and complete information\n- Comply with all applicable regulations\n- Accept responsibility for any false statements",
|
|
129
|
+
"hint": "Please read and confirm the following terms"
|
|
123
130
|
}
|
|
124
131
|
]
|
|
125
132
|
},
|
|
@@ -219,7 +219,7 @@ pages:
|
|
|
219
219
|
controller: FileUploadPageController
|
|
220
220
|
section: Regnsa
|
|
221
221
|
next:
|
|
222
|
-
- path: '/
|
|
222
|
+
- path: '/declaration'
|
|
223
223
|
components:
|
|
224
224
|
- name: dLzALM
|
|
225
225
|
title: Documents
|
|
@@ -230,6 +230,17 @@ pages:
|
|
|
230
230
|
schema:
|
|
231
231
|
min: 1
|
|
232
232
|
max: 3
|
|
233
|
+
- title: Declaration
|
|
234
|
+
path: '/declaration'
|
|
235
|
+
section: section
|
|
236
|
+
components:
|
|
237
|
+
- name: diLmal
|
|
238
|
+
title: Declaration
|
|
239
|
+
type: DeclarationField
|
|
240
|
+
content: 'Fill in this field'
|
|
241
|
+
options: {}
|
|
242
|
+
next:
|
|
243
|
+
- path: '/summary'
|
|
233
244
|
conditions:
|
|
234
245
|
- displayName: Address is different
|
|
235
246
|
name: IrVmYz
|
|
@@ -30,4 +30,4 @@ export declare class ComponentBase {
|
|
|
30
30
|
});
|
|
31
31
|
get viewModel(): ViewModel;
|
|
32
32
|
}
|
|
33
|
-
export type ComponentSchema = ArraySchema<string> | ArraySchema<number> | ArraySchema<boolean> | ArraySchema<object> | BooleanSchema<string> | DateSchema | NumberSchema<string> | NumberSchema | ObjectSchema | StringSchema;
|
|
33
|
+
export type ComponentSchema = ArraySchema<string> | ArraySchema<number> | ArraySchema<boolean> | ArraySchema<object> | BooleanSchema<string> | BooleanSchema | DateSchema | NumberSchema<string> | NumberSchema | ObjectSchema | StringSchema;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentBase.js","names":["isConditionalRevealType","joi","ComponentBase","page","parent","collection","type","name","title","schema","options","isFormComponent","model","formSchema","string","stateSchema","constructor","def","props","viewModel","attributes","autocomplete","classes","condition"],"sources":["../../../../../src/server/plugins/engine/components/ComponentBase.ts"],"sourcesContent":["import { isConditionalRevealType, type ComponentDef } from '@defra/forms-model'\nimport joi, {\n type ArraySchema,\n type BooleanSchema,\n type DateSchema,\n type NumberSchema,\n type ObjectSchema,\n type StringSchema\n} from 'joi'\n\nimport { type ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport { type Component } from '~/src/server/plugins/engine/components/helpers/components.js'\nimport { type ViewModel } from '~/src/server/plugins/engine/components/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\n\nexport class ComponentBase {\n page?: PageControllerClass\n parent: Component | undefined\n collection: ComponentCollection | undefined\n\n type: ComponentDef['type']\n name: ComponentDef['name']\n title: ComponentDef['title']\n schema?: Extract<ComponentDef, { schema?: object }>['schema']\n options?: Extract<ComponentDef, { options: object }>['options']\n\n isFormComponent = false\n model: FormModel\n\n /** joi schemas based on a component defined in the form JSON. This validates a user's answer and is generated from {@link ComponentDef} */\n formSchema: ComponentSchema = joi.string()\n stateSchema: ComponentSchema = joi.string()\n\n constructor(\n def: ComponentDef,\n props: {\n page?: PageControllerClass\n parent?: Component\n model: FormModel\n }\n ) {\n this.type = def.type\n this.name = def.name\n this.title = def.title\n\n if ('schema' in def) {\n this.schema = def.schema\n }\n\n if ('options' in def) {\n this.options = def.options\n }\n\n this.page = props.page\n this.parent = props.parent\n this.model = props.model\n }\n\n get viewModel() {\n const { options, type } = this\n\n const viewModel: ViewModel = {\n attributes: {}\n }\n\n if (!options) {\n return viewModel\n }\n\n if ('autocomplete' in options) {\n viewModel.attributes.autocomplete = options.autocomplete\n }\n\n if ('classes' in options) {\n viewModel.classes = options.classes\n }\n\n if ('condition' in options && isConditionalRevealType(type)) {\n viewModel.condition = options.condition\n }\n\n return viewModel\n }\n}\n\nexport type ComponentSchema =\n | ArraySchema<string>\n | ArraySchema<number>\n | ArraySchema<boolean>\n | ArraySchema<object>\n | BooleanSchema<string>\n | DateSchema\n | NumberSchema<string>\n | NumberSchema\n | ObjectSchema\n | StringSchema\n"],"mappings":"AAAA,SAASA,uBAAuB,QAA2B,oBAAoB;AAC/E,OAAOC,GAAG,MAOH,KAAK;AAQZ,OAAO,MAAMC,aAAa,CAAC;EACzBC,IAAI;EACJC,MAAM;EACNC,UAAU;EAEVC,IAAI;EACJC,IAAI;EACJC,KAAK;EACLC,MAAM;EACNC,OAAO;EAEPC,eAAe,GAAG,KAAK;EACvBC,KAAK;;EAEL;EACAC,UAAU,GAAoBZ,GAAG,CAACa,MAAM,CAAC,CAAC;EAC1CC,WAAW,GAAoBd,GAAG,CAACa,MAAM,CAAC,CAAC;EAE3CE,WAAWA,CACTC,GAAiB,EACjBC,KAIC,EACD;IACA,IAAI,CAACZ,IAAI,GAAGW,GAAG,CAACX,IAAI;IACpB,IAAI,CAACC,IAAI,GAAGU,GAAG,CAACV,IAAI;IACpB,IAAI,CAACC,KAAK,GAAGS,GAAG,CAACT,KAAK;IAEtB,IAAI,QAAQ,IAAIS,GAAG,EAAE;MACnB,IAAI,CAACR,MAAM,GAAGQ,GAAG,CAACR,MAAM;IAC1B;IAEA,IAAI,SAAS,IAAIQ,GAAG,EAAE;MACpB,IAAI,CAACP,OAAO,GAAGO,GAAG,CAACP,OAAO;IAC5B;IAEA,IAAI,CAACP,IAAI,GAAGe,KAAK,CAACf,IAAI;IACtB,IAAI,CAACC,MAAM,GAAGc,KAAK,CAACd,MAAM;IAC1B,IAAI,CAACQ,KAAK,GAAGM,KAAK,CAACN,KAAK;EAC1B;EAEA,IAAIO,SAASA,CAAA,EAAG;IACd,MAAM;MAAET,OAAO;MAAEJ;IAAK,CAAC,GAAG,IAAI;IAE9B,MAAMa,SAAoB,GAAG;MAC3BC,UAAU,EAAE,CAAC;IACf,CAAC;IAED,IAAI,CAACV,OAAO,EAAE;MACZ,OAAOS,SAAS;IAClB;IAEA,IAAI,cAAc,IAAIT,OAAO,EAAE;MAC7BS,SAAS,CAACC,UAAU,CAACC,YAAY,GAAGX,OAAO,CAACW,YAAY;IAC1D;IAEA,IAAI,SAAS,IAAIX,OAAO,EAAE;MACxBS,SAAS,CAACG,OAAO,GAAGZ,OAAO,CAACY,OAAO;IACrC;IAEA,IAAI,WAAW,IAAIZ,OAAO,IAAIV,uBAAuB,CAACM,IAAI,CAAC,EAAE;MAC3Da,SAAS,CAACI,SAAS,GAAGb,OAAO,CAACa,SAAS;IACzC;IAEA,OAAOJ,SAAS;EAClB;AACF","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"ComponentBase.js","names":["isConditionalRevealType","joi","ComponentBase","page","parent","collection","type","name","title","schema","options","isFormComponent","model","formSchema","string","stateSchema","constructor","def","props","viewModel","attributes","autocomplete","classes","condition"],"sources":["../../../../../src/server/plugins/engine/components/ComponentBase.ts"],"sourcesContent":["import { isConditionalRevealType, type ComponentDef } from '@defra/forms-model'\nimport joi, {\n type ArraySchema,\n type BooleanSchema,\n type DateSchema,\n type NumberSchema,\n type ObjectSchema,\n type StringSchema\n} from 'joi'\n\nimport { type ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport { type Component } from '~/src/server/plugins/engine/components/helpers/components.js'\nimport { type ViewModel } from '~/src/server/plugins/engine/components/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\n\nexport class ComponentBase {\n page?: PageControllerClass\n parent: Component | undefined\n collection: ComponentCollection | undefined\n\n type: ComponentDef['type']\n name: ComponentDef['name']\n title: ComponentDef['title']\n schema?: Extract<ComponentDef, { schema?: object }>['schema']\n options?: Extract<ComponentDef, { options: object }>['options']\n\n isFormComponent = false\n model: FormModel\n\n /** joi schemas based on a component defined in the form JSON. This validates a user's answer and is generated from {@link ComponentDef} */\n formSchema: ComponentSchema = joi.string()\n stateSchema: ComponentSchema = joi.string()\n\n constructor(\n def: ComponentDef,\n props: {\n page?: PageControllerClass\n parent?: Component\n model: FormModel\n }\n ) {\n this.type = def.type\n this.name = def.name\n this.title = def.title\n\n if ('schema' in def) {\n this.schema = def.schema\n }\n\n if ('options' in def) {\n this.options = def.options\n }\n\n this.page = props.page\n this.parent = props.parent\n this.model = props.model\n }\n\n get viewModel() {\n const { options, type } = this\n\n const viewModel: ViewModel = {\n attributes: {}\n }\n\n if (!options) {\n return viewModel\n }\n\n if ('autocomplete' in options) {\n viewModel.attributes.autocomplete = options.autocomplete\n }\n\n if ('classes' in options) {\n viewModel.classes = options.classes\n }\n\n if ('condition' in options && isConditionalRevealType(type)) {\n viewModel.condition = options.condition\n }\n\n return viewModel\n }\n}\n\nexport type ComponentSchema =\n | ArraySchema<string>\n | ArraySchema<number>\n | ArraySchema<boolean>\n | ArraySchema<object>\n | BooleanSchema<string>\n | BooleanSchema\n | DateSchema\n | NumberSchema<string>\n | NumberSchema\n | ObjectSchema\n | StringSchema\n"],"mappings":"AAAA,SAASA,uBAAuB,QAA2B,oBAAoB;AAC/E,OAAOC,GAAG,MAOH,KAAK;AAQZ,OAAO,MAAMC,aAAa,CAAC;EACzBC,IAAI;EACJC,MAAM;EACNC,UAAU;EAEVC,IAAI;EACJC,IAAI;EACJC,KAAK;EACLC,MAAM;EACNC,OAAO;EAEPC,eAAe,GAAG,KAAK;EACvBC,KAAK;;EAEL;EACAC,UAAU,GAAoBZ,GAAG,CAACa,MAAM,CAAC,CAAC;EAC1CC,WAAW,GAAoBd,GAAG,CAACa,MAAM,CAAC,CAAC;EAE3CE,WAAWA,CACTC,GAAiB,EACjBC,KAIC,EACD;IACA,IAAI,CAACZ,IAAI,GAAGW,GAAG,CAACX,IAAI;IACpB,IAAI,CAACC,IAAI,GAAGU,GAAG,CAACV,IAAI;IACpB,IAAI,CAACC,KAAK,GAAGS,GAAG,CAACT,KAAK;IAEtB,IAAI,QAAQ,IAAIS,GAAG,EAAE;MACnB,IAAI,CAACR,MAAM,GAAGQ,GAAG,CAACR,MAAM;IAC1B;IAEA,IAAI,SAAS,IAAIQ,GAAG,EAAE;MACpB,IAAI,CAACP,OAAO,GAAGO,GAAG,CAACP,OAAO;IAC5B;IAEA,IAAI,CAACP,IAAI,GAAGe,KAAK,CAACf,IAAI;IACtB,IAAI,CAACC,MAAM,GAAGc,KAAK,CAACd,MAAM;IAC1B,IAAI,CAACQ,KAAK,GAAGM,KAAK,CAACN,KAAK;EAC1B;EAEA,IAAIO,SAASA,CAAA,EAAG;IACd,MAAM;MAAET,OAAO;MAAEJ;IAAK,CAAC,GAAG,IAAI;IAE9B,MAAMa,SAAoB,GAAG;MAC3BC,UAAU,EAAE,CAAC;IACf,CAAC;IAED,IAAI,CAACV,OAAO,EAAE;MACZ,OAAOS,SAAS;IAClB;IAEA,IAAI,cAAc,IAAIT,OAAO,EAAE;MAC7BS,SAAS,CAACC,UAAU,CAACC,YAAY,GAAGX,OAAO,CAACW,YAAY;IAC1D;IAEA,IAAI,SAAS,IAAIX,OAAO,EAAE;MACxBS,SAAS,CAACG,OAAO,GAAGZ,OAAO,CAACY,OAAO;IACrC;IAEA,IAAI,WAAW,IAAIZ,OAAO,IAAIV,uBAAuB,CAACM,IAAI,CAAC,EAAE;MAC3Da,SAAS,CAACI,SAAS,GAAGb,OAAO,CAACa,SAAS;IACzC;IAEA,OAAOJ,SAAS;EAClB;AACF","ignoreList":[]}
|
|
@@ -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","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/components.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/pages.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":[]}
|
|
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/components.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/pages.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\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":[]}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type DeclarationFieldComponent, type Item } from '@defra/forms-model';
|
|
2
|
+
import { type ArraySchema, type BooleanSchema, type StringSchema } from 'joi';
|
|
3
|
+
import { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js';
|
|
4
|
+
import { type ErrorMessageTemplateList, type FormPayload, type FormState, type FormStateValue, type FormSubmissionError, type FormSubmissionState, type FormValue } from '~/src/server/plugins/engine/types.js';
|
|
5
|
+
export declare class DeclarationField extends FormComponent {
|
|
6
|
+
private readonly DEFAULT_DECLARATION_LABEL;
|
|
7
|
+
options: DeclarationFieldComponent['options'];
|
|
8
|
+
declarationConfirmationLabel: string;
|
|
9
|
+
formSchema: ArraySchema<StringSchema[]>;
|
|
10
|
+
stateSchema: BooleanSchema;
|
|
11
|
+
content: string;
|
|
12
|
+
constructor(def: DeclarationFieldComponent, props: ConstructorParameters<typeof FormComponent>[1]);
|
|
13
|
+
getFormValueFromState(state: FormSubmissionState): "true" | undefined;
|
|
14
|
+
getFormDataFromState(state: FormSubmissionState): FormPayload;
|
|
15
|
+
getStateFromValidForm(payload: FormPayload): FormState;
|
|
16
|
+
getContextValueFromFormValue(value: FormValue | FormPayload): boolean;
|
|
17
|
+
getFormValue(value?: FormStateValue | FormState): (string | number | boolean)[] | undefined;
|
|
18
|
+
getDisplayStringFromFormValue(value: FormValue | FormPayload): string;
|
|
19
|
+
getViewModel(payload: FormPayload, errors?: FormSubmissionError[]): {
|
|
20
|
+
hint: {
|
|
21
|
+
text: string;
|
|
22
|
+
} | undefined;
|
|
23
|
+
fieldset: {
|
|
24
|
+
legend: {
|
|
25
|
+
text: string;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
content: string;
|
|
29
|
+
values: FormValue;
|
|
30
|
+
items: {
|
|
31
|
+
text: string;
|
|
32
|
+
value: string;
|
|
33
|
+
}[];
|
|
34
|
+
label: {
|
|
35
|
+
text: string;
|
|
36
|
+
};
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
value: FormValue;
|
|
40
|
+
type?: string;
|
|
41
|
+
prefix?: import("./types.js").ComponentText;
|
|
42
|
+
suffix?: import("./types.js").ComponentText;
|
|
43
|
+
classes?: string;
|
|
44
|
+
condition?: string;
|
|
45
|
+
errors?: FormSubmissionError[];
|
|
46
|
+
errorMessage?: {
|
|
47
|
+
text: string;
|
|
48
|
+
};
|
|
49
|
+
summaryHtml?: string;
|
|
50
|
+
html?: string;
|
|
51
|
+
attributes: {
|
|
52
|
+
autocomplete?: string;
|
|
53
|
+
maxlength?: number;
|
|
54
|
+
multiple?: string;
|
|
55
|
+
accept?: string;
|
|
56
|
+
inputmode?: string;
|
|
57
|
+
};
|
|
58
|
+
maxlength?: number;
|
|
59
|
+
maxwords?: number;
|
|
60
|
+
rows?: number;
|
|
61
|
+
formGroup?: {
|
|
62
|
+
classes?: string;
|
|
63
|
+
attributes?: string | Record<string, string>;
|
|
64
|
+
};
|
|
65
|
+
components?: import("./types.js").ComponentViewModel[];
|
|
66
|
+
upload?: {
|
|
67
|
+
count: number;
|
|
68
|
+
summaryList: import("~/src/server/plugins/engine/types.js").SummaryList;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
isValue(value?: FormStateValue | FormState): value is Item['value'][];
|
|
72
|
+
/**
|
|
73
|
+
* For error preview page that shows all possible errors on a component
|
|
74
|
+
*/
|
|
75
|
+
getAllPossibleErrors(): ErrorMessageTemplateList;
|
|
76
|
+
/**
|
|
77
|
+
* Static version of getAllPossibleErrors that doesn't require a component instance.
|
|
78
|
+
*/
|
|
79
|
+
static getAllPossibleErrors(): ErrorMessageTemplateList;
|
|
80
|
+
static isBool(value?: FormStateValue | FormState): value is boolean;
|
|
81
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import joi from 'joi';
|
|
2
|
+
import { FormComponent, isFormValue } from "./FormComponent.js";
|
|
3
|
+
import { messageTemplate } from "../pageControllers/validationOptions.js";
|
|
4
|
+
export class DeclarationField extends FormComponent {
|
|
5
|
+
DEFAULT_DECLARATION_LABEL = 'I understand and agree';
|
|
6
|
+
constructor(def, props) {
|
|
7
|
+
super(def, props);
|
|
8
|
+
const {
|
|
9
|
+
options,
|
|
10
|
+
content
|
|
11
|
+
} = def;
|
|
12
|
+
let checkboxSchema = joi.string().valid('true');
|
|
13
|
+
if (options.required !== false) {
|
|
14
|
+
checkboxSchema = checkboxSchema.required();
|
|
15
|
+
}
|
|
16
|
+
const formSchema = joi.array().items(checkboxSchema, joi.string().valid('unchecked').strip()).label(this.label).single().messages({
|
|
17
|
+
'any.required': messageTemplate.declarationRequired,
|
|
18
|
+
'any.unknown': messageTemplate.declarationRequired,
|
|
19
|
+
'array.includesRequiredUnknowns': messageTemplate.declarationRequired
|
|
20
|
+
});
|
|
21
|
+
this.formSchema = formSchema;
|
|
22
|
+
this.stateSchema = joi.boolean().cast('string').label(this.label).required();
|
|
23
|
+
this.options = options;
|
|
24
|
+
this.content = content;
|
|
25
|
+
this.declarationConfirmationLabel = options.declarationConfirmationLabel ?? this.DEFAULT_DECLARATION_LABEL;
|
|
26
|
+
}
|
|
27
|
+
getFormValueFromState(state) {
|
|
28
|
+
const {
|
|
29
|
+
name
|
|
30
|
+
} = this;
|
|
31
|
+
return state[name] === true ? 'true' : undefined;
|
|
32
|
+
}
|
|
33
|
+
getFormDataFromState(state) {
|
|
34
|
+
const {
|
|
35
|
+
name
|
|
36
|
+
} = this;
|
|
37
|
+
return {
|
|
38
|
+
[name]: state[name] === true ? 'true' : undefined
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
getStateFromValidForm(payload) {
|
|
42
|
+
const {
|
|
43
|
+
name
|
|
44
|
+
} = this;
|
|
45
|
+
const payloadValue = payload[name];
|
|
46
|
+
const value = this.isValue(payloadValue) && payloadValue.length > 0 && payloadValue.every(v => {
|
|
47
|
+
return v === 'true';
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
[name]: value
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
getContextValueFromFormValue(value) {
|
|
54
|
+
return value === 'true';
|
|
55
|
+
}
|
|
56
|
+
getFormValue(value) {
|
|
57
|
+
return this.isValue(value) ? value : undefined;
|
|
58
|
+
}
|
|
59
|
+
getDisplayStringFromFormValue(value) {
|
|
60
|
+
return value ? this.declarationConfirmationLabel : '';
|
|
61
|
+
}
|
|
62
|
+
getViewModel(payload, errors) {
|
|
63
|
+
const defaultDeclarationConfirmationLabel = 'I confirm that I understand and accept this declaration';
|
|
64
|
+
const {
|
|
65
|
+
title,
|
|
66
|
+
hint,
|
|
67
|
+
content,
|
|
68
|
+
declarationConfirmationLabel = defaultDeclarationConfirmationLabel
|
|
69
|
+
} = this;
|
|
70
|
+
return {
|
|
71
|
+
...super.getViewModel(payload, errors),
|
|
72
|
+
hint: hint ? {
|
|
73
|
+
text: hint
|
|
74
|
+
} : undefined,
|
|
75
|
+
fieldset: {
|
|
76
|
+
legend: {
|
|
77
|
+
text: title
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
content,
|
|
81
|
+
values: payload[this.name],
|
|
82
|
+
items: [{
|
|
83
|
+
text: declarationConfirmationLabel,
|
|
84
|
+
value: 'true'
|
|
85
|
+
}]
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
isValue(value) {
|
|
89
|
+
if (!Array.isArray(value)) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Skip checks when empty
|
|
94
|
+
if (!value.length) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
return value.every(isFormValue);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* For error preview page that shows all possible errors on a component
|
|
102
|
+
*/
|
|
103
|
+
getAllPossibleErrors() {
|
|
104
|
+
return DeclarationField.getAllPossibleErrors();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Static version of getAllPossibleErrors that doesn't require a component instance.
|
|
109
|
+
*/
|
|
110
|
+
static getAllPossibleErrors() {
|
|
111
|
+
return {
|
|
112
|
+
baseErrors: [{
|
|
113
|
+
type: 'required',
|
|
114
|
+
template: messageTemplate.declarationRequired
|
|
115
|
+
}],
|
|
116
|
+
advancedSettingsErrors: []
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
static isBool(value) {
|
|
120
|
+
return isFormValue(value) && typeof value === 'boolean';
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=DeclarationField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeclarationField.js","names":["joi","FormComponent","isFormValue","messageTemplate","DeclarationField","DEFAULT_DECLARATION_LABEL","constructor","def","props","options","content","checkboxSchema","string","valid","required","formSchema","array","items","strip","label","single","messages","declarationRequired","stateSchema","boolean","cast","declarationConfirmationLabel","getFormValueFromState","state","name","undefined","getFormDataFromState","getStateFromValidForm","payload","payloadValue","value","isValue","length","every","v","getContextValueFromFormValue","getFormValue","getDisplayStringFromFormValue","getViewModel","errors","defaultDeclarationConfirmationLabel","title","hint","text","fieldset","legend","values","Array","isArray","getAllPossibleErrors","baseErrors","type","template","advancedSettingsErrors","isBool"],"sources":["../../../../../src/server/plugins/engine/components/DeclarationField.ts"],"sourcesContent":["import { type DeclarationFieldComponent, type Item } from '@defra/forms-model'\nimport joi, {\n type ArraySchema,\n type BooleanSchema,\n type StringSchema\n} from 'joi'\n\nimport {\n FormComponent,\n isFormValue\n} 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 FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValue\n} from '~/src/server/plugins/engine/types.js'\n\nexport class DeclarationField extends FormComponent {\n private readonly DEFAULT_DECLARATION_LABEL = 'I understand and agree'\n\n declare options: DeclarationFieldComponent['options']\n\n declare declarationConfirmationLabel: string\n\n declare formSchema: ArraySchema<StringSchema[]>\n declare stateSchema: BooleanSchema\n declare content: string\n\n constructor(\n def: DeclarationFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options, content } = def\n\n let checkboxSchema = joi.string().valid('true')\n\n if (options.required !== false) {\n checkboxSchema = checkboxSchema.required()\n }\n\n const formSchema = joi\n .array()\n .items(checkboxSchema, joi.string().valid('unchecked').strip())\n .label(this.label)\n .single()\n .messages({\n 'any.required': messageTemplate.declarationRequired as string,\n 'any.unknown': messageTemplate.declarationRequired as string,\n 'array.includesRequiredUnknowns':\n messageTemplate.declarationRequired as string\n }) as ArraySchema<StringSchema[]>\n\n this.formSchema = formSchema\n this.stateSchema = joi.boolean().cast('string').label(this.label).required()\n\n this.options = options\n this.content = content\n this.declarationConfirmationLabel =\n options.declarationConfirmationLabel ?? this.DEFAULT_DECLARATION_LABEL\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const { name } = this\n return state[name] === true ? 'true' : undefined\n }\n\n getFormDataFromState(state: FormSubmissionState): FormPayload {\n const { name } = this\n return { [name]: state[name] === true ? 'true' : undefined }\n }\n\n getStateFromValidForm(payload: FormPayload): FormState {\n const { name } = this\n const payloadValue = payload[name]\n const value =\n this.isValue(payloadValue) &&\n payloadValue.length > 0 &&\n payloadValue.every((v) => {\n return v === 'true'\n })\n\n return { [name]: value }\n }\n\n getContextValueFromFormValue(value: FormValue | FormPayload): boolean {\n return value === 'true'\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getDisplayStringFromFormValue(value: FormValue | FormPayload): string {\n return value ? this.declarationConfirmationLabel : ''\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const defaultDeclarationConfirmationLabel =\n 'I confirm that I understand and accept this declaration'\n const {\n title,\n hint,\n content,\n declarationConfirmationLabel = defaultDeclarationConfirmationLabel\n } = this\n return {\n ...super.getViewModel(payload, errors),\n hint: hint ? { text: hint } : undefined,\n fieldset: {\n legend: {\n text: title\n }\n },\n content,\n values: payload[this.name],\n items: [\n {\n text: declarationConfirmationLabel,\n value: 'true'\n }\n ]\n }\n }\n\n isValue(value?: FormStateValue | FormState): value is Item['value'][] {\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(isFormValue)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return DeclarationField.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: messageTemplate.declarationRequired }\n ],\n advancedSettingsErrors: []\n }\n }\n\n static isBool(value?: FormStateValue | FormState): value is boolean {\n return isFormValue(value) && typeof value === 'boolean'\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -4,7 +4,7 @@ import { ListFormComponent } from '~/src/server/plugins/engine/components/ListFo
|
|
|
4
4
|
import * as Components from '~/src/server/plugins/engine/components/index.js';
|
|
5
5
|
import { type FormState } from '~/src/server/plugins/engine/types.js';
|
|
6
6
|
export type Component = InstanceType<(typeof Components)[keyof typeof Components]>;
|
|
7
|
-
export type Field = InstanceType<typeof Components.AutocompleteField | typeof Components.RadiosField | typeof Components.YesNoField | typeof Components.CheckboxesField | typeof Components.DatePartsField | typeof Components.EastingNorthingField | typeof Components.EmailAddressField | typeof Components.LatLongField | typeof Components.MonthYearField | typeof Components.MultilineTextField | typeof Components.NationalGridFieldNumberField | typeof Components.NumberField | typeof Components.OsGridRefField | typeof Components.SelectField | typeof Components.TelephoneNumberField | typeof Components.TextField | typeof Components.UkAddressField | typeof Components.FileUploadField>;
|
|
7
|
+
export type Field = InstanceType<typeof Components.AutocompleteField | typeof Components.RadiosField | typeof Components.YesNoField | typeof Components.CheckboxesField | typeof Components.DatePartsField | typeof Components.DeclarationField | typeof Components.EastingNorthingField | typeof Components.EmailAddressField | typeof Components.LatLongField | typeof Components.MonthYearField | typeof Components.MultilineTextField | typeof Components.NationalGridFieldNumberField | typeof Components.NumberField | typeof Components.OsGridRefField | typeof Components.SelectField | typeof Components.TelephoneNumberField | typeof Components.TextField | typeof Components.UkAddressField | typeof Components.FileUploadField>;
|
|
8
8
|
export type Guidance = InstanceType<typeof Components.Details> | InstanceType<typeof Components.Html> | InstanceType<typeof Components.Markdown> | InstanceType<typeof Components.InsetText> | InstanceType<typeof Components.List>;
|
|
9
9
|
export type ListField = InstanceType<typeof Components.AutocompleteField | typeof Components.CheckboxesField | typeof Components.RadiosField | typeof Components.SelectField | typeof Components.YesNoField>;
|
|
10
10
|
export declare const designerUrl: string;
|
|
@@ -44,6 +44,9 @@ export function createComponent(def, options) {
|
|
|
44
44
|
case ComponentType.DatePartsField:
|
|
45
45
|
component = new Components.DatePartsField(def, options);
|
|
46
46
|
break;
|
|
47
|
+
case ComponentType.DeclarationField:
|
|
48
|
+
component = new Components.DeclarationField(def, options);
|
|
49
|
+
break;
|
|
47
50
|
case ComponentType.Details:
|
|
48
51
|
component = new Components.Details(def, options);
|
|
49
52
|
break;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.js","names":["ComponentType","config","ListFormComponent","escapeMarkdown","Components","markdown","designerUrl","get","hasListFormField","field","type","undefined","isListFieldType","allowedTypes","AutocompleteField","CheckboxesField","RadiosField","SelectField","YesNoField","includes","createComponent","def","options","component","DatePartsField","Details","EmailAddressField","Html","InsetText","List","Markdown","MultilineTextField","NumberField","TelephoneNumberField","TextField","UkAddressField","MonthYearField","FileUploadField","EastingNorthingField","OsGridRefField","NationalGridFieldNumberField","LatLongField","Error","getAnswer","state","format","getAnswerMarkdown","context","getContextValueFromState","toString","parse","async","trim","getDisplayStringFromState","answer","answerEscaped","files","getFormValueFromState","length","map","status","file","form","filename","fileId","join","values","flat","items","filter","value","item","label","text","line","toLowerCase","split","concat","contextValue"],"sources":["../../../../../../src/server/plugins/engine/components/helpers/components.ts"],"sourcesContent":["import { ComponentType, type ComponentDef } from '@defra/forms-model'\n\nimport { config } from '~/src/config/index.js'\nimport { type ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'\nimport { ListFormComponent } from '~/src/server/plugins/engine/components/ListFormComponent.js'\nimport { escapeMarkdown } from '~/src/server/plugins/engine/components/helpers/index.js'\nimport * as Components from '~/src/server/plugins/engine/components/index.js'\nimport { markdown } from '~/src/server/plugins/engine/components/markdownParser.js'\nimport { type FormState } from '~/src/server/plugins/engine/types.js'\n\n// All component instances\nexport type Component = InstanceType<\n (typeof Components)[keyof typeof Components]\n>\n\n// Field component instances only\nexport type Field = InstanceType<\n | typeof Components.AutocompleteField\n | typeof Components.RadiosField\n | typeof Components.YesNoField\n | typeof Components.CheckboxesField\n | typeof Components.DatePartsField\n | typeof Components.EastingNorthingField\n | typeof Components.EmailAddressField\n | typeof Components.LatLongField\n | typeof Components.MonthYearField\n | typeof Components.MultilineTextField\n | typeof Components.NationalGridFieldNumberField\n | typeof Components.NumberField\n | typeof Components.OsGridRefField\n | typeof Components.SelectField\n | typeof Components.TelephoneNumberField\n | typeof Components.TextField\n | typeof Components.UkAddressField\n | typeof Components.FileUploadField\n>\n\n// Guidance component instances only\nexport type Guidance =\n | InstanceType<typeof Components.Details>\n | InstanceType<typeof Components.Html>\n | InstanceType<typeof Components.Markdown>\n | InstanceType<typeof Components.InsetText>\n | InstanceType<typeof Components.List>\n\n// List component instances only\nexport type ListField = InstanceType<\n | typeof Components.AutocompleteField\n | typeof Components.CheckboxesField\n | typeof Components.RadiosField\n | typeof Components.SelectField\n | typeof Components.YesNoField\n>\n\nexport const designerUrl = config.get('designerUrl')\n\n// Re-export markdown from its own module to avoid circular dependencies\nexport { markdown } from '~/src/server/plugins/engine/components/markdownParser.js'\n\n/**\n * Filter known components with lists\n */\nexport function hasListFormField(\n field?: Partial<Component>\n): field is ListFormComponent {\n return !!field && field.type !== undefined && isListFieldType(field.type)\n}\n\nexport function isListFieldType(\n type?: ComponentType\n): type is ListField['type'] {\n const allowedTypes = [\n ComponentType.AutocompleteField,\n ComponentType.CheckboxesField,\n ComponentType.RadiosField,\n ComponentType.SelectField,\n ComponentType.YesNoField\n ]\n\n return !!type && allowedTypes.includes(type)\n}\n\n/**\n * Create field instance for each {@link ComponentDef} type\n */\nexport function createComponent(\n def: ComponentDef,\n options: ConstructorParameters<typeof ComponentBase>[1]\n): Component {\n let component: Component | undefined\n\n switch (def.type) {\n case ComponentType.AutocompleteField:\n component = new Components.AutocompleteField(def, options)\n break\n\n case ComponentType.CheckboxesField:\n component = new Components.CheckboxesField(def, options)\n break\n\n case ComponentType.DatePartsField:\n component = new Components.DatePartsField(def, options)\n break\n\n case ComponentType.Details:\n component = new Components.Details(def, options)\n break\n\n case ComponentType.EmailAddressField:\n component = new Components.EmailAddressField(def, options)\n break\n\n case ComponentType.Html:\n component = new Components.Html(def, options)\n break\n\n case ComponentType.InsetText:\n component = new Components.InsetText(def, options)\n break\n\n case ComponentType.List:\n component = new Components.List(def, options)\n break\n\n case ComponentType.Markdown:\n component = new Components.Markdown(def, options)\n break\n\n case ComponentType.MultilineTextField:\n component = new Components.MultilineTextField(def, options)\n break\n\n case ComponentType.NumberField:\n component = new Components.NumberField(def, options)\n break\n\n case ComponentType.RadiosField:\n component = new Components.RadiosField(def, options)\n break\n\n case ComponentType.SelectField:\n component = new Components.SelectField(def, options)\n break\n\n case ComponentType.TelephoneNumberField:\n component = new Components.TelephoneNumberField(def, options)\n break\n\n case ComponentType.TextField:\n component = new Components.TextField(def, options)\n break\n\n case ComponentType.UkAddressField:\n component = new Components.UkAddressField(def, options)\n break\n\n case ComponentType.YesNoField:\n component = new Components.YesNoField(def, options)\n break\n\n case ComponentType.MonthYearField:\n component = new Components.MonthYearField(def, options)\n break\n\n case ComponentType.FileUploadField:\n component = new Components.FileUploadField(def, options)\n break\n\n case ComponentType.EastingNorthingField:\n component = new Components.EastingNorthingField(def, options)\n break\n\n case ComponentType.OsGridRefField:\n component = new Components.OsGridRefField(def, options)\n break\n\n case ComponentType.NationalGridFieldNumberField:\n component = new Components.NationalGridFieldNumberField(def, options)\n break\n\n case ComponentType.LatLongField:\n component = new Components.LatLongField(def, options)\n break\n }\n\n if (typeof component === 'undefined') {\n throw new Error(`Component type ${def.type} does not exist`)\n }\n\n return component\n}\n\n/**\n * Get formatted answer for a field\n */\nexport function getAnswer(\n field: Field,\n state: FormState,\n options: {\n format:\n | 'data' // Submission data\n | 'email' // GOV.UK Notify emails\n | 'summary' // Check answers summary\n } = { format: 'summary' }\n) {\n // Use escaped display text for GOV.UK Notify emails\n if (options.format === 'email') {\n return getAnswerMarkdown(field, state, { format: 'email' })\n }\n\n // Use context value for submission data\n if (options.format === 'data') {\n const context = field.getContextValueFromState(state)\n return context?.toString() ?? ''\n }\n\n // Use display HTML for check answers summary (multi line)\n if (\n field instanceof ListFormComponent ||\n field instanceof Components.MultilineTextField ||\n field instanceof Components.UkAddressField ||\n field instanceof Components.EastingNorthingField ||\n field instanceof Components.LatLongField\n ) {\n return markdown\n .parse(getAnswerMarkdown(field, state), { async: false })\n .trim()\n }\n\n // Use display text for check answers summary (single line)\n return field.getDisplayStringFromState(state)\n}\n\n/**\n * Get formatted answer for a field (Markdown only)\n */\nexport function getAnswerMarkdown(\n field: Field,\n state: FormState,\n options: {\n format:\n | 'email' // GOV.UK Notify emails\n | 'summary' // Check answers summary\n } = { format: 'summary' }\n) {\n const answer = field.getDisplayStringFromState(state)\n\n // Use escaped display text\n let answerEscaped = `${escapeMarkdown(answer)}\\n`\n\n if (field instanceof Components.FileUploadField) {\n const files = field.getFormValueFromState(state)\n\n // Skip empty files\n if (!files?.length) {\n return answerEscaped\n }\n\n answerEscaped = `${escapeMarkdown(answer)}:\\n\\n`\n\n // Append bullet points\n answerEscaped += files\n .map(({ status }) => {\n const { file } = status.form\n const filename = escapeMarkdown(file.filename)\n return `* [${filename}](${designerUrl}/file-download/${file.fileId})\\n`\n })\n .join('')\n } else if (field instanceof ListFormComponent) {\n const values = [field.getContextValueFromState(state)].flat()\n const items = field.items.filter(({ value }) => values.includes(value))\n\n // Skip empty values\n if (!items.length) {\n return answerEscaped\n }\n\n answerEscaped = ''\n\n // Append bullet points\n answerEscaped += items\n .map((item) => {\n const label = escapeMarkdown(item.text)\n const value = escapeMarkdown(`(${item.value})`)\n\n let line = label\n\n // Prepend bullet points for checkboxes only\n if (field instanceof Components.CheckboxesField) {\n line = `* ${line}`\n }\n\n // Append raw values in parentheses\n // e.g. `* None of the above (false)`\n return options.format === 'email' &&\n `${item.value}`.toLowerCase() !== item.text.toLowerCase()\n ? `${line} ${value}\\n`\n : `${line}\\n`\n })\n .join('')\n } else if (field instanceof Components.MultilineTextField) {\n // Preserve Multiline text new lines\n answerEscaped = answer\n .split(/(?:\\r?\\n)+/)\n .map(escapeMarkdown)\n .join('\\n')\n .concat('\\n')\n } else if (field instanceof Components.UkAddressField) {\n // Format UK addresses into new lines\n answerEscaped = (field.getContextValueFromState(state) ?? [])\n .map(escapeMarkdown)\n .join('\\n')\n .concat('\\n')\n } else if (\n field instanceof Components.EastingNorthingField ||\n field instanceof Components.LatLongField\n ) {\n const contextValue = field.getContextValueFromState(state)\n answerEscaped = contextValue ? `${contextValue}\\n` : ''\n }\n\n return answerEscaped\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"components.js","names":["ComponentType","config","ListFormComponent","escapeMarkdown","Components","markdown","designerUrl","get","hasListFormField","field","type","undefined","isListFieldType","allowedTypes","AutocompleteField","CheckboxesField","RadiosField","SelectField","YesNoField","includes","createComponent","def","options","component","DatePartsField","DeclarationField","Details","EmailAddressField","Html","InsetText","List","Markdown","MultilineTextField","NumberField","TelephoneNumberField","TextField","UkAddressField","MonthYearField","FileUploadField","EastingNorthingField","OsGridRefField","NationalGridFieldNumberField","LatLongField","Error","getAnswer","state","format","getAnswerMarkdown","context","getContextValueFromState","toString","parse","async","trim","getDisplayStringFromState","answer","answerEscaped","files","getFormValueFromState","length","map","status","file","form","filename","fileId","join","values","flat","items","filter","value","item","label","text","line","toLowerCase","split","concat","contextValue"],"sources":["../../../../../../src/server/plugins/engine/components/helpers/components.ts"],"sourcesContent":["import { ComponentType, type ComponentDef } from '@defra/forms-model'\n\nimport { config } from '~/src/config/index.js'\nimport { type ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'\nimport { ListFormComponent } from '~/src/server/plugins/engine/components/ListFormComponent.js'\nimport { escapeMarkdown } from '~/src/server/plugins/engine/components/helpers/index.js'\nimport * as Components from '~/src/server/plugins/engine/components/index.js'\nimport { markdown } from '~/src/server/plugins/engine/components/markdownParser.js'\nimport { type FormState } from '~/src/server/plugins/engine/types.js'\n\n// All component instances\nexport type Component = InstanceType<\n (typeof Components)[keyof typeof Components]\n>\n\n// Field component instances only\nexport type Field = InstanceType<\n | typeof Components.AutocompleteField\n | typeof Components.RadiosField\n | typeof Components.YesNoField\n | typeof Components.CheckboxesField\n | typeof Components.DatePartsField\n | typeof Components.DeclarationField\n | typeof Components.EastingNorthingField\n | typeof Components.EmailAddressField\n | typeof Components.LatLongField\n | typeof Components.MonthYearField\n | typeof Components.MultilineTextField\n | typeof Components.NationalGridFieldNumberField\n | typeof Components.NumberField\n | typeof Components.OsGridRefField\n | typeof Components.SelectField\n | typeof Components.TelephoneNumberField\n | typeof Components.TextField\n | typeof Components.UkAddressField\n | typeof Components.FileUploadField\n>\n\n// Guidance component instances only\nexport type Guidance =\n | InstanceType<typeof Components.Details>\n | InstanceType<typeof Components.Html>\n | InstanceType<typeof Components.Markdown>\n | InstanceType<typeof Components.InsetText>\n | InstanceType<typeof Components.List>\n\n// List component instances only\nexport type ListField = InstanceType<\n | typeof Components.AutocompleteField\n | typeof Components.CheckboxesField\n | typeof Components.RadiosField\n | typeof Components.SelectField\n | typeof Components.YesNoField\n>\n\nexport const designerUrl = config.get('designerUrl')\n\n// Re-export markdown from its own module to avoid circular dependencies\nexport { markdown } from '~/src/server/plugins/engine/components/markdownParser.js'\n\n/**\n * Filter known components with lists\n */\nexport function hasListFormField(\n field?: Partial<Component>\n): field is ListFormComponent {\n return !!field && field.type !== undefined && isListFieldType(field.type)\n}\n\nexport function isListFieldType(\n type?: ComponentType\n): type is ListField['type'] {\n const allowedTypes = [\n ComponentType.AutocompleteField,\n ComponentType.CheckboxesField,\n ComponentType.RadiosField,\n ComponentType.SelectField,\n ComponentType.YesNoField\n ]\n\n return !!type && allowedTypes.includes(type)\n}\n\n/**\n * Create field instance for each {@link ComponentDef} type\n */\nexport function createComponent(\n def: ComponentDef,\n options: ConstructorParameters<typeof ComponentBase>[1]\n): Component {\n let component: Component | undefined\n\n switch (def.type) {\n case ComponentType.AutocompleteField:\n component = new Components.AutocompleteField(def, options)\n break\n\n case ComponentType.CheckboxesField:\n component = new Components.CheckboxesField(def, options)\n break\n\n case ComponentType.DatePartsField:\n component = new Components.DatePartsField(def, options)\n break\n\n case ComponentType.DeclarationField:\n component = new Components.DeclarationField(def, options)\n break\n\n case ComponentType.Details:\n component = new Components.Details(def, options)\n break\n\n case ComponentType.EmailAddressField:\n component = new Components.EmailAddressField(def, options)\n break\n\n case ComponentType.Html:\n component = new Components.Html(def, options)\n break\n\n case ComponentType.InsetText:\n component = new Components.InsetText(def, options)\n break\n\n case ComponentType.List:\n component = new Components.List(def, options)\n break\n\n case ComponentType.Markdown:\n component = new Components.Markdown(def, options)\n break\n\n case ComponentType.MultilineTextField:\n component = new Components.MultilineTextField(def, options)\n break\n\n case ComponentType.NumberField:\n component = new Components.NumberField(def, options)\n break\n\n case ComponentType.RadiosField:\n component = new Components.RadiosField(def, options)\n break\n\n case ComponentType.SelectField:\n component = new Components.SelectField(def, options)\n break\n\n case ComponentType.TelephoneNumberField:\n component = new Components.TelephoneNumberField(def, options)\n break\n\n case ComponentType.TextField:\n component = new Components.TextField(def, options)\n break\n\n case ComponentType.UkAddressField:\n component = new Components.UkAddressField(def, options)\n break\n\n case ComponentType.YesNoField:\n component = new Components.YesNoField(def, options)\n break\n\n case ComponentType.MonthYearField:\n component = new Components.MonthYearField(def, options)\n break\n\n case ComponentType.FileUploadField:\n component = new Components.FileUploadField(def, options)\n break\n\n case ComponentType.EastingNorthingField:\n component = new Components.EastingNorthingField(def, options)\n break\n\n case ComponentType.OsGridRefField:\n component = new Components.OsGridRefField(def, options)\n break\n\n case ComponentType.NationalGridFieldNumberField:\n component = new Components.NationalGridFieldNumberField(def, options)\n break\n\n case ComponentType.LatLongField:\n component = new Components.LatLongField(def, options)\n break\n }\n\n if (typeof component === 'undefined') {\n throw new Error(`Component type ${def.type} does not exist`)\n }\n\n return component\n}\n\n/**\n * Get formatted answer for a field\n */\nexport function getAnswer(\n field: Field,\n state: FormState,\n options: {\n format:\n | 'data' // Submission data\n | 'email' // GOV.UK Notify emails\n | 'summary' // Check answers summary\n } = { format: 'summary' }\n) {\n // Use escaped display text for GOV.UK Notify emails\n if (options.format === 'email') {\n return getAnswerMarkdown(field, state, { format: 'email' })\n }\n\n // Use context value for submission data\n if (options.format === 'data') {\n const context = field.getContextValueFromState(state)\n return context?.toString() ?? ''\n }\n\n // Use display HTML for check answers summary (multi line)\n if (\n field instanceof ListFormComponent ||\n field instanceof Components.MultilineTextField ||\n field instanceof Components.UkAddressField ||\n field instanceof Components.EastingNorthingField ||\n field instanceof Components.LatLongField\n ) {\n return markdown\n .parse(getAnswerMarkdown(field, state), { async: false })\n .trim()\n }\n\n // Use display text for check answers summary (single line)\n return field.getDisplayStringFromState(state)\n}\n\n/**\n * Get formatted answer for a field (Markdown only)\n */\nexport function getAnswerMarkdown(\n field: Field,\n state: FormState,\n options: {\n format:\n | 'email' // GOV.UK Notify emails\n | 'summary' // Check answers summary\n } = { format: 'summary' }\n) {\n const answer = field.getDisplayStringFromState(state)\n\n // Use escaped display text\n let answerEscaped = `${escapeMarkdown(answer)}\\n`\n\n if (field instanceof Components.FileUploadField) {\n const files = field.getFormValueFromState(state)\n\n // Skip empty files\n if (!files?.length) {\n return answerEscaped\n }\n\n answerEscaped = `${escapeMarkdown(answer)}:\\n\\n`\n\n // Append bullet points\n answerEscaped += files\n .map(({ status }) => {\n const { file } = status.form\n const filename = escapeMarkdown(file.filename)\n return `* [${filename}](${designerUrl}/file-download/${file.fileId})\\n`\n })\n .join('')\n } else if (field instanceof ListFormComponent) {\n const values = [field.getContextValueFromState(state)].flat()\n const items = field.items.filter(({ value }) => values.includes(value))\n\n // Skip empty values\n if (!items.length) {\n return answerEscaped\n }\n\n answerEscaped = ''\n\n // Append bullet points\n answerEscaped += items\n .map((item) => {\n const label = escapeMarkdown(item.text)\n const value = escapeMarkdown(`(${item.value})`)\n\n let line = label\n\n // Prepend bullet points for checkboxes only\n if (field instanceof Components.CheckboxesField) {\n line = `* ${line}`\n }\n\n // Append raw values in parentheses\n // e.g. `* None of the above (false)`\n return options.format === 'email' &&\n `${item.value}`.toLowerCase() !== item.text.toLowerCase()\n ? `${line} ${value}\\n`\n : `${line}\\n`\n })\n .join('')\n } else if (field instanceof Components.MultilineTextField) {\n // Preserve Multiline text new lines\n answerEscaped = answer\n .split(/(?:\\r?\\n)+/)\n .map(escapeMarkdown)\n .join('\\n')\n .concat('\\n')\n } else if (field instanceof Components.UkAddressField) {\n // Format UK addresses into new lines\n answerEscaped = (field.getContextValueFromState(state) ?? [])\n .map(escapeMarkdown)\n .join('\\n')\n .concat('\\n')\n } else if (\n field instanceof Components.EastingNorthingField ||\n field instanceof Components.LatLongField\n ) {\n const contextValue = field.getContextValueFromState(state)\n answerEscaped = contextValue ? `${contextValue}\\n` : ''\n }\n\n return answerEscaped\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
export { AutocompleteField } from '~/src/server/plugins/engine/components/AutocompleteField.js';
|
|
7
7
|
export { CheckboxesField } from '~/src/server/plugins/engine/components/CheckboxesField.js';
|
|
8
8
|
export { DatePartsField } from '~/src/server/plugins/engine/components/DatePartsField.js';
|
|
9
|
+
export { DeclarationField } from '~/src/server/plugins/engine/components/DeclarationField.js';
|
|
9
10
|
export { Details } from '~/src/server/plugins/engine/components/Details.js';
|
|
10
11
|
export { EmailAddressField } from '~/src/server/plugins/engine/components/EmailAddressField.js';
|
|
11
12
|
export { FileUploadField } from '~/src/server/plugins/engine/components/FileUploadField.js';
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
export { AutocompleteField } from "./AutocompleteField.js";
|
|
8
8
|
export { CheckboxesField } from "./CheckboxesField.js";
|
|
9
9
|
export { DatePartsField } from "./DatePartsField.js";
|
|
10
|
+
export { DeclarationField } from "./DeclarationField.js";
|
|
10
11
|
export { Details } from "./Details.js";
|
|
11
12
|
export { EmailAddressField } from "./EmailAddressField.js";
|
|
12
13
|
export { FileUploadField } from "./FileUploadField.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["AutocompleteField","CheckboxesField","DatePartsField","Details","EmailAddressField","FileUploadField","Html","InsetText","List","Markdown","MonthYearField","MultilineTextField","NumberField","RadiosField","SelectField","TelephoneNumberField","TextField","UkAddressField","YesNoField","EastingNorthingField","OsGridRefField","NationalGridFieldNumberField","LatLongField"],"sources":["../../../../../src/server/plugins/engine/components/index.ts"],"sourcesContent":["/**\n * IMPORTANT: Exported Components must follow the naming convention implemented in {@link @defra/forms-model#ComponentType}\n * In the Form JSON, components have a type property which is the name of the components, e.g. DatePartsField.\n * Components are loaded in the ComponentsCollection constructor.\n */\n\nexport { AutocompleteField } from '~/src/server/plugins/engine/components/AutocompleteField.js'\nexport { CheckboxesField } from '~/src/server/plugins/engine/components/CheckboxesField.js'\nexport { DatePartsField } from '~/src/server/plugins/engine/components/DatePartsField.js'\nexport { Details } from '~/src/server/plugins/engine/components/Details.js'\nexport { EmailAddressField } from '~/src/server/plugins/engine/components/EmailAddressField.js'\nexport { FileUploadField } from '~/src/server/plugins/engine/components/FileUploadField.js'\nexport { Html } from '~/src/server/plugins/engine/components/Html.js'\nexport { InsetText } from '~/src/server/plugins/engine/components/InsetText.js'\nexport { List } from '~/src/server/plugins/engine/components/List.js'\nexport { Markdown } from '~/src/server/plugins/engine/components/Markdown.js'\nexport { MonthYearField } from '~/src/server/plugins/engine/components/MonthYearField.js'\nexport { MultilineTextField } from '~/src/server/plugins/engine/components/MultilineTextField.js'\nexport { NumberField } from '~/src/server/plugins/engine/components/NumberField.js'\nexport { RadiosField } from '~/src/server/plugins/engine/components/RadiosField.js'\nexport { SelectField } from '~/src/server/plugins/engine/components/SelectField.js'\nexport { TelephoneNumberField } from '~/src/server/plugins/engine/components/TelephoneNumberField.js'\nexport { TextField } from '~/src/server/plugins/engine/components/TextField.js'\nexport { UkAddressField } from '~/src/server/plugins/engine/components/UkAddressField.js'\nexport { YesNoField } from '~/src/server/plugins/engine/components/YesNoField.js'\nexport { EastingNorthingField } from '~/src/server/plugins/engine/components/EastingNorthingField.js'\nexport { OsGridRefField } from '~/src/server/plugins/engine/components/OsGridRefField.js'\nexport { NationalGridFieldNumberField } from '~/src/server/plugins/engine/components/NationalGridFieldNumberField.js'\nexport { LatLongField } from '~/src/server/plugins/engine/components/LatLongField.js'\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAEA,SAASA,iBAAiB;AAC1B,SAASC,eAAe;AACxB,SAASC,cAAc;AACvB,SAASC,OAAO;AAChB,SAASC,iBAAiB;AAC1B,SAASC,eAAe;AACxB,SAASC,IAAI;AACb,SAASC,SAAS;AAClB,SAASC,IAAI;AACb,SAASC,QAAQ;AACjB,SAASC,cAAc;AACvB,SAASC,kBAAkB;AAC3B,SAASC,WAAW;AACpB,SAASC,WAAW;AACpB,SAASC,WAAW;AACpB,SAASC,oBAAoB;AAC7B,SAASC,SAAS;AAClB,SAASC,cAAc;AACvB,SAASC,UAAU;AACnB,SAASC,oBAAoB;AAC7B,SAASC,cAAc;AACvB,SAASC,4BAA4B;AACrC,SAASC,YAAY","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"index.js","names":["AutocompleteField","CheckboxesField","DatePartsField","DeclarationField","Details","EmailAddressField","FileUploadField","Html","InsetText","List","Markdown","MonthYearField","MultilineTextField","NumberField","RadiosField","SelectField","TelephoneNumberField","TextField","UkAddressField","YesNoField","EastingNorthingField","OsGridRefField","NationalGridFieldNumberField","LatLongField"],"sources":["../../../../../src/server/plugins/engine/components/index.ts"],"sourcesContent":["/**\n * IMPORTANT: Exported Components must follow the naming convention implemented in {@link @defra/forms-model#ComponentType}\n * In the Form JSON, components have a type property which is the name of the components, e.g. DatePartsField.\n * Components are loaded in the ComponentsCollection constructor.\n */\n\nexport { AutocompleteField } from '~/src/server/plugins/engine/components/AutocompleteField.js'\nexport { CheckboxesField } from '~/src/server/plugins/engine/components/CheckboxesField.js'\nexport { DatePartsField } from '~/src/server/plugins/engine/components/DatePartsField.js'\nexport { DeclarationField } from '~/src/server/plugins/engine/components/DeclarationField.js'\nexport { Details } from '~/src/server/plugins/engine/components/Details.js'\nexport { EmailAddressField } from '~/src/server/plugins/engine/components/EmailAddressField.js'\nexport { FileUploadField } from '~/src/server/plugins/engine/components/FileUploadField.js'\nexport { Html } from '~/src/server/plugins/engine/components/Html.js'\nexport { InsetText } from '~/src/server/plugins/engine/components/InsetText.js'\nexport { List } from '~/src/server/plugins/engine/components/List.js'\nexport { Markdown } from '~/src/server/plugins/engine/components/Markdown.js'\nexport { MonthYearField } from '~/src/server/plugins/engine/components/MonthYearField.js'\nexport { MultilineTextField } from '~/src/server/plugins/engine/components/MultilineTextField.js'\nexport { NumberField } from '~/src/server/plugins/engine/components/NumberField.js'\nexport { RadiosField } from '~/src/server/plugins/engine/components/RadiosField.js'\nexport { SelectField } from '~/src/server/plugins/engine/components/SelectField.js'\nexport { TelephoneNumberField } from '~/src/server/plugins/engine/components/TelephoneNumberField.js'\nexport { TextField } from '~/src/server/plugins/engine/components/TextField.js'\nexport { UkAddressField } from '~/src/server/plugins/engine/components/UkAddressField.js'\nexport { YesNoField } from '~/src/server/plugins/engine/components/YesNoField.js'\nexport { EastingNorthingField } from '~/src/server/plugins/engine/components/EastingNorthingField.js'\nexport { OsGridRefField } from '~/src/server/plugins/engine/components/OsGridRefField.js'\nexport { NationalGridFieldNumberField } from '~/src/server/plugins/engine/components/NationalGridFieldNumberField.js'\nexport { LatLongField } from '~/src/server/plugins/engine/components/LatLongField.js'\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAEA,SAASA,iBAAiB;AAC1B,SAASC,eAAe;AACxB,SAASC,cAAc;AACvB,SAASC,gBAAgB;AACzB,SAASC,OAAO;AAChB,SAASC,iBAAiB;AAC1B,SAASC,eAAe;AACxB,SAASC,IAAI;AACb,SAASC,SAAS;AAClB,SAASC,IAAI;AACb,SAASC,QAAQ;AACjB,SAASC,cAAc;AACvB,SAASC,kBAAkB;AAC3B,SAASC,WAAW;AACpB,SAASC,WAAW;AACpB,SAASC,WAAW;AACpB,SAASC,oBAAoB;AAC7B,SAASC,SAAS;AAClB,SAASC,cAAc;AACvB,SAASC,UAAU;AACnB,SAASC,oBAAoB;AAC7B,SAASC,cAAc;AACvB,SAASC,4BAA4B;AACrC,SAASC,YAAY","ignoreList":[]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SchemaVersion } from '@defra/forms-model';
|
|
1
2
|
import { getAnswer } from "../components/helpers/components.js";
|
|
2
3
|
import { evaluateTemplate, getError, getPageHref } from "../helpers.js";
|
|
3
4
|
import { RepeatPageController } from "../pageControllers/RepeatPageController.js";
|
|
@@ -36,6 +37,9 @@ export class SummaryViewModel {
|
|
|
36
37
|
} = context;
|
|
37
38
|
this.page = page;
|
|
38
39
|
this.pageTitle = page.title;
|
|
40
|
+
if (def.schema === SchemaVersion.V2 && !page.title) {
|
|
41
|
+
this.pageTitle = 'Check your answers before sending your form';
|
|
42
|
+
}
|
|
39
43
|
this.serviceUrl = `/${basePath}`;
|
|
40
44
|
this.name = def.name;
|
|
41
45
|
this.declaration = def.declaration;
|