@ackplus/react-tanstack-data-table 1.0.34 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/{src → dist}/index.d.ts +21 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/{src → dist}/lib/components/droupdown/menu-dropdown.d.ts +2 -1
- package/dist/lib/components/droupdown/menu-dropdown.d.ts.map +1 -0
- package/{src → dist}/lib/components/droupdown/menu-dropdown.js +38 -7
- package/{src → dist}/lib/components/filters/filter-value-input.d.ts +3 -1
- package/dist/lib/components/filters/filter-value-input.d.ts.map +1 -0
- package/dist/lib/components/filters/filter-value-input.js +83 -0
- package/{src → dist}/lib/components/filters/index.d.ts +1 -0
- package/dist/lib/components/filters/index.d.ts.map +1 -0
- package/dist/lib/components/filters/index.js +142 -0
- package/{src → dist}/lib/components/headers/draggable-header.d.ts +2 -2
- package/dist/lib/components/headers/draggable-header.d.ts.map +1 -0
- package/{src → dist}/lib/components/headers/draggable-header.js +81 -17
- package/dist/lib/components/headers/index.d.ts +6 -0
- package/dist/lib/components/headers/index.d.ts.map +1 -0
- package/dist/lib/components/headers/index.js +21 -0
- package/{src → dist}/lib/components/headers/table-header.d.ts +15 -1
- package/dist/lib/components/headers/table-header.d.ts.map +1 -0
- package/{src → dist}/lib/components/headers/table-header.js +50 -17
- package/{src → dist}/lib/components/index.d.ts +6 -1
- package/dist/lib/components/index.d.ts.map +1 -0
- package/dist/lib/components/index.js +32 -0
- package/{src → dist}/lib/components/pagination/data-table-pagination.d.ts +2 -1
- package/dist/lib/components/pagination/data-table-pagination.d.ts.map +1 -0
- package/{src → dist}/lib/components/pagination/data-table-pagination.js +20 -6
- package/dist/lib/components/pagination/index.d.ts +5 -0
- package/dist/lib/components/pagination/index.d.ts.map +1 -0
- package/dist/lib/components/pagination/index.js +20 -0
- package/{src → dist}/lib/components/rows/data-table-row.d.ts +15 -2
- package/dist/lib/components/rows/data-table-row.d.ts.map +1 -0
- package/{src → dist}/lib/components/rows/data-table-row.js +58 -25
- package/{src → dist}/lib/components/rows/empty-data-row.d.ts +3 -3
- package/dist/lib/components/rows/empty-data-row.d.ts.map +1 -0
- package/{src → dist}/lib/components/rows/empty-data-row.js +12 -4
- package/dist/lib/components/rows/index.d.ts +7 -0
- package/dist/lib/components/rows/index.d.ts.map +1 -0
- package/dist/lib/components/rows/index.js +22 -0
- package/{src → dist}/lib/components/rows/loading-rows.d.ts +3 -1
- package/dist/lib/components/rows/loading-rows.d.ts.map +1 -0
- package/{src → dist}/lib/components/rows/loading-rows.js +27 -19
- package/{src → dist}/lib/components/toolbar/bulk-actions-toolbar.d.ts +4 -3
- package/dist/lib/components/toolbar/bulk-actions-toolbar.d.ts.map +1 -0
- package/dist/lib/components/toolbar/bulk-actions-toolbar.js +49 -0
- package/{src → dist}/lib/components/toolbar/column-filter-control.d.ts +3 -1
- package/dist/lib/components/toolbar/column-filter-control.d.ts.map +1 -0
- package/{src → dist}/lib/components/toolbar/column-filter-control.js +73 -4
- package/{src → dist}/lib/components/toolbar/column-pinning-control.d.ts +2 -1
- package/dist/lib/components/toolbar/column-pinning-control.d.ts.map +1 -0
- package/{src → dist}/lib/components/toolbar/column-pinning-control.js +71 -7
- package/{src → dist}/lib/components/toolbar/column-reset-control.d.ts +3 -1
- package/dist/lib/components/toolbar/column-reset-control.d.ts.map +1 -0
- package/{src → dist}/lib/components/toolbar/column-reset-control.js +9 -3
- package/{src → dist}/lib/components/toolbar/column-visibility-control.d.ts +2 -1
- package/dist/lib/components/toolbar/column-visibility-control.d.ts.map +1 -0
- package/dist/lib/components/toolbar/column-visibility-control.js +77 -0
- package/{src → dist}/lib/components/toolbar/data-table-toolbar.d.ts +3 -2
- package/dist/lib/components/toolbar/data-table-toolbar.d.ts.map +1 -0
- package/{src → dist}/lib/components/toolbar/data-table-toolbar.js +17 -4
- package/{src → dist}/lib/components/toolbar/index.d.ts +4 -0
- package/dist/lib/components/toolbar/index.d.ts.map +1 -0
- package/{src → dist}/lib/components/toolbar/index.js +6 -0
- package/dist/lib/components/toolbar/table-export-control.d.ts +12 -0
- package/dist/lib/components/toolbar/table-export-control.d.ts.map +1 -0
- package/dist/lib/components/toolbar/table-export-control.js +67 -0
- package/{src → dist}/lib/components/toolbar/table-search-control.d.ts +3 -1
- package/dist/lib/components/toolbar/table-search-control.d.ts.map +1 -0
- package/{src → dist}/lib/components/toolbar/table-search-control.js +45 -2
- package/{src → dist}/lib/components/toolbar/table-size-control.d.ts +3 -1
- package/dist/lib/components/toolbar/table-size-control.d.ts.map +1 -0
- package/{src → dist}/lib/components/toolbar/table-size-control.js +20 -8
- package/{src → dist}/lib/contexts/data-table-context.d.ts +6 -2
- package/dist/lib/contexts/data-table-context.d.ts.map +1 -0
- package/{src → dist}/lib/contexts/data-table-context.js +34 -1
- package/dist/lib/data-table.d.ts +5 -0
- package/dist/lib/data-table.d.ts.map +1 -0
- package/{src/lib/components/table → dist/lib}/data-table.js +449 -151
- package/dist/lib/features/column-filter.feature.d.ts +55 -0
- package/dist/lib/features/column-filter.feature.d.ts.map +1 -0
- package/{src → dist}/lib/features/column-filter.feature.js +116 -18
- package/dist/lib/features/index.d.ts +9 -0
- package/dist/lib/features/index.d.ts.map +1 -0
- package/{src → dist}/lib/features/index.js +7 -0
- package/{src → dist}/lib/features/selection.feature.d.ts +8 -1
- package/dist/lib/features/selection.feature.d.ts.map +1 -0
- package/{src → dist}/lib/features/selection.feature.js +76 -15
- package/dist/lib/icons/add-icon.d.ts +4 -0
- package/dist/lib/icons/add-icon.d.ts.map +1 -0
- package/dist/lib/icons/add-icon.js +12 -0
- package/dist/lib/icons/csv-icon.d.ts +4 -0
- package/dist/lib/icons/csv-icon.d.ts.map +1 -0
- package/dist/lib/icons/csv-icon.js +12 -0
- package/dist/lib/icons/delete-icon.d.ts +4 -0
- package/dist/lib/icons/delete-icon.d.ts.map +1 -0
- package/dist/lib/icons/delete-icon.js +12 -0
- package/dist/lib/icons/excel-icon.d.ts +4 -0
- package/dist/lib/icons/excel-icon.d.ts.map +1 -0
- package/dist/lib/icons/excel-icon.js +12 -0
- package/dist/lib/icons/index.d.ts +8 -0
- package/dist/lib/icons/index.d.ts.map +1 -0
- package/dist/lib/icons/unpin-icon.d.ts +4 -0
- package/dist/lib/icons/unpin-icon.d.ts.map +1 -0
- package/dist/lib/icons/unpin-icon.js +12 -0
- package/{src → dist}/lib/icons/view-comfortable-icon.d.ts +3 -1
- package/dist/lib/icons/view-comfortable-icon.d.ts.map +1 -0
- package/dist/lib/icons/view-comfortable-icon.js +12 -0
- package/dist/lib/icons/view-compact-icon.d.ts +4 -0
- package/dist/lib/icons/view-compact-icon.d.ts.map +1 -0
- package/dist/lib/icons/view-compact-icon.js +12 -0
- package/{src → dist}/lib/types/column.types.d.ts +10 -1
- package/dist/lib/types/column.types.d.ts.map +1 -0
- package/{src → dist}/lib/types/data-table-api.d.ts +2 -1
- package/dist/lib/types/data-table-api.d.ts.map +1 -0
- package/{src/lib/components/table → dist/lib/types}/data-table.types.d.ts +10 -10
- package/dist/lib/types/data-table.types.d.ts.map +1 -0
- package/{src → dist}/lib/types/export.types.d.ts +38 -0
- package/dist/lib/types/export.types.d.ts.map +1 -0
- package/dist/lib/types/export.types.js +6 -0
- package/{src → dist}/lib/types/index.d.ts +5 -0
- package/dist/lib/types/index.d.ts.map +1 -0
- package/dist/lib/types/index.js +30 -0
- package/{src → dist}/lib/types/slots.types.d.ts +50 -3
- package/dist/lib/types/slots.types.d.ts.map +1 -0
- package/{src → dist}/lib/types/table.types.d.ts +14 -0
- package/dist/lib/types/table.types.d.ts.map +1 -0
- package/{src → dist}/lib/utils/column-helpers.d.ts +10 -0
- package/dist/lib/utils/column-helpers.d.ts.map +1 -0
- package/{src → dist}/lib/utils/column-helpers.js +20 -4
- package/{src → dist}/lib/utils/debounced-fetch.utils.d.ts +3 -5
- package/dist/lib/utils/debounced-fetch.utils.d.ts.map +1 -0
- package/{src → dist}/lib/utils/debounced-fetch.utils.js +12 -6
- package/{src → dist}/lib/utils/export-utils.d.ts +13 -0
- package/dist/lib/utils/export-utils.d.ts.map +1 -0
- package/dist/lib/utils/export-utils.js +252 -0
- package/{src → dist}/lib/utils/index.d.ts +4 -0
- package/dist/lib/utils/index.d.ts.map +1 -0
- package/dist/lib/utils/index.js +35 -0
- package/{src → dist}/lib/utils/logger.d.ts +43 -0
- package/dist/lib/utils/logger.d.ts.map +1 -0
- package/{src → dist}/lib/utils/logger.js +22 -2
- package/{src → dist}/lib/utils/slot-helpers.d.ts +39 -1
- package/dist/lib/utils/slot-helpers.d.ts.map +1 -0
- package/{src → dist}/lib/utils/slot-helpers.js +55 -6
- package/{src → dist}/lib/utils/special-columns.utils.d.ts +10 -0
- package/dist/lib/utils/special-columns.utils.d.ts.map +1 -0
- package/{src → dist}/lib/utils/special-columns.utils.js +41 -5
- package/{src → dist}/lib/utils/styling-helpers.d.ts +20 -0
- package/dist/lib/utils/styling-helpers.d.ts.map +1 -0
- package/dist/lib/utils/styling-helpers.js +108 -0
- package/{src → dist}/lib/utils/table-helpers.d.ts +25 -0
- package/dist/lib/utils/table-helpers.d.ts.map +1 -0
- package/{src → dist}/lib/utils/table-helpers.js +24 -0
- package/package.json +36 -11
- package/src/index.ts +71 -0
- package/src/lib/components/droupdown/menu-dropdown.tsx +97 -0
- package/src/lib/components/filters/filter-value-input.tsx +225 -0
- package/src/lib/components/filters/{index.js → index.ts} +3 -6
- package/src/lib/components/headers/draggable-header.tsx +326 -0
- package/src/lib/components/headers/{index.d.ts → index.ts} +4 -0
- package/src/lib/components/headers/table-header.tsx +173 -0
- package/src/lib/components/index.ts +21 -0
- package/src/lib/components/pagination/data-table-pagination.tsx +99 -0
- package/src/lib/components/pagination/index.ts +5 -0
- package/src/lib/components/rows/data-table-row.tsx +208 -0
- package/src/lib/components/rows/empty-data-row.tsx +69 -0
- package/src/lib/components/rows/{index.d.ts → index.ts} +4 -0
- package/src/lib/components/rows/loading-rows.tsx +160 -0
- package/src/lib/components/toolbar/bulk-actions-toolbar.tsx +125 -0
- package/src/lib/components/toolbar/column-filter-control.tsx +374 -0
- package/src/lib/components/toolbar/column-pinning-control.tsx +275 -0
- package/src/lib/components/toolbar/column-reset-control.tsx +74 -0
- package/src/lib/components/toolbar/column-visibility-control.tsx +105 -0
- package/src/lib/components/toolbar/data-table-toolbar.tsx +229 -0
- package/src/lib/components/toolbar/index.ts +17 -0
- package/src/lib/components/toolbar/table-export-control.tsx +179 -0
- package/src/lib/components/toolbar/table-search-control.tsx +155 -0
- package/src/lib/components/toolbar/table-size-control.tsx +102 -0
- package/src/lib/contexts/data-table-context.tsx +112 -0
- package/src/lib/data-table.tsx +1911 -0
- package/src/lib/features/README.md +161 -0
- package/src/lib/features/column-filter.feature.ts +456 -0
- package/src/lib/features/index.ts +23 -0
- package/src/lib/features/selection.feature.ts +318 -0
- package/src/lib/icons/add-icon.tsx +23 -0
- package/src/lib/icons/csv-icon.tsx +15 -0
- package/src/lib/icons/delete-icon.tsx +30 -0
- package/src/lib/icons/excel-icon.tsx +15 -0
- package/src/lib/icons/unpin-icon.tsx +18 -0
- package/src/lib/icons/view-comfortable-icon.tsx +45 -0
- package/src/lib/icons/view-compact-icon.tsx +55 -0
- package/src/lib/types/column.types.ts +44 -0
- package/src/lib/types/data-table-api.ts +169 -0
- package/src/lib/types/data-table.types.ts +139 -0
- package/src/lib/types/export.types.ts +154 -0
- package/src/lib/types/index.ts +22 -0
- package/src/lib/types/slots.types.ts +332 -0
- package/src/lib/types/table.types.ts +90 -0
- package/src/lib/utils/column-helpers.ts +72 -0
- package/src/lib/utils/debounced-fetch.utils.ts +54 -0
- package/src/lib/utils/export-utils.ts +285 -0
- package/src/lib/utils/index.ts +27 -0
- package/src/lib/utils/logger.ts +203 -0
- package/src/lib/utils/slot-helpers.tsx +194 -0
- package/src/lib/utils/special-columns.utils.ts +94 -0
- package/src/lib/utils/styling-helpers.ts +126 -0
- package/src/lib/utils/table-helpers.ts +106 -0
- package/src/index.js +0 -27
- package/src/lib/components/filters/filter-value-input.js +0 -41
- package/src/lib/components/headers/index.js +0 -5
- package/src/lib/components/index.js +0 -10
- package/src/lib/components/pagination/index.d.ts +0 -1
- package/src/lib/components/pagination/index.js +0 -4
- package/src/lib/components/rows/index.js +0 -6
- package/src/lib/components/table/data-table.d.ts +0 -4
- package/src/lib/components/table/index.d.ts +0 -2
- package/src/lib/components/table/index.js +0 -5
- package/src/lib/components/toolbar/bulk-actions-toolbar.js +0 -30
- package/src/lib/components/toolbar/column-visibility-control.js +0 -31
- package/src/lib/components/toolbar/table-export-control.d.ts +0 -31
- package/src/lib/components/toolbar/table-export-control.js +0 -56
- package/src/lib/examples/advanced-features-example.d.ts +0 -1
- package/src/lib/examples/advanced-features-example.js +0 -269
- package/src/lib/examples/bulk-actions-test.d.ts +0 -1
- package/src/lib/examples/bulk-actions-test.js +0 -44
- package/src/lib/examples/custom-column-filter-example.d.ts +0 -1
- package/src/lib/examples/custom-column-filter-example.js +0 -60
- package/src/lib/examples/index.d.ts +0 -8
- package/src/lib/examples/index.js +0 -19
- package/src/lib/examples/selection-test-example.d.ts +0 -1
- package/src/lib/examples/selection-test-example.js +0 -101
- package/src/lib/examples/server-side-fetching-example.d.ts +0 -1
- package/src/lib/examples/server-side-fetching-example.js +0 -245
- package/src/lib/examples/server-side-test.d.ts +0 -1
- package/src/lib/examples/server-side-test.js +0 -9
- package/src/lib/examples/simple-local-example.d.ts +0 -1
- package/src/lib/examples/simple-local-example.js +0 -95
- package/src/lib/examples/simple-slots-example.d.ts +0 -1
- package/src/lib/examples/simple-slots-example.js +0 -115
- package/src/lib/features/column-filter.feature.d.ts +0 -45
- package/src/lib/features/index.d.ts +0 -2
- package/src/lib/hooks/index.d.ts +0 -1
- package/src/lib/hooks/index.js +0 -4
- package/src/lib/hooks/use-data-table-api.d.ts +0 -46
- package/src/lib/hooks/use-data-table-api.js +0 -690
- package/src/lib/icons/add-icon.d.ts +0 -2
- package/src/lib/icons/add-icon.js +0 -8
- package/src/lib/icons/csv-icon.d.ts +0 -2
- package/src/lib/icons/csv-icon.js +0 -8
- package/src/lib/icons/delete-icon.d.ts +0 -2
- package/src/lib/icons/delete-icon.js +0 -8
- package/src/lib/icons/excel-icon.d.ts +0 -2
- package/src/lib/icons/excel-icon.js +0 -8
- package/src/lib/icons/unpin-icon.d.ts +0 -2
- package/src/lib/icons/unpin-icon.js +0 -8
- package/src/lib/icons/view-comfortable-icon.js +0 -8
- package/src/lib/icons/view-compact-icon.d.ts +0 -2
- package/src/lib/icons/view-compact-icon.js +0 -8
- package/src/lib/types/export.types.js +0 -2
- package/src/lib/types/index.js +0 -8
- package/src/lib/utils/export-utils.js +0 -175
- package/src/lib/utils/index.js +0 -11
- package/src/lib/utils/styling-helpers.js +0 -70
- package/tsconfig.tsbuildinfo +0 -1
- /package/{src → dist}/lib/icons/index.js +0 -0
- /package/{src → dist}/lib/types/column.types.js +0 -0
- /package/{src → dist}/lib/types/data-table-api.js +0 -0
- /package/{src/lib/components/table → dist/lib/types}/data-table.types.js +0 -0
- /package/{src → dist}/lib/types/slots.types.js +0 -0
- /package/{src → dist}/lib/types/table.types.js +0 -0
- /package/src/lib/icons/{index.d.ts → index.ts} +0 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import React, { ReactElement } from 'react';
|
|
2
|
+
import { TableCell, TableRow, Skeleton, TableRowProps, TableCellProps, SxProps } from '@mui/material';
|
|
3
|
+
|
|
4
|
+
import { useDataTableContext } from '../../contexts/data-table-context';
|
|
5
|
+
import { getPinnedColumnStyle } from '../../utils';
|
|
6
|
+
import { getSlotComponent, mergeSlotProps, extractSlotProps } from '../../utils/slot-helpers';
|
|
7
|
+
|
|
8
|
+
export interface LoadingRowsProps {
|
|
9
|
+
rowCount?: number;
|
|
10
|
+
// Enhanced customization props
|
|
11
|
+
rowProps?: TableRowProps;
|
|
12
|
+
cellProps?: TableCellProps;
|
|
13
|
+
skeletonProps?: any;
|
|
14
|
+
containerSx?: SxProps;
|
|
15
|
+
slots?: Record<string, any>;
|
|
16
|
+
slotProps?: Record<string, any>;
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function LoadingRows(props: LoadingRowsProps): ReactElement {
|
|
21
|
+
const {
|
|
22
|
+
rowCount = 5,
|
|
23
|
+
rowProps,
|
|
24
|
+
cellProps,
|
|
25
|
+
skeletonProps,
|
|
26
|
+
containerSx,
|
|
27
|
+
slots,
|
|
28
|
+
slotProps,
|
|
29
|
+
} = props;
|
|
30
|
+
|
|
31
|
+
const { table } = useDataTableContext();
|
|
32
|
+
const visibleColumns = table.getVisibleLeafColumns();
|
|
33
|
+
|
|
34
|
+
// Extract slot-specific props with enhanced merging
|
|
35
|
+
const cellSlotProps = extractSlotProps(slotProps, 'cell');
|
|
36
|
+
const rowSlotProps = extractSlotProps(slotProps, 'row');
|
|
37
|
+
|
|
38
|
+
const CellSlot = getSlotComponent(slots, 'cell', TableCell);
|
|
39
|
+
const TableRowSlot = getSlotComponent(slots, 'row', TableRow);
|
|
40
|
+
|
|
41
|
+
// Merge all props for maximum flexibility
|
|
42
|
+
const mergedRowProps = mergeSlotProps(
|
|
43
|
+
{
|
|
44
|
+
sx: containerSx,
|
|
45
|
+
},
|
|
46
|
+
rowSlotProps,
|
|
47
|
+
rowProps || {}
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
{Array.from({ length: rowCount }, (_, rowIndex) => (
|
|
53
|
+
<TableRowSlot
|
|
54
|
+
key={`skeleton-row-${rowIndex}`}
|
|
55
|
+
{...mergedRowProps}
|
|
56
|
+
>
|
|
57
|
+
{visibleColumns.map((column: any, colIndex: number) => {
|
|
58
|
+
const isPinned = column.getIsPinned();
|
|
59
|
+
const pinnedPosition = isPinned ? column.getStart('left') : undefined;
|
|
60
|
+
const pinnedRightPosition = isPinned === 'right' ? column.getAfter('right') : undefined;
|
|
61
|
+
|
|
62
|
+
// Determine skeleton type based on column meta or content
|
|
63
|
+
const columnMeta = column.columnDef?.meta;
|
|
64
|
+
const isDateColumn = columnMeta?.type === 'date';
|
|
65
|
+
const isBooleanColumn = columnMeta?.type === 'boolean';
|
|
66
|
+
const isNumberColumn = columnMeta?.type === 'number';
|
|
67
|
+
const isSelectionColumn = column.id === 'select';
|
|
68
|
+
|
|
69
|
+
const mergedCellProps = mergeSlotProps(
|
|
70
|
+
{
|
|
71
|
+
sx: {
|
|
72
|
+
...getPinnedColumnStyle({
|
|
73
|
+
width: column.getSize() || 'auto',
|
|
74
|
+
isPinned,
|
|
75
|
+
pinnedPosition,
|
|
76
|
+
pinnedRightPosition,
|
|
77
|
+
zIndex: isPinned ? 9 : 1,
|
|
78
|
+
isLastLeftPinnedColumn: isPinned === 'left' && column.getIsLastColumn('left'),
|
|
79
|
+
isFirstRightPinnedColumn: isPinned === 'right' && column.getIsFirstColumn('right'),
|
|
80
|
+
}),
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
cellSlotProps,
|
|
84
|
+
cellProps || {}
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const getSkeletonContent = () => {
|
|
88
|
+
if (isSelectionColumn) {
|
|
89
|
+
return (
|
|
90
|
+
<Skeleton
|
|
91
|
+
variant="rectangular"
|
|
92
|
+
width={20}
|
|
93
|
+
height={20}
|
|
94
|
+
animation="wave"
|
|
95
|
+
{...skeletonProps}
|
|
96
|
+
/>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (isBooleanColumn) {
|
|
101
|
+
return (
|
|
102
|
+
<Skeleton
|
|
103
|
+
variant="circular"
|
|
104
|
+
width={16}
|
|
105
|
+
height={16}
|
|
106
|
+
animation="wave"
|
|
107
|
+
{...skeletonProps}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (isDateColumn) {
|
|
113
|
+
return (
|
|
114
|
+
<Skeleton
|
|
115
|
+
variant="text"
|
|
116
|
+
width="80%"
|
|
117
|
+
height={20}
|
|
118
|
+
animation="wave"
|
|
119
|
+
{...skeletonProps}
|
|
120
|
+
/>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (isNumberColumn) {
|
|
125
|
+
return (
|
|
126
|
+
<Skeleton
|
|
127
|
+
variant="text"
|
|
128
|
+
width="60%"
|
|
129
|
+
height={20}
|
|
130
|
+
animation="wave"
|
|
131
|
+
{...skeletonProps}
|
|
132
|
+
/>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<Skeleton
|
|
138
|
+
variant="text"
|
|
139
|
+
width={`${Math.random() * 40 + 60}%`}
|
|
140
|
+
height={20}
|
|
141
|
+
animation="wave"
|
|
142
|
+
{...skeletonProps}
|
|
143
|
+
/>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<CellSlot
|
|
149
|
+
key={`skeleton-${column.id || colIndex}-${rowIndex}`}
|
|
150
|
+
{...mergedCellProps}
|
|
151
|
+
>
|
|
152
|
+
{getSkeletonContent()}
|
|
153
|
+
</CellSlot>
|
|
154
|
+
);
|
|
155
|
+
})}
|
|
156
|
+
</TableRowSlot>
|
|
157
|
+
))}
|
|
158
|
+
</>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Box,
|
|
3
|
+
Toolbar,
|
|
4
|
+
Typography,
|
|
5
|
+
Chip,
|
|
6
|
+
Fade,
|
|
7
|
+
alpha,
|
|
8
|
+
Theme,
|
|
9
|
+
ToolbarProps,
|
|
10
|
+
SxProps,
|
|
11
|
+
} from '@mui/material';
|
|
12
|
+
import { ReactNode, useMemo, ReactElement } from 'react';
|
|
13
|
+
|
|
14
|
+
import { useDataTableContext } from '../../contexts/data-table-context';
|
|
15
|
+
import { getSlotComponent, mergeSlotProps, extractSlotProps } from '../../utils/slot-helpers';
|
|
16
|
+
import { SelectionState } from '../../features';
|
|
17
|
+
|
|
18
|
+
export interface BulkActionsToolbarProps extends ToolbarProps {
|
|
19
|
+
selectionState: SelectionState;
|
|
20
|
+
selectedRowCount: number;
|
|
21
|
+
bulkActions?: (selectionState: SelectionState) => ReactNode;
|
|
22
|
+
// Enhanced customization props
|
|
23
|
+
chipProps?: any;
|
|
24
|
+
containerSx?: SxProps;
|
|
25
|
+
leftSectionSx?: SxProps;
|
|
26
|
+
rightSectionSx?: SxProps;
|
|
27
|
+
fadeProps?: any;
|
|
28
|
+
[key: string]: any;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function BulkActionsToolbar(props: BulkActionsToolbarProps): ReactElement {
|
|
32
|
+
const {
|
|
33
|
+
selectionState,
|
|
34
|
+
selectedRowCount,
|
|
35
|
+
bulkActions,
|
|
36
|
+
chipProps,
|
|
37
|
+
containerSx,
|
|
38
|
+
leftSectionSx,
|
|
39
|
+
rightSectionSx,
|
|
40
|
+
fadeProps,
|
|
41
|
+
sx,
|
|
42
|
+
...otherProps
|
|
43
|
+
} = props;
|
|
44
|
+
|
|
45
|
+
const { slots, slotProps } = useDataTableContext();
|
|
46
|
+
|
|
47
|
+
// Extract slot-specific props with enhanced merging
|
|
48
|
+
const toolbarSlotProps = extractSlotProps(slotProps, 'bulkActionsToolbar');
|
|
49
|
+
const ToolbarSlot = getSlotComponent(slots, 'bulkActionsToolbar', Toolbar);
|
|
50
|
+
|
|
51
|
+
// Memoize the bulk actions rendering to prevent infinite re-renders
|
|
52
|
+
const renderedBulkActions = useMemo(() => {
|
|
53
|
+
if (!bulkActions) return null;
|
|
54
|
+
return bulkActions(selectionState) as any;
|
|
55
|
+
}, [bulkActions, selectionState]);
|
|
56
|
+
|
|
57
|
+
// Merge all props for maximum flexibility
|
|
58
|
+
const mergedToolbarProps = mergeSlotProps(
|
|
59
|
+
{
|
|
60
|
+
sx: {
|
|
61
|
+
pl: { sm: 2 },
|
|
62
|
+
pr: { xs: 1, sm: 1 },
|
|
63
|
+
bgcolor: (theme: Theme) => alpha(theme.palette.primary.main, 0.05),
|
|
64
|
+
mb: 1,
|
|
65
|
+
position: 'relative',
|
|
66
|
+
zIndex: 1,
|
|
67
|
+
...sx,
|
|
68
|
+
...containerSx,
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
toolbarSlotProps,
|
|
72
|
+
otherProps
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const mergedChipProps = mergeSlotProps(
|
|
76
|
+
{
|
|
77
|
+
label: `${selectedRowCount} selected`,
|
|
78
|
+
size: 'small',
|
|
79
|
+
color: 'primary',
|
|
80
|
+
variant: 'outlined',
|
|
81
|
+
},
|
|
82
|
+
chipProps || {}
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<Fade
|
|
87
|
+
in={selectedRowCount > 0}
|
|
88
|
+
{...fadeProps}
|
|
89
|
+
>
|
|
90
|
+
<ToolbarSlot
|
|
91
|
+
{...mergedToolbarProps}
|
|
92
|
+
>
|
|
93
|
+
{/* Left section - Selection info */}
|
|
94
|
+
<Box
|
|
95
|
+
sx={{
|
|
96
|
+
flex: '1 1 100%',
|
|
97
|
+
...leftSectionSx,
|
|
98
|
+
}}
|
|
99
|
+
>
|
|
100
|
+
<Typography
|
|
101
|
+
color="inherit"
|
|
102
|
+
variant="subtitle1"
|
|
103
|
+
component="div"
|
|
104
|
+
>
|
|
105
|
+
<Chip
|
|
106
|
+
{...mergedChipProps}
|
|
107
|
+
/>
|
|
108
|
+
</Typography>
|
|
109
|
+
</Box>
|
|
110
|
+
|
|
111
|
+
{/* Right section - Actions */}
|
|
112
|
+
<Box
|
|
113
|
+
sx={{
|
|
114
|
+
display: 'flex',
|
|
115
|
+
alignItems: 'center',
|
|
116
|
+
gap: 1,
|
|
117
|
+
...rightSectionSx,
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
{renderedBulkActions}
|
|
121
|
+
</Box>
|
|
122
|
+
</ToolbarSlot>
|
|
123
|
+
</Fade>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
@@ -0,0 +1,374 @@
|
|
|
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
|
+
IconButtonProps,
|
|
15
|
+
SxProps,
|
|
16
|
+
} from '@mui/material';
|
|
17
|
+
import React, { useMemo, useCallback, useEffect, ReactElement } from 'react';
|
|
18
|
+
|
|
19
|
+
import { MenuDropdown } from '../droupdown/menu-dropdown';
|
|
20
|
+
import { useDataTableContext } from '../../contexts/data-table-context';
|
|
21
|
+
import {
|
|
22
|
+
AddIcon,
|
|
23
|
+
DeleteIcon,
|
|
24
|
+
} from '../../icons';
|
|
25
|
+
import { getColumnType, isColumnFilterable } from '../../utils/column-helpers';
|
|
26
|
+
import { getSlotComponent, mergeSlotProps, extractSlotProps } from '../../utils/slot-helpers';
|
|
27
|
+
import { FILTER_OPERATORS } from '../filters';
|
|
28
|
+
import { FilterValueInput } from '../filters/filter-value-input';
|
|
29
|
+
import { ColumnFilterRule } from '../../features';
|
|
30
|
+
|
|
31
|
+
export interface ColumnFilterControlProps {
|
|
32
|
+
// Allow full customization of any prop
|
|
33
|
+
title?: string;
|
|
34
|
+
titleSx?: SxProps;
|
|
35
|
+
menuSx?: SxProps;
|
|
36
|
+
iconButtonProps?: IconButtonProps;
|
|
37
|
+
badgeProps?: any;
|
|
38
|
+
clearButtonProps?: any;
|
|
39
|
+
applyButtonProps?: any;
|
|
40
|
+
addButtonProps?: any;
|
|
41
|
+
logicSelectProps?: any;
|
|
42
|
+
[key: string]: any;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function ColumnFilterControl(props: ColumnFilterControlProps = {}): ReactElement {
|
|
46
|
+
const { table, slots, slotProps } = useDataTableContext();
|
|
47
|
+
|
|
48
|
+
// Extract slot-specific props with enhanced merging
|
|
49
|
+
const iconSlotProps = extractSlotProps(slotProps, 'filterIcon');
|
|
50
|
+
|
|
51
|
+
const FilterIconSlot = getSlotComponent(slots, 'filterIcon', FilterList);
|
|
52
|
+
|
|
53
|
+
// Use the custom feature state from the table - now using pending filters for UI
|
|
54
|
+
const filterState = table?.getColumnFilterState?.() || {
|
|
55
|
+
filters: [],
|
|
56
|
+
logic: 'AND',
|
|
57
|
+
pendingFilters: [],
|
|
58
|
+
pendingLogic: 'AND'
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Use pending filters for the UI (draft state)
|
|
62
|
+
const filters = filterState.pendingFilters;
|
|
63
|
+
const filterLogic = filterState.pendingLogic;
|
|
64
|
+
|
|
65
|
+
// Active filters are the actual applied filters
|
|
66
|
+
const activeFiltersCount = table?.getActiveColumnFilters?.()?.length || 0;
|
|
67
|
+
|
|
68
|
+
const filterableColumns = useMemo(() => {
|
|
69
|
+
return table?.getAllLeafColumns()
|
|
70
|
+
.filter(column => isColumnFilterable(column));
|
|
71
|
+
}, [table]);
|
|
72
|
+
|
|
73
|
+
const addFilter = useCallback((columnId?: string, operator?: string) => {
|
|
74
|
+
// If no column specified, use empty (user will select)
|
|
75
|
+
// If column specified, get its appropriate default operator
|
|
76
|
+
let defaultOperator = operator || '';
|
|
77
|
+
|
|
78
|
+
if (columnId && !operator) {
|
|
79
|
+
const column = filterableColumns?.find(col => col.id === columnId);
|
|
80
|
+
const columnType = getColumnType(column as any);
|
|
81
|
+
const operators = FILTER_OPERATORS[columnType as keyof typeof FILTER_OPERATORS] || FILTER_OPERATORS.text;
|
|
82
|
+
defaultOperator = operators[0]?.value || 'contains';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
table?.addPendingColumnFilter?.(columnId || '', defaultOperator, '');
|
|
86
|
+
}, [table, filterableColumns]);
|
|
87
|
+
|
|
88
|
+
const handleAddFilter = useCallback(() => {
|
|
89
|
+
addFilter();
|
|
90
|
+
}, [addFilter]);
|
|
91
|
+
|
|
92
|
+
const updateFilter = useCallback((filterId: string, updates: Partial<ColumnFilterRule>) => {
|
|
93
|
+
table?.updatePendingColumnFilter?.(filterId, updates);
|
|
94
|
+
}, [table]);
|
|
95
|
+
|
|
96
|
+
const removeFilter = useCallback((filterId: string) => {
|
|
97
|
+
table?.removePendingColumnFilter?.(filterId);
|
|
98
|
+
}, [table]);
|
|
99
|
+
|
|
100
|
+
const clearAllFilters = useCallback((closeDialog?: () => void) => {
|
|
101
|
+
// Clear all pending filters
|
|
102
|
+
table?.clearAllPendingColumnFilters?.();
|
|
103
|
+
// Immediately apply the clear (which will clear active filters too)
|
|
104
|
+
setTimeout(() => {
|
|
105
|
+
table?.applyPendingColumnFilters?.();
|
|
106
|
+
// Close dialog if callback provided
|
|
107
|
+
if (closeDialog) {
|
|
108
|
+
closeDialog();
|
|
109
|
+
}
|
|
110
|
+
}, 0);
|
|
111
|
+
}, [table]);
|
|
112
|
+
|
|
113
|
+
// Handle filter logic change (AND/OR)
|
|
114
|
+
const handleLogicChange = useCallback((newLogic: 'AND' | 'OR') => {
|
|
115
|
+
table?.setPendingFilterLogic?.(newLogic);
|
|
116
|
+
}, [table]);
|
|
117
|
+
|
|
118
|
+
// Apply all pending filters
|
|
119
|
+
const applyFilters = useCallback(() => {
|
|
120
|
+
table?.applyPendingColumnFilters?.();
|
|
121
|
+
}, [table]);
|
|
122
|
+
|
|
123
|
+
// Handle apply button click
|
|
124
|
+
const handleApplyFilters = useCallback((closeDialog: () => void) => {
|
|
125
|
+
applyFilters();
|
|
126
|
+
closeDialog();
|
|
127
|
+
}, [applyFilters]);
|
|
128
|
+
|
|
129
|
+
const getOperatorsForColumn = useCallback((columnId: string) => {
|
|
130
|
+
const column = filterableColumns?.find(col => col.id === columnId);
|
|
131
|
+
const type = getColumnType(column as any);
|
|
132
|
+
return FILTER_OPERATORS[type as keyof typeof FILTER_OPERATORS] || FILTER_OPERATORS.text;
|
|
133
|
+
}, [filterableColumns]);
|
|
134
|
+
|
|
135
|
+
// Handle column selection change
|
|
136
|
+
const handleColumnChange = useCallback((filterId: string, newColumnId: string, currentFilter: ColumnFilterRule) => {
|
|
137
|
+
const newColumn = filterableColumns?.find(col => col.id === newColumnId);
|
|
138
|
+
const columnType = getColumnType(newColumn as any);
|
|
139
|
+
const operators = FILTER_OPERATORS[columnType as keyof typeof FILTER_OPERATORS] || FILTER_OPERATORS.text;
|
|
140
|
+
|
|
141
|
+
// Only reset operator if current operator is not valid for new column type
|
|
142
|
+
const currentOperatorValid = operators.some(op => op.value === currentFilter.operator);
|
|
143
|
+
const newOperator = currentOperatorValid ? currentFilter.operator : operators[0]?.value || '';
|
|
144
|
+
|
|
145
|
+
updateFilter(filterId, {
|
|
146
|
+
columnId: newColumnId,
|
|
147
|
+
operator: newOperator,
|
|
148
|
+
// Keep the current value unless operator is empty/notEmpty
|
|
149
|
+
value: ['isEmpty', 'isNotEmpty'].includes(newOperator) ? '' : currentFilter.value,
|
|
150
|
+
});
|
|
151
|
+
}, [filterableColumns, updateFilter]);
|
|
152
|
+
|
|
153
|
+
// Handle operator selection change
|
|
154
|
+
const handleOperatorChange = useCallback((filterId: string, newOperator: string, currentFilter: ColumnFilterRule) => {
|
|
155
|
+
updateFilter(filterId, {
|
|
156
|
+
operator: newOperator,
|
|
157
|
+
// Only reset value if operator is empty/notEmpty, otherwise preserve it
|
|
158
|
+
value: ['isEmpty', 'isNotEmpty'].includes(newOperator) ? '' : currentFilter.value,
|
|
159
|
+
});
|
|
160
|
+
}, [updateFilter]);
|
|
161
|
+
|
|
162
|
+
// Handle filter value change
|
|
163
|
+
const handleFilterValueChange = useCallback((filterId: string, value: any) => {
|
|
164
|
+
updateFilter(filterId, { value });
|
|
165
|
+
}, [updateFilter]);
|
|
166
|
+
|
|
167
|
+
// Handle filter removal
|
|
168
|
+
const handleRemoveFilter = useCallback((filterId: string) => {
|
|
169
|
+
removeFilter(filterId);
|
|
170
|
+
}, [removeFilter]);
|
|
171
|
+
|
|
172
|
+
// Count pending filters that are ready to apply (have column, operator, and value OR are empty/notEmpty operators)
|
|
173
|
+
const pendingFiltersCount = filters.filter(f => {
|
|
174
|
+
if (!f.columnId || !f.operator) return false;
|
|
175
|
+
// For empty/notEmpty operators, no value is needed
|
|
176
|
+
if (['isEmpty', 'isNotEmpty'].includes(f.operator)) return true;
|
|
177
|
+
// For other operators, value is required
|
|
178
|
+
return f.value && f.value.toString().trim() !== '';
|
|
179
|
+
}).length;
|
|
180
|
+
|
|
181
|
+
// Check if we need to show "Clear Applied Filters" button
|
|
182
|
+
const hasAppliedFilters = activeFiltersCount > 0;
|
|
183
|
+
|
|
184
|
+
// Determine if there are pending changes that can be applied
|
|
185
|
+
const hasPendingChanges = pendingFiltersCount > 0 || (filters.length === 0 && hasAppliedFilters);
|
|
186
|
+
|
|
187
|
+
// Auto-add default filter when opening if no filters exist AND no applied filters
|
|
188
|
+
useEffect(() => {
|
|
189
|
+
if (filters.length === 0 && filterableColumns && filterableColumns?.length > 0 && activeFiltersCount === 0) {
|
|
190
|
+
const firstColumn = filterableColumns[0];
|
|
191
|
+
const columnType = getColumnType(firstColumn as any);
|
|
192
|
+
const operators = FILTER_OPERATORS[columnType as keyof typeof FILTER_OPERATORS] || FILTER_OPERATORS.text;
|
|
193
|
+
const defaultOperator = operators[0]?.value || 'contains';
|
|
194
|
+
// Add default filter with first column and its first operator
|
|
195
|
+
addFilter(firstColumn?.id, defaultOperator);
|
|
196
|
+
}
|
|
197
|
+
}, [filters.length, filterableColumns, addFilter, activeFiltersCount]);
|
|
198
|
+
|
|
199
|
+
// Merge all props for maximum flexibility
|
|
200
|
+
const mergedProps = mergeSlotProps(
|
|
201
|
+
{
|
|
202
|
+
// Default props
|
|
203
|
+
size: 'small',
|
|
204
|
+
sx: { flexShrink: 0 },
|
|
205
|
+
},
|
|
206
|
+
slotProps?.columnFilterControl || {},
|
|
207
|
+
props
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
return (
|
|
211
|
+
<MenuDropdown
|
|
212
|
+
anchor={(
|
|
213
|
+
<Badge
|
|
214
|
+
badgeContent={activeFiltersCount > 0 ? activeFiltersCount : 0}
|
|
215
|
+
color="primary"
|
|
216
|
+
invisible={activeFiltersCount === 0}
|
|
217
|
+
{...mergedProps.badgeProps}
|
|
218
|
+
>
|
|
219
|
+
<IconButton
|
|
220
|
+
{...mergedProps}
|
|
221
|
+
>
|
|
222
|
+
<FilterIconSlot
|
|
223
|
+
{...iconSlotProps}
|
|
224
|
+
/>
|
|
225
|
+
</IconButton>
|
|
226
|
+
</Badge>
|
|
227
|
+
)}
|
|
228
|
+
>
|
|
229
|
+
{({ handleClose }: { handleClose: () => void }) => (
|
|
230
|
+
<Box
|
|
231
|
+
sx={{
|
|
232
|
+
p: 2,
|
|
233
|
+
minWidth: 400,
|
|
234
|
+
maxWidth: 600,
|
|
235
|
+
...mergedProps.menuSx,
|
|
236
|
+
}}
|
|
237
|
+
>
|
|
238
|
+
<Typography
|
|
239
|
+
variant="subtitle2"
|
|
240
|
+
sx={{
|
|
241
|
+
mb: 1,
|
|
242
|
+
...mergedProps.titleSx,
|
|
243
|
+
}}
|
|
244
|
+
>
|
|
245
|
+
{mergedProps.title || 'Column Filters'}
|
|
246
|
+
</Typography>
|
|
247
|
+
<Divider sx={{ mb: 2 }} />
|
|
248
|
+
|
|
249
|
+
{/* Filter Logic Selection */}
|
|
250
|
+
{filters.length > 1 && (
|
|
251
|
+
<Box sx={{ mb: 2 }}>
|
|
252
|
+
<FormControl size="small" sx={{ minWidth: 120 }}>
|
|
253
|
+
<InputLabel>Logic</InputLabel>
|
|
254
|
+
<Select
|
|
255
|
+
value={filterLogic}
|
|
256
|
+
label="Logic"
|
|
257
|
+
onChange={(e) => handleLogicChange(e.target.value as 'AND' | 'OR')}
|
|
258
|
+
{...mergedProps.logicSelectProps}
|
|
259
|
+
>
|
|
260
|
+
<MenuItem value="AND">AND</MenuItem>
|
|
261
|
+
<MenuItem value="OR">OR</MenuItem>
|
|
262
|
+
</Select>
|
|
263
|
+
</FormControl>
|
|
264
|
+
</Box>
|
|
265
|
+
)}
|
|
266
|
+
|
|
267
|
+
{/* Filter Rules */}
|
|
268
|
+
<Stack spacing={2} sx={{ mb: 2 }}>
|
|
269
|
+
{filters.map((filter) => {
|
|
270
|
+
const selectedColumn = filterableColumns?.find(col => col.id === filter.columnId);
|
|
271
|
+
const operators = filter.columnId ? getOperatorsForColumn(filter.columnId) : [];
|
|
272
|
+
const needsValue = !['isEmpty', 'isNotEmpty'].includes(filter.operator);
|
|
273
|
+
|
|
274
|
+
return (
|
|
275
|
+
<Stack key={filter.id} direction="row" spacing={1} alignItems="center">
|
|
276
|
+
{/* Column Selection */}
|
|
277
|
+
<FormControl size="small" sx={{ minWidth: 120 }}>
|
|
278
|
+
<InputLabel>Column</InputLabel>
|
|
279
|
+
<Select
|
|
280
|
+
value={filter.columnId || ''}
|
|
281
|
+
label="Column"
|
|
282
|
+
onChange={(e) => handleColumnChange(filter.id, e.target.value, filter)}
|
|
283
|
+
>
|
|
284
|
+
{filterableColumns?.map(column => (
|
|
285
|
+
<MenuItem key={column.id} value={column.id}>
|
|
286
|
+
{typeof column.columnDef.header === 'string'
|
|
287
|
+
? column.columnDef.header
|
|
288
|
+
: column.id}
|
|
289
|
+
</MenuItem>
|
|
290
|
+
))}
|
|
291
|
+
</Select>
|
|
292
|
+
</FormControl>
|
|
293
|
+
|
|
294
|
+
{/* Operator Selection */}
|
|
295
|
+
<FormControl size="small" sx={{ minWidth: 120 }}>
|
|
296
|
+
<InputLabel>Operator</InputLabel>
|
|
297
|
+
<Select
|
|
298
|
+
value={filter.operator || ''}
|
|
299
|
+
label="Operator"
|
|
300
|
+
onChange={(e) => handleOperatorChange(filter.id, e.target.value, filter)}
|
|
301
|
+
disabled={!filter.columnId}
|
|
302
|
+
>
|
|
303
|
+
{operators.map(op => (
|
|
304
|
+
<MenuItem key={op.value} value={op.value}>
|
|
305
|
+
{op.label}
|
|
306
|
+
</MenuItem>
|
|
307
|
+
))}
|
|
308
|
+
</Select>
|
|
309
|
+
</FormControl>
|
|
310
|
+
|
|
311
|
+
{/* Value Input */}
|
|
312
|
+
{needsValue && selectedColumn && (
|
|
313
|
+
<FilterValueInput
|
|
314
|
+
filter={filter}
|
|
315
|
+
column={selectedColumn}
|
|
316
|
+
onValueChange={(value) => handleFilterValueChange(filter.id, value)}
|
|
317
|
+
/>
|
|
318
|
+
)}
|
|
319
|
+
|
|
320
|
+
{/* Remove Filter Button */}
|
|
321
|
+
<IconButton
|
|
322
|
+
size="small"
|
|
323
|
+
onClick={() => handleRemoveFilter(filter.id)}
|
|
324
|
+
color="error"
|
|
325
|
+
{...mergedProps.deleteButtonProps}
|
|
326
|
+
>
|
|
327
|
+
<DeleteIcon fontSize="small" />
|
|
328
|
+
</IconButton>
|
|
329
|
+
</Stack>
|
|
330
|
+
);
|
|
331
|
+
})}
|
|
332
|
+
</Stack>
|
|
333
|
+
|
|
334
|
+
{/* Add Filter Button */}
|
|
335
|
+
<Button
|
|
336
|
+
variant="outlined"
|
|
337
|
+
size="small"
|
|
338
|
+
startIcon={<AddIcon />}
|
|
339
|
+
onClick={handleAddFilter}
|
|
340
|
+
disabled={!filterableColumns || filterableColumns.length === 0}
|
|
341
|
+
sx={{ mb: 2 }}
|
|
342
|
+
{...mergedProps.addButtonProps}
|
|
343
|
+
>
|
|
344
|
+
Add Filter
|
|
345
|
+
</Button>
|
|
346
|
+
|
|
347
|
+
{/* Action Buttons */}
|
|
348
|
+
<Stack direction="row" spacing={1} justifyContent="flex-end">
|
|
349
|
+
{hasAppliedFilters && (
|
|
350
|
+
<Button
|
|
351
|
+
variant="outlined"
|
|
352
|
+
size="small"
|
|
353
|
+
onClick={() => clearAllFilters(handleClose)}
|
|
354
|
+
color="error"
|
|
355
|
+
{...mergedProps.clearButtonProps}
|
|
356
|
+
>
|
|
357
|
+
Clear All
|
|
358
|
+
</Button>
|
|
359
|
+
)}
|
|
360
|
+
<Button
|
|
361
|
+
variant="contained"
|
|
362
|
+
size="small"
|
|
363
|
+
onClick={() => handleApplyFilters(handleClose)}
|
|
364
|
+
disabled={!hasPendingChanges}
|
|
365
|
+
{...mergedProps.applyButtonProps}
|
|
366
|
+
>
|
|
367
|
+
Apply
|
|
368
|
+
</Button>
|
|
369
|
+
</Stack>
|
|
370
|
+
</Box>
|
|
371
|
+
)}
|
|
372
|
+
</MenuDropdown>
|
|
373
|
+
);
|
|
374
|
+
}
|