@k-int/stripes-kint-components 5.3.1 → 5.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.
- package/CHANGELOG.md +20 -0
- package/es/lib/EditableSettingsList/SettingField/EditSettingValue.js +5 -1
- package/es/lib/FormModal/FormModal.js +14 -12
- package/es/lib/SASQLookupComponent/SASQLookupComponent.js +4 -0
- package/es/lib/SASQLookupComponent/TableBody/TableBody.js +48 -12
- package/es/lib/utils/highlightString.js +28 -12
- package/es/lib/utils/matchString.js +17 -2
- package/package.json +3 -3
- package/renovate.json +6 -0
- package/src/lib/EditableSettingsList/SettingField/EditSettingValue.js +5 -1
- package/src/lib/FormModal/FormModal.js +14 -13
- package/src/lib/SASQLookupComponent/SASQLookupComponent.js +3 -0
- package/src/lib/SASQLookupComponent/TableBody/TableBody.js +42 -5
- package/src/lib/utils/highlightString.js +36 -20
- package/src/lib/utils/matchString.js +24 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
# [5.5.0](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/compare/v5.4.0...v5.5.0) (2024-03-15)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* FormModal handleSUbmit clears form ([2abf0dd](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/commit/2abf0dddd042a0ea79970aa09b01ecca073d5705))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* SASQLookupComponent rowNavigation ([57aa5d2](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/commit/57aa5d231f2700e2930ff26726d8445d03bd9001))
|
|
12
|
+
|
|
13
|
+
# [5.4.0](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/compare/v5.3.1...v5.4.0) (2024-02-29)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* EditSettingValue: refdata default sort ([9e7f530](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/commit/9e7f5301bb43050ba263b303e0e05462b1268a8a))
|
|
19
|
+
* matchString and highlightString improvements ([83f98e9](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/commit/83f98e9ebc678c3a893504a9959d35f9e1318b7b))
|
|
20
|
+
|
|
1
21
|
## [5.3.1](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/compare/v5.3.0...v5.3.1) (2024-01-26)
|
|
2
22
|
|
|
3
23
|
|
|
@@ -37,10 +37,14 @@ const EditSettingValue = props => {
|
|
|
37
37
|
if (refdata.length > 0 && refdata.length <= 4) {
|
|
38
38
|
RefdataComponent = _RefdataButtons.default;
|
|
39
39
|
}
|
|
40
|
+
|
|
41
|
+
// Adding default sort to refdata object in ascending order by label
|
|
42
|
+
const sortByLabel = (a, b) => a.label.localeCompare(b.label);
|
|
43
|
+
const sortedRefdata = refdata.sort(sortByLabel);
|
|
40
44
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactFinalForm.Field, {
|
|
41
45
|
"aria-label": fieldLabel,
|
|
42
46
|
component: RefdataComponent,
|
|
43
|
-
dataOptions:
|
|
47
|
+
dataOptions: sortedRefdata,
|
|
44
48
|
name: "".concat(input.name, ".value")
|
|
45
49
|
});
|
|
46
50
|
case 'Password':
|
|
@@ -41,12 +41,17 @@ const FormModal = _ref => {
|
|
|
41
41
|
onClose(e);
|
|
42
42
|
restart();
|
|
43
43
|
};
|
|
44
|
+
const handleSaveAndClear = function () {
|
|
45
|
+
handleSubmit(...arguments);
|
|
46
|
+
restart();
|
|
47
|
+
};
|
|
44
48
|
const renderFooter = () => {
|
|
45
49
|
if (footer) {
|
|
46
50
|
return footer({
|
|
47
51
|
formState,
|
|
48
|
-
handleSubmit,
|
|
49
|
-
handleClose
|
|
52
|
+
handleSubmit: handleSaveAndClear,
|
|
53
|
+
handleClose,
|
|
54
|
+
handleSubmitNoRestart: handleSubmit
|
|
50
55
|
});
|
|
51
56
|
}
|
|
52
57
|
const {
|
|
@@ -59,7 +64,7 @@ const FormModal = _ref => {
|
|
|
59
64
|
buttonStyle: "primary",
|
|
60
65
|
disabled: submitting || invalid || pristine,
|
|
61
66
|
marginBottom0: true,
|
|
62
|
-
onClick:
|
|
67
|
+
onClick: handleSaveAndClear,
|
|
63
68
|
type: "submit",
|
|
64
69
|
children: kintIntl.formatKintMessage({
|
|
65
70
|
id: 'saveAndClose',
|
|
@@ -75,15 +80,12 @@ const FormModal = _ref => {
|
|
|
75
80
|
})]
|
|
76
81
|
});
|
|
77
82
|
};
|
|
78
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
...modalProps,
|
|
85
|
-
children: children
|
|
86
|
-
})
|
|
83
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Modal, {
|
|
84
|
+
enforceFocus: false,
|
|
85
|
+
footer: renderFooter(),
|
|
86
|
+
onClose: handleClose,
|
|
87
|
+
...modalProps,
|
|
88
|
+
children: children
|
|
87
89
|
});
|
|
88
90
|
}
|
|
89
91
|
});
|
|
@@ -32,6 +32,8 @@ const SASQLookupComponent = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
32
32
|
noSearchField,
|
|
33
33
|
persistedPanesetProps = {},
|
|
34
34
|
RenderBody,
|
|
35
|
+
rowNavigation = true,
|
|
36
|
+
// Default navigation onRowClick
|
|
35
37
|
sasqProps,
|
|
36
38
|
searchFieldAriaLabel,
|
|
37
39
|
searchFieldProps
|
|
@@ -221,6 +223,7 @@ const SASQLookupComponent = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
221
223
|
intlNS: passedIntlNS,
|
|
222
224
|
labelOverrides: labelOverrides,
|
|
223
225
|
query: query,
|
|
226
|
+
rowNavigation: rowNavigation,
|
|
224
227
|
toggleFilterPane: toggleFilterPane,
|
|
225
228
|
...restOfInfiniteQueryProps,
|
|
226
229
|
...sasqRenderProps,
|
|
@@ -253,6 +256,7 @@ SASQLookupComponent.propTypes = {
|
|
|
253
256
|
RenderBody: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.node]),
|
|
254
257
|
resource: _propTypes.default.object,
|
|
255
258
|
resultColumns: _propTypes.default.arrayOf(_propTypes.default.object),
|
|
259
|
+
rowNavigation: _propTypes.default.bool,
|
|
256
260
|
sasqProps: _propTypes.default.object,
|
|
257
261
|
searchFieldAriaLabel: _propTypes.default.string,
|
|
258
262
|
searchFieldProps: _propTypes.default.object
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
+
var _react = require("react");
|
|
7
8
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
8
9
|
var _reactRouterDom = require("react-router-dom");
|
|
9
10
|
var _components = require("@folio/stripes/components");
|
|
@@ -11,7 +12,7 @@ var _NoResultsMessage = _interopRequireDefault(require("../../NoResultsMessage")
|
|
|
11
12
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
12
13
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
14
|
const TableBody = _ref => {
|
|
14
|
-
var _query$sort;
|
|
15
|
+
var _query$sort, _match$params2;
|
|
15
16
|
let {
|
|
16
17
|
data,
|
|
17
18
|
error,
|
|
@@ -23,10 +24,15 @@ const TableBody = _ref => {
|
|
|
23
24
|
isLoading,
|
|
24
25
|
labelOverrides = {},
|
|
25
26
|
match,
|
|
26
|
-
mclProps
|
|
27
|
+
mclProps: {
|
|
28
|
+
formatter = {},
|
|
29
|
+
...mclProps
|
|
30
|
+
},
|
|
27
31
|
onSort,
|
|
28
32
|
path,
|
|
29
33
|
resultColumns,
|
|
34
|
+
rowNavigation = true,
|
|
35
|
+
// Default navigation onRowClick
|
|
30
36
|
toggleFilterPane,
|
|
31
37
|
query
|
|
32
38
|
} = _ref;
|
|
@@ -44,11 +50,48 @@ const TableBody = _ref => {
|
|
|
44
50
|
|
|
45
51
|
// Build the list of visible columns
|
|
46
52
|
const visibleColumns = resultColumns.map(e => e.propertyPath);
|
|
53
|
+
const getRowUrl = (0, _react.useCallback)(rowData => {
|
|
54
|
+
const baseUrl = "".concat(path, "/").concat(rowData === null || rowData === void 0 ? void 0 : rowData.id);
|
|
55
|
+
return {
|
|
56
|
+
url: "".concat(baseUrl).concat(location === null || location === void 0 ? void 0 : location.search),
|
|
57
|
+
path,
|
|
58
|
+
baseUrl,
|
|
59
|
+
location
|
|
60
|
+
};
|
|
61
|
+
}, [location, path]);
|
|
62
|
+
const getEnhancedFormatter = (0, _react.useCallback)(() => {
|
|
63
|
+
const enhancedFormatter = {};
|
|
64
|
+
for (const [key, value] of Object.entries(formatter)) {
|
|
65
|
+
enhancedFormatter[key] = item => value({
|
|
66
|
+
...item,
|
|
67
|
+
defaultRowUrl: getRowUrl(item)
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return enhancedFormatter;
|
|
71
|
+
}, [formatter, getRowUrl]);
|
|
72
|
+
const getOnRowClick = (0, _react.useCallback)(() => {
|
|
73
|
+
if (rowNavigation) {
|
|
74
|
+
return (_e, rowData) => {
|
|
75
|
+
history.push(getRowUrl(rowData).url);
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}, [getRowUrl, history, rowNavigation]);
|
|
80
|
+
const isSelected = (0, _react.useCallback)(_ref2 => {
|
|
81
|
+
var _match$params;
|
|
82
|
+
let {
|
|
83
|
+
item
|
|
84
|
+
} = _ref2;
|
|
85
|
+
return item.id === (match === null || match === void 0 || (_match$params = match.params) === null || _match$params === void 0 ? void 0 : _match$params.id);
|
|
86
|
+
}, [match === null || match === void 0 || (_match$params2 = match.params) === null || _match$params2 === void 0 ? void 0 : _match$params2.id]);
|
|
47
87
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.MultiColumnList, {
|
|
48
88
|
autosize: true,
|
|
49
89
|
columnMapping: columnMapping,
|
|
50
90
|
contentData: data === null || data === void 0 ? void 0 : data.results,
|
|
91
|
+
formatter: getEnhancedFormatter() // Pass enhanced formatter
|
|
92
|
+
,
|
|
51
93
|
hasMargin: true,
|
|
94
|
+
interactive: rowNavigation,
|
|
52
95
|
isEmptyMessage: /*#__PURE__*/(0, _jsxRuntime.jsx)(_NoResultsMessage.default, {
|
|
53
96
|
error,
|
|
54
97
|
filterPaneIsVisible: filterPaneVisible,
|
|
@@ -60,18 +103,10 @@ const TableBody = _ref => {
|
|
|
60
103
|
searchTerm: query.query,
|
|
61
104
|
toggleFilterPane
|
|
62
105
|
}),
|
|
63
|
-
isSelected:
|
|
64
|
-
var _match$params;
|
|
65
|
-
let {
|
|
66
|
-
item
|
|
67
|
-
} = _ref2;
|
|
68
|
-
return item.id === (match === null || match === void 0 || (_match$params = match.params) === null || _match$params === void 0 ? void 0 : _match$params.id);
|
|
69
|
-
},
|
|
106
|
+
isSelected: isSelected,
|
|
70
107
|
onHeaderClick: onSort,
|
|
71
108
|
onNeedMoreData: onNeedMoreData,
|
|
72
|
-
onRowClick: (
|
|
73
|
-
history.push("".concat(path, "/").concat(rowData === null || rowData === void 0 ? void 0 : rowData.id).concat(location === null || location === void 0 ? void 0 : location.search));
|
|
74
|
-
},
|
|
109
|
+
onRowClick: getOnRowClick(),
|
|
75
110
|
pagingType: "click",
|
|
76
111
|
sortDirection: sortOrder.startsWith('-') ? 'descending' : 'ascending',
|
|
77
112
|
sortOrder: sortOrder.replace(/^-/, '').replace(/,.*/, ''),
|
|
@@ -101,6 +136,7 @@ TableBody.propTypes = {
|
|
|
101
136
|
path: _propTypes.default.string.isRequired,
|
|
102
137
|
query: _propTypes.default.object,
|
|
103
138
|
resultColumns: _propTypes.default.arrayOf(_propTypes.default.object),
|
|
139
|
+
rowNavigation: _propTypes.default.bool,
|
|
104
140
|
toggleFilterPane: _propTypes.default.func
|
|
105
141
|
};
|
|
106
142
|
var _default = exports.default = TableBody;
|
|
@@ -9,21 +9,37 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
9
9
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
10
10
|
const highlightString = function (match, str) {
|
|
11
11
|
let ignoreNull = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
let simpleSplit = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
|
|
13
|
+
const [parts, regex] = (0, _matchString.default)(match, str, ignoreNull, simpleSplit);
|
|
14
|
+
return parts.map((part, i) => {
|
|
15
|
+
// RegExp is stateful, set up a new one to work with
|
|
16
|
+
const immutableRegex = new RegExp(regex);
|
|
17
|
+
if (immutableRegex.exec(part) !== null) {
|
|
18
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)("mark", {
|
|
19
|
+
children: part
|
|
20
|
+
}, i);
|
|
21
|
+
}
|
|
22
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
23
|
+
children: part
|
|
24
|
+
}, i);
|
|
25
|
+
});
|
|
18
26
|
};
|
|
19
27
|
exports.highlightString = highlightString;
|
|
20
28
|
const boldString = function (match, str) {
|
|
21
29
|
let ignoreNull = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
let simpleSplit = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
|
|
31
|
+
const [parts, regex] = (0, _matchString.default)(match, str, ignoreNull, simpleSplit);
|
|
32
|
+
return parts.map((part, i) => {
|
|
33
|
+
// RegExp is stateful, set up a new one to work with
|
|
34
|
+
const immutableRegex = new RegExp(regex);
|
|
35
|
+
if (immutableRegex.exec(part) !== null) {
|
|
36
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)("strong", {
|
|
37
|
+
children: part
|
|
38
|
+
}, i);
|
|
39
|
+
}
|
|
40
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
41
|
+
children: part
|
|
42
|
+
}, i);
|
|
43
|
+
});
|
|
28
44
|
};
|
|
29
45
|
exports.boldString = boldString;
|
|
@@ -7,13 +7,28 @@ exports.default = void 0;
|
|
|
7
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
|
+
var _str$split2;
|
|
10
11
|
let ignoreNull = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
11
|
-
|
|
12
|
+
let simpleSplit = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
|
|
13
|
+
// Simple regex split -- this is default behaviour
|
|
14
|
+
const regexSimple = new RegExp("".concat(match.split(/(\s+)/).filter(h => h.trim()).map(hl => '(' + (0, _escapeRegExp.default)(hl) + ')').join('|')), 'gi');
|
|
15
|
+
|
|
16
|
+
// Split Elivis "The King" Presley into [Elvis, The King, Presley]
|
|
17
|
+
const regex = new RegExp("".concat(match.split(/(?!\B"[^"]*)\s+(?![^"]*"\B)/).filter(h => h.trim()).map(quotedSection => {
|
|
18
|
+
if (quotedSection.charAt(0) === '"' && quotedSection.charAt(quotedSection.length - 1) === '"') {
|
|
19
|
+
return quotedSection.slice(1, quotedSection.length - 1);
|
|
20
|
+
}
|
|
21
|
+
return quotedSection;
|
|
22
|
+
}).map(hl => '(' + (0, _escapeRegExp.default)(hl) + ')').join('|')), 'gi');
|
|
12
23
|
if (ignoreNull && !match) {
|
|
13
24
|
const nullRegex = /a^/gi; // Should match nothing
|
|
14
25
|
|
|
15
26
|
return [[str], nullRegex];
|
|
16
27
|
}
|
|
17
|
-
|
|
28
|
+
if (simpleSplit) {
|
|
29
|
+
var _str$split;
|
|
30
|
+
return [(_str$split = str.split(regexSimple)) === null || _str$split === void 0 ? void 0 : _str$split.filter(s => s && s.trim()), regexSimple];
|
|
31
|
+
}
|
|
32
|
+
return [(_str$split2 = str.split(regex)) === null || _str$split2 === void 0 ? void 0 : _str$split2.filter(s => s && s.trim()), regex];
|
|
18
33
|
};
|
|
19
34
|
var _default = exports.default = matchString;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@k-int/stripes-kint-components",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.0",
|
|
4
4
|
"description": "Stripes Component library for K-Int specific applications",
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"*.css"
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@semantic-release/npm": "^11.0.0",
|
|
53
53
|
"babel-eslint": "^10.1.0",
|
|
54
54
|
"babel-plugin-const-enum": "^1.0.1",
|
|
55
|
-
"babel-plugin-module-resolver": "^
|
|
55
|
+
"babel-plugin-module-resolver": "^5.0.0",
|
|
56
56
|
"babel-plugin-require-context-hook": "^1.0.0",
|
|
57
57
|
"babel-plugin-transform-async-to-promises": "^0.8.15",
|
|
58
58
|
"babel-polyfill": "^6.26.0",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"react-router-dom": "^5.2.0",
|
|
75
75
|
"redux": "^4.0.0",
|
|
76
76
|
"redux-observable": "^1.2.0",
|
|
77
|
-
"regenerator-runtime": "^0.
|
|
77
|
+
"regenerator-runtime": "^0.14.0",
|
|
78
78
|
"rxjs": "^6.6.3",
|
|
79
79
|
"semantic-release": "^22.0.6",
|
|
80
80
|
"sinon": "^14.0.0",
|
package/renovate.json
ADDED
|
@@ -36,11 +36,15 @@ const EditSettingValue = (props) => {
|
|
|
36
36
|
RefdataComponent = RefdataButtons;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
// Adding default sort to refdata object in ascending order by label
|
|
40
|
+
const sortByLabel = (a, b) => (a.label.localeCompare(b.label));
|
|
41
|
+
const sortedRefdata = refdata.sort(sortByLabel);
|
|
42
|
+
|
|
39
43
|
return (
|
|
40
44
|
<Field
|
|
41
45
|
aria-label={fieldLabel}
|
|
42
46
|
component={RefdataComponent}
|
|
43
|
-
dataOptions={
|
|
47
|
+
dataOptions={sortedRefdata}
|
|
44
48
|
name={`${input.name}.value`}
|
|
45
49
|
/>
|
|
46
50
|
);
|
|
@@ -27,9 +27,14 @@ const FormModal = ({
|
|
|
27
27
|
restart();
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
const handleSaveAndClear = (...onSaveProps) => {
|
|
31
|
+
handleSubmit(...onSaveProps);
|
|
32
|
+
restart();
|
|
33
|
+
};
|
|
34
|
+
|
|
30
35
|
const renderFooter = () => {
|
|
31
36
|
if (footer) {
|
|
32
|
-
return footer({ formState, handleSubmit, handleClose });
|
|
37
|
+
return footer({ formState, handleSubmit: handleSaveAndClear, handleClose, handleSubmitNoRestart: handleSubmit });
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
const { invalid, pristine, submitting } = formState;
|
|
@@ -39,7 +44,7 @@ const FormModal = ({
|
|
|
39
44
|
buttonStyle="primary"
|
|
40
45
|
disabled={submitting || invalid || pristine}
|
|
41
46
|
marginBottom0
|
|
42
|
-
onClick={
|
|
47
|
+
onClick={handleSaveAndClear}
|
|
43
48
|
type="submit"
|
|
44
49
|
>
|
|
45
50
|
{kintIntl.formatKintMessage({
|
|
@@ -61,18 +66,14 @@ const FormModal = ({
|
|
|
61
66
|
};
|
|
62
67
|
|
|
63
68
|
return (
|
|
64
|
-
<
|
|
65
|
-
|
|
69
|
+
<Modal
|
|
70
|
+
enforceFocus={false}
|
|
71
|
+
footer={renderFooter()}
|
|
72
|
+
onClose={handleClose}
|
|
73
|
+
{...modalProps}
|
|
66
74
|
>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
footer={renderFooter()}
|
|
70
|
-
onClose={handleClose}
|
|
71
|
-
{...modalProps}
|
|
72
|
-
>
|
|
73
|
-
{children}
|
|
74
|
-
</Modal>
|
|
75
|
-
</form>
|
|
75
|
+
{children}
|
|
76
|
+
</Modal>
|
|
76
77
|
);
|
|
77
78
|
}}
|
|
78
79
|
</Form>
|
|
@@ -44,6 +44,7 @@ const SASQLookupComponent = forwardRef((props, ref) => {
|
|
|
44
44
|
noSearchField,
|
|
45
45
|
persistedPanesetProps = {},
|
|
46
46
|
RenderBody,
|
|
47
|
+
rowNavigation = true, // Default navigation onRowClick
|
|
47
48
|
sasqProps,
|
|
48
49
|
searchFieldAriaLabel,
|
|
49
50
|
searchFieldProps
|
|
@@ -266,6 +267,7 @@ const SASQLookupComponent = forwardRef((props, ref) => {
|
|
|
266
267
|
intlNS={passedIntlNS}
|
|
267
268
|
labelOverrides={labelOverrides}
|
|
268
269
|
query={query}
|
|
270
|
+
rowNavigation={rowNavigation}
|
|
269
271
|
toggleFilterPane={toggleFilterPane}
|
|
270
272
|
{...restOfInfiniteQueryProps}
|
|
271
273
|
{...sasqRenderProps}
|
|
@@ -320,6 +322,7 @@ SASQLookupComponent.propTypes = {
|
|
|
320
322
|
]),
|
|
321
323
|
resource: PropTypes.object,
|
|
322
324
|
resultColumns: PropTypes.arrayOf(PropTypes.object),
|
|
325
|
+
rowNavigation: PropTypes.bool,
|
|
323
326
|
sasqProps: PropTypes.object,
|
|
324
327
|
searchFieldAriaLabel: PropTypes.string,
|
|
325
328
|
searchFieldProps: PropTypes.object
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
1
2
|
import PropTypes from 'prop-types';
|
|
2
3
|
|
|
3
4
|
import { useHistory, useLocation } from 'react-router-dom';
|
|
@@ -18,10 +19,14 @@ const TableBody = ({
|
|
|
18
19
|
isLoading,
|
|
19
20
|
labelOverrides = {},
|
|
20
21
|
match,
|
|
21
|
-
mclProps
|
|
22
|
+
mclProps: {
|
|
23
|
+
formatter = {},
|
|
24
|
+
...mclProps
|
|
25
|
+
},
|
|
22
26
|
onSort,
|
|
23
27
|
path,
|
|
24
28
|
resultColumns,
|
|
29
|
+
rowNavigation = true, // Default navigation onRowClick
|
|
25
30
|
toggleFilterPane,
|
|
26
31
|
query,
|
|
27
32
|
}) => {
|
|
@@ -41,12 +46,45 @@ const TableBody = ({
|
|
|
41
46
|
// Build the list of visible columns
|
|
42
47
|
const visibleColumns = resultColumns.map(e => e.propertyPath);
|
|
43
48
|
|
|
49
|
+
const getRowUrl = useCallback((rowData) => {
|
|
50
|
+
const baseUrl = `${path}/${rowData?.id}`;
|
|
51
|
+
return {
|
|
52
|
+
url: `${baseUrl}${location?.search}`,
|
|
53
|
+
path,
|
|
54
|
+
baseUrl,
|
|
55
|
+
location
|
|
56
|
+
};
|
|
57
|
+
}, [location, path]);
|
|
58
|
+
|
|
59
|
+
const getEnhancedFormatter = useCallback(() => {
|
|
60
|
+
const enhancedFormatter = {};
|
|
61
|
+
for (const [key, value] of Object.entries(formatter)) {
|
|
62
|
+
enhancedFormatter[key] = (item) => value({ ...item, defaultRowUrl: getRowUrl(item) });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return enhancedFormatter;
|
|
66
|
+
}, [formatter, getRowUrl]);
|
|
67
|
+
|
|
68
|
+
const getOnRowClick = useCallback(() => {
|
|
69
|
+
if (rowNavigation) {
|
|
70
|
+
return (_e, rowData) => {
|
|
71
|
+
history.push(getRowUrl(rowData).url);
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return null;
|
|
76
|
+
}, [getRowUrl, history, rowNavigation]);
|
|
77
|
+
|
|
78
|
+
const isSelected = useCallback(({ item }) => item.id === match?.params?.id, [match?.params?.id]);
|
|
79
|
+
|
|
44
80
|
return (
|
|
45
81
|
<MultiColumnList
|
|
46
82
|
autosize
|
|
47
83
|
columnMapping={columnMapping}
|
|
48
84
|
contentData={data?.results}
|
|
85
|
+
formatter={getEnhancedFormatter()} // Pass enhanced formatter
|
|
49
86
|
hasMargin
|
|
87
|
+
interactive={rowNavigation}
|
|
50
88
|
isEmptyMessage={
|
|
51
89
|
<NoResultsMessage
|
|
52
90
|
{...{
|
|
@@ -62,12 +100,10 @@ const TableBody = ({
|
|
|
62
100
|
}}
|
|
63
101
|
/>
|
|
64
102
|
}
|
|
65
|
-
isSelected={
|
|
103
|
+
isSelected={isSelected}
|
|
66
104
|
onHeaderClick={onSort}
|
|
67
105
|
onNeedMoreData={onNeedMoreData}
|
|
68
|
-
onRowClick={(
|
|
69
|
-
history.push(`${path}/${rowData?.id}${location?.search}`);
|
|
70
|
-
}}
|
|
106
|
+
onRowClick={getOnRowClick()}
|
|
71
107
|
pagingType="click"
|
|
72
108
|
sortDirection={sortOrder.startsWith('-') ? 'descending' : 'ascending'}
|
|
73
109
|
sortOrder={sortOrder.replace(/^-/, '').replace(/,.*/, '')}
|
|
@@ -99,6 +135,7 @@ TableBody.propTypes = {
|
|
|
99
135
|
path: PropTypes.string.isRequired,
|
|
100
136
|
query: PropTypes.object,
|
|
101
137
|
resultColumns: PropTypes.arrayOf(PropTypes.object),
|
|
138
|
+
rowNavigation: PropTypes.bool,
|
|
102
139
|
toggleFilterPane: PropTypes.func
|
|
103
140
|
};
|
|
104
141
|
|
|
@@ -1,38 +1,54 @@
|
|
|
1
1
|
import matchString from './matchString';
|
|
2
2
|
|
|
3
|
-
const highlightString = (match, str, ignoreNull = true) => {
|
|
4
|
-
const [parts, regex] = matchString(match, str, ignoreNull);
|
|
3
|
+
const highlightString = (match, str, ignoreNull = true, simpleSplit = true) => {
|
|
4
|
+
const [parts, regex] = matchString(match, str, ignoreNull, simpleSplit);
|
|
5
5
|
|
|
6
6
|
return (
|
|
7
|
-
parts.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
parts.map((part, i) => {
|
|
8
|
+
// RegExp is stateful, set up a new one to work with
|
|
9
|
+
const immutableRegex = new RegExp(regex);
|
|
10
|
+
if (immutableRegex.exec(part) !== null) {
|
|
11
|
+
return (
|
|
12
|
+
<mark
|
|
13
|
+
key={i}
|
|
14
|
+
>
|
|
15
|
+
{part}
|
|
16
|
+
</mark>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (
|
|
14
21
|
<span key={i}>
|
|
15
22
|
{part}
|
|
16
23
|
</span>
|
|
17
|
-
|
|
24
|
+
);
|
|
25
|
+
})
|
|
18
26
|
);
|
|
19
27
|
};
|
|
20
28
|
|
|
21
|
-
const boldString = (match, str, ignoreNull = true) => {
|
|
22
|
-
const [parts, regex] = matchString(match, str, ignoreNull);
|
|
29
|
+
const boldString = (match, str, ignoreNull = true, simpleSplit = true) => {
|
|
30
|
+
const [parts, regex] = matchString(match, str, ignoreNull, simpleSplit);
|
|
23
31
|
|
|
24
32
|
return (
|
|
25
|
-
parts.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
parts.map((part, i) => {
|
|
34
|
+
// RegExp is stateful, set up a new one to work with
|
|
35
|
+
const immutableRegex = new RegExp(regex);
|
|
36
|
+
if (immutableRegex.exec(part) !== null) {
|
|
37
|
+
return (
|
|
38
|
+
<strong
|
|
39
|
+
key={i}
|
|
40
|
+
>
|
|
41
|
+
{part}
|
|
42
|
+
</strong>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return (
|
|
32
47
|
<span key={i}>
|
|
33
48
|
{part}
|
|
34
49
|
</span>
|
|
35
|
-
|
|
50
|
+
);
|
|
51
|
+
})
|
|
36
52
|
);
|
|
37
53
|
};
|
|
38
54
|
|
|
@@ -1,14 +1,35 @@
|
|
|
1
1
|
import escapeRegExp from 'lodash/escapeRegExp';
|
|
2
2
|
|
|
3
|
-
const matchString = (match, str, ignoreNull = true) => {
|
|
4
|
-
|
|
3
|
+
const matchString = (match, str, ignoreNull = true, simpleSplit = true) => {
|
|
4
|
+
// Simple regex split -- this is default behaviour
|
|
5
|
+
const regexSimple = new RegExp(`${match.split(/(\s+)/).filter(h => h.trim()).map(hl => '(' + escapeRegExp(hl) + ')').join('|')}`, 'gi');
|
|
6
|
+
|
|
7
|
+
// Split Elivis "The King" Presley into [Elvis, The King, Presley]
|
|
8
|
+
const regex = new RegExp(`${
|
|
9
|
+
match.split(/(?!\B"[^"]*)\s+(?![^"]*"\B)/)
|
|
10
|
+
.filter(h => h.trim())
|
|
11
|
+
.map(quotedSection => {
|
|
12
|
+
if (quotedSection.charAt(0) === '"' && quotedSection.charAt(quotedSection.length - 1) === '"') {
|
|
13
|
+
return quotedSection.slice(1, quotedSection.length - 1);
|
|
14
|
+
}
|
|
15
|
+
return quotedSection;
|
|
16
|
+
})
|
|
17
|
+
.map(hl => '(' + escapeRegExp(hl) + ')')
|
|
18
|
+
.join('|')
|
|
19
|
+
}`,
|
|
20
|
+
'gi');
|
|
21
|
+
|
|
5
22
|
if (ignoreNull && !match) {
|
|
6
23
|
const nullRegex = /a^/gi; // Should match nothing
|
|
7
24
|
|
|
8
25
|
return [[str], nullRegex];
|
|
9
26
|
}
|
|
10
27
|
|
|
11
|
-
|
|
28
|
+
if (simpleSplit) {
|
|
29
|
+
return [str.split(regexSimple)?.filter(s => s && s.trim()), regexSimple];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return [str.split(regex)?.filter(s => s && s.trim()), regex];
|
|
12
33
|
};
|
|
13
34
|
|
|
14
35
|
export default matchString;
|