@antscorp/antsomi-ui 1.3.5-beta.490 → 1.3.5-beta.491

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.
@@ -13,7 +13,7 @@ var __rest = (this && this.__rest) || function (s, e) {
13
13
  // Libraries
14
14
  import { ConfigProvider } from 'antd';
15
15
  import { uniqBy } from 'lodash';
16
- import React, { useMemo, useState } from 'react';
16
+ import React, { useEffect, useMemo, useState } from 'react';
17
17
  // Components
18
18
  import { EmptyData, Select } from '@antscorp/antsomi-ui/es/components/molecules';
19
19
  import { Button, Flex, Icon, Input, Popover, Scrollbars, Spin, Typography, Tooltip, } from '@antscorp/antsomi-ui/es/components/atoms';
@@ -27,7 +27,7 @@ import { translations } from '@antscorp/antsomi-ui/es/locales/translations';
27
27
  import { MATCHES_ANY_THEME } from './constants';
28
28
  import { globalToken } from '@antscorp/antsomi-ui/es/constants';
29
29
  // Hooks
30
- import { useDeepCompareEffect, useDeepCompareMemo } from '@antscorp/antsomi-ui/es/hooks';
30
+ import { useDeepCompareEffect, useDeepCompareMemo, useIntersectionObserver, } from '@antscorp/antsomi-ui/es/hooks';
31
31
  // Utils
32
32
  import { flatTree, recursiveSearchItems } from '@antscorp/antsomi-ui/es/utils';
33
33
  import { DataIcon } from '../../icons';
@@ -37,16 +37,27 @@ const initialState = {
37
37
  const matchesAnyInitialState = {
38
38
  searchValue: '',
39
39
  selectedItems: [],
40
+ isShowLoadMoreEl: false,
40
41
  };
41
42
  const { t } = i18nInstance;
42
43
  const { Text } = Typography;
43
44
  export const MatchesAny = props => {
44
45
  // Props
45
- const { objectName, loading = false, showExtendValue = true, items, onApply = () => { }, onCancel = () => { } } = props, restOfProps = __rest(props, ["objectName", "loading", "showExtendValue", "items", "onApply", "onCancel"]);
46
+ const { objectName, loading = false, showExtendValue = true, items, onApply = () => { }, onCancel = () => { }, onLoadMore = () => { } } = props, restOfProps = __rest(props, ["objectName", "loading", "showExtendValue", "items", "onApply", "onCancel", "onLoadMore"]);
46
47
  // State
47
48
  const [state, setState] = useState(matchesAnyInitialState);
48
49
  // Variables
49
- const { searchValue, selectedItems } = state;
50
+ const { searchValue, selectedItems, isShowLoadMoreEl } = state;
51
+ // Refs
52
+ const { ref: loadMoreRef } = useIntersectionObserver({
53
+ threshold: 0,
54
+ initialIsIntersecting: false,
55
+ onChange(isIntersecting) {
56
+ if (isIntersecting) {
57
+ onLoadMore();
58
+ }
59
+ },
60
+ });
50
61
  // Effects
51
62
  /**
52
63
  * Updates the `selectedItems` state when the `selectedItems` prop changes.
@@ -54,6 +65,12 @@ export const MatchesAny = props => {
54
65
  useDeepCompareEffect(() => {
55
66
  setState(prev => (Object.assign(Object.assign({}, prev), { selectedItems: props.selectedItems })));
56
67
  }, [props.selectedItems]);
68
+ useEffect(() => {
69
+ // Delay for show load more el
70
+ setTimeout(() => {
71
+ setState(prev => (Object.assign(Object.assign({}, prev), { isShowLoadMoreEl: true })));
72
+ }, 500);
73
+ }, []);
57
74
  // Handlers
58
75
  /**
59
76
  * Adds an item and, if applicable, its leaf descendants to the list of selected items.
@@ -147,7 +164,10 @@ export const MatchesAny = props => {
147
164
  (selectedItem.isExtendValue && selectedItem.title === item.title)))
148
165
  : selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.some(selectedItem => selectedItem.key === item.key ||
149
166
  (selectedItem.isExtendValue && selectedItem.title === item.title));
150
- return Object.assign(Object.assign(Object.assign({}, item), { title: renderItemNodeTitle({ item, onSelectItem }), disabled: isSelected }), (item.children && {
167
+ return Object.assign(Object.assign(Object.assign({}, item), { title: renderItemNodeTitle({
168
+ item,
169
+ onSelectItem,
170
+ }), disabled: isSelected }), (item.children && {
151
171
  children: serializeTreeData(item.children),
152
172
  }));
153
173
  });
@@ -155,8 +175,10 @@ export const MatchesAny = props => {
155
175
  return { treeData, matchedParents };
156
176
  }, [items, searchValue, selectedItems]);
157
177
  const selectedTreeData = useMemo(() => {
158
- const notExtendValueSelectedItems = selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.filter(item => !item.isExtendValue);
159
- const extendValueSelectedItems = selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.filter(item => item.isExtendValue);
178
+ var _a;
179
+ const notExtendValueSelectedItems = (selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.filter(item => !item.isExtendValue)) || [];
180
+ const extendValueSelectedItems = (selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.filter(item => item.isExtendValue)) || [];
181
+ const lazyLoadSelectedItems = (selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.filter(selectedItem => !flatTree(items || [], 'children').some(item => item.key === selectedItem.key))) || [];
160
182
  const serializeTreeData = (list) => {
161
183
  var _a;
162
184
  return ((_a = list
@@ -176,7 +198,7 @@ export const MatchesAny = props => {
176
198
  children: serializeTreeData(item.children),
177
199
  }))))) || [];
178
200
  };
179
- return serializeTreeData(items || []).concat((extendValueSelectedItems === null || extendValueSelectedItems === void 0 ? void 0 : extendValueSelectedItems.map(item => (Object.assign(Object.assign({}, item), { title: renderItemNodeTitle({ item, onRemoveItem }) })))) || []);
201
+ return serializeTreeData(items || []).concat(((_a = [...lazyLoadSelectedItems, ...extendValueSelectedItems]) === null || _a === void 0 ? void 0 : _a.map(item => (Object.assign(Object.assign({}, item), { title: renderItemNodeTitle({ item, onRemoveItem }) })))) || []);
180
202
  }, [items, selectedItems]);
181
203
  const isDisableRemoveAll = useDeepCompareMemo(() => !(selectedTreeData === null || selectedTreeData === void 0 ? void 0 : selectedTreeData.length), [selectedTreeData]);
182
204
  const isDisableSelectAll = useDeepCompareMemo(() => {
@@ -195,21 +217,22 @@ export const MatchesAny = props => {
195
217
  React.createElement(Text, { strong: true }, `${objectName} (${flatTree(items, 'children').filter(item => !item.children).length})`),
196
218
  React.createElement(TextButton, { disabled: isDisableSelectAll, onClick: onSelectAll }, t(translations.global.selectAll).toString())),
197
219
  React.createElement(Spin, { spinning: loading },
198
- React.createElement(Scrollbars, { style: { height: '100%' } }, (treeData === null || treeData === void 0 ? void 0 : treeData.length) ? (React.createElement(StyledTree, { key: searchValue, defaultExpandedKeys: matchedParents.map(item => item.key), selectable: false, treeData: treeData, switcherIcon: props => (React.createElement(Icon, { type: "icon-ants-caret-down", style: {
199
- transform: props.expanded ? 'rotate(0)' : 'rotate(-90deg)',
200
- transition: 'transform 0.3s ease',
201
- }, color: globalToken === null || globalToken === void 0 ? void 0 : globalToken.bw8 })) })) : (React.createElement(EmptyData, { showIcon: false, description: t(translations.global.noResultsMatchesKeyWord).toString() })))))));
220
+ React.createElement(Scrollbars, { style: { height: '100%' } }, (treeData === null || treeData === void 0 ? void 0 : treeData.length) ? (React.createElement(React.Fragment, null,
221
+ React.createElement(StyledTree, { key: searchValue, defaultExpandedKeys: matchedParents.map(item => item.key), selectable: false, treeData: treeData, switcherIcon: props => (React.createElement(Icon, { type: "icon-ants-caret-down", style: {
222
+ transform: props.expanded ? 'rotate(0)' : 'rotate(-90deg)',
223
+ transition: 'transform 0.3s ease',
224
+ }, color: globalToken === null || globalToken === void 0 ? void 0 : globalToken.bw8 })) }),
225
+ isShowLoadMoreEl && React.createElement("div", { ref: loadMoreRef }))) : (React.createElement(EmptyData, { showIcon: false, description: t(translations.global.noResultsMatchesKeyWord).toString() })))))));
202
226
  };
203
227
  const renderSelectedList = () => (React.createElement("div", { className: "matches-any__section" },
204
228
  React.createElement(Flex, { className: "matches-any__header", justify: "space-between" },
205
229
  React.createElement(Text, { strong: true }, `${t(translations.global.selected)} (${(selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length) || 0})`),
206
230
  React.createElement(TextButton, { disabled: isDisableRemoveAll, onClick: onRemoveAll }, t(translations.global.removeAll).toString())),
207
231
  React.createElement("div", { className: "matches-any__body" },
208
- React.createElement(Spin, { spinning: loading },
209
- React.createElement(Scrollbars, { style: { height: '100%' } }, !(selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length) ? (React.createElement(EmptyData, { icon: React.createElement(DataIcon, { color: globalToken === null || globalToken === void 0 ? void 0 : globalToken.bw5, width: 48, height: 48 }), description: t(translations.global.selectItemsFromList).toString() })) : (React.createElement(StyledTree, { selectable: false, treeData: selectedTreeData, switcherIcon: props => (React.createElement(Icon, { type: "icon-ants-caret-down", style: {
210
- transform: props.expanded ? 'rotate(0)' : 'rotate(-90deg)',
211
- transition: 'transform 0.3s ease',
212
- }, color: globalToken === null || globalToken === void 0 ? void 0 : globalToken.bw8 })) })))))));
232
+ React.createElement(Scrollbars, { style: { height: '100%' } }, !(selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length) ? (React.createElement(EmptyData, { icon: React.createElement(DataIcon, { color: globalToken === null || globalToken === void 0 ? void 0 : globalToken.bw5, width: 48, height: 48 }), description: t(translations.global.selectItemsFromList).toString() })) : (React.createElement(StyledTree, { selectable: false, treeData: selectedTreeData, switcherIcon: props => (React.createElement(Icon, { type: "icon-ants-caret-down", style: {
233
+ transform: props.expanded ? 'rotate(0)' : 'rotate(-90deg)',
234
+ transition: 'transform 0.3s ease',
235
+ }, color: globalToken === null || globalToken === void 0 ? void 0 : globalToken.bw8 })) }))))));
213
236
  // Handlers
214
237
  const onApplyExtendValue = (extendValues) => {
215
238
  // Filter out values that are already present in selectedItems
@@ -239,7 +262,7 @@ export const MatchesAny = props => {
239
262
  };
240
263
  export const MatchesAnySelect = props => {
241
264
  var _a, _b, _c;
242
- const { placeholder = 'Select an item', dropdownStyle, objectName, selectedItems, items, loading, popupClassName, onChange = () => { } } = props, restProps = __rest(props, ["placeholder", "dropdownStyle", "objectName", "selectedItems", "items", "loading", "popupClassName", "onChange"]);
265
+ const { placeholder = 'Select an item', dropdownStyle, objectName, selectedItems, items, loading, popupClassName, onChange = () => { }, onLoadMore } = props, restProps = __rest(props, ["placeholder", "dropdownStyle", "objectName", "selectedItems", "items", "loading", "popupClassName", "onChange", "onLoadMore"]);
243
266
  // State
244
267
  const [state, setState] = useState(initialState);
245
268
  // Variables
@@ -252,7 +275,7 @@ export const MatchesAnySelect = props => {
252
275
  onChange(selectedItems);
253
276
  setState(prev => (Object.assign(Object.assign({}, prev), { isOpenPopover: false })));
254
277
  };
255
- return (React.createElement(Popover, { open: isOpenPopover, arrow: false, placement: "bottomLeft", content: React.createElement(MatchesAny, { className: popupClassName, items: items, selectedItems: selectedItems, loading: loading, objectName: objectName, onApply: onApplyMatchesAny, onCancel: () => setState(prev => (Object.assign(Object.assign({}, prev), { isOpenPopover: false }))) }), overlayStyle: { width: 700 }, overlayInnerStyle: {
278
+ return (React.createElement(Popover, { open: isOpenPopover, arrow: false, placement: "bottomLeft", content: React.createElement(MatchesAny, { className: popupClassName, items: items, selectedItems: selectedItems, loading: loading, objectName: objectName, onApply: onApplyMatchesAny, onCancel: () => setState(prev => (Object.assign(Object.assign({}, prev), { isOpenPopover: false }))), onLoadMore: onLoadMore }), overlayStyle: { width: 700 }, overlayInnerStyle: {
256
279
  padding: 0,
257
280
  }, trigger: ['click'], destroyTooltipOnHide: true, onOpenChange: () => setState(prev => (Object.assign(Object.assign({}, prev), { isOpenPopover: !isOpenPopover }))) },
258
281
  React.createElement(Tooltip, { mouseEnterDelay: 0.5, title: `${selectedItems ? selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.map(item => item.title).join(', ') : ''}` },
@@ -20,6 +20,8 @@ export interface MatchesAnySelectProps extends SelectProps {
20
20
  selectedItems?: MatchesAnyItem[];
21
21
  /** Callback function that is called when the selected items change. */
22
22
  onChange?: (selectedItems: MatchesAnyItem[]) => void;
23
+ /** Callback function that is called when the user scroll */
24
+ onLoadMore?: () => void;
23
25
  }
24
26
  export interface MatchesAnyProps extends Omit<FlexProps, 'children'> {
25
27
  /** The name of the object, corresponding to the `objectName` property in `MatchesAnySelectProps`. */
@@ -40,4 +42,6 @@ export interface MatchesAnyProps extends Omit<FlexProps, 'children'> {
40
42
  onApply?: (selectedItems: MatchesAnyItem[]) => void;
41
43
  /** Callback function that is called when the cancel action is triggered. */
42
44
  onCancel?: () => void;
45
+ /** Callback function that is called when the user scroll */
46
+ onLoadMore?: MatchesAnySelectProps['onLoadMore'];
43
47
  }
@@ -13,7 +13,7 @@ import { translations } from '@antscorp/antsomi-ui/es/locales/translations';
13
13
  import { EXCEPTION_OFF_FILTER_CLASS } from '../../constants/filter';
14
14
  export const AddFilterButton = memo(() => {
15
15
  const { t } = i18nInstance;
16
- const { openPopover, selectedFilterMetric, matchesAny, onSelectFilterMetric, onApplyFilterMetricCondition, onClickAddFilter, onChangeFilterCondition, setState: setAddFilterConditionState, } = useAddFilterCondition();
16
+ const { openPopover, selectedFilterMetric, matchesAny, onSelectFilterMetric, onApplyFilterMetricCondition, onClickAddFilter, onChangeFilterCondition, onMatchesAnyLoadMore, setState: setAddFilterConditionState, } = useAddFilterCondition();
17
17
  return (React.createElement(Popover, { open: openPopover, content: React.createElement("div", { className: EXCEPTION_OFF_FILTER_CLASS }, selectedFilterMetric ? (React.createElement(FilterCondition, { filterMetric: selectedFilterMetric, matchesAny: matchesAny, onCancel: () => onSelectFilterMetric(undefined), onApply: ({ operator, value }) => {
18
18
  onApplyFilterMetricCondition({
19
19
  filterMetric: selectedFilterMetric,
@@ -22,7 +22,7 @@ export const AddFilterButton = memo(() => {
22
22
  });
23
23
  onSelectFilterMetric(undefined);
24
24
  setAddFilterConditionState(prev => (Object.assign(Object.assign({}, prev), { openPopover: false })));
25
- }, onChange: condition => {
25
+ }, onLoadMore: () => onMatchesAnyLoadMore(selectedFilterMetric.id), onChange: condition => {
26
26
  const { id, dataType } = selectedFilterMetric;
27
27
  const { operator, value } = condition || {};
28
28
  onChangeFilterCondition({
@@ -11,6 +11,7 @@ interface FilterConditionProps {
11
11
  onCancel?: () => void;
12
12
  onApply?: (values: TFormType) => void;
13
13
  onChange?: (values: TFormType) => void;
14
+ onLoadMore?: () => void;
14
15
  }
15
16
  export declare const FilterCondition: React.FC<FilterConditionProps>;
16
17
  export {};
@@ -11,7 +11,7 @@ import { renderValueField } from '../../../utils';
11
11
  const { BETWEEN, EXISTS, NOT_EXISTS } = OPERATORS_OPTION;
12
12
  export const FilterCondition = props => {
13
13
  // Props
14
- const { filterMetric, filterCondition, matchesAny, onChange, onCancel, onApply } = props;
14
+ const { filterMetric, filterCondition, matchesAny, onChange, onCancel, onApply, onLoadMore } = props;
15
15
  // Hooks
16
16
  const [form] = Form.useForm();
17
17
  // Form
@@ -96,6 +96,7 @@ export const FilterCondition = props => {
96
96
  operator,
97
97
  value,
98
98
  matchesAny,
99
+ onLoadMore,
99
100
  onChangeValue: value => {
100
101
  form.setFieldsValue({
101
102
  value,
@@ -22,7 +22,7 @@ import { translations } from '@antscorp/antsomi-ui/es/locales/translations';
22
22
  const { t } = i18nInstance;
23
23
  export const FilterConditionList = memo(() => {
24
24
  // Store
25
- const { filterMetrics, filters, isFilterActive, matchesAny, onChangeFilters = () => { }, onChangeFilterCondition = () => { }, } = useDataTableContext(store => store.filter);
25
+ const { filterMetrics, filters, isFilterActive, matchesAny, onChangeFilters = () => { }, onChangeFilterCondition = () => { }, onMatchesAnyLoadMore = () => { }, } = useDataTableContext(store => store.filter);
26
26
  const setFilter = useDataTableContext(store => store.setFilter);
27
27
  // State
28
28
  /* Reserve for handle popover open per filter condition */
@@ -80,7 +80,7 @@ export const FilterConditionList = memo(() => {
80
80
  value: condition.value,
81
81
  dataType: metric.dataType,
82
82
  });
83
- }, onCancel: () => handleTogglePopover(index, false) })), trigger: ['click'], overlayInnerStyle: { width: 300, padding: 0, overflow: 'visible' }, arrow: false, placement: "bottomLeft", onOpenChange: open => handleTogglePopover(index, open) },
83
+ }, onLoadMore: () => onMatchesAnyLoadMore(metric.id), onCancel: () => handleTogglePopover(index, false) })), trigger: ['click'], overlayInnerStyle: { width: 300, padding: 0, overflow: 'visible' }, arrow: false, placement: "bottomLeft", onOpenChange: open => handleTogglePopover(index, open) },
84
84
  React.createElement(FilterItem, { gap: 5, onClick: () => setFilter({
85
85
  isFilterActive: true,
86
86
  }), name: (metric === null || metric === void 0 ? void 0 : metric.name) || column.toString() || '', operator: operator, value: value, onClickRemove: () => onClickRemoveFilter(index) })));
@@ -21,6 +21,7 @@ export declare const useAddFilterCondition: () => {
21
21
  onApplyFilterMetricCondition: (values: OnApplyFilterMetricConditionValue) => void;
22
22
  onClickAddFilter: () => void;
23
23
  onChangeFilterCondition: (filterItem: import("../types").FilterItem) => void;
24
+ onMatchesAnyLoadMore: (metricId?: string | number | undefined) => void;
24
25
  openPopover?: boolean | undefined;
25
26
  selectedFilterMetric?: FilterMetricItem | undefined;
26
27
  };
@@ -10,7 +10,7 @@ export const useAddFilterCondition = () => {
10
10
  selectedFilterMetric: undefined,
11
11
  });
12
12
  // Store
13
- const { filters, matchesAny, onChangeFilters = () => { }, onChangeFilterCondition = () => { }, } = useDataTableContext(store => store.filter);
13
+ const { filters, matchesAny, onChangeFilters = () => { }, onChangeFilterCondition = () => { }, onMatchesAnyLoadMore = () => { }, } = useDataTableContext(store => store.filter);
14
14
  const setFilter = useDataTableContext(store => store.setFilter);
15
15
  // Handlers
16
16
  const onSelectFilterMetric = useCallback((filterMetric) => {
@@ -54,5 +54,6 @@ export const useAddFilterCondition = () => {
54
54
  onSelectFilterMetric,
55
55
  onApplyFilterMetricCondition,
56
56
  onClickAddFilter,
57
- onChangeFilterCondition });
57
+ onChangeFilterCondition,
58
+ onMatchesAnyLoadMore });
58
59
  };
@@ -1,6 +1,7 @@
1
1
  // Context
2
2
  import { useDataTableContext } from '../contexts/DataTableContext';
3
3
  import { useDeepCompareEffect } from '@antscorp/antsomi-ui/es/hooks';
4
+ import { omit } from 'lodash';
4
5
  export const useDataTable = (props) => {
5
6
  // Props
6
7
  const { table, toolbar, filter, pagination } = props || {};
@@ -25,7 +26,7 @@ export const useDataTable = (props) => {
25
26
  /* Handle update filter */
26
27
  useDeepCompareEffect(() => {
27
28
  if (filter) {
28
- setFilter(filter);
29
+ setFilter(omit(filter, 'onMatchesAnyLoadMore'));
29
30
  }
30
31
  }, [setFilter, filter]);
31
32
  /* Handle update pagination */
@@ -14,6 +14,7 @@ export type TApiGlobal = AxiosRequestConfig<any> & {
14
14
  type TMatchesAnyParams = (filterItem?: FilterItem) => any | any;
15
15
  type TMatchesAnyProps = {
16
16
  formatData: (response: any) => MatchesAnyItem[];
17
+ total?: (response: any) => number | number;
17
18
  };
18
19
  export type TConfig<TTableType = any> = {
19
20
  env?: TEnv;
@@ -21,7 +21,7 @@ var __rest = (this && this.__rest) || function (s, e) {
21
21
  // Libraries
22
22
  import React, { useCallback, useState } from 'react';
23
23
  import { Link } from 'react-router-dom';
24
- import { isEmpty, pick } from 'lodash';
24
+ import { flatMap, isEmpty, pick } from 'lodash';
25
25
  import { useQueryClient } from '@tanstack/react-query';
26
26
  // Types
27
27
  import { useAppConfigContext } from '@antscorp/antsomi-ui/es/providers';
@@ -33,7 +33,7 @@ import { MODIFY_COLUMN_DISABLE_EDITABLE, MODIFY_COLUMN_DISABLE_REMOVE, SAVED_FIL
33
33
  import { DEFAULT_CELL_EMPTY, DEFAULT_TOGGLE_WIDTH, SORT_MAP } from '../../constants';
34
34
  // Hooks
35
35
  import { useDeepCompareEffect, useDeepCompareMemo } from '@antscorp/antsomi-ui/es/hooks';
36
- import { useCreateModifyColumn, useDeleteModifyColumn, useDeleteSavedFilter, useGetColumnMetrics, useGetFilterMetricList, useGetMatchesAnyList, useGetModifyColumnList, useGetSavedFilterList, useGetSearchListing, useGetTableListing, useSaveFilter, useUpdateFilter, useUpdateModifyColumn, } from '@antscorp/antsomi-ui/es/queries';
36
+ import { useCreateModifyColumn, useDeleteModifyColumn, useDeleteSavedFilter, useGetColumnMetrics, useGetFilterMetricList, useGetInfiniteMatchesAnyList, useGetModifyColumnList, useGetSavedFilterList, useGetSearchListing, useGetTableListing, useSaveFilter, useUpdateFilter, useUpdateModifyColumn, } from '@antscorp/antsomi-ui/es/queries';
37
37
  // Utils
38
38
  import { flatTree, mapResponseSearchToGeneral, parseJSONFromLocalStorage, } from '@antscorp/antsomi-ui/es/utils';
39
39
  import { METRIC_MAP_NUMBER_TYPE } from '../../constants/filter';
@@ -91,6 +91,14 @@ export function useDataTableListing(props) {
91
91
  const matchesAnyRequest = (apiMatchesAny === null || apiMatchesAny === void 0 ? void 0 : apiMatchesAny[`${selectedFilterItem === null || selectedFilterItem === void 0 ? void 0 : selectedFilterItem.column}`.toLowerCase()])
92
92
  ? apiMatchesAny === null || apiMatchesAny === void 0 ? void 0 : apiMatchesAny[`${selectedFilterItem === null || selectedFilterItem === void 0 ? void 0 : selectedFilterItem.column}`.toLowerCase()]
93
93
  : apiMatchesAny === null || apiMatchesAny === void 0 ? void 0 : apiMatchesAny.general;
94
+ /**
95
+ * If `selectedFilterItem` has a column, the function will attempt to find a matching property in the `matchesAny`
96
+ * object by converting the column name to lowercase. If such a property does not exist, it will default to using
97
+ * the `general` property from the `matchesAny` object.
98
+ */
99
+ const matchesAnyProps = (matchesAny === null || matchesAny === void 0 ? void 0 : matchesAny[`${selectedFilterItem === null || selectedFilterItem === void 0 ? void 0 : selectedFilterItem.column}`.toLowerCase()])
100
+ ? matchesAny === null || matchesAny === void 0 ? void 0 : matchesAny[`${selectedFilterItem === null || selectedFilterItem === void 0 ? void 0 : selectedFilterItem.column}`.toLowerCase()]
101
+ : matchesAny === null || matchesAny === void 0 ? void 0 : matchesAny.general;
94
102
  // Memos
95
103
  const mapObject = useDeepCompareMemo(() => ({
96
104
  objType: object === null || object === void 0 ? void 0 : object.type,
@@ -131,7 +139,7 @@ export function useDataTableListing(props) {
131
139
  },
132
140
  options: Object.assign({ enabled: enabledApiFilter }, queryOptions === null || queryOptions === void 0 ? void 0 : queryOptions.getFilterMetricList),
133
141
  });
134
- const getMatchesAnyList = useGetMatchesAnyList({
142
+ const getInfiniteMatchesAnyList = useGetInfiniteMatchesAnyList({
135
143
  args: {
136
144
  auth,
137
145
  params: (_a = matchesAnyRequest === null || matchesAnyRequest === void 0 ? void 0 : matchesAnyRequest.params) === null || _a === void 0 ? void 0 : _a.call(matchesAnyRequest, selectedFilterItem),
@@ -140,9 +148,27 @@ export function useDataTableListing(props) {
140
148
  options: {
141
149
  enabled: !!selectedFilterItem &&
142
150
  [MATCHES_ANY, NOT_MATCHES, MATCHES].includes(selectedFilterItem.operator) &&
143
- !!matchesAnyRequest,
151
+ !!matchesAnyRequest &&
152
+ (typeof matchesAnyRequest.enabled === 'boolean' ? matchesAnyRequest.enabled : true),
144
153
  keepPreviousData: true,
145
154
  retry: false,
155
+ getNextPageParam(lastPage, allPages) {
156
+ // Extract the total number of items from the last fetched page
157
+ const total = (typeof (matchesAnyProps === null || matchesAnyProps === void 0 ? void 0 : matchesAnyProps.total) === 'function'
158
+ ? matchesAnyProps === null || matchesAnyProps === void 0 ? void 0 : matchesAnyProps.total(lastPage)
159
+ : matchesAnyProps === null || matchesAnyProps === void 0 ? void 0 : matchesAnyProps.total) || lastPage.total;
160
+ // Check if the total number of items is defined
161
+ if (total) {
162
+ // Calculate the current total number of items retrieved so far
163
+ // Process all pages and their data using formatData function and flatten the results
164
+ const currentTotalItems = flatMap(allPages === null || allPages === void 0 ? void 0 : allPages.map(page => { var _a; return ((_a = matchesAnyProps === null || matchesAnyProps === void 0 ? void 0 : matchesAnyProps.formatData) === null || _a === void 0 ? void 0 : _a.call(matchesAnyProps, page)) || []; }));
165
+ // If the total number of items fetched is less than the total available,
166
+ // return the next page number (allPages.length + 1). Otherwise, return undefined.
167
+ return ((currentTotalItems === null || currentTotalItems === void 0 ? void 0 : currentTotalItems.length) || 0) < total ? (allPages === null || allPages === void 0 ? void 0 : allPages.length) + 1 : undefined;
168
+ }
169
+ // If the total number of items is not defined, return undefined
170
+ return undefined;
171
+ },
146
172
  },
147
173
  });
148
174
  // Variables
@@ -177,7 +203,7 @@ export function useDataTableListing(props) {
177
203
  const { data: tableListing, isLoading: isTableListingLoading, isRefetching: isTableListingRefetching, } = getTableListing || {};
178
204
  const { body: tableBody, header: tableHeader, total } = tableListing || {};
179
205
  const { data: searchListingData, isLoading: isSearchListingLoading, isFetching: isSearchListingFetching, } = getSearchListing || {};
180
- const { data: matchesAnyListData, isLoading: isMatchesAnyListLoading = false } = getMatchesAnyList || {};
206
+ const { data: infiniteMatchesAnyData, isFetchingNextPage, isLoading: isMatchesAnyListLoading = false, isFetching: isMatchesAnyListFetching = false, fetchNextPage, } = getInfiniteMatchesAnyList || {};
181
207
  // Conditionally format search listing data based on the presence of a formatData function in searchProps.
182
208
  // If formatData is defined, use it to format searchListingData.
183
209
  // Otherwise, use the mapResponseSearchToGeneral function to format searchListingData.
@@ -299,16 +325,16 @@ export function useDataTableListing(props) {
299
325
  return ((searchListingBody === null || searchListingBody === void 0 ? void 0 : searchListingBody.map(searchItem => (Object.assign(Object.assign({}, Object.entries(itemMapKeys || {}).reduce((acc, [key, value]) => (Object.assign(Object.assign({}, acc), { [key]: searchItem[value] })), {})), { icon: typeof icon === 'function' ? icon(searchItem) : icon, link: typeof link === 'function' ? link(searchItem) : link })))) || []);
300
326
  }, [searchListingData, searchProps]);
301
327
  const matchesAnyList = useDeepCompareMemo(() => {
302
- /**
303
- * If `selectedFilterItem` has a column, the function will attempt to find a matching property in the `matchesAny`
304
- * object by converting the column name to lowercase. If such a property does not exist, it will default to using
305
- * the `general` property from the `matchesAny` object.
306
- */
307
- const matchesAnyProps = (matchesAny === null || matchesAny === void 0 ? void 0 : matchesAny[`${selectedFilterItem === null || selectedFilterItem === void 0 ? void 0 : selectedFilterItem.column}`.toLowerCase()])
308
- ? matchesAny === null || matchesAny === void 0 ? void 0 : matchesAny[`${selectedFilterItem === null || selectedFilterItem === void 0 ? void 0 : selectedFilterItem.column}`.toLowerCase()]
309
- : matchesAny === null || matchesAny === void 0 ? void 0 : matchesAny.general;
310
- return (matchesAnyProps === null || matchesAnyProps === void 0 ? void 0 : matchesAnyProps.formatData(matchesAnyListData)) || [];
311
- }, [matchesAny, matchesAnyListData, selectedFilterItem === null || selectedFilterItem === void 0 ? void 0 : selectedFilterItem.column]);
328
+ var _a;
329
+ const { formatData } = matchesAnyProps || {};
330
+ let matchesAnyList = [];
331
+ if (formatData) {
332
+ (_a = infiniteMatchesAnyData === null || infiniteMatchesAnyData === void 0 ? void 0 : infiniteMatchesAnyData.pages) === null || _a === void 0 ? void 0 : _a.forEach(page => {
333
+ matchesAnyList = matchesAnyList.concat((formatData === null || formatData === void 0 ? void 0 : formatData(page)) || []);
334
+ });
335
+ }
336
+ return matchesAnyList;
337
+ }, [matchesAny, infiniteMatchesAnyData, selectedFilterItem === null || selectedFilterItem === void 0 ? void 0 : selectedFilterItem.column]);
312
338
  // Effects
313
339
  /**
314
340
  * Update values from local storage to state
@@ -501,6 +527,11 @@ export function useDataTableListing(props) {
501
527
  exact: false,
502
528
  });
503
529
  }, [name, queryClient]);
530
+ const onMatchesAnyLoadMore = useCallback(() => {
531
+ if (!isFetchingNextPage) {
532
+ fetchNextPage();
533
+ }
534
+ }, [fetchNextPage, isFetchingNextPage]);
504
535
  return {
505
536
  /* Modify Column */
506
537
  modifyColumn: {
@@ -526,11 +557,12 @@ export function useDataTableListing(props) {
526
557
  filterMetrics,
527
558
  matchesAny: {
528
559
  list: matchesAnyList,
529
- isLoading: isMatchesAnyListLoading && !!matchesAnyRequest,
560
+ isLoading: (isMatchesAnyListLoading || isMatchesAnyListFetching) && !!matchesAnyRequest,
530
561
  },
531
562
  onSaveFilter,
532
563
  onChangeFilters,
533
564
  onChangeFilterCondition,
565
+ onMatchesAnyLoadMore,
534
566
  },
535
567
  /* Pagination */
536
568
  pagination: Object.assign(Object.assign({}, pagination), { total, onChange: onChangePagination }),
@@ -50,5 +50,7 @@ export interface FilterProps<TActionKey extends string[] = []> {
50
50
  onSaveFilter?: (args: TOnSaveFilterArgs) => Promise<TConfirmResponse>;
51
51
  /** Handle callback when filter condition changed */
52
52
  onChangeFilterCondition?: (filterItem: FilterItem) => void;
53
+ /** Handle callback when matches any load more */
54
+ onMatchesAnyLoadMore?: (metricId?: FilterMetricItem['id']) => void;
53
55
  }
54
56
  export type TApiFilter = Record<string, any>[];
@@ -17,6 +17,7 @@ type TRenderValueField = {
17
17
  value?: any;
18
18
  matchesAny?: FilterProps['matchesAny'];
19
19
  onChangeValue?: (value: any) => void;
20
+ onLoadMore?: () => void;
20
21
  };
21
22
  type TGetFilterMetricByName = {
22
23
  filterMetrics: FilterMetricItem[];
@@ -74,7 +75,7 @@ export declare const serializeFilterMetricsToMenuItems: ({ filterMetrics, level,
74
75
  * // ]
75
76
  */
76
77
  export declare const flatFilterMetrics: (filterMetrics: FilterMetricItem[]) => FilterMetricItem[];
77
- export declare const renderValueField: ({ filterMetric, operator, value, matchesAny, onChangeValue, }: TRenderValueField) => React.JSX.Element | null;
78
+ export declare const renderValueField: ({ filterMetric, operator, value, matchesAny, onLoadMore, onChangeValue, }: TRenderValueField) => React.JSX.Element | null;
78
79
  /**
79
80
  * Retrieves a filter metric by its name from a collection of filter metrics.
80
81
  *
@@ -104,7 +104,7 @@ export const flatFilterMetrics = (filterMetrics) => filterMetrics.reduce((acc, c
104
104
  return [...acc, cur];
105
105
  }, []);
106
106
  /* Render Value Field */
107
- export const renderValueField = ({ filterMetric, operator, value, matchesAny, onChangeValue = () => { }, }) => {
107
+ export const renderValueField = ({ filterMetric, operator, value, matchesAny, onLoadMore = () => { }, onChangeValue = () => { }, }) => {
108
108
  const { dataType, name } = filterMetric;
109
109
  switch (operator) {
110
110
  case OPERATORS_CODE.GREATER_THAN:
@@ -160,7 +160,7 @@ export const renderValueField = ({ filterMetric, operator, value, matchesAny, on
160
160
  case OPERATORS_CODE.MATCHES_ANY:
161
161
  case OPERATORS_CODE.NOT_MATCHES: {
162
162
  const { list, isLoading } = matchesAny || {};
163
- return (React.createElement(MatchesAnySelect, { selectedItems: Array.isArray(value) ? value : [], popupClassName: EXCEPTION_OFF_FILTER_CLASS, objectName: name, items: list, loading: isLoading, onChange: onChangeValue }));
163
+ return (React.createElement(MatchesAnySelect, { selectedItems: Array.isArray(value) ? value : [], popupClassName: EXCEPTION_OFF_FILTER_CLASS, objectName: name, items: list, loading: isLoading, onChange: onChangeValue, onLoadMore: onLoadMore }));
164
164
  }
165
165
  case OPERATORS_CODE.AFTER:
166
166
  case OPERATORS_CODE.AFTER_DATE:
@@ -102,6 +102,7 @@ export const useTemplateListing = (options) => {
102
102
  // enabled: false,
103
103
  // },
104
104
  });
105
+ console.log('infiniteObjectTemplate', infiniteObjectTemplate);
105
106
  // useDeepCompareEffect(() => {
106
107
  // refetchTemplateList();
107
108
  // }, [getTemplateListParams]);
@@ -34,4 +34,5 @@ export declare const QUERY_KEYS: {
34
34
  GET_FILTER_METRIC_LIST: string;
35
35
  GET_SEARCH_LIST: string;
36
36
  GET_MATCHES_ANY_LIST: string;
37
+ GET_INFINITE_MATCHES_ANY_LIST: string;
37
38
  };
@@ -47,4 +47,5 @@ export const QUERY_KEYS = {
47
47
  GET_FILTER_METRIC_LIST: 'GET_FILTER_METRIC_LIST',
48
48
  GET_SEARCH_LIST: 'GET_SEARCH_LIST',
49
49
  GET_MATCHES_ANY_LIST: 'GET_MATCHES_ANY_LIST',
50
+ GET_INFINITE_MATCHES_ANY_LIST: 'GET_INFINITE_MATCHES_ANY_LIST',
50
51
  };
@@ -1,4 +1,4 @@
1
- import { UseMutationOptions, UseQueryOptions } from '@tanstack/react-query';
1
+ import { UseInfiniteQueryOptions, UseMutationOptions, UseQueryOptions } from '@tanstack/react-query';
2
2
  import { TCreateModifyColumnArgs, TDeleteModifyColumnArgs, TDeleteSavedFilterArgs, TGetFilterMetricListArgs, TGetMatchesAnyListArgs, TGetMetricListArgs, TGetModifyColumnListArgs, TGetSavedFilterListArgs, TGetSearchListingArgs, TGetTableListingArgs, TSaveFilterArgs, TUpdateFilterArgs, TUpdateModifyColumnArgs } from '../../services/DataTable';
3
3
  import { ColumnMetric, FilterMetric, ModifyColumn } from '../../models/DataTable';
4
4
  import { SavedFilter } from '../../models/DataTable/SavedFilter';
@@ -41,6 +41,10 @@ export type TGetMatchesAnyList = {
41
41
  args: TGetMatchesAnyListArgs;
42
42
  options?: UseQueryOptions<any, any, any, any[]>;
43
43
  };
44
+ export type TGetInfiniteMatchesAnyList = {
45
+ args: TGetMatchesAnyListArgs;
46
+ options?: UseInfiniteQueryOptions<any, any, any, any[]>;
47
+ };
44
48
  export type TSaveFilter = {
45
49
  auth: TSaveFilterArgs['auth'];
46
50
  options?: UseMutationOptions<{
@@ -92,3 +96,4 @@ export declare const useDeleteSavedFilter: (params?: TDeleteSavedFilter) => impo
92
96
  export declare const useGetTableListing: <T>(params: TGetTableListing<T>) => import("@tanstack/react-query").UseQueryResult<DataTableListing<T>, any>;
93
97
  export declare const useGetSearchListing: (params: TGetSearchListing) => import("@tanstack/react-query").UseQueryResult<any, any>;
94
98
  export declare const useGetMatchesAnyList: (params: TGetMatchesAnyList) => import("@tanstack/react-query").UseQueryResult<any, any>;
99
+ export declare const useGetInfiniteMatchesAnyList: (params: TGetMatchesAnyList) => import("@tanstack/react-query").UseInfiniteQueryResult<any, any>;
@@ -1,11 +1,11 @@
1
1
  // Types
2
- import { useMutation, useQuery, useQueryClient, } from '@tanstack/react-query';
2
+ import { useInfiniteQuery, useMutation, useQuery, useQueryClient, } from '@tanstack/react-query';
3
3
  import { omit } from 'lodash';
4
4
  // Services
5
5
  import { dataTableServices, } from '../../services/DataTable';
6
6
  // Constants
7
7
  import { QUERY_KEYS } from '../../constants';
8
- const { GET_COLUMN_METRICS, GET_MODIFY_COLUMN_LIST, GET_SAVED_FILTER_LIST, GET_FILTER_METRIC_LIST, GET_SEARCH_LIST, GET_MATCHES_ANY_LIST, GET_DATA_TABLE_LISTING, } = QUERY_KEYS;
8
+ const { GET_COLUMN_METRICS, GET_MODIFY_COLUMN_LIST, GET_SAVED_FILTER_LIST, GET_FILTER_METRIC_LIST, GET_SEARCH_LIST, GET_MATCHES_ANY_LIST, GET_DATA_TABLE_LISTING, GET_INFINITE_MATCHES_ANY_LIST, } = QUERY_KEYS;
9
9
  /* Column */
10
10
  export const useGetColumnMetrics = (params) => {
11
11
  const { args, options } = params;
@@ -91,3 +91,7 @@ export const useGetMatchesAnyList = (params) => {
91
91
  const { args, options } = params || {};
92
92
  return useQuery(Object.assign({ queryKey: [GET_MATCHES_ANY_LIST, args], queryFn: ({ signal }) => dataTableServices.filter.getMatchesAnyList(Object.assign(Object.assign({}, args), { request: Object.assign(Object.assign({}, args.request), { signal }) })) }, options));
93
93
  };
94
+ export const useGetInfiniteMatchesAnyList = (params) => {
95
+ const { args, options } = params || {};
96
+ return useInfiniteQuery(Object.assign({ queryKey: [GET_INFINITE_MATCHES_ANY_LIST, args], queryFn: ({ signal, pageParam = 1 }) => dataTableServices.filter.getMatchesAnyList(Object.assign(Object.assign({}, args), { request: Object.assign(Object.assign({}, args.request), { signal }), params: Object.assign(Object.assign({}, args.params), { page: pageParam }) })), getNextPageParam: () => undefined }, options));
97
+ };
@@ -49,12 +49,11 @@ export const DataTableTest = () => {
49
49
  },
50
50
  },
51
51
  survey_id: {
52
- url: 'https://sandbox-survey.antsomi.com/api/v1/survey/filter/get-value-matches-any',
53
- params(filterItem) {
54
- var _a;
52
+ url: 'https://sandbox-survey.antsomi.com/api/v1/survey/performance',
53
+ params() {
55
54
  return {
56
- test: 'survey_id',
57
- metric_code: (_a = filterItem === null || filterItem === void 0 ? void 0 : filterItem.column) === null || _a === void 0 ? void 0 : _a.toString().toLowerCase(),
55
+ page: 1,
56
+ limit: 20,
58
57
  };
59
58
  },
60
59
  },
@@ -100,24 +99,24 @@ export const DataTableTest = () => {
100
99
  },
101
100
  survey_id: {
102
101
  formatData(response) {
103
- return response === null || response === void 0 ? void 0 : response.rows.map(record => ({
104
- key: record.value,
105
- title: record.value,
102
+ return response === null || response === void 0 ? void 0 : response.body.map(record => ({
103
+ key: record.survey_id,
104
+ title: record.survey_id,
106
105
  }));
107
106
  },
108
107
  },
109
108
  },
110
- formatFilterValue: {
111
- matches(value) {
112
- return Array.isArray(value) && value.map(item => item.key).join(',');
113
- },
114
- matches_any(value) {
115
- return Array.isArray(value) && value.map(item => item.key).join(',');
116
- },
117
- not_matches(value) {
118
- return Array.isArray(value) && value.map(item => item.key).join(',');
119
- },
120
- },
109
+ // formatFilterValue: {
110
+ // matches(value) {
111
+ // return Array.isArray(value) && value.map(item => item.key).join(',');
112
+ // },
113
+ // matches_any(value) {
114
+ // return Array.isArray(value) && value.map(item => item.key).join(',');
115
+ // },
116
+ // not_matches(value) {
117
+ // return Array.isArray(value) && value.map(item => item.key).join(',');
118
+ // },
119
+ // },
121
120
  },
122
121
  });
123
122
  return (React.createElement(BrowserRouter, null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antscorp/antsomi-ui",
3
- "version": "1.3.5-beta.490",
3
+ "version": "1.3.5-beta.491",
4
4
  "description": "An enterprise-class UI design language and React UI library.",
5
5
  "sideEffects": [
6
6
  "dist/*",