@k-int/stripes-kint-components 5.23.0 → 5.24.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 +7 -0
- package/es/lib/SASQLookupComponent/SASQLookupComponent.js +53 -18
- package/es/lib/utils/generateKiwtQueryParams/generateKiwtQueryParams.js +15 -1
- package/package.json +1 -1
- package/src/lib/SASQLookupComponent/README.md +58 -53
- package/src/lib/SASQLookupComponent/SASQLookupComponent.js +275 -232
- package/src/lib/utils/generateKiwtQueryParams/generateKiwtQueryParams.js +15 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [5.24.0](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/compare/v5.23.0...v5.24.0) (2025-07-02)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* SASQLookupComponent -- lookupQueryPromise/lookupResponseTransform properties ([565d1d1](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/commit/565d1d1c3da273d7c207bc9cc5646222537c0cc9))
|
|
7
|
+
|
|
1
8
|
# [5.23.0](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/compare/v5.22.0...v5.23.0) (2025-06-25)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -44,6 +44,16 @@ const SASQLookupComponent = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
44
44
|
queryNamespace.push(currentPage);
|
|
45
45
|
return queryNamespace;
|
|
46
46
|
},
|
|
47
|
+
lookupQueryPromise = _ref2 => {
|
|
48
|
+
let {
|
|
49
|
+
endpoint,
|
|
50
|
+
ky,
|
|
51
|
+
queryParams
|
|
52
|
+
} = _ref2;
|
|
53
|
+
return ky.get(`${endpoint}${queryParams}`).json();
|
|
54
|
+
},
|
|
55
|
+
lookupResponseTransform = response => response,
|
|
56
|
+
// Function to transform the response from the query
|
|
47
57
|
mainPaneProps = {},
|
|
48
58
|
mclProps = {},
|
|
49
59
|
noResultsProps = {},
|
|
@@ -70,12 +80,16 @@ const SASQLookupComponent = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
70
80
|
querySetter: sasqPropsQuerySetter,
|
|
71
81
|
syncToLocation = true
|
|
72
82
|
} = sasqProps ?? {};
|
|
83
|
+
|
|
84
|
+
// We manage our internal state of pagination (URL vs MCL page state) using usePrevNextPagination.
|
|
85
|
+
// Below the queryParameterGenerator can then choose to use the outputs (namely totalRecords and page) as it sees fit.
|
|
73
86
|
const {
|
|
74
87
|
currentPage,
|
|
75
88
|
paginationMCLProps,
|
|
76
89
|
paginationSASQProps
|
|
77
90
|
} = (0, _hooks.usePrevNextPagination)({
|
|
78
91
|
count,
|
|
92
|
+
// totalRecord
|
|
79
93
|
pageSize: fetchParameters.SASQ_MAP?.perPage,
|
|
80
94
|
syncToLocation
|
|
81
95
|
});
|
|
@@ -92,10 +106,14 @@ const SASQLookupComponent = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
92
106
|
} = (0, _core.useNamespace)();
|
|
93
107
|
const ky = (0, _core.useOkapiKy)();
|
|
94
108
|
const filterPaneVisibileKey = `${namespace}-${id}-filterPaneVisibility`;
|
|
95
|
-
const queryParams = (0, _react.useMemo)(() => queryParameterGenerator(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
109
|
+
const queryParams = (0, _react.useMemo)(() => queryParameterGenerator(
|
|
110
|
+
// With Typescript this would be a type of SASQ_MAP, and so totalRecords is a valid property in our new shape
|
|
111
|
+
// In generateKiwtQueryParams we can choose to ignore totalRecords, which while being a valid property is not necessary for KIWT queries
|
|
112
|
+
{
|
|
113
|
+
page: currentPage,
|
|
114
|
+
totalRecords: count,
|
|
115
|
+
...fetchParameters.SASQ_MAP
|
|
116
|
+
}, query ?? {}), [count, currentPage, fetchParameters.SASQ_MAP, query, queryParameterGenerator]);
|
|
99
117
|
const [filterPaneVisible, setFilterPaneVisible] = (0, _hooks.useLocalStorageState)(filterPaneVisibileKey, true);
|
|
100
118
|
const toggleFilterPane = () => setFilterPaneVisible(!filterPaneVisible);
|
|
101
119
|
const {
|
|
@@ -109,10 +127,20 @@ const SASQLookupComponent = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
109
127
|
query,
|
|
110
128
|
queryParams
|
|
111
129
|
}), () => {
|
|
112
|
-
return
|
|
130
|
+
return lookupQueryPromise({
|
|
131
|
+
ky,
|
|
132
|
+
queryParams,
|
|
133
|
+
endpoint: fetchParameters.endpoint
|
|
134
|
+
});
|
|
113
135
|
}, {
|
|
114
136
|
enabled: (!!query?.filters || !!query?.query) && !!currentPage,
|
|
115
|
-
...(fetchParameters.queryOptions ?? {})
|
|
137
|
+
...(fetchParameters.queryOptions ?? {}),
|
|
138
|
+
// select is a parameter supported by useQuery to transform the response
|
|
139
|
+
// Could be possible to instead pass this down along with the queryOptions
|
|
140
|
+
// Additionally this is assuming the lookupResponseTransform is a func as opposed to an object
|
|
141
|
+
select: selectData => {
|
|
142
|
+
return lookupResponseTransform(selectData);
|
|
143
|
+
}
|
|
116
144
|
});
|
|
117
145
|
(0, _react.useEffect)(() => {
|
|
118
146
|
if (count !== data?.totalRecords) {
|
|
@@ -169,6 +197,20 @@ const SASQLookupComponent = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
169
197
|
setFilterPaneVisible,
|
|
170
198
|
toggleFilterPane
|
|
171
199
|
};
|
|
200
|
+
const renderFirstMenu = () => {
|
|
201
|
+
if (mainPaneFirstMenu) {
|
|
202
|
+
return mainPaneFirstMenu(internalStateProps);
|
|
203
|
+
}
|
|
204
|
+
if (!filterPaneVisible) {
|
|
205
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.PaneMenu, {
|
|
206
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_smartComponents.ExpandFilterPaneButton, {
|
|
207
|
+
filterCount: filterCount,
|
|
208
|
+
onClick: toggleFilterPane
|
|
209
|
+
})
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
};
|
|
172
214
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_smartComponents.PersistedPaneset, {
|
|
173
215
|
appId: namespace,
|
|
174
216
|
id: `${id}-paneset`,
|
|
@@ -238,12 +280,7 @@ const SASQLookupComponent = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
238
280
|
})
|
|
239
281
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Pane, {
|
|
240
282
|
defaultWidth: "fill",
|
|
241
|
-
firstMenu:
|
|
242
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_smartComponents.ExpandFilterPaneButton, {
|
|
243
|
-
filterCount: filterCount,
|
|
244
|
-
onClick: toggleFilterPane
|
|
245
|
-
})
|
|
246
|
-
}) : null,
|
|
283
|
+
firstMenu: renderFirstMenu(),
|
|
247
284
|
id: `${id}-main-pane`,
|
|
248
285
|
lastMenu: mainPaneLastMenu ? mainPaneLastMenu(internalStateProps) : null,
|
|
249
286
|
noOverflow: true,
|
|
@@ -286,21 +323,19 @@ SASQLookupComponent.propTypes = {
|
|
|
286
323
|
FilterComponent: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.node]),
|
|
287
324
|
FilterPaneHeaderComponent: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.node]),
|
|
288
325
|
queryParameterGenerator: _propTypes.default.func,
|
|
289
|
-
history: _propTypes.default.object,
|
|
290
326
|
id: _propTypes.default.string.isRequired,
|
|
291
327
|
intlKey: _propTypes.default.string,
|
|
292
328
|
intlNS: _propTypes.default.string,
|
|
293
329
|
labelOverrides: _propTypes.default.object,
|
|
294
|
-
|
|
330
|
+
lookupQueryNamespaceGenerator: _propTypes.default.func,
|
|
331
|
+
lookupQueryPromise: _propTypes.default.func,
|
|
332
|
+
lookupResponseTransform: _propTypes.default.func,
|
|
295
333
|
mainPaneProps: _propTypes.default.object,
|
|
296
|
-
match: _propTypes.default.object,
|
|
297
334
|
mclProps: _propTypes.default.object,
|
|
335
|
+
noResultsProps: _propTypes.default.object,
|
|
298
336
|
noSearchField: _propTypes.default.bool,
|
|
299
|
-
path: _propTypes.default.string.isRequired,
|
|
300
337
|
persistedPanesetProps: _propTypes.default.object,
|
|
301
338
|
RenderBody: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.node]),
|
|
302
|
-
resource: _propTypes.default.object,
|
|
303
|
-
resultColumns: _propTypes.default.arrayOf(_propTypes.default.object),
|
|
304
339
|
rowNavigation: _propTypes.default.bool,
|
|
305
340
|
sasqProps: _propTypes.default.object,
|
|
306
341
|
searchableIndexes: _propTypes.default.arrayOf(_propTypes.default.shape({
|
|
@@ -53,6 +53,18 @@ const buildFilterOptionBlock = function (opf) {
|
|
|
53
53
|
}
|
|
54
54
|
return null;
|
|
55
55
|
};
|
|
56
|
+
|
|
57
|
+
/*
|
|
58
|
+
* GenerateKiwtQueryParams accepts
|
|
59
|
+
* SASQ_MAP shape "options" -- TODO write a TS shape for this
|
|
60
|
+
* SASQ "nsValues" shape "nsValues" -- TODO write a TS shape for this
|
|
61
|
+
* boolean "encode"
|
|
62
|
+
* It then uses these props to generate a query string for sending to KIWT type doTheLookupEndpoints
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
// For now we can store the "safe to ignore" keys from the normal SASQ_MAP shape here.
|
|
66
|
+
// These will be ignored rather than appended directly to the query as per normal.
|
|
67
|
+
const keysToIgnore = ['totalRecords'];
|
|
56
68
|
const generateKiwtQueryParams = function (options, nsValues) {
|
|
57
69
|
let encode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
58
70
|
const {
|
|
@@ -185,7 +197,9 @@ const generateKiwtQueryParams = function (options, nsValues) {
|
|
|
185
197
|
paramsArray.push('stats=true');
|
|
186
198
|
}
|
|
187
199
|
for (const [key, value] of Object.entries(rest)) {
|
|
188
|
-
|
|
200
|
+
if (!keysToIgnore.includes(key)) {
|
|
201
|
+
paramsArray.push(`${key}=${conditionalEncodeURIComponent(value, encode)}`);
|
|
202
|
+
}
|
|
189
203
|
}
|
|
190
204
|
return paramsArray;
|
|
191
205
|
};
|
package/package.json
CHANGED
|
@@ -46,58 +46,64 @@ const MyLookupView = () => {
|
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
export default MyLookupView;
|
|
49
|
-
|
|
49
|
+
````
|
|
50
50
|
|
|
51
51
|
In this example, **SASQLookupComponent**:
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
* Uses `fetchParameters` to configure data fetching.
|
|
54
|
+
* Provides a custom filter interface via `FilterComponent`.
|
|
55
|
+
* Renders results using a custom table body (or defaults to an internal **TableBody**).
|
|
56
|
+
* Manages pagination and query state via hooks like `usePrevNextPagination` and `useKiwtSASQuery`.
|
|
57
57
|
|
|
58
58
|
## Props
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
79
|
-
| `
|
|
80
|
-
| `
|
|
81
|
-
| `
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
84
|
-
|
|
85
|
-
|
|
59
|
+
| Name | Type | Description | Default | Required |
|
|
60
|
+
|---------------------------------|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------|----------|
|
|
61
|
+
| `id` | `string` | A unique identifier for the lookup instance. Used to generate unique keys for query state, persistent paneset, and filter pane visibility in local storage. | | ✓ |
|
|
62
|
+
| `fetchParameters` | `object` | An object that defines the endpoints and SASQ configuration used for fetching data. It must include:\<br\>\<br\>• **endpoint:** The URL used to fetch the main data set. This is effectively required for data fetching to work.\<br\>• **SASQ\_MAP:** An object containing settings for search, filter, pagination (e.g., `searchKey`, `perPage`, etc.). | `{}` | ✕ |
|
|
63
|
+
| `FilterComponent` | `func` or `node` | A custom component used to render additional filtering options in the filter pane. This component receives props for managing active filters, search state, and resetting filters. | `() => null` | ✕ |
|
|
64
|
+
| `FilterPaneHeaderComponent` | `func` or `node` | A component rendered at the top of the filter pane. Use this to customize the header area of the filter pane. | `() => null` | ✕ |
|
|
65
|
+
| `filterPaneProps` | `object` | Additional props to be passed to the filter pane. These props can customize the appearance and behavior of the filter pane (such as first or last menu elements). | `{}` | ✕ |
|
|
66
|
+
| `intlKey` | `string` | A base internationalization key used by the internal `useKintIntl` hook to resolve localized messages (e.g., for labels or pane titles). | | ✕ |
|
|
67
|
+
| `intlNS` | `string` | An internationalization namespace used by the internal `useKintIntl` hook. | | ✕ |
|
|
68
|
+
| `labelOverrides` | `object` | An object for overriding default labels, such as the text for displaying the count of found values. | `{}` | ✕ |
|
|
69
|
+
| `lookupQueryNamespaceGenerator` | `func` | A function that generates a query namespace (an array) for `react-query` based on provided parameters such as `currentPage`, `namespace`, `id`, `query`, etc. This ensures that queries are uniquely identified. | See default implementation in source code | ✕ |
|
|
70
|
+
| `lookupQueryPromise` | `func` | A function to execute the data fetching promise. Receives an object with `endpoint`, `ky` (OkapiKy instance), `queryParams`. Should return a Promise that resolves to the fetched data. This is in place to allow for varying fetch methodologies, such as implementing a non-FOLIO ky instance. | See default implementation in source code | ✕ |
|
|
71
|
+
| `lookupResponseTransform` | `func` | A function passed to the "select" prop of react-query useQuery, allowing for direct transformation of the return shape of data. | response => response | ✕ |
|
|
72
|
+
| `mainPaneProps` | `object` | Additional props to be passed to the main pane containing the lookup results. This can include custom menu elements or styling. | `{}` | ✕ |
|
|
73
|
+
| `mclProps` | `object` | Custom properties to be passed to the underlying Multi-Column List (MCL) component. These properties are merged with pagination props derived from `usePrevNextPagination`. | `{}` | ✕ |
|
|
74
|
+
| `noResultsProps` | `object` | Props to be passed down to the [NoResultsMessage](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/-/tree/main/src/lib/NoResultsMessage) splash screen component rendered when no results are present from the query. If `component` is passed, this will be rendered with the props available to `NoResultsMessage`. | `{}` | ✕ |
|
|
75
|
+
| `noSearchField` | `bool` | When set to `true`, the search field is not rendered in the filter pane. Use this if you want to disable search input. | `false` | ✕ |
|
|
76
|
+
| `persistedPanesetProps` | `object` | Additional props to be passed to the **PersistedPaneset** component, which manages the persistent layout of the filter and main panes. | `{}` | ✕ |
|
|
77
|
+
| `queryParameterGenerator` | `func` | A function that takes the SASQ\_MAP configuration and current query values to generate an array of query parameters for the fetch call. Defaults to `generateKiwtQuery`. | `generateKiwtQuery` | ✕ |
|
|
78
|
+
| `RenderBody` | `func` or `node` | A component used to render the body of the main pane (typically a table). If not provided, the internal **TableBody** component is used. | `TableBody` | ✕ |
|
|
79
|
+
| `rowNavigation` | `bool` | Flag to enable or disable row navigation. When enabled, clicking on a row triggers navigation to a detailed view. | `true` | ✕ |
|
|
80
|
+
| `sasqProps` | `object` | Additional props to override or extend the default SASQ query behavior. These props can include custom query values, setters, getters, and `initialSortState`. | | ✕ |
|
|
81
|
+
| `searchableIndexes` | `arrayOf(object)` | An array of objects defining the options for the search index selection component (`SearchKeyControl`), rendered below the search field. Each object typically has `key` and `label` keys. If empty or omitted, the qindex checkboxes are not shown. | `[]` | ✕ |
|
|
82
|
+
| `searchFieldAriaLabel` | `string` | Accessibility label for the search field. | | ✕ |
|
|
83
|
+
| `searchFieldProps` | `object` | Additional props to be passed to the **SearchField** component for customizing its behavior or styling. | `{}` | ✕ |
|
|
84
|
+
| `children` | `node`, `func` | Optional children to be rendered below the main pane. These are rendered within the **PersistedPaneset** container. | | ✕ |
|
|
85
|
+
| `history` | `object` | (Provided by React Router) The history object. | | ✕ |
|
|
86
|
+
| `location` | `object` | (Provided by React Router) The location object. | | ✕ |
|
|
87
|
+
| `match` | `object` | (Provided by React Router) The match object. | | ✕ |
|
|
88
|
+
| `path` | `string` | (Provided by React Router) The path for the current route. | | ✓ |
|
|
89
|
+
| `resource` | `object` | (Provided by Stripes) The resource object, typically containing data and metadata for the current resource. | | ✕ |
|
|
90
|
+
| `resultColumns` | `arrayOf(object)` | An array of objects defining the columns for the MCL component, typically used by `RenderBody` (e.g., `TableBody`). | | ✕ |
|
|
86
91
|
|
|
87
92
|
## Exposed Ref Functionality
|
|
88
93
|
|
|
89
94
|
**SASQLookupComponent** uses `forwardRef` and `useImperativeHandle` to expose specific properties to parent components. This allows external components to access certain internal states and query-related information directly. The ref object includes the following properties:
|
|
90
95
|
|
|
91
|
-
|
|
96
|
+
* **`lookupQueryProps`**:
|
|
92
97
|
An object containing:
|
|
93
|
-
- **`data`**: The latest data fetched by the component.
|
|
94
|
-
- Additional query-related properties returned from `useQuery` (such as loading state, error, etc.).
|
|
95
98
|
|
|
96
|
-
|
|
97
|
-
The array of query parameters generated by the component, based on the provided SASQ configuration and current query state. This reflects the current filters, pagination, and search criteria used for the data fetch.
|
|
99
|
+
* **`data`**: The latest data fetched by the component.
|
|
98
100
|
|
|
99
|
-
|
|
101
|
+
* Additional query-related properties returned from `useQuery` (such as loading state, error, etc.).
|
|
100
102
|
|
|
103
|
+
* **`queryParams`**:
|
|
104
|
+
The array of query parameters generated by the component, based on the provided SASQ configuration and current query state. This reflects the current filters, pagination, and search criteria used for the data fetch.
|
|
105
|
+
|
|
106
|
+
In general it is recommended not to use this functionality, as it represents an antipattern in React to pass information back up to the parents. Instead the implementing developer should try to replace the inner rendered components and do their logic there with the passed information.
|
|
101
107
|
|
|
102
108
|
### Worked Example
|
|
103
109
|
|
|
@@ -117,7 +123,7 @@ const LookupWithRefExample = () => {
|
|
|
117
123
|
const { lookupQueryProps, queryParams } = lookupRef.current;
|
|
118
124
|
console.log('Fetched data:', lookupQueryProps.data);
|
|
119
125
|
console.log('Current query parameters:', queryParams);
|
|
120
|
-
|
|
126
|
+
|
|
121
127
|
// Example: Check if data is loaded and then trigger some side-effect
|
|
122
128
|
if (!lookupQueryProps.isLoading && lookupQueryProps.data) {
|
|
123
129
|
// Perform an action with the fetched data
|
|
@@ -155,19 +161,18 @@ export default LookupWithRefExample;
|
|
|
155
161
|
|
|
156
162
|
## How It Works
|
|
157
163
|
|
|
158
|
-
1.
|
|
159
|
-
|
|
160
|
-
2.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
3.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
Using `forwardRef` and `useImperativeHandle`, the component exposes certain query properties and generated query parameters to parent components.
|
|
164
|
+
1. **Query and Pagination Management:**
|
|
165
|
+
* The component leverages hooks such as `usePrevNextPagination` (for page state), `useKiwtSASQuery` (for search/filter/sort state), and `useQuery` (from `react-query` for data fetching). The query parameters string is generated using the provided `queryParameterGenerator` function based on the `fetchParameters.SASQ_MAP` and the current state from the hooks.
|
|
166
|
+
2. **Filter Pane & Main Pane Layout:**
|
|
167
|
+
* **Filter Pane:**
|
|
168
|
+
* Rendered conditionally based on local storage state (`filterPaneVisible`), it contains a search section (SearchField, SearchKeyControl if `searchableIndexes` are provided, Submit/Reset buttons - unless `noSearchField` is true) and custom filtering options provided via `FilterComponent` and `FilterPaneHeaderComponent`. Buttons for collapsing the pane are included.
|
|
169
|
+
* **Main Pane:**
|
|
170
|
+
* Displays the fetched data using the `RenderBody` component (defaulting to `TableBody`). It integrates pagination controls (via `mclProps` passed to `RenderBody`) and displays record counts in the header. An expand button is shown if the filter pane is collapsed.
|
|
171
|
+
3. **Persistent Layout:**
|
|
172
|
+
The component wraps its content in a **PersistedPaneset** which maintains pane states (such as sizes and visibility) across sessions.
|
|
173
|
+
4. **Customization and Extensibility:**
|
|
174
|
+
Through various props, consumers can inject custom components (`FilterComponent`, `FilterPaneHeaderComponent`, `RenderBody`), override query generation (`queryParameterGenerator`, `lookupQueryNamespaceGenerator`), configure data fetching (`fetchParameters`), pass props down to underlying components (`filterPaneProps`, `mainPaneProps`, `mclProps`, `persistedPanesetProps`, `searchFieldProps`), tweak SASQ behavior (`sasqProps`), and adjust UI elements (`noSearchField`, `labelOverrides`, `searchableIndexes`).
|
|
175
|
+
5. **Ref Forwarding:**
|
|
176
|
+
Using `forwardRef` and `useImperativeHandle`, the component exposes certain query properties and generated query parameters to parent components.
|
|
172
177
|
|
|
173
178
|
This design enables **SASQLookupComponent** to serve as a robust and flexible foundation for building data lookup views with advanced filtering, search, and pagination functionalities.
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useEffect,
|
|
4
|
+
useImperativeHandle,
|
|
5
|
+
useMemo,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react';
|
|
2
8
|
|
|
3
9
|
import PropTypes from 'prop-types';
|
|
4
10
|
import { FormattedMessage } from 'react-intl';
|
|
5
11
|
import { useQuery } from 'react-query';
|
|
6
12
|
|
|
7
|
-
import {
|
|
8
|
-
useNamespace,
|
|
9
|
-
useOkapiKy
|
|
10
|
-
} from '@folio/stripes/core';
|
|
13
|
+
import { useNamespace, useOkapiKy } from '@folio/stripes/core';
|
|
11
14
|
|
|
12
15
|
import {
|
|
13
16
|
CollapseFilterPaneButton,
|
|
@@ -25,7 +28,12 @@ import {
|
|
|
25
28
|
} from '@folio/stripes/components';
|
|
26
29
|
|
|
27
30
|
import { generateKiwtQuery } from '../utils';
|
|
28
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
useKintIntl,
|
|
33
|
+
useKiwtSASQuery,
|
|
34
|
+
useLocalStorageState,
|
|
35
|
+
usePrevNextPagination,
|
|
36
|
+
} from '../hooks';
|
|
29
37
|
|
|
30
38
|
import TableBody from './TableBody';
|
|
31
39
|
import SearchKeyControl from '../SearchKeyControl';
|
|
@@ -41,7 +49,12 @@ const SASQLookupComponent = forwardRef((props, ref) => {
|
|
|
41
49
|
intlKey: passedIntlKey,
|
|
42
50
|
intlNS: passedIntlNS,
|
|
43
51
|
labelOverrides = {},
|
|
44
|
-
lookupQueryNamespaceGenerator = ({
|
|
52
|
+
lookupQueryNamespaceGenerator = ({
|
|
53
|
+
currentPage,
|
|
54
|
+
namespace,
|
|
55
|
+
id: passedId,
|
|
56
|
+
query,
|
|
57
|
+
}) => {
|
|
45
58
|
const queryNamespace = [namespace, 'SASQ'];
|
|
46
59
|
if (passedId) {
|
|
47
60
|
queryNamespace.push(passedId);
|
|
@@ -52,6 +65,8 @@ const SASQLookupComponent = forwardRef((props, ref) => {
|
|
|
52
65
|
|
|
53
66
|
return queryNamespace;
|
|
54
67
|
},
|
|
68
|
+
lookupQueryPromise = ({ endpoint, ky, queryParams }) => ky.get(`${endpoint}${queryParams}`).json(),
|
|
69
|
+
lookupResponseTransform = (response) => response, // Function to transform the response from the query
|
|
55
70
|
mainPaneProps = {},
|
|
56
71
|
mclProps = {},
|
|
57
72
|
noResultsProps = {},
|
|
@@ -73,60 +88,87 @@ const SASQLookupComponent = forwardRef((props, ref) => {
|
|
|
73
88
|
query: sasqPropsQuery, // If these are overriden we need to make use of them
|
|
74
89
|
queryGetter: sasqPropsQueryGetter,
|
|
75
90
|
querySetter: sasqPropsQuerySetter,
|
|
76
|
-
syncToLocation = true
|
|
91
|
+
syncToLocation = true,
|
|
77
92
|
} = sasqProps ?? {};
|
|
78
93
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
94
|
+
// We manage our internal state of pagination (URL vs MCL page state) using usePrevNextPagination.
|
|
95
|
+
// Below the queryParameterGenerator can then choose to use the outputs (namely totalRecords and page) as it sees fit.
|
|
96
|
+
const { currentPage, paginationMCLProps, paginationSASQProps } =
|
|
97
|
+
usePrevNextPagination({
|
|
98
|
+
count, // totalRecord
|
|
99
|
+
pageSize: fetchParameters.SASQ_MAP?.perPage,
|
|
100
|
+
syncToLocation,
|
|
101
|
+
});
|
|
84
102
|
|
|
85
103
|
const {
|
|
86
104
|
query: kintSASQQuery,
|
|
87
105
|
queryGetter: kintSASQQueryGetter,
|
|
88
|
-
querySetter: kintSASQQuerySetter
|
|
106
|
+
querySetter: kintSASQQuerySetter,
|
|
89
107
|
} = useKiwtSASQuery();
|
|
90
108
|
|
|
91
|
-
const query = useMemo(
|
|
92
|
-
|
|
93
|
-
|
|
109
|
+
const query = useMemo(
|
|
110
|
+
() => sasqPropsQuery ?? kintSASQQuery,
|
|
111
|
+
[sasqPropsQuery, kintSASQQuery]
|
|
112
|
+
);
|
|
113
|
+
const queryGetter = useMemo(
|
|
114
|
+
() => sasqPropsQueryGetter ?? kintSASQQueryGetter,
|
|
115
|
+
[sasqPropsQueryGetter, kintSASQQueryGetter]
|
|
116
|
+
);
|
|
117
|
+
const querySetter = useMemo(
|
|
118
|
+
() => sasqPropsQuerySetter ?? kintSASQQuerySetter,
|
|
119
|
+
[sasqPropsQuerySetter, kintSASQQuerySetter]
|
|
120
|
+
);
|
|
94
121
|
|
|
95
122
|
const { 0: namespace } = useNamespace();
|
|
96
123
|
const ky = useOkapiKy();
|
|
97
124
|
|
|
98
125
|
const filterPaneVisibileKey = `${namespace}-${id}-filterPaneVisibility`;
|
|
99
126
|
|
|
100
|
-
const queryParams = useMemo(
|
|
101
|
-
queryParameterGenerator(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
127
|
+
const queryParams = useMemo(
|
|
128
|
+
() => queryParameterGenerator(
|
|
129
|
+
// With Typescript this would be a type of SASQ_MAP, and so totalRecords is a valid property in our new shape
|
|
130
|
+
// In generateKiwtQueryParams we can choose to ignore totalRecords, which while being a valid property is not necessary for KIWT queries
|
|
131
|
+
{
|
|
132
|
+
page: currentPage,
|
|
133
|
+
totalRecords: count,
|
|
134
|
+
...fetchParameters.SASQ_MAP,
|
|
135
|
+
},
|
|
136
|
+
query ?? {}
|
|
137
|
+
),
|
|
138
|
+
[count, currentPage, fetchParameters.SASQ_MAP, query, queryParameterGenerator]
|
|
139
|
+
);
|
|
108
140
|
|
|
109
|
-
const [filterPaneVisible, setFilterPaneVisible] = useLocalStorageState(
|
|
141
|
+
const [filterPaneVisible, setFilterPaneVisible] = useLocalStorageState(
|
|
142
|
+
filterPaneVisibileKey,
|
|
143
|
+
true
|
|
144
|
+
);
|
|
110
145
|
const toggleFilterPane = () => setFilterPaneVisible(!filterPaneVisible);
|
|
111
146
|
|
|
112
|
-
const {
|
|
113
|
-
data = {},
|
|
114
|
-
...restOfQueryProps
|
|
115
|
-
} = useQuery(
|
|
147
|
+
const { data = {}, ...restOfQueryProps } = useQuery(
|
|
116
148
|
lookupQueryNamespaceGenerator({
|
|
117
149
|
currentPage,
|
|
118
150
|
endpoint: fetchParameters.endpoint,
|
|
119
151
|
namespace,
|
|
120
152
|
id,
|
|
121
153
|
query,
|
|
122
|
-
queryParams
|
|
154
|
+
queryParams,
|
|
123
155
|
}),
|
|
124
156
|
() => {
|
|
125
|
-
return
|
|
157
|
+
return lookupQueryPromise({
|
|
158
|
+
ky,
|
|
159
|
+
queryParams,
|
|
160
|
+
endpoint: fetchParameters.endpoint
|
|
161
|
+
});
|
|
126
162
|
},
|
|
127
163
|
{
|
|
128
164
|
enabled: (!!query?.filters || !!query?.query) && !!currentPage,
|
|
129
|
-
...(fetchParameters.queryOptions ?? {})
|
|
165
|
+
...(fetchParameters.queryOptions ?? {}),
|
|
166
|
+
// select is a parameter supported by useQuery to transform the response
|
|
167
|
+
// Could be possible to instead pass this down along with the queryOptions
|
|
168
|
+
// Additionally this is assuming the lookupResponseTransform is a func as opposed to an object
|
|
169
|
+
select: (selectData) => {
|
|
170
|
+
return lookupResponseTransform(selectData);
|
|
171
|
+
},
|
|
130
172
|
}
|
|
131
173
|
);
|
|
132
174
|
|
|
@@ -136,15 +178,13 @@ const SASQLookupComponent = forwardRef((props, ref) => {
|
|
|
136
178
|
}
|
|
137
179
|
}, [count, data.totalRecords]);
|
|
138
180
|
|
|
139
|
-
useImperativeHandle(ref, () => (
|
|
140
|
-
{
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
));
|
|
181
|
+
useImperativeHandle(ref, () => ({
|
|
182
|
+
lookupQueryProps: {
|
|
183
|
+
data,
|
|
184
|
+
...restOfQueryProps,
|
|
185
|
+
},
|
|
186
|
+
queryParams,
|
|
187
|
+
}));
|
|
148
188
|
|
|
149
189
|
return (
|
|
150
190
|
<SearchAndSortQuery
|
|
@@ -155,231 +195,234 @@ const SASQLookupComponent = forwardRef((props, ref) => {
|
|
|
155
195
|
{...sasqProps}
|
|
156
196
|
{...paginationSASQProps}
|
|
157
197
|
>
|
|
158
|
-
{
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
} = sasqRenderProps;
|
|
198
|
+
{(sasqRenderProps) => {
|
|
199
|
+
const {
|
|
200
|
+
activeFilters,
|
|
201
|
+
filterChanged,
|
|
202
|
+
getFilterHandlers,
|
|
203
|
+
getSearchHandlers,
|
|
204
|
+
onSubmitSearch,
|
|
205
|
+
resetAll,
|
|
206
|
+
searchChanged,
|
|
207
|
+
searchValue,
|
|
208
|
+
} = sasqRenderProps;
|
|
170
209
|
|
|
171
|
-
|
|
172
|
-
|
|
210
|
+
const searchHandlers = getSearchHandlers();
|
|
211
|
+
const disableReset = !filterChanged && !searchChanged;
|
|
173
212
|
|
|
174
|
-
|
|
213
|
+
const filterCount = activeFilters.string
|
|
214
|
+
? activeFilters.string.split(',').length
|
|
215
|
+
: 0;
|
|
175
216
|
|
|
176
|
-
|
|
217
|
+
const Body = RenderBody ?? TableBody;
|
|
177
218
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
mainPaneLastMenu,
|
|
186
|
-
...restOfMainPaneProps
|
|
187
|
-
} = mainPaneProps;
|
|
219
|
+
const {
|
|
220
|
+
filterPaneFirstMenu,
|
|
221
|
+
filterPaneLastMenu,
|
|
222
|
+
...restOfFilterPaneProps
|
|
223
|
+
} = filterPaneProps;
|
|
224
|
+
const { mainPaneFirstMenu, mainPaneLastMenu, ...restOfMainPaneProps } =
|
|
225
|
+
mainPaneProps;
|
|
188
226
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
227
|
+
const internalStateProps = {
|
|
228
|
+
activeFilters,
|
|
229
|
+
filterCount,
|
|
230
|
+
filterPaneVisible,
|
|
231
|
+
searchChanged,
|
|
232
|
+
searchValue,
|
|
233
|
+
setFilterPaneVisible,
|
|
234
|
+
toggleFilterPane,
|
|
235
|
+
};
|
|
198
236
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
237
|
+
const renderFirstMenu = () => {
|
|
238
|
+
if (mainPaneFirstMenu) {
|
|
239
|
+
return mainPaneFirstMenu(internalStateProps);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (!filterPaneVisible) {
|
|
243
|
+
return (
|
|
244
|
+
<PaneMenu>
|
|
245
|
+
<ExpandFilterPaneButton
|
|
246
|
+
filterCount={filterCount}
|
|
247
|
+
onClick={toggleFilterPane}
|
|
248
|
+
/>
|
|
249
|
+
</PaneMenu>
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
return null;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
return (
|
|
256
|
+
<PersistedPaneset
|
|
257
|
+
appId={namespace}
|
|
258
|
+
id={`${id}-paneset`}
|
|
259
|
+
{...persistedPanesetProps}
|
|
260
|
+
>
|
|
261
|
+
{filterPaneVisible && (
|
|
262
|
+
<Pane
|
|
263
|
+
defaultWidth="20%"
|
|
264
|
+
firstMenu={
|
|
265
|
+
filterPaneFirstMenu
|
|
266
|
+
? filterPaneFirstMenu(internalStateProps)
|
|
267
|
+
: null
|
|
268
|
+
}
|
|
269
|
+
id={`${id}-filter-pane`}
|
|
270
|
+
lastMenu={
|
|
271
|
+
filterPaneLastMenu ? (
|
|
272
|
+
filterPaneLastMenu(internalStateProps)
|
|
273
|
+
) : (
|
|
215
274
|
<PaneMenu>
|
|
216
275
|
<CollapseFilterPaneButton onClick={toggleFilterPane} />
|
|
217
276
|
</PaneMenu>
|
|
218
|
-
|
|
219
|
-
paneTitle={<FormattedMessage id="stripes-smart-components.searchAndFilter" />}
|
|
220
|
-
{...restOfFilterPaneProps}
|
|
221
|
-
>
|
|
222
|
-
<form onSubmit={onSubmitSearch}>
|
|
223
|
-
<FilterPaneHeaderComponent />
|
|
224
|
-
{!noSearchField &&
|
|
225
|
-
<>
|
|
226
|
-
<SearchField
|
|
227
|
-
ariaLabel={searchFieldAriaLabel}
|
|
228
|
-
autoFocus
|
|
229
|
-
id={`sasq-search-field-${id}`}
|
|
230
|
-
name="query"
|
|
231
|
-
onChange={e => {
|
|
232
|
-
if (e.target?.value) {
|
|
233
|
-
searchHandlers.query(e); // SASQ needs the whole event here
|
|
234
|
-
} else {
|
|
235
|
-
searchHandlers.reset();
|
|
236
|
-
}
|
|
237
|
-
}}
|
|
238
|
-
onClear={searchHandlers.reset}
|
|
239
|
-
value={searchValue.query}
|
|
240
|
-
{...searchFieldProps}
|
|
241
|
-
/>
|
|
242
|
-
{searchableIndexes?.length > 0 && (
|
|
243
|
-
<SearchKeyControl options={searchableIndexes} />
|
|
244
|
-
)}
|
|
245
|
-
<Button
|
|
246
|
-
buttonStyle="primary"
|
|
247
|
-
disabled={!searchValue.query}
|
|
248
|
-
fullWidth
|
|
249
|
-
type="submit"
|
|
250
|
-
>
|
|
251
|
-
<FormattedMessage id="stripes-smart-components.search" />
|
|
252
|
-
</Button>
|
|
253
|
-
<Button
|
|
254
|
-
buttonStyle="none"
|
|
255
|
-
disabled={disableReset}
|
|
256
|
-
id="clickable-reset-all"
|
|
257
|
-
onClick={resetAll}
|
|
258
|
-
>
|
|
259
|
-
<Icon icon="times-circle-solid">
|
|
260
|
-
<FormattedMessage id="stripes-smart-components.resetAll" />
|
|
261
|
-
</Icon>
|
|
262
|
-
</Button>
|
|
263
|
-
</>
|
|
264
|
-
}
|
|
265
|
-
<FilterComponent
|
|
266
|
-
activeFilters={activeFilters.state}
|
|
267
|
-
filterChanged={filterChanged}
|
|
268
|
-
filterHandlers={getFilterHandlers()}
|
|
269
|
-
resetAll={resetAll}
|
|
270
|
-
searchChanged={searchChanged}
|
|
271
|
-
searchHandlers={getSearchHandlers()}
|
|
272
|
-
searchValue={searchValue}
|
|
273
|
-
/>
|
|
274
|
-
</form>
|
|
275
|
-
</Pane>
|
|
276
|
-
}
|
|
277
|
-
<Pane
|
|
278
|
-
defaultWidth="fill"
|
|
279
|
-
firstMenu={mainPaneFirstMenu ?
|
|
280
|
-
mainPaneFirstMenu(internalStateProps) :
|
|
281
|
-
!filterPaneVisible ?
|
|
282
|
-
<PaneMenu>
|
|
283
|
-
<ExpandFilterPaneButton filterCount={filterCount} onClick={toggleFilterPane} />
|
|
284
|
-
</PaneMenu> :
|
|
285
|
-
null
|
|
277
|
+
)
|
|
286
278
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
mainPaneLastMenu(internalStateProps) :
|
|
290
|
-
null
|
|
279
|
+
paneTitle={
|
|
280
|
+
<FormattedMessage id="stripes-smart-components.searchAndFilter" />
|
|
291
281
|
}
|
|
292
|
-
|
|
293
|
-
padContent={false}
|
|
294
|
-
paneSub={
|
|
295
|
-
kintIntl.formatKintMessage({
|
|
296
|
-
id: 'found#Values',
|
|
297
|
-
overrideValue: labelOverrides?.foundValues
|
|
298
|
-
}, { total: data?.total })
|
|
299
|
-
}
|
|
300
|
-
{...restOfMainPaneProps}
|
|
282
|
+
{...restOfFilterPaneProps}
|
|
301
283
|
>
|
|
302
|
-
<
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
284
|
+
<form onSubmit={onSubmitSearch}>
|
|
285
|
+
<FilterPaneHeaderComponent />
|
|
286
|
+
{!noSearchField && (
|
|
287
|
+
<>
|
|
288
|
+
<SearchField
|
|
289
|
+
ariaLabel={searchFieldAriaLabel}
|
|
290
|
+
autoFocus
|
|
291
|
+
id={`sasq-search-field-${id}`}
|
|
292
|
+
name="query"
|
|
293
|
+
onChange={(e) => {
|
|
294
|
+
if (e.target?.value) {
|
|
295
|
+
searchHandlers.query(e); // SASQ needs the whole event here
|
|
296
|
+
} else {
|
|
297
|
+
searchHandlers.reset();
|
|
298
|
+
}
|
|
299
|
+
}}
|
|
300
|
+
onClear={searchHandlers.reset}
|
|
301
|
+
value={searchValue.query}
|
|
302
|
+
{...searchFieldProps}
|
|
303
|
+
/>
|
|
304
|
+
{searchableIndexes?.length > 0 && (
|
|
305
|
+
<SearchKeyControl options={searchableIndexes} />
|
|
306
|
+
)}
|
|
307
|
+
<Button
|
|
308
|
+
buttonStyle="primary"
|
|
309
|
+
disabled={!searchValue.query}
|
|
310
|
+
fullWidth
|
|
311
|
+
type="submit"
|
|
312
|
+
>
|
|
313
|
+
<FormattedMessage id="stripes-smart-components.search" />
|
|
314
|
+
</Button>
|
|
315
|
+
<Button
|
|
316
|
+
buttonStyle="none"
|
|
317
|
+
disabled={disableReset}
|
|
318
|
+
id="clickable-reset-all"
|
|
319
|
+
onClick={resetAll}
|
|
320
|
+
>
|
|
321
|
+
<Icon icon="times-circle-solid">
|
|
322
|
+
<FormattedMessage id="stripes-smart-components.resetAll" />
|
|
323
|
+
</Icon>
|
|
324
|
+
</Button>
|
|
325
|
+
</>
|
|
326
|
+
)}
|
|
327
|
+
<FilterComponent
|
|
328
|
+
activeFilters={activeFilters.state}
|
|
329
|
+
filterChanged={filterChanged}
|
|
330
|
+
filterHandlers={getFilterHandlers()}
|
|
331
|
+
resetAll={resetAll}
|
|
332
|
+
searchChanged={searchChanged}
|
|
333
|
+
searchHandlers={getSearchHandlers()}
|
|
334
|
+
searchValue={searchValue}
|
|
335
|
+
/>
|
|
336
|
+
</form>
|
|
331
337
|
</Pane>
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
338
|
+
)}
|
|
339
|
+
<Pane
|
|
340
|
+
defaultWidth="fill"
|
|
341
|
+
firstMenu={renderFirstMenu()}
|
|
342
|
+
id={`${id}-main-pane`}
|
|
343
|
+
lastMenu={
|
|
344
|
+
mainPaneLastMenu ? mainPaneLastMenu(internalStateProps) : null
|
|
345
|
+
}
|
|
346
|
+
noOverflow
|
|
347
|
+
padContent={false}
|
|
348
|
+
paneSub={kintIntl.formatKintMessage(
|
|
349
|
+
{
|
|
350
|
+
id: 'found#Values',
|
|
351
|
+
overrideValue: labelOverrides?.foundValues,
|
|
352
|
+
},
|
|
353
|
+
{ total: data?.total }
|
|
354
|
+
)}
|
|
355
|
+
{...restOfMainPaneProps}
|
|
356
|
+
>
|
|
357
|
+
<Body
|
|
358
|
+
data={data}
|
|
359
|
+
filterPaneVisible={filterPaneVisible}
|
|
360
|
+
intlKey={passedIntlKey}
|
|
361
|
+
intlNS={passedIntlNS}
|
|
362
|
+
labelOverrides={labelOverrides}
|
|
363
|
+
noResultsProps={noResultsProps}
|
|
364
|
+
query={query}
|
|
365
|
+
rowNavigation={rowNavigation}
|
|
366
|
+
toggleFilterPane={toggleFilterPane}
|
|
367
|
+
{...restOfQueryProps}
|
|
368
|
+
{...sasqRenderProps}
|
|
369
|
+
/*
|
|
370
|
+
* This is insane, it looks like SASQProps `initialSortState`
|
|
371
|
+
* needs to be passed through to MCL, as it relies on MCL calling the initial
|
|
372
|
+
* sort handler. Passing through SASQProps.
|
|
373
|
+
*/
|
|
374
|
+
{...sasqProps}
|
|
375
|
+
// pass down all props handed to us except mclProps (pass those down below with our extra prev/next goodies)
|
|
376
|
+
{...{
|
|
377
|
+
...props,
|
|
378
|
+
mclProps: {
|
|
379
|
+
...paginationMCLProps,
|
|
380
|
+
...mclProps,
|
|
381
|
+
},
|
|
382
|
+
}}
|
|
383
|
+
/>
|
|
384
|
+
</Pane>
|
|
385
|
+
{children}
|
|
386
|
+
</PersistedPaneset>
|
|
387
|
+
);
|
|
388
|
+
}}
|
|
337
389
|
</SearchAndSortQuery>
|
|
338
390
|
);
|
|
339
391
|
});
|
|
340
392
|
|
|
341
393
|
SASQLookupComponent.propTypes = {
|
|
342
|
-
children: PropTypes.oneOfType([
|
|
343
|
-
PropTypes.func,
|
|
344
|
-
PropTypes.node
|
|
345
|
-
]),
|
|
394
|
+
children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
|
|
346
395
|
fetchParameters: PropTypes.object,
|
|
347
396
|
filterPaneProps: PropTypes.object,
|
|
348
|
-
FilterComponent: PropTypes.oneOfType([
|
|
349
|
-
PropTypes.func,
|
|
350
|
-
PropTypes.node
|
|
351
|
-
]),
|
|
397
|
+
FilterComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
|
|
352
398
|
FilterPaneHeaderComponent: PropTypes.oneOfType([
|
|
353
399
|
PropTypes.func,
|
|
354
|
-
PropTypes.node
|
|
400
|
+
PropTypes.node,
|
|
355
401
|
]),
|
|
356
402
|
queryParameterGenerator: PropTypes.func,
|
|
357
|
-
history: PropTypes.object,
|
|
358
403
|
id: PropTypes.string.isRequired,
|
|
359
404
|
intlKey: PropTypes.string,
|
|
360
405
|
intlNS: PropTypes.string,
|
|
361
406
|
labelOverrides: PropTypes.object,
|
|
362
|
-
|
|
407
|
+
lookupQueryNamespaceGenerator: PropTypes.func,
|
|
408
|
+
lookupQueryPromise: PropTypes.func,
|
|
409
|
+
lookupResponseTransform: PropTypes.func,
|
|
363
410
|
mainPaneProps: PropTypes.object,
|
|
364
|
-
match: PropTypes.object,
|
|
365
411
|
mclProps: PropTypes.object,
|
|
412
|
+
noResultsProps: PropTypes.object,
|
|
366
413
|
noSearchField: PropTypes.bool,
|
|
367
|
-
path: PropTypes.string.isRequired,
|
|
368
414
|
persistedPanesetProps: PropTypes.object,
|
|
369
|
-
RenderBody: PropTypes.oneOfType([
|
|
370
|
-
PropTypes.func,
|
|
371
|
-
PropTypes.node
|
|
372
|
-
]),
|
|
373
|
-
resource: PropTypes.object,
|
|
374
|
-
resultColumns: PropTypes.arrayOf(PropTypes.object),
|
|
415
|
+
RenderBody: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
|
|
375
416
|
rowNavigation: PropTypes.bool,
|
|
376
417
|
sasqProps: PropTypes.object,
|
|
377
|
-
searchableIndexes: PropTypes.arrayOf(
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
418
|
+
searchableIndexes: PropTypes.arrayOf(
|
|
419
|
+
PropTypes.shape({
|
|
420
|
+
key: PropTypes.string.isRequired,
|
|
421
|
+
label: PropTypes.string,
|
|
422
|
+
})
|
|
423
|
+
),
|
|
381
424
|
searchFieldAriaLabel: PropTypes.string,
|
|
382
|
-
searchFieldProps: PropTypes.object
|
|
425
|
+
searchFieldProps: PropTypes.object,
|
|
383
426
|
};
|
|
384
427
|
|
|
385
428
|
export default SASQLookupComponent;
|
|
@@ -51,6 +51,18 @@ const buildFilterOptionBlock = (opf, isNested = false, encode = true) => {
|
|
|
51
51
|
return null;
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
+
/*
|
|
55
|
+
* GenerateKiwtQueryParams accepts
|
|
56
|
+
* SASQ_MAP shape "options" -- TODO write a TS shape for this
|
|
57
|
+
* SASQ "nsValues" shape "nsValues" -- TODO write a TS shape for this
|
|
58
|
+
* boolean "encode"
|
|
59
|
+
* It then uses these props to generate a query string for sending to KIWT type doTheLookupEndpoints
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
// For now we can store the "safe to ignore" keys from the normal SASQ_MAP shape here.
|
|
63
|
+
// These will be ignored rather than appended directly to the query as per normal.
|
|
64
|
+
const keysToIgnore = ['totalRecords'];
|
|
65
|
+
|
|
54
66
|
const generateKiwtQueryParams = (options, nsValues, encode = true) => {
|
|
55
67
|
const { qindex, query, filters, sort } = nsValues;
|
|
56
68
|
const {
|
|
@@ -187,7 +199,9 @@ const generateKiwtQueryParams = (options, nsValues, encode = true) => {
|
|
|
187
199
|
}
|
|
188
200
|
|
|
189
201
|
for (const [key, value] of Object.entries(rest)) {
|
|
190
|
-
|
|
202
|
+
if (!keysToIgnore.includes(key)) {
|
|
203
|
+
paramsArray.push(`${key}=${conditionalEncodeURIComponent(value, encode)}`);
|
|
204
|
+
}
|
|
191
205
|
}
|
|
192
206
|
|
|
193
207
|
return paramsArray;
|