@ackplus/react-tanstack-data-table 1.1.20 → 1.1.21
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/dist/lib/hooks/use-data-table-engine.d.ts.map +1 -1
- package/dist/lib/hooks/use-data-table-engine.js +4 -0
- package/package.json +3 -4
- package/src/index.ts +0 -75
- package/src/lib/components/data-table-view.tsx +0 -386
- package/src/lib/components/droupdown/menu-dropdown.tsx +0 -103
- package/src/lib/components/filters/filter-value-input.tsx +0 -225
- package/src/lib/components/filters/index.ts +0 -126
- package/src/lib/components/headers/draggable-header.tsx +0 -326
- package/src/lib/components/headers/index.ts +0 -6
- package/src/lib/components/headers/table-header.tsx +0 -175
- package/src/lib/components/index.ts +0 -21
- package/src/lib/components/pagination/data-table-pagination.tsx +0 -111
- package/src/lib/components/pagination/index.ts +0 -5
- package/src/lib/components/rows/data-table-row.tsx +0 -218
- package/src/lib/components/rows/empty-data-row.tsx +0 -69
- package/src/lib/components/rows/index.ts +0 -7
- package/src/lib/components/rows/loading-rows.tsx +0 -164
- package/src/lib/components/toolbar/bulk-actions-toolbar.tsx +0 -125
- package/src/lib/components/toolbar/column-filter-control.tsx +0 -432
- package/src/lib/components/toolbar/column-pinning-control.tsx +0 -275
- package/src/lib/components/toolbar/column-reset-control.tsx +0 -74
- package/src/lib/components/toolbar/column-visibility-control.tsx +0 -105
- package/src/lib/components/toolbar/data-table-toolbar.tsx +0 -257
- package/src/lib/components/toolbar/index.ts +0 -17
- package/src/lib/components/toolbar/table-export-control.tsx +0 -233
- package/src/lib/components/toolbar/table-refresh-control.tsx +0 -62
- package/src/lib/components/toolbar/table-search-control.tsx +0 -155
- package/src/lib/components/toolbar/table-size-control.tsx +0 -102
- package/src/lib/contexts/data-table-context.tsx +0 -126
- package/src/lib/data-table.tsx +0 -29
- package/src/lib/features/README.md +0 -161
- package/src/lib/features/column-filter.feature.ts +0 -493
- package/src/lib/features/index.ts +0 -23
- package/src/lib/features/selection.feature.ts +0 -322
- package/src/lib/hooks/index.ts +0 -2
- package/src/lib/hooks/use-data-table-engine.ts +0 -1552
- package/src/lib/icons/add-icon.tsx +0 -23
- package/src/lib/icons/csv-icon.tsx +0 -15
- package/src/lib/icons/delete-icon.tsx +0 -30
- package/src/lib/icons/excel-icon.tsx +0 -15
- package/src/lib/icons/index.ts +0 -7
- package/src/lib/icons/unpin-icon.tsx +0 -18
- package/src/lib/icons/view-comfortable-icon.tsx +0 -45
- package/src/lib/icons/view-compact-icon.tsx +0 -55
- package/src/lib/types/column.types.ts +0 -63
- package/src/lib/types/data-table-api.ts +0 -191
- package/src/lib/types/data-table.types.ts +0 -193
- package/src/lib/types/export.types.ts +0 -223
- package/src/lib/types/index.ts +0 -24
- package/src/lib/types/slots.types.ts +0 -342
- package/src/lib/types/table.types.ts +0 -88
- package/src/lib/utils/column-helpers.ts +0 -72
- package/src/lib/utils/debounced-fetch.utils.ts +0 -131
- package/src/lib/utils/export-utils.ts +0 -712
- package/src/lib/utils/index.ts +0 -27
- package/src/lib/utils/logger.ts +0 -203
- package/src/lib/utils/slot-helpers.tsx +0 -194
- package/src/lib/utils/special-columns.utils.ts +0 -101
- package/src/lib/utils/styling-helpers.ts +0 -126
- package/src/lib/utils/table-helpers.ts +0 -106
|
@@ -1,432 +0,0 @@
|
|
|
1
|
-
import { FilterList } from "@mui/icons-material";
|
|
2
|
-
import {
|
|
3
|
-
Box,
|
|
4
|
-
MenuItem,
|
|
5
|
-
Select,
|
|
6
|
-
FormControl,
|
|
7
|
-
InputLabel,
|
|
8
|
-
Button,
|
|
9
|
-
Stack,
|
|
10
|
-
Typography,
|
|
11
|
-
IconButton,
|
|
12
|
-
Divider,
|
|
13
|
-
Badge,
|
|
14
|
-
type IconButtonProps,
|
|
15
|
-
type SxProps,
|
|
16
|
-
} from "@mui/material";
|
|
17
|
-
import React, {
|
|
18
|
-
useMemo,
|
|
19
|
-
useCallback,
|
|
20
|
-
useEffect,
|
|
21
|
-
useRef,
|
|
22
|
-
useState,
|
|
23
|
-
type ReactElement,
|
|
24
|
-
} from "react";
|
|
25
|
-
|
|
26
|
-
import { MenuDropdown } from "../droupdown/menu-dropdown";
|
|
27
|
-
import { useDataTableContext } from "../../contexts/data-table-context";
|
|
28
|
-
import { AddIcon, DeleteIcon } from "../../icons";
|
|
29
|
-
import { getColumnType, isColumnFilterable } from "../../utils/column-helpers";
|
|
30
|
-
import { getSlotComponent, mergeSlotProps, extractSlotProps } from "../../utils/slot-helpers";
|
|
31
|
-
import { FILTER_OPERATORS } from "../filters";
|
|
32
|
-
import { FilterValueInput } from "../filters/filter-value-input";
|
|
33
|
-
import type { ColumnFilterRule } from "../../features";
|
|
34
|
-
|
|
35
|
-
export interface ColumnFilterControlProps {
|
|
36
|
-
title?: string;
|
|
37
|
-
titleSx?: SxProps;
|
|
38
|
-
menuSx?: SxProps;
|
|
39
|
-
|
|
40
|
-
iconButtonProps?: IconButtonProps;
|
|
41
|
-
badgeProps?: any;
|
|
42
|
-
|
|
43
|
-
clearButtonProps?: any;
|
|
44
|
-
applyButtonProps?: any;
|
|
45
|
-
addButtonProps?: any;
|
|
46
|
-
deleteButtonProps?: any;
|
|
47
|
-
logicSelectProps?: any;
|
|
48
|
-
|
|
49
|
-
[key: string]: any;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Small helper component to sync MenuDropdown open state to parent state
|
|
54
|
-
* WITHOUT calling hooks inside render-prop callback.
|
|
55
|
-
*/
|
|
56
|
-
function OpenStateSync({
|
|
57
|
-
open,
|
|
58
|
-
onChange,
|
|
59
|
-
}: {
|
|
60
|
-
open: boolean;
|
|
61
|
-
onChange: (open: boolean) => void;
|
|
62
|
-
}) {
|
|
63
|
-
useEffect(() => onChange(open), [open, onChange]);
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function ColumnFilterControl(props: ColumnFilterControlProps = {}): ReactElement {
|
|
68
|
-
const { table, slots, slotProps } = useDataTableContext();
|
|
69
|
-
|
|
70
|
-
const iconSlotProps = extractSlotProps(slotProps, "filterIcon");
|
|
71
|
-
const FilterIconSlot = getSlotComponent(slots, "filterIcon", FilterList);
|
|
72
|
-
|
|
73
|
-
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
74
|
-
const didAutoAddRef = useRef(false);
|
|
75
|
-
|
|
76
|
-
const filterState =
|
|
77
|
-
table?.getColumnFilterState?.() || ({
|
|
78
|
-
filters: [],
|
|
79
|
-
logic: "AND",
|
|
80
|
-
pendingFilters: [],
|
|
81
|
-
pendingLogic: "AND",
|
|
82
|
-
} as any);
|
|
83
|
-
|
|
84
|
-
const filters: ColumnFilterRule[] = filterState.pendingFilters || [];
|
|
85
|
-
const filterLogic: "AND" | "OR" = (filterState.pendingLogic || "AND") as any;
|
|
86
|
-
|
|
87
|
-
const activeFiltersCount = table?.getActiveColumnFilters?.()?.length || 0;
|
|
88
|
-
|
|
89
|
-
const filterableColumns = useMemo(() => {
|
|
90
|
-
return table?.getAllLeafColumns().filter((column: any) => isColumnFilterable(column)) || [];
|
|
91
|
-
}, [table]);
|
|
92
|
-
|
|
93
|
-
const getOperatorsForColumn = useCallback(
|
|
94
|
-
(columnId: string) => {
|
|
95
|
-
const column = filterableColumns.find((col: any) => col.id === columnId);
|
|
96
|
-
const type = getColumnType(column as any);
|
|
97
|
-
return FILTER_OPERATORS[type as keyof typeof FILTER_OPERATORS] || FILTER_OPERATORS.text;
|
|
98
|
-
},
|
|
99
|
-
[filterableColumns]
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
const addFilter = useCallback(
|
|
103
|
-
(columnId?: string, operator?: string) => {
|
|
104
|
-
let defaultOperator = operator || "";
|
|
105
|
-
|
|
106
|
-
if (columnId && !operator) {
|
|
107
|
-
const column = filterableColumns.find((col: any) => col.id === columnId);
|
|
108
|
-
const columnType = getColumnType(column as any);
|
|
109
|
-
const operators =
|
|
110
|
-
FILTER_OPERATORS[columnType as keyof typeof FILTER_OPERATORS] || FILTER_OPERATORS.text;
|
|
111
|
-
defaultOperator = operators[0]?.value || "contains";
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
table?.addPendingColumnFilter?.(columnId || "", defaultOperator, "");
|
|
115
|
-
},
|
|
116
|
-
[table, filterableColumns]
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
const updateFilter = useCallback(
|
|
120
|
-
(filterId: string, updates: Partial<ColumnFilterRule>) => {
|
|
121
|
-
table?.updatePendingColumnFilter?.(filterId, updates);
|
|
122
|
-
},
|
|
123
|
-
[table]
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
const removeFilter = useCallback(
|
|
127
|
-
(filterId: string) => {
|
|
128
|
-
table?.removePendingColumnFilter?.(filterId);
|
|
129
|
-
},
|
|
130
|
-
[table]
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
const clearAllFilters = useCallback((closeDialog?: () => void) => {
|
|
134
|
-
// Defer all work to avoid long-running click handler (prevents "[Violation] 'click' handler took Xms")
|
|
135
|
-
setTimeout(() => {
|
|
136
|
-
table?.resetColumnFilter?.();
|
|
137
|
-
// Prevent auto-add effect from adding a row when it sees empty state after clear
|
|
138
|
-
didAutoAddRef.current = true;
|
|
139
|
-
closeDialog?.();
|
|
140
|
-
}, 0);
|
|
141
|
-
}, [table]);
|
|
142
|
-
|
|
143
|
-
const handleLogicChange = useCallback(
|
|
144
|
-
(newLogic: "AND" | "OR") => {
|
|
145
|
-
table?.setPendingFilterLogic?.(newLogic);
|
|
146
|
-
},
|
|
147
|
-
[table]
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
const applyFilters = useCallback(() => {
|
|
151
|
-
table?.applyPendingColumnFilters?.();
|
|
152
|
-
}, [table]);
|
|
153
|
-
|
|
154
|
-
const handleApplyFilters = useCallback(
|
|
155
|
-
(closeDialog: () => void) => {
|
|
156
|
-
// Defer so click handler returns immediately (prevents "[Violation] 'click' handler took Xms")
|
|
157
|
-
setTimeout(() => {
|
|
158
|
-
applyFilters();
|
|
159
|
-
closeDialog();
|
|
160
|
-
}, 0);
|
|
161
|
-
},
|
|
162
|
-
[applyFilters]
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
const handleColumnChange = useCallback(
|
|
166
|
-
(filterId: string, newColumnId: string, currentFilter: ColumnFilterRule) => {
|
|
167
|
-
const newColumn = filterableColumns.find((col: any) => col.id === newColumnId);
|
|
168
|
-
const columnType = getColumnType(newColumn as any);
|
|
169
|
-
const operators =
|
|
170
|
-
FILTER_OPERATORS[columnType as keyof typeof FILTER_OPERATORS] || FILTER_OPERATORS.text;
|
|
171
|
-
|
|
172
|
-
const currentOperatorValid = operators.some((op) => op.value === currentFilter.operator);
|
|
173
|
-
const newOperator = currentOperatorValid ? currentFilter.operator : operators[0]?.value || "";
|
|
174
|
-
|
|
175
|
-
updateFilter(filterId, {
|
|
176
|
-
columnId: newColumnId,
|
|
177
|
-
operator: newOperator,
|
|
178
|
-
value: ["isEmpty", "isNotEmpty"].includes(newOperator) ? "" : currentFilter.value,
|
|
179
|
-
});
|
|
180
|
-
},
|
|
181
|
-
[filterableColumns, updateFilter]
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
const handleOperatorChange = useCallback(
|
|
185
|
-
(filterId: string, newOperator: string, currentFilter: ColumnFilterRule) => {
|
|
186
|
-
updateFilter(filterId, {
|
|
187
|
-
operator: newOperator,
|
|
188
|
-
value: ["isEmpty", "isNotEmpty"].includes(newOperator) ? "" : currentFilter.value,
|
|
189
|
-
});
|
|
190
|
-
},
|
|
191
|
-
[updateFilter]
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
const handleFilterValueChange = useCallback(
|
|
195
|
-
(filterId: string, value: any) => {
|
|
196
|
-
updateFilter(filterId, { value });
|
|
197
|
-
},
|
|
198
|
-
[updateFilter]
|
|
199
|
-
);
|
|
200
|
-
|
|
201
|
-
const pendingReadyCount = useMemo(() => {
|
|
202
|
-
return filters.filter((f) => {
|
|
203
|
-
if (!f.columnId || !f.operator) return false;
|
|
204
|
-
if (["isEmpty", "isNotEmpty"].includes(f.operator)) return true;
|
|
205
|
-
return f.value != null && String(f.value).trim() !== "";
|
|
206
|
-
}).length;
|
|
207
|
-
}, [filters]);
|
|
208
|
-
|
|
209
|
-
const hasAppliedFilters = activeFiltersCount > 0;
|
|
210
|
-
const hasPendingChanges = pendingReadyCount > 0 || (filters.length === 0 && hasAppliedFilters);
|
|
211
|
-
|
|
212
|
-
// Auto-add only once per open. If menu opened with existing filters, mark as processed so
|
|
213
|
-
// "Clear All" doesn't cause a new row to be auto-added when state becomes empty.
|
|
214
|
-
useEffect(() => {
|
|
215
|
-
if (!isMenuOpen) {
|
|
216
|
-
didAutoAddRef.current = false;
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
if (didAutoAddRef.current) return;
|
|
220
|
-
if (!filterableColumns.length) {
|
|
221
|
-
didAutoAddRef.current = true;
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
if (filters.length > 0 || activeFiltersCount > 0) {
|
|
225
|
-
// Already have filters this session; mark processed so clear won't re-trigger auto-add
|
|
226
|
-
didAutoAddRef.current = true;
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const firstColumn = filterableColumns[0];
|
|
231
|
-
const columnType = getColumnType(firstColumn as any);
|
|
232
|
-
const operators =
|
|
233
|
-
FILTER_OPERATORS[columnType as keyof typeof FILTER_OPERATORS] || FILTER_OPERATORS.text;
|
|
234
|
-
const defaultOperator = operators[0]?.value || "contains";
|
|
235
|
-
|
|
236
|
-
didAutoAddRef.current = true;
|
|
237
|
-
addFilter(firstColumn.id, defaultOperator);
|
|
238
|
-
}, [isMenuOpen, filterableColumns, filters.length, activeFiltersCount, addFilter]);
|
|
239
|
-
|
|
240
|
-
// Merge props but do NOT spread non-icon props onto IconButton
|
|
241
|
-
const mergedProps = mergeSlotProps(
|
|
242
|
-
{ size: "small", sx: { flexShrink: 0 } },
|
|
243
|
-
slotProps?.columnFilterControl || {},
|
|
244
|
-
props
|
|
245
|
-
);
|
|
246
|
-
|
|
247
|
-
const {
|
|
248
|
-
badgeProps,
|
|
249
|
-
menuSx,
|
|
250
|
-
title,
|
|
251
|
-
titleSx,
|
|
252
|
-
logicSelectProps,
|
|
253
|
-
clearButtonProps,
|
|
254
|
-
applyButtonProps,
|
|
255
|
-
addButtonProps,
|
|
256
|
-
deleteButtonProps,
|
|
257
|
-
iconButtonProps,
|
|
258
|
-
...iconButtonRestProps
|
|
259
|
-
} = mergedProps;
|
|
260
|
-
|
|
261
|
-
return (
|
|
262
|
-
<MenuDropdown
|
|
263
|
-
anchor={({ isOpen }) => (
|
|
264
|
-
<Box sx={{ display: "inline-flex" }}>
|
|
265
|
-
{/* sync dropdown open state to our local state */}
|
|
266
|
-
<OpenStateSync open={isOpen} onChange={setIsMenuOpen} />
|
|
267
|
-
|
|
268
|
-
<Badge
|
|
269
|
-
badgeContent={activeFiltersCount > 0 ? activeFiltersCount : 0}
|
|
270
|
-
color="primary"
|
|
271
|
-
invisible={activeFiltersCount === 0}
|
|
272
|
-
{...badgeProps}
|
|
273
|
-
>
|
|
274
|
-
<IconButton
|
|
275
|
-
{...(iconButtonRestProps as IconButtonProps)}
|
|
276
|
-
{...(iconButtonProps as IconButtonProps)}
|
|
277
|
-
>
|
|
278
|
-
<FilterIconSlot {...iconSlotProps} />
|
|
279
|
-
</IconButton>
|
|
280
|
-
</Badge>
|
|
281
|
-
</Box>
|
|
282
|
-
)}
|
|
283
|
-
>
|
|
284
|
-
{({ handleClose }: { handleClose: (event?: any) => void }) => (
|
|
285
|
-
<Box
|
|
286
|
-
sx={{
|
|
287
|
-
p: 2,
|
|
288
|
-
minWidth: 400,
|
|
289
|
-
maxWidth: 600,
|
|
290
|
-
...(menuSx || {}),
|
|
291
|
-
}}
|
|
292
|
-
onClick={(e) => e.stopPropagation()}
|
|
293
|
-
>
|
|
294
|
-
<Typography
|
|
295
|
-
variant="subtitle2"
|
|
296
|
-
sx={{
|
|
297
|
-
mb: 1,
|
|
298
|
-
...(titleSx || {}),
|
|
299
|
-
}}
|
|
300
|
-
>
|
|
301
|
-
{title || "Column Filters"}
|
|
302
|
-
</Typography>
|
|
303
|
-
|
|
304
|
-
<Divider sx={{ mb: 2 }} />
|
|
305
|
-
|
|
306
|
-
{filters.length > 1 && (
|
|
307
|
-
<Box sx={{ mb: 2 }}>
|
|
308
|
-
<FormControl size="small" sx={{ minWidth: 120 }}>
|
|
309
|
-
<InputLabel>Logic</InputLabel>
|
|
310
|
-
<Select
|
|
311
|
-
value={filterLogic}
|
|
312
|
-
label="Logic"
|
|
313
|
-
onChange={(e) => handleLogicChange(e.target.value as "AND" | "OR")}
|
|
314
|
-
{...logicSelectProps}
|
|
315
|
-
>
|
|
316
|
-
<MenuItem value="AND">AND</MenuItem>
|
|
317
|
-
<MenuItem value="OR">OR</MenuItem>
|
|
318
|
-
</Select>
|
|
319
|
-
</FormControl>
|
|
320
|
-
</Box>
|
|
321
|
-
)}
|
|
322
|
-
|
|
323
|
-
<Stack spacing={2} sx={{ mb: 2 }}>
|
|
324
|
-
{filters.map((filter) => {
|
|
325
|
-
const selectedColumn = filterableColumns.find((col: any) => col.id === filter.columnId);
|
|
326
|
-
const operators = filter.columnId ? getOperatorsForColumn(filter.columnId) : [];
|
|
327
|
-
const needsValue = !["isEmpty", "isNotEmpty"].includes(filter.operator);
|
|
328
|
-
|
|
329
|
-
return (
|
|
330
|
-
<Stack key={filter.id} direction="row" spacing={1} alignItems="center">
|
|
331
|
-
<FormControl size="small" sx={{ minWidth: 120 }}>
|
|
332
|
-
<InputLabel>Column</InputLabel>
|
|
333
|
-
<Select
|
|
334
|
-
value={filter.columnId || ""}
|
|
335
|
-
label="Column"
|
|
336
|
-
onChange={(e) =>
|
|
337
|
-
handleColumnChange(filter.id, e.target.value as string, filter)
|
|
338
|
-
}
|
|
339
|
-
>
|
|
340
|
-
{filterableColumns.map((column: any) => (
|
|
341
|
-
<MenuItem key={column.id} value={column.id}>
|
|
342
|
-
{typeof column.columnDef.header === "string"
|
|
343
|
-
? column.columnDef.header
|
|
344
|
-
: column.id}
|
|
345
|
-
</MenuItem>
|
|
346
|
-
))}
|
|
347
|
-
</Select>
|
|
348
|
-
</FormControl>
|
|
349
|
-
|
|
350
|
-
<FormControl size="small" sx={{ minWidth: 120 }}>
|
|
351
|
-
<InputLabel>Operator</InputLabel>
|
|
352
|
-
<Select
|
|
353
|
-
value={filter.operator || ""}
|
|
354
|
-
label="Operator"
|
|
355
|
-
onChange={(e) =>
|
|
356
|
-
handleOperatorChange(filter.id, e.target.value as string, filter)
|
|
357
|
-
}
|
|
358
|
-
disabled={!filter.columnId}
|
|
359
|
-
>
|
|
360
|
-
{operators.map((op: any) => (
|
|
361
|
-
<MenuItem key={op.value} value={op.value}>
|
|
362
|
-
{op.label}
|
|
363
|
-
</MenuItem>
|
|
364
|
-
))}
|
|
365
|
-
</Select>
|
|
366
|
-
</FormControl>
|
|
367
|
-
|
|
368
|
-
{needsValue && selectedColumn && (
|
|
369
|
-
<FilterValueInput
|
|
370
|
-
filter={filter}
|
|
371
|
-
column={selectedColumn}
|
|
372
|
-
onValueChange={(value) => handleFilterValueChange(filter.id, value)}
|
|
373
|
-
/>
|
|
374
|
-
)}
|
|
375
|
-
|
|
376
|
-
<IconButton
|
|
377
|
-
size="small"
|
|
378
|
-
onClick={() => removeFilter(filter.id)}
|
|
379
|
-
color="error"
|
|
380
|
-
{...deleteButtonProps}
|
|
381
|
-
>
|
|
382
|
-
<DeleteIcon fontSize="small" />
|
|
383
|
-
</IconButton>
|
|
384
|
-
</Stack>
|
|
385
|
-
);
|
|
386
|
-
})}
|
|
387
|
-
</Stack>
|
|
388
|
-
|
|
389
|
-
<Button
|
|
390
|
-
variant="outlined"
|
|
391
|
-
size="small"
|
|
392
|
-
startIcon={<AddIcon />}
|
|
393
|
-
onClick={() => addFilter()}
|
|
394
|
-
disabled={filterableColumns.length === 0}
|
|
395
|
-
sx={{ mb: 2 }}
|
|
396
|
-
{...addButtonProps}
|
|
397
|
-
>
|
|
398
|
-
Add Filter
|
|
399
|
-
</Button>
|
|
400
|
-
|
|
401
|
-
<Stack direction="row" spacing={1} justifyContent="flex-end">
|
|
402
|
-
{hasAppliedFilters && (
|
|
403
|
-
<Button
|
|
404
|
-
variant="outlined"
|
|
405
|
-
size="small"
|
|
406
|
-
onClick={(e) => {
|
|
407
|
-
e.preventDefault();
|
|
408
|
-
e.stopPropagation();
|
|
409
|
-
clearAllFilters(handleClose);
|
|
410
|
-
}}
|
|
411
|
-
color="error"
|
|
412
|
-
{...clearButtonProps}
|
|
413
|
-
>
|
|
414
|
-
Clear All
|
|
415
|
-
</Button>
|
|
416
|
-
)}
|
|
417
|
-
|
|
418
|
-
<Button
|
|
419
|
-
variant="contained"
|
|
420
|
-
size="small"
|
|
421
|
-
onClick={() => handleApplyFilters(() => handleClose?.())}
|
|
422
|
-
disabled={!hasPendingChanges}
|
|
423
|
-
{...applyButtonProps}
|
|
424
|
-
>
|
|
425
|
-
Apply
|
|
426
|
-
</Button>
|
|
427
|
-
</Stack>
|
|
428
|
-
</Box>
|
|
429
|
-
)}
|
|
430
|
-
</MenuDropdown>
|
|
431
|
-
);
|
|
432
|
-
}
|