@ukhomeoffice/cop-react-form-renderer 5.34.1 → 5.37.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.
@@ -66,7 +66,8 @@ var CollectionSummary = function CollectionSummary(_ref) {
66
66
  });
67
67
  };
68
68
  var onDuplicate = function onDuplicate(entry) {
69
- _utils.default.CollectionPage.duplicateEntry(config.collectionName, formData, entry.id);
69
+ var _config$card;
70
+ _utils.default.CollectionPage.duplicateEntry(config.collectionName, formData, entry.id, ((_config$card = config.card) === null || _config$card === void 0 || (_config$card = _config$card.duplicateAction) === null || _config$card === void 0 ? void 0 : _config$card.fieldsToIgnore) || []);
70
71
  var parentCollection = config.collectionName.split('.').shift();
71
72
  // Report the whole top-level collection as being changed. We have to do this
72
73
  // because of how patch is applied to formData on a page submission.
@@ -162,7 +163,10 @@ CollectionSummary.propTypes = {
162
163
  card: _propTypes.default.shape({
163
164
  banners: _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.shape({})])),
164
165
  title: _propTypes.default.string,
165
- details: _propTypes.default.string
166
+ details: _propTypes.default.string,
167
+ duplicateAction: _propTypes.default.shape({
168
+ fieldsToIgnore: _propTypes.default.arrayOf(_propTypes.default.string)
169
+ })
166
170
  }),
167
171
  confirmation: _propTypes.default.shape({
168
172
  message: _propTypes.default.string,
@@ -179,6 +179,7 @@ var getCYARowsForCollectionPage = function getCYARowsForCollectionPage(page, onA
179
179
  var activeIds = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
180
180
  var collectionName = page.collection.name.split('.').pop();
181
181
  var collectionData = data[collectionName] || null;
182
+ var activeId = data["".concat(collectionName, "ActiveId")];
182
183
  if (!collectionData || collectionData.length === 0) {
183
184
  return [];
184
185
  }
@@ -186,16 +187,24 @@ var getCYARowsForCollectionPage = function getCYARowsForCollectionPage(page, onA
186
187
  if (!page.collection.hideNameFromCYA) {
187
188
  rows.push(getCollectionNameHeading(page, collectionName));
188
189
  }
189
- collectionData.forEach(function (item, index) {
190
+ var itemIndex = 0;
191
+ if (page.collection.onlyShowActiveEntryOnCYA) {
192
+ var activeEntry = collectionData.find(function (entry, index) {
193
+ itemIndex = index;
194
+ return entry.id === activeId;
195
+ });
196
+ collectionData = [activeEntry];
197
+ }
198
+ collectionData.forEach(function (item) {
190
199
  var _page$collection2;
191
200
  // Keep track of the active entry in each collection.
192
201
  // This helps us make sure the right entry is being affected
193
202
  // by change/remove links.
194
203
  // eslint-disable-next-line no-param-reassign
195
204
  activeIds = _objectSpread(_objectSpread({}, activeIds), {}, _defineProperty({}, "".concat(collectionName, "ActiveId"), item.id));
196
- var labelCount = index + 1;
205
+ var labelCount = itemIndex + 1;
197
206
  var actionPosition = ((_page$collection2 = page.collection) === null || _page$collection2 === void 0 ? void 0 : _page$collection2.actionPosition) || 'top';
198
- var fullPath = "".concat(page.collection.name, "[").concat(index, "]");
207
+ var fullPath = "".concat(page.collection.name, "[").concat(itemIndex, "]");
199
208
  var titleRow = getTitleRowForItem(page, item, page.id, labelCount, fullPath);
200
209
  var actionRows = getActionRows(page, item, onAction, labelCount, activeIds);
201
210
  rows = rows.concat(titleRow);
@@ -206,6 +215,7 @@ var getCYARowsForCollectionPage = function getCYARowsForCollectionPage(page, onA
206
215
  if (actionPosition === 'bottom') {
207
216
  rows = rows.concat(actionRows);
208
217
  }
218
+ itemIndex += 1;
209
219
  });
210
220
  return rows.filter(function (row) {
211
221
  return !!row;
@@ -170,6 +170,45 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
170
170
  key: 'Test date'
171
171
  });
172
172
  });
173
+ it('should return correctly formatted rows for only the active entry when page.collection.onlyShowActiveEntryOnCYA is defined', function () {
174
+ var FORM_DATA = {
175
+ collectionActiveId: '02',
176
+ collection: [{
177
+ id: '01',
178
+ testText: 'value'
179
+ }, {
180
+ id: '02',
181
+ testText: 'value'
182
+ }]
183
+ };
184
+ var PAGE = _objectSpread(_objectSpread({}, MASTER_PAGE), {}, {
185
+ collection: _objectSpread(_objectSpread({}, MASTER_PAGE.collection), {}, {
186
+ onlyShowActiveEntryOnCYA: true
187
+ }),
188
+ formData: FORM_DATA
189
+ });
190
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FORM_DATA);
191
+ expect(ROWS.length).toEqual(7); // Title row + component row for only the active item.
192
+ expect(ROWS[0]).toMatchObject({
193
+ type: 'heading',
194
+ key: 'Collection'
195
+ });
196
+ expect(ROWS[1]).toMatchObject({
197
+ type: 'heading',
198
+ key: 'Collection entry 2'
199
+ });
200
+ expect(ROWS[2].action.label).toEqual('Change');
201
+ expect(ROWS[3].action.label).toEqual('custom remove label');
202
+ expect(ROWS[4].action.label).toEqual('custom change label');
203
+ expect(ROWS[5]).toMatchObject({
204
+ value: 'value',
205
+ key: 'Test text'
206
+ });
207
+ expect(ROWS[6]).toMatchObject({
208
+ value: '',
209
+ key: 'Test date'
210
+ });
211
+ });
173
212
  it('should exclude components that should not be shown', function () {
174
213
  var FD = {
175
214
  collection: [{
@@ -13,6 +13,7 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
13
13
  function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
14
14
  function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
15
15
  var duplicateCollectionPageEntry = function duplicateCollectionPageEntry(collectionName, formData, entryId) {
16
+ var fieldsToIgnore = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
16
17
  var collectionData = (0, _getCollectionPageData.default)(collectionName, formData);
17
18
  var entryToDuplicate = collectionData === null || collectionData === void 0 ? void 0 : collectionData.find(function (entry) {
18
19
  return entry.id === entryId;
@@ -23,6 +24,9 @@ var duplicateCollectionPageEntry = function duplicateCollectionPageEntry(collect
23
24
  var newEntry = _objectSpread(_objectSpread({}, entryToDuplicate), {}, {
24
25
  id: Date.now().toString()
25
26
  });
27
+ fieldsToIgnore.forEach(function (field) {
28
+ return delete newEntry[field];
29
+ });
26
30
  collectionData.push(newEntry);
27
31
  // eslint-disable-next-line no-param-reassign
28
32
  formData["".concat(collectionName.split('.').pop(), "ActiveId")] = newEntry.id;
@@ -53,10 +53,22 @@ describe('utils.CollectionPage.duplicateCollectionPageEntry', function () {
53
53
  expect((0, _getCollectionPageActiveId.default)('parents.children', FORM_DATA)).toBeTruthy();
54
54
  expect((0, _getCollectionPageActiveId.default)('parents.children', FORM_DATA) === '2').toBeFalsy();
55
55
  });
56
- it('should do nothing if an entry with the given id does not exist', function () {
57
- var _FORM_DATA2, _expect$toEqual;
56
+ it('should ignore fields in the fieldToIgnore array', function () {
57
+ var _FORM_DATA2;
58
58
  var FORM_DATA = (_FORM_DATA2 = {}, _defineProperty(_FORM_DATA2, "".concat(COLLECTION_NAME, "ActiveId"), '1'), _defineProperty(_FORM_DATA2, COLLECTION_NAME, [OBJ]), _FORM_DATA2);
59
59
  ;
60
+ var FIELDS_TO_IGNORE = ['value'];
61
+ (0, _duplicateCollectionPageEntry.default)(COLLECTION_NAME, FORM_DATA, '1', FIELDS_TO_IGNORE);
62
+ expect(FORM_DATA[COLLECTION_NAME].length).toEqual(2);
63
+ expect(FORM_DATA[COLLECTION_NAME][0].id).toBeTruthy();
64
+ expect(FORM_DATA[COLLECTION_NAME][0].value).toBeTruthy();
65
+ expect(FORM_DATA[COLLECTION_NAME][1].id).toBeTruthy();
66
+ expect(FORM_DATA[COLLECTION_NAME][1].value).toBeUndefined();
67
+ });
68
+ it('should do nothing if an entry with the given id does not exist', function () {
69
+ var _FORM_DATA3, _expect$toEqual;
70
+ var FORM_DATA = (_FORM_DATA3 = {}, _defineProperty(_FORM_DATA3, "".concat(COLLECTION_NAME, "ActiveId"), '1'), _defineProperty(_FORM_DATA3, COLLECTION_NAME, [OBJ]), _FORM_DATA3);
71
+ ;
60
72
  (0, _duplicateCollectionPageEntry.default)(COLLECTION_NAME, FORM_DATA, '0');
61
73
  expect(FORM_DATA).toEqual((_expect$toEqual = {}, _defineProperty(_expect$toEqual, "".concat(COLLECTION_NAME, "ActiveId"), '1'), _defineProperty(_expect$toEqual, COLLECTION_NAME, [OBJ]), _expect$toEqual));
62
74
  });
@@ -42,8 +42,12 @@ describe('utils.Component.defaultValue', function () {
42
42
  it('should return defaultObjectValue if the component has defaultObjectValue prop', function () {
43
43
  expect((0, _getDefaultValue.default)({
44
44
  type: _models.ComponentTypes.AUTOCOMPLETE,
45
- defaultObjectValue: 'test'
46
- })).toEqual('test');
45
+ defaultObjectValue: {
46
+ testText: 'text'
47
+ }
48
+ })).toEqual({
49
+ testText: 'text'
50
+ });
47
51
  });
48
52
  Object.values(_models.ComponentTypes).forEach(function (value) {
49
53
  if (![_models.ComponentTypes.COLLECTION, _models.ComponentTypes.CONTAINER, _models.ComponentTypes.FILE].includes(value)) {
@@ -8,10 +8,13 @@ var _dayjs = _interopRequireDefault(require("dayjs"));
8
8
  var _getSourceData = _interopRequireDefault(require("../Data/getSourceData"));
9
9
  var _models = require("../../models");
10
10
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
- // Global imports.
12
-
11
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
12
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
13
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
14
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
15
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
16
+ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } // Global imports.
13
17
  // Local imports.
14
-
15
18
  var hasDefaultValue = function hasDefaultValue(component) {
16
19
  return component.defaultValue || component.defaultObjectValue;
17
20
  };
@@ -20,6 +23,75 @@ var getDefaultForDate = function getDefaultForDate(date) {
20
23
  var defaultDate = dateFormat.test(date.defaultValue) ? date.defaultValue : null;
21
24
  return date.defaultValue === 'today' ? (0, _dayjs.default)().format('DD-MM-YYYY') : defaultDate;
22
25
  };
26
+
27
+ /**
28
+ * This function sets up a components defaultObjectValue, handling both a mixture
29
+ * of literal values and values to be sourced from formData.
30
+ *
31
+ * An example defaultObjectValue is:
32
+ * {
33
+ * skipIfSourceInvalid: true,
34
+ * sourced: {
35
+ * fieldOne: 'target1.value',
36
+ * fieldTwo: 'target2.value'
37
+ * },
38
+ * literal: {
39
+ * fieldThree: 'a literal value',
40
+ * fieldFour: 'another literal value'
41
+ * }
42
+ * }
43
+ *
44
+ * Any fields specified in sourced will be searched for in data. If any of the sourced
45
+ * values cannot be found and 'skipIfSourceInvalid' is true, then the entire defaultObject
46
+ * is treated as invalid and the function returns null. If any of the sourced values can't
47
+ * be found and 'skipIfSourceInvalid' is false, then the value of the field in sourced is
48
+ * used literally - e.g. 'target1.value'. This is often not desired, so it is recommended
49
+ * to have 'skipIfSourceInvalid' as true when using sourced values.
50
+ *
51
+ * 'skipIfSourceInvalid' is assumed false unless defined.
52
+ *
53
+ * Literal values are taken as is and copied to the resulting object.
54
+ *
55
+ * A defaultObjectValue can contain both sourced & literal, or either individually.
56
+ *
57
+ * The old syntax for defaultObjectValue is also supported. In that scenario, all fields
58
+ * are treated as sourced fields.
59
+ *
60
+ * @param {object} defaultObject The defaultObjectValue field for a component.
61
+ * @param {object} data The current formData.
62
+ * @returns An object to be used as the component's default value.
63
+ */
64
+ var setupDefaultObjectValue = function setupDefaultObjectValue(defaultObject, data) {
65
+ var defaultObj = _objectSpread({}, defaultObject);
66
+ var result = null;
67
+ // This handles objects using the previous syntax where
68
+ // defaultObject.literal and defaultObject.sourced won't
69
+ // be defined.
70
+ if (!defaultObj.literal && !defaultObj.sourced) {
71
+ defaultObj.sourced = _objectSpread({}, defaultObj);
72
+ }
73
+ // defaultObject.literal is an object with values that should
74
+ // be copied as-is to the result object.
75
+ if (defaultObj.literal) {
76
+ result = _objectSpread({}, defaultObj.literal);
77
+ }
78
+ // defaultObject.sourced is an object with values that should
79
+ // be used as field names to get values from data.
80
+ if (defaultObj.sourced) {
81
+ var _result;
82
+ (_result = result) !== null && _result !== void 0 ? _result : result = {};
83
+ Object.keys(defaultObj.sourced).every(function (key) {
84
+ var sourcedValue = typeof defaultObj.sourced[key] === 'string' && (0, _getSourceData.default)(data, defaultObj.sourced[key]);
85
+ if (sourcedValue === undefined && defaultObj.skipIfSourceInvalid) {
86
+ result = null;
87
+ return false;
88
+ }
89
+ result[key] = sourcedValue || defaultObj.sourced[key];
90
+ return true;
91
+ });
92
+ }
93
+ return result;
94
+ };
23
95
  var getDefaultValueFromConfig = function getDefaultValueFromConfig(component, data) {
24
96
  if (!hasDefaultValue(component)) {
25
97
  return null;
@@ -29,15 +101,8 @@ var getDefaultValueFromConfig = function getDefaultValueFromConfig(component, da
29
101
  return getDefaultForDate(component, data);
30
102
  default:
31
103
  {
32
- if (component.defaultObjectValue) {
33
- Object.keys(component.defaultObjectValue).forEach(function (value) {
34
- if (typeof component.defaultObjectValue[value] === 'string' && (0, _getSourceData.default)(data, component.defaultObjectValue[value]) !== undefined) {
35
- // eslint-disable-next-line no-param-reassign
36
- component.defaultObjectValue[value] = (0, _getSourceData.default)(data, component.defaultObjectValue[value]);
37
- }
38
- });
39
- }
40
- return component.defaultObjectValue ? component.defaultObjectValue : component.defaultValue;
104
+ var defaultValue = component.defaultObjectValue ? setupDefaultObjectValue(component.defaultObjectValue, data) : null;
105
+ return defaultValue || component.defaultValue || null;
41
106
  }
42
107
  }
43
108
  };
@@ -65,6 +65,60 @@ describe('utils.component.defaultValueFromConfig', function () {
65
65
  bravo: 'value'
66
66
  });
67
67
  });
68
+ it('should allow specific sourced and literal object values to be defined', function () {
69
+ var COMPONENT = {
70
+ defaultObjectValue: {
71
+ sourced: {
72
+ value1: 'field1.value',
73
+ value2: 'field2.value'
74
+ },
75
+ literal: {
76
+ value3: 'literal text 1',
77
+ value4: 'literal text 2'
78
+ }
79
+ }
80
+ };
81
+ var DATA = {
82
+ field1: {
83
+ value: 'sourced text 1'
84
+ },
85
+ field2: {
86
+ value: 'sourced text 2'
87
+ }
88
+ };
89
+ var result = (0, _getDefaultValueFromConfig.default)(COMPONENT, DATA);
90
+ expect(result).toMatchObject({
91
+ value1: 'sourced text 1',
92
+ value2: 'sourced text 2',
93
+ value3: 'literal text 1',
94
+ value4: 'literal text 2'
95
+ });
96
+ });
97
+ it('should handle the skipIfSourceInvalid flag and return null if a sourced value cannot be found', function () {
98
+ var COMPONENT = {
99
+ defaultObjectValue: {
100
+ skipIfSourceInvalid: true,
101
+ sourced: {
102
+ value1: 'notafield.value',
103
+ value2: 'field2.value'
104
+ },
105
+ literal: {
106
+ value3: 'literal text 1',
107
+ value4: 'literal text 2'
108
+ }
109
+ }
110
+ };
111
+ var DATA = {
112
+ field1: {
113
+ value: 'sourced text 1'
114
+ },
115
+ field2: {
116
+ value: 'sourced text 2'
117
+ }
118
+ };
119
+ var result = (0, _getDefaultValueFromConfig.default)(COMPONENT, DATA);
120
+ expect(result).toEqual(null);
121
+ });
68
122
  describe('for a date component', function () {
69
123
  it('should return a normal default value', function () {
70
124
  var COMPONENT = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ukhomeoffice/cop-react-form-renderer",
3
- "version": "5.34.1",
3
+ "version": "5.37.0",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "clean": "rimraf dist",