@k-int/stripes-kint-components 2.3.1 → 2.4.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 +15 -1
- package/es/index.js +26 -2
- package/es/lib/ActionList/ActionListFieldArray.js +3 -4
- package/es/lib/CustomProperties/Config/CustomPropertiesSettings.js +9 -6
- package/es/lib/CustomProperties/View/CustomPropertiesViewCtx.js +22 -15
- package/es/lib/CustomProperties/View/CustomPropertyCard.js +3 -2
- package/es/lib/FormModal/FormModal.js +2 -0
- package/es/lib/SASQLookupComponent/SASQLookupComponent.js +61 -105
- package/es/lib/SASQLookupComponent/TableBody/TableBody.js +146 -0
- package/es/lib/SASQLookupComponent/TableBody/index.js +19 -0
- package/es/lib/SASQLookupComponent/index.js +9 -1
- package/es/lib/SASQRoute/SASQRoute.js +2 -2
- package/es/lib/utils/highlightString.js +94 -0
- package/es/lib/utils/index.js +23 -1
- package/es/lib/utils/matchString.js +59 -0
- package/package.json +1 -1
- package/src/index.js +6 -1
- package/src/lib/ActionList/ActionListFieldArray.js +2 -3
- package/src/lib/CustomProperties/Config/CustomPropertiesSettings.js +9 -6
- package/src/lib/CustomProperties/View/CustomPropertiesViewCtx.js +13 -8
- package/src/lib/CustomProperties/View/CustomPropertyCard.js +2 -2
- package/src/lib/FormModal/FormModal.js +2 -0
- package/src/lib/SASQLookupComponent/SASQLookupComponent.js +39 -77
- package/src/lib/SASQLookupComponent/TableBody/TableBody.js +96 -0
- package/src/lib/SASQLookupComponent/TableBody/index.js +1 -0
- package/src/lib/SASQLookupComponent/index.js +2 -1
- package/src/lib/SASQRoute/SASQRoute.js +1 -1
- package/src/lib/utils/highlightString.js +42 -0
- package/src/lib/utils/index.js +4 -0
- package/src/lib/utils/matchString.js +14 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import PropTypes from 'prop-types';
|
|
3
2
|
import { FormattedMessage } from 'react-intl';
|
|
4
3
|
import { useInfiniteQuery } from 'react-query';
|
|
@@ -17,34 +16,30 @@ import {
|
|
|
17
16
|
Button,
|
|
18
17
|
IconButton,
|
|
19
18
|
Icon,
|
|
20
|
-
MultiColumnList,
|
|
21
19
|
Pane,
|
|
22
20
|
PaneMenu,
|
|
23
21
|
SearchField,
|
|
24
22
|
} from '@folio/stripes/components';
|
|
25
|
-
import NoResultsMessage from '../NoResultsMessage';
|
|
26
23
|
|
|
27
24
|
import { generateKiwtQuery } from '../utils';
|
|
28
25
|
import { useKiwtSASQuery, useLocalStorageState } from '../hooks';
|
|
29
26
|
|
|
27
|
+
import TableBody from './TableBody';
|
|
28
|
+
|
|
29
|
+
const SASQLookupComponent = (props) => {
|
|
30
|
+
const {
|
|
31
|
+
children,
|
|
32
|
+
fetchParameters = {},
|
|
33
|
+
FilterComponent = () => null,
|
|
34
|
+
FilterPaneHeaderComponent = () => null,
|
|
35
|
+
filterPaneProps,
|
|
36
|
+
id,
|
|
37
|
+
mainPaneProps,
|
|
38
|
+
noSearchField,
|
|
39
|
+
RenderBody,
|
|
40
|
+
sasqProps,
|
|
41
|
+
} = props;
|
|
30
42
|
|
|
31
|
-
const SASQLookupComponent = ({
|
|
32
|
-
children,
|
|
33
|
-
fetchParameters = {},
|
|
34
|
-
FilterPaneHeaderComponent = () => null,
|
|
35
|
-
FilterComponent = () => null,
|
|
36
|
-
history,
|
|
37
|
-
id,
|
|
38
|
-
location,
|
|
39
|
-
mainPaneProps,
|
|
40
|
-
match,
|
|
41
|
-
mclProps,
|
|
42
|
-
noSearchField,
|
|
43
|
-
path,
|
|
44
|
-
resultColumns = [],
|
|
45
|
-
RenderBody,
|
|
46
|
-
sasqProps,
|
|
47
|
-
}) => {
|
|
48
43
|
const { query, queryGetter, querySetter } = useKiwtSASQuery();
|
|
49
44
|
const { 0: namespace } = useNamespace();
|
|
50
45
|
const ky = useOkapiKy();
|
|
@@ -62,10 +57,7 @@ const SASQLookupComponent = ({
|
|
|
62
57
|
|
|
63
58
|
const {
|
|
64
59
|
data: totalData = {},
|
|
65
|
-
|
|
66
|
-
isError,
|
|
67
|
-
isLoading,
|
|
68
|
-
fetchNextPage,
|
|
60
|
+
...restOfInfiniteQueryProps
|
|
69
61
|
} = useInfiniteQuery(
|
|
70
62
|
[namespace, id, 'data', query],
|
|
71
63
|
fetchPageData
|
|
@@ -93,20 +85,6 @@ const SASQLookupComponent = ({
|
|
|
93
85
|
{}
|
|
94
86
|
) ?? {};
|
|
95
87
|
|
|
96
|
-
// TODO focus handling to stop redraw movin to top
|
|
97
|
-
|
|
98
|
-
const onNeedMoreData = (_askAmount, index) => {
|
|
99
|
-
fetchNextPage({ pageParam: index });
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
// Build the map of column definitions
|
|
103
|
-
const columnMapping = Object.fromEntries(
|
|
104
|
-
resultColumns.map(e => [e.propertyPath, e.label])
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
// Build the list of visible columns
|
|
108
|
-
const visibleColumns = resultColumns.map(e => e.propertyPath);
|
|
109
|
-
|
|
110
88
|
return (
|
|
111
89
|
<SearchAndSortQuery
|
|
112
90
|
initialSearchState={{ query: '' }}
|
|
@@ -115,56 +93,23 @@ const SASQLookupComponent = ({
|
|
|
115
93
|
{...sasqProps}
|
|
116
94
|
>
|
|
117
95
|
{
|
|
118
|
-
({
|
|
96
|
+
(sasqRenderProps) => {
|
|
97
|
+
const {
|
|
119
98
|
activeFilters,
|
|
120
99
|
filterChanged,
|
|
121
100
|
getFilterHandlers,
|
|
122
101
|
getSearchHandlers,
|
|
123
|
-
onSort,
|
|
124
102
|
onSubmitSearch,
|
|
125
103
|
resetAll,
|
|
126
104
|
searchChanged,
|
|
127
105
|
searchValue
|
|
128
|
-
}
|
|
106
|
+
} = sasqRenderProps;
|
|
107
|
+
|
|
129
108
|
const searchHandlers = getSearchHandlers();
|
|
130
|
-
const sortOrder = query.sort ?? '';
|
|
131
109
|
const disableReset = !filterChanged && !searchChanged;
|
|
132
110
|
|
|
133
111
|
const filterCount = activeFilters.string ? activeFilters.string.split(',').length : 0;
|
|
134
112
|
|
|
135
|
-
const TableBody = () => (
|
|
136
|
-
<MultiColumnList
|
|
137
|
-
autosize
|
|
138
|
-
columnMapping={columnMapping}
|
|
139
|
-
contentData={data?.results}
|
|
140
|
-
isEmptyMessage={
|
|
141
|
-
<NoResultsMessage
|
|
142
|
-
{...{
|
|
143
|
-
error,
|
|
144
|
-
isError,
|
|
145
|
-
isLoading,
|
|
146
|
-
filterPaneIsVisible: filterPaneVisible,
|
|
147
|
-
searchTerm: query.query,
|
|
148
|
-
toggleFilterPane
|
|
149
|
-
}}
|
|
150
|
-
/>
|
|
151
|
-
}
|
|
152
|
-
isSelected={({ item }) => item.id === match?.params?.id}
|
|
153
|
-
onHeaderClick={onSort}
|
|
154
|
-
onNeedMoreData={onNeedMoreData}
|
|
155
|
-
onRowClick={(_e, rowData) => {
|
|
156
|
-
history.push(`${path}/${rowData?.id}${location?.search}`);
|
|
157
|
-
}}
|
|
158
|
-
pagingType="click"
|
|
159
|
-
sortDirection={sortOrder.startsWith('-') ? 'descending' : 'ascending'}
|
|
160
|
-
sortOrder={sortOrder.replace(/^-/, '').replace(/,.*/, '')}
|
|
161
|
-
totalCount={data.totalRecords}
|
|
162
|
-
virtualize
|
|
163
|
-
visibleColumns={visibleColumns}
|
|
164
|
-
{...mclProps}
|
|
165
|
-
/>
|
|
166
|
-
);
|
|
167
|
-
|
|
168
113
|
const Body = RenderBody ?? TableBody;
|
|
169
114
|
|
|
170
115
|
return (
|
|
@@ -184,6 +129,7 @@ const SASQLookupComponent = ({
|
|
|
184
129
|
</PaneMenu>
|
|
185
130
|
}
|
|
186
131
|
paneTitle={<FormattedMessage id="stripes-smart-components.searchAndFilter" />}
|
|
132
|
+
{...filterPaneProps}
|
|
187
133
|
>
|
|
188
134
|
<form onSubmit={onSubmitSearch}>
|
|
189
135
|
<FilterPaneHeaderComponent />
|
|
@@ -192,7 +138,13 @@ const SASQLookupComponent = ({
|
|
|
192
138
|
<SearchField
|
|
193
139
|
autoFocus
|
|
194
140
|
name="query"
|
|
195
|
-
onChange={
|
|
141
|
+
onChange={e => {
|
|
142
|
+
if (e.target?.value) {
|
|
143
|
+
searchHandlers.query(e); // SASQ needs the whole event here
|
|
144
|
+
} else {
|
|
145
|
+
searchHandlers.reset();
|
|
146
|
+
}
|
|
147
|
+
}}
|
|
196
148
|
onClear={searchHandlers.reset}
|
|
197
149
|
value={searchValue.query}
|
|
198
150
|
/>
|
|
@@ -240,10 +192,19 @@ const SASQLookupComponent = ({
|
|
|
240
192
|
</PaneMenu>
|
|
241
193
|
:
|
|
242
194
|
null}
|
|
195
|
+
noOverflow
|
|
196
|
+
padContent={false}
|
|
243
197
|
paneSub={<FormattedMessage id="stripes-kint-components.sasqLookupComponent.mainPane.found" values={{ total: data?.total }} />}
|
|
244
198
|
{...mainPaneProps}
|
|
245
199
|
>
|
|
246
|
-
<Body
|
|
200
|
+
<Body
|
|
201
|
+
data={data}
|
|
202
|
+
query={query}
|
|
203
|
+
toggleFilterPane={toggleFilterPane}
|
|
204
|
+
{...restOfInfiniteQueryProps}
|
|
205
|
+
{...sasqProps}
|
|
206
|
+
{...props}
|
|
207
|
+
/>
|
|
247
208
|
</Pane>
|
|
248
209
|
{children}
|
|
249
210
|
</PersistedPaneset>
|
|
@@ -260,6 +221,7 @@ SASQLookupComponent.propTypes = {
|
|
|
260
221
|
PropTypes.node
|
|
261
222
|
]),
|
|
262
223
|
fetchParameters: PropTypes.object,
|
|
224
|
+
filterPaneProps: PropTypes.object,
|
|
263
225
|
FilterComponent: PropTypes.oneOfType([
|
|
264
226
|
PropTypes.func,
|
|
265
227
|
PropTypes.node
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import PropTypes from 'prop-types';
|
|
2
|
+
|
|
3
|
+
import { useHistory, useLocation } from 'react-router-dom';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
MultiColumnList,
|
|
7
|
+
} from '@folio/stripes/components';
|
|
8
|
+
import NoResultsMessage from '../../NoResultsMessage';
|
|
9
|
+
|
|
10
|
+
const TableBody = ({
|
|
11
|
+
data,
|
|
12
|
+
error,
|
|
13
|
+
fetchNextPage,
|
|
14
|
+
filterPaneVisible,
|
|
15
|
+
isError,
|
|
16
|
+
isLoading,
|
|
17
|
+
match,
|
|
18
|
+
mclProps,
|
|
19
|
+
onSort,
|
|
20
|
+
path,
|
|
21
|
+
resultColumns,
|
|
22
|
+
toggleFilterPane,
|
|
23
|
+
query,
|
|
24
|
+
}) => {
|
|
25
|
+
const sortOrder = query.sort ?? '';
|
|
26
|
+
const history = useHistory();
|
|
27
|
+
const location = useLocation();
|
|
28
|
+
|
|
29
|
+
const onNeedMoreData = (_askAmount, index) => {
|
|
30
|
+
fetchNextPage({ pageParam: index });
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Build the map of column definitions
|
|
34
|
+
const columnMapping = Object.fromEntries(
|
|
35
|
+
resultColumns.map(e => [e.propertyPath, e.label])
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Build the list of visible columns
|
|
39
|
+
const visibleColumns = resultColumns.map(e => e.propertyPath);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<MultiColumnList
|
|
43
|
+
autosize
|
|
44
|
+
columnMapping={columnMapping}
|
|
45
|
+
contentData={data?.results}
|
|
46
|
+
hasMargin
|
|
47
|
+
isEmptyMessage={
|
|
48
|
+
<NoResultsMessage
|
|
49
|
+
{...{
|
|
50
|
+
error,
|
|
51
|
+
isError,
|
|
52
|
+
isLoading,
|
|
53
|
+
filterPaneIsVisible: filterPaneVisible,
|
|
54
|
+
searchTerm: query.query,
|
|
55
|
+
toggleFilterPane
|
|
56
|
+
}}
|
|
57
|
+
/>
|
|
58
|
+
}
|
|
59
|
+
isSelected={({ item }) => item.id === match?.params?.id}
|
|
60
|
+
onHeaderClick={onSort}
|
|
61
|
+
onNeedMoreData={onNeedMoreData}
|
|
62
|
+
onRowClick={(_e, rowData) => {
|
|
63
|
+
history.push(`${path}/${rowData?.id}${location?.search}`);
|
|
64
|
+
}}
|
|
65
|
+
pagingType="click"
|
|
66
|
+
sortDirection={sortOrder.startsWith('-') ? 'descending' : 'ascending'}
|
|
67
|
+
sortOrder={sortOrder.replace(/^-/, '').replace(/,.*/, '')}
|
|
68
|
+
totalCount={data.totalRecords}
|
|
69
|
+
visibleColumns={visibleColumns}
|
|
70
|
+
{...mclProps}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
TableBody.propTypes = {
|
|
76
|
+
data: PropTypes.shape({
|
|
77
|
+
totalRecords: PropTypes.number,
|
|
78
|
+
results: PropTypes.arrayOf(PropTypes.object)
|
|
79
|
+
}),
|
|
80
|
+
error: PropTypes.object,
|
|
81
|
+
fetchNextPage: PropTypes.func,
|
|
82
|
+
filterPaneVisible: PropTypes.bool,
|
|
83
|
+
history: PropTypes.object,
|
|
84
|
+
isError: PropTypes.bool,
|
|
85
|
+
isLoading: PropTypes.bool,
|
|
86
|
+
location: PropTypes.object,
|
|
87
|
+
match: PropTypes.object,
|
|
88
|
+
mclProps: PropTypes.object,
|
|
89
|
+
onSort: PropTypes.func,
|
|
90
|
+
path: PropTypes.string.isRequired,
|
|
91
|
+
query: PropTypes.object,
|
|
92
|
+
resultColumns: PropTypes.arrayOf(PropTypes.object),
|
|
93
|
+
toggleFilterPane: PropTypes.func
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export default TableBody;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './TableBody';
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export { default } from './SASQLookupComponent';
|
|
1
|
+
export { default as SASQLookupComponent } from './SASQLookupComponent';
|
|
2
|
+
export { default as TableBody } from './TableBody';
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
Switch
|
|
7
7
|
} from 'react-router-dom';
|
|
8
8
|
|
|
9
|
-
import SASQLookupComponent from '../SASQLookupComponent';
|
|
9
|
+
import { SASQLookupComponent } from '../SASQLookupComponent';
|
|
10
10
|
import SASQViewComponent from '../SASQViewComponent';
|
|
11
11
|
|
|
12
12
|
const SASQRoute = ({ children, path, fetchParameters, ...props }) => {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import matchString from './matchString';
|
|
2
|
+
|
|
3
|
+
const highlightString = (match, str, ignoreNull = true) => {
|
|
4
|
+
const [parts, regex] = matchString(match, str, ignoreNull);
|
|
5
|
+
|
|
6
|
+
return (
|
|
7
|
+
parts.filter(part => part).map((part, i) => (
|
|
8
|
+
regex.test(part) ?
|
|
9
|
+
<mark
|
|
10
|
+
key={i}
|
|
11
|
+
>
|
|
12
|
+
{part}
|
|
13
|
+
</mark> :
|
|
14
|
+
<span key={i}>
|
|
15
|
+
{part}
|
|
16
|
+
</span>
|
|
17
|
+
))
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const boldString = (match, str, ignoreNull = true) => {
|
|
22
|
+
const [parts, regex] = matchString(match, str, ignoreNull);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
parts.filter(part => part).map((part, i) => (
|
|
26
|
+
regex.test(part) ?
|
|
27
|
+
<strong
|
|
28
|
+
key={i}
|
|
29
|
+
>
|
|
30
|
+
{part}
|
|
31
|
+
</strong> :
|
|
32
|
+
<span key={i}>
|
|
33
|
+
{part}
|
|
34
|
+
</span>
|
|
35
|
+
))
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export {
|
|
40
|
+
boldString,
|
|
41
|
+
highlightString
|
|
42
|
+
};
|
package/src/lib/utils/index.js
CHANGED
|
@@ -15,3 +15,7 @@ export { default as groupCustomPropertiesByCtx } from './groupCustomPropertiesBy
|
|
|
15
15
|
export { default as renderHelpText } from './renderHelpText';
|
|
16
16
|
export { default as sortByLabel } from './sortByLabel';
|
|
17
17
|
export { default as toCamelCase } from './toCamelCase'; // I hate that this exists
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
export { default as matchString } from './matchString';
|
|
21
|
+
export { boldString, highlightString } from './highlightString';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import escapeRegExp from 'lodash/escapeRegExp';
|
|
2
|
+
|
|
3
|
+
const matchString = (match, str, ignoreNull = true) => {
|
|
4
|
+
const regex = new RegExp(`${match.split(/(\s+)/).filter(h => h.trim()).map(hl => '(' + escapeRegExp(hl) + ')').join('|')}`, 'gi')
|
|
5
|
+
if (ignoreNull && !match) {
|
|
6
|
+
const nullRegex = /a^/gi; // Should match nothing
|
|
7
|
+
|
|
8
|
+
return [[str], nullRegex];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return [str.split(regex), regex];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default matchString;
|