@blaze-cms/plugin-data-ui 0.140.3 → 0.141.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/lib/components/EntityManager/Entity/Entity.js +9 -1
  3. package/lib/components/EntityManager/Entity/Entity.js.map +1 -1
  4. package/lib/components/EntityManager/Entity/EntityHeader/EntityHeader.js +18 -4
  5. package/lib/components/EntityManager/Entity/EntityHeader/EntityHeader.js.map +1 -1
  6. package/lib/components/EntityManager/Entity/SideBarRelations/helpers/build-dynamic-query.js +1 -1
  7. package/lib/components/EntityManager/Entity/SideBarRelations/helpers/build-dynamic-query.js.map +1 -1
  8. package/lib/components/InfoBoxes/helpers/build-dynamic-query.js +1 -1
  9. package/lib/components/InfoBoxes/helpers/build-dynamic-query.js.map +1 -1
  10. package/lib/components/InfoBoxes/presentational/InfoBox.js +2 -1
  11. package/lib/components/InfoBoxes/presentational/InfoBox.js.map +1 -1
  12. package/lib/components/ListingTable/ListingTable.js +116 -120
  13. package/lib/components/ListingTable/ListingTable.js.map +1 -1
  14. package/lib/components/ListingTable/ListingTableContent/ListingTableContent.js +18 -19
  15. package/lib/components/ListingTable/ListingTableContent/ListingTableContent.js.map +1 -1
  16. package/lib/components/ListingTable/mappers/populate-rows.js +3 -2
  17. package/lib/components/ListingTable/mappers/populate-rows.js.map +1 -1
  18. package/lib/components/ListingTable/service/index.js +11 -2
  19. package/lib/components/ListingTable/service/index.js.map +1 -1
  20. package/lib/components/hooks/useCallbackDebounce.js +22 -0
  21. package/lib/components/hooks/useCallbackDebounce.js.map +1 -0
  22. package/lib/utils/build-listing-query.js +1 -1
  23. package/lib/utils/build-listing-query.js.map +1 -1
  24. package/lib/utils/get-default-query-params.js +1 -1
  25. package/lib/utils/get-default-query-params.js.map +1 -1
  26. package/lib-es/components/EntityManager/Entity/Entity.js +12 -1
  27. package/lib-es/components/EntityManager/Entity/Entity.js.map +1 -1
  28. package/lib-es/components/EntityManager/Entity/EntityHeader/EntityHeader.js +18 -4
  29. package/lib-es/components/EntityManager/Entity/EntityHeader/EntityHeader.js.map +1 -1
  30. package/lib-es/components/EntityManager/Entity/SideBarRelations/helpers/build-dynamic-query.js +1 -0
  31. package/lib-es/components/EntityManager/Entity/SideBarRelations/helpers/build-dynamic-query.js.map +1 -1
  32. package/lib-es/components/InfoBoxes/helpers/build-dynamic-query.js +1 -0
  33. package/lib-es/components/InfoBoxes/helpers/build-dynamic-query.js.map +1 -1
  34. package/lib-es/components/InfoBoxes/presentational/InfoBox.js +2 -1
  35. package/lib-es/components/InfoBoxes/presentational/InfoBox.js.map +1 -1
  36. package/lib-es/components/ListingTable/ListingTable.js +58 -57
  37. package/lib-es/components/ListingTable/ListingTable.js.map +1 -1
  38. package/lib-es/components/ListingTable/ListingTableContent/ListingTableContent.js +18 -19
  39. package/lib-es/components/ListingTable/ListingTableContent/ListingTableContent.js.map +1 -1
  40. package/lib-es/components/ListingTable/mappers/populate-rows.js +20 -17
  41. package/lib-es/components/ListingTable/mappers/populate-rows.js.map +1 -1
  42. package/lib-es/components/ListingTable/service/index.js +7 -1
  43. package/lib-es/components/ListingTable/service/index.js.map +1 -1
  44. package/lib-es/components/hooks/useCallbackDebounce.js +12 -0
  45. package/lib-es/components/hooks/useCallbackDebounce.js.map +1 -0
  46. package/lib-es/utils/build-listing-query.js +1 -0
  47. package/lib-es/utils/build-listing-query.js.map +1 -1
  48. package/lib-es/utils/get-default-query-params.js +1 -1
  49. package/lib-es/utils/get-default-query-params.js.map +1 -1
  50. package/package.json +8 -7
  51. package/src/components/EntityManager/Entity/Entity.js +18 -0
  52. package/src/components/EntityManager/Entity/EntityHeader/EntityHeader.js +24 -11
  53. package/src/components/EntityManager/Entity/SideBarRelations/helpers/build-dynamic-query.js +1 -0
  54. package/src/components/InfoBoxes/helpers/build-dynamic-query.js +1 -0
  55. package/src/components/InfoBoxes/presentational/InfoBox.js +2 -2
  56. package/src/components/ListingTable/ListingTable.js +86 -93
  57. package/src/components/ListingTable/ListingTableContent/ListingTableContent.js +20 -18
  58. package/src/components/ListingTable/mappers/populate-rows.js +19 -16
  59. package/src/components/ListingTable/service/index.js +13 -2
  60. package/src/components/hooks/useCallbackDebounce.js +15 -0
  61. package/src/utils/build-listing-query.js +1 -0
  62. package/src/utils/get-default-query-params.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blaze-cms/plugin-data-ui",
3
- "version": "0.140.3",
3
+ "version": "0.141.0-alpha.1",
4
4
  "description": "Blaze plugin data ui",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib-es/index.js",
@@ -27,18 +27,19 @@
27
27
  },
28
28
  "license": "GPL-3.0",
29
29
  "dependencies": {
30
- "@blaze-cms/admin-ui-utils": "^0.140.3",
30
+ "@blaze-cms/admin-ui-utils": "0.141.0-alpha.0",
31
31
  "@blaze-cms/core-errors": "^0.140.3",
32
32
  "@blaze-cms/plugin-render-hooks-ui": "^0.140.3",
33
- "@blaze-cms/react-form-builder": "^0.140.3",
34
- "@blaze-cms/react-page-builder": "^0.140.3",
33
+ "@blaze-cms/react-form-builder": "0.141.0-alpha.1",
34
+ "@blaze-cms/react-page-builder": "0.141.0-alpha.1",
35
35
  "@blaze-cms/setup-ui": "^0.140.3",
36
36
  "@blaze-cms/versioning-ui": "^0.140.3",
37
37
  "@blaze-react/button": "0.5.19",
38
38
  "@blaze-react/more": "0.5.19",
39
- "@blaze-react/multiselect": "0.6.6",
39
+ "@blaze-react/multiselect": "0.8.0-alpha.78",
40
+ "@blaze-react/pagination": "0.8.0-alpha.76",
40
41
  "@blaze-react/select": "0.8.0-alpha.64",
41
- "@blaze-react/table": "0.5.31",
42
+ "@blaze-react/table": "0.8.0-alpha.74",
42
43
  "@blaze-react/toaster": "0.5.17",
43
44
  "@blaze-react/utils": "0.5.15",
44
45
  "core-js": "^3.2.1",
@@ -66,5 +67,5 @@
66
67
  "lib/*",
67
68
  "lib-es/*"
68
69
  ],
69
- "gitHead": "f62fd2bbc9cd4f2d1d3e77e679551b1a6ee72b81"
70
+ "gitHead": "511c3db4259e32fc0e45b4072254189b9d64764c"
70
71
  }
@@ -14,6 +14,7 @@ import isFormEmpty from '../utils/is-form-empty';
14
14
  import availableActions from './actions-handlers';
15
15
  import SideBarRelations from './SideBarRelations';
16
16
  import Tabs from '../../Tabs';
17
+ import useCallbackDebounce from '../../hooks/useCallbackDebounce';
17
18
 
18
19
  import {
19
20
  ENTITY_PUBLISHED,
@@ -27,6 +28,7 @@ import {
27
28
  UNPUBLISHED_WARNING
28
29
  } from '../../../constants';
29
30
  import EntityHeader from './EntityHeader';
31
+
30
32
  import {
31
33
  validateSideBarRelations,
32
34
  canViewPage,
@@ -84,6 +86,20 @@ const Entity = ({
84
86
 
85
87
  // Here's how we'll keep track of our component's mounted state
86
88
  const componentIsMounted = useRef(true);
89
+
90
+ const {
91
+ displayProperties: { saveOnChange = false }
92
+ } = schema;
93
+
94
+ useCallbackDebounce(
95
+ () => {
96
+ isSaveButtonAvailable && onSubmit();
97
+ },
98
+ 500,
99
+ [isSaveButtonAvailable],
100
+ !saveOnChange
101
+ );
102
+
87
103
  useEffect(
88
104
  () => () => {
89
105
  componentIsMounted.current = false;
@@ -424,6 +440,8 @@ const Entity = ({
424
440
  formData={formData}
425
441
  onViewUrl={onViewUrlHandler}
426
442
  saveButtonText={saveButtonText}
443
+ saveOnChange={saveOnChange}
444
+ entitySchema={entitySchema}
427
445
  />
428
446
  <div className="page-wrapper__content">
429
447
  <div className="tabs-wrapper tabs-wrapper__tab">
@@ -9,6 +9,7 @@ import { SAVE_BUTTON_TEXTS } from '../../../../constants';
9
9
  const EntityHeader = ({
10
10
  saveButtonText,
11
11
  entityData,
12
+ entitySchema,
12
13
  entityIdentifier,
13
14
  pageTitle,
14
15
  onSubmit,
@@ -20,18 +21,29 @@ const EntityHeader = ({
20
21
  toggleModal,
21
22
  formData,
22
23
  pageName,
23
- onViewUrl
24
+ onViewUrl,
25
+ saveOnChange
24
26
  }) => {
25
27
  const SaveButtonModifiers = isSaveButtonAvailable ? ['small'] : ['small', 'disabled'];
26
28
  const showPreviewButton = isEnablePreviewButton && entityIdentifier && entityData.id;
27
29
  const shouldDisableMoreMenu = saveButtonText === SAVE_BUTTON_TEXTS.saving;
28
30
 
31
+ const {
32
+ displayProperties: { adminCrudActions: { delete: deleteAction = { active: true } } = {} } = {}
33
+ } =
34
+ entitySchema || {};
35
+
36
+ const showDeleteButton =
37
+ deleteAction.active && formData && Object.keys(formData.values).length !== 0;
38
+
29
39
  return (
30
40
  <PageHeader title={pageTitle} pageName={pageName} onViewUrl={onViewUrl}>
31
41
  <PageHeader.Actions>
32
- <Button onClick={onSubmit} modifiers={SaveButtonModifiers} data-testid="button-save">
33
- {saveButtonText}
34
- </Button>
42
+ {!saveOnChange && (
43
+ <Button onClick={onSubmit} modifiers={SaveButtonModifiers} data-testid="button-save">
44
+ {saveButtonText}
45
+ </Button>
46
+ )}
35
47
  <More disabled={shouldDisableMoreMenu}>
36
48
  <More.Avatar data-testid={`entity-header-${pageName}`} isMoreMenu>
37
49
  <span className="material-icons">more_vert</span>
@@ -58,12 +70,11 @@ const EntityHeader = ({
58
70
  View
59
71
  </Button>
60
72
  )}
61
- {formData &&
62
- Object.keys(formData.values).length !== 0 && (
63
- <Button className="more-menu__link" onClick={toggleModal}>
64
- Delete
65
- </Button>
66
- )}
73
+ {showDeleteButton && (
74
+ <Button className="more-menu__link" onClick={toggleModal}>
75
+ Delete
76
+ </Button>
77
+ )}
67
78
  </More.Content>
68
79
  </More>
69
80
  </PageHeader.Actions>
@@ -74,6 +85,7 @@ const EntityHeader = ({
74
85
  EntityHeader.propTypes = {
75
86
  entityData: PropTypes.object,
76
87
  entityIdentifier: PropTypes.string,
88
+ entitySchema: PropTypes.object.isRequired,
77
89
  pageTitle: PropTypes.string.isRequired,
78
90
  pageName: PropTypes.string,
79
91
  onSubmit: PropTypes.func.isRequired,
@@ -85,7 +97,8 @@ EntityHeader.propTypes = {
85
97
  toggleModal: PropTypes.func.isRequired,
86
98
  formData: PropTypes.object,
87
99
  onViewUrl: PropTypes.func.isRequired,
88
- saveButtonText: PropTypes.string
100
+ saveButtonText: PropTypes.string,
101
+ saveOnChange: PropTypes.bool.isRequired
89
102
  };
90
103
 
91
104
  EntityHeader.defaultProps = {
@@ -17,6 +17,7 @@ export default function buildDynamicQuery({ id, schema, displayProperties }) {
17
17
  `${infoProperty} {
18
18
  label
19
19
  value
20
+ showLabel
20
21
  }`
21
22
  );
22
23
 
@@ -11,6 +11,7 @@ export default function buildDynamicQuery({ id, schema, infoBox }) {
11
11
  const fields = `${infoBox.property} {
12
12
  label
13
13
  value
14
+ showLabel
14
15
  }`;
15
16
 
16
17
  return {
@@ -8,10 +8,10 @@ const InfoBox = ({ items, infoBoxKey }) => {
8
8
  Object.values(item)
9
9
  .map(info => {
10
10
  if (!info.label || !info.value) return null;
11
-
11
+ const label = info.showLabel === false ? '' : `${info.label}: `;
12
12
  return (
13
13
  <div className="info-box--item" key={`${infoBoxKey}-${info.label.toLowerCase()}`}>
14
- <div className="info-box--label">{info.label}: </div>
14
+ <div className="info-box--label">{label}</div>
15
15
  <div className="info-box--value">{info.value}</div>
16
16
  </div>
17
17
  );
@@ -1,8 +1,8 @@
1
- import { useApolloClient } from '@apollo/client';
2
1
  import React, { useEffect, useState, Fragment } from 'react';
3
2
  import PropTypes from 'prop-types';
4
- import { withRouter, Link } from 'react-router-dom';
5
3
  import More from '@blaze-react/more';
4
+ import { useApolloClient } from '@apollo/client';
5
+ import { withRouter, Link, useLocation } from 'react-router-dom';
6
6
  import { PageHeader, DeleteAction, CardPrompt } from '@blaze-cms/admin';
7
7
  import { useToasts } from '@blaze-react/toaster';
8
8
  import { RenderHook } from '@blaze-cms/plugin-render-hooks-ui';
@@ -12,20 +12,20 @@ import { fetchData } from './service';
12
12
  import { populateRows, formatRows, getParsedRowData } from './mappers/populate-rows';
13
13
  import { getDefaultQueryParams } from '../../utils/get-default-query-params';
14
14
 
15
- const OVER_SCAN_BUFFER = 10;
16
-
17
- const ListingTable = ({ match, entitySchema }) => {
15
+ const ListingTable = ({ match, entitySchema, history }) => {
18
16
  const [tableData, setTableData] = useState({});
19
17
  const [modalStatus, setModalStatus] = useState(false);
20
18
  const [itemToDelete, setItemToDelete] = useState({});
21
19
  const [previousSchema, setPreviousSchema] = useState({ id: null });
22
- const [scrollToIndex, setScrollToIndex] = useState(0);
23
- const [verifiedRanges, setVerifiedRanges] = useState([]);
20
+ const [totalItems, setTotalItems] = useState(0);
24
21
  const queryParamsDefault = getDefaultQueryParams(entitySchema);
25
22
  const [queryParams, setQueryParams] = useState(queryParamsDefault);
26
23
  const [listFilters, setListFilters] = useState([]);
27
24
  const client = useApolloClient();
28
25
  const { addToast } = useToasts();
26
+ const location = useLocation();
27
+ const searchParams = new URLSearchParams(location.search);
28
+ const currentPage = Number(searchParams.get('page')) || 1;
29
29
 
30
30
  useEffect(
31
31
  () => {
@@ -42,12 +42,12 @@ const ListingTable = ({ match, entitySchema }) => {
42
42
  [client, entitySchema, match.url, previousSchema.id, queryParams] // eslint-disable-line react-hooks/exhaustive-deps
43
43
  );
44
44
 
45
- const doQuery = async (filters = listFilters) => {
46
- const data = await fetchData({
45
+ const doQuery = async (filters = listFilters, params = queryParamsDefault) => {
46
+ const { listingData, totalRecords } = await fetchData({
47
47
  client,
48
48
  querySettings: {
49
49
  entitySchema,
50
- queryParams: queryParamsDefault
50
+ queryParams: params
51
51
  },
52
52
  listFilters: filters
53
53
  });
@@ -56,10 +56,23 @@ const ListingTable = ({ match, entitySchema }) => {
56
56
  toggleModal,
57
57
  url: match.url,
58
58
  entitySchema,
59
- rows: data
59
+ rows: listingData
60
60
  });
61
61
 
62
62
  setTableData(populatedTable);
63
+ setTotalItems(totalRecords);
64
+ };
65
+
66
+ const handleOnPageChange = async ({ pageNumber, offset: _offset }) => {
67
+ const updatedQueryParams = {
68
+ ...queryParams,
69
+ offset: _offset
70
+ };
71
+
72
+ await doQuery(listFilters, updatedQueryParams);
73
+
74
+ history.push(`?page=${pageNumber}`);
75
+ document.getElementsByClassName('page')[0].scrollTo(0, 0);
63
76
  };
64
77
 
65
78
  const updateListingFilters = async filters => {
@@ -100,11 +113,9 @@ const ListingTable = ({ match, entitySchema }) => {
100
113
  ...queryParamsDefault,
101
114
  sort: [{ property, direction }]
102
115
  };
103
- setScrollToIndex(0);
104
- setVerifiedRanges([]);
105
116
  setQueryParams(sortQueryParams);
106
117
 
107
- const data = await fetchData({
118
+ const { listingData } = await fetchData({
108
119
  client,
109
120
  querySettings: {
110
121
  entitySchema,
@@ -119,85 +130,62 @@ const ListingTable = ({ match, entitySchema }) => {
119
130
  ...tableData,
120
131
  appliedSort: { [property]: direction },
121
132
  rows: formatRows({
122
- rows: getParsedRowData(data),
133
+ rows: getParsedRowData(listingData),
123
134
  url: match.url,
124
135
  toggleModal,
125
136
  firstColumn,
126
137
  isEnquiry
127
138
  })
128
139
  });
129
- };
130
-
131
- const handleRenderedItems = async params => {
132
- const { startIndex } = params;
133
- const rowsLength = tableData.rows.length;
134
- const loadIndex = Math.floor(rowsLength / 3) - OVER_SCAN_BUFFER;
135
- if (loadIndex > 0 && loadIndex < startIndex && !verifiedRanges.includes(loadIndex)) {
136
- const updatedQueryParams = {
137
- ...queryParams,
138
- offset: rowsLength
139
- };
140
- const data = await fetchData({
141
- client,
142
- querySettings: {
143
- entitySchema,
144
- queryParams: updatedQueryParams
145
- },
146
- listFilters
147
- });
148
- const updatedRows = [
149
- ...tableData.rows,
150
- ...formatRows({
151
- rows: getParsedRowData(data),
152
- url: match.url,
153
- toggleModal,
154
- isEnquiry: tableData.isEnquiry
155
- })
156
- ];
157
-
158
- setVerifiedRanges([...verifiedRanges, loadIndex]);
159
- setQueryParams(updatedQueryParams);
160
- setTableData({
161
- ...tableData,
162
- rows: updatedRows
163
- });
164
- setScrollToIndex(startIndex + OVER_SCAN_BUFFER);
165
- }
140
+ history.push('?page=1');
166
141
  };
167
142
 
168
143
  if (!tableData || !tableData.rows) return 'loading';
169
- const showAddButton = !!tableData.rows.length;
144
+
145
+ const {
146
+ displayProperties: {
147
+ adminCrudActions: {
148
+ create: createAction = { active: true },
149
+ delete: _deleteAction = { active: true }
150
+ } = {}
151
+ } = {}
152
+ } = entitySchema;
153
+
154
+ const showAddButton = !tableData.rows.length && listFilters.length === 0;
170
155
 
171
156
  return (
172
157
  <div className="page">
173
- {modalStatus && (
174
- <DeleteAction
175
- onClose={toggleModal}
176
- deleteAction={deleteAction}
177
- itemName={itemToDelete.name}
178
- />
179
- )}
180
- <PageHeader title={entitySchema.displayName} subtitle="">
181
- {showAddButton && (
182
- <Fragment>
183
- <Link
184
- data-testid="addEntity"
185
- className="button button--small"
186
- to={`${match.url}/create`}>
187
- Add
188
- </Link>
189
- <PageHeader.Actions>
190
- <More>
191
- <More.Avatar isMoreMenu>
192
- <span className="material-icons">more_vert</span>
193
- </More.Avatar>
194
- <More.Content isMoreMenu />
195
- </More>
196
- </PageHeader.Actions>
197
- </Fragment>
158
+ {modalStatus &&
159
+ _deleteAction.active && (
160
+ <DeleteAction
161
+ data-testid="deleteEntity"
162
+ onClose={toggleModal}
163
+ deleteAction={deleteAction}
164
+ itemName={itemToDelete.name}
165
+ />
198
166
  )}
167
+ <PageHeader title={entitySchema.displayName} subtitle="">
168
+ {createAction.active &&
169
+ !showAddButton && (
170
+ <Fragment>
171
+ <Link
172
+ data-testid="addEntity"
173
+ className="button button--small"
174
+ to={`${match.url}/create`}>
175
+ Add
176
+ </Link>
177
+ <PageHeader.Actions>
178
+ <More>
179
+ <More.Avatar isMoreMenu>
180
+ <span className="material-icons">more_vert</span>
181
+ </More.Avatar>
182
+ <More.Content isMoreMenu />
183
+ </More>
184
+ </PageHeader.Actions>
185
+ </Fragment>
186
+ )}
199
187
  </PageHeader>
200
- {!showAddButton && (
188
+ {showAddButton ? (
201
189
  <CardPrompt>
202
190
  <Link
203
191
  className="button button--rounded button--cta"
@@ -206,26 +194,31 @@ const ListingTable = ({ match, entitySchema }) => {
206
194
  Add
207
195
  </Link>
208
196
  </CardPrompt>
197
+ ) : (
198
+ <>
199
+ <RenderHook
200
+ hookKey="entity:listing:main:top"
201
+ schema={entitySchema}
202
+ listFilters={listFilters}
203
+ setListFilters={updateListingFilters}
204
+ />
205
+ <ListingTableContent
206
+ totalItems={totalItems}
207
+ currentPage={currentPage}
208
+ onSort={handleSort}
209
+ handleOnPageChange={handleOnPageChange}
210
+ tableData={tableData}
211
+ onCloseCardPrompt={onCloseCardPrompt}
212
+ />
213
+ </>
209
214
  )}
210
- <RenderHook
211
- hookKey="entity:listing:main:top"
212
- schema={entitySchema}
213
- setListFilters={updateListingFilters}
214
- />
215
- <ListingTableContent
216
- overScanBuffer={OVER_SCAN_BUFFER}
217
- onSort={handleSort}
218
- onRenderItems={handleRenderedItems}
219
- tableData={tableData}
220
- onCloseCardPrompt={onCloseCardPrompt}
221
- scrollToIndex={scrollToIndex}
222
- />
223
215
  </div>
224
216
  );
225
217
  };
226
218
  ListingTable.propTypes = {
227
219
  entitySchema: PropTypes.object.isRequired,
228
- match: PropTypes.object.isRequired
220
+ match: PropTypes.object.isRequired,
221
+ history: PropTypes.object.isRequired
229
222
  };
230
223
 
231
224
  export default withRouter(ListingTable);
@@ -1,5 +1,7 @@
1
1
  import React from 'react';
2
2
  import Table from '@blaze-react/table';
3
+ import Pagination from '@blaze-react/pagination';
4
+
3
5
  import PropTypes from 'prop-types';
4
6
  import { withRouter } from 'react-router-dom';
5
7
 
@@ -7,10 +9,9 @@ const ListingTableContent = ({
7
9
  tableData,
8
10
  handleSelect,
9
11
  onSort,
10
- onClickRow,
11
- overScanBuffer,
12
- onRenderItems,
13
- scrollToIndex
12
+ handleOnPageChange,
13
+ currentPage,
14
+ totalItems
14
15
  }) => {
15
16
  const displayTable = tableData && tableData.rows && !!tableData.rows.length;
16
17
  const { isEnquiry } = tableData;
@@ -18,22 +19,28 @@ const ListingTableContent = ({
18
19
 
19
20
  return (
20
21
  <>
21
- {displayTable && (
22
+ {displayTable ? (
22
23
  <>
23
24
  <div className={className}>
24
25
  <Table
25
- scrollToIndex={scrollToIndex}
26
26
  onSort={onSort}
27
- onClickRow={onClickRow}
28
- overScanBuffer={overScanBuffer}
29
- onRenderItems={onRenderItems}
30
27
  data={tableData}
31
28
  checkboxes={!isEnquiry}
32
29
  onSelect={handleSelect}
33
30
  data-testid="listing-table-content"
34
31
  />
32
+ <Pagination
33
+ visiblePages={10}
34
+ totalItems={totalItems}
35
+ currentPage={currentPage}
36
+ onPageChange={handleOnPageChange}
37
+ />
35
38
  </div>
36
39
  </>
40
+ ) : (
41
+ <span className="table-no-results" data-testid="no-results">
42
+ No results
43
+ </span>
37
44
  )}
38
45
  </>
39
46
  );
@@ -46,20 +53,15 @@ ListingTableContent.propTypes = {
46
53
  }).isRequired,
47
54
  handleSelect: PropTypes.func,
48
55
  onSort: PropTypes.func,
49
- onClickRow: PropTypes.func,
50
- overScanBuffer: PropTypes.number,
51
- scrollToIndex: PropTypes.number,
52
- onRenderItems: PropTypes.func
56
+ handleOnPageChange: PropTypes.func,
57
+ currentPage: PropTypes.number.isRequired,
58
+ totalItems: PropTypes.number.isRequired
53
59
  };
54
60
 
55
61
  ListingTableContent.defaultProps = {
56
62
  handleSelect: () => {},
57
63
  onSort: () => {},
58
- onClickRow: () => {},
59
- overScanBuffer: 0,
60
- scrollToIndex: 0,
61
- onRenderItems: () => {},
62
- selectedMenuItem: null
64
+ handleOnPageChange: () => {}
63
65
  };
64
66
 
65
67
  export default withRouter(ListingTableContent);
@@ -34,22 +34,25 @@ const getSanitizedColumnLabel = columnProp => {
34
34
 
35
35
  const buildArrayRowContent = rowData => (
36
36
  <div className="table-row-list">
37
- {rowData.map(rowGroup => (
38
- <div className="table-row-list__group">
39
- {rowGroup.map(({ label, value, url }) => (
40
- <div className="table-row-list__group__item">
41
- <span className="table-row-list__group__item__label"> {label}:</span>
42
- {url ? (
43
- <Link to={url} role="button" className="table-row-list__group__item__value">
44
- {value}
45
- </Link>
46
- ) : (
47
- <span className="table-row-list__group__item__value"> {value}</span>
48
- )}
49
- </div>
50
- ))}
51
- </div>
52
- ))}
37
+ {rowData.map(rowGroup => {
38
+ if (!rowGroup.length) return null;
39
+ return (
40
+ <div className="table-row-list__group">
41
+ {rowGroup.map(({ label, value, url }) => (
42
+ <div className="table-row-list__group__item">
43
+ <span className="table-row-list__group__item__label"> {label}:</span>
44
+ {url && value ? (
45
+ <Link to={url} role="button" className="table-row-list__group__item__value">
46
+ {value}
47
+ </Link>
48
+ ) : (
49
+ value && <span className="table-row-list__group__item__value"> {value}</span>
50
+ )}
51
+ </div>
52
+ ))}
53
+ </div>
54
+ );
55
+ })}
53
56
  </div>
54
57
  );
55
58
 
@@ -41,9 +41,20 @@ const fetchData = async ({ client, querySettings: { entitySchema, queryParams },
41
41
  const isSearchQuery = source === 'search';
42
42
  const query = buildListingQuery(entitySchema, isSearchQuery);
43
43
  const variables = buildVariables({ entitySchema, listFilters, queryParams, isSearchQuery });
44
- const { data = {} } = await client.query({ query, variables, fetchPolicy: 'network-only' });
45
44
 
46
- return data.searchResults ? data.searchResults.results : data.listingData;
45
+ const { data = {} } = await client.query({
46
+ query,
47
+ variables,
48
+ fetchPolicy: 'network-only'
49
+ });
50
+
51
+ if (data.searchResults) {
52
+ return {
53
+ listingData: data.searchResults.results,
54
+ totalRecords: data.searchResults.total
55
+ };
56
+ }
57
+ return data;
47
58
  };
48
59
 
49
60
  export { fetchData };
@@ -0,0 +1,15 @@
1
+ import { useEffect } from 'react';
2
+
3
+ function useCallbackDebounce(callback, delay, dependencies, skip) {
4
+ useEffect(
5
+ () => {
6
+ if (skip) return;
7
+ const timer = setTimeout(callback, delay);
8
+ return () => clearTimeout(timer);
9
+ },
10
+ // eslint-disable-next-line react-hooks/exhaustive-deps
11
+ dependencies
12
+ );
13
+ }
14
+
15
+ export default useCallbackDebounce;
@@ -31,6 +31,7 @@ function buildListingQuery(entitySchema, isSearchQuery) {
31
31
  id,
32
32
  ${entitySchema.listingProperties.join(',\n')}
33
33
  }
34
+ totalRecords: ${entitySchema.actions.countAll}(where: $where)
34
35
  }
35
36
  `;
36
37
  }
@@ -4,7 +4,7 @@ const getDefaultQueryParams = schema => {
4
4
 
5
5
  return {
6
6
  where,
7
- limit: 40,
7
+ limit: 10,
8
8
  offset: 0,
9
9
  sort: updated
10
10
  ? [