@visns-studio/visns-components 5.8.20 → 5.9.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/README.md +149 -0
- package/package.json +1 -1
- package/src/components/crm/DataGrid.jsx +1177 -56
- package/src/components/crm/Field.jsx +2 -2
- package/src/components/crm/MultiSelect.jsx +33 -13
- package/src/components/crm/styles/DataGrid.module.scss +66 -6
- package/src/components/crm/styles/MultiSelect.module.scss +31 -9
- package/src/components/crm/styles/global-datagrid.css +240 -10
- package/src/examples/MultiSelectStylingTest.jsx +76 -0
|
@@ -43,6 +43,7 @@ import { toast } from 'react-toastify';
|
|
|
43
43
|
import imageCompression from 'browser-image-compression';
|
|
44
44
|
import Vapor from 'laravel-vapor';
|
|
45
45
|
import Lightbox from 'yet-another-react-lightbox';
|
|
46
|
+
import { Tooltip } from 'react-tooltip';
|
|
46
47
|
import fetchUtil from '../../utils/fetchUtil';
|
|
47
48
|
import { confirmDialog } from '../utils/ConfirmDialog';
|
|
48
49
|
import {
|
|
@@ -85,6 +86,101 @@ import Download from './Download';
|
|
|
85
86
|
import Form from './Form';
|
|
86
87
|
import _ from 'lodash';
|
|
87
88
|
|
|
89
|
+
// CSS styles to ensure consistent group header heights with compact design and click indicators
|
|
90
|
+
const groupHeaderStyles = `
|
|
91
|
+
.datagrid-fixed-group-headers .group-header-fixed-height {
|
|
92
|
+
height: 34px !important;
|
|
93
|
+
min-height: 34px !important;
|
|
94
|
+
max-height: 34px !important;
|
|
95
|
+
box-sizing: border-box !important;
|
|
96
|
+
line-height: 1.1 !important;
|
|
97
|
+
flex-shrink: 0 !important;
|
|
98
|
+
overflow: hidden !important;
|
|
99
|
+
transition: background-color 0.2s ease, box-shadow 0.2s ease !important;
|
|
100
|
+
cursor: pointer !important;
|
|
101
|
+
position: relative !important;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Hover effect for entire group header */
|
|
105
|
+
.datagrid-fixed-group-headers .group-header-fixed-height:hover {
|
|
106
|
+
background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%) !important;
|
|
107
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.15) !important;
|
|
108
|
+
transform: translateY(-1px) !important;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* Click indicator overlay */
|
|
112
|
+
.datagrid-fixed-group-headers .group-header-fixed-height::after {
|
|
113
|
+
content: '' !important;
|
|
114
|
+
position: absolute !important;
|
|
115
|
+
top: 0 !important;
|
|
116
|
+
left: 0 !important;
|
|
117
|
+
right: 0 !important;
|
|
118
|
+
bottom: 0 !important;
|
|
119
|
+
background: rgba(59, 130, 246, 0.05) !important;
|
|
120
|
+
opacity: 0 !important;
|
|
121
|
+
transition: opacity 0.2s ease !important;
|
|
122
|
+
pointer-events: none !important;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.datagrid-fixed-group-headers .group-header-fixed-height:hover::after {
|
|
126
|
+
opacity: 1 !important;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.datagrid-fixed-group-headers .InovuaReactDataGrid__group-row {
|
|
130
|
+
height: 34px !important;
|
|
131
|
+
min-height: 34px !important;
|
|
132
|
+
max-height: 34px !important;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.datagrid-fixed-group-headers .InovuaReactDataGrid__group-row .InovuaReactDataGrid__group-cell {
|
|
136
|
+
height: 34px !important;
|
|
137
|
+
min-height: 34px !important;
|
|
138
|
+
max-height: 34px !important;
|
|
139
|
+
padding: 0 !important;
|
|
140
|
+
overflow: hidden !important;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.datagrid-fixed-group-headers .InovuaReactDataGrid__group-row .InovuaReactDataGrid__group-cell > div {
|
|
144
|
+
height: 34px !important;
|
|
145
|
+
min-height: 34px !important;
|
|
146
|
+
max-height: 34px !important;
|
|
147
|
+
overflow: hidden !important;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* Ensure group headers maintain consistent styling during expand/collapse */
|
|
151
|
+
.datagrid-fixed-group-headers .InovuaReactDataGrid__group-row--collapsed .group-header-fixed-height,
|
|
152
|
+
.datagrid-fixed-group-headers .InovuaReactDataGrid__group-row--expanded .group-header-fixed-height {
|
|
153
|
+
height: 34px !important;
|
|
154
|
+
min-height: 34px !important;
|
|
155
|
+
max-height: 34px !important;
|
|
156
|
+
transition: background-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease !important;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* Force consistent height for all group headers regardless of content */
|
|
160
|
+
.datagrid-fixed-group-headers .InovuaReactDataGrid__group-row[data-group-by] {
|
|
161
|
+
height: 34px !important;
|
|
162
|
+
min-height: 34px !important;
|
|
163
|
+
max-height: 34px !important;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.datagrid-fixed-group-headers .InovuaReactDataGrid__group-row[data-group-by] .InovuaReactDataGrid__group-cell {
|
|
167
|
+
height: 34px !important;
|
|
168
|
+
min-height: 34px !important;
|
|
169
|
+
max-height: 34px !important;
|
|
170
|
+
}
|
|
171
|
+
`;
|
|
172
|
+
|
|
173
|
+
// Inject styles into the document head
|
|
174
|
+
if (typeof document !== 'undefined') {
|
|
175
|
+
const styleId = 'datagrid-group-header-styles';
|
|
176
|
+
if (!document.getElementById(styleId)) {
|
|
177
|
+
const style = document.createElement('style');
|
|
178
|
+
style.id = styleId;
|
|
179
|
+
style.textContent = groupHeaderStyles;
|
|
180
|
+
document.head.appendChild(style);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
88
184
|
const loadData = async (
|
|
89
185
|
{ skip, limit, sortInfo, filterValue },
|
|
90
186
|
search,
|
|
@@ -146,6 +242,123 @@ const loadData = async (
|
|
|
146
242
|
}
|
|
147
243
|
};
|
|
148
244
|
|
|
245
|
+
// Utility function to check if text content is truncated
|
|
246
|
+
const isTextTruncated = (element) => {
|
|
247
|
+
if (!element) return false;
|
|
248
|
+
return (
|
|
249
|
+
element.scrollWidth > element.clientWidth ||
|
|
250
|
+
element.scrollHeight > element.clientHeight
|
|
251
|
+
);
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// Utility function to format cell value for tooltip display
|
|
255
|
+
const formatCellValueForTooltip = (value, columnType) => {
|
|
256
|
+
if (value === null || value === undefined || value === '') {
|
|
257
|
+
return '';
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
switch (columnType) {
|
|
261
|
+
case 'date':
|
|
262
|
+
case 'datetime':
|
|
263
|
+
if (
|
|
264
|
+
moment(value).isValid() &&
|
|
265
|
+
moment(value).format('YYYY-MM-DD') !== '1970-01-01'
|
|
266
|
+
) {
|
|
267
|
+
return moment(value).format('DD-MM-YYYY HH:mm');
|
|
268
|
+
}
|
|
269
|
+
return String(value);
|
|
270
|
+
case 'currency':
|
|
271
|
+
return numeral(value).format('$0,0.00');
|
|
272
|
+
case 'number':
|
|
273
|
+
return numeral(value).format('0,0');
|
|
274
|
+
case 'boolean':
|
|
275
|
+
return value ? 'Yes' : 'No';
|
|
276
|
+
case 'richtext':
|
|
277
|
+
// Strip HTML tags for tooltip
|
|
278
|
+
const tempDiv = document.createElement('div');
|
|
279
|
+
tempDiv.innerHTML = value;
|
|
280
|
+
return tempDiv.textContent || tempDiv.innerText || '';
|
|
281
|
+
default:
|
|
282
|
+
return String(value);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
// Component to wrap cell content with tooltip functionality
|
|
287
|
+
const CellWithTooltip = ({
|
|
288
|
+
children,
|
|
289
|
+
value,
|
|
290
|
+
columnType = 'text',
|
|
291
|
+
className = '',
|
|
292
|
+
}) => {
|
|
293
|
+
const cellRef = useRef(null);
|
|
294
|
+
const [showTooltip, setShowTooltip] = useState(false);
|
|
295
|
+
const [tooltipId] = useState(
|
|
296
|
+
() => `cell-tooltip-${Math.random().toString(36).substr(2, 9)}`
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
useEffect(() => {
|
|
300
|
+
const checkTruncation = () => {
|
|
301
|
+
if (cellRef.current) {
|
|
302
|
+
const isTruncated = isTextTruncated(cellRef.current);
|
|
303
|
+
setShowTooltip(isTruncated);
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
// Check truncation on mount and when content changes
|
|
308
|
+
checkTruncation();
|
|
309
|
+
|
|
310
|
+
// Also check on window resize
|
|
311
|
+
const handleResize = () => checkTruncation();
|
|
312
|
+
window.addEventListener('resize', handleResize);
|
|
313
|
+
|
|
314
|
+
return () => {
|
|
315
|
+
window.removeEventListener('resize', handleResize);
|
|
316
|
+
};
|
|
317
|
+
}, [children, value]);
|
|
318
|
+
|
|
319
|
+
const tooltipContent = formatCellValueForTooltip(value, columnType);
|
|
320
|
+
|
|
321
|
+
// Only show tooltip if content is truncated and we have meaningful content
|
|
322
|
+
const shouldShowTooltip =
|
|
323
|
+
showTooltip && tooltipContent && tooltipContent.trim() !== '';
|
|
324
|
+
|
|
325
|
+
return (
|
|
326
|
+
<div
|
|
327
|
+
ref={cellRef}
|
|
328
|
+
className={className}
|
|
329
|
+
style={{
|
|
330
|
+
overflow: 'hidden',
|
|
331
|
+
textOverflow: 'ellipsis',
|
|
332
|
+
whiteSpace: 'nowrap',
|
|
333
|
+
width: '100%',
|
|
334
|
+
}}
|
|
335
|
+
{...(shouldShowTooltip && {
|
|
336
|
+
'data-tooltip-id': tooltipId,
|
|
337
|
+
'data-tooltip-content': tooltipContent,
|
|
338
|
+
})}
|
|
339
|
+
>
|
|
340
|
+
{children}
|
|
341
|
+
{shouldShowTooltip && (
|
|
342
|
+
<Tooltip
|
|
343
|
+
id={tooltipId}
|
|
344
|
+
style={{
|
|
345
|
+
backgroundColor: 'rgba(0, 0, 0, 0.9)',
|
|
346
|
+
color: 'white',
|
|
347
|
+
borderRadius: '6px',
|
|
348
|
+
padding: '8px 12px',
|
|
349
|
+
fontSize: '13px',
|
|
350
|
+
maxWidth: '300px',
|
|
351
|
+
wordWrap: 'break-word',
|
|
352
|
+
zIndex: 9999,
|
|
353
|
+
}}
|
|
354
|
+
place="top"
|
|
355
|
+
offset={5}
|
|
356
|
+
/>
|
|
357
|
+
)}
|
|
358
|
+
</div>
|
|
359
|
+
);
|
|
360
|
+
};
|
|
361
|
+
|
|
149
362
|
const DataGrid = forwardRef(
|
|
150
363
|
(
|
|
151
364
|
{
|
|
@@ -370,6 +583,75 @@ const DataGrid = forwardRef(
|
|
|
370
583
|
/** Table States */
|
|
371
584
|
const dataRef = useRef(null);
|
|
372
585
|
const [dSearch, setDSearch] = useState('');
|
|
586
|
+
|
|
587
|
+
/** Group expansion state */
|
|
588
|
+
const [collapsedGroups, setCollapsedGroups] = useState({});
|
|
589
|
+
|
|
590
|
+
/** Force re-render trigger for group header consistency */
|
|
591
|
+
const [groupRenderKey, setGroupRenderKey] = useState(0);
|
|
592
|
+
|
|
593
|
+
/** Prevent rapid group selection clicks */
|
|
594
|
+
const groupClickTimeoutRef = useRef(null);
|
|
595
|
+
|
|
596
|
+
// Effect to ensure group headers maintain consistent styling after expand/collapse
|
|
597
|
+
useEffect(() => {
|
|
598
|
+
if (ajaxSetting?.groupBy) {
|
|
599
|
+
// Small delay to allow ReactDataGrid to complete its rendering
|
|
600
|
+
const timer = setTimeout(() => {
|
|
601
|
+
// Force a re-render to ensure consistent styling
|
|
602
|
+
setGroupRenderKey((prev) => prev + 1);
|
|
603
|
+
|
|
604
|
+
// Apply styles to any group headers that might have been missed
|
|
605
|
+
const groupHeaders = document.querySelectorAll(
|
|
606
|
+
'.group-header-fixed-height'
|
|
607
|
+
);
|
|
608
|
+
groupHeaders.forEach((header) => {
|
|
609
|
+
header.style.height = '34px';
|
|
610
|
+
header.style.minHeight = '34px';
|
|
611
|
+
header.style.maxHeight = '34px';
|
|
612
|
+
header.style.boxSizing = 'border-box';
|
|
613
|
+
header.style.lineHeight = '1.1';
|
|
614
|
+
header.style.flexShrink = '0';
|
|
615
|
+
header.style.overflow = 'hidden';
|
|
616
|
+
header.style.cursor = 'pointer';
|
|
617
|
+
header.style.position = 'relative';
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
// Also apply to ReactDataGrid group rows to fix height inconsistency
|
|
621
|
+
const groupRows = document.querySelectorAll(
|
|
622
|
+
'.datagrid-fixed-group-headers .InovuaReactDataGrid__group-row'
|
|
623
|
+
);
|
|
624
|
+
groupRows.forEach((row) => {
|
|
625
|
+
row.style.height = '34px';
|
|
626
|
+
row.style.minHeight = '34px';
|
|
627
|
+
row.style.maxHeight = '34px';
|
|
628
|
+
|
|
629
|
+
// Apply to group cells within the row
|
|
630
|
+
const groupCells = row.querySelectorAll(
|
|
631
|
+
'.InovuaReactDataGrid__group-cell'
|
|
632
|
+
);
|
|
633
|
+
groupCells.forEach((cell) => {
|
|
634
|
+
cell.style.height = '34px';
|
|
635
|
+
cell.style.minHeight = '34px';
|
|
636
|
+
cell.style.maxHeight = '34px';
|
|
637
|
+
cell.style.padding = '0';
|
|
638
|
+
cell.style.overflow = 'hidden';
|
|
639
|
+
|
|
640
|
+
// Apply to div elements within group cells
|
|
641
|
+
const divs = cell.querySelectorAll('div');
|
|
642
|
+
divs.forEach((div) => {
|
|
643
|
+
div.style.height = '34px';
|
|
644
|
+
div.style.minHeight = '34px';
|
|
645
|
+
div.style.maxHeight = '34px';
|
|
646
|
+
div.style.overflow = 'hidden';
|
|
647
|
+
});
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
}, 50);
|
|
651
|
+
|
|
652
|
+
return () => clearTimeout(timer);
|
|
653
|
+
}
|
|
654
|
+
}, [collapsedGroups, ajaxSetting?.groupBy]);
|
|
373
655
|
const dataSource = useCallback(
|
|
374
656
|
(params) => {
|
|
375
657
|
const sqlResult = loadData(params, dSearch, ajaxSetting);
|
|
@@ -378,6 +660,18 @@ const DataGrid = forwardRef(
|
|
|
378
660
|
}
|
|
379
661
|
|
|
380
662
|
sqlResult.then((res) => {
|
|
663
|
+
// Sort data by grouping field if grouping is enabled
|
|
664
|
+
if (ajaxSetting?.groupBy?.length > 0) {
|
|
665
|
+
const groupField = ajaxSetting.groupBy[0]; // groupBy is array of strings
|
|
666
|
+
res.data.sort((a, b) => {
|
|
667
|
+
const aValue = a[groupField] || '';
|
|
668
|
+
const bValue = b[groupField] || '';
|
|
669
|
+
return aValue
|
|
670
|
+
.toString()
|
|
671
|
+
.localeCompare(bValue.toString());
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
|
|
381
675
|
if (setTotal) {
|
|
382
676
|
setTotal(res.count);
|
|
383
677
|
}
|
|
@@ -390,7 +684,7 @@ const DataGrid = forwardRef(
|
|
|
390
684
|
|
|
391
685
|
return sqlResult;
|
|
392
686
|
},
|
|
393
|
-
[ajaxSetting, dSearch]
|
|
687
|
+
[ajaxSetting, dSearch, collapsedGroups]
|
|
394
688
|
);
|
|
395
689
|
const [filterDataSource, setFilterDataSource] = useState([]);
|
|
396
690
|
const [filterValue, setFilterValue] = useState([]);
|
|
@@ -547,9 +841,31 @@ const DataGrid = forwardRef(
|
|
|
547
841
|
if (param.selected === true) {
|
|
548
842
|
// Select all rows - this happens when header checkbox is clicked to select all
|
|
549
843
|
const s = {};
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
844
|
+
|
|
845
|
+
// Always prefer dataRef.current as it contains the most reliable data
|
|
846
|
+
// especially when grouping is active
|
|
847
|
+
if (dataRef.current && Array.isArray(dataRef.current)) {
|
|
848
|
+
dataRef.current.forEach((obj) => {
|
|
849
|
+
if (
|
|
850
|
+
obj &&
|
|
851
|
+
obj.id !== undefined &&
|
|
852
|
+
obj.id !== null
|
|
853
|
+
) {
|
|
854
|
+
s[obj.id] = obj;
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
} else if (param.data && Array.isArray(param.data)) {
|
|
858
|
+
// Fallback to param.data if dataRef.current is not available
|
|
859
|
+
param.data.forEach((obj) => {
|
|
860
|
+
if (
|
|
861
|
+
obj &&
|
|
862
|
+
obj.id !== undefined &&
|
|
863
|
+
obj.id !== null
|
|
864
|
+
) {
|
|
865
|
+
s[obj.id] = obj;
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
}
|
|
553
869
|
setSelected(s);
|
|
554
870
|
// Update parent component's rowsSelected state
|
|
555
871
|
if (setRowsSelected) {
|
|
@@ -569,17 +885,148 @@ const DataGrid = forwardRef(
|
|
|
569
885
|
} else if (typeof param.selected === 'object') {
|
|
570
886
|
// Individual row selection/deselection - ReactDataGrid sends the complete new selection state
|
|
571
887
|
// ReactDataGrid sends the complete new selection state, not just the changed row
|
|
572
|
-
//
|
|
573
|
-
|
|
888
|
+
// Clean the selection to remove any group objects or invalid entries
|
|
889
|
+
const cleanSelection = {};
|
|
890
|
+
Object.keys(param.selected).forEach((key) => {
|
|
891
|
+
const item = param.selected[key];
|
|
892
|
+
// Only keep items that have valid IDs and are not group objects
|
|
893
|
+
if (
|
|
894
|
+
key !== 'undefined' &&
|
|
895
|
+
key !== 'null' &&
|
|
896
|
+
item &&
|
|
897
|
+
!item.__group &&
|
|
898
|
+
item.id !== undefined
|
|
899
|
+
) {
|
|
900
|
+
cleanSelection[key] = item;
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
setSelected(cleanSelection);
|
|
574
905
|
// Update parent component's rowsSelected state
|
|
575
906
|
if (setRowsSelected) {
|
|
576
|
-
setRowsSelected(
|
|
907
|
+
setRowsSelected(cleanSelection);
|
|
577
908
|
}
|
|
578
909
|
}
|
|
579
910
|
},
|
|
580
911
|
[selected, setRowsSelected]
|
|
581
912
|
);
|
|
582
913
|
|
|
914
|
+
// Group selection functions
|
|
915
|
+
const handleGroupSelectionChange = useCallback(
|
|
916
|
+
(groupValue, isChecked) => {
|
|
917
|
+
if (!dataRef.current || !ajaxSetting?.groupBy) {
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
const groupField = ajaxSetting.groupBy[0];
|
|
922
|
+
const groupRows = dataRef.current.filter(
|
|
923
|
+
(row) => row[groupField] === groupValue
|
|
924
|
+
);
|
|
925
|
+
|
|
926
|
+
// Clean the selected state - remove any invalid entries
|
|
927
|
+
const cleanSelected = {};
|
|
928
|
+
Object.keys(selected).forEach((key) => {
|
|
929
|
+
const item = selected[key];
|
|
930
|
+
// Only keep items that have valid IDs and are not group objects
|
|
931
|
+
if (
|
|
932
|
+
key !== 'undefined' &&
|
|
933
|
+
key !== 'null' &&
|
|
934
|
+
item &&
|
|
935
|
+
!item.__group &&
|
|
936
|
+
item.id !== undefined
|
|
937
|
+
) {
|
|
938
|
+
cleanSelected[key] = item;
|
|
939
|
+
}
|
|
940
|
+
});
|
|
941
|
+
const newSelected = { ...cleanSelected };
|
|
942
|
+
|
|
943
|
+
if (isChecked) {
|
|
944
|
+
// Select all rows in the group
|
|
945
|
+
groupRows.forEach((row) => {
|
|
946
|
+
if (row && row.id !== undefined && row.id !== null) {
|
|
947
|
+
newSelected[row.id] = row;
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
} else {
|
|
951
|
+
// Deselect all rows in the group
|
|
952
|
+
groupRows.forEach((row) => {
|
|
953
|
+
if (row && row.id !== undefined && row.id !== null) {
|
|
954
|
+
delete newSelected[row.id];
|
|
955
|
+
}
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// Update the selection state
|
|
960
|
+
setSelected(newSelected);
|
|
961
|
+
if (setRowsSelected) {
|
|
962
|
+
setRowsSelected(newSelected);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// Force ReactDataGrid to update its selection using the grid API
|
|
966
|
+
setTimeout(() => {
|
|
967
|
+
if (gridRef.current && gridRef.current.setSelected) {
|
|
968
|
+
gridRef.current.setSelected(newSelected);
|
|
969
|
+
} else if (gridRef.current) {
|
|
970
|
+
// Try alternative methods
|
|
971
|
+
if (gridRef.current.updateSelected) {
|
|
972
|
+
gridRef.current.updateSelected(newSelected);
|
|
973
|
+
} else if (gridRef.current.setSelection) {
|
|
974
|
+
gridRef.current.setSelection(newSelected);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
}, 10);
|
|
978
|
+
},
|
|
979
|
+
[selected, setRowsSelected, ajaxSetting]
|
|
980
|
+
);
|
|
981
|
+
|
|
982
|
+
const isGroupSelected = useCallback(
|
|
983
|
+
(groupValue) => {
|
|
984
|
+
if (!dataRef.current || !ajaxSetting?.groupBy) {
|
|
985
|
+
return false;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
// Clean the selected state first
|
|
989
|
+
const cleanSelected = {};
|
|
990
|
+
Object.keys(selected).forEach((key) => {
|
|
991
|
+
const item = selected[key];
|
|
992
|
+
if (
|
|
993
|
+
key !== 'undefined' &&
|
|
994
|
+
key !== 'null' &&
|
|
995
|
+
item &&
|
|
996
|
+
!item.__group &&
|
|
997
|
+
item.id !== undefined
|
|
998
|
+
) {
|
|
999
|
+
cleanSelected[key] = item;
|
|
1000
|
+
}
|
|
1001
|
+
});
|
|
1002
|
+
|
|
1003
|
+
const groupField = ajaxSetting.groupBy[0];
|
|
1004
|
+
const groupRows = dataRef.current.filter(
|
|
1005
|
+
(row) => row[groupField] === groupValue
|
|
1006
|
+
);
|
|
1007
|
+
|
|
1008
|
+
if (groupRows.length === 0) {
|
|
1009
|
+
return false;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
// Filter out rows with invalid IDs and check if all valid rows are selected
|
|
1013
|
+
const validRows = groupRows.filter(
|
|
1014
|
+
(row) => row && row.id !== undefined && row.id !== null
|
|
1015
|
+
);
|
|
1016
|
+
|
|
1017
|
+
if (validRows.length === 0) {
|
|
1018
|
+
return false;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
const allSelected = validRows.every(
|
|
1022
|
+
(row) => cleanSelected[row.id]
|
|
1023
|
+
);
|
|
1024
|
+
|
|
1025
|
+
return allSelected;
|
|
1026
|
+
},
|
|
1027
|
+
[selected, ajaxSetting]
|
|
1028
|
+
);
|
|
1029
|
+
|
|
583
1030
|
const findUpdatedFilter = (filters, currentValues) => {
|
|
584
1031
|
for (const filter of filters) {
|
|
585
1032
|
const matchingCurrentValue = currentValues.find(
|
|
@@ -1213,6 +1660,7 @@ const DataGrid = forwardRef(
|
|
|
1213
1660
|
}
|
|
1214
1661
|
} else {
|
|
1215
1662
|
// For non-checkbox columns, handle normal row clicks
|
|
1663
|
+
// But do NOT trigger checkbox selection
|
|
1216
1664
|
onRowClick(rowProps, event);
|
|
1217
1665
|
|
|
1218
1666
|
// Call the original onClick handler
|
|
@@ -1222,7 +1670,7 @@ const DataGrid = forwardRef(
|
|
|
1222
1670
|
}
|
|
1223
1671
|
};
|
|
1224
1672
|
},
|
|
1225
|
-
[selected, setRowsSelected]
|
|
1673
|
+
[selected, setRowsSelected, onRowClick]
|
|
1226
1674
|
);
|
|
1227
1675
|
|
|
1228
1676
|
const exportTrigger = async () => {
|
|
@@ -1538,10 +1986,11 @@ const DataGrid = forwardRef(
|
|
|
1538
1986
|
'var(--light-bg-color, #f5f5f5)',
|
|
1539
1987
|
borderRadius: '4px',
|
|
1540
1988
|
padding: '4px',
|
|
1541
|
-
width: '
|
|
1542
|
-
height: '
|
|
1989
|
+
width: '28px',
|
|
1990
|
+
height: '28px',
|
|
1543
1991
|
boxShadow: '0 1px 2px rgba(0,0,0,0.05)',
|
|
1544
1992
|
margin: '0 1px',
|
|
1993
|
+
cursor: 'pointer',
|
|
1545
1994
|
}}
|
|
1546
1995
|
>
|
|
1547
1996
|
<img
|
|
@@ -1550,8 +1999,8 @@ const DataGrid = forwardRef(
|
|
|
1550
1999
|
data-tooltip-id="system-tooltip"
|
|
1551
2000
|
data-tooltip-content={tooltipContent}
|
|
1552
2001
|
style={{
|
|
1553
|
-
maxHeight: '
|
|
1554
|
-
maxWidth: '
|
|
2002
|
+
maxHeight: '20px',
|
|
2003
|
+
maxWidth: '20px',
|
|
1555
2004
|
objectFit: 'contain',
|
|
1556
2005
|
}}
|
|
1557
2006
|
/>
|
|
@@ -1586,10 +2035,11 @@ const DataGrid = forwardRef(
|
|
|
1586
2035
|
'var(--light-bg-color, #f5f5f5)',
|
|
1587
2036
|
borderRadius: '4px',
|
|
1588
2037
|
padding: '4px',
|
|
1589
|
-
width: '
|
|
1590
|
-
height: '
|
|
2038
|
+
width: '28px',
|
|
2039
|
+
height: '28px',
|
|
1591
2040
|
boxShadow: '0 1px 2px rgba(0,0,0,0.05)',
|
|
1592
2041
|
margin: '0 1px',
|
|
2042
|
+
cursor: 'pointer',
|
|
1593
2043
|
}}
|
|
1594
2044
|
>
|
|
1595
2045
|
<IconComponent
|
|
@@ -1670,6 +2120,82 @@ const DataGrid = forwardRef(
|
|
|
1670
2120
|
}
|
|
1671
2121
|
}, [selected]);
|
|
1672
2122
|
|
|
2123
|
+
// Add styling to grouped column header with enhanced debugging
|
|
2124
|
+
useEffect(() => {
|
|
2125
|
+
if (ajaxSetting?.groupBy && ajaxSetting.groupBy.length > 0) {
|
|
2126
|
+
const groupedColumnName = ajaxSetting.groupBy[0];
|
|
2127
|
+
|
|
2128
|
+
// Multiple attempts to find and style the grouped column header
|
|
2129
|
+
const applyGroupedStyling = () => {
|
|
2130
|
+
const headerCells = document.querySelectorAll(
|
|
2131
|
+
'.InovuaReactDataGrid__header-cell'
|
|
2132
|
+
);
|
|
2133
|
+
|
|
2134
|
+
headerCells.forEach((cell) => {
|
|
2135
|
+
const cellContent = cell.textContent?.trim();
|
|
2136
|
+
const dataColumnId =
|
|
2137
|
+
cell.getAttribute('data-column-id');
|
|
2138
|
+
|
|
2139
|
+
// Find the column that matches the grouped field
|
|
2140
|
+
const matchingColumn = gridColumns.find(
|
|
2141
|
+
(col) =>
|
|
2142
|
+
col.name === groupedColumnName ||
|
|
2143
|
+
col.header === cellContent ||
|
|
2144
|
+
col.id === groupedColumnName ||
|
|
2145
|
+
dataColumnId === groupedColumnName
|
|
2146
|
+
);
|
|
2147
|
+
|
|
2148
|
+
if (
|
|
2149
|
+
matchingColumn &&
|
|
2150
|
+
(matchingColumn.name === groupedColumnName ||
|
|
2151
|
+
matchingColumn.id === groupedColumnName ||
|
|
2152
|
+
dataColumnId === groupedColumnName)
|
|
2153
|
+
) {
|
|
2154
|
+
cell.classList.add(
|
|
2155
|
+
'InovuaReactDataGrid__header-cell--grouped'
|
|
2156
|
+
);
|
|
2157
|
+
// Force inline styles as backup
|
|
2158
|
+
cell.style.background =
|
|
2159
|
+
'linear-gradient(135deg, var(--primary-color, #3b82f6) 0%, var(--secondary-color, #2563eb) 100%)';
|
|
2160
|
+
cell.style.color = 'white';
|
|
2161
|
+
cell.style.fontWeight = '800';
|
|
2162
|
+
cell.style.textTransform = 'uppercase';
|
|
2163
|
+
cell.style.letterSpacing = '0.1em';
|
|
2164
|
+
cell.style.borderBottom =
|
|
2165
|
+
'4px solid var(--secondary-color, #2563eb)';
|
|
2166
|
+
}
|
|
2167
|
+
});
|
|
2168
|
+
|
|
2169
|
+
// Also apply class to the main DataGrid container for debugging
|
|
2170
|
+
const dataGrids = document.querySelectorAll(
|
|
2171
|
+
'.InovuaReactDataGrid'
|
|
2172
|
+
);
|
|
2173
|
+
dataGrids.forEach((grid) => {
|
|
2174
|
+
if (
|
|
2175
|
+
grid.classList.contains(
|
|
2176
|
+
'InovuaReactDataGrid--grouped'
|
|
2177
|
+
) ||
|
|
2178
|
+
grid.classList.contains('datagrid-with-grouping')
|
|
2179
|
+
) {
|
|
2180
|
+
// Main checkbox is now enabled for grouped data
|
|
2181
|
+
}
|
|
2182
|
+
});
|
|
2183
|
+
};
|
|
2184
|
+
|
|
2185
|
+
// Apply immediately and with delays
|
|
2186
|
+
applyGroupedStyling();
|
|
2187
|
+
const timer1 = setTimeout(applyGroupedStyling, 100);
|
|
2188
|
+
const timer2 = setTimeout(applyGroupedStyling, 500);
|
|
2189
|
+
const timer3 = setTimeout(applyGroupedStyling, 1000);
|
|
2190
|
+
|
|
2191
|
+
return () => {
|
|
2192
|
+
clearTimeout(timer1);
|
|
2193
|
+
clearTimeout(timer2);
|
|
2194
|
+
clearTimeout(timer3);
|
|
2195
|
+
};
|
|
2196
|
+
}
|
|
2197
|
+
}, [ajaxSetting?.groupBy, gridColumns]);
|
|
2198
|
+
|
|
1673
2199
|
useEffect(() => {
|
|
1674
2200
|
const delayedSetDSearch = debounce(() => {
|
|
1675
2201
|
setDSearch(search);
|
|
@@ -2133,7 +2659,14 @@ const DataGrid = forwardRef(
|
|
|
2133
2659
|
|
|
2134
2660
|
const value = `${addressValue} ${stateValue}`;
|
|
2135
2661
|
|
|
2136
|
-
return
|
|
2662
|
+
return (
|
|
2663
|
+
<CellWithTooltip
|
|
2664
|
+
value={value}
|
|
2665
|
+
columnType="address"
|
|
2666
|
+
>
|
|
2667
|
+
<span>{value}</span>
|
|
2668
|
+
</CellWithTooltip>
|
|
2669
|
+
);
|
|
2137
2670
|
},
|
|
2138
2671
|
};
|
|
2139
2672
|
case 'age':
|
|
@@ -2190,11 +2723,17 @@ const DataGrid = forwardRef(
|
|
|
2190
2723
|
name: `${column.type}.${column.id}`,
|
|
2191
2724
|
sortable: false,
|
|
2192
2725
|
render: ({ data }) => {
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2726
|
+
const value = data[column.id]
|
|
2727
|
+
? 'Yes'
|
|
2728
|
+
: 'No';
|
|
2729
|
+
return (
|
|
2730
|
+
<CellWithTooltip
|
|
2731
|
+
value={data[column.id]}
|
|
2732
|
+
columnType="boolean"
|
|
2733
|
+
>
|
|
2734
|
+
<span>{value}</span>
|
|
2735
|
+
</CellWithTooltip>
|
|
2736
|
+
);
|
|
2198
2737
|
},
|
|
2199
2738
|
};
|
|
2200
2739
|
case 'coding':
|
|
@@ -2278,7 +2817,14 @@ const DataGrid = forwardRef(
|
|
|
2278
2817
|
data[column.id]
|
|
2279
2818
|
).format('$0,0.00');
|
|
2280
2819
|
|
|
2281
|
-
return
|
|
2820
|
+
return (
|
|
2821
|
+
<CellWithTooltip
|
|
2822
|
+
value={data[column.id]}
|
|
2823
|
+
columnType="currency"
|
|
2824
|
+
>
|
|
2825
|
+
<span>{data}</span>
|
|
2826
|
+
</CellWithTooltip>
|
|
2827
|
+
);
|
|
2282
2828
|
} else {
|
|
2283
2829
|
return null;
|
|
2284
2830
|
}
|
|
@@ -2328,9 +2874,14 @@ const DataGrid = forwardRef(
|
|
|
2328
2874
|
}
|
|
2329
2875
|
|
|
2330
2876
|
return (
|
|
2331
|
-
<
|
|
2332
|
-
{
|
|
2333
|
-
|
|
2877
|
+
<CellWithTooltip
|
|
2878
|
+
value={data[column.id]}
|
|
2879
|
+
columnType="date"
|
|
2880
|
+
>
|
|
2881
|
+
<span style={columnStyle}>
|
|
2882
|
+
{value}
|
|
2883
|
+
</span>
|
|
2884
|
+
</CellWithTooltip>
|
|
2334
2885
|
);
|
|
2335
2886
|
} else {
|
|
2336
2887
|
return null;
|
|
@@ -2451,7 +3002,13 @@ const DataGrid = forwardRef(
|
|
|
2451
3002
|
}}
|
|
2452
3003
|
>
|
|
2453
3004
|
<option value="">
|
|
2454
|
-
Select
|
|
3005
|
+
Select{' '}
|
|
3006
|
+
{/^[aeioAEIO]/.test(
|
|
3007
|
+
column.label
|
|
3008
|
+
)
|
|
3009
|
+
? 'an'
|
|
3010
|
+
: 'a'}{' '}
|
|
3011
|
+
{column.label}
|
|
2455
3012
|
</option>
|
|
2456
3013
|
{dropdownData[column.id] &&
|
|
2457
3014
|
dropdownData[column.id].length >
|
|
@@ -2505,7 +3062,7 @@ const DataGrid = forwardRef(
|
|
|
2505
3062
|
data-tooltip-id={`system-tooltip`}
|
|
2506
3063
|
data-tooltip-content={`Download File ${file.file_name}`}
|
|
2507
3064
|
strokeWidth={2}
|
|
2508
|
-
size={
|
|
3065
|
+
size={14}
|
|
2509
3066
|
className={
|
|
2510
3067
|
styles.tdaction
|
|
2511
3068
|
}
|
|
@@ -2537,7 +3094,7 @@ const DataGrid = forwardRef(
|
|
|
2537
3094
|
.file_name
|
|
2538
3095
|
}`}
|
|
2539
3096
|
strokeWidth={2}
|
|
2540
|
-
size={
|
|
3097
|
+
size={14}
|
|
2541
3098
|
className={
|
|
2542
3099
|
styles.tdaction
|
|
2543
3100
|
}
|
|
@@ -2622,7 +3179,14 @@ const DataGrid = forwardRef(
|
|
|
2622
3179
|
column.jsonData
|
|
2623
3180
|
];
|
|
2624
3181
|
|
|
2625
|
-
return
|
|
3182
|
+
return (
|
|
3183
|
+
<CellWithTooltip
|
|
3184
|
+
value={data}
|
|
3185
|
+
columnType="json"
|
|
3186
|
+
>
|
|
3187
|
+
<span>{data}</span>
|
|
3188
|
+
</CellWithTooltip>
|
|
3189
|
+
);
|
|
2626
3190
|
} else {
|
|
2627
3191
|
return null;
|
|
2628
3192
|
}
|
|
@@ -2668,7 +3232,14 @@ const DataGrid = forwardRef(
|
|
|
2668
3232
|
];
|
|
2669
3233
|
}
|
|
2670
3234
|
|
|
2671
|
-
return
|
|
3235
|
+
return (
|
|
3236
|
+
<CellWithTooltip
|
|
3237
|
+
value={newData}
|
|
3238
|
+
columnType="option"
|
|
3239
|
+
>
|
|
3240
|
+
<span>{newData}</span>
|
|
3241
|
+
</CellWithTooltip>
|
|
3242
|
+
);
|
|
2672
3243
|
} else {
|
|
2673
3244
|
return null;
|
|
2674
3245
|
}
|
|
@@ -2682,9 +3253,14 @@ const DataGrid = forwardRef(
|
|
|
2682
3253
|
render: ({ data }) => {
|
|
2683
3254
|
if (data) {
|
|
2684
3255
|
return (
|
|
2685
|
-
<
|
|
2686
|
-
{column.placeholder}
|
|
2687
|
-
|
|
3256
|
+
<CellWithTooltip
|
|
3257
|
+
value={column.placeholder}
|
|
3258
|
+
columnType="placeholder"
|
|
3259
|
+
>
|
|
3260
|
+
<span>
|
|
3261
|
+
{column.placeholder}
|
|
3262
|
+
</span>
|
|
3263
|
+
</CellWithTooltip>
|
|
2688
3264
|
);
|
|
2689
3265
|
} else {
|
|
2690
3266
|
return null;
|
|
@@ -2772,7 +3348,14 @@ const DataGrid = forwardRef(
|
|
|
2772
3348
|
typeof value === 'string' ||
|
|
2773
3349
|
typeof value === 'number'
|
|
2774
3350
|
) {
|
|
2775
|
-
return
|
|
3351
|
+
return (
|
|
3352
|
+
<CellWithTooltip
|
|
3353
|
+
value={value}
|
|
3354
|
+
columnType="relation"
|
|
3355
|
+
>
|
|
3356
|
+
<span>{value}</span>
|
|
3357
|
+
</CellWithTooltip>
|
|
3358
|
+
);
|
|
2776
3359
|
} else {
|
|
2777
3360
|
return null;
|
|
2778
3361
|
}
|
|
@@ -2923,7 +3506,14 @@ const DataGrid = forwardRef(
|
|
|
2923
3506
|
result += values.join('<br />');
|
|
2924
3507
|
}
|
|
2925
3508
|
|
|
2926
|
-
return
|
|
3509
|
+
return (
|
|
3510
|
+
<CellWithTooltip
|
|
3511
|
+
value={result}
|
|
3512
|
+
columnType="relationArray"
|
|
3513
|
+
>
|
|
3514
|
+
<span>{parse(result)}</span>
|
|
3515
|
+
</CellWithTooltip>
|
|
3516
|
+
);
|
|
2927
3517
|
// }
|
|
2928
3518
|
} else {
|
|
2929
3519
|
let result = '';
|
|
@@ -2954,7 +3544,14 @@ const DataGrid = forwardRef(
|
|
|
2954
3544
|
: '';
|
|
2955
3545
|
}
|
|
2956
3546
|
|
|
2957
|
-
return
|
|
3547
|
+
return (
|
|
3548
|
+
<CellWithTooltip
|
|
3549
|
+
value={result}
|
|
3550
|
+
columnType="relationArray"
|
|
3551
|
+
>
|
|
3552
|
+
<span>{parse(result)}</span>
|
|
3553
|
+
</CellWithTooltip>
|
|
3554
|
+
);
|
|
2958
3555
|
}
|
|
2959
3556
|
|
|
2960
3557
|
return null;
|
|
@@ -2967,9 +3564,14 @@ const DataGrid = forwardRef(
|
|
|
2967
3564
|
render: ({ data }) => {
|
|
2968
3565
|
if (data && data[column.id]) {
|
|
2969
3566
|
return (
|
|
2970
|
-
<
|
|
2971
|
-
{
|
|
2972
|
-
|
|
3567
|
+
<CellWithTooltip
|
|
3568
|
+
value={data[column.id]}
|
|
3569
|
+
columnType="richtext"
|
|
3570
|
+
>
|
|
3571
|
+
<span>
|
|
3572
|
+
{parse(data[column.id])}
|
|
3573
|
+
</span>
|
|
3574
|
+
</CellWithTooltip>
|
|
2973
3575
|
);
|
|
2974
3576
|
} else {
|
|
2975
3577
|
return null;
|
|
@@ -2990,7 +3592,14 @@ const DataGrid = forwardRef(
|
|
|
2990
3592
|
}
|
|
2991
3593
|
});
|
|
2992
3594
|
|
|
2993
|
-
return
|
|
3595
|
+
return (
|
|
3596
|
+
<CellWithTooltip
|
|
3597
|
+
value={stage}
|
|
3598
|
+
columnType="stage"
|
|
3599
|
+
>
|
|
3600
|
+
<span>{stage}</span>
|
|
3601
|
+
</CellWithTooltip>
|
|
3602
|
+
);
|
|
2994
3603
|
},
|
|
2995
3604
|
};
|
|
2996
3605
|
case 'time':
|
|
@@ -3014,7 +3623,14 @@ const DataGrid = forwardRef(
|
|
|
3014
3623
|
: 'hh:mm A'
|
|
3015
3624
|
);
|
|
3016
3625
|
|
|
3017
|
-
return
|
|
3626
|
+
return (
|
|
3627
|
+
<CellWithTooltip
|
|
3628
|
+
value={data[column.id]}
|
|
3629
|
+
columnType="time"
|
|
3630
|
+
>
|
|
3631
|
+
<span>{data}</span>
|
|
3632
|
+
</CellWithTooltip>
|
|
3633
|
+
);
|
|
3018
3634
|
} else {
|
|
3019
3635
|
return null;
|
|
3020
3636
|
}
|
|
@@ -3041,7 +3657,14 @@ const DataGrid = forwardRef(
|
|
|
3041
3657
|
: 'DD-MM-YYYY hh:mm A'
|
|
3042
3658
|
);
|
|
3043
3659
|
|
|
3044
|
-
return
|
|
3660
|
+
return (
|
|
3661
|
+
<CellWithTooltip
|
|
3662
|
+
value={data[column.id]}
|
|
3663
|
+
columnType="timer"
|
|
3664
|
+
>
|
|
3665
|
+
<span>{data}</span>
|
|
3666
|
+
</CellWithTooltip>
|
|
3667
|
+
);
|
|
3045
3668
|
} else {
|
|
3046
3669
|
let shouldRenderButton = false;
|
|
3047
3670
|
|
|
@@ -3166,7 +3789,7 @@ const DataGrid = forwardRef(
|
|
|
3166
3789
|
data-tooltip-id="system-tooltip"
|
|
3167
3790
|
data-tooltip-content={`${column.label} Timer`}
|
|
3168
3791
|
strokeWidth={2}
|
|
3169
|
-
size={
|
|
3792
|
+
size={14}
|
|
3170
3793
|
style={{
|
|
3171
3794
|
color: 'white',
|
|
3172
3795
|
}}
|
|
@@ -3175,7 +3798,22 @@ const DataGrid = forwardRef(
|
|
|
3175
3798
|
);
|
|
3176
3799
|
}
|
|
3177
3800
|
|
|
3178
|
-
|
|
3801
|
+
// Return a placeholder div to maintain consistent row height
|
|
3802
|
+
return (
|
|
3803
|
+
<div
|
|
3804
|
+
style={{
|
|
3805
|
+
width: '28px',
|
|
3806
|
+
height: '28px',
|
|
3807
|
+
display: 'flex',
|
|
3808
|
+
alignItems: 'center',
|
|
3809
|
+
justifyContent:
|
|
3810
|
+
'center',
|
|
3811
|
+
margin: '0 auto',
|
|
3812
|
+
}}
|
|
3813
|
+
>
|
|
3814
|
+
{/* Empty placeholder to maintain layout */}
|
|
3815
|
+
</div>
|
|
3816
|
+
);
|
|
3179
3817
|
}
|
|
3180
3818
|
},
|
|
3181
3819
|
};
|
|
@@ -3467,14 +4105,21 @@ const DataGrid = forwardRef(
|
|
|
3467
4105
|
render: ({ data }) => {
|
|
3468
4106
|
if (data && data[column.id]) {
|
|
3469
4107
|
return (
|
|
3470
|
-
<
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
>
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
4108
|
+
<CellWithTooltip
|
|
4109
|
+
value={data[column.id]}
|
|
4110
|
+
columnType="url"
|
|
4111
|
+
>
|
|
4112
|
+
<span>
|
|
4113
|
+
<a
|
|
4114
|
+
href={
|
|
4115
|
+
data[column.id]
|
|
4116
|
+
}
|
|
4117
|
+
target="_blank"
|
|
4118
|
+
>
|
|
4119
|
+
Link
|
|
4120
|
+
</a>
|
|
4121
|
+
</span>
|
|
4122
|
+
</CellWithTooltip>
|
|
3478
4123
|
);
|
|
3479
4124
|
} else {
|
|
3480
4125
|
return null;
|
|
@@ -3606,7 +4251,14 @@ const DataGrid = forwardRef(
|
|
|
3606
4251
|
}
|
|
3607
4252
|
|
|
3608
4253
|
return (
|
|
3609
|
-
<
|
|
4254
|
+
<CellWithTooltip
|
|
4255
|
+
value={data[column.id]}
|
|
4256
|
+
columnType="text"
|
|
4257
|
+
>
|
|
4258
|
+
<span>
|
|
4259
|
+
{parse(content)}
|
|
4260
|
+
</span>
|
|
4261
|
+
</CellWithTooltip>
|
|
3610
4262
|
);
|
|
3611
4263
|
} else {
|
|
3612
4264
|
return null;
|
|
@@ -3840,7 +4492,7 @@ const DataGrid = forwardRef(
|
|
|
3840
4492
|
setLimit(ajaxSetting.take);
|
|
3841
4493
|
} else {
|
|
3842
4494
|
const calculateRows = (height) =>
|
|
3843
|
-
Math.floor((height - 100) /
|
|
4495
|
+
Math.floor((height - 100) / 32);
|
|
3844
4496
|
|
|
3845
4497
|
const rowCount = calculateRows(minHeight);
|
|
3846
4498
|
setLimit(rowCount);
|
|
@@ -3936,12 +4588,395 @@ const DataGrid = forwardRef(
|
|
|
3936
4588
|
<ReactDataGrid
|
|
3937
4589
|
key={`datagrid-${ajaxSetting?.url || ''}-${
|
|
3938
4590
|
ajaxSetting?.groupBy ? 'grouped' : 'ungrouped'
|
|
3939
|
-
}`}
|
|
4591
|
+
}-${groupRenderKey}`}
|
|
3940
4592
|
{...tableSetting}
|
|
3941
4593
|
columns={gridColumns}
|
|
3942
4594
|
dataSource={dataSource}
|
|
3943
4595
|
{...(ajaxSetting && ajaxSetting.groupBy
|
|
3944
|
-
? {
|
|
4596
|
+
? {
|
|
4597
|
+
defaultGroupBy: ajaxSetting.groupBy,
|
|
4598
|
+
defaultCollapsed: true,
|
|
4599
|
+
collapsedGroups: collapsedGroups,
|
|
4600
|
+
onGroupToggle: (groupData) => {
|
|
4601
|
+
// Handle group expand/collapse events
|
|
4602
|
+
// Update collapsed groups state
|
|
4603
|
+
const groupValue =
|
|
4604
|
+
typeof groupData === 'string'
|
|
4605
|
+
? groupData
|
|
4606
|
+
: groupData?.value ||
|
|
4607
|
+
groupData?.name ||
|
|
4608
|
+
'';
|
|
4609
|
+
|
|
4610
|
+
setCollapsedGroups((prev) => {
|
|
4611
|
+
const newState = { ...prev };
|
|
4612
|
+
if (newState[groupValue]) {
|
|
4613
|
+
delete newState[groupValue];
|
|
4614
|
+
} else {
|
|
4615
|
+
newState[groupValue] = true;
|
|
4616
|
+
}
|
|
4617
|
+
console.log(
|
|
4618
|
+
'Updated collapsed groups:',
|
|
4619
|
+
newState
|
|
4620
|
+
);
|
|
4621
|
+
return newState;
|
|
4622
|
+
});
|
|
4623
|
+
},
|
|
4624
|
+
renderGroupTitle: (groupData) => {
|
|
4625
|
+
const groupValue =
|
|
4626
|
+
typeof groupData === 'string'
|
|
4627
|
+
? groupData
|
|
4628
|
+
: groupData?.value ||
|
|
4629
|
+
groupData?.name ||
|
|
4630
|
+
'';
|
|
4631
|
+
|
|
4632
|
+
// Use ReactDataGrid's built-in toggle functionality
|
|
4633
|
+
const collapsed =
|
|
4634
|
+
collapsedGroups[groupValue] ||
|
|
4635
|
+
false;
|
|
4636
|
+
const toggleGroup = () => {
|
|
4637
|
+
// Update the collapsed state
|
|
4638
|
+
setCollapsedGroups((prev) => {
|
|
4639
|
+
const newState = { ...prev };
|
|
4640
|
+
if (newState[groupValue]) {
|
|
4641
|
+
delete newState[
|
|
4642
|
+
groupValue
|
|
4643
|
+
];
|
|
4644
|
+
} else {
|
|
4645
|
+
newState[
|
|
4646
|
+
groupValue
|
|
4647
|
+
] = true;
|
|
4648
|
+
}
|
|
4649
|
+
return newState;
|
|
4650
|
+
});
|
|
4651
|
+
};
|
|
4652
|
+
const groupCount =
|
|
4653
|
+
typeof groupData === 'object'
|
|
4654
|
+
? groupData?.count || 0
|
|
4655
|
+
: 0;
|
|
4656
|
+
const hasCheckboxColumn =
|
|
4657
|
+
gridColumns.some(
|
|
4658
|
+
(col) =>
|
|
4659
|
+
col.id ===
|
|
4660
|
+
'__checkbox-column'
|
|
4661
|
+
);
|
|
4662
|
+
|
|
4663
|
+
// Handle group header click for selection
|
|
4664
|
+
const handleGroupHeaderClick = (
|
|
4665
|
+
e
|
|
4666
|
+
) => {
|
|
4667
|
+
// Prevent rapid clicks
|
|
4668
|
+
if (
|
|
4669
|
+
groupClickTimeoutRef.current
|
|
4670
|
+
) {
|
|
4671
|
+
console.log(
|
|
4672
|
+
'🖱️ Ignoring rapid click'
|
|
4673
|
+
);
|
|
4674
|
+
return;
|
|
4675
|
+
}
|
|
4676
|
+
|
|
4677
|
+
// Don't trigger if clicking on the expand button or checkbox
|
|
4678
|
+
if (
|
|
4679
|
+
e.target.closest(
|
|
4680
|
+
'.group-expand-btn'
|
|
4681
|
+
) ||
|
|
4682
|
+
e.target.closest(
|
|
4683
|
+
'input[type="checkbox"]'
|
|
4684
|
+
)
|
|
4685
|
+
) {
|
|
4686
|
+
console.log(
|
|
4687
|
+
'🖱️ Ignoring click on expand button or checkbox'
|
|
4688
|
+
);
|
|
4689
|
+
return;
|
|
4690
|
+
}
|
|
4691
|
+
|
|
4692
|
+
// Set timeout to prevent rapid clicks
|
|
4693
|
+
groupClickTimeoutRef.current =
|
|
4694
|
+
setTimeout(() => {
|
|
4695
|
+
groupClickTimeoutRef.current =
|
|
4696
|
+
null;
|
|
4697
|
+
}, 300);
|
|
4698
|
+
|
|
4699
|
+
// Toggle selection of all items in this group
|
|
4700
|
+
const isCurrentlySelected =
|
|
4701
|
+
isGroupSelected(groupValue);
|
|
4702
|
+
|
|
4703
|
+
handleGroupSelectionChange(
|
|
4704
|
+
groupValue,
|
|
4705
|
+
!isCurrentlySelected
|
|
4706
|
+
);
|
|
4707
|
+
};
|
|
4708
|
+
|
|
4709
|
+
return (
|
|
4710
|
+
<div
|
|
4711
|
+
className="group-header-clean group-header-fixed-height"
|
|
4712
|
+
onClick={
|
|
4713
|
+
handleGroupHeaderClick
|
|
4714
|
+
}
|
|
4715
|
+
style={{
|
|
4716
|
+
display: 'flex',
|
|
4717
|
+
alignItems: 'center',
|
|
4718
|
+
justifyContent:
|
|
4719
|
+
'space-between',
|
|
4720
|
+
width: '100%',
|
|
4721
|
+
height: '34px', // Compact height
|
|
4722
|
+
padding: '6px 12px', // Reduced padding for compact design
|
|
4723
|
+
background:
|
|
4724
|
+
'linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%)',
|
|
4725
|
+
borderLeft:
|
|
4726
|
+
'4px solid var(--primary-color, #3b82f6)',
|
|
4727
|
+
position: 'relative',
|
|
4728
|
+
overflow: 'hidden',
|
|
4729
|
+
boxShadow:
|
|
4730
|
+
'0 1px 3px rgba(0,0,0,0.1)',
|
|
4731
|
+
borderRadius:
|
|
4732
|
+
'0 4px 4px 0',
|
|
4733
|
+
cursor: 'pointer',
|
|
4734
|
+
boxSizing: 'border-box',
|
|
4735
|
+
lineHeight: '1.1', // Compact line height
|
|
4736
|
+
flexShrink: 0,
|
|
4737
|
+
transition:
|
|
4738
|
+
'background-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease',
|
|
4739
|
+
}}
|
|
4740
|
+
onMouseEnter={(e) => {
|
|
4741
|
+
e.currentTarget.style.background =
|
|
4742
|
+
'linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%)';
|
|
4743
|
+
e.currentTarget.style.boxShadow =
|
|
4744
|
+
'0 2px 8px rgba(0,0,0,0.15)';
|
|
4745
|
+
e.currentTarget.style.transform =
|
|
4746
|
+
'translateY(-1px)';
|
|
4747
|
+
}}
|
|
4748
|
+
onMouseLeave={(e) => {
|
|
4749
|
+
e.currentTarget.style.background =
|
|
4750
|
+
'linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%)';
|
|
4751
|
+
e.currentTarget.style.boxShadow =
|
|
4752
|
+
'0 1px 3px rgba(0,0,0,0.1)';
|
|
4753
|
+
e.currentTarget.style.transform =
|
|
4754
|
+
'translateY(0)';
|
|
4755
|
+
}}
|
|
4756
|
+
>
|
|
4757
|
+
{/* Left side - Group info and expand/collapse */}
|
|
4758
|
+
<div
|
|
4759
|
+
style={{
|
|
4760
|
+
display: 'flex',
|
|
4761
|
+
alignItems: 'center',
|
|
4762
|
+
flex: 1,
|
|
4763
|
+
zIndex: 2,
|
|
4764
|
+
position: 'relative',
|
|
4765
|
+
}}
|
|
4766
|
+
>
|
|
4767
|
+
<button
|
|
4768
|
+
className="group-expand-btn"
|
|
4769
|
+
onClick={(e) => {
|
|
4770
|
+
e.stopPropagation();
|
|
4771
|
+
if (
|
|
4772
|
+
typeof toggleGroup ===
|
|
4773
|
+
'function'
|
|
4774
|
+
) {
|
|
4775
|
+
toggleGroup();
|
|
4776
|
+
} else {
|
|
4777
|
+
console.warn(
|
|
4778
|
+
'toggleGroup is not a function:',
|
|
4779
|
+
toggleGroup
|
|
4780
|
+
);
|
|
4781
|
+
}
|
|
4782
|
+
}}
|
|
4783
|
+
style={{
|
|
4784
|
+
background:
|
|
4785
|
+
'var(--primary-color, #3b82f6)',
|
|
4786
|
+
border: 'none',
|
|
4787
|
+
borderRadius:
|
|
4788
|
+
'3px',
|
|
4789
|
+
color: 'white',
|
|
4790
|
+
width: '20px', // More compact
|
|
4791
|
+
height: '20px', // More compact
|
|
4792
|
+
display: 'flex',
|
|
4793
|
+
alignItems:
|
|
4794
|
+
'center',
|
|
4795
|
+
justifyContent:
|
|
4796
|
+
'center',
|
|
4797
|
+
marginRight:
|
|
4798
|
+
'8px', // Reduced margin
|
|
4799
|
+
cursor: 'pointer',
|
|
4800
|
+
fontSize: '11px', // Smaller font
|
|
4801
|
+
fontWeight:
|
|
4802
|
+
'bold',
|
|
4803
|
+
boxShadow:
|
|
4804
|
+
'0 1px 2px rgba(0,0,0,0.1)',
|
|
4805
|
+
transition:
|
|
4806
|
+
'all 0.15s ease',
|
|
4807
|
+
}}
|
|
4808
|
+
onMouseEnter={(e) => {
|
|
4809
|
+
e.target.style.transform =
|
|
4810
|
+
'scale(1.05)';
|
|
4811
|
+
e.target.style.background =
|
|
4812
|
+
'var(--secondary-color, #2563eb)';
|
|
4813
|
+
}}
|
|
4814
|
+
onMouseLeave={(e) => {
|
|
4815
|
+
e.target.style.transform =
|
|
4816
|
+
'scale(1)';
|
|
4817
|
+
e.target.style.background =
|
|
4818
|
+
'var(--primary-color, #3b82f6)';
|
|
4819
|
+
}}
|
|
4820
|
+
>
|
|
4821
|
+
{collapsed
|
|
4822
|
+
? '+'
|
|
4823
|
+
: '−'}
|
|
4824
|
+
</button>
|
|
4825
|
+
<div
|
|
4826
|
+
style={{
|
|
4827
|
+
display: 'flex',
|
|
4828
|
+
alignItems:
|
|
4829
|
+
'center', // Changed to center for compact layout
|
|
4830
|
+
gap: '8px', // Add gap between elements
|
|
4831
|
+
}}
|
|
4832
|
+
>
|
|
4833
|
+
<strong
|
|
4834
|
+
style={{
|
|
4835
|
+
fontSize:
|
|
4836
|
+
'0.85rem', // Slightly smaller for compact design
|
|
4837
|
+
color: 'var(--secondary-color, #1f2937)',
|
|
4838
|
+
fontWeight:
|
|
4839
|
+
'600',
|
|
4840
|
+
textTransform:
|
|
4841
|
+
'uppercase',
|
|
4842
|
+
letterSpacing:
|
|
4843
|
+
'0.025em',
|
|
4844
|
+
}}
|
|
4845
|
+
>
|
|
4846
|
+
{groupValue}
|
|
4847
|
+
</strong>
|
|
4848
|
+
{groupCount > 0 && (
|
|
4849
|
+
<span
|
|
4850
|
+
style={{
|
|
4851
|
+
color: '#6b7280',
|
|
4852
|
+
fontSize:
|
|
4853
|
+
'0.75rem', // Smaller for compact design
|
|
4854
|
+
fontWeight:
|
|
4855
|
+
'500',
|
|
4856
|
+
}}
|
|
4857
|
+
>
|
|
4858
|
+
({groupCount}{' '}
|
|
4859
|
+
{groupCount ===
|
|
4860
|
+
1
|
|
4861
|
+
? 'item'
|
|
4862
|
+
: 'items'}
|
|
4863
|
+
)
|
|
4864
|
+
</span>
|
|
4865
|
+
)}
|
|
4866
|
+
{/* Click indicator */}
|
|
4867
|
+
<span
|
|
4868
|
+
style={{
|
|
4869
|
+
color: '#9ca3af',
|
|
4870
|
+
fontSize:
|
|
4871
|
+
'0.7rem',
|
|
4872
|
+
fontStyle:
|
|
4873
|
+
'italic',
|
|
4874
|
+
opacity: 0.8,
|
|
4875
|
+
marginLeft:
|
|
4876
|
+
'auto',
|
|
4877
|
+
userSelect:
|
|
4878
|
+
'none',
|
|
4879
|
+
}}
|
|
4880
|
+
>
|
|
4881
|
+
Click to
|
|
4882
|
+
select/unselect
|
|
4883
|
+
all
|
|
4884
|
+
</span>
|
|
4885
|
+
</div>
|
|
4886
|
+
</div>
|
|
4887
|
+
|
|
4888
|
+
{/* Right side - Group selection */}
|
|
4889
|
+
{hasCheckboxColumn && (
|
|
4890
|
+
<div
|
|
4891
|
+
style={{
|
|
4892
|
+
display: 'flex',
|
|
4893
|
+
alignItems:
|
|
4894
|
+
'center',
|
|
4895
|
+
gap: '4px', // Reduced gap for compact design
|
|
4896
|
+
fontSize:
|
|
4897
|
+
'0.75rem', // Smaller font for compact design
|
|
4898
|
+
background:
|
|
4899
|
+
'rgba(255, 255, 255, 0.9)',
|
|
4900
|
+
padding:
|
|
4901
|
+
'3px 8px', // Reduced padding for compact design
|
|
4902
|
+
borderRadius:
|
|
4903
|
+
'12px', // Smaller border radius
|
|
4904
|
+
border: '1px solid rgba(59, 130, 246, 0.3)',
|
|
4905
|
+
zIndex: 2,
|
|
4906
|
+
position:
|
|
4907
|
+
'relative',
|
|
4908
|
+
boxShadow:
|
|
4909
|
+
'0 1px 2px rgba(0,0,0,0.05)',
|
|
4910
|
+
}}
|
|
4911
|
+
>
|
|
4912
|
+
<input
|
|
4913
|
+
type="checkbox"
|
|
4914
|
+
onChange={(e) => {
|
|
4915
|
+
e.stopPropagation();
|
|
4916
|
+
handleGroupSelectionChange(
|
|
4917
|
+
groupValue,
|
|
4918
|
+
e.target
|
|
4919
|
+
.checked
|
|
4920
|
+
);
|
|
4921
|
+
}}
|
|
4922
|
+
checked={isGroupSelected(
|
|
4923
|
+
groupValue
|
|
4924
|
+
)}
|
|
4925
|
+
style={{
|
|
4926
|
+
width: '14px', // Smaller checkbox for compact design
|
|
4927
|
+
height: '14px',
|
|
4928
|
+
cursor: 'pointer',
|
|
4929
|
+
accentColor:
|
|
4930
|
+
'var(--primary-color, #3b82f6)',
|
|
4931
|
+
}}
|
|
4932
|
+
/>
|
|
4933
|
+
<span
|
|
4934
|
+
style={{
|
|
4935
|
+
cursor: 'pointer',
|
|
4936
|
+
userSelect:
|
|
4937
|
+
'none',
|
|
4938
|
+
color: 'var(--secondary-color, #1f2937)',
|
|
4939
|
+
fontWeight:
|
|
4940
|
+
'500',
|
|
4941
|
+
fontSize:
|
|
4942
|
+
'0.7rem', // Smaller font for compact design
|
|
4943
|
+
}}
|
|
4944
|
+
onClick={(e) => {
|
|
4945
|
+
e.stopPropagation();
|
|
4946
|
+
const checkbox =
|
|
4947
|
+
e.target
|
|
4948
|
+
.previousElementSibling;
|
|
4949
|
+
checkbox.checked =
|
|
4950
|
+
!checkbox.checked;
|
|
4951
|
+
handleGroupSelectionChange(
|
|
4952
|
+
groupValue,
|
|
4953
|
+
checkbox.checked
|
|
4954
|
+
);
|
|
4955
|
+
}}
|
|
4956
|
+
>
|
|
4957
|
+
Select All
|
|
4958
|
+
</span>
|
|
4959
|
+
</div>
|
|
4960
|
+
)}
|
|
4961
|
+
|
|
4962
|
+
{/* Background pattern */}
|
|
4963
|
+
<div
|
|
4964
|
+
style={{
|
|
4965
|
+
position: 'absolute',
|
|
4966
|
+
top: 0,
|
|
4967
|
+
left: 0,
|
|
4968
|
+
right: 0,
|
|
4969
|
+
bottom: 0,
|
|
4970
|
+
background:
|
|
4971
|
+
'repeating-linear-gradient(45deg, transparent, transparent 2px, rgba(59, 130, 246, 0.03) 2px, rgba(59, 130, 246, 0.03) 4px)',
|
|
4972
|
+
zIndex: 1,
|
|
4973
|
+
pointerEvents: 'none',
|
|
4974
|
+
}}
|
|
4975
|
+
/>
|
|
4976
|
+
</div>
|
|
4977
|
+
);
|
|
4978
|
+
},
|
|
4979
|
+
}
|
|
3945
4980
|
: {})}
|
|
3946
4981
|
filterValue={filterValue}
|
|
3947
4982
|
limit={limit}
|
|
@@ -3952,7 +4987,7 @@ const DataGrid = forwardRef(
|
|
|
3952
4987
|
}
|
|
3953
4988
|
headerProps={headerProps}
|
|
3954
4989
|
idProperty="id"
|
|
3955
|
-
minRowHeight={
|
|
4990
|
+
minRowHeight={32}
|
|
3956
4991
|
onFilterValueChange={(fv) => {
|
|
3957
4992
|
handleFilterChange(fv, filterValue);
|
|
3958
4993
|
}}
|
|
@@ -3986,6 +5021,11 @@ const DataGrid = forwardRef(
|
|
|
3986
5021
|
borderRadius: 'var(--br, 4px)',
|
|
3987
5022
|
overflow: 'hidden',
|
|
3988
5023
|
}}
|
|
5024
|
+
className={
|
|
5025
|
+
ajaxSetting?.groupBy
|
|
5026
|
+
? 'InovuaReactDataGrid--grouped datagrid-with-grouping datagrid-fixed-group-headers'
|
|
5027
|
+
: 'datagrid-without-grouping'
|
|
5028
|
+
}
|
|
3989
5029
|
checkboxColumnProps={{
|
|
3990
5030
|
width: 60,
|
|
3991
5031
|
minWidth: 60,
|
|
@@ -3994,7 +5034,88 @@ const DataGrid = forwardRef(
|
|
|
3994
5034
|
sortable: false,
|
|
3995
5035
|
headerAlign: 'center',
|
|
3996
5036
|
textAlign: 'center',
|
|
5037
|
+
renderHeader: () => {
|
|
5038
|
+
// Custom header checkbox that works with grouped data
|
|
5039
|
+
const allRowsSelected =
|
|
5040
|
+
dataRef.current &&
|
|
5041
|
+
dataRef.current.length > 0 &&
|
|
5042
|
+
dataRef.current.every(
|
|
5043
|
+
(row) =>
|
|
5044
|
+
row &&
|
|
5045
|
+
row.id !== undefined &&
|
|
5046
|
+
row.id !== null &&
|
|
5047
|
+
selected[row.id]
|
|
5048
|
+
);
|
|
5049
|
+
const someRowsSelected =
|
|
5050
|
+
dataRef.current &&
|
|
5051
|
+
dataRef.current.some(
|
|
5052
|
+
(row) =>
|
|
5053
|
+
row &&
|
|
5054
|
+
row.id !== undefined &&
|
|
5055
|
+
row.id !== null &&
|
|
5056
|
+
selected[row.id]
|
|
5057
|
+
);
|
|
5058
|
+
|
|
5059
|
+
return (
|
|
5060
|
+
<input
|
|
5061
|
+
type="checkbox"
|
|
5062
|
+
checked={allRowsSelected}
|
|
5063
|
+
ref={(checkbox) => {
|
|
5064
|
+
if (checkbox) {
|
|
5065
|
+
checkbox.indeterminate =
|
|
5066
|
+
someRowsSelected &&
|
|
5067
|
+
!allRowsSelected;
|
|
5068
|
+
}
|
|
5069
|
+
}}
|
|
5070
|
+
onChange={(e) => {
|
|
5071
|
+
if (e.target.checked) {
|
|
5072
|
+
// Select all rows
|
|
5073
|
+
const s = {};
|
|
5074
|
+
if (
|
|
5075
|
+
dataRef.current &&
|
|
5076
|
+
Array.isArray(
|
|
5077
|
+
dataRef.current
|
|
5078
|
+
)
|
|
5079
|
+
) {
|
|
5080
|
+
dataRef.current.forEach(
|
|
5081
|
+
(obj) => {
|
|
5082
|
+
if (
|
|
5083
|
+
obj &&
|
|
5084
|
+
obj.id !==
|
|
5085
|
+
undefined &&
|
|
5086
|
+
obj.id !==
|
|
5087
|
+
null
|
|
5088
|
+
) {
|
|
5089
|
+
s[obj.id] =
|
|
5090
|
+
obj;
|
|
5091
|
+
}
|
|
5092
|
+
}
|
|
5093
|
+
);
|
|
5094
|
+
}
|
|
5095
|
+
setSelected(s);
|
|
5096
|
+
if (setRowsSelected) {
|
|
5097
|
+
setRowsSelected(s);
|
|
5098
|
+
}
|
|
5099
|
+
} else {
|
|
5100
|
+
// Deselect all rows
|
|
5101
|
+
setSelected({});
|
|
5102
|
+
if (setRowsSelected) {
|
|
5103
|
+
setRowsSelected({});
|
|
5104
|
+
}
|
|
5105
|
+
}
|
|
5106
|
+
}}
|
|
5107
|
+
style={{
|
|
5108
|
+
width: '20px',
|
|
5109
|
+
height: '20px',
|
|
5110
|
+
cursor: 'pointer',
|
|
5111
|
+
accentColor:
|
|
5112
|
+
'var(--primary-color, #3b82f6)',
|
|
5113
|
+
}}
|
|
5114
|
+
/>
|
|
5115
|
+
);
|
|
5116
|
+
},
|
|
3997
5117
|
}}
|
|
5118
|
+
checkboxOnlyRowSelect={true}
|
|
3998
5119
|
/>
|
|
3999
5120
|
) : null}
|
|
4000
5121
|
</div>
|