@k-int/stripes-kint-components 5.2.3 → 5.3.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 (98) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/es/index.js +8 -0
  3. package/es/lib/ActionList/ActionListFieldArray.js +61 -43
  4. package/es/lib/ComboButton/ComboButton.js +6 -5
  5. package/es/lib/CustomProperties/Config/CustomPropertiesLookup.js +7 -4
  6. package/es/lib/CustomProperties/Config/CustomPropertiesSettings.js +32 -30
  7. package/es/lib/CustomProperties/Config/CustomPropertyForm.js +58 -58
  8. package/es/lib/CustomProperties/Config/CustomPropertyForm.test.js +2 -2
  9. package/es/lib/CustomProperties/Config/CustomPropertyView.js +33 -32
  10. package/es/lib/CustomProperties/Config/CustomPropertyView.test.js +1 -1
  11. package/es/lib/CustomProperties/Edit/CustomPropertiesEdit.js +1 -1
  12. package/es/lib/CustomProperties/Edit/CustomPropertiesEditCtx.js +3 -3
  13. package/es/lib/CustomProperties/Edit/CustomPropertiesListField.js +10 -5
  14. package/es/lib/CustomProperties/Edit/CustomPropertyField.js +25 -19
  15. package/es/lib/CustomProperties/Edit/CustomPropertyField.test.js +5 -5
  16. package/es/lib/CustomProperties/Edit/CustomPropertyFormCard.js +2 -2
  17. package/es/lib/CustomProperties/Edit/CustomPropertyFormCard.test.js +1 -1
  18. package/es/lib/CustomProperties/Edit/testResources.js +12 -11
  19. package/es/lib/CustomProperties/Filter/CustomPropertiesFilter.js +11 -7
  20. package/es/lib/CustomProperties/Filter/CustomPropertiesFilterField.js +28 -20
  21. package/es/lib/CustomProperties/Filter/CustomPropertiesFilterField.test.js +1 -1
  22. package/es/lib/CustomProperties/Filter/CustomPropertiesFilterFieldArray.js +6 -6
  23. package/es/lib/CustomProperties/Filter/CustomPropertiesRule.js +8 -8
  24. package/es/lib/CustomProperties/Filter/testResources.js +2 -1
  25. package/es/lib/CustomProperties/Filter/useParseActiveFilterStrings.js +2 -1
  26. package/es/lib/CustomProperties/View/CustomPropertiesView.js +1 -1
  27. package/es/lib/CustomProperties/View/CustomPropertiesViewCtx.js +26 -19
  28. package/es/lib/CustomProperties/View/CustomPropertyCard.js +11 -7
  29. package/es/lib/CycleButton/CycleButton.js +1 -1
  30. package/es/lib/EditableRefdataCategoryList/EditableRefdataCategoryList.js +82 -29
  31. package/es/lib/EditableRefdataList/EditableRefdataList.js +33 -27
  32. package/es/lib/EditableSettingsList/EditableSettingsListFieldArray.js +1 -1
  33. package/es/lib/EditableSettingsList/SettingField/EditSettingValue.js +5 -6
  34. package/es/lib/EditableSettingsList/SettingField/RenderSettingValue.js +12 -10
  35. package/es/lib/EditableSettingsList/SettingField/RenderSettingValue.test.js +0 -1
  36. package/es/lib/EditableSettingsList/SettingField/SettingField.js +4 -4
  37. package/es/lib/FormattedKintMessage/FormattedKintMessage.js +7 -4
  38. package/es/lib/IconSelect/IconSelect.js +9 -5
  39. package/es/lib/NoResultsMessage/NoResultsMessage.js +4 -4
  40. package/es/lib/RefdataButtons/RefdataButtons.js +3 -3
  41. package/es/lib/RefdataCategoriesSettings/RefdataCategoriesSettings.js +158 -0
  42. package/es/lib/RefdataCategoriesSettings/index.js +13 -0
  43. package/es/lib/ResponsiveButtonGroup/ResponsiveButtonGroup.js +28 -21
  44. package/es/lib/ResponsiveButtonGroup/useResponsiveButtonGroupSizing.js +6 -5
  45. package/es/lib/RichSelect/RichSelect.js +19 -14
  46. package/es/lib/RichSelect/useSelectedOption.js +2 -1
  47. package/es/lib/SASQLookupComponent/SASQLookupComponent.js +17 -14
  48. package/es/lib/SASQLookupComponent/TableBody/TableBody.js +6 -4
  49. package/es/lib/SASQRoute/SASQRoute.js +2 -2
  50. package/es/lib/SASQViewComponent/SASQViewComponent.js +9 -5
  51. package/es/lib/SettingPage/SettingPagePane.js +2 -2
  52. package/es/lib/SettingsFormContainer/SettingsFormContainer.js +2 -3
  53. package/es/lib/Typedown/Typedown.js +26 -20
  54. package/es/lib/hooks/__mocks__/index.js +4 -0
  55. package/es/lib/hooks/index.js +7 -0
  56. package/es/lib/hooks/typedownHooks/useTypedown.js +2 -2
  57. package/es/lib/hooks/typedownHooks/useTypedownToggle.js +2 -2
  58. package/es/lib/hooks/useActionListRef.js +34 -0
  59. package/es/lib/hooks/useActiveElement.js +1 -1
  60. package/es/lib/hooks/useCustomProperties.js +2 -2
  61. package/es/lib/hooks/useHelperApp.js +6 -6
  62. package/es/lib/hooks/useIntlKeyStore.js +7 -4
  63. package/es/lib/hooks/useKintIntl.js +11 -5
  64. package/es/lib/hooks/useKiwtSASQuery.js +1 -1
  65. package/es/lib/hooks/useModConfigEntries.js +2 -2
  66. package/es/lib/hooks/useMutateCustomProperties.js +8 -8
  67. package/es/lib/hooks/useMutateModConfigEntry.js +2 -2
  68. package/es/lib/hooks/useMutateRefdataCategory.js +4 -4
  69. package/es/lib/hooks/useMutateRefdataValue.js +6 -6
  70. package/es/lib/hooks/useQIndex.js +17 -9
  71. package/es/lib/hooks/useRefdata.js +3 -3
  72. package/es/lib/hooks/useTemplates.js +4 -4
  73. package/es/lib/settingsHooks/useAppSettings.js +11 -7
  74. package/es/lib/settingsHooks/useSettingSection.js +2 -2
  75. package/es/lib/settingsHooks/useSettings.js +3 -3
  76. package/es/lib/utils/buildUrl.js +3 -2
  77. package/es/lib/utils/filterParsers/deparseKiwtQueryFilters.js +5 -5
  78. package/es/lib/utils/filterParsers/parseKiwtQueryFilters.js +2 -2
  79. package/es/lib/utils/filterParsers/parseKiwtQueryGroups.js +5 -4
  80. package/es/lib/utils/filterParsers/parseKiwtQueryString.js +3 -2
  81. package/es/lib/utils/generateKiwtQueryParams.js +37 -28
  82. package/es/lib/utils/groupCustomPropertiesByCtx.js +3 -2
  83. package/es/lib/utils/matchString.js +1 -1
  84. package/es/lib/utils/parseErrorResponse.js +3 -2
  85. package/es/lib/utils/parseModConfigEntry.js +0 -1
  86. package/es/lib/utils/selectorSafe.js +3 -2
  87. package/es/lib/utils/sortByLabel.js +3 -2
  88. package/es/lib/validators/validators.js +3 -3
  89. package/package.json +1 -1
  90. package/src/index.js +3 -0
  91. package/src/lib/ActionList/ActionListFieldArray.js +29 -15
  92. package/src/lib/EditableRefdataCategoryList/EditableRefdataCategoryList.js +67 -13
  93. package/src/lib/RefdataCategoriesSettings/RefdataCategoriesSettings.js +176 -0
  94. package/src/lib/RefdataCategoriesSettings/index.js +1 -0
  95. package/src/lib/hooks/__mocks__/index.js +4 -0
  96. package/src/lib/hooks/index.js +1 -0
  97. package/src/lib/hooks/useActionListRef.js +36 -0
  98. package/src/lib/hooks/useQIndex.js +12 -4
@@ -17,36 +17,40 @@ const conditionalEncodeURIComponent = function (str) {
17
17
  const buildFilterOptionBlock = function (opf) {
18
18
  let isNested = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
19
19
  let encode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
20
- if (opf?.groupValues) {
20
+ if (opf !== null && opf !== void 0 && opf.groupValues) {
21
21
  const groupValues = opf.groupValues;
22
22
 
23
23
  // Small utility function to add negation and brackets to the options block where necessary
24
- const negationAndNesting = str => `${groupValues?.NOT ? '!' : ''}${isNested || groupValues?.NOT ? '(' : ''}${str}${isNested || groupValues?.NOT ? ')' : ''}`;
24
+ const negationAndNesting = str => "".concat(groupValues !== null && groupValues !== void 0 && groupValues.NOT ? '!' : '').concat(isNested || groupValues !== null && groupValues !== void 0 && groupValues.NOT ? '(' : '').concat(str).concat(isNested || groupValues !== null && groupValues !== void 0 && groupValues.NOT ? ')' : '');
25
25
 
26
26
  // First check whether groupValues is ANDed or ORed together
27
- if (groupValues?.AND && Array.isArray(groupValues.AND) || groupValues?.OR && Array.isArray(groupValues.OR)) {
27
+ if (groupValues !== null && groupValues !== void 0 && groupValues.AND && Array.isArray(groupValues.AND) || groupValues !== null && groupValues !== void 0 && groupValues.OR && Array.isArray(groupValues.OR)) {
28
+ var _groupValues$OR;
28
29
  // AND takes precedence
29
30
  if (groupValues.AND) {
30
- return negationAndNesting(groupValues?.AND?.map(gvo => buildFilterOptionBlock(gvo, true, encode))?.join('&&'));
31
+ var _groupValues$AND;
32
+ return negationAndNesting(groupValues === null || groupValues === void 0 || (_groupValues$AND = groupValues.AND) === null || _groupValues$AND === void 0 || (_groupValues$AND = _groupValues$AND.map(gvo => buildFilterOptionBlock(gvo, true, encode))) === null || _groupValues$AND === void 0 ? void 0 : _groupValues$AND.join('&&'));
31
33
  }
32
- return negationAndNesting(groupValues?.OR?.map(gvo => buildFilterOptionBlock(gvo, true, encode))?.join('||'));
34
+ return negationAndNesting(groupValues === null || groupValues === void 0 || (_groupValues$OR = groupValues.OR) === null || _groupValues$OR === void 0 || (_groupValues$OR = _groupValues$OR.map(gvo => buildFilterOptionBlock(gvo, true, encode))) === null || _groupValues$OR === void 0 ? void 0 : _groupValues$OR.join('||'));
33
35
  }
34
36
  // If neither valid OR nor AND exist, ignore the block
35
- } else if (opf?.values) {
37
+ } else if (opf !== null && opf !== void 0 && opf.values) {
36
38
  // Build the values filter block
37
39
  const innerFilters = [];
38
40
  opf.values.forEach(opfv => {
39
41
  if (opf.path) {
40
- innerFilters.push(`${opf.path}${opf.comparator ?? '=='}${opfv}`);
42
+ var _opf$comparator;
43
+ innerFilters.push("".concat(opf.path).concat((_opf$comparator = opf.comparator) !== null && _opf$comparator !== void 0 ? _opf$comparator : '==').concat(opfv));
41
44
  } else {
42
45
  innerFilters.push(opfv);
43
46
  }
44
47
  });
45
48
  return conditionalEncodeURIComponent(innerFilters.join('||'), encode);
46
- } else if (opf?.value) {
49
+ } else if (opf !== null && opf !== void 0 && opf.value) {
47
50
  // If no value OR values, then ignore
48
51
  if (opf.path) {
49
- const filterString = `${opf.path}${opf.comparator ?? '=='}${opf.value}`;
52
+ var _opf$comparator2;
53
+ const filterString = "".concat(opf.path).concat((_opf$comparator2 = opf.comparator) !== null && _opf$comparator2 !== void 0 ? _opf$comparator2 : '==').concat(opf.value);
50
54
  return conditionalEncodeURIComponent(filterString, encode);
51
55
  }
52
56
  return conditionalEncodeURIComponent(opf.value, encode);
@@ -104,8 +108,9 @@ const generateKiwtQueryParams = function (options, nsValues) {
104
108
  } = options;
105
109
  const paramsArray = [];
106
110
  if (query) {
107
- paramsArray.push(...((qindex || searchKey)?.split(',') ?? []).map(m => `match=${conditionalEncodeURIComponent(m, encode)}`));
108
- paramsArray.push(`term=${conditionalEncodeURIComponent(query, encode)}`);
111
+ var _split, _ref;
112
+ paramsArray.push(...((_split = (_ref = qindex || searchKey) === null || _ref === void 0 ? void 0 : _ref.split(',')) !== null && _split !== void 0 ? _split : []).map(m => "match=".concat(conditionalEncodeURIComponent(m, encode))));
113
+ paramsArray.push("term=".concat(conditionalEncodeURIComponent(query, encode)));
109
114
  }
110
115
 
111
116
  // Actually build the optionsFilters block (Moved logic to its own function to allow recursion)
@@ -113,67 +118,71 @@ const generateKiwtQueryParams = function (options, nsValues) {
113
118
  optionsFilters.forEach(opf => {
114
119
  const optionsBlock = buildFilterOptionBlock(opf, false, encode);
115
120
  if (optionsBlock) {
116
- paramsArray.push(`filters=${optionsBlock}`);
121
+ paramsArray.push("filters=".concat(optionsBlock));
117
122
  }
118
123
  });
119
124
  }
120
125
  if (filters) {
121
126
  const filterMap = {};
122
127
  filters.split(',').forEach(filter => {
123
- const [filterName, ...filterRest] = filter.trim()?.split('.') ?? [];
128
+ var _filter$trim$split, _filter$trim;
129
+ const [filterName, ...filterRest] = (_filter$trim$split = (_filter$trim = filter.trim()) === null || _filter$trim === void 0 ? void 0 : _filter$trim.split('.')) !== null && _filter$trim$split !== void 0 ? _filter$trim$split : [];
124
130
  const filterValue = filterRest.join('.');
125
131
  if (filterMap[filterName] === undefined) filterMap[filterName] = [];
126
132
  filterMap[filterName].push(filterValue);
127
133
  });
128
134
 
129
135
  // We now have a filterMap of shape { status: ['active', 'cancelled'], type: ['local'] }
130
- Object.entries(filterMap).forEach(_ref => {
131
- let [filterName, filterValues] = _ref;
136
+ Object.entries(filterMap).forEach(_ref2 => {
137
+ let [filterName, filterValues] = _ref2;
132
138
  const filterConfigEntry = filterConfig.find(conf => conf.name === filterName);
133
139
  const filterKey = filterKeys[filterName];
134
140
  if (filterConfigEntry) {
135
141
  // We have a direct mapping instruction, use it
136
142
  const filterString = filterValues.map(v => {
137
- const fceValue = filterConfigEntry?.values?.find(fce => fce.name === v)?.value;
138
- return `${filterName}==${fceValue ?? v}`;
143
+ var _filterConfigEntry$va;
144
+ const fceValue = filterConfigEntry === null || filterConfigEntry === void 0 || (_filterConfigEntry$va = filterConfigEntry.values) === null || _filterConfigEntry$va === void 0 || (_filterConfigEntry$va = _filterConfigEntry$va.find(fce => fce.name === v)) === null || _filterConfigEntry$va === void 0 ? void 0 : _filterConfigEntry$va.value;
145
+ return "".concat(filterName, "==").concat(fceValue !== null && fceValue !== void 0 ? fceValue : v);
139
146
  }).join('||');
140
- paramsArray.push(`filters=${conditionalEncodeURIComponent(filterString, encode)}`);
147
+ paramsArray.push("filters=".concat(conditionalEncodeURIComponent(filterString, encode)));
141
148
  } else if (!filterKey) {
142
149
  // These filters have no key mapping so we just pass the values to the backend as-is.
143
- paramsArray.push(...(filterValues ?? []).map(f => `filters=${conditionalEncodeURIComponent(f, encode)}`));
150
+ paramsArray.push(...(filterValues !== null && filterValues !== void 0 ? filterValues : []).map(f => "filters=".concat(conditionalEncodeURIComponent(f, encode))));
144
151
  } else {
145
- const filterString = filterValues.map(v => `${filterKey}==${v}`).join('||');
146
- paramsArray.push(`filters=${conditionalEncodeURIComponent(filterString, encode)}`);
152
+ const filterString = filterValues.map(v => "".concat(filterKey, "==").concat(v)).join('||');
153
+ paramsArray.push("filters=".concat(conditionalEncodeURIComponent(filterString, encode)));
147
154
  }
148
155
  });
149
156
  }
150
157
  if (optionsSort && optionsSort.length > 0) {
151
158
  optionsSort.forEach(os => {
152
159
  if (os.value) {
153
- paramsArray.push(`sort=${conditionalEncodeURIComponent(os.value, encode)}`);
160
+ paramsArray.push("sort=".concat(conditionalEncodeURIComponent(os.value, encode)));
154
161
  } else if (os.path) {
162
+ var _os$direction;
155
163
  // If no path then ignore
156
- const sortString = `${os.path};${os.direction ?? 'asc'}`;
157
- paramsArray.push(`sort=${conditionalEncodeURIComponent(sortString, encode)}`);
164
+ const sortString = "".concat(os.path, ";").concat((_os$direction = os.direction) !== null && _os$direction !== void 0 ? _os$direction : 'asc');
165
+ paramsArray.push("sort=".concat(conditionalEncodeURIComponent(sortString, encode)));
158
166
  }
159
167
  });
160
168
  }
161
169
  if (sort) {
162
- paramsArray.push(...(sort.trim()?.split(',') ?? []).map(sortKey => {
170
+ var _sort$trim$split, _sort$trim;
171
+ paramsArray.push(...((_sort$trim$split = (_sort$trim = sort.trim()) === null || _sort$trim === void 0 ? void 0 : _sort$trim.split(',')) !== null && _sort$trim$split !== void 0 ? _sort$trim$split : []).map(sortKey => {
163
172
  const descending = sortKey.startsWith('-');
164
173
  let term = sortKey.replace('-', '');
165
174
  if (term in sortKeys) {
166
175
  term = term.replace(term, sortKeys[term]);
167
176
  }
168
- const sortString = `${term};${descending ? 'desc' : 'asc'}`;
169
- return `sort=${conditionalEncodeURIComponent(sortString, encode)}`;
177
+ const sortString = "".concat(term, ";").concat(descending ? 'desc' : 'asc');
178
+ return "sort=".concat(conditionalEncodeURIComponent(sortString, encode));
170
179
  }));
171
180
  }
172
181
  if (stats) {
173
182
  paramsArray.push('stats=true');
174
183
  }
175
184
  for (const [key, value] of Object.entries(rest)) {
176
- paramsArray.push(`${key}=${conditionalEncodeURIComponent(value, encode)}`);
185
+ paramsArray.push("".concat(key, "=").concat(conditionalEncodeURIComponent(value, encode)));
177
186
  }
178
187
  return paramsArray;
179
188
  };
@@ -7,11 +7,12 @@ exports.default = void 0;
7
7
  const groupCustomPropertiesByCtx = function () {
8
8
  let customProperties = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
9
9
  return customProperties.reduce((acc, curr) => {
10
- const ctx = curr.ctx ?? 'isNull';
10
+ var _curr$ctx, _acc$ctx;
11
+ const ctx = (_curr$ctx = curr.ctx) !== null && _curr$ctx !== void 0 ? _curr$ctx : 'isNull';
11
12
  const returnObj = {
12
13
  ...acc
13
14
  };
14
- returnObj[ctx] = [...(acc?.[ctx] ?? []), curr];
15
+ returnObj[ctx] = [...((_acc$ctx = acc === null || acc === void 0 ? void 0 : acc[ctx]) !== null && _acc$ctx !== void 0 ? _acc$ctx : []), curr];
15
16
  return returnObj;
16
17
  }, {});
17
18
  };
@@ -8,7 +8,7 @@ var _escapeRegExp = _interopRequireDefault(require("lodash/escapeRegExp"));
8
8
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
9
  const matchString = function (match, str) {
10
10
  let ignoreNull = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
11
- const regex = new RegExp(`${match.split(/(\s+)/).filter(h => h.trim()).map(hl => '(' + (0, _escapeRegExp.default)(hl) + ')').join('|')}`, 'gi');
11
+ const regex = new RegExp("".concat(match.split(/(\s+)/).filter(h => h.trim()).map(hl => '(' + (0, _escapeRegExp.default)(hl) + ')').join('|')), 'gi');
12
12
  if (ignoreNull && !match) {
13
13
  const nullRegex = /a^/gi; // Should match nothing
14
14
 
@@ -5,9 +5,10 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  const parseErrorResponse = async responseObj => {
8
+ var _ref;
8
9
  let errorResp;
9
- const code = responseObj?.status;
10
- const contentType = [...responseObj?.headers]?.find(header => header[0] === 'content-type')?.[1];
10
+ const code = responseObj === null || responseObj === void 0 ? void 0 : responseObj.status;
11
+ const contentType = (_ref = [...(responseObj === null || responseObj === void 0 ? void 0 : responseObj.headers)]) === null || _ref === void 0 || (_ref = _ref.find(header => header[0] === 'content-type')) === null || _ref === void 0 ? void 0 : _ref[1];
11
12
  if (contentType.includes('json')) {
12
13
  errorResp = await responseObj.json();
13
14
  } else {
@@ -14,7 +14,6 @@ const parseModConfigEntry = setting => {
14
14
  console.error(error); // eslint-disable-line no-console
15
15
  }
16
16
  }
17
-
18
17
  return parsedSettings;
19
18
  };
20
19
  var _default = exports.default = parseModConfigEntry;
@@ -5,11 +5,12 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  const selectorSafe = string => {
8
+ var _string$normalize;
8
9
  // Normalise to separate diacritics from their base characters as "marks"
9
10
  // then strip out all marks.
10
- return string.normalize('NFKD')?.replace(/\p{M}/gu, '')
11
+ return (_string$normalize = string.normalize('NFKD')) === null || _string$normalize === void 0 || (_string$normalize = _string$normalize.replace(/\p{M}/gu, '')
11
12
  // Then swap out any non-letter/number characters (Also ignore - and _) for `_`
12
- ?.replace(/[^\p{L}\p{N}\-_]/gu, '_');
13
+ ) === null || _string$normalize === void 0 ? void 0 : _string$normalize.replace(/[^\p{L}\p{N}\-_]/gu, '_');
13
14
  };
14
15
  var _default = exports.default = selectorSafe;
15
16
  /*
@@ -5,8 +5,9 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  const sortByLabel = (a, b) => {
8
- const al = a.label?.toLowerCase() ?? a.id?.toLowerCase();
9
- const bl = b.label?.toLowerCase() ?? b.id?.toLowerCase();
8
+ var _a$label$toLowerCase, _a$label, _a$id, _b$label$toLowerCase, _b$label, _b$id;
9
+ const al = (_a$label$toLowerCase = (_a$label = a.label) === null || _a$label === void 0 ? void 0 : _a$label.toLowerCase()) !== null && _a$label$toLowerCase !== void 0 ? _a$label$toLowerCase : (_a$id = a.id) === null || _a$id === void 0 ? void 0 : _a$id.toLowerCase();
10
+ const bl = (_b$label$toLowerCase = (_b$label = b.label) === null || _b$label === void 0 ? void 0 : _b$label.toLowerCase()) !== null && _b$label$toLowerCase !== void 0 ? _b$label$toLowerCase : (_b$id = b.id) === null || _b$id === void 0 ? void 0 : _b$id.toLowerCase();
10
11
  if (al < bl) {
11
12
  return -1;
12
13
  }
@@ -64,7 +64,7 @@ const invalidNumber = function (value, _min, _max, intlKey, intlNS) {
64
64
  id: "errors.invalidNumber",
65
65
  intlKey: intlKey,
66
66
  intlNS: intlNS,
67
- overrideValue: labelOverrides?.invalidNumberError
67
+ overrideValue: labelOverrides === null || labelOverrides === void 0 ? void 0 : labelOverrides.invalidNumberError
68
68
  });
69
69
  }
70
70
  return undefined;
@@ -77,7 +77,7 @@ const rangeOverflow = function (value, min, max, intlKey, intlNS) {
77
77
  id: "errors.decimalValueNotInRange",
78
78
  intlKey: intlKey,
79
79
  intlNS: intlNS,
80
- overrideValue: labelOverrides?.decimalValueNotInRangeError,
80
+ overrideValue: labelOverrides === null || labelOverrides === void 0 ? void 0 : labelOverrides.decimalValueNotInRangeError,
81
81
  values: {
82
82
  min,
83
83
  max
@@ -94,7 +94,7 @@ const rangeUnderflow = function (value, min, max, intlKey, intlNS) {
94
94
  id: "errors.decimalValueNotInRange",
95
95
  intlKey: intlKey,
96
96
  intlNS: intlNS,
97
- overrideValue: labelOverrides?.decimalValueNotInRangeError,
97
+ overrideValue: labelOverrides === null || labelOverrides === void 0 ? void 0 : labelOverrides.decimalValueNotInRangeError,
98
98
  values: {
99
99
  min,
100
100
  max
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k-int/stripes-kint-components",
3
- "version": "5.2.3",
3
+ "version": "5.3.1",
4
4
  "description": "Stripes Component library for K-Int specific applications",
5
5
  "sideEffects": [
6
6
  "*.css"
package/src/index.js CHANGED
@@ -92,6 +92,9 @@ export {
92
92
  useParseActiveFilterStrings
93
93
  } from './lib/CustomProperties';
94
94
 
95
+ // Refdata categories
96
+ export { default as RefdataCategoriesSettings } from './lib/RefdataCategoriesSettings';
97
+
95
98
  export * as customPropertyConstants from './lib/constants/customProperties';
96
99
 
97
100
  export * as endpoints from './lib/constants/endpoints';
@@ -1,4 +1,4 @@
1
- import React, { forwardRef, useImperativeHandle, useState } from 'react';
1
+ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
 
4
4
  import get from 'lodash/get';
@@ -70,6 +70,8 @@ ActionTrigger.propTypes = {
70
70
  })
71
71
  };
72
72
 
73
+ const NEW_ROW = 'NEW_ROW';
74
+
73
75
  const ActionListFieldArray = forwardRef(({
74
76
  actionAssigner,
75
77
  columnMapping,
@@ -100,21 +102,29 @@ const ActionListFieldArray = forwardRef(({
100
102
  null for no field, string id if we are editing an existing field and
101
103
  'NEW_ROW' for a new row
102
104
  */
103
- const [editing, setEditing] = useState(null);
105
+ const [editing, setEditing] = useState((fields?.value?.filter(f => f._isNewActionListRow)?.length ?? 0) > 0 ? NEW_ROW : undefined);
104
106
 
105
- const toggleEditing = (id) => {
107
+ const toggleEditing = useCallback((id) => {
106
108
  if (editing) {
107
- setEditing(null);
109
+ setEditing();
108
110
  } else {
109
111
  setEditing(id);
110
112
  }
111
- };
113
+ }, [editing]);
114
+
115
+ // Ensure editing doesn't get stuck in "NEW_ROW" state;
116
+ useEffect(() => {
117
+ if (editing === NEW_ROW && (fields?.value?.filter(f => f._isNewActionListRow)?.length ?? 0) === 0) {
118
+ setEditing();
119
+ }
120
+ }, [editing, fields?.value]);
112
121
 
113
122
  const handleSave = (index) => {
114
123
  const {
115
124
  actionListActions: _a,
116
125
  fieldName: _fn,
117
126
  fieldIndex: _fi,
127
+ _isNewActionListRow: _inalr,
118
128
  ...rowData
119
129
  } = fields.value[index];
120
130
 
@@ -130,6 +140,7 @@ const ActionListFieldArray = forwardRef(({
130
140
  actionListActions: _a,
131
141
  fieldName: _fn,
132
142
  fieldIndex: _fi,
143
+ _isNewActionListRow: _inalr,
133
144
  ...rowData
134
145
  } = fields.value[index];
135
146
 
@@ -138,16 +149,19 @@ const ActionListFieldArray = forwardRef(({
138
149
  }
139
150
  };
140
151
 
141
- const handleClickCreate = () => {
142
- toggleEditing('NEW_ROW');
143
- fields.unshift(defaultNewObject);
144
- };
152
+ const handleClickCreate = useCallback(() => {
153
+ toggleEditing(NEW_ROW);
154
+ fields.unshift({
155
+ ...defaultNewObject,
156
+ _isNewActionListRow: true
157
+ });
158
+ }, [defaultNewObject, fields, toggleEditing]);
145
159
 
146
160
  // Way to go into create mode from external component, and way to tell internal editing state
147
161
  useImperativeHandle(ref, () => ({
148
162
  create: handleClickCreate,
149
163
  editing
150
- }));
164
+ }), [editing, handleClickCreate]);
151
165
 
152
166
  const getColumnWidths = () => {
153
167
  const widthNotInUseByActions = editing ?
@@ -173,7 +187,7 @@ const ActionListFieldArray = forwardRef(({
173
187
  const fieldName = `contentData[${data.rowIndex}]`;
174
188
  const { actionListActions: actions, ...rest } = data;
175
189
 
176
- if (data.id === editing || (!data.id && editing === 'NEW_ROW')) {
190
+ if (data.id === editing || (!data.id && editing === NEW_ROW)) {
177
191
  // Render the save/cancel buttons
178
192
  return (
179
193
  <div id={`action-button-parent-${data.rowIndex + 1}`}>
@@ -186,12 +200,12 @@ const ActionListFieldArray = forwardRef(({
186
200
  triggerFormSubmit(); // This is set up as () => null in ActionList, so essentially only acts here to force validation
187
201
 
188
202
  if (!hasValidationErrors) {
189
- if (!data.id && editing === 'NEW_ROW') {
203
+ if (!data.id && editing === NEW_ROW) {
190
204
  handleCreate(data.rowIndex);
191
205
  } else {
192
206
  handleSave(data.rowIndex);
193
207
  }
194
- toggleEditing(data.id);
208
+ toggleEditing();
195
209
  }
196
210
  }}
197
211
  type="submit"
@@ -206,9 +220,9 @@ const ActionListFieldArray = forwardRef(({
206
220
  data-type-button="cancel"
207
221
  marginBottom0
208
222
  onClick={() => {
209
- if (!data.id && editing === 'NEW_ROW') {
223
+ if (!data.id && editing === NEW_ROW) {
210
224
  fields.remove(data.rowIndex);
211
- toggleEditing('NEW_ROW');
225
+ toggleEditing(NEW_ROW);
212
226
  } else {
213
227
  change(fieldName, get(initialValues, fieldName));
214
228
  toggleEditing(data.id);
@@ -1,14 +1,16 @@
1
- import React, { useEffect, useState, useContext } from 'react';
1
+ import { useEffect, useState, useContext, forwardRef } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
 
4
- import { ConfirmationModal } from '@folio/stripes/components';
4
+ import { Button, ConfirmationModal } from '@folio/stripes/components';
5
5
  import { CalloutContext } from '@folio/stripes/core';
6
6
 
7
7
  import { useKintIntl, useMutateRefdataCategory, useRefdata } from '../hooks';
8
8
 
9
+ import SearchField from '../SearchField';
9
10
  import ActionList from '../ActionList';
10
11
  import { required } from '../validators';
11
12
  import { parseErrorResponse } from '../utils';
13
+ import css from '../../../styles/CustomProperties.css';
12
14
 
13
15
  const propTypes = {
14
16
  afterQueryCalls: PropTypes.object,
@@ -18,17 +20,21 @@ const propTypes = {
18
20
  delete: PropTypes.bool,
19
21
  view: PropTypes.bool,
20
22
  }),
23
+ handleRefdataCategoryClick: PropTypes.func,
24
+ hideCreateButton: PropTypes.bool,
21
25
  intlKey: PropTypes.string,
22
26
  intlNS: PropTypes.string,
27
+ isSearchDisabled: PropTypes.bool,
23
28
  label: PropTypes.oneOfType([
24
29
  PropTypes.string,
25
30
  PropTypes.node
26
31
  ]),
27
32
  labelOverrides: PropTypes.object,
28
- refdataEndpoint: PropTypes.string
33
+ onConfirmDelete: PropTypes.func,
34
+ refdataEndpoint: PropTypes.string,
29
35
  };
30
36
 
31
- const EditableRefdataCategoryList = ({
37
+ const EditableRefdataCategoryList = forwardRef(({
32
38
  afterQueryCalls,
33
39
  catchQueryCalls,
34
40
  /*
@@ -42,12 +48,18 @@ const EditableRefdataCategoryList = ({
42
48
  create: true,
43
49
  delete: true,
44
50
  },
51
+ handleRefdataCategoryClick,
52
+ hideCreateButton,
53
+ isSearchDisabled,
45
54
  intlKey: passedIntlKey,
46
55
  intlNS: passedIntlNS,
47
56
  label,
48
57
  labelOverrides = {}, // An object containing translation alternatives
49
- refdataEndpoint
50
- }) => {
58
+ // A function which will fire on confirmation of delete,
59
+ // with id of deleted Refdata category
60
+ onConfirmDelete = (_id) => null,
61
+ refdataEndpoint,
62
+ }, ref) => {
51
63
  /* A component that allows for editing of refdata categories */
52
64
  const callout = useContext(CalloutContext);
53
65
  const kintIntl = useKintIntl(passedIntlKey, passedIntlNS);
@@ -63,6 +75,7 @@ const EditableRefdataCategoryList = ({
63
75
  returnQueryObject: true
64
76
  });
65
77
 
78
+ const [searchTerm, setSearchTerm] = useState('');
66
79
  const [contentData, setContentData] = useState([]);
67
80
  const [deleteModal, setDeleteModal] = useState({
68
81
  visible: false,
@@ -73,9 +86,14 @@ const EditableRefdataCategoryList = ({
73
86
 
74
87
  useEffect(() => {
75
88
  if (!isRefdataLoading) {
76
- setContentData(refdata?.sort(sortByDesc) ?? []);
89
+ if (searchTerm) {
90
+ const filteredRefdata = refdata?.filter(rd => rd.desc.toLowerCase().includes(searchTerm.toLowerCase()));
91
+ setContentData(filteredRefdata?.sort(sortByDesc) ?? []);
92
+ } else {
93
+ setContentData(refdata?.sort(sortByDesc) ?? []);
94
+ }
77
95
  }
78
- }, [isRefdataLoading, refdata]);
96
+ }, [isRefdataLoading, refdata, searchTerm]);
79
97
 
80
98
  // Edit and Create will use the same POST mutation
81
99
  const { delete: deleteRefdataCategory, post: createRefdataCategory } = useMutateRefdataCategory({
@@ -101,10 +119,10 @@ const EditableRefdataCategoryList = ({
101
119
  id: 'refdataCategory.deleteRefdataCategory.errorMessage',
102
120
  overrideValue: labelOverrides?.deleteError
103
121
  },
104
- {
105
- label: deleteModal?.refdata?.label,
106
- error: errorResp?.message
107
- }),
122
+ {
123
+ label: deleteModal?.refdata?.label,
124
+ error: errorResp?.message
125
+ }),
108
126
  type: 'error',
109
127
  });
110
128
  },
@@ -153,7 +171,28 @@ const EditableRefdataCategoryList = ({
153
171
 
154
172
  return (
155
173
  <>
174
+ {!isSearchDisabled ?
175
+ <div
176
+ className={css.lookupSearchContainer}
177
+ >
178
+ <SearchField
179
+ ariaLabel={
180
+ kintIntl.formatKintMessage({
181
+ id: 'refdataCategories.config.searchAriaLabel',
182
+ overrideValue: labelOverrides.searchAriaLabel,
183
+ fallbackMessage: 'refdata-category-search-field'
184
+ })
185
+ }
186
+ className={css.lookupSearch}
187
+ marginBottom0
188
+ onChange={e => setSearchTerm(e.target.value)}
189
+ value={searchTerm}
190
+ />
191
+ </div>
192
+ : null
193
+ }
156
194
  <ActionList
195
+ ref={ref}
157
196
  actionAssigner={actionAssigner}
158
197
  columnMapping={{
159
198
  desc: kintIntl.formatKintMessage({
@@ -174,6 +213,19 @@ const EditableRefdataCategoryList = ({
174
213
  (data) => createRefdataCategory(data)
175
214
  }
176
215
  formatter={{
216
+ desc: (rowData) => {
217
+ if (handleRefdataCategoryClick) {
218
+ return (
219
+ <Button
220
+ buttonStyle="link"
221
+ onClick={() => handleRefdataCategoryClick(rowData)}
222
+ >
223
+ {rowData?.desc}
224
+ </Button>
225
+ );
226
+ }
227
+ return rowData?.desc;
228
+ },
177
229
  values: (rowData) => rowData?.values?.length
178
230
  }}
179
231
  /* Hide actions column when no permissions, or no deletable refdata categories */
@@ -181,6 +233,7 @@ const EditableRefdataCategoryList = ({
181
233
  (!createCondition && !deleteCondition) ||
182
234
  !contentData?.find(cd => cd?.values?.length === 0)
183
235
  }
236
+ hideCreateButton={hideCreateButton}
184
237
  label={label}
185
238
  validateFields={{
186
239
  desc: () => required
@@ -209,13 +262,14 @@ const EditableRefdataCategoryList = ({
209
262
  onCancel={() => setDeleteModal({ visible: false, refdata: null })}
210
263
  onConfirm={() => {
211
264
  deleteRefdataCategory(deleteModal?.refdata?.id);
265
+ onConfirmDelete(deleteModal?.refdata?.id);
212
266
  setDeleteModal({ visible: false, refdata: null });
213
267
  }}
214
268
  open={deleteModal?.visible}
215
269
  />
216
270
  </>
217
271
  );
218
- };
272
+ });
219
273
 
220
274
  EditableRefdataCategoryList.propTypes = propTypes;
221
275