@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 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
- ...fetchParameters.SASQ_MAP,
97
- page: currentPage
98
- }, query ?? {}), [currentPage, fetchParameters.SASQ_MAP, query, queryParameterGenerator]);
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 ky.get(`${fetchParameters.endpoint}${queryParams}`).json();
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: mainPaneFirstMenu ? mainPaneFirstMenu(internalStateProps) : !filterPaneVisible ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.PaneMenu, {
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
- location: _propTypes.default.object,
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
- paramsArray.push(`${key}=${conditionalEncodeURIComponent(value, encode)}`);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k-int/stripes-kint-components",
3
- "version": "5.23.0",
3
+ "version": "5.24.0",
4
4
  "description": "Stripes Component library for K-Int specific applications",
5
5
  "sideEffects": [
6
6
  "*.css"
@@ -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
- - 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`.
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
- | Name | Type | Description | Default | Required |
61
- |---------------------------------|------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------|----------|
62
- | `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. | | |
63
- | `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.<br>• **SASQ_MAP:** An object containing settings for search, filter, pagination (e.g., `searchKey`, `perPage`, etc.). Additional keys (such as `itemEndpoint`) can also be provided if needed. | `{}` | |
64
- | `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` | ✕ |
65
- | `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` | ✕ |
66
- | `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). | `{}` | ✕ |
67
- | `intlKey` | `string` | A base internationalization key used by the internal `useKintIntl` hook to resolve localized messages (e.g., for labels or pane titles). | | ✕ |
68
- | `intlNS` | `string` | An internationalization namespace used by the internal `useKintIntl` hook. | | ✕ |
69
- | `labelOverrides` | `object` | An object for overriding default labels, such as the text for displaying the count of found values. | `{}` | ✕ |
70
- | `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 | ✕ |
71
- | `mainPaneProps` | `object` | Additional props to be passed to the main pane containing the lookup results. This can include custom menu elements or styling. | `{}` | ✕ |
72
- | `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`. | `{}` | ✕ |
73
- | `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` | {} | ✕ |
74
- | `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` | ✕ |
75
- | `persistedPanesetProps` | `object` | Additional props to be passed to the **PersistedPaneset** component, which manages the persistent layout of the filter and main panes. | `{}` | ✕ |
76
- | `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` | ✕ |
77
- | `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` | ✕ |
78
- | `rowNavigation` | `bool` | Flag to enable or disable row navigation. When enabled, clicking on a row triggers navigation to a detailed view. | `true` | ✕ |
79
- | `sasqProps` | `object` | Additional props to override or extend the default SASQ query behavior. These props can include custom query values, setters, or getters. | | ✕ |
80
- | `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 `value` and `label` keys. If empty or omitted, the qindex checkboxes are not shown. | `[]` | ✕ |
81
- | `searchFieldAriaLabel` | `string` | Accessibility label for the search field. | | ✕ |
82
- | `searchFieldProps` | `object` | Additional props to be passed to the **SearchField** component for customizing its behavior or styling. | | ✕ |
83
- | `children` | `node`, `func` | Optional children to be rendered below the main pane. These are rendered within the **PersistedPaneset** container. | | ✕ |
84
- Below is an additional section for **SASQLookupComponent** documentation that describes the available functionality on the component's ref along with a worked example.
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
- - **`lookupQueryProps`**:
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
- - **`queryParams`**:
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
- In general is 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
+ * 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. **Query and Pagination Management:**
159
- + 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 `WorkspaceParameters.SASQ_MAP` and the current state from the hooks.
160
- 2. **Filter Pane & Main Pane Layout:**
161
- - **Filter Pane:**
162
- + 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.
163
- - **Main Pane:**
164
- + 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.
165
- 3. **Persistent Layout:**
166
- The component wraps its content in a **PersistedPaneset** which maintains pane states (such as sizes and visibility) across sessions.
167
-
168
- 4. **Customization and Extensibility:**
169
- Through various props, consumers can inject custom components (`FilterComponent`, `FilterPaneHeaderComponent`, `RenderBody`), override query generation (`queryParameterGenerator`, `lookupQueryNamespaceGenerator`), configure data fetching (`WorkspaceParameters`), pass props down to underlying components (`filterPaneProps`, `mainPaneProps`, `mclProps`, `persistedPanesetProps`, `searchFieldProps`), tweak SASQ behavior (`sasqProps`), and adjust UI elements (`noSearchField`, `labelOverrides`, `searchableIndexes`).
170
- 5. **Ref Forwarding:**
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 { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from 'react';
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 { useKintIntl, useKiwtSASQuery, useLocalStorageState, usePrevNextPagination } from '../hooks';
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 = ({ currentPage, namespace, id: passedId, query }) => {
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
- const { currentPage, paginationMCLProps, paginationSASQProps } = usePrevNextPagination({
80
- count,
81
- pageSize: fetchParameters.SASQ_MAP?.perPage,
82
- syncToLocation
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(() => sasqPropsQuery ?? kintSASQQuery, [sasqPropsQuery, kintSASQQuery]);
92
- const queryGetter = useMemo(() => sasqPropsQueryGetter ?? kintSASQQueryGetter, [sasqPropsQueryGetter, kintSASQQueryGetter]);
93
- const querySetter = useMemo(() => sasqPropsQuerySetter ?? kintSASQQuerySetter, [sasqPropsQuerySetter, kintSASQQuerySetter]);
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
- ...fetchParameters.SASQ_MAP,
104
- page: currentPage,
105
- }, (query ?? {})
106
- )
107
- ), [currentPage, fetchParameters.SASQ_MAP, query, queryParameterGenerator]);
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(filterPaneVisibileKey, true);
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 ky.get(`${fetchParameters.endpoint}${queryParams}`).json();
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
- lookupQueryProps: {
142
- data,
143
- ...restOfQueryProps
144
- },
145
- queryParams
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
- (sasqRenderProps) => {
160
- const {
161
- activeFilters,
162
- filterChanged,
163
- getFilterHandlers,
164
- getSearchHandlers,
165
- onSubmitSearch,
166
- resetAll,
167
- searchChanged,
168
- searchValue
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
- const searchHandlers = getSearchHandlers();
172
- const disableReset = !filterChanged && !searchChanged;
210
+ const searchHandlers = getSearchHandlers();
211
+ const disableReset = !filterChanged && !searchChanged;
173
212
 
174
- const filterCount = activeFilters.string ? activeFilters.string.split(',').length : 0;
213
+ const filterCount = activeFilters.string
214
+ ? activeFilters.string.split(',').length
215
+ : 0;
175
216
 
176
- const Body = RenderBody ?? TableBody;
217
+ const Body = RenderBody ?? TableBody;
177
218
 
178
- const {
179
- filterPaneFirstMenu,
180
- filterPaneLastMenu,
181
- ...restOfFilterPaneProps
182
- } = filterPaneProps;
183
- const {
184
- mainPaneFirstMenu,
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
- const internalStateProps = {
190
- activeFilters,
191
- filterCount,
192
- filterPaneVisible,
193
- searchChanged,
194
- searchValue,
195
- setFilterPaneVisible,
196
- toggleFilterPane
197
- };
227
+ const internalStateProps = {
228
+ activeFilters,
229
+ filterCount,
230
+ filterPaneVisible,
231
+ searchChanged,
232
+ searchValue,
233
+ setFilterPaneVisible,
234
+ toggleFilterPane,
235
+ };
198
236
 
199
- return (
200
- <PersistedPaneset
201
- appId={namespace}
202
- id={`${id}-paneset`}
203
- {...persistedPanesetProps}
204
- >
205
- {filterPaneVisible &&
206
- <Pane
207
- defaultWidth="20%"
208
- firstMenu={filterPaneFirstMenu ?
209
- filterPaneFirstMenu(internalStateProps) :
210
- null
211
- }
212
- id={`${id}-filter-pane`}
213
- lastMenu={filterPaneLastMenu ?
214
- filterPaneLastMenu(internalStateProps) :
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
- id={`${id}-main-pane`}
288
- lastMenu={mainPaneLastMenu ?
289
- mainPaneLastMenu(internalStateProps) :
290
- null
279
+ paneTitle={
280
+ <FormattedMessage id="stripes-smart-components.searchAndFilter" />
291
281
  }
292
- noOverflow
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
- <Body
303
- data={data}
304
- filterPaneVisible={filterPaneVisible}
305
- intlKey={passedIntlKey}
306
- intlNS={passedIntlNS}
307
- labelOverrides={labelOverrides}
308
- noResultsProps={noResultsProps}
309
- query={query}
310
- rowNavigation={rowNavigation}
311
- toggleFilterPane={toggleFilterPane}
312
- {...restOfQueryProps}
313
- {...sasqRenderProps}
314
- /*
315
- * This is insane, it looks like SASQProps `initialSortState`
316
- * needs to be passed through to MCL, as it relies on MCL calling the initial
317
- * sort handler. Passing through SASQProps.
318
- */
319
- {...sasqProps}
320
- // pass down all props handed to us except mclProps (pass those down below with our extra prev/next goodies)
321
- {
322
- ...{
323
- ...props,
324
- mclProps: {
325
- ...paginationMCLProps,
326
- ...mclProps,
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
- {children}
333
- </PersistedPaneset>
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
- location: PropTypes.object,
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(PropTypes.shape({
378
- key: PropTypes.string.isRequired,
379
- label: PropTypes.string
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
- paramsArray.push(`${key}=${conditionalEncodeURIComponent(value, encode)}`);
202
+ if (!keysToIgnore.includes(key)) {
203
+ paramsArray.push(`${key}=${conditionalEncodeURIComponent(value, encode)}`);
204
+ }
191
205
  }
192
206
 
193
207
  return paramsArray;