@defra/forms-engine-plugin 4.3.0 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/.public/javascripts/application.min.js +1 -1
  2. package/.public/javascripts/application.min.js.map +1 -1
  3. package/.public/javascripts/shared.min.js +1 -1
  4. package/.public/javascripts/shared.min.js.map +1 -1
  5. package/.public/javascripts/vendor/accessible-autocomplete.min.js.map +1 -1
  6. package/.public/stylesheets/application.min.css +1 -1
  7. package/.public/stylesheets/application.min.css.map +1 -1
  8. package/.server/client/javascripts/file-upload.js +13 -8
  9. package/.server/client/javascripts/file-upload.js.map +1 -1
  10. package/.server/client/javascripts/geospatial-map.d.ts +189 -0
  11. package/.server/client/javascripts/geospatial-map.js +1068 -0
  12. package/.server/client/javascripts/geospatial-map.js.map +1 -0
  13. package/.server/client/javascripts/location-map.d.ts +6 -91
  14. package/.server/client/javascripts/location-map.js +78 -385
  15. package/.server/client/javascripts/location-map.js.map +1 -1
  16. package/.server/client/javascripts/map.d.ts +199 -0
  17. package/.server/client/javascripts/map.js +384 -0
  18. package/.server/client/javascripts/map.js.map +1 -0
  19. package/.server/client/javascripts/shared.d.ts +3 -1
  20. package/.server/client/javascripts/shared.js +3 -1
  21. package/.server/client/javascripts/shared.js.map +1 -1
  22. package/.server/client/stylesheets/shared.scss +7 -0
  23. package/.server/server/plugins/engine/components/ComponentBase.d.ts +1 -0
  24. package/.server/server/plugins/engine/components/ComponentBase.js +2 -0
  25. package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
  26. package/.server/server/plugins/engine/components/FileUploadField.d.ts +3 -2
  27. package/.server/server/plugins/engine/components/FileUploadField.js +11 -3
  28. package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
  29. package/.server/server/plugins/engine/components/FormComponent.d.ts +9 -1
  30. package/.server/server/plugins/engine/components/FormComponent.js +22 -0
  31. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  32. package/.server/server/plugins/engine/components/GeospatialField.d.ts +77 -0
  33. package/.server/server/plugins/engine/components/GeospatialField.js +102 -0
  34. package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -0
  35. package/.server/server/plugins/engine/components/helpers/__stubs__/geospatial.d.ts +3 -0
  36. package/.server/server/plugins/engine/components/helpers/__stubs__/geospatial.js +63 -0
  37. package/.server/server/plugins/engine/components/helpers/__stubs__/geospatial.js.map +1 -0
  38. package/.server/server/plugins/engine/components/helpers/components.d.ts +1 -1
  39. package/.server/server/plugins/engine/components/helpers/components.js +7 -0
  40. package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
  41. package/.server/server/plugins/engine/components/helpers/geospatial.d.ts +6 -0
  42. package/.server/server/plugins/engine/components/helpers/geospatial.js +71 -0
  43. package/.server/server/plugins/engine/components/helpers/geospatial.js.map +1 -0
  44. package/.server/server/plugins/engine/components/helpers/geospatial.test.js +42 -0
  45. package/.server/server/plugins/engine/components/helpers/geospatial.test.js.map +1 -0
  46. package/.server/server/plugins/engine/components/index.d.ts +1 -0
  47. package/.server/server/plugins/engine/components/index.js +1 -0
  48. package/.server/server/plugins/engine/components/index.js.map +1 -1
  49. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +11 -0
  50. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +65 -28
  51. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
  52. package/.server/server/plugins/engine/pageControllers/PageController.d.ts +1 -0
  53. package/.server/server/plugins/engine/pageControllers/PageController.js +2 -0
  54. package/.server/server/plugins/engine/pageControllers/PageController.js.map +1 -1
  55. package/.server/server/plugins/engine/pageControllers/helpers/submission.js +13 -1
  56. package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -1
  57. package/.server/server/plugins/engine/pageControllers/validationOptions.js +2 -1
  58. package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
  59. package/.server/server/plugins/engine/types.d.ts +63 -2
  60. package/.server/server/plugins/engine/types.js +33 -0
  61. package/.server/server/plugins/engine/types.js.map +1 -1
  62. package/.server/server/plugins/engine/views/components/geospatialfield.html +7 -0
  63. package/.server/server/plugins/nunjucks/context.test.js.map +1 -1
  64. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  65. package/.server/server/routes/types.js.map +1 -1
  66. package/.server/server/services/cacheService.js +3 -0
  67. package/.server/server/services/cacheService.js.map +1 -1
  68. package/package.json +9 -5
  69. package/src/client/javascripts/file-upload.js +12 -8
  70. package/src/client/javascripts/geospatial-map.js +1023 -0
  71. package/src/client/javascripts/location-map.js +94 -390
  72. package/src/client/javascripts/map.js +389 -0
  73. package/src/client/javascripts/shared.js +3 -1
  74. package/src/client/stylesheets/shared.scss +7 -0
  75. package/src/server/plugins/engine/components/ComponentBase.ts +2 -0
  76. package/src/server/plugins/engine/components/FileUploadField.test.ts +11 -8
  77. package/src/server/plugins/engine/components/FileUploadField.ts +14 -5
  78. package/src/server/plugins/engine/components/FormComponent.ts +29 -0
  79. package/src/server/plugins/engine/components/GeospatialField.test.ts +380 -0
  80. package/src/server/plugins/engine/components/GeospatialField.ts +145 -0
  81. package/src/server/plugins/engine/components/helpers/__stubs__/geospatial.ts +85 -0
  82. package/src/server/plugins/engine/components/helpers/components.test.ts +44 -0
  83. package/src/server/plugins/engine/components/helpers/components.ts +10 -0
  84. package/src/server/plugins/engine/components/helpers/geospatial.test.js +55 -0
  85. package/src/server/plugins/engine/components/helpers/geospatial.ts +93 -0
  86. package/src/server/plugins/engine/components/index.ts +1 -0
  87. package/src/server/plugins/engine/pageControllers/FileUploadPageController.test.ts +109 -5
  88. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +69 -21
  89. package/src/server/plugins/engine/pageControllers/PageController.ts +2 -0
  90. package/src/server/plugins/engine/pageControllers/helpers/submission.test.ts +74 -0
  91. package/src/server/plugins/engine/pageControllers/helpers/submission.ts +17 -1
  92. package/src/server/plugins/engine/pageControllers/validationOptions.ts +3 -1
  93. package/src/server/plugins/engine/types.ts +77 -4
  94. package/src/server/plugins/engine/views/components/geospatialfield.html +7 -0
  95. package/src/server/plugins/nunjucks/context.test.js +2 -3
  96. package/src/server/routes/types.ts +4 -2
  97. package/src/server/services/cacheService.ts +2 -0
@@ -6,6 +6,7 @@ import { type ViewModel } from '~/src/server/plugins/engine/components/types.js'
6
6
  import { type FormModel } from '~/src/server/plugins/engine/models/index.js';
7
7
  import { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js';
8
8
  export declare class ComponentBase {
9
+ id?: string;
9
10
  page?: PageControllerClass;
10
11
  parent: Component | undefined;
11
12
  collection: ComponentCollection | undefined;
@@ -1,6 +1,7 @@
1
1
  import { isConditionalRevealType } from '@defra/forms-model';
2
2
  import joi from 'joi';
3
3
  export class ComponentBase {
4
+ id;
4
5
  page;
5
6
  parent;
6
7
  collection;
@@ -16,6 +17,7 @@ export class ComponentBase {
16
17
  formSchema = joi.string();
17
18
  stateSchema = joi.string();
18
19
  constructor(def, props) {
20
+ this.id = def.id;
19
21
  this.type = def.type;
20
22
  this.name = def.name;
21
23
  this.title = def.title;
@@ -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 | 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
+ {"version":3,"file":"ComponentBase.js","names":["isConditionalRevealType","joi","ComponentBase","id","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 id?: string\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.id = def.id\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,EAAE;EACFC,IAAI;EACJC,MAAM;EACNC,UAAU;EAEVC,IAAI;EACJC,IAAI;EACJC,KAAK;EACLC,MAAM;EACNC,OAAO;EAEPC,eAAe,GAAG,KAAK;EACvBC,KAAK;;EAEL;EACAC,UAAU,GAAoBb,GAAG,CAACc,MAAM,CAAC,CAAC;EAC1CC,WAAW,GAAoBf,GAAG,CAACc,MAAM,CAAC,CAAC;EAE3CE,WAAWA,CACTC,GAAiB,EACjBC,KAIC,EACD;IACA,IAAI,CAAChB,EAAE,GAAGe,GAAG,CAACf,EAAE;IAChB,IAAI,CAACI,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,IAAIX,uBAAuB,CAACO,IAAI,CAAC,EAAE;MAC3Da,SAAS,CAACI,SAAS,GAAGb,OAAO,CAACa,SAAS;IACzC;IAEA,OAAOJ,SAAS;EAClB;AACF","ignoreList":[]}
@@ -26,12 +26,13 @@ export declare class FileUploadField extends FormComponent {
26
26
  getContextValueFromFormValue(files: UploadState | undefined): string[] | null;
27
27
  getContextValueFromState(state: FormSubmissionState): string[] | null;
28
28
  getViewModel(payload: FormPayload, errors?: FormSubmissionError[], query?: FormQuery): {
29
- value: string;
30
- name: string;
31
29
  upload: {
32
30
  count: number;
33
31
  summaryList: SummaryList;
34
32
  };
33
+ multiple?: boolean | undefined;
34
+ value: string;
35
+ name: string;
35
36
  label: {
36
37
  text: string;
37
38
  };
@@ -25,7 +25,7 @@ export const tempStatusSchema = joi.object({
25
25
  uploadStatus: joi.string().valid(UploadStatus.ready, UploadStatus.pending).required(),
26
26
  metadata: metadataSchema,
27
27
  form: joi.object().required().keys({
28
- file: tempFileSchema
28
+ file: joi.array().items(tempFileSchema).single().required()
29
29
  }),
30
30
  numberOfRejectedFiles: joi.number().optional()
31
31
  }).required();
@@ -106,7 +106,8 @@ export class FileUploadField extends FormComponent {
106
106
  getViewModel(payload, errors, query = {}) {
107
107
  const {
108
108
  options,
109
- page
109
+ page,
110
+ schema
110
111
  } = this;
111
112
 
112
113
  // Allow preview URL direct access
@@ -153,7 +154,7 @@ export class FileUploadField extends FormComponent {
153
154
 
154
155
  // Remove summary list actions from previews
155
156
  if (!isForceAccess) {
156
- const path = `/${item.uploadId}/confirm-delete`;
157
+ const path = `/${file.fileId}/confirm-delete`;
157
158
  const href = page?.getHref(`${page.path}${path}`) ?? '#';
158
159
  items.push({
159
160
  href,
@@ -182,6 +183,9 @@ export class FileUploadField extends FormComponent {
182
183
  if ('accept' in options && options.accept) {
183
184
  attributes.accept = options.accept;
184
185
  }
186
+
187
+ // Allow multiple file selection when schema permits more than 1 file
188
+ const allowsMultiple = schema.max !== 1 && schema.length !== 1;
185
189
  const summaryList = {
186
190
  classes: 'govuk-summary-list--long-key',
187
191
  rows
@@ -192,6 +196,10 @@ export class FileUploadField extends FormComponent {
192
196
  value: '',
193
197
  // Override the component name we send to CDP
194
198
  name: 'file',
199
+ // Enable multi-file selection in the file picker
200
+ ...(allowsMultiple && {
201
+ multiple: true
202
+ }),
195
203
  upload: {
196
204
  count,
197
205
  summaryList
@@ -1 +1 @@
1
- {"version":3,"file":"FileUploadField.js","names":["Boom","joi","FormComponent","isUploadState","InvalidComponentStateError","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","getDisplayStringFromFormValue","files","unit","getDisplayStringFromState","getContextValueFromFormValue","map","getContextValueFromState","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","onSubmit","request","notificationEmail","Error","app","model","services","formSubmissionService","values","initiatedRetrievalKey","persistFiles","error","isBoom","output","statusCode","baseErrors","type","template","selectRequired","advancedSettingsErrors"],"sources":["../../../../../src/server/plugins/engine/components/FileUploadField.ts"],"sourcesContent":["import {\n type FileUploadFieldComponent,\n type FormMetadata\n} from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport joi, { type ArraySchema } from 'joi'\n\nimport {\n FormComponent,\n isUploadState\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { InvalidComponentStateError } from '~/src/server/plugins/engine/pageControllers/errors.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 FormContext,\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 {\n type FormQuery,\n type FormRequestPayload\n} 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 } else if (options.required !== false) {\n formSchema = formSchema.min(1)\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 getDisplayStringFromFormValue(files: FileState[] | undefined): string {\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 getDisplayStringFromState(state: FormSubmissionState) {\n const files = this.getFormValueFromState(state)\n\n return this.getDisplayStringFromFormValue(files)\n }\n\n getContextValueFromFormValue(\n files: UploadState | undefined\n ): string[] | null {\n return files?.map(({ status }) => status.form.file.fileId) ?? null\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const files = this.getFormValueFromState(state)\n return this.getContextValueFromFormValue(files)\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 FileUploadField.getAllPossibleErrors()\n }\n\n async onSubmit(\n request: FormRequestPayload,\n metadata: FormMetadata,\n context: FormContext\n ) {\n const notificationEmail = metadata.notificationEmail\n\n if (!notificationEmail) {\n // this should not happen because notificationEmail is checked further up\n // the chain in SummaryPageController before submitForm is called.\n throw new Error('Unexpected missing notificationEmail in metadata')\n }\n\n if (!request.app.model?.services.formSubmissionService) {\n throw new Error('No form submission service available in app model')\n }\n\n const { formSubmissionService } = request.app.model.services\n const values = this.getFormValueFromState(context.state) ?? []\n\n const files = values.map((value) => ({\n fileId: value.status.form.file.fileId,\n initiatedRetrievalKey: value.status.metadata.retrievalKey\n }))\n\n if (!files.length) {\n return\n }\n\n try {\n await formSubmissionService.persistFiles(files, notificationEmail)\n } catch (error) {\n if (\n Boom.isBoom(error) &&\n (error.output.statusCode === 403 || // Forbidden - retrieval key invalid\n error.output.statusCode === 410) // Gone - file expired (took to long to submit, etc)\n ) {\n // Failed to persist files. We can't recover from this, the only real way we can recover the submissions is\n // by resetting the problematic components and letting the user re-try.\n // Scenarios: file missing from S3, invalid retrieval key (timing problem), etc.\n throw new InvalidComponentStateError(\n this,\n 'There was a problem with your uploaded files. Re-upload them before submitting the form again.'\n )\n }\n\n throw error\n }\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: '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":[]}
1
+ {"version":3,"file":"FileUploadField.js","names":["Boom","joi","FormComponent","isUploadState","InvalidComponentStateError","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","array","items","single","numberOfRejectedFiles","formStatusSchema","itemSchema","uploadId","tempItemSchema","status","formItemSchema","FileUploadField","constructor","def","props","options","schema","formSchema","label","length","max","min","stateSchema","default","allow","getFormValueFromState","state","name","getFormValue","value","isValue","undefined","getDisplayStringFromFormValue","files","unit","getDisplayStringFromState","getContextValueFromFormValue","map","getContextValueFromState","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","allowsMultiple","summaryList","multiple","upload","getAllPossibleErrors","onSubmit","request","notificationEmail","Error","app","model","services","formSubmissionService","values","initiatedRetrievalKey","persistFiles","error","isBoom","output","statusCode","baseErrors","type","template","selectRequired","advancedSettingsErrors"],"sources":["../../../../../src/server/plugins/engine/components/FileUploadField.ts"],"sourcesContent":["import {\n type FileUploadFieldComponent,\n type FormMetadata\n} from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport joi, { type ArraySchema } from 'joi'\n\nimport {\n FormComponent,\n isUploadState\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { InvalidComponentStateError } from '~/src/server/plugins/engine/pageControllers/errors.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 FormContext,\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 {\n type FormQuery,\n type FormRequestPayload\n} 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\n .object()\n .required()\n .keys({\n file: joi.array().items(tempFileSchema).single().required()\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 } else if (options.required !== false) {\n formSchema = formSchema.min(1)\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 getDisplayStringFromFormValue(files: FileState[] | undefined): string {\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 getDisplayStringFromState(state: FormSubmissionState) {\n const files = this.getFormValueFromState(state)\n\n return this.getDisplayStringFromFormValue(files)\n }\n\n getContextValueFromFormValue(\n files: UploadState | undefined\n ): string[] | null {\n return files?.map(({ status }) => status.form.file.fileId) ?? null\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const files = this.getFormValueFromState(state)\n return this.getContextValueFromFormValue(files)\n }\n\n getViewModel(\n payload: FormPayload,\n errors?: FormSubmissionError[],\n query: FormQuery = {}\n ) {\n const { options, page, schema } = 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 = `/${file.fileId}/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 // Allow multiple file selection when schema permits more than 1 file\n const allowsMultiple = schema.max !== 1 && schema.length !== 1\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 // Enable multi-file selection in the file picker\n ...(allowsMultiple && { multiple: true }),\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 FileUploadField.getAllPossibleErrors()\n }\n\n async onSubmit(\n request: FormRequestPayload,\n metadata: FormMetadata,\n context: FormContext\n ) {\n const notificationEmail = metadata.notificationEmail\n\n if (!notificationEmail) {\n // this should not happen because notificationEmail is checked further up\n // the chain in SummaryPageController before submitForm is called.\n throw new Error('Unexpected missing notificationEmail in metadata')\n }\n\n if (!request.app.model?.services.formSubmissionService) {\n throw new Error('No form submission service available in app model')\n }\n\n const { formSubmissionService } = request.app.model.services\n const values = this.getFormValueFromState(context.state) ?? []\n\n const files = values.map((value) => ({\n fileId: value.status.form.file.fileId,\n initiatedRetrievalKey: value.status.metadata.retrievalKey\n }))\n\n if (!files.length) {\n return\n }\n\n try {\n await formSubmissionService.persistFiles(files, notificationEmail)\n } catch (error) {\n if (\n Boom.isBoom(error) &&\n (error.output.statusCode === 403 || // Forbidden - retrieval key invalid\n error.output.statusCode === 410) // Gone - file expired (took to long to submit, etc)\n ) {\n // Failed to persist files. We can't recover from this, the only real way we can recover the submissions is\n // by resetting the problematic components and letting the user re-try.\n // Scenarios: file missing from S3, invalid retrieval key (timing problem), etc.\n throw new InvalidComponentStateError(\n this,\n 'There was a problem with your uploaded files. Re-upload them before submitting the form again.'\n )\n }\n\n throw error\n }\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: '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":[]}
@@ -1,7 +1,7 @@
1
1
  import { type FormComponentsDef, type FormMetadata, type Item } from '@defra/forms-model';
2
2
  import { ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js';
3
3
  import { type FormContext, type FormRequestPayload } from '~/src/server/plugins/engine/types/index.js';
4
- import { type ErrorMessageTemplateList, type FileState, type FormPayload, type FormState, type FormStateValue, type FormSubmissionError, type FormSubmissionState, type FormValue, type RepeatItemState, type RepeatListState, type UploadState } from '~/src/server/plugins/engine/types.js';
4
+ import { type ErrorMessageTemplateList, type Feature, type FileState, type FormPayload, type FormState, type FormStateValue, type FormSubmissionError, type FormSubmissionState, type FormValue, type GeospatialState, type RepeatItemState, type RepeatListState, type UploadState } from '~/src/server/plugins/engine/types.js';
5
5
  export declare class FormComponent extends ComponentBase {
6
6
  type: FormComponentsDef['type'];
7
7
  hint: FormComponentsDef['hint'];
@@ -102,7 +102,15 @@ export declare function isRepeatValue(value?: unknown): value is RepeatItemState
102
102
  * Check for upload state
103
103
  */
104
104
  export declare function isUploadState(value?: unknown): value is UploadState;
105
+ /**
106
+ * Check for geospatial state
107
+ */
108
+ export declare function isGeospatialState(value?: unknown): value is GeospatialState;
105
109
  /**
106
110
  * Check for upload state value
107
111
  */
108
112
  export declare function isUploadValue(value?: unknown): value is FileState;
113
+ /**
114
+ * Check for geospatial state value
115
+ */
116
+ export declare function isGeospatialValue(value?: unknown): value is Feature;
@@ -235,10 +235,32 @@ export function isUploadState(value) {
235
235
  return value.every(isUploadValue);
236
236
  }
237
237
 
238
+ /**
239
+ * Check for geospatial state
240
+ */
241
+ export function isGeospatialState(value) {
242
+ if (!Array.isArray(value)) {
243
+ return false;
244
+ }
245
+
246
+ // Skip checks when empty
247
+ if (!value.length) {
248
+ return true;
249
+ }
250
+ return value.every(isGeospatialValue);
251
+ }
252
+
238
253
  /**
239
254
  * Check for upload state value
240
255
  */
241
256
  export function isUploadValue(value) {
242
257
  return isFormState(value) && typeof value.uploadId === 'string';
243
258
  }
259
+
260
+ /**
261
+ * Check for geospatial state value
262
+ */
263
+ export function isGeospatialValue(value) {
264
+ return isFormState(value) && typeof value.type === 'string' && value.type === 'Feature';
265
+ }
244
266
  //# sourceMappingURL=FormComponent.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FormComponent.js","names":["ComponentBase","optionalText","FormComponent","type","hint","label","isFormComponent","isAppendageStateSingleObject","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","getDisplayStringFromFormValue","toString","getDisplayStringFromState","getContextValueFromFormValue","isState","values","Object","isFormValue","Array","isArray","getContextValueFromState","isFormState","getAllPossibleErrors","baseErrors","advancedSettingsErrors","onSubmit","_request","_metadata","_context","Promise","resolve","isRepeatState","every","isRepeatValue","itemId","isUploadState","isUploadValue","uploadId"],"sources":["../../../../../src/server/plugins/engine/components/FormComponent.ts"],"sourcesContent":["import {\n type FormComponentsDef,\n type FormMetadata,\n type Item\n} 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 FormContext,\n type FormRequestPayload\n} from '~/src/server/plugins/engine/types/index.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 isAppendageStateSingleObject = false\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 getDisplayStringFromFormValue(value: FormValue | FormPayload): string {\n // Map selected values to text\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n return this.isValue(value) ? value.toString() : ''\n }\n\n getDisplayStringFromState(state: FormSubmissionState): string {\n const value = this.getFormValueFromState(state)\n return this.getDisplayStringFromFormValue(value)\n }\n\n getContextValueFromFormValue(\n value: FormValue | FormPayload\n ): Item['value'] | Item['value'][] | null {\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 getContextValueFromState(\n state: FormSubmissionState\n ): Item['value'] | Item['value'][] | null {\n const value = this.getFormValueFromState(state)\n\n return this.getContextValueFromFormValue(value)\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 * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return FormComponent.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 advancedSettingsErrors: []\n }\n }\n\n onSubmit(\n _request: FormRequestPayload,\n _metadata: FormMetadata,\n _context: FormContext\n ): Promise<void> {\n return Promise.resolve()\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","isAppendageStateSingleObject","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","getDisplayStringFromFormValue","toString","getDisplayStringFromState","getContextValueFromFormValue","isState","values","Object","isFormValue","Array","isArray","getContextValueFromState","isFormState","getAllPossibleErrors","baseErrors","advancedSettingsErrors","onSubmit","_request","_metadata","_context","Promise","resolve","isRepeatState","every","isRepeatValue","itemId","isUploadState","isUploadValue","isGeospatialState","isGeospatialValue","uploadId"],"sources":["../../../../../src/server/plugins/engine/components/FormComponent.ts"],"sourcesContent":["import {\n type FormComponentsDef,\n type FormMetadata,\n type Item\n} 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 FormContext,\n type FormRequestPayload\n} from '~/src/server/plugins/engine/types/index.js'\nimport {\n type ErrorMessageTemplateList,\n type Feature,\n type FileState,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValue,\n type GeospatialState,\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 isAppendageStateSingleObject = false\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 getDisplayStringFromFormValue(value: FormValue | FormPayload): string {\n // Map selected values to text\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n return this.isValue(value) ? value.toString() : ''\n }\n\n getDisplayStringFromState(state: FormSubmissionState): string {\n const value = this.getFormValueFromState(state)\n return this.getDisplayStringFromFormValue(value)\n }\n\n getContextValueFromFormValue(\n value: FormValue | FormPayload\n ): Item['value'] | Item['value'][] | null {\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 getContextValueFromState(\n state: FormSubmissionState\n ): Item['value'] | Item['value'][] | null {\n const value = this.getFormValueFromState(state)\n\n return this.getContextValueFromFormValue(value)\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 * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return FormComponent.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 advancedSettingsErrors: []\n }\n }\n\n onSubmit(\n _request: FormRequestPayload,\n _metadata: FormMetadata,\n _context: FormContext\n ): Promise<void> {\n return Promise.resolve()\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 geospatial state\n */\nexport function isGeospatialState(value?: unknown): value is GeospatialState {\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(isGeospatialValue)\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\n/**\n * Check for geospatial state value\n */\nexport function isGeospatialValue(value?: unknown): value is Feature {\n return (\n isFormState(value) &&\n typeof value.type === 'string' &&\n value.type === 'Feature'\n )\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,77 @@
1
+ import { type GeospatialFieldComponent } from '@defra/forms-model';
2
+ import { type ArraySchema } from 'joi';
3
+ import { type ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js';
4
+ import { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js';
5
+ import { type ErrorMessageTemplateList, type FormPayload, type FormState, type FormStateValue, type FormSubmissionError, type FormSubmissionState, type GeospatialState } from '~/src/server/plugins/engine/types.js';
6
+ export declare class GeospatialField extends FormComponent {
7
+ options: GeospatialFieldComponent['options'];
8
+ formSchema: ArraySchema<GeospatialState>;
9
+ stateSchema: ArraySchema<GeospatialState>;
10
+ constructor(def: GeospatialFieldComponent, props: ConstructorParameters<typeof ComponentBase>[1]);
11
+ getFormValueFromState(state: FormSubmissionState): import("~/src/server/plugins/engine/types.js").FeatureCollection | undefined;
12
+ getFormValue(value?: FormStateValue | FormState): import("~/src/server/plugins/engine/types.js").FeatureCollection | undefined;
13
+ getDisplayStringFromFormValue(features: GeospatialState | undefined): string;
14
+ getDisplayStringFromState(state: FormSubmissionState): string;
15
+ getContextValueFromFormValue(features: GeospatialState | undefined): string[] | null;
16
+ getContextValueFromState(state: FormSubmissionState): string[] | null;
17
+ getViewModel(payload: FormPayload, errors?: FormSubmissionError[]): {
18
+ value: string;
19
+ label: {
20
+ text: string;
21
+ };
22
+ id: string;
23
+ name: string;
24
+ type?: string;
25
+ hint?: {
26
+ id?: string;
27
+ text: string;
28
+ };
29
+ prefix?: import("./types.js").ComponentText;
30
+ suffix?: import("./types.js").ComponentText;
31
+ classes?: string;
32
+ condition?: string;
33
+ errors?: FormSubmissionError[];
34
+ errorMessage?: {
35
+ text: string;
36
+ };
37
+ summaryHtml?: string;
38
+ html?: string;
39
+ attributes: {
40
+ autocomplete?: string;
41
+ maxlength?: number;
42
+ multiple?: string;
43
+ accept?: string;
44
+ inputmode?: string;
45
+ };
46
+ content?: import("./types.js").Content | import("./types.js").Content[] | string;
47
+ maxlength?: number;
48
+ maxwords?: number;
49
+ rows?: number;
50
+ items?: import("./types.js").ListItem[] | import("./types.js").DateInputItem[];
51
+ fieldset?: {
52
+ attributes?: string | Record<string, string>;
53
+ legend?: import("./types.js").Label;
54
+ };
55
+ formGroup?: {
56
+ classes?: string;
57
+ attributes?: string | Record<string, string>;
58
+ };
59
+ showFieldsetError?: boolean;
60
+ components?: import("./types.js").ComponentViewModel[];
61
+ upload?: {
62
+ count: number;
63
+ summaryList: import("~/src/server/plugins/engine/types.js").SummaryList;
64
+ };
65
+ };
66
+ getErrors(errors?: FormSubmissionError[]): FormSubmissionError[] | undefined;
67
+ getViewErrors(errors?: FormSubmissionError[]): FormSubmissionError[] | undefined;
68
+ isValue(value?: FormStateValue | FormState): value is GeospatialState;
69
+ /**
70
+ * For error preview page that shows all possible errors on a component
71
+ */
72
+ getAllPossibleErrors(): ErrorMessageTemplateList;
73
+ /**
74
+ * Static version of getAllPossibleErrors that doesn't require a component instance.
75
+ */
76
+ static getAllPossibleErrors(): ErrorMessageTemplateList;
77
+ }
@@ -0,0 +1,102 @@
1
+ import { FormComponent, isGeospatialState } from "./FormComponent.js";
2
+ import { geospatialSchema } from "./helpers/geospatial.js";
3
+ import { messageTemplate } from "../pageControllers/validationOptions.js";
4
+ export class GeospatialField extends FormComponent {
5
+ constructor(def, props) {
6
+ super(def, props);
7
+ const {
8
+ options
9
+ } = def;
10
+ let formSchema = geospatialSchema.label(this.label).required();
11
+ if (options.required !== false) {
12
+ formSchema = formSchema.min(1);
13
+ }
14
+ this.formSchema = formSchema;
15
+ this.stateSchema = formSchema.default(null);
16
+ this.options = options;
17
+ }
18
+ getFormValueFromState(state) {
19
+ const {
20
+ name
21
+ } = this;
22
+ return this.getFormValue(state[name]);
23
+ }
24
+ getFormValue(value) {
25
+ return this.isValue(value) ? value : undefined;
26
+ }
27
+ getDisplayStringFromFormValue(features) {
28
+ if (!features?.length) {
29
+ return '';
30
+ }
31
+ const unit = features.length === 1 ? 'location' : 'locations';
32
+ return `Added ${features.length} ${unit}`;
33
+ }
34
+ getDisplayStringFromState(state) {
35
+ const features = this.getFormValueFromState(state);
36
+ return this.getDisplayStringFromFormValue(features);
37
+ }
38
+ getContextValueFromFormValue(features) {
39
+ return features?.map(({
40
+ id
41
+ }) => id) ?? null;
42
+ }
43
+ getContextValueFromState(state) {
44
+ const features = this.getFormValueFromState(state);
45
+ return this.getContextValueFromFormValue(features);
46
+ }
47
+ getViewModel(payload, errors) {
48
+ const viewModel = super.getViewModel(payload, errors);
49
+ const value = typeof viewModel.value === 'string' ? viewModel.value : JSON.stringify(viewModel.value, null, 2);
50
+ return {
51
+ ...viewModel,
52
+ value
53
+ };
54
+ }
55
+ getErrors(errors) {
56
+ const fieldErrors = super.getErrors(errors);
57
+ fieldErrors?.forEach(err => {
58
+ if (err.name === 'description') {
59
+ err.href = `#description_${err.path[1]}`;
60
+ err.text = `Enter description for location ${Number(err.path[1]) + 1}`;
61
+ }
62
+ });
63
+ return fieldErrors;
64
+ }
65
+ getViewErrors(errors) {
66
+ return this.getErrors(errors);
67
+ }
68
+ isValue(value) {
69
+ return isGeospatialState(value);
70
+ }
71
+
72
+ /**
73
+ * For error preview page that shows all possible errors on a component
74
+ */
75
+ getAllPossibleErrors() {
76
+ const staticErrors = GeospatialField.getAllPossibleErrors();
77
+ return {
78
+ ...staticErrors,
79
+ advancedSettingsErrors: [...staticErrors.advancedSettingsErrors]
80
+ };
81
+ }
82
+
83
+ /**
84
+ * Static version of getAllPossibleErrors that doesn't require a component instance.
85
+ */
86
+ static getAllPossibleErrors() {
87
+ return {
88
+ baseErrors: [{
89
+ type: 'required',
90
+ template: messageTemplate.selectRequired
91
+ }, {
92
+ type: 'array.min',
93
+ template: '{{#title}} must contain at least 1 items'
94
+ }, {
95
+ type: 'object.invalidjson',
96
+ template: messageTemplate.format
97
+ }],
98
+ advancedSettingsErrors: []
99
+ };
100
+ }
101
+ }
102
+ //# sourceMappingURL=GeospatialField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GeospatialField.js","names":["FormComponent","isGeospatialState","geospatialSchema","messageTemplate","GeospatialField","constructor","def","props","options","formSchema","label","required","min","stateSchema","default","getFormValueFromState","state","name","getFormValue","value","isValue","undefined","getDisplayStringFromFormValue","features","length","unit","getDisplayStringFromState","getContextValueFromFormValue","map","id","getContextValueFromState","getViewModel","payload","errors","viewModel","JSON","stringify","getErrors","fieldErrors","forEach","err","href","path","text","Number","getViewErrors","getAllPossibleErrors","staticErrors","advancedSettingsErrors","baseErrors","type","template","selectRequired","format"],"sources":["../../../../../src/server/plugins/engine/components/GeospatialField.ts"],"sourcesContent":["import { type GeospatialFieldComponent } from '@defra/forms-model'\nimport { type ArraySchema } from 'joi'\n\nimport { type ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'\nimport {\n FormComponent,\n isGeospatialState\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { geospatialSchema } from '~/src/server/plugins/engine/components/helpers/geospatial.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 GeospatialState\n} from '~/src/server/plugins/engine/types.js'\n\nexport class GeospatialField extends FormComponent {\n declare options: GeospatialFieldComponent['options']\n declare formSchema: ArraySchema<GeospatialState>\n declare stateSchema: ArraySchema<GeospatialState>\n\n constructor(\n def: GeospatialFieldComponent,\n props: ConstructorParameters<typeof ComponentBase>[1]\n ) {\n super(def, props)\n\n const { options } = def\n\n let formSchema = geospatialSchema.label(this.label).required()\n\n if (options.required !== false) {\n formSchema = formSchema.min(1)\n }\n\n this.formSchema = formSchema\n this.stateSchema = formSchema.default(null)\n this.options = options\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 getDisplayStringFromFormValue(features: GeospatialState | undefined): string {\n if (!features?.length) {\n return ''\n }\n\n const unit = features.length === 1 ? 'location' : 'locations'\n\n return `Added ${features.length} ${unit}`\n }\n\n getDisplayStringFromState(state: FormSubmissionState) {\n const features = this.getFormValueFromState(state)\n\n return this.getDisplayStringFromFormValue(features)\n }\n\n getContextValueFromFormValue(\n features: GeospatialState | undefined\n ): string[] | null {\n return features?.map(({ id }) => id) ?? null\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const features = this.getFormValueFromState(state)\n\n return this.getContextValueFromFormValue(features)\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const viewModel = super.getViewModel(payload, errors)\n const value =\n typeof viewModel.value === 'string'\n ? viewModel.value\n : JSON.stringify(viewModel.value, null, 2)\n\n return {\n ...viewModel,\n value\n }\n }\n\n getErrors(errors?: FormSubmissionError[]): FormSubmissionError[] | undefined {\n const fieldErrors = super.getErrors(errors)\n\n fieldErrors?.forEach((err) => {\n if (err.name === 'description') {\n err.href = `#description_${err.path[1]}`\n err.text = `Enter description for location ${Number(err.path[1]) + 1}`\n }\n })\n\n return fieldErrors\n }\n\n getViewErrors(\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n return this.getErrors(errors)\n }\n\n isValue(value?: FormStateValue | FormState): value is GeospatialState {\n return isGeospatialState(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n const staticErrors = GeospatialField.getAllPossibleErrors()\n return {\n ...staticErrors,\n advancedSettingsErrors: [...staticErrors.advancedSettingsErrors]\n }\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.selectRequired },\n {\n type: 'array.min',\n template: '{{#title}} must contain at least 1 items'\n },\n { type: 'object.invalidjson', template: messageTemplate.format }\n ],\n advancedSettingsErrors: []\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,3 @@
1
+ import { type GeospatialState } from '~/src/server/plugins/engine/types.js';
2
+ export declare const validState: GeospatialState;
3
+ export declare const validSingleState: GeospatialState;
@@ -0,0 +1,63 @@
1
+ export const validState = [{
2
+ type: 'Feature',
3
+ properties: {
4
+ description: 'My farm house',
5
+ coordinateGridReference: 'ST 00001',
6
+ centroidGridReference: 'ST 00001'
7
+ },
8
+ geometry: {
9
+ coordinates: [-2.5723699109417737, 53.2380485215034],
10
+ type: 'Point'
11
+ },
12
+ id: 'a'
13
+ }, {
14
+ type: 'Feature',
15
+ properties: {
16
+ description: 'Main gas line',
17
+ coordinateGridReference: 'ST 00001',
18
+ centroidGridReference: 'ST 00001'
19
+ },
20
+ geometry: {
21
+ coordinates: [[-2.570496516462896, 53.239162468888566], [-2.5722447488110447, 53.238174174285746]],
22
+ type: 'LineString'
23
+ },
24
+ id: 'b'
25
+ }, {
26
+ type: 'Feature',
27
+ properties: {
28
+ description: 'My Pony Paddock',
29
+ coordinateGridReference: 'ST 00001',
30
+ centroidGridReference: 'ST 00001'
31
+ },
32
+ geometry: {
33
+ coordinates: [[[-2.573552894955583, 53.238229751360706], [-2.5738557065633643, 53.23812342993719], [-2.5737507318720247, 53.23797119653088], [-2.573411582871387, 53.23785037598134], [-2.5727575097991178, 53.23787454011864], [-2.572858447002119, 53.23825391528342], [-2.573552894955583, 53.238229751360706]]],
34
+ type: 'Polygon'
35
+ },
36
+ id: 'c'
37
+ }, {
38
+ type: 'Feature',
39
+ properties: {
40
+ description: 'My farm house #2',
41
+ coordinateGridReference: 'ST 00001',
42
+ centroidGridReference: 'ST 00001'
43
+ },
44
+ geometry: {
45
+ coordinates: [-2.5724, 53.239],
46
+ type: 'Point'
47
+ },
48
+ id: 'd'
49
+ }];
50
+ export const validSingleState = [{
51
+ type: 'Feature',
52
+ properties: {
53
+ description: 'My farm house',
54
+ coordinateGridReference: 'ST 00001',
55
+ centroidGridReference: 'ST 00001'
56
+ },
57
+ geometry: {
58
+ coordinates: [-2.5723699109417737, 53.2380485215034],
59
+ type: 'Point'
60
+ },
61
+ id: 'a'
62
+ }];
63
+ //# sourceMappingURL=geospatial.js.map