@antscorp/antsomi-ui 1.3.5-beta.473 → 1.3.5-beta.474
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/es/components/icons/EventIcon.js +1 -1
- package/es/components/molecules/DatePicker/DatePicker.js +6 -0
- package/es/components/molecules/MatchAnySelect/MatchesAnySelect.js +14 -11
- package/es/components/molecules/MatchAnySelect/styled.js +14 -1
- package/es/components/molecules/MatchAnySelect/types.d.ts +5 -3
- package/es/components/organism/DataTable/components/Filter/AddFilterButton.js +11 -2
- package/es/components/organism/DataTable/components/Filter/FilterCondition/index.d.ts +3 -1
- package/es/components/organism/DataTable/components/Filter/FilterCondition/index.js +11 -4
- package/es/components/organism/DataTable/components/Filter/FilterConditionList.js +12 -10
- package/es/components/organism/DataTable/components/Filter/FilterItem.js +36 -6
- package/es/components/organism/DataTable/components/Toolbar/styled.js +1 -1
- package/es/components/organism/DataTable/constants/theme.js +2 -0
- package/es/components/organism/DataTable/hooks/useAddFilterButton.d.ts +5 -0
- package/es/components/organism/DataTable/hooks/useAddFilterButton.js +4 -2
- package/es/components/organism/DataTable/hooks/useDataTableListing/types.d.ts +15 -3
- package/es/components/organism/DataTable/hooks/useDataTableListing/useDataTableListing.d.ts +1 -0
- package/es/components/organism/DataTable/hooks/useDataTableListing/useDataTableListing.js +59 -13
- package/es/components/organism/DataTable/types/filter.d.ts +7 -0
- package/es/components/organism/DataTable/utils/filter.d.ts +4 -2
- package/es/components/organism/DataTable/utils/filter.js +46 -10
- package/es/constants/condition.d.ts +15 -0
- package/es/constants/condition.js +15 -0
- package/es/constants/datetime.d.ts +4 -0
- package/es/constants/datetime.js +4 -0
- package/es/constants/queries.d.ts +1 -0
- package/es/constants/queries.js +1 -0
- package/es/constants/theme.js +1 -0
- package/es/locales/en/translation.json +2 -1
- package/es/locales/i18n.d.ts +2 -0
- package/es/locales/translations.d.ts +1 -0
- package/es/locales/vi/translation.json +2 -1
- package/es/queries/DataTable/index.d.ts +6 -1
- package/es/queries/DataTable/index.js +5 -1
- package/es/services/DataTable/index.d.ts +7 -0
- package/es/services/DataTable/index.js +16 -4
- package/es/tests/DataTableTest.js +45 -12
- package/package.json +1 -1
|
@@ -14,5 +14,5 @@ export const EventIcon = (_a) => {
|
|
|
14
14
|
var props = __rest(_a, []);
|
|
15
15
|
return (React.createElement("svg", Object.assign({ xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 0 24 24", width: "24px", fill: "currentColor" }, props),
|
|
16
16
|
React.createElement("path", { d: "M0 0h24v24H0V0z", fill: "none" }),
|
|
17
|
-
React.createElement("path", { d: "
|
|
17
|
+
React.createElement("path", { d: "M16 13h-3c-.55 0-1 .45-1 1v3c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-3c0-.55-.45-1-1-1zm0-10v1H8V3c0-.55-.45-1-1-1s-1 .45-1 1v1H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2h-1V3c0-.55-.45-1-1-1s-1 .45-1 1zm2 17H6c-.55 0-1-.45-1-1V9h14v10c0 .55-.45 1-1 1z" })));
|
|
18
18
|
};
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
// Libraries
|
|
2
|
+
import React from 'react';
|
|
2
3
|
import { DatePicker as AntdDatePicker } from 'antd';
|
|
3
4
|
// Components
|
|
4
5
|
import { AdvancedPicker } from './components/AdvancedPicker';
|
|
5
6
|
import { AdvancedRangePicker } from './components/AdvancedRangePicker';
|
|
7
|
+
import { EventIcon } from '../../icons';
|
|
8
|
+
import { globalToken } from '@antscorp/antsomi-ui/es/constants';
|
|
6
9
|
export const DatePicker = AntdDatePicker;
|
|
10
|
+
DatePicker.defaultProps = {
|
|
11
|
+
suffixIcon: React.createElement(EventIcon, { width: 20, height: 20, color: globalToken === null || globalToken === void 0 ? void 0 : globalToken.bw8 }),
|
|
12
|
+
};
|
|
7
13
|
DatePicker.AdvancedPicker = AdvancedPicker;
|
|
8
14
|
DatePicker.AdvancedRangePicker = AdvancedRangePicker;
|
|
@@ -41,7 +41,7 @@ const { t } = i18nInstance;
|
|
|
41
41
|
const { Text } = Typography;
|
|
42
42
|
export const MatchesAny = props => {
|
|
43
43
|
// Props
|
|
44
|
-
const { objectName,
|
|
44
|
+
const { objectName, loading = false, showExtendValue = true, items, onApply = () => { }, onCancel = () => { } } = props, restOfProps = __rest(props, ["objectName", "loading", "showExtendValue", "items", "onApply", "onCancel"]);
|
|
45
45
|
// State
|
|
46
46
|
const [state, setState] = useState(matchesAnyInitialState);
|
|
47
47
|
// Variables
|
|
@@ -104,9 +104,11 @@ export const MatchesAny = props => {
|
|
|
104
104
|
setState(prev => (Object.assign(Object.assign({}, prev), { selectedItems: [] })));
|
|
105
105
|
};
|
|
106
106
|
const renderItemNodeTitle = ({ item, onSelectItem, onRemoveItem, }) => {
|
|
107
|
-
const { isExtendValue, title } = item; // Destructure properties from item
|
|
107
|
+
const { isExtendValue, title, subTitle } = item; // Destructure properties from item
|
|
108
108
|
return (React.createElement(React.Fragment, null,
|
|
109
|
-
React.createElement(
|
|
109
|
+
React.createElement("div", { className: "title-content" },
|
|
110
|
+
React.createElement(Text, { ellipsis: { tooltip: true } }, title),
|
|
111
|
+
subTitle && (React.createElement(Text, { className: "sub-title", ellipsis: { tooltip: true }, style: { color: globalToken === null || globalToken === void 0 ? void 0 : globalToken.bw8 } }, subTitle))),
|
|
110
112
|
React.createElement(Flex, { align: "center", gap: 5 },
|
|
111
113
|
isExtendValue && (React.createElement(Icon, { type: "icon-ants-empty-flag", size: 20, color: globalToken === null || globalToken === void 0 ? void 0 : globalToken.colorPrimary })),
|
|
112
114
|
React.createElement(ActionButton, { className: "select-button", align: "center", justify: "center", onClick: () => {
|
|
@@ -191,18 +193,18 @@ export const MatchesAny = props => {
|
|
|
191
193
|
React.createElement(Flex, { align: "center", justify: "space-between" },
|
|
192
194
|
React.createElement(Text, { strong: true }, `${objectName} (${flatTree(items, 'children').filter(item => !item.children).length})`),
|
|
193
195
|
React.createElement(TextButton, { disabled: isDisableSelectAll, onClick: onSelectAll }, t(translations.global.selectAll).toString())),
|
|
194
|
-
React.createElement(Spin, { spinning:
|
|
196
|
+
React.createElement(Spin, { spinning: loading },
|
|
195
197
|
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: {
|
|
196
198
|
transform: props.expanded ? 'rotate(0)' : 'rotate(-90deg)',
|
|
197
199
|
transition: 'transform 0.3s ease',
|
|
198
|
-
}, color: globalToken === null || globalToken === void 0 ? void 0 : globalToken.bw8 })) })) : (React.createElement(EmptyData, { showIcon: false,
|
|
200
|
+
}, color: globalToken === null || globalToken === void 0 ? void 0 : globalToken.bw8 })) })) : (React.createElement(EmptyData, { showIcon: false, description: t(translations.global.noResultsMatchesKeyWord).toString() })))))));
|
|
199
201
|
};
|
|
200
202
|
const renderSelectedList = () => (React.createElement("div", { className: "matches-any__section" },
|
|
201
203
|
React.createElement(Flex, { className: "matches-any__header", justify: "space-between" },
|
|
202
204
|
React.createElement(Text, { strong: true }, `${t(translations.global.selected)} (${(selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length) || 0})`),
|
|
203
205
|
React.createElement(TextButton, { disabled: isDisableRemoveAll, onClick: onRemoveAll }, t(translations.global.removeAll).toString())),
|
|
204
206
|
React.createElement("div", { className: "matches-any__body" },
|
|
205
|
-
React.createElement(Spin, { spinning:
|
|
207
|
+
React.createElement(Spin, { spinning: loading },
|
|
206
208
|
React.createElement(Scrollbars, { style: { height: '100%' } }, !(selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length) ? (React.createElement(EmptyData, { icon: "icon-ants-database", description: t(translations.global.selectItemsFromList).toString() })) : (React.createElement(StyledTree, { selectable: false, treeData: selectedTreeData, switcherIcon: props => (React.createElement(Icon, { type: "icon-ants-caret-down", style: {
|
|
207
209
|
transform: props.expanded ? 'rotate(0)' : 'rotate(-90deg)',
|
|
208
210
|
transition: 'transform 0.3s ease',
|
|
@@ -236,12 +238,11 @@ export const MatchesAny = props => {
|
|
|
236
238
|
};
|
|
237
239
|
export const MatchesAnySelect = props => {
|
|
238
240
|
var _a, _b, _c;
|
|
239
|
-
const { placeholder = 'Select an item', dropdownStyle, objectName, selectedItems, items,
|
|
241
|
+
const { placeholder = 'Select an item', dropdownStyle, objectName, selectedItems, items, loading, popupClassName, onChange = () => { } } = props, restProps = __rest(props, ["placeholder", "dropdownStyle", "objectName", "selectedItems", "items", "loading", "popupClassName", "onChange"]);
|
|
240
242
|
// State
|
|
241
243
|
const [state, setState] = useState(initialState);
|
|
242
244
|
// Variables
|
|
243
245
|
const { isOpenPopover } = state;
|
|
244
|
-
// Memo
|
|
245
246
|
const value = Array.isArray(selectedItems) && (selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length)
|
|
246
247
|
? `${(_a = selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.map(item => item.title)) === null || _a === void 0 ? void 0 : _a[0]}${((_b = selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.slice(1)) === null || _b === void 0 ? void 0 : _b.length) ? `, and +${(_c = selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.slice(1)) === null || _c === void 0 ? void 0 : _c.length} more` : ''}` || []
|
|
247
248
|
: undefined;
|
|
@@ -250,7 +251,9 @@ export const MatchesAnySelect = props => {
|
|
|
250
251
|
onChange(selectedItems);
|
|
251
252
|
setState(prev => (Object.assign(Object.assign({}, prev), { isOpenPopover: false })));
|
|
252
253
|
};
|
|
253
|
-
return (React.createElement(Popover, { open: isOpenPopover, arrow: false, placement: "bottomLeft", content: React.createElement(MatchesAny, { items: items, selectedItems: selectedItems,
|
|
254
|
-
|
|
255
|
-
|
|
254
|
+
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: {
|
|
255
|
+
padding: 0,
|
|
256
|
+
}, trigger: ['click'], destroyTooltipOnHide: true, onOpenChange: () => setState(prev => (Object.assign(Object.assign({}, prev), { isOpenPopover: !isOpenPopover }))) },
|
|
257
|
+
React.createElement(Tooltip, { mouseEnterDelay: 0.5, title: `${selectedItems ? selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.map(item => item.title).join(', ') : ''}` },
|
|
258
|
+
React.createElement(Select, Object.assign({ title: "", value: value, placeholder: placeholder, popupMatchSelectWidth: 700, dropdownStyle: Object.assign(Object.assign({}, dropdownStyle), { display: 'none', padding: 0 }), loading: loading }, restProps)))));
|
|
256
259
|
};
|
|
@@ -90,6 +90,19 @@ export const MatchesAnyWrapper = styled(Flex) `
|
|
|
90
90
|
align-items: center;
|
|
91
91
|
justify-content: space-between;
|
|
92
92
|
gap: 10px;
|
|
93
|
+
|
|
94
|
+
.title-content {
|
|
95
|
+
padding: 5px 0px;
|
|
96
|
+
display: flex;
|
|
97
|
+
flex-direction: column;
|
|
98
|
+
width: 100%;
|
|
99
|
+
height: 100%;
|
|
100
|
+
overflow: auto;
|
|
101
|
+
|
|
102
|
+
.sub-title {
|
|
103
|
+
font-size: 11px;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
93
106
|
}
|
|
94
107
|
}
|
|
95
108
|
|
|
@@ -113,7 +126,7 @@ export const MatchesAnyWrapper = styled(Flex) `
|
|
|
113
126
|
|
|
114
127
|
&.antsomi-tree-treenode-disabled {
|
|
115
128
|
.antsomi-typography {
|
|
116
|
-
color: ${globalToken === null || globalToken === void 0 ? void 0 : globalToken.bw6};
|
|
129
|
+
color: ${globalToken === null || globalToken === void 0 ? void 0 : globalToken.bw6} !important;
|
|
117
130
|
}
|
|
118
131
|
|
|
119
132
|
.select-button {
|
|
@@ -2,14 +2,16 @@ import { TreeDataNode } from 'antd';
|
|
|
2
2
|
import type { SelectProps } from '@antscorp/antsomi-ui/es/components/molecules';
|
|
3
3
|
import type { FlexProps } from '@antscorp/antsomi-ui/es/components/atoms';
|
|
4
4
|
export type MatchesAnyItem = TreeDataNode & {
|
|
5
|
+
/** Addition title of the item. */
|
|
6
|
+
subTitle?: string;
|
|
7
|
+
/** Indicates whether the item is extended */
|
|
5
8
|
isExtendValue?: boolean;
|
|
9
|
+
/** An array of children items. */
|
|
6
10
|
children?: MatchesAnyItem[];
|
|
7
11
|
};
|
|
8
12
|
export interface MatchesAnySelectProps extends SelectProps {
|
|
9
13
|
/** The name of object to be displayed in Popover */
|
|
10
14
|
objectName?: string;
|
|
11
|
-
/** Indicates whether the component is loading */
|
|
12
|
-
isLoading?: boolean;
|
|
13
15
|
/** Indicates whether show the extend value button */
|
|
14
16
|
showExtendValue?: boolean;
|
|
15
17
|
/** An array of items. */
|
|
@@ -23,7 +25,7 @@ export interface MatchesAnyProps extends Omit<FlexProps, 'children'> {
|
|
|
23
25
|
/** The name of the object, corresponding to the `objectName` property in `MatchesAnySelectProps`. */
|
|
24
26
|
objectName?: MatchesAnySelectProps['objectName'];
|
|
25
27
|
/** Indicates whether the component is in a loading state, corresponding to the `isLoading` property in `MatchesAnySelectProps`. */
|
|
26
|
-
|
|
28
|
+
loading?: MatchesAnySelectProps['loading'];
|
|
27
29
|
/** Determines whether to show the extended value, corresponding to the `showExtendValue` property in `MatchesAnySelectProps`. */
|
|
28
30
|
showExtendValue?: MatchesAnySelectProps['showExtendValue'];
|
|
29
31
|
/** An array of items. */
|
|
@@ -13,8 +13,8 @@ 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, onSelectFilterMetric, onApplyFilterMetricCondition, onClickAddFilter, setState: setAddFilterConditionState, } = useAddFilterCondition();
|
|
17
|
-
return (React.createElement(Popover, { open: openPopover, content: React.createElement("div", { className: EXCEPTION_OFF_FILTER_CLASS }, selectedFilterMetric ? (React.createElement(FilterCondition, { filterMetric: selectedFilterMetric, onCancel: () => onSelectFilterMetric(undefined), onApply: ({ operator, value }) => {
|
|
16
|
+
const { openPopover, selectedFilterMetric, matchesAny, onSelectFilterMetric, onApplyFilterMetricCondition, onClickAddFilter, onChangeFilterCondition, setState: setAddFilterConditionState, } = useAddFilterCondition();
|
|
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,
|
|
20
20
|
operator,
|
|
@@ -22,6 +22,15 @@ export const AddFilterButton = memo(() => {
|
|
|
22
22
|
});
|
|
23
23
|
onSelectFilterMetric(undefined);
|
|
24
24
|
setAddFilterConditionState(prev => (Object.assign(Object.assign({}, prev), { openPopover: false })));
|
|
25
|
+
}, onChange: condition => {
|
|
26
|
+
const { id, dataType } = selectedFilterMetric;
|
|
27
|
+
const { operator, value } = condition || {};
|
|
28
|
+
onChangeFilterCondition({
|
|
29
|
+
column: id,
|
|
30
|
+
operator,
|
|
31
|
+
value,
|
|
32
|
+
dataType,
|
|
33
|
+
});
|
|
25
34
|
} })) : (React.createElement(SavedFilterAndMetrics, { onSelectFilterMetric: onSelectFilterMetric, onSelectSavedFilter: () => {
|
|
26
35
|
setAddFilterConditionState(prev => (Object.assign(Object.assign({}, prev), { openPopover: false })));
|
|
27
36
|
} }))), trigger: ['click'], overlayInnerStyle: { width: 300, padding: 0 }, arrow: false, placement: "bottomLeft", destroyTooltipOnHide: true, onOpenChange: open => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { FilterItem, FilterMetricItem } from '../../../types';
|
|
2
|
+
import { FilterItem, FilterMetricItem, FilterProps } from '../../../types';
|
|
3
3
|
type TFormType = {
|
|
4
4
|
operator: string;
|
|
5
5
|
value: any;
|
|
@@ -7,8 +7,10 @@ type TFormType = {
|
|
|
7
7
|
interface FilterConditionProps {
|
|
8
8
|
filterMetric: FilterMetricItem;
|
|
9
9
|
filterCondition?: FilterItem;
|
|
10
|
+
matchesAny?: FilterProps['matchesAny'];
|
|
10
11
|
onCancel?: () => void;
|
|
11
12
|
onApply?: (values: TFormType) => void;
|
|
13
|
+
onChange?: (values: TFormType) => void;
|
|
12
14
|
}
|
|
13
15
|
export declare const FilterCondition: React.FC<FilterConditionProps>;
|
|
14
16
|
export {};
|
|
@@ -10,12 +10,12 @@ import { EXCEPTION_OFF_FILTER_CLASS } from '../../../constants/filter';
|
|
|
10
10
|
const { BETWEEN, EXISTS, NOT_EXISTS } = OPERATORS_OPTION;
|
|
11
11
|
export const FilterCondition = props => {
|
|
12
12
|
// Props
|
|
13
|
-
const { filterMetric, filterCondition, onCancel, onApply } = props;
|
|
13
|
+
const { filterMetric, filterCondition, matchesAny, onChange, onCancel, onApply } = props;
|
|
14
14
|
// Hooks
|
|
15
15
|
const [form] = Form.useForm();
|
|
16
16
|
// Form
|
|
17
|
-
const
|
|
18
|
-
const value =
|
|
17
|
+
const formValues = Form.useWatch([], form);
|
|
18
|
+
const { operator, value } = formValues || {};
|
|
19
19
|
// Variables
|
|
20
20
|
const { name, dataType, operators } = filterMetric;
|
|
21
21
|
// Memos
|
|
@@ -53,6 +53,12 @@ export const FilterCondition = props => {
|
|
|
53
53
|
operator: ((_a = operatorList[0]) === null || _a === void 0 ? void 0 : _a.value) || '',
|
|
54
54
|
});
|
|
55
55
|
}, [form, operatorList]);
|
|
56
|
+
/** Handle callback change values */
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (formValues) {
|
|
59
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(formValues);
|
|
60
|
+
}
|
|
61
|
+
}, [formValues, onChange]);
|
|
56
62
|
/* Update filter condition values */
|
|
57
63
|
useEffect(() => {
|
|
58
64
|
if (filterCondition) {
|
|
@@ -82,12 +88,13 @@ export const FilterCondition = props => {
|
|
|
82
88
|
React.createElement(Form.Item, { name: "operator", noStyle: true },
|
|
83
89
|
React.createElement(Select, { value: operator, options: operatorList, onChange: () => form.setFieldsValue({
|
|
84
90
|
value: '',
|
|
85
|
-
}),
|
|
91
|
+
}), dropdownRender: menu => (React.createElement("div", { className: EXCEPTION_OFF_FILTER_CLASS, onClick: e => e.stopPropagation() }, menu)) })),
|
|
86
92
|
React.createElement(Form.Item, { name: "value", noStyle: true }),
|
|
87
93
|
renderValueField({
|
|
88
94
|
filterMetric,
|
|
89
95
|
operator,
|
|
90
96
|
value,
|
|
97
|
+
matchesAny,
|
|
91
98
|
onChangeValue: value => {
|
|
92
99
|
form.setFieldsValue({
|
|
93
100
|
value,
|
|
@@ -6,7 +6,7 @@ import { Button, Flex, Icon, Popover } from '@antscorp/antsomi-ui/es/components/
|
|
|
6
6
|
import { FilterCondition } from './FilterCondition';
|
|
7
7
|
// Constants
|
|
8
8
|
import { EXCEPTION_OFF_FILTER_CLASS, FILTER_SHOW_MAX } from '../../constants/filter';
|
|
9
|
-
import {
|
|
9
|
+
import { globalToken } from '@antscorp/antsomi-ui/es/constants';
|
|
10
10
|
// Contexts
|
|
11
11
|
import { useDataTableContext } from '../../contexts/DataTableContext';
|
|
12
12
|
// Hooks
|
|
@@ -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, onChangeFilters = () => { }, } = useDataTableContext(store => store.filter);
|
|
25
|
+
const { filterMetrics, filters, isFilterActive, matchesAny, onChangeFilters = () => { }, onChangeFilterCondition = () => { }, } = 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 */
|
|
@@ -60,36 +60,38 @@ export const FilterConditionList = memo(() => {
|
|
|
60
60
|
onChangeFilters(cloneFilters || []);
|
|
61
61
|
};
|
|
62
62
|
const renderFilterItem = () => serializeFilters === null || serializeFilters === void 0 ? void 0 : serializeFilters.map((filter, index) => {
|
|
63
|
-
var _a;
|
|
64
63
|
const { column, operator, value, isOpenPopover } = filter;
|
|
65
64
|
const metric = flattenFilterMetrics === null || flattenFilterMetrics === void 0 ? void 0 : flattenFilterMetrics.find(filterMetric => filterMetric.id === column);
|
|
66
|
-
const operatorLabel = ((_a = Object.values(OPERATORS_OPTION).find(({ value }) => value === operator)) === null || _a === void 0 ? void 0 : _a.label) || '';
|
|
67
65
|
// Hide too many filter when filter is active
|
|
68
66
|
if (!metric || (!isFilterActive && index + 1 > FILTER_SHOW_MAX))
|
|
69
67
|
return null;
|
|
70
68
|
return (React.createElement(Popover, { key: `${column}-${operator}-${value}-${index}`, open: isOpenPopover, content: React.createElement("div", { className: EXCEPTION_OFF_FILTER_CLASS },
|
|
71
|
-
React.createElement(FilterCondition, { filterMetric: metric, filterCondition: filter, onApply: ({ operator, value }) => {
|
|
69
|
+
React.createElement(FilterCondition, { matchesAny: matchesAny, filterMetric: metric, filterCondition: filter, onApply: ({ operator, value }) => {
|
|
72
70
|
onApplyFilterMetricCondition({
|
|
73
71
|
operator,
|
|
74
72
|
value,
|
|
75
73
|
existMetricIdx: index,
|
|
76
74
|
});
|
|
77
75
|
handleTogglePopover(index, false);
|
|
76
|
+
}, onChange: condition => {
|
|
77
|
+
onChangeFilterCondition({
|
|
78
|
+
column: metric.id,
|
|
79
|
+
operator: condition.operator,
|
|
80
|
+
value: condition.value,
|
|
81
|
+
dataType: metric.dataType,
|
|
82
|
+
});
|
|
78
83
|
}, onCancel: () => handleTogglePopover(index, false) })), trigger: ['click'], overlayInnerStyle: { width: 300, padding: 0 }, arrow: false, placement: "bottomLeft", onOpenChange: open => handleTogglePopover(index, open) },
|
|
79
84
|
React.createElement(FilterItem, { gap: 5, onClick: () => setFilter({
|
|
80
85
|
isFilterActive: true,
|
|
81
|
-
}), name: (metric === null || metric === void 0 ? void 0 : metric.name) || column.toString() || '', operator:
|
|
86
|
+
}), name: (metric === null || metric === void 0 ? void 0 : metric.name) || column.toString() || '', operator: operator, value: value, onClickRemove: () => onClickRemoveFilter(index) })));
|
|
82
87
|
});
|
|
83
88
|
const renderViewAll = () => {
|
|
84
89
|
var _a;
|
|
85
90
|
if (isFilterActive || (serializeFilters === null || serializeFilters === void 0 ? void 0 : serializeFilters.length) <= FILTER_SHOW_MAX)
|
|
86
91
|
return null;
|
|
87
92
|
return (React.createElement(Popover, { open: isOpenViewAllPopover, content: React.createElement(Flex, { vertical: true, gap: 5 }, (_a = serializeFilters === null || serializeFilters === void 0 ? void 0 : serializeFilters.slice(3)) === null || _a === void 0 ? void 0 : _a.map((filter, index) => {
|
|
88
|
-
var _a;
|
|
89
93
|
const { column, operator, value } = filter;
|
|
90
94
|
const metric = flattenFilterMetrics === null || flattenFilterMetrics === void 0 ? void 0 : flattenFilterMetrics.find(filterMetric => filterMetric.id === column);
|
|
91
|
-
const operatorLabel = ((_a = Object.values(OPERATORS_OPTION).find(({ value }) => value === operator)) === null || _a === void 0 ? void 0 : _a.label) ||
|
|
92
|
-
'';
|
|
93
95
|
if (!metric)
|
|
94
96
|
return null;
|
|
95
97
|
return (React.createElement(FilterItem, { key: `${column}-${operator}-${value}-${index}`, gap: 5, onClick: () => {
|
|
@@ -100,7 +102,7 @@ export const FilterConditionList = memo(() => {
|
|
|
100
102
|
handleTogglePopover(FILTER_SHOW_MAX + index, true);
|
|
101
103
|
// Close popover view all
|
|
102
104
|
setState(prev => (Object.assign(Object.assign({}, prev), { isOpenViewAllPopover: false })));
|
|
103
|
-
}, name: (metric === null || metric === void 0 ? void 0 : metric.name) || column.toString() || '', operator:
|
|
105
|
+
}, name: (metric === null || metric === void 0 ? void 0 : metric.name) || column.toString() || '', operator: operator, value: value, onClickRemove: () => onClickRemoveFilter(index) }));
|
|
104
106
|
})), trigger: ['click'], overlayInnerStyle: { width: 300, padding: 15 }, arrow: false, onOpenChange: open => setState(prev => (Object.assign(Object.assign({}, prev), { isOpenViewAllPopover: open }))) },
|
|
105
107
|
React.createElement(Button, { type: "text", style: Object.assign({}, (isOpenViewAllPopover && { backgroundColor: globalToken === null || globalToken === void 0 ? void 0 : globalToken.blue1_1 })) },
|
|
106
108
|
t(translations.viewAll).toString(),
|
|
@@ -10,22 +10,52 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
// Libraries
|
|
13
|
-
import React from 'react';
|
|
13
|
+
import React, { useMemo } from 'react';
|
|
14
|
+
import dayjs from 'dayjs';
|
|
14
15
|
// Components
|
|
15
16
|
import { Icon, Typography } from '@antscorp/antsomi-ui/es/components/atoms';
|
|
16
17
|
// Styled
|
|
17
18
|
import { StyledFilterItem } from './styled';
|
|
19
|
+
// Constants
|
|
20
|
+
import { DATE_TIME_FORMAT, OPERATORS_CODE, OPERATORS_OPTION, } from '@antscorp/antsomi-ui/es/constants';
|
|
21
|
+
const { MATCHES_ANY, MATCHES, NOT_MATCHES, IS } = OPERATORS_CODE;
|
|
18
22
|
const { Text } = Typography;
|
|
19
23
|
export const FilterItem = props => {
|
|
20
24
|
const { name, operator, value, onClickRemove } = props, restProps = __rest(props, ["name", "operator", "value", "onClickRemove"]);
|
|
21
|
-
|
|
25
|
+
// Memo
|
|
26
|
+
const serializeValue = useMemo(() => {
|
|
27
|
+
// Check type of value is valid date
|
|
28
|
+
if (dayjs(value).isValid()) {
|
|
29
|
+
return dayjs(value).format(DATE_TIME_FORMAT.FILTER_CONDITION);
|
|
30
|
+
}
|
|
31
|
+
// Check value is an array and operator is MATCHES_ANY
|
|
32
|
+
if (Array.isArray(value) && operator === MATCHES_ANY) {
|
|
33
|
+
return value.map(item => item.title).join(', ');
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}, [operator, value]);
|
|
37
|
+
const serializeOperator = useMemo(() => {
|
|
38
|
+
var _a;
|
|
39
|
+
const operatorLabel = ((_a = Object.values(OPERATORS_OPTION).find(({ value }) => value === operator)) === null || _a === void 0 ? void 0 : _a.label) || '';
|
|
40
|
+
switch (operator) {
|
|
41
|
+
case MATCHES_ANY:
|
|
42
|
+
case NOT_MATCHES:
|
|
43
|
+
case MATCHES:
|
|
44
|
+
case IS:
|
|
45
|
+
return null;
|
|
46
|
+
default:
|
|
47
|
+
return operatorLabel;
|
|
48
|
+
}
|
|
49
|
+
}, [operator]);
|
|
50
|
+
const tooltipContent = `${name} ${operator} ${serializeValue}`;
|
|
22
51
|
return (React.createElement(StyledFilterItem, Object.assign({ gap: 5 }, restProps),
|
|
23
52
|
React.createElement(Text, { ellipsis: { tooltip: tooltipContent } },
|
|
24
|
-
React.createElement(Text,
|
|
25
|
-
" \u00A0",
|
|
26
|
-
React.createElement(Text, null, operator),
|
|
53
|
+
React.createElement(Text, null, name),
|
|
27
54
|
" \u00A0",
|
|
28
|
-
React.createElement(Text,
|
|
55
|
+
serializeOperator && React.createElement(Text, null,
|
|
56
|
+
serializeOperator,
|
|
57
|
+
" \u00A0"),
|
|
58
|
+
React.createElement(Text, { strong: true, className: "filter-item__value" }, serializeValue)),
|
|
29
59
|
React.createElement("div", { className: "filter-item__close-btn", onClick: e => {
|
|
30
60
|
e.stopPropagation();
|
|
31
61
|
if (onClickRemove) {
|
|
@@ -38,7 +38,7 @@ export const FilterSection = styled(Flex) `
|
|
|
38
38
|
cursor: pointer;
|
|
39
39
|
`;
|
|
40
40
|
export const RowSelectedControlWrapper = styled(Flex) `
|
|
41
|
-
flex:
|
|
41
|
+
flex-shrink: 0;
|
|
42
42
|
height: ${toolbarHeight}px;
|
|
43
43
|
background-color: ${globalToken === null || globalToken === void 0 ? void 0 : globalToken.colorPrimary};
|
|
44
44
|
color: ${globalToken === null || globalToken === void 0 ? void 0 : globalToken.bw0};
|
|
@@ -12,10 +12,15 @@ type OnApplyFilterMetricConditionValue = {
|
|
|
12
12
|
};
|
|
13
13
|
export declare const useAddFilterCondition: () => {
|
|
14
14
|
filters: import("../types").FilterItem[] | undefined;
|
|
15
|
+
matchesAny: {
|
|
16
|
+
list?: import("../../..").MatchesAnyItem[] | undefined;
|
|
17
|
+
isLoading?: boolean | undefined;
|
|
18
|
+
} | undefined;
|
|
15
19
|
setState: import("react").Dispatch<import("react").SetStateAction<TState>>;
|
|
16
20
|
onSelectFilterMetric: (filterMetric?: FilterMetricItem) => void;
|
|
17
21
|
onApplyFilterMetricCondition: (values: OnApplyFilterMetricConditionValue) => void;
|
|
18
22
|
onClickAddFilter: () => void;
|
|
23
|
+
onChangeFilterCondition: (filterItem: import("../types").FilterItem) => void;
|
|
19
24
|
openPopover?: boolean | undefined;
|
|
20
25
|
selectedFilterMetric?: FilterMetricItem | undefined;
|
|
21
26
|
};
|
|
@@ -10,7 +10,7 @@ export const useAddFilterCondition = () => {
|
|
|
10
10
|
selectedFilterMetric: undefined,
|
|
11
11
|
});
|
|
12
12
|
// Store
|
|
13
|
-
const { filters, onChangeFilters = () => { } } = useDataTableContext(store => store.filter);
|
|
13
|
+
const { filters, matchesAny, onChangeFilters = () => { }, onChangeFilterCondition = () => { }, } = useDataTableContext(store => store.filter);
|
|
14
14
|
const setFilter = useDataTableContext(store => store.setFilter);
|
|
15
15
|
// Handlers
|
|
16
16
|
const onSelectFilterMetric = useCallback((filterMetric) => {
|
|
@@ -48,9 +48,11 @@ export const useAddFilterCondition = () => {
|
|
|
48
48
|
return Object.assign(Object.assign({}, state), {
|
|
49
49
|
// Filter
|
|
50
50
|
filters,
|
|
51
|
+
matchesAny,
|
|
51
52
|
// Handlers
|
|
52
53
|
setState,
|
|
53
54
|
onSelectFilterMetric,
|
|
54
55
|
onApplyFilterMetricCondition,
|
|
55
|
-
onClickAddFilter
|
|
56
|
+
onClickAddFilter,
|
|
57
|
+
onChangeFilterCondition });
|
|
56
58
|
};
|
|
@@ -7,9 +7,14 @@ import { PaginationProps } from '../../components';
|
|
|
7
7
|
import { ColumnType } from 'antd/es/table';
|
|
8
8
|
import { SorterResult } from 'antd/es/table/interface';
|
|
9
9
|
import { TGetColumnMetrics, TGetFilterMetricList, TGetModifyColumnList, TGetSavedFilterList, TGetSearchListing, TGetTableListing } from '@antscorp/antsomi-ui/es/queries';
|
|
10
|
+
import { MatchesAnyItem } from '@antscorp/antsomi-ui/es/components/molecules';
|
|
10
11
|
export type TApiGlobal = AxiosRequestConfig<any> & {
|
|
11
12
|
enabled?: boolean;
|
|
12
13
|
};
|
|
14
|
+
type TMatchesAnyParams = (filterItem?: FilterItem) => any | any;
|
|
15
|
+
type TMatchesAnyProps = {
|
|
16
|
+
formatData: (response: any) => MatchesAnyItem[];
|
|
17
|
+
};
|
|
13
18
|
export type TConfig<TTableType = any> = {
|
|
14
19
|
env?: TEnv;
|
|
15
20
|
auth?: TServiceAuth;
|
|
@@ -19,8 +24,12 @@ export type TConfig<TTableType = any> = {
|
|
|
19
24
|
filter?: TApiGlobal;
|
|
20
25
|
search?: TApiGlobal;
|
|
21
26
|
matchesAny?: {
|
|
22
|
-
general: TApiGlobal
|
|
23
|
-
|
|
27
|
+
general: Omit<TApiGlobal, 'params'> & {
|
|
28
|
+
params?: TMatchesAnyParams;
|
|
29
|
+
};
|
|
30
|
+
} & Partial<Record<keyof TTableType, Omit<TApiGlobal, 'params'> & {
|
|
31
|
+
params?: TMatchesAnyParams;
|
|
32
|
+
}>>;
|
|
24
33
|
};
|
|
25
34
|
object?: {
|
|
26
35
|
type: number;
|
|
@@ -48,7 +57,7 @@ type TSearchProps<TSearchType> = Partial<Pick<TSearchActionButton, 'addFilterInf
|
|
|
48
57
|
};
|
|
49
58
|
export interface UseDataTableListingProps<TTableType = any, TSearchType = any> {
|
|
50
59
|
name?: string;
|
|
51
|
-
config: TConfig
|
|
60
|
+
config: TConfig<TTableType>;
|
|
52
61
|
queryOptions?: {
|
|
53
62
|
getTableListing?: TGetTableListing['options'];
|
|
54
63
|
getColumnMetricList?: TGetColumnMetrics['options'];
|
|
@@ -68,6 +77,9 @@ export interface UseDataTableListingProps<TTableType = any, TSearchType = any> {
|
|
|
68
77
|
filter?: {
|
|
69
78
|
externalFilters?: FilterItem[];
|
|
70
79
|
includeDataType?: boolean;
|
|
80
|
+
matchesAny?: {
|
|
81
|
+
general: TMatchesAnyProps;
|
|
82
|
+
} & Partial<Record<keyof TTableType, TMatchesAnyProps>>;
|
|
71
83
|
};
|
|
72
84
|
}
|
|
73
85
|
export interface DataTableLocalStorage<TTableType = any> {
|
|
@@ -47,6 +47,7 @@ type TState<TTableType = any> = {
|
|
|
47
47
|
};
|
|
48
48
|
searchValue?: string;
|
|
49
49
|
sorter?: SorterResult<TTableType>;
|
|
50
|
+
selectedFilterItem?: FilterItem;
|
|
50
51
|
};
|
|
51
52
|
export declare function useDataTableListing<TTableType = Record<string, any>, TSearchType = any>(props: UseDataTableListingProps<TTableType, TSearchType>): TUseDataTableListing<TTableType>;
|
|
52
53
|
export {};
|
|
@@ -28,17 +28,18 @@ import { useAppConfigContext } from '@antscorp/antsomi-ui/es/providers';
|
|
|
28
28
|
// Components
|
|
29
29
|
import { Typography, Switch, Flex } from '@antscorp/antsomi-ui/es/components/atoms';
|
|
30
30
|
// Constants
|
|
31
|
-
import { COLUMN_DOMAIN, QUERY_KEYS, globalToken } from '@antscorp/antsomi-ui/es/constants';
|
|
31
|
+
import { COLUMN_DOMAIN, OPERATORS_CODE, QUERY_KEYS, globalToken, } from '@antscorp/antsomi-ui/es/constants';
|
|
32
32
|
import { MODIFY_COLUMN_DISABLE_EDITABLE, MODIFY_COLUMN_DISABLE_REMOVE, SAVED_FILTER_DEFAULT, TABLE_LISTING_PREFIX, } from './constants';
|
|
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, useGetModifyColumnList, useGetSavedFilterList, useGetSearchListing, useGetTableListing, useSaveFilter, useUpdateFilter, useUpdateModifyColumn, } from '@antscorp/antsomi-ui/es/queries';
|
|
36
|
+
import { useCreateModifyColumn, useDeleteModifyColumn, useDeleteSavedFilter, useGetColumnMetrics, useGetFilterMetricList, useGetMatchesAnyList, 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';
|
|
40
40
|
import { mapFiltersToApiFilters, mapFiltersToRules, mapRulesToFilters } from '../../utils';
|
|
41
41
|
const { Text } = Typography;
|
|
42
|
+
const { MATCHES, MATCHES_ANY, NOT_MATCHES } = OPERATORS_CODE;
|
|
42
43
|
const initialState = {
|
|
43
44
|
filters: [],
|
|
44
45
|
selectedFilterId: SAVED_FILTER_DEFAULT[0].id,
|
|
@@ -58,9 +59,10 @@ const initialState = {
|
|
|
58
59
|
},
|
|
59
60
|
searchValue: '',
|
|
60
61
|
sorter: {},
|
|
62
|
+
selectedFilterItem: undefined,
|
|
61
63
|
};
|
|
62
64
|
export function useDataTableListing(props) {
|
|
63
|
-
var _a, _b;
|
|
65
|
+
var _a, _b, _c;
|
|
64
66
|
// Props
|
|
65
67
|
const { config, name = 'default', table: tableProps, search: searchProps, filter: filterProps, queryOptions, } = props || {};
|
|
66
68
|
// Hooks
|
|
@@ -70,18 +72,25 @@ export function useDataTableListing(props) {
|
|
|
70
72
|
const [state, setState] = useState(initialState);
|
|
71
73
|
// Variables
|
|
72
74
|
const { env = appConfig === null || appConfig === void 0 ? void 0 : appConfig.env, auth = appConfig === null || appConfig === void 0 ? void 0 : appConfig.auth, api, object } = config;
|
|
73
|
-
const { column: apiColumn, filter: apiFilter, listing: apiListing, search: apiSearch, } = api || {};
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
const { filters, selectedFilterId, pagination, selectedRowKeys, searchValue, table, sorter, selectedRow, } = state;
|
|
79
|
-
const { externalFilters, includeDataType = false } = filterProps || {};
|
|
75
|
+
const { column: apiColumn, filter: apiFilter, listing: apiListing, search: apiSearch, matchesAny: apiMatchesAny, } = api || {};
|
|
76
|
+
const _d = apiColumn || {}, { url: columnUrl = `${COLUMN_DOMAIN[env || 'development']}/api/column`, enabled: enabledApiColumn = true } = _d, restOfApiColumnRequest = __rest(_d, ["url", "enabled"]);
|
|
77
|
+
const _e = apiFilter || {}, { url: filterUrl = `${COLUMN_DOMAIN[env || 'development']}/api/filter`, enabled: enabledApiFilter = true } = _e, restOfApiFilterRequest = __rest(_e, ["url", "enabled"]);
|
|
78
|
+
const _f = apiListing || {}, { url: listingUrl = '', enabled: enabledApiListing = true } = _f, restOfApiListingRequest = __rest(_f, ["url", "enabled"]);
|
|
79
|
+
const _g = apiSearch || {}, { url: searchUrl = '', enabled: enabledApiSearch = true } = _g, restOfApiSearchRequest = __rest(_g, ["url", "enabled"]);
|
|
80
|
+
const { filters, selectedFilterId, pagination, selectedRowKeys, searchValue, table, sorter, selectedRow, selectedFilterItem, } = state;
|
|
81
|
+
const { externalFilters, includeDataType = false, matchesAny } = filterProps || {};
|
|
80
82
|
const { sortDirectionKey = 'az', mainColumnKey } = tableProps || {};
|
|
81
83
|
const modifyColumnAuth = Object.assign(Object.assign({}, auth), { url: columnUrl });
|
|
82
84
|
const filterAuth = Object.assign(Object.assign({}, auth), { url: filterUrl });
|
|
83
85
|
const listingAuth = Object.assign(Object.assign({}, auth), { url: listingUrl });
|
|
84
86
|
const searchAuth = Object.assign(Object.assign({}, auth), { url: searchUrl });
|
|
87
|
+
/**
|
|
88
|
+
* If has api config for specific selectedFilterItem, use it
|
|
89
|
+
* Otherwise use general api config
|
|
90
|
+
*/
|
|
91
|
+
const matchesAnyRequest = (apiMatchesAny === null || apiMatchesAny === void 0 ? void 0 : apiMatchesAny[`${selectedFilterItem === null || selectedFilterItem === void 0 ? void 0 : selectedFilterItem.column}`.toLowerCase()])
|
|
92
|
+
? apiMatchesAny === null || apiMatchesAny === void 0 ? void 0 : apiMatchesAny[`${selectedFilterItem === null || selectedFilterItem === void 0 ? void 0 : selectedFilterItem.column}`.toLowerCase()]
|
|
93
|
+
: apiMatchesAny === null || apiMatchesAny === void 0 ? void 0 : apiMatchesAny.general;
|
|
85
94
|
// Memos
|
|
86
95
|
const mapObject = useMemo(() => ({
|
|
87
96
|
objType: object === null || object === void 0 ? void 0 : object.type,
|
|
@@ -122,13 +131,26 @@ export function useDataTableListing(props) {
|
|
|
122
131
|
},
|
|
123
132
|
options: Object.assign({ enabled: enabledApiFilter }, queryOptions === null || queryOptions === void 0 ? void 0 : queryOptions.getFilterMetricList),
|
|
124
133
|
});
|
|
134
|
+
const getMatchesAnyList = useGetMatchesAnyList({
|
|
135
|
+
args: {
|
|
136
|
+
auth,
|
|
137
|
+
params: (_a = matchesAnyRequest === null || matchesAnyRequest === void 0 ? void 0 : matchesAnyRequest.params) === null || _a === void 0 ? void 0 : _a.call(matchesAnyRequest, selectedFilterItem),
|
|
138
|
+
request: matchesAnyRequest,
|
|
139
|
+
},
|
|
140
|
+
options: {
|
|
141
|
+
enabled: !!selectedFilterItem &&
|
|
142
|
+
[MATCHES_ANY, NOT_MATCHES, MATCHES].includes(selectedFilterItem.operator),
|
|
143
|
+
keepPreviousData: true,
|
|
144
|
+
retry: false,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
125
147
|
// Variables
|
|
126
148
|
const { data: modifyColumnsData, isLoading: isModifyColumnsLoading } = getModifyColumnList || {};
|
|
127
149
|
const modifyColumnSelected = useDeepCompareMemo(() => { var _a; return ((_a = modifyColumnsData === null || modifyColumnsData === void 0 ? void 0 : modifyColumnsData.find(({ isLasted }) => +isLasted === 1)) === null || _a === void 0 ? void 0 : _a.modifyColId) || ''; }, [modifyColumnsData]);
|
|
128
150
|
const getTableListing = useGetTableListing({
|
|
129
151
|
args: {
|
|
130
152
|
auth: listingAuth,
|
|
131
|
-
params: Object.assign({ limit: pagination.pageSize, page: pagination.page, filter: JSON.stringify(mapFiltersToApiFilters([...(filters || []), ...(externalFilters || [])], includeDataType)), columns: JSON.stringify(((
|
|
153
|
+
params: Object.assign({ limit: pagination.pageSize, page: pagination.page, filter: JSON.stringify(mapFiltersToApiFilters([...(filters || []), ...(externalFilters || [])], includeDataType)), columns: JSON.stringify(((_c = (_b = modifyColumnsData === null || modifyColumnsData === void 0 ? void 0 : modifyColumnsData.find(modifyColumnItem => modifyColumnItem.modifyColId === modifyColumnSelected)) === null || _b === void 0 ? void 0 : _b.columns) === null || _c === void 0 ? void 0 : _c.map(col => { var _a; return (_a = col.metricCode) === null || _a === void 0 ? void 0 : _a.toUpperCase(); })) || []) }, ((sorter === null || sorter === void 0 ? void 0 : sorter.order) &&
|
|
132
154
|
(sorter === null || sorter === void 0 ? void 0 : sorter.columnKey) && {
|
|
133
155
|
sort: sorter.columnKey.toString(),
|
|
134
156
|
[sortDirectionKey]: SORT_MAP[sorter.order],
|
|
@@ -154,6 +176,7 @@ export function useDataTableListing(props) {
|
|
|
154
176
|
const { data: tableListing, isLoading: isTableListingLoading, isRefetching: isTableListingRefetching, } = getTableListing || {};
|
|
155
177
|
const { body: tableBody, header: tableHeader, total } = tableListing || {};
|
|
156
178
|
const { data: searchListingData, isLoading: isSearchListingLoading, isFetching: isSearchListingFetching, } = getSearchListing || {};
|
|
179
|
+
const { data: matchesAnyListData, isLoading: isMatchesAnyListLoading } = getMatchesAnyList || {};
|
|
157
180
|
// Conditionally format search listing data based on the presence of a formatData function in searchProps.
|
|
158
181
|
// If formatData is defined, use it to format searchListingData.
|
|
159
182
|
// Otherwise, use the mapResponseSearchToGeneral function to format searchListingData.
|
|
@@ -272,6 +295,20 @@ export function useDataTableListing(props) {
|
|
|
272
295
|
const { itemMapKeys, icon, link } = searchProps || {};
|
|
273
296
|
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 })))) || []);
|
|
274
297
|
}, [searchListingData, searchProps]);
|
|
298
|
+
const matchesAnyList = useMemo(() => {
|
|
299
|
+
/**
|
|
300
|
+
* If `selectedFilterItem` has a column, the function will attempt to find a matching property in the `matchesAny`
|
|
301
|
+
* object by converting the column name to lowercase. If such a property does not exist, it will default to using
|
|
302
|
+
* the `general` property from the `matchesAny` object.
|
|
303
|
+
*/
|
|
304
|
+
const matchesAnyProps = (matchesAny === null || matchesAny === void 0 ? void 0 : matchesAny[`${selectedFilterItem === null || selectedFilterItem === void 0 ? void 0 : selectedFilterItem.column}`.toLowerCase()])
|
|
305
|
+
? matchesAny === null || matchesAny === void 0 ? void 0 : matchesAny[`${selectedFilterItem === null || selectedFilterItem === void 0 ? void 0 : selectedFilterItem.column}`.toLowerCase()]
|
|
306
|
+
: matchesAny === null || matchesAny === void 0 ? void 0 : matchesAny.general;
|
|
307
|
+
if (matchesAnyListData) {
|
|
308
|
+
return matchesAnyProps.formatData(matchesAnyListData);
|
|
309
|
+
}
|
|
310
|
+
return [];
|
|
311
|
+
}, [matchesAny, matchesAnyListData, selectedFilterItem === null || selectedFilterItem === void 0 ? void 0 : selectedFilterItem.column]);
|
|
275
312
|
// Effects
|
|
276
313
|
/**
|
|
277
314
|
* Update values from local storage to state
|
|
@@ -314,7 +351,7 @@ export function useDataTableListing(props) {
|
|
|
314
351
|
});
|
|
315
352
|
}, [mapObject, updateModifyColumn]);
|
|
316
353
|
const onApplyModifyColumn = useCallback((args) => __awaiter(this, void 0, void 0, function* () {
|
|
317
|
-
var
|
|
354
|
+
var _h;
|
|
318
355
|
const { selectedMetrics, columnSetName, existColumnSet } = args || {};
|
|
319
356
|
const flattenMetrics = flatTree(columnMetricsData, 'child');
|
|
320
357
|
const selectedColumnMetrics = selectedMetrics
|
|
@@ -327,7 +364,7 @@ export function useDataTableListing(props) {
|
|
|
327
364
|
exitModifyColumnId = (existColumnSet === null || existColumnSet === void 0 ? void 0 : existColumnSet.id) || '';
|
|
328
365
|
if (columnSetName === '') {
|
|
329
366
|
exitModifyColumnId =
|
|
330
|
-
((
|
|
367
|
+
((_h = modifyColumnsData === null || modifyColumnsData === void 0 ? void 0 : modifyColumnsData.find(modifyColumn => modifyColumn.modifyName === 'Custom')) === null || _h === void 0 ? void 0 : _h.modifyColId) || '';
|
|
331
368
|
}
|
|
332
369
|
}
|
|
333
370
|
/**
|
|
@@ -379,12 +416,16 @@ export function useDataTableListing(props) {
|
|
|
379
416
|
// Set Local Storage
|
|
380
417
|
localStorage.setItem(localStorageKey, JSON.stringify(Object.assign(Object.assign({}, localStorageValues), { sorter })));
|
|
381
418
|
}, [localStorageKey]);
|
|
419
|
+
/* Filter */
|
|
382
420
|
const onChangeFilters = useCallback((filters) => {
|
|
383
421
|
handleUpdateFilter({
|
|
384
422
|
filters,
|
|
385
423
|
selectedFilterId: SAVED_FILTER_DEFAULT[0].id,
|
|
386
424
|
});
|
|
387
425
|
}, [handleUpdateFilter]);
|
|
426
|
+
const onChangeFilterCondition = useCallback((filterItem) => {
|
|
427
|
+
setState(prev => (Object.assign(Object.assign({}, prev), { selectedFilterItem: filterItem })));
|
|
428
|
+
}, []);
|
|
388
429
|
const onSaveFilter = useCallback((args) => __awaiter(this, void 0, void 0, function* () {
|
|
389
430
|
const { filters, name, existSavedFilter } = args;
|
|
390
431
|
// Update exits filter
|
|
@@ -483,8 +524,13 @@ export function useDataTableListing(props) {
|
|
|
483
524
|
},
|
|
484
525
|
filters,
|
|
485
526
|
filterMetrics,
|
|
527
|
+
matchesAny: {
|
|
528
|
+
list: matchesAnyList,
|
|
529
|
+
isLoading: isMatchesAnyListLoading,
|
|
530
|
+
},
|
|
486
531
|
onSaveFilter,
|
|
487
532
|
onChangeFilters,
|
|
533
|
+
onChangeFilterCondition,
|
|
488
534
|
},
|
|
489
535
|
/* Pagination */
|
|
490
536
|
pagination: Object.assign(Object.assign({}, pagination), { total, onChange: onChangePagination }),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MatchesAnyItem } from '../../../molecules';
|
|
1
2
|
import { FILTER_ACTION_KEYS } from '../constants/filter';
|
|
2
3
|
import { TActionButton, TConfirmResponse } from '@antscorp/antsomi-ui/es/types';
|
|
3
4
|
export type TActionFilterButtonKey<T extends string[] = []> = (typeof FILTER_ACTION_KEYS)[keyof typeof FILTER_ACTION_KEYS] | T[number];
|
|
@@ -40,8 +41,14 @@ export interface FilterProps<TActionKey extends string[] = []> {
|
|
|
40
41
|
savedFilter?: SavedFilter;
|
|
41
42
|
filterMetrics?: FilterMetricItem[];
|
|
42
43
|
filters?: FilterItem[];
|
|
44
|
+
matchesAny?: {
|
|
45
|
+
list?: MatchesAnyItem[];
|
|
46
|
+
isLoading?: boolean;
|
|
47
|
+
};
|
|
43
48
|
actionButtons?: Partial<Record<TActionFilterButtonKey<TActionKey>, TActionButton>>;
|
|
44
49
|
onChangeFilters?: (filters: FilterItem[]) => void;
|
|
45
50
|
onSaveFilter?: (args: TOnSaveFilterArgs) => Promise<TConfirmResponse>;
|
|
51
|
+
/** Handle callback when filter condition changed */
|
|
52
|
+
onChangeFilterCondition?: (filterItem: FilterItem) => void;
|
|
46
53
|
}
|
|
47
54
|
export type TApiFilter = Record<string, any>[];
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { MenuProps } from 'antd';
|
|
3
3
|
import { FilterItem, FilterMetricItem, TApiFilter } from '../types';
|
|
4
4
|
import { SavedFilter } from '@antscorp/antsomi-ui/es/models/DataTable/SavedFilter';
|
|
5
|
+
import { FilterProps } from '../..';
|
|
5
6
|
type MenuItem = Required<MenuProps>['items'][number];
|
|
6
7
|
type TSerializeFilterMetricsToMenuItems = {
|
|
7
8
|
filterMetrics: FilterMetricItem[];
|
|
@@ -12,7 +13,8 @@ type TSerializeFilterMetricsToMenuItems = {
|
|
|
12
13
|
type TRenderValueField = {
|
|
13
14
|
filterMetric: FilterMetricItem;
|
|
14
15
|
operator: string;
|
|
15
|
-
value?:
|
|
16
|
+
value?: any;
|
|
17
|
+
matchesAny?: FilterProps['matchesAny'];
|
|
16
18
|
onChangeValue?: (value: any) => void;
|
|
17
19
|
};
|
|
18
20
|
type TGetFilterMetricByName = {
|
|
@@ -71,7 +73,7 @@ export declare const serializeFilterMetricsToMenuItems: ({ filterMetrics, level,
|
|
|
71
73
|
* // ]
|
|
72
74
|
*/
|
|
73
75
|
export declare const flatFilterMetrics: (filterMetrics: FilterMetricItem[]) => FilterMetricItem[];
|
|
74
|
-
export declare const renderValueField: ({ filterMetric, operator, value, onChangeValue, }: TRenderValueField) => React.JSX.Element | null;
|
|
76
|
+
export declare const renderValueField: ({ filterMetric, operator, value, matchesAny, onChangeValue, }: TRenderValueField) => React.JSX.Element | null;
|
|
75
77
|
/**
|
|
76
78
|
* Retrieves a filter metric by its name from a collection of filter metrics.
|
|
77
79
|
*
|
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { isEmpty } from 'lodash';
|
|
4
4
|
import i18nInstance from '@antscorp/antsomi-ui/es/locales/i18n';
|
|
5
|
+
import dayjs from 'dayjs';
|
|
5
6
|
// Components
|
|
6
7
|
import { Popover, Typography, Icon, FormatInputNumber, Flex, Input } from '../../../atoms';
|
|
7
|
-
import { METRIC_TYPE } from '@antscorp/antsomi-ui/es/constants';
|
|
8
|
+
import { DATE_TIME_FORMAT, DATE_TIME_FORMAT_DISPLAY, METRIC_TYPE, } from '@antscorp/antsomi-ui/es/constants';
|
|
8
9
|
import { Menu } from '../..';
|
|
10
|
+
import { DatePicker, MatchesAnySelect } from '../../../molecules';
|
|
9
11
|
// Styled
|
|
10
12
|
import { FilterMetricLabel } from '../styled';
|
|
11
13
|
import { OPERATORS_CODE } from '@antscorp/antsomi-ui/es/constants/condition';
|
|
12
14
|
// Translations
|
|
13
15
|
import { translations } from '@antscorp/antsomi-ui/es/locales/translations';
|
|
14
|
-
import { METRIC_MAP_NUMBER_TYPE, METRIC_MAP_STRING_TYPE } from '../constants/filter';
|
|
15
|
-
|
|
16
|
+
import { EXCEPTION_OFF_FILTER_CLASS, METRIC_MAP_NUMBER_TYPE, METRIC_MAP_STRING_TYPE, } from '../constants/filter';
|
|
17
|
+
const { MATCHES, MATCHES_ANY, NOT_MATCHES, ON, BEFORE, BEFORE_DATE, AFTER, AFTER_DATE } = OPERATORS_CODE;
|
|
16
18
|
const { t } = i18nInstance;
|
|
17
19
|
const { Text } = Typography;
|
|
18
20
|
/* Filter */
|
|
@@ -102,9 +104,8 @@ export const flatFilterMetrics = (filterMetrics) => filterMetrics.reduce((acc, c
|
|
|
102
104
|
return [...acc, cur];
|
|
103
105
|
}, []);
|
|
104
106
|
/* Render Value Field */
|
|
105
|
-
export const renderValueField = ({ filterMetric, operator, value, onChangeValue = () => { }, }) => {
|
|
106
|
-
const { dataType } = filterMetric;
|
|
107
|
-
console.log('🚀 ~ filterMetric:', filterMetric);
|
|
107
|
+
export const renderValueField = ({ filterMetric, operator, value, matchesAny, onChangeValue = () => { }, }) => {
|
|
108
|
+
const { dataType, name } = filterMetric;
|
|
108
109
|
switch (operator) {
|
|
109
110
|
case OPERATORS_CODE.GREATER_THAN:
|
|
110
111
|
case OPERATORS_CODE.GREATER_THAN_EQUAL:
|
|
@@ -143,7 +144,15 @@ export const renderValueField = ({ filterMetric, operator, value, onChangeValue
|
|
|
143
144
|
case OPERATORS_CODE.MATCHES:
|
|
144
145
|
case OPERATORS_CODE.MATCHES_ANY:
|
|
145
146
|
case OPERATORS_CODE.NOT_MATCHES: {
|
|
146
|
-
|
|
147
|
+
const { list, isLoading } = matchesAny || {};
|
|
148
|
+
return (React.createElement(MatchesAnySelect, { selectedItems: value, popupClassName: EXCEPTION_OFF_FILTER_CLASS, objectName: name, items: list, loading: isLoading, onChange: onChangeValue }));
|
|
149
|
+
}
|
|
150
|
+
case OPERATORS_CODE.AFTER:
|
|
151
|
+
case OPERATORS_CODE.AFTER_DATE:
|
|
152
|
+
case OPERATORS_CODE.BEFORE:
|
|
153
|
+
case OPERATORS_CODE.ON:
|
|
154
|
+
case OPERATORS_CODE.BEFORE_DATE: {
|
|
155
|
+
return (React.createElement(DatePicker, { placeholder: DATE_TIME_FORMAT_DISPLAY.FILTER_CONDITION, format: DATE_TIME_FORMAT_DISPLAY.FILTER_CONDITION, allowClear: false, popupClassName: EXCEPTION_OFF_FILTER_CLASS, value: dayjs(value).isValid() ? dayjs(value) : undefined, onChange: onChangeValue }));
|
|
147
156
|
}
|
|
148
157
|
default:
|
|
149
158
|
return null;
|
|
@@ -179,6 +188,33 @@ export const mapRulesToFilters = (rules) => rules.map(({ dataType, metricCode, o
|
|
|
179
188
|
operator: operatorValue,
|
|
180
189
|
value: filterValue,
|
|
181
190
|
}));
|
|
182
|
-
export const mapFiltersToApiFilters = (filters, includeDataType = false) => filters.map(({ column, operator, value, dataType }) =>
|
|
183
|
-
|
|
184
|
-
|
|
191
|
+
export const mapFiltersToApiFilters = (filters, includeDataType = false) => filters.map(({ column, operator, value, dataType }) => {
|
|
192
|
+
let serializeValue = '';
|
|
193
|
+
switch (operator) {
|
|
194
|
+
case MATCHES:
|
|
195
|
+
case MATCHES_ANY:
|
|
196
|
+
case NOT_MATCHES: {
|
|
197
|
+
if (Array.isArray(value)) {
|
|
198
|
+
serializeValue = value.map(item => item.key);
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
/** Date time */
|
|
203
|
+
case AFTER:
|
|
204
|
+
case AFTER_DATE:
|
|
205
|
+
case BEFORE:
|
|
206
|
+
case ON:
|
|
207
|
+
case BEFORE_DATE: {
|
|
208
|
+
if (dayjs(value).isValid()) {
|
|
209
|
+
serializeValue = dayjs(value).format(DATE_TIME_FORMAT.FILTER_CONDITION);
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
default:
|
|
214
|
+
serializeValue = value;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
[column]: Object.assign({ [operator]: serializeValue }, (includeDataType && { dataType: METRIC_MAP_STRING_TYPE[dataType || 'string'] })),
|
|
219
|
+
};
|
|
220
|
+
});
|
|
@@ -29,6 +29,9 @@ export declare const OPERATORS_CODE: {
|
|
|
29
29
|
readonly CONTAIN: "contain";
|
|
30
30
|
readonly DOES_NOT_CONTAIN: "does_not_contain";
|
|
31
31
|
readonly IS: "is";
|
|
32
|
+
readonly ON: "on";
|
|
33
|
+
readonly AFTER: "after";
|
|
34
|
+
readonly BEFORE: "before";
|
|
32
35
|
};
|
|
33
36
|
export declare const OPERATORS_OPTION: {
|
|
34
37
|
GREATER_THAN: {
|
|
@@ -151,6 +154,18 @@ export declare const OPERATORS_OPTION: {
|
|
|
151
154
|
label: string;
|
|
152
155
|
value: "is";
|
|
153
156
|
};
|
|
157
|
+
ON: {
|
|
158
|
+
label: string;
|
|
159
|
+
value: "on";
|
|
160
|
+
};
|
|
161
|
+
AFTER: {
|
|
162
|
+
label: string;
|
|
163
|
+
value: "after";
|
|
164
|
+
};
|
|
165
|
+
BEFORE: {
|
|
166
|
+
label: string;
|
|
167
|
+
value: "before";
|
|
168
|
+
};
|
|
154
169
|
};
|
|
155
170
|
export declare const OPERATORS: {
|
|
156
171
|
number: {
|
|
@@ -29,6 +29,9 @@ export const OPERATORS_CODE = {
|
|
|
29
29
|
CONTAIN: 'contain',
|
|
30
30
|
DOES_NOT_CONTAIN: 'does_not_contain',
|
|
31
31
|
IS: 'is',
|
|
32
|
+
ON: 'on',
|
|
33
|
+
AFTER: 'after',
|
|
34
|
+
BEFORE: 'before',
|
|
32
35
|
};
|
|
33
36
|
const { GREATER_THAN, GREATER_THAN_EQUAL, LESS_THAN, LESS_THAN_EQUAL, NOT_EQUALS, EQUALS, BETWEEN, EXISTS, NOT_EXISTS, CONTAINS, DOESNT_CONTAIN, START_WITH, NOT_START_WITH, END_WITH, NOT_END_WITH, BEFORE_DATE, } = OPERATORS_CODE;
|
|
34
37
|
export const OPERATORS_OPTION = {
|
|
@@ -152,6 +155,18 @@ export const OPERATORS_OPTION = {
|
|
|
152
155
|
label: 'is',
|
|
153
156
|
value: OPERATORS_CODE.IS,
|
|
154
157
|
},
|
|
158
|
+
ON: {
|
|
159
|
+
label: 'on',
|
|
160
|
+
value: OPERATORS_CODE.ON,
|
|
161
|
+
},
|
|
162
|
+
AFTER: {
|
|
163
|
+
label: 'is',
|
|
164
|
+
value: OPERATORS_CODE.AFTER,
|
|
165
|
+
},
|
|
166
|
+
BEFORE: {
|
|
167
|
+
label: 'before',
|
|
168
|
+
value: OPERATORS_CODE.BEFORE,
|
|
169
|
+
},
|
|
155
170
|
};
|
|
156
171
|
export const OPERATORS = {
|
|
157
172
|
number: {
|
package/es/constants/datetime.js
CHANGED
|
@@ -1591,4 +1591,8 @@ export const TIME_ZONES = [
|
|
|
1591
1591
|
export const DATE_TIME_FORMAT = {
|
|
1592
1592
|
TITLE_DATE_TIME: 'YYYY-MM-DD HH:mm:ss',
|
|
1593
1593
|
DATE_TIME: 'DD/MM/YYYY - HH:mm:ss',
|
|
1594
|
+
FILTER_CONDITION: 'DD/MM/YYYY',
|
|
1595
|
+
};
|
|
1596
|
+
export const DATE_TIME_FORMAT_DISPLAY = {
|
|
1597
|
+
FILTER_CONDITION: 'MM/DD/YYYY',
|
|
1594
1598
|
};
|
package/es/constants/queries.js
CHANGED
package/es/constants/theme.js
CHANGED
|
@@ -152,6 +152,7 @@ THEME.components = {
|
|
|
152
152
|
borderRadiusSM: 0,
|
|
153
153
|
borderRadiusOuter: 0,
|
|
154
154
|
borderRadiusXS: 0,
|
|
155
|
+
paddingInline: 5,
|
|
155
156
|
colorBorder: (_s = THEME.token) === null || _s === void 0 ? void 0 : _s.blue1,
|
|
156
157
|
controlItemBgActive: '#E0EBF7',
|
|
157
158
|
colorBgContainerDisabled: (_t = THEME.token) === null || _t === void 0 ? void 0 : _t.bw2,
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"removeAll": "Remove All",
|
|
10
10
|
"selectAll": "Select All",
|
|
11
11
|
"selected": "Selected",
|
|
12
|
-
"selectItemsFromList": "Select items from the list"
|
|
12
|
+
"selectItemsFromList": "Select items from the list",
|
|
13
|
+
"noResultsMatchesKeyWord": "No result matches for your keyword"
|
|
13
14
|
},
|
|
14
15
|
"form": {
|
|
15
16
|
"placeholder": {
|
package/es/locales/i18n.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare const translationsJson: {
|
|
|
12
12
|
selectAll: string;
|
|
13
13
|
selected: string;
|
|
14
14
|
selectItemsFromList: string;
|
|
15
|
+
noResultsMatchesKeyWord: string;
|
|
15
16
|
};
|
|
16
17
|
form: {
|
|
17
18
|
placeholder: {
|
|
@@ -610,6 +611,7 @@ export declare const translationsJson: {
|
|
|
610
611
|
selectAll: string;
|
|
611
612
|
selected: string;
|
|
612
613
|
selectItemsFromList: string;
|
|
614
|
+
noResultsMatchesKeyWord: string;
|
|
613
615
|
};
|
|
614
616
|
form: {
|
|
615
617
|
placeholder: {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"removeAll": "Xóa tất cả",
|
|
10
10
|
"selectAll": "Chọn tất cả",
|
|
11
11
|
"selected": "Đã chọn",
|
|
12
|
-
"selectItemsFromList": "Chọn các mục từ danh sách"
|
|
12
|
+
"selectItemsFromList": "Chọn các mục từ danh sách",
|
|
13
|
+
"noResultsMatchesKeyWord": "Không có kết quả nào phù hợp với từ khóa của bạn"
|
|
13
14
|
},
|
|
14
15
|
"form": {
|
|
15
16
|
"placeholder": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { UseMutationOptions, UseQueryOptions } from '@tanstack/react-query';
|
|
2
|
-
import { TCreateModifyColumnArgs, TDeleteModifyColumnArgs, TDeleteSavedFilterArgs, TGetFilterMetricListArgs, TGetMetricListArgs, TGetModifyColumnListArgs, TGetSavedFilterListArgs, TGetSearchListingArgs, TGetTableListingArgs, TSaveFilterArgs, TUpdateFilterArgs, TUpdateModifyColumnArgs } from '../../services/DataTable';
|
|
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';
|
|
5
5
|
import { DataTableListing } from '../../models/DataTable/DataTableListing';
|
|
@@ -37,6 +37,10 @@ export type TGetFilterMetricList = {
|
|
|
37
37
|
args: TGetFilterMetricListArgs;
|
|
38
38
|
options?: UseQueryOptions<FilterMetric[], any, FilterMetric[], any[]>;
|
|
39
39
|
};
|
|
40
|
+
export type TGetMatchesAnyList = {
|
|
41
|
+
args: TGetMatchesAnyListArgs;
|
|
42
|
+
options?: UseQueryOptions<any, any, any, any[]>;
|
|
43
|
+
};
|
|
40
44
|
export type TSaveFilter = {
|
|
41
45
|
auth: TSaveFilterArgs['auth'];
|
|
42
46
|
options?: UseMutationOptions<{
|
|
@@ -87,3 +91,4 @@ export declare const useDeleteSavedFilter: (params?: TDeleteSavedFilter) => impo
|
|
|
87
91
|
}, any, TDeleteSavedFilterArgs, unknown>;
|
|
88
92
|
export declare const useGetTableListing: <T>(params: TGetTableListing<T>) => import("@tanstack/react-query").UseQueryResult<DataTableListing<T>, any>;
|
|
89
93
|
export declare const useGetSearchListing: (params: TGetSearchListing) => import("@tanstack/react-query").UseQueryResult<any, any>;
|
|
94
|
+
export declare const useGetMatchesAnyList: (params: TGetMatchesAnyList) => import("@tanstack/react-query").UseQueryResult<any, any>;
|
|
@@ -5,7 +5,7 @@ import { omit } from 'lodash';
|
|
|
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_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, } = QUERY_KEYS;
|
|
9
9
|
/* Column */
|
|
10
10
|
export const useGetColumnMetrics = (params) => {
|
|
11
11
|
const { args, options } = params;
|
|
@@ -87,3 +87,7 @@ export const useGetSearchListing = (params) => {
|
|
|
87
87
|
const { args, options } = params || {};
|
|
88
88
|
return useQuery(Object.assign({ queryKey: [GET_SEARCH_LIST, args], queryFn: ({ signal }) => dataTableServices.search.getSearchListing(Object.assign(Object.assign({}, args), { request: Object.assign(Object.assign({}, args.request), { signal }) })) }, options));
|
|
89
89
|
};
|
|
90
|
+
export const useGetMatchesAnyList = (params) => {
|
|
91
|
+
const { args, options } = params || {};
|
|
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
|
+
};
|
|
@@ -8,6 +8,7 @@ export type TGlobalApiParams = {
|
|
|
8
8
|
objType?: number;
|
|
9
9
|
objId?: number;
|
|
10
10
|
actionType?: number;
|
|
11
|
+
[key: string]: any;
|
|
11
12
|
};
|
|
12
13
|
export type TGetMetricListArgs = {
|
|
13
14
|
auth?: TServiceAuth;
|
|
@@ -51,6 +52,11 @@ export type TGetFilterMetricListArgs = {
|
|
|
51
52
|
params?: TGlobalApiParams;
|
|
52
53
|
request?: AxiosRequestConfig<any>;
|
|
53
54
|
};
|
|
55
|
+
export type TGetMatchesAnyListArgs = {
|
|
56
|
+
auth?: TServiceAuth;
|
|
57
|
+
params?: TGlobalApiParams;
|
|
58
|
+
request?: AxiosRequestConfig<any>;
|
|
59
|
+
};
|
|
54
60
|
export type TSaveFilterArgs = {
|
|
55
61
|
auth?: TServiceAuth;
|
|
56
62
|
data?: TGlobalApiParams & {
|
|
@@ -118,6 +124,7 @@ export declare const dataTableServices: {
|
|
|
118
124
|
deleteSavedFilter: ({ auth, params, }: TDeleteSavedFilterArgs) => Promise<{
|
|
119
125
|
status: number;
|
|
120
126
|
}>;
|
|
127
|
+
getMatchesAnyList: ({ auth, params, request }: TGetMatchesAnyListArgs) => Promise<any>;
|
|
121
128
|
};
|
|
122
129
|
listing: {
|
|
123
130
|
getTableListing<T = any>({ auth, params, request, }: TGetTableListingArgs): Promise<DataTableListing<T>>;
|
|
@@ -104,7 +104,7 @@ export const dataTableServices = {
|
|
|
104
104
|
try {
|
|
105
105
|
const { url } = auth || {};
|
|
106
106
|
const { type = GET_SAVED_FILTER, objType: object, objId } = params || {};
|
|
107
|
-
const response = yield axios(Object.assign(Object.assign({
|
|
107
|
+
const response = yield axios(Object.assign(Object.assign({ url, method: 'GET' }, request), { params: Object.assign(Object.assign({ type,
|
|
108
108
|
object,
|
|
109
109
|
objId }, mapAuth(auth)), request === null || request === void 0 ? void 0 : request.params) }));
|
|
110
110
|
return get(response, 'data.data.filters', []);
|
|
@@ -117,7 +117,7 @@ export const dataTableServices = {
|
|
|
117
117
|
try {
|
|
118
118
|
const { url } = auth || {};
|
|
119
119
|
const { type = GET_LIST_FILTER, objType: object, objId } = params || {};
|
|
120
|
-
const response = yield axios(Object.assign(Object.assign({
|
|
120
|
+
const response = yield axios(Object.assign(Object.assign({ url, method: 'GET' }, request), { params: Object.assign(Object.assign({ type,
|
|
121
121
|
object,
|
|
122
122
|
objId }, mapAuth(auth)), request === null || request === void 0 ? void 0 : request.params) }));
|
|
123
123
|
return get(response, 'data.data.filters', []);
|
|
@@ -180,12 +180,24 @@ export const dataTableServices = {
|
|
|
180
180
|
return Promise.reject(error);
|
|
181
181
|
}
|
|
182
182
|
}),
|
|
183
|
+
getMatchesAnyList: (_r) => __awaiter(void 0, [_r], void 0, function* ({ auth, params, request }) {
|
|
184
|
+
try {
|
|
185
|
+
const { url } = auth || {};
|
|
186
|
+
const _s = request || {}, { method = 'GET' } = _s, restOfRequest = __rest(_s, ["method"]);
|
|
187
|
+
const response = yield axios(Object.assign(Object.assign({ url,
|
|
188
|
+
method }, restOfRequest), { params: Object.assign(Object.assign(Object.assign({}, mapAuth(auth)), params), request === null || request === void 0 ? void 0 : request.params) }));
|
|
189
|
+
return get(response, 'data.data', {});
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
return Promise.reject(error);
|
|
193
|
+
}
|
|
194
|
+
}),
|
|
183
195
|
},
|
|
184
196
|
listing: {
|
|
185
197
|
getTableListing(_a) {
|
|
186
198
|
return __awaiter(this, arguments, void 0, function* ({ auth, params, request, }) {
|
|
187
199
|
try {
|
|
188
|
-
const response = yield axios(Object.assign(Object.assign({
|
|
200
|
+
const response = yield axios(Object.assign(Object.assign({ url: `${auth === null || auth === void 0 ? void 0 : auth.url}`, method: 'GET' }, request), { params: Object.assign(Object.assign(Object.assign({}, params), mapAuth(auth)), request === null || request === void 0 ? void 0 : request.params) }));
|
|
189
201
|
return mapResponseListingToGeneral(get(response, 'data.data', {}));
|
|
190
202
|
}
|
|
191
203
|
catch (error) {
|
|
@@ -200,7 +212,7 @@ export const dataTableServices = {
|
|
|
200
212
|
const { search } = params || {};
|
|
201
213
|
const _b = request || {}, { method = 'GET' } = _b, restOfRequest = __rest(_b, ["method"]);
|
|
202
214
|
try {
|
|
203
|
-
const response = yield axios(Object.assign(Object.assign({
|
|
215
|
+
const response = yield axios(Object.assign(Object.assign({ method, url: `${auth === null || auth === void 0 ? void 0 : auth.url}` }, restOfRequest), { params: Object.assign(Object.assign({ search }, mapAuth(auth)), request === null || request === void 0 ? void 0 : request.params) }));
|
|
204
216
|
return get(response, 'data.data', {});
|
|
205
217
|
}
|
|
206
218
|
catch (error) {
|
|
@@ -5,11 +5,11 @@ import { BrowserRouter } from 'react-router-dom';
|
|
|
5
5
|
import { DataTable } from '../components/organism/DataTable';
|
|
6
6
|
// Styled
|
|
7
7
|
import { TableTestWrapper } from './styled';
|
|
8
|
+
// Constants
|
|
8
9
|
import { useDataTableListing } from '../components/organism/DataTable/hooks/useDataTableListing';
|
|
9
|
-
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
|
10
10
|
export const DataTableTest = () => {
|
|
11
11
|
// Hooks
|
|
12
|
-
const { filter, modifyColumn, pagination, table, search
|
|
12
|
+
const { filter, modifyColumn, pagination, table, search } = useDataTableListing({
|
|
13
13
|
name: 'survey-project',
|
|
14
14
|
config: {
|
|
15
15
|
// NOTES: This is no need pass auth props when had
|
|
@@ -38,15 +38,33 @@ export const DataTableTest = () => {
|
|
|
38
38
|
page: 1,
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
|
+
matchesAny: {
|
|
42
|
+
general: {
|
|
43
|
+
url: `https://sandbox-survey.antsomi.com/api/v1/survey/filter/get-value-matches-any`,
|
|
44
|
+
params(filterItem) {
|
|
45
|
+
var _a;
|
|
46
|
+
return {
|
|
47
|
+
metric_code: (_a = filterItem === null || filterItem === void 0 ? void 0 : filterItem.column) === null || _a === void 0 ? void 0 : _a.toString().toLowerCase(),
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
survey_id: {
|
|
52
|
+
url: 'https://sandbox-survey.antsomi.com/api/v1/survey/filter/get-value-matches-any',
|
|
53
|
+
params(filterItem) {
|
|
54
|
+
var _a;
|
|
55
|
+
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(),
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
41
62
|
},
|
|
42
63
|
object: {
|
|
43
64
|
type: 5, // Survey,
|
|
44
65
|
objectId: -1, // NOTES: will note detail when to use objectId, current is no need
|
|
45
66
|
},
|
|
46
67
|
},
|
|
47
|
-
// table: {
|
|
48
|
-
// sortDirectionKey: 'sortDirection',
|
|
49
|
-
// },
|
|
50
68
|
search: {
|
|
51
69
|
itemMapKeys: {
|
|
52
70
|
id: 'survey_id',
|
|
@@ -64,20 +82,36 @@ export const DataTableTest = () => {
|
|
|
64
82
|
formatData(response) {
|
|
65
83
|
return (response === null || response === void 0 ? void 0 : response.body) || [];
|
|
66
84
|
},
|
|
67
|
-
onClickSearchItem(item) {
|
|
68
|
-
console.log(item);
|
|
69
|
-
},
|
|
70
85
|
},
|
|
71
86
|
queryOptions: {
|
|
72
87
|
getTableListing: {
|
|
73
88
|
refetchOnMount: 'always',
|
|
74
89
|
},
|
|
75
90
|
},
|
|
91
|
+
filter: {
|
|
92
|
+
matchesAny: {
|
|
93
|
+
general: {
|
|
94
|
+
formatData(response) {
|
|
95
|
+
return response === null || response === void 0 ? void 0 : response.rows.map(record => ({
|
|
96
|
+
key: record.value,
|
|
97
|
+
title: record.label,
|
|
98
|
+
}));
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
survey_id: {
|
|
102
|
+
formatData(response) {
|
|
103
|
+
return response === null || response === void 0 ? void 0 : response.rows.map(record => ({
|
|
104
|
+
key: record.value,
|
|
105
|
+
title: record.value,
|
|
106
|
+
}));
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
76
111
|
});
|
|
77
112
|
return (React.createElement(BrowserRouter, null,
|
|
78
113
|
React.createElement(TableTestWrapper, null,
|
|
79
|
-
React.createElement(DataTable, { table:
|
|
80
|
-
addButton: {},
|
|
114
|
+
React.createElement(DataTable, { table: table, filter: filter, toolbar: {
|
|
81
115
|
actionButtons: {
|
|
82
116
|
SEARCH: search,
|
|
83
117
|
COLUMN: modifyColumn,
|
|
@@ -97,6 +131,5 @@ export const DataTableTest = () => {
|
|
|
97
131
|
},
|
|
98
132
|
},
|
|
99
133
|
},
|
|
100
|
-
}, pagination: pagination }))
|
|
101
|
-
React.createElement(ReactQueryDevtools, { initialIsOpen: false })));
|
|
134
|
+
}, pagination: pagination }))));
|
|
102
135
|
};
|