@ukhomeoffice/cop-react-form-renderer 6.15.8-alpha → 6.15.9-alpha

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 (26) hide show
  1. package/dist/components/CollectionSummary/BannerStrip.scss +4 -0
  2. package/dist/components/FormPage/FormPage.js +8 -10
  3. package/dist/components/FormRenderer/FormRenderer.js +5 -10
  4. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-page-same-component-reused-one-shown.json +74 -0
  5. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-page-same-component-reused-one-shown.json +8 -0
  6. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-page-same-component-reused-one-shown-removed.json +7 -0
  7. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutes.js +239 -174
  8. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutes.test.js +11 -7
  9. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutesUtils.js +126 -35
  10. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutesUtils.test.js +64 -7
  11. package/dist/components/FormRenderer/onCYAAction.js +0 -2
  12. package/dist/components/FormRenderer/onCYAAction.test.js +5 -0
  13. package/dist/components/FormRenderer/onPageAction.js +0 -1
  14. package/dist/hooks/useGetRequest.js +15 -15
  15. package/dist/hooks/useRefData.js +3 -2
  16. package/dist/utils/Component/getDefaultValueFromConfig.js +2 -1
  17. package/dist/utils/Condition/meetsCondition.js +26 -12
  18. package/dist/utils/Condition/meetsCondition.test.js +21 -0
  19. package/dist/utils/Data/getAutocompleteSource.js +68 -51
  20. package/dist/utils/Data/getAutocompleteSource.test.js +31 -18
  21. package/dist/utils/Operate/doesContainValue.js +34 -0
  22. package/dist/utils/Operate/doesContainValue.test.js +75 -0
  23. package/dist/utils/Operate/runPageOperations.js +2 -0
  24. package/dist/utils/Validate/validateOnPageLoad.js +23 -0
  25. package/dist/utils/Validate/validateOnPageLoad.test.js +88 -0
  26. package/package.json +2 -2
@@ -3,28 +3,43 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.removeObjectWithSingleIdFieldInPlace = exports.removeEmptyArraysAndUnusedCollectionIDs = exports.isShowEntity = exports.getNestedQuestionPath = exports.getImmediateParent = exports.getDependencyObjectFromPath = exports.getDependencies = exports.findComponentDefinitionInForm = exports.deleteNodeByPath = exports.deleteCorrespondingMetaInfo = void 0;
6
+ exports.toArray = exports.removeObjectWithOnlySingleIdField = exports.removeEmptyArraysAndUnusedCollectionIDs = exports.pruneCollectionEntry = exports.isShowEntity = exports.getNestedQuestionPath = exports.getImmediateParent = exports.getDependencyObjectFromPath = exports.getDependencies = exports.findComponentDefinitionInForm = exports.deleteNodeByPath = exports.deleteNodeAndOptions = exports.deleteCorrespondingMetaInfo = exports.deleteComponentData = exports.addValue = void 0;
7
7
  var _Condition = _interopRequireDefault(require("../../../utils/Condition"));
8
8
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
+ /* eslint-disable no-param-reassign */
10
+
9
11
  /**
10
- * Given a path, remove a node from this path within an object.
12
+ * Add a value to a map of arrays. If the key exists, append the value to the array.
13
+ * If not, create the map entry with that key.
11
14
  *
15
+ * @param {*} key
16
+ * @param {*} value
17
+ * @param {*} multiMap
18
+ */
19
+ const addValue = (key, value, multiMap) => {
20
+ if (!multiMap.has(key)) {
21
+ multiMap.set(key, []);
22
+ }
23
+ multiMap.get(key).push(value);
24
+ };
25
+
26
+ /**
27
+ * Given a path, remove a node from this path within an object.
12
28
  *
13
- * @param {Object} obj Javascript object from which the node will be deleted. Updated by the method.
29
+ * @param {Object} payload Javascript object from which the node will be deleted. Updated by the method.
14
30
  * @param {String} path A string containing a decimal point delimited path specifying the node to delete.
15
31
  * @return Nothing, obj above updated.
16
32
  */
17
-
18
- /* eslint-disable consistent-return, no-param-reassign */
19
- const deleteNodeByPath = (obj, path) => {
20
- if (Array.isArray(obj)) {
21
- // If obj is an array, recursively call deleteNodeByPath on each element
22
- for (let i = 0; i < obj.length; i += 1) {
23
- deleteNodeByPath(obj[i], path);
33
+ exports.addValue = addValue;
34
+ const deleteNodeByPath = (payload, path) => {
35
+ if (Array.isArray(payload)) {
36
+ // If payload is an array, recursively call deleteNodeByPath on each element
37
+ for (let i = 0; i < payload.length; i += 1) {
38
+ deleteNodeByPath(payload[i], path);
24
39
  }
25
40
  }
26
41
  const keys = path.split('.');
27
- let current = obj;
42
+ let current = payload;
28
43
  for (let i = 0; i < keys.length - 1; i += 1) {
29
44
  current = current[keys[i]];
30
45
  if (current === undefined) {
@@ -32,27 +47,8 @@ const deleteNodeByPath = (obj, path) => {
32
47
  }
33
48
  }
34
49
  if (current[keys[keys.length - 1]]) {
35
- console.log("Deleting element : ".concat(keys[keys.length - 1]));
36
50
  delete current[keys[keys.length - 1]];
37
51
  }
38
- return obj;
39
- };
40
-
41
- /**
42
- * Pruning a collection payload may have resulted in objects that are only left with their 'id' field, which isn't data
43
- * but added by the renderer to find the activeId. If so, remove these objects entirely as they have been pruned.
44
- *
45
- * @param {Array} array Array of objects. Each object which has only 1 remaining field called 'id' should be removed.
46
- * @return Nothing, array above updated.
47
- */
48
- exports.deleteNodeByPath = deleteNodeByPath;
49
- const removeObjectWithSingleIdFieldInPlace = array => {
50
- for (let i = array.length - 1; i >= 0; i -= 1) {
51
- const obj = array[i];
52
- if (Object.keys(obj).length === 1 && Object.keys(obj)[0] === 'id') {
53
- array.splice(i, 1);
54
- }
55
- }
56
52
  };
57
53
 
58
54
  /**
@@ -63,7 +59,7 @@ const removeObjectWithSingleIdFieldInPlace = array => {
63
59
  * @param {String} path Decimal point delimited path.
64
60
  * @returns {String} Immediate parent of the path passed in.
65
61
  */
66
- exports.removeObjectWithSingleIdFieldInPlace = removeObjectWithSingleIdFieldInPlace;
62
+ exports.deleteNodeByPath = deleteNodeByPath;
67
63
  const getImmediateParent = path => {
68
64
  if (typeof path !== 'string' || !path.includes('.')) {
69
65
  return null;
@@ -89,6 +85,48 @@ const getNestedQuestionPath = (optionPath, nestedFieldId) => {
89
85
  return parentPath ? "".concat(parentPath, ".").concat(nestedFieldId) : nestedFieldId;
90
86
  };
91
87
 
88
+ /**
89
+ * If the component has options, go through each option removing the data for any nested fields.
90
+ * Required as nested options are in the payload at the same heirarchical level.
91
+
92
+ * @param {Object} payload Javascript object from which the node will be deleted. Updated by the method.
93
+ * @param {String} path A string containing a decimal point delimited path specifying the node to delete.
94
+ * @param {Object} component The form component representing the path being deleted
95
+ * @return Nothing, obj above updated.
96
+ */
97
+ exports.getNestedQuestionPath = getNestedQuestionPath;
98
+ const deleteNodeAndOptions = (payload, path, component) => {
99
+ var _component$data;
100
+ deleteNodeByPath(payload, path);
101
+ // If the component has options, go through each option removing the data for any nested fields. Required as nested options are in the payload at the same heirarchical level.
102
+ if (component !== null && component !== void 0 && (_component$data = component.data) !== null && _component$data !== void 0 && _component$data.options) {
103
+ var _component$data2;
104
+ component === null || component === void 0 || (_component$data2 = component.data) === null || _component$data2 === void 0 || (_component$data2 = _component$data2.options) === null || _component$data2 === void 0 || _component$data2.forEach(option => {
105
+ var _option$nested;
106
+ (_option$nested = option.nested) === null || _option$nested === void 0 || _option$nested.forEach(nested => {
107
+ deleteNodeByPath(payload, getNestedQuestionPath(path, nested.fieldId));
108
+ });
109
+ });
110
+ }
111
+ };
112
+
113
+ /**
114
+ * Pruning a collection payload may have resulted in objects that are only left with their 'id' field, which isn't data
115
+ * but added by the renderer to find the activeId. If so, remove these objects entirely as they have been pruned.
116
+ *
117
+ * @param {Array} array Array of objects. Each object which has only 1 remaining field called 'id' should be removed.
118
+ * @return Nothing, array above updated.
119
+ */
120
+ exports.deleteNodeAndOptions = deleteNodeAndOptions;
121
+ const removeObjectWithOnlySingleIdField = array => {
122
+ for (let i = array.length - 1; i >= 0; i -= 1) {
123
+ const obj = array[i];
124
+ if (Object.keys(obj).length === 1 && Object.keys(obj)[0] === 'id') {
125
+ array.splice(i, 1);
126
+ }
127
+ }
128
+ };
129
+
92
130
  /**
93
131
  * Helper method to establish all the payload paths (dependencies) that an entity (page or component) is
94
132
  * dependent on through its show_when rule.
@@ -102,7 +140,7 @@ const getNestedQuestionPath = (optionPath, nestedFieldId) => {
102
140
  * @param {Object} entity Entity whose show_when rule is to be searched for 'field' data items within.
103
141
  * @returns {Set} Set of payload paths that the entity (page or component) is dependent on.
104
142
  */
105
- exports.getNestedQuestionPath = getNestedQuestionPath;
143
+ exports.removeObjectWithOnlySingleIdField = removeObjectWithOnlySingleIdField;
106
144
  const getDependencies = entity => {
107
145
  const findShowWhenFields = (showWhenObject, showWhenFields) => {
108
146
  if (typeof showWhenObject === 'object' && showWhenObject !== null) {
@@ -236,6 +274,7 @@ const deleteCorrespondingMetaInfo = (component, collectionDataObject, formData)
236
274
  }
237
275
  }
238
276
  };
277
+
239
278
  /**
240
279
  * After the payload has been cleansed of individual data items, empty arrays and objects may remain.
241
280
  * Removing an array (when the payload for a collection) may leave a redundant activeId field. The active Id
@@ -252,6 +291,7 @@ const deleteCorrespondingMetaInfo = (component, collectionDataObject, formData)
252
291
  * 3. The function operates recursively to handle deeply nested structures.
253
292
  *
254
293
  * @param {any} payload - The input data structure, which can be an array or an object.
294
+ *
255
295
  */
256
296
  exports.deleteCorrespondingMetaInfo = deleteCorrespondingMetaInfo;
257
297
  const removeEmptyArraysAndUnusedCollectionIDs = payload => {
@@ -274,12 +314,10 @@ const removeEmptyArraysAndUnusedCollectionIDs = payload => {
274
314
  // If the array being removed has an activeId associated with it, remove it
275
315
  if (payload["".concat(key, "ActiveId")]) {
276
316
  delete payload["".concat(key, "ActiveId")];
277
- console.log("Deleted element : ".concat(key, "ActiveId}"));
278
317
  }
279
318
  delete payload["".concat(key, "ActiveId")];
280
319
  if (payload[key]) {
281
320
  delete payload[key];
282
- console.log("Deleted element : ".concat(key));
283
321
  }
284
322
  } else {
285
323
  removeEmptyArraysAndUnusedCollectionIDs(payload[key]); // Recurse for nested structures
@@ -287,4 +325,57 @@ const removeEmptyArraysAndUnusedCollectionIDs = payload => {
287
325
  });
288
326
  }
289
327
  };
290
- exports.removeEmptyArraysAndUnusedCollectionIDs = removeEmptyArraysAndUnusedCollectionIDs;
328
+
329
+ /**
330
+ * Delete a component's payload item from the overall payload.
331
+ * A component can be defined in >1 places in the form spec. To cater for this,
332
+ * if the componentsToKeep counter tells us that there is > 1 uses of this component
333
+ * still unaccounted for in the form then don't delete, but reduce the count by 1.
334
+ *
335
+ * When the counter reaches 1 we know all other occurences of the component have been resolved
336
+ * so it is safe to delete.
337
+ *
338
+ * @param {*} payload The form payload from which to delete the component data
339
+ * @param {*} path The payload path of the component
340
+ * @param {*} component The component whose data we should attempt to delete
341
+ * @param {*} componentsToKeep A list of all components with a count of their number of uses in the form
342
+ */
343
+ exports.removeEmptyArraysAndUnusedCollectionIDs = removeEmptyArraysAndUnusedCollectionIDs;
344
+ const deleteComponentData = (payload, path, component, componentsToKeep) => {
345
+ if (componentsToKeep[path] > 1) {
346
+ componentsToKeep[path] -= 1;
347
+ } else {
348
+ deleteNodeAndOptions(payload, path, component);
349
+ }
350
+ };
351
+
352
+ /**
353
+ *
354
+ * Takes a single page collection payload object and removes the payload items specified in the componentsToPrune list
355
+ * as long as they don't appear in the componentsToKeep list.
356
+ * Additionally, if the component type is multifile, remove the corresponding data entries that will have been created
357
+ * in the meta section of the payload by the form renderer.
358
+ *
359
+ * @param {Set} pathsToKeep paths that we cannot delete from the collectionDataObject
360
+ * @param {Map} componentsToPrune paths that we should delete, as long as they are not in the pathsToKeep
361
+ * @param {Object} collectionDataObject the payload from which to delete the paths
362
+ * @param {Object} formData The form data, whose meta section may include corresponding documents entries for multifile entries
363
+ */
364
+ exports.deleteComponentData = deleteComponentData;
365
+ const pruneCollectionEntry = (pathsToKeep, componentsToPrune, collectionDataObject, formData) => {
366
+ componentsToPrune.forEach(component => {
367
+ if (!pathsToKeep.has(component.fieldId)) {
368
+ if (component.type === "multifile") {
369
+ deleteCorrespondingMetaInfo(component, collectionDataObject, formData);
370
+ }
371
+ deleteNodeAndOptions(collectionDataObject, component.fieldId, component);
372
+ }
373
+ });
374
+ };
375
+
376
+ /*
377
+ * Converts an object to an array if it isn't already, for use when combining show when rules.
378
+ */
379
+ exports.pruneCollectionEntry = pruneCollectionEntry;
380
+ const toArray = value => Array.isArray(value) ? value : [value];
381
+ exports.toArray = toArray;
@@ -19,8 +19,8 @@ describe('deleteNodeByPath', () => {
19
19
  epsilon: "epsilon"
20
20
  };
21
21
  const path = 'type';
22
- const result = Utils.deleteNodeByPath(nested, path);
23
- expect(result).toEqual({
22
+ Utils.deleteNodeByPath(nested, path);
23
+ expect(nested).toEqual({
24
24
  alpha: "alpha",
25
25
  bravo: "bravo",
26
26
  person: {
@@ -44,8 +44,8 @@ describe('deleteNodeByPath', () => {
44
44
  epsilon: "epsilon"
45
45
  };
46
46
  const path = 'person.charlie';
47
- const result = Utils.deleteNodeByPath(nested, path);
48
- expect(result).toEqual({
47
+ Utils.deleteNodeByPath(nested, path);
48
+ expect(nested).toEqual({
49
49
  type: "Example form",
50
50
  alpha: "alpha",
51
51
  bravo: "bravo",
@@ -57,7 +57,7 @@ describe('deleteNodeByPath', () => {
57
57
  });
58
58
  });
59
59
  });
60
- describe('removeObjectWithSingleIdFieldInPlace', () => {
60
+ describe('removeObjectWithOnlySingleIdField', () => {
61
61
  it('removes objects with only the "id" field', () => {
62
62
  const inputArray = [{
63
63
  id: 1
@@ -73,7 +73,7 @@ describe('removeObjectWithSingleIdFieldInPlace', () => {
73
73
  id: 4,
74
74
  name: 'John'
75
75
  }];
76
- Utils.removeObjectWithSingleIdFieldInPlace(inputArray);
76
+ Utils.removeObjectWithOnlySingleIdField(inputArray);
77
77
  expect(inputArray).toEqual([{
78
78
  name: 'John'
79
79
  }, {
@@ -90,7 +90,7 @@ describe('removeObjectWithSingleIdFieldInPlace', () => {
90
90
  age: 30
91
91
  }];
92
92
  const originalArray = [].concat(inputArray);
93
- Utils.removeObjectWithSingleIdFieldInPlace(inputArray);
93
+ Utils.removeObjectWithOnlySingleIdField(inputArray);
94
94
  expect(inputArray).toEqual(originalArray);
95
95
  });
96
96
  });
@@ -499,4 +499,61 @@ describe("removeEmptyArraysAndUnusedCollectionIDs", () => {
499
499
  nested: {}
500
500
  }]);
501
501
  });
502
+ });
503
+ describe("pruneCollectionEntry", () => {
504
+ let pathsToKeep;
505
+ let componentsToPrune;
506
+ let collectionDataObject;
507
+ let formData;
508
+ let expectedFormData;
509
+ beforeEach(() => {
510
+ pathsToKeep = new Set(['keepThis']);
511
+ componentsToPrune = [{
512
+ fieldId: 'removeThis',
513
+ type: 'text'
514
+ }, {
515
+ fieldId: 'keepThis',
516
+ type: 'text'
517
+ }, {
518
+ fieldId: 'removeMultifile',
519
+ type: 'multifile'
520
+ }];
521
+ collectionDataObject = {
522
+ 'removeThis': 'value',
523
+ 'keepThis': 'value',
524
+ 'removeMultifile': {
525
+ 'url': 'https://example.com/file1.pdf'
526
+ }
527
+ };
528
+ formData = {
529
+ meta: {
530
+ documents: [{
531
+ url: 'https://example.com/file1.pdf'
532
+ }, {
533
+ url: 'https://example.com/file2.pdf'
534
+ }, {
535
+ url: 'https://example.com/file3.pdf'
536
+ }]
537
+ }
538
+ };
539
+ expectedFormData = {
540
+ meta: {
541
+ documents: [{
542
+ url: 'https://example.com/file2.pdf'
543
+ }, {
544
+ url: 'https://example.com/file3.pdf'
545
+ }]
546
+ }
547
+ };
548
+ });
549
+ it('should remove components not in pathsToKeep', () => {
550
+ Utils.pruneCollectionEntry(pathsToKeep, componentsToPrune, collectionDataObject, formData);
551
+ expect(collectionDataObject).toEqual({
552
+ 'keepThis': 'value'
553
+ });
554
+ });
555
+ it('should delete meta.documents for multifile components', () => {
556
+ Utils.pruneCollectionEntry(pathsToKeep, componentsToPrune, collectionDataObject, formData);
557
+ expect(formData).toEqual(expectedFormData);
558
+ });
502
559
  });
@@ -36,7 +36,6 @@ const onCYAAction = (setPagePoint, action, pages, validate, components, data, se
36
36
  pages,
37
37
  components
38
38
  };
39
- console.log("Invoking clearOutUncompletedRoutes");
40
39
  _helpers.default.clearOutUncompletedRoutes(formPagesAndComponents, submissionData);
41
40
  submissionData.formStatus = _helpers.default.getSubmissionStatus(type, pages, pageId, action, submissionData, currentTask, true);
42
41
  setData(submissionData);
@@ -81,7 +80,6 @@ const onCYAAction = (setPagePoint, action, pages, validate, components, data, se
81
80
  pages,
82
81
  components
83
82
  };
84
- console.log("Invoking clearOutUncompletedRoutes");
85
83
  _helpers.default.clearOutUncompletedRoutes(formPagesAndComponents, submissionData);
86
84
  submissionData.formStatus = _helpers.default.getSubmissionStatus(type, pages, pageId, action, submissionData, currentTask, true);
87
85
  setData(submissionData);
@@ -55,6 +55,11 @@ jest.mock('./helpers', () => ({
55
55
  this.getNextPageIdCalls = 0;
56
56
  this.getFormStateCalls = 0;
57
57
  this.getSubmissionStatusCalls = 0;
58
+ },
59
+ clearOutUncompletedRoutesCalls: 0,
60
+ clearOutUncompletedRoutes(formPagesAndComponents, formData) {
61
+ this.clearOutUncompletedRoutesCalls += 1;
62
+ return formData;
58
63
  }
59
64
  }));
60
65
  jest.mock('../../utils', () => ({
@@ -112,7 +112,6 @@ const onPageAction = (action, patch, patchLabel, hooks, data, formState, validat
112
112
  components
113
113
  };
114
114
  if (action.type === _models.PageAction.TYPES.SUBMIT) {
115
- console.log("Invoking clearOutUncompletedRoutes");
116
115
  _helpers.default.clearOutUncompletedRoutes(formPagesAndComponents, submissionData);
117
116
  }
118
117
 
@@ -8,10 +8,6 @@ var _axios = _interopRequireDefault(require("axios"));
8
8
  var _react = require("react");
9
9
  var _useAxios = _interopRequireDefault(require("./useAxios"));
10
10
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
- // Global imports
12
-
13
- // Local imports
14
-
15
11
  // Caches for responses and errors.
16
12
  const cache = {};
17
13
  const errorCache = {};
@@ -31,15 +27,18 @@ const STATUS_IDLE = exports.STATUS_IDLE = 'idle';
31
27
  const STATUS_FETCHING = exports.STATUS_FETCHING = 'fetching';
32
28
  const STATUS_FETCHED = exports.STATUS_FETCHED = 'fetched';
33
29
  const STATUS_ERROR = exports.STATUS_ERROR = 'error';
34
- const useGetRequest = url => {
30
+ const useGetRequest = function (url) {
31
+ let caching = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
35
32
  const axiosInstance = (0, _useAxios.default)();
36
- const cancelToken = _axios.default.CancelToken.source();
37
- const cancelRequests = () => {
38
- if (cancelToken) cancelToken.cancel();
39
- };
33
+ const cancelTokenRef = (0, _react.useRef)(_axios.default.CancelToken.source());
40
34
  const [status, setStatus] = (0, _react.useState)(STATUS_IDLE);
41
35
  const [error, setError] = (0, _react.useState)(null);
42
36
  const [data, setData] = (0, _react.useState)(null);
37
+ const cancelRequests = () => {
38
+ if (cancelTokenRef.current) {
39
+ cancelTokenRef.current.cancel();
40
+ }
41
+ };
43
42
  (0, _react.useEffect)(() => {
44
43
  if (!url || !axiosInstance) return;
45
44
  const fetchData = async () => {
@@ -47,9 +46,9 @@ const useGetRequest = url => {
47
46
  setError(null);
48
47
  setStatus(STATUS_FETCHING);
49
48
  let fetchedData;
50
- if (cache[url]) {
49
+ if (caching && cache[url]) {
51
50
  fetchedData = cache[url];
52
- } else if (errorCache[url]) {
51
+ } else if (caching && errorCache[url]) {
53
52
  /**
54
53
  * This logic is intended to stop multiple requests being made in succession
55
54
  * that all fail. Presently, this will only allow the first request to be
@@ -60,24 +59,25 @@ const useGetRequest = url => {
60
59
  throw errorCache[url];
61
60
  } else {
62
61
  const response = await axiosInstance.get(url, {
63
- cancelToken: cancelToken.token
62
+ cancelToken: cancelTokenRef.current.token
64
63
  }).catch(e => {
64
+ setError(e);
65
65
  throw e;
66
66
  });
67
67
  fetchedData = response.data;
68
- cache[url] = fetchedData;
68
+ if (caching) cache[url] = fetchedData;
69
69
  }
70
70
  setData(fetchedData);
71
71
  setStatus(STATUS_FETCHED);
72
72
  } catch (e) {
73
- errorCache[url] = e;
73
+ if (caching) errorCache[url] = e;
74
74
  setError(e);
75
75
  setData(null);
76
76
  setStatus(STATUS_ERROR);
77
77
  }
78
78
  };
79
79
  fetchData();
80
- }, [axiosInstance, url, cancelToken.token]);
80
+ }, [axiosInstance, url, caching]);
81
81
  return {
82
82
  status,
83
83
  error,
@@ -28,13 +28,14 @@ const getRefDataUrl = component => {
28
28
  return undefined;
29
29
  };
30
30
  const useRefData = (component, formData) => {
31
+ var _component$data;
31
32
  const url = getRefDataUrl(_objectSpread(_objectSpread({}, component), {}, {
32
33
  formData
33
34
  }));
34
35
  const {
35
36
  status: _status,
36
37
  data: _data
37
- } = (0, _useGetRequest.default)(url);
38
+ } = (0, _useGetRequest.default)(url, component === null || component === void 0 || (_component$data = component.data) === null || _component$data === void 0 ? void 0 : _component$data.useCache);
38
39
  const [data, setData] = (0, _react.useState)([]);
39
40
  const [status, setStatus] = (0, _react.useState)(STATUS_LOADING);
40
41
  (0, _react.useEffect)(() => {
@@ -52,7 +53,7 @@ const useRefData = (component, formData) => {
52
53
  setData([]);
53
54
  setStatus(STATUS_COMPLETE);
54
55
  }
55
- }, [component, _status, _data, url, setData, setStatus]);
56
+ }, [component.id, _status, _data, url]);
56
57
  return {
57
58
  data,
58
59
  status
@@ -75,7 +75,8 @@ const setupDefaultObjectValue = (defaultObject, data) => {
75
75
  // defaultObject.sourced is an object with values that should
76
76
  // be used as field names to get values from data.
77
77
  if (defaultObj.sourced) {
78
- result = result !== null && result !== void 0 ? result : {};
78
+ var _result;
79
+ result = (_result = result) !== null && _result !== void 0 ? _result : {};
79
80
  Object.keys(defaultObj.sourced).every(key => {
80
81
  const sourcedValue = typeof defaultObj.sourced[key] === 'string' && (0, _getSourceData.default)(data, defaultObj.sourced[key]);
81
82
  if (sourcedValue === undefined && defaultObj.skipIfSourceInvalid) {
@@ -20,6 +20,26 @@ const getComparisonValue = (condition, data) => {
20
20
  return condition.value;
21
21
  };
22
22
 
23
+ /**
24
+ * Processes a value based on its type.
25
+ * - If it's an array, returns its length.
26
+ * - If it's a string, parses it as a float.
27
+ * - If it's a number, returns it as is.
28
+ * - Returns `undefined` for other types.
29
+ *
30
+ * @param {any} value - The value to process.
31
+ * @returns {number | undefined} - The processed value or `undefined` if not applicable.
32
+ */
33
+ const getProcessedValue = obj => {
34
+ if (Array.isArray(obj)) return obj.length;
35
+ if (typeof obj === "string") {
36
+ const cleaned = obj.replace(/,/g, ''); // Remove all commas
37
+ return Number.isNaN(cleaned) ? null : parseFloat(cleaned);
38
+ }
39
+ if (typeof obj === "number") return obj;
40
+ return null;
41
+ };
42
+
23
43
  /**
24
44
  * Looks at a condition object to see if the supplied value meets it.
25
45
  * The condition object contains an `op` property, along with a comparator
@@ -66,21 +86,15 @@ const meetsCondition = (condition, value, data) => {
66
86
  }
67
87
  case '<':
68
88
  {
69
- if (!value || !compare) {
70
- return false;
71
- }
72
- const valFloat = parseFloat(value.replace(',', ''));
73
- const compareFloat = parseFloat(compare.replace(',', ''));
74
- return valFloat < compareFloat;
89
+ const valFloat = getProcessedValue(value);
90
+ const compareFloat = getProcessedValue(compare);
91
+ return valFloat != null && compareFloat != null && valFloat < compareFloat;
75
92
  }
76
93
  case '>':
77
94
  {
78
- if (!value || !compare) {
79
- return false;
80
- }
81
- const valFloat = parseFloat(value.replace(/,/g, ''));
82
- const compareFloat = parseFloat(compare.replace(/,/g, ''));
83
- return valFloat > compareFloat;
95
+ const valFloat = getProcessedValue(value);
96
+ const compareFloat = getProcessedValue(compare);
97
+ return valFloat != null && compareFloat != null && valFloat > compareFloat;
84
98
  }
85
99
  case 'contains':
86
100
  {
@@ -551,6 +551,27 @@ describe('utils.Condition.meetsCondition', () => {
551
551
  };
552
552
  expect((0, _meetsCondition.default)(CONDITION, '10,000,000')).toBeTruthy();
553
553
  });
554
+ it('greater than should handle value is 0', () => {
555
+ const CONDITION = {
556
+ op: '>',
557
+ value: 0
558
+ };
559
+ expect((0, _meetsCondition.default)(CONDITION, 1)).toBeTruthy();
560
+ });
561
+ it('greater than should handle compear is 0', () => {
562
+ const CONDITION = {
563
+ op: '<',
564
+ value: 1
565
+ };
566
+ expect((0, _meetsCondition.default)(CONDITION, 0)).toBeTruthy();
567
+ });
568
+ it('greater than should handle array is 0', () => {
569
+ const CONDITION = {
570
+ op: '>',
571
+ value: 1
572
+ };
573
+ expect((0, _meetsCondition.default)(CONDITION, ["A", "B", "C"])).toBeTruthy();
574
+ });
554
575
  });
555
576
  describe('operator includes', () => {
556
577
  it('should accept a string that exists within the value', () => {