@defra/forms-engine-plugin 4.13.0 → 4.14.1

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 (32) hide show
  1. package/.public/javascripts/shared.min.js +1 -1
  2. package/.public/javascripts/shared.min.js.map +1 -1
  3. package/.server/client/javascripts/geospatial-map.d.ts +32 -0
  4. package/.server/client/javascripts/geospatial-map.js +161 -70
  5. package/.server/client/javascripts/geospatial-map.js.map +1 -1
  6. package/.server/client/javascripts/map.d.ts +6 -0
  7. package/.server/client/javascripts/map.js +5 -0
  8. package/.server/client/javascripts/map.js.map +1 -1
  9. package/.server/client/javascripts/utils.d.ts +7 -0
  10. package/.server/client/javascripts/utils.js +21 -0
  11. package/.server/client/javascripts/utils.js.map +1 -0
  12. package/.server/server/forms/simple-form.yaml +9 -0
  13. package/.server/server/plugins/engine/components/GeospatialField.d.ts +1 -0
  14. package/.server/server/plugins/engine/components/GeospatialField.js +9 -5
  15. package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
  16. package/.server/server/plugins/engine/components/helpers/geospatial.d.ts +2 -2
  17. package/.server/server/plugins/engine/components/helpers/geospatial.js +32 -5
  18. package/.server/server/plugins/engine/components/helpers/geospatial.js.map +1 -1
  19. package/.server/server/plugins/engine/components/helpers/geospatial.test.js +37 -6
  20. package/.server/server/plugins/engine/components/helpers/geospatial.test.js.map +1 -1
  21. package/.server/server/plugins/engine/pageControllers/validationOptions.js +4 -1
  22. package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
  23. package/.server/server/plugins/engine/views/components/geospatialfield.html +1 -1
  24. package/package.json +2 -2
  25. package/src/client/javascripts/geospatial-map.js +168 -53
  26. package/src/client/javascripts/map.js +5 -0
  27. package/src/client/javascripts/utils.js +23 -0
  28. package/src/server/forms/simple-form.yaml +9 -0
  29. package/src/server/plugins/engine/components/GeospatialField.ts +11 -7
  30. package/src/server/plugins/engine/components/helpers/geospatial.ts +49 -11
  31. package/src/server/plugins/engine/pageControllers/validationOptions.ts +4 -1
  32. package/src/server/plugins/engine/views/components/geospatialfield.html +1 -1
@@ -25,6 +25,15 @@ pages:
25
25
  required: true
26
26
  schema: {}
27
27
  id: b68df7f1-d4f4-4c17-83c8-402f584906c9
28
+ - type: GeospatialField
29
+ title: Where do you live?
30
+ name: applicantLocation
31
+ shortDescription: Your location
32
+ hint: ''
33
+ options:
34
+ required: true
35
+ schema: {}
36
+ id: e18116e0-7c3e-416a-af42-6f229017c5b1
28
37
  next: []
29
38
  id: 622a35ec-3795-418a-81f3-a45746959045
30
39
  - title: Upload a copy of your passport
@@ -31,18 +31,21 @@ export class GeospatialField extends FormComponent {
31
31
 
32
32
  const { options } = def
33
33
 
34
- let formSchema = getGeospatialSchema(options.countries?.at(0))
34
+ const formSchema = getGeospatialSchema(def)
35
35
  .label(this.label)
36
- .required()
36
+ .messages({
37
+ 'array.min': messageTemplate.featuresMin as string,
38
+ 'array.max': messageTemplate.featuresMax as string,
39
+ 'array.length': messageTemplate.featuresLength as string
40
+ })
37
41
 
38
- formSchema = formSchema.max(50)
42
+ this.formSchema = formSchema
43
+ this.stateSchema = formSchema.default(null)
39
44
 
40
- if (options.required !== false) {
41
- formSchema = formSchema.min(1)
45
+ if (options.required === false) {
46
+ this.stateSchema = this.stateSchema.allow(null)
42
47
  }
43
48
 
44
- this.formSchema = formSchema
45
- this.stateSchema = formSchema.default(null)
46
49
  this.options = options
47
50
  }
48
51
 
@@ -93,6 +96,7 @@ export class GeospatialField extends FormComponent {
93
96
  return {
94
97
  ...viewModel,
95
98
  country: this.options.countries?.at(0),
99
+ geometryTypes: this.options.geometryTypes,
96
100
  value
97
101
  }
98
102
  }
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  GeospatialFieldOptionsCountryEnum,
3
+ type GeospatialFieldComponent,
3
4
  type GeospatialFieldOptionsCountry
4
5
  } from '@defra/forms-model'
5
6
  import Bourne from '@hapi/bourne'
@@ -31,7 +32,8 @@ const Joi = JoiBase.extend({
31
32
  from: 'string',
32
33
  method(value, helpers) {
33
34
  if (typeof value === 'string') {
34
- if (value.trim() === '') {
35
+ const trimmed = value.trim()
36
+ if (trimmed === '' || trimmed === '[]') {
35
37
  return {
36
38
  value: undefined
37
39
  }
@@ -96,14 +98,48 @@ const featureSchema = Joi.object<Feature>().keys({
96
98
  geometry: featureGeometrySchema
97
99
  })
98
100
 
99
- const geospatialSchema = Joi.array<Feature[]>()
100
- .items(featureSchema)
101
- .unique('id')
102
- .required()
101
+ function applySchemaConstraints(
102
+ schema: JoiBase.ArraySchema<Feature[]>,
103
+ def: GeospatialFieldComponent
104
+ ) {
105
+ const { options, schema: constraints } = def
106
+ const isOptional = options.required === false
107
+
108
+ if (typeof constraints?.length === 'number') {
109
+ schema = schema.length(constraints.length)
110
+ } else {
111
+ if (typeof constraints?.min === 'number') {
112
+ schema = schema.min(constraints.min)
113
+ } else if (!isOptional) {
114
+ schema = schema.min(1)
115
+ }
116
+
117
+ schema = schema.max(
118
+ typeof constraints?.max === 'number' ? constraints.max : 50
119
+ )
120
+ }
121
+
122
+ if (isOptional) {
123
+ schema = schema.optional()
124
+ } else {
125
+ schema = schema.required()
126
+ }
127
+
128
+ return schema
129
+ }
130
+
131
+ export function getGeospatialSchema(
132
+ def: GeospatialFieldComponent
133
+ ): JoiBase.ArraySchema<Feature[]> {
134
+ const { options = {} } = def
135
+ const country: GeospatialFieldOptionsCountry | undefined =
136
+ options.countries?.at(0)
103
137
 
104
- export function getGeospatialSchema(country?: GeospatialFieldOptionsCountry) {
105
138
  if (!country) {
106
- return geospatialSchema
139
+ return applySchemaConstraints(
140
+ Joi.array<Feature[]>().items(featureSchema).unique('id'),
141
+ def
142
+ )
107
143
  }
108
144
 
109
145
  const validateCountryBounds: CustomValidator = (value, helpers) => {
@@ -128,10 +164,12 @@ export function getGeospatialSchema(country?: GeospatialFieldOptionsCountry) {
128
164
  return value
129
165
  }
130
166
 
131
- return Joi.array<Feature[]>()
132
- .items(featureSchema.custom(validateCountryBounds))
133
- .unique('id')
134
- .required()
167
+ return applySchemaConstraints(
168
+ Joi.array<Feature[]>()
169
+ .items(featureSchema.custom(validateCountryBounds))
170
+ .unique('id'),
171
+ def
172
+ )
135
173
  }
136
174
 
137
175
  /**
@@ -64,7 +64,10 @@ export const messageTemplate: Record<string, JoiExpression> = {
64
64
  dateMax: '{{#title}} must be the same as or before {{#limit}}',
65
65
  arrayMin: 'Select at least {{#limit}} options from the list',
66
66
  arrayMax: 'Only {{#limit}} can be selected from the list',
67
- arrayLength: 'Select only {{#limit}} options from the list'
67
+ arrayLength: 'Select only {{#limit}} options from the list',
68
+ featuresMin: 'Define at least {{#limit}} features',
69
+ featuresMax: 'Only {{#limit}} features can be defined',
70
+ featuresLength: 'Define exactly {{#limit}} features'
68
71
  }
69
72
 
70
73
  export const messages: LanguageMessagesExt = {
@@ -1,7 +1,7 @@
1
1
  {% from "govuk/components/textarea/macro.njk" import govukTextarea %}
2
2
 
3
3
  {% macro GeospatialField(component) %}
4
- <div class="app-geospatial-field" data-country="{{component.model.country}}">
4
+ <div class="app-geospatial-field" data-country="{{component.model.country}}" data-geometryTypes="{{component.model.geometryTypes}}">
5
5
  {{ govukTextarea(component.model) }}
6
6
  </div>
7
7
  {% endmacro %}