@visns-studio/visns-components 5.8.19 → 5.9.0
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 +485 -131
- package/src/components/crm/Field.jsx +2 -2
- package/src/components/crm/MultiSelect.jsx +33 -13
- package/src/components/crm/generic/GenericDetail.jsx +32 -2
- package/src/components/crm/styles/DataGrid.module.scss +38 -6
- package/src/components/crm/styles/MultiSelect.module.scss +31 -9
- package/src/components/crm/styles/TableFilter.module.scss +32 -1
- package/src/components/crm/styles/global-datagrid.css +175 -1
- package/src/components/styles/global.css +29 -0
- package/src/examples/ImprovedCheckboxDataGrid.jsx +269 -0
- package/src/examples/MultiSelectStylingTest.jsx +76 -0
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import '../styles/global.css';
|
|
2
2
|
import './styles/global-datagrid.css';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* DataGrid Component
|
|
6
|
+
*
|
|
7
|
+
* This component provides a data grid with modal form editing capabilities.
|
|
8
|
+
*
|
|
9
|
+
* Modal Vertical Alignment:
|
|
10
|
+
* To position the modal toward the top of the viewport instead of center, add the `verticalAlign: "top"` property to the form object.
|
|
11
|
+
* Example:
|
|
12
|
+
* {
|
|
13
|
+
* form: {
|
|
14
|
+
* verticalAlign: "top",
|
|
15
|
+
* primaryKey: "id",
|
|
16
|
+
* url: "/ajax/jobs",
|
|
17
|
+
* // other form properties
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
*/
|
|
21
|
+
|
|
4
22
|
import React, {
|
|
5
23
|
forwardRef,
|
|
6
24
|
useCallback,
|
|
@@ -25,6 +43,7 @@ import { toast } from 'react-toastify';
|
|
|
25
43
|
import imageCompression from 'browser-image-compression';
|
|
26
44
|
import Vapor from 'laravel-vapor';
|
|
27
45
|
import Lightbox from 'yet-another-react-lightbox';
|
|
46
|
+
import { Tooltip } from 'react-tooltip';
|
|
28
47
|
import fetchUtil from '../../utils/fetchUtil';
|
|
29
48
|
import { confirmDialog } from '../utils/ConfirmDialog';
|
|
30
49
|
import {
|
|
@@ -128,6 +147,123 @@ const loadData = async (
|
|
|
128
147
|
}
|
|
129
148
|
};
|
|
130
149
|
|
|
150
|
+
// Utility function to check if text content is truncated
|
|
151
|
+
const isTextTruncated = (element) => {
|
|
152
|
+
if (!element) return false;
|
|
153
|
+
return (
|
|
154
|
+
element.scrollWidth > element.clientWidth ||
|
|
155
|
+
element.scrollHeight > element.clientHeight
|
|
156
|
+
);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Utility function to format cell value for tooltip display
|
|
160
|
+
const formatCellValueForTooltip = (value, columnType) => {
|
|
161
|
+
if (value === null || value === undefined || value === '') {
|
|
162
|
+
return '';
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
switch (columnType) {
|
|
166
|
+
case 'date':
|
|
167
|
+
case 'datetime':
|
|
168
|
+
if (
|
|
169
|
+
moment(value).isValid() &&
|
|
170
|
+
moment(value).format('YYYY-MM-DD') !== '1970-01-01'
|
|
171
|
+
) {
|
|
172
|
+
return moment(value).format('DD-MM-YYYY HH:mm');
|
|
173
|
+
}
|
|
174
|
+
return String(value);
|
|
175
|
+
case 'currency':
|
|
176
|
+
return numeral(value).format('$0,0.00');
|
|
177
|
+
case 'number':
|
|
178
|
+
return numeral(value).format('0,0');
|
|
179
|
+
case 'boolean':
|
|
180
|
+
return value ? 'Yes' : 'No';
|
|
181
|
+
case 'richtext':
|
|
182
|
+
// Strip HTML tags for tooltip
|
|
183
|
+
const tempDiv = document.createElement('div');
|
|
184
|
+
tempDiv.innerHTML = value;
|
|
185
|
+
return tempDiv.textContent || tempDiv.innerText || '';
|
|
186
|
+
default:
|
|
187
|
+
return String(value);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// Component to wrap cell content with tooltip functionality
|
|
192
|
+
const CellWithTooltip = ({
|
|
193
|
+
children,
|
|
194
|
+
value,
|
|
195
|
+
columnType = 'text',
|
|
196
|
+
className = '',
|
|
197
|
+
}) => {
|
|
198
|
+
const cellRef = useRef(null);
|
|
199
|
+
const [showTooltip, setShowTooltip] = useState(false);
|
|
200
|
+
const [tooltipId] = useState(
|
|
201
|
+
() => `cell-tooltip-${Math.random().toString(36).substr(2, 9)}`
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
useEffect(() => {
|
|
205
|
+
const checkTruncation = () => {
|
|
206
|
+
if (cellRef.current) {
|
|
207
|
+
const isTruncated = isTextTruncated(cellRef.current);
|
|
208
|
+
setShowTooltip(isTruncated);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Check truncation on mount and when content changes
|
|
213
|
+
checkTruncation();
|
|
214
|
+
|
|
215
|
+
// Also check on window resize
|
|
216
|
+
const handleResize = () => checkTruncation();
|
|
217
|
+
window.addEventListener('resize', handleResize);
|
|
218
|
+
|
|
219
|
+
return () => {
|
|
220
|
+
window.removeEventListener('resize', handleResize);
|
|
221
|
+
};
|
|
222
|
+
}, [children, value]);
|
|
223
|
+
|
|
224
|
+
const tooltipContent = formatCellValueForTooltip(value, columnType);
|
|
225
|
+
|
|
226
|
+
// Only show tooltip if content is truncated and we have meaningful content
|
|
227
|
+
const shouldShowTooltip =
|
|
228
|
+
showTooltip && tooltipContent && tooltipContent.trim() !== '';
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<div
|
|
232
|
+
ref={cellRef}
|
|
233
|
+
className={className}
|
|
234
|
+
style={{
|
|
235
|
+
overflow: 'hidden',
|
|
236
|
+
textOverflow: 'ellipsis',
|
|
237
|
+
whiteSpace: 'nowrap',
|
|
238
|
+
width: '100%',
|
|
239
|
+
}}
|
|
240
|
+
{...(shouldShowTooltip && {
|
|
241
|
+
'data-tooltip-id': tooltipId,
|
|
242
|
+
'data-tooltip-content': tooltipContent,
|
|
243
|
+
})}
|
|
244
|
+
>
|
|
245
|
+
{children}
|
|
246
|
+
{shouldShowTooltip && (
|
|
247
|
+
<Tooltip
|
|
248
|
+
id={tooltipId}
|
|
249
|
+
style={{
|
|
250
|
+
backgroundColor: 'rgba(0, 0, 0, 0.9)',
|
|
251
|
+
color: 'white',
|
|
252
|
+
borderRadius: '6px',
|
|
253
|
+
padding: '8px 12px',
|
|
254
|
+
fontSize: '13px',
|
|
255
|
+
maxWidth: '300px',
|
|
256
|
+
wordWrap: 'break-word',
|
|
257
|
+
zIndex: 9999,
|
|
258
|
+
}}
|
|
259
|
+
place="top"
|
|
260
|
+
offset={5}
|
|
261
|
+
/>
|
|
262
|
+
)}
|
|
263
|
+
</div>
|
|
264
|
+
);
|
|
265
|
+
};
|
|
266
|
+
|
|
131
267
|
const DataGrid = forwardRef(
|
|
132
268
|
(
|
|
133
269
|
{
|
|
@@ -360,6 +496,18 @@ const DataGrid = forwardRef(
|
|
|
360
496
|
}
|
|
361
497
|
|
|
362
498
|
sqlResult.then((res) => {
|
|
499
|
+
// Sort data by grouping field if grouping is enabled
|
|
500
|
+
if (ajaxSetting?.groupBy?.length > 0) {
|
|
501
|
+
const groupField = ajaxSetting.groupBy[0]; // groupBy is array of strings
|
|
502
|
+
res.data.sort((a, b) => {
|
|
503
|
+
const aValue = a[groupField] || '';
|
|
504
|
+
const bValue = b[groupField] || '';
|
|
505
|
+
return aValue
|
|
506
|
+
.toString()
|
|
507
|
+
.localeCompare(bValue.toString());
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
|
|
363
511
|
if (setTotal) {
|
|
364
512
|
setTotal(res.count);
|
|
365
513
|
}
|
|
@@ -525,47 +673,33 @@ const DataGrid = forwardRef(
|
|
|
525
673
|
|
|
526
674
|
const handleSelectionChange = useCallback(
|
|
527
675
|
(param) => {
|
|
528
|
-
//
|
|
529
|
-
if (
|
|
530
|
-
|
|
676
|
+
// Handle the selection change based on the parameter type
|
|
677
|
+
if (param.selected === true) {
|
|
678
|
+
// Select all rows - this happens when header checkbox is clicked to select all
|
|
679
|
+
const s = {};
|
|
680
|
+
param.data.forEach((obj) => {
|
|
681
|
+
s[obj.id] = obj;
|
|
682
|
+
});
|
|
683
|
+
setSelected(s);
|
|
684
|
+
// Update parent component's rowsSelected state
|
|
685
|
+
if (setRowsSelected) {
|
|
686
|
+
setRowsSelected(s);
|
|
687
|
+
}
|
|
688
|
+
} else if (
|
|
689
|
+
param.selected === false ||
|
|
531
690
|
(typeof param.selected === 'object' &&
|
|
532
|
-
Object.keys(param.selected).length
|
|
691
|
+
Object.keys(param.selected).length === 0)
|
|
533
692
|
) {
|
|
534
|
-
//
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
});
|
|
540
|
-
setSelected(s);
|
|
541
|
-
// Update parent component's rowsSelected state
|
|
542
|
-
if (setRowsSelected) {
|
|
543
|
-
setRowsSelected(s);
|
|
544
|
-
}
|
|
545
|
-
} else if (typeof param.selected === 'object') {
|
|
546
|
-
const selectedKey = Object.keys(param.selected)[0];
|
|
547
|
-
const isSelectedAlready =
|
|
548
|
-
selected.hasOwnProperty(selectedKey);
|
|
549
|
-
|
|
550
|
-
let newSelected;
|
|
551
|
-
if (isSelectedAlready) {
|
|
552
|
-
newSelected = {};
|
|
553
|
-
setSelected(newSelected);
|
|
554
|
-
} else {
|
|
555
|
-
newSelected = {
|
|
556
|
-
...selected,
|
|
557
|
-
[selectedKey]: param.selected[selectedKey],
|
|
558
|
-
};
|
|
559
|
-
setSelected(newSelected);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// Update parent component's rowsSelected state
|
|
563
|
-
if (setRowsSelected) {
|
|
564
|
-
setRowsSelected(newSelected);
|
|
565
|
-
}
|
|
693
|
+
// Deselect all rows - this happens when header checkbox is clicked to deselect all
|
|
694
|
+
setSelected({});
|
|
695
|
+
// Update parent component's rowsSelected state
|
|
696
|
+
if (setRowsSelected) {
|
|
697
|
+
setRowsSelected({});
|
|
566
698
|
}
|
|
567
|
-
} else {
|
|
568
|
-
//
|
|
699
|
+
} else if (typeof param.selected === 'object') {
|
|
700
|
+
// Individual row selection/deselection - ReactDataGrid sends the complete new selection state
|
|
701
|
+
// ReactDataGrid sends the complete new selection state, not just the changed row
|
|
702
|
+
// So we can directly use param.selected as the new selection state
|
|
569
703
|
setSelected(param.selected);
|
|
570
704
|
// Update parent component's rowsSelected state
|
|
571
705
|
if (setRowsSelected) {
|
|
@@ -574,7 +708,7 @@ const DataGrid = forwardRef(
|
|
|
574
708
|
}
|
|
575
709
|
},
|
|
576
710
|
[selected, setRowsSelected]
|
|
577
|
-
);
|
|
711
|
+
);
|
|
578
712
|
|
|
579
713
|
const findUpdatedFilter = (filters, currentValues) => {
|
|
580
714
|
for (const filter of filters) {
|
|
@@ -1141,35 +1275,85 @@ const DataGrid = forwardRef(
|
|
|
1141
1275
|
}
|
|
1142
1276
|
}, []);
|
|
1143
1277
|
|
|
1144
|
-
const onRenderRow = useCallback(
|
|
1145
|
-
|
|
1146
|
-
|
|
1278
|
+
const onRenderRow = useCallback(
|
|
1279
|
+
(rowProps) => {
|
|
1280
|
+
// save the original handlers to be called later
|
|
1281
|
+
const { onClick } = rowProps;
|
|
1147
1282
|
|
|
1148
|
-
|
|
1149
|
-
|
|
1283
|
+
rowProps.onClick = (event) => {
|
|
1284
|
+
const cellElement = event.target.closest(
|
|
1285
|
+
'.InovuaReactDataGrid__cell'
|
|
1286
|
+
);
|
|
1150
1287
|
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1288
|
+
// Add null check to prevent errors when cellElement is null
|
|
1289
|
+
if (!cellElement) {
|
|
1290
|
+
return; // Exit early if no cell element was found
|
|
1291
|
+
}
|
|
1154
1292
|
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
}
|
|
1293
|
+
const columnIndex = Array.from(
|
|
1294
|
+
cellElement.parentNode.children
|
|
1295
|
+
).indexOf(cellElement);
|
|
1159
1296
|
|
|
1160
|
-
|
|
1161
|
-
cellElement.parentNode.children
|
|
1162
|
-
).indexOf(cellElement);
|
|
1297
|
+
const column = rowProps.columns[columnIndex];
|
|
1163
1298
|
|
|
1164
|
-
|
|
1299
|
+
if (column.id === '__checkbox-column') {
|
|
1300
|
+
// For checkbox column clicks, we need to handle them specially
|
|
1301
|
+
// to ensure consistent behavior whether clicking checkbox or cell area
|
|
1165
1302
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1303
|
+
// Check if clicking directly on the checkbox input
|
|
1304
|
+
const isCheckboxInput = event.target.matches(
|
|
1305
|
+
'input[type="checkbox"]'
|
|
1306
|
+
);
|
|
1307
|
+
|
|
1308
|
+
if (!isCheckboxInput) {
|
|
1309
|
+
// If clicking on empty space in checkbox cell, simulate checkbox click
|
|
1310
|
+
// by manually toggling the selection state
|
|
1311
|
+
event.preventDefault();
|
|
1312
|
+
event.stopPropagation();
|
|
1313
|
+
|
|
1314
|
+
const rowId =
|
|
1315
|
+
rowProps.data[rowProps.idProperty || 'id'];
|
|
1316
|
+
const isCurrentlySelected =
|
|
1317
|
+
selected.hasOwnProperty(rowId);
|
|
1318
|
+
|
|
1319
|
+
let newSelected;
|
|
1320
|
+
if (isCurrentlySelected) {
|
|
1321
|
+
// Remove from selection
|
|
1322
|
+
newSelected = { ...selected };
|
|
1323
|
+
delete newSelected[rowId];
|
|
1324
|
+
} else {
|
|
1325
|
+
// Add to selection
|
|
1326
|
+
newSelected = {
|
|
1327
|
+
...selected,
|
|
1328
|
+
[rowId]: rowProps.data,
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
setSelected(newSelected);
|
|
1333
|
+
if (setRowsSelected) {
|
|
1334
|
+
setRowsSelected(newSelected);
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
return; // Don't call the original onClick
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
// If clicking directly on checkbox input, let ReactDataGrid handle it
|
|
1341
|
+
if (onClick) {
|
|
1342
|
+
onClick(event);
|
|
1343
|
+
}
|
|
1344
|
+
} else {
|
|
1345
|
+
// For non-checkbox columns, handle normal row clicks
|
|
1346
|
+
onRowClick(rowProps, event);
|
|
1347
|
+
|
|
1348
|
+
// Call the original onClick handler
|
|
1349
|
+
if (onClick) {
|
|
1350
|
+
onClick(event);
|
|
1351
|
+
}
|
|
1169
1352
|
}
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1353
|
+
};
|
|
1354
|
+
},
|
|
1355
|
+
[selected, setRowsSelected]
|
|
1356
|
+
);
|
|
1173
1357
|
|
|
1174
1358
|
const exportTrigger = async () => {
|
|
1175
1359
|
try {
|
|
@@ -1403,14 +1587,29 @@ const DataGrid = forwardRef(
|
|
|
1403
1587
|
);
|
|
1404
1588
|
};
|
|
1405
1589
|
|
|
1406
|
-
|
|
1590
|
+
// Helper function to determine if auto refresh should be relocated
|
|
1591
|
+
const shouldRelocateAutoRefresh = () => {
|
|
1592
|
+
const isSearchDisabled = form.searchDisable === true;
|
|
1593
|
+
const isCreateDisabled = form.createDisable === true;
|
|
1594
|
+
const hasAutoRefresh =
|
|
1595
|
+
ajaxSetting && ajaxSetting.autoRefresh !== undefined;
|
|
1596
|
+
|
|
1597
|
+
// Relocate only if auto refresh is the sole control (no search, no create button)
|
|
1598
|
+
return hasAutoRefresh && isSearchDisabled && isCreateDisabled;
|
|
1599
|
+
};
|
|
1600
|
+
|
|
1601
|
+
const renderAutoRefreshControls = (isRelocated = false) => {
|
|
1407
1602
|
// Only show auto-refresh if the setting is present in ajaxSetting
|
|
1408
1603
|
if (!ajaxSetting || ajaxSetting.autoRefresh === undefined) {
|
|
1409
1604
|
return null;
|
|
1410
1605
|
}
|
|
1411
1606
|
|
|
1607
|
+
const containerClass = isRelocated
|
|
1608
|
+
? styles.autoRefreshContainerRelocated
|
|
1609
|
+
: styles.autoRefreshContainer;
|
|
1610
|
+
|
|
1412
1611
|
return (
|
|
1413
|
-
<div className={
|
|
1612
|
+
<div className={containerClass}>
|
|
1414
1613
|
<label className={styles.autoRefreshLabel}>
|
|
1415
1614
|
<input
|
|
1416
1615
|
type="checkbox"
|
|
@@ -1469,10 +1668,11 @@ const DataGrid = forwardRef(
|
|
|
1469
1668
|
'var(--light-bg-color, #f5f5f5)',
|
|
1470
1669
|
borderRadius: '4px',
|
|
1471
1670
|
padding: '4px',
|
|
1472
|
-
width: '
|
|
1473
|
-
height: '
|
|
1671
|
+
width: '28px',
|
|
1672
|
+
height: '28px',
|
|
1474
1673
|
boxShadow: '0 1px 2px rgba(0,0,0,0.05)',
|
|
1475
1674
|
margin: '0 1px',
|
|
1675
|
+
cursor: 'pointer',
|
|
1476
1676
|
}}
|
|
1477
1677
|
>
|
|
1478
1678
|
<img
|
|
@@ -1481,8 +1681,8 @@ const DataGrid = forwardRef(
|
|
|
1481
1681
|
data-tooltip-id="system-tooltip"
|
|
1482
1682
|
data-tooltip-content={tooltipContent}
|
|
1483
1683
|
style={{
|
|
1484
|
-
maxHeight: '
|
|
1485
|
-
maxWidth: '
|
|
1684
|
+
maxHeight: '20px',
|
|
1685
|
+
maxWidth: '20px',
|
|
1486
1686
|
objectFit: 'contain',
|
|
1487
1687
|
}}
|
|
1488
1688
|
/>
|
|
@@ -1517,10 +1717,11 @@ const DataGrid = forwardRef(
|
|
|
1517
1717
|
'var(--light-bg-color, #f5f5f5)',
|
|
1518
1718
|
borderRadius: '4px',
|
|
1519
1719
|
padding: '4px',
|
|
1520
|
-
width: '
|
|
1521
|
-
height: '
|
|
1720
|
+
width: '28px',
|
|
1721
|
+
height: '28px',
|
|
1522
1722
|
boxShadow: '0 1px 2px rgba(0,0,0,0.05)',
|
|
1523
1723
|
margin: '0 1px',
|
|
1724
|
+
cursor: 'pointer',
|
|
1524
1725
|
}}
|
|
1525
1726
|
>
|
|
1526
1727
|
<IconComponent
|
|
@@ -2064,7 +2265,14 @@ const DataGrid = forwardRef(
|
|
|
2064
2265
|
|
|
2065
2266
|
const value = `${addressValue} ${stateValue}`;
|
|
2066
2267
|
|
|
2067
|
-
return
|
|
2268
|
+
return (
|
|
2269
|
+
<CellWithTooltip
|
|
2270
|
+
value={value}
|
|
2271
|
+
columnType="address"
|
|
2272
|
+
>
|
|
2273
|
+
<span>{value}</span>
|
|
2274
|
+
</CellWithTooltip>
|
|
2275
|
+
);
|
|
2068
2276
|
},
|
|
2069
2277
|
};
|
|
2070
2278
|
case 'age':
|
|
@@ -2121,11 +2329,17 @@ const DataGrid = forwardRef(
|
|
|
2121
2329
|
name: `${column.type}.${column.id}`,
|
|
2122
2330
|
sortable: false,
|
|
2123
2331
|
render: ({ data }) => {
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2332
|
+
const value = data[column.id]
|
|
2333
|
+
? 'Yes'
|
|
2334
|
+
: 'No';
|
|
2335
|
+
return (
|
|
2336
|
+
<CellWithTooltip
|
|
2337
|
+
value={data[column.id]}
|
|
2338
|
+
columnType="boolean"
|
|
2339
|
+
>
|
|
2340
|
+
<span>{value}</span>
|
|
2341
|
+
</CellWithTooltip>
|
|
2342
|
+
);
|
|
2129
2343
|
},
|
|
2130
2344
|
};
|
|
2131
2345
|
case 'coding':
|
|
@@ -2209,7 +2423,14 @@ const DataGrid = forwardRef(
|
|
|
2209
2423
|
data[column.id]
|
|
2210
2424
|
).format('$0,0.00');
|
|
2211
2425
|
|
|
2212
|
-
return
|
|
2426
|
+
return (
|
|
2427
|
+
<CellWithTooltip
|
|
2428
|
+
value={data[column.id]}
|
|
2429
|
+
columnType="currency"
|
|
2430
|
+
>
|
|
2431
|
+
<span>{data}</span>
|
|
2432
|
+
</CellWithTooltip>
|
|
2433
|
+
);
|
|
2213
2434
|
} else {
|
|
2214
2435
|
return null;
|
|
2215
2436
|
}
|
|
@@ -2259,9 +2480,14 @@ const DataGrid = forwardRef(
|
|
|
2259
2480
|
}
|
|
2260
2481
|
|
|
2261
2482
|
return (
|
|
2262
|
-
<
|
|
2263
|
-
{
|
|
2264
|
-
|
|
2483
|
+
<CellWithTooltip
|
|
2484
|
+
value={data[column.id]}
|
|
2485
|
+
columnType="date"
|
|
2486
|
+
>
|
|
2487
|
+
<span style={columnStyle}>
|
|
2488
|
+
{value}
|
|
2489
|
+
</span>
|
|
2490
|
+
</CellWithTooltip>
|
|
2265
2491
|
);
|
|
2266
2492
|
} else {
|
|
2267
2493
|
return null;
|
|
@@ -2382,7 +2608,13 @@ const DataGrid = forwardRef(
|
|
|
2382
2608
|
}}
|
|
2383
2609
|
>
|
|
2384
2610
|
<option value="">
|
|
2385
|
-
Select
|
|
2611
|
+
Select{' '}
|
|
2612
|
+
{/^[aeiouAEIOU]/.test(
|
|
2613
|
+
column.label
|
|
2614
|
+
)
|
|
2615
|
+
? 'an'
|
|
2616
|
+
: 'a'}{' '}
|
|
2617
|
+
{column.label}
|
|
2386
2618
|
</option>
|
|
2387
2619
|
{dropdownData[column.id] &&
|
|
2388
2620
|
dropdownData[column.id].length >
|
|
@@ -2436,7 +2668,7 @@ const DataGrid = forwardRef(
|
|
|
2436
2668
|
data-tooltip-id={`system-tooltip`}
|
|
2437
2669
|
data-tooltip-content={`Download File ${file.file_name}`}
|
|
2438
2670
|
strokeWidth={2}
|
|
2439
|
-
size={
|
|
2671
|
+
size={14}
|
|
2440
2672
|
className={
|
|
2441
2673
|
styles.tdaction
|
|
2442
2674
|
}
|
|
@@ -2468,7 +2700,7 @@ const DataGrid = forwardRef(
|
|
|
2468
2700
|
.file_name
|
|
2469
2701
|
}`}
|
|
2470
2702
|
strokeWidth={2}
|
|
2471
|
-
size={
|
|
2703
|
+
size={14}
|
|
2472
2704
|
className={
|
|
2473
2705
|
styles.tdaction
|
|
2474
2706
|
}
|
|
@@ -2553,7 +2785,14 @@ const DataGrid = forwardRef(
|
|
|
2553
2785
|
column.jsonData
|
|
2554
2786
|
];
|
|
2555
2787
|
|
|
2556
|
-
return
|
|
2788
|
+
return (
|
|
2789
|
+
<CellWithTooltip
|
|
2790
|
+
value={data}
|
|
2791
|
+
columnType="json"
|
|
2792
|
+
>
|
|
2793
|
+
<span>{data}</span>
|
|
2794
|
+
</CellWithTooltip>
|
|
2795
|
+
);
|
|
2557
2796
|
} else {
|
|
2558
2797
|
return null;
|
|
2559
2798
|
}
|
|
@@ -2599,7 +2838,14 @@ const DataGrid = forwardRef(
|
|
|
2599
2838
|
];
|
|
2600
2839
|
}
|
|
2601
2840
|
|
|
2602
|
-
return
|
|
2841
|
+
return (
|
|
2842
|
+
<CellWithTooltip
|
|
2843
|
+
value={newData}
|
|
2844
|
+
columnType="option"
|
|
2845
|
+
>
|
|
2846
|
+
<span>{newData}</span>
|
|
2847
|
+
</CellWithTooltip>
|
|
2848
|
+
);
|
|
2603
2849
|
} else {
|
|
2604
2850
|
return null;
|
|
2605
2851
|
}
|
|
@@ -2613,9 +2859,14 @@ const DataGrid = forwardRef(
|
|
|
2613
2859
|
render: ({ data }) => {
|
|
2614
2860
|
if (data) {
|
|
2615
2861
|
return (
|
|
2616
|
-
<
|
|
2617
|
-
{column.placeholder}
|
|
2618
|
-
|
|
2862
|
+
<CellWithTooltip
|
|
2863
|
+
value={column.placeholder}
|
|
2864
|
+
columnType="placeholder"
|
|
2865
|
+
>
|
|
2866
|
+
<span>
|
|
2867
|
+
{column.placeholder}
|
|
2868
|
+
</span>
|
|
2869
|
+
</CellWithTooltip>
|
|
2619
2870
|
);
|
|
2620
2871
|
} else {
|
|
2621
2872
|
return null;
|
|
@@ -2703,7 +2954,14 @@ const DataGrid = forwardRef(
|
|
|
2703
2954
|
typeof value === 'string' ||
|
|
2704
2955
|
typeof value === 'number'
|
|
2705
2956
|
) {
|
|
2706
|
-
return
|
|
2957
|
+
return (
|
|
2958
|
+
<CellWithTooltip
|
|
2959
|
+
value={value}
|
|
2960
|
+
columnType="relation"
|
|
2961
|
+
>
|
|
2962
|
+
<span>{value}</span>
|
|
2963
|
+
</CellWithTooltip>
|
|
2964
|
+
);
|
|
2707
2965
|
} else {
|
|
2708
2966
|
return null;
|
|
2709
2967
|
}
|
|
@@ -2854,7 +3112,14 @@ const DataGrid = forwardRef(
|
|
|
2854
3112
|
result += values.join('<br />');
|
|
2855
3113
|
}
|
|
2856
3114
|
|
|
2857
|
-
return
|
|
3115
|
+
return (
|
|
3116
|
+
<CellWithTooltip
|
|
3117
|
+
value={result}
|
|
3118
|
+
columnType="relationArray"
|
|
3119
|
+
>
|
|
3120
|
+
<span>{parse(result)}</span>
|
|
3121
|
+
</CellWithTooltip>
|
|
3122
|
+
);
|
|
2858
3123
|
// }
|
|
2859
3124
|
} else {
|
|
2860
3125
|
let result = '';
|
|
@@ -2885,7 +3150,14 @@ const DataGrid = forwardRef(
|
|
|
2885
3150
|
: '';
|
|
2886
3151
|
}
|
|
2887
3152
|
|
|
2888
|
-
return
|
|
3153
|
+
return (
|
|
3154
|
+
<CellWithTooltip
|
|
3155
|
+
value={result}
|
|
3156
|
+
columnType="relationArray"
|
|
3157
|
+
>
|
|
3158
|
+
<span>{parse(result)}</span>
|
|
3159
|
+
</CellWithTooltip>
|
|
3160
|
+
);
|
|
2889
3161
|
}
|
|
2890
3162
|
|
|
2891
3163
|
return null;
|
|
@@ -2898,9 +3170,14 @@ const DataGrid = forwardRef(
|
|
|
2898
3170
|
render: ({ data }) => {
|
|
2899
3171
|
if (data && data[column.id]) {
|
|
2900
3172
|
return (
|
|
2901
|
-
<
|
|
2902
|
-
{
|
|
2903
|
-
|
|
3173
|
+
<CellWithTooltip
|
|
3174
|
+
value={data[column.id]}
|
|
3175
|
+
columnType="richtext"
|
|
3176
|
+
>
|
|
3177
|
+
<span>
|
|
3178
|
+
{parse(data[column.id])}
|
|
3179
|
+
</span>
|
|
3180
|
+
</CellWithTooltip>
|
|
2904
3181
|
);
|
|
2905
3182
|
} else {
|
|
2906
3183
|
return null;
|
|
@@ -2921,7 +3198,14 @@ const DataGrid = forwardRef(
|
|
|
2921
3198
|
}
|
|
2922
3199
|
});
|
|
2923
3200
|
|
|
2924
|
-
return
|
|
3201
|
+
return (
|
|
3202
|
+
<CellWithTooltip
|
|
3203
|
+
value={stage}
|
|
3204
|
+
columnType="stage"
|
|
3205
|
+
>
|
|
3206
|
+
<span>{stage}</span>
|
|
3207
|
+
</CellWithTooltip>
|
|
3208
|
+
);
|
|
2925
3209
|
},
|
|
2926
3210
|
};
|
|
2927
3211
|
case 'time':
|
|
@@ -2945,7 +3229,14 @@ const DataGrid = forwardRef(
|
|
|
2945
3229
|
: 'hh:mm A'
|
|
2946
3230
|
);
|
|
2947
3231
|
|
|
2948
|
-
return
|
|
3232
|
+
return (
|
|
3233
|
+
<CellWithTooltip
|
|
3234
|
+
value={data[column.id]}
|
|
3235
|
+
columnType="time"
|
|
3236
|
+
>
|
|
3237
|
+
<span>{data}</span>
|
|
3238
|
+
</CellWithTooltip>
|
|
3239
|
+
);
|
|
2949
3240
|
} else {
|
|
2950
3241
|
return null;
|
|
2951
3242
|
}
|
|
@@ -2972,7 +3263,14 @@ const DataGrid = forwardRef(
|
|
|
2972
3263
|
: 'DD-MM-YYYY hh:mm A'
|
|
2973
3264
|
);
|
|
2974
3265
|
|
|
2975
|
-
return
|
|
3266
|
+
return (
|
|
3267
|
+
<CellWithTooltip
|
|
3268
|
+
value={data[column.id]}
|
|
3269
|
+
columnType="timer"
|
|
3270
|
+
>
|
|
3271
|
+
<span>{data}</span>
|
|
3272
|
+
</CellWithTooltip>
|
|
3273
|
+
);
|
|
2976
3274
|
} else {
|
|
2977
3275
|
let shouldRenderButton = false;
|
|
2978
3276
|
|
|
@@ -3097,7 +3395,7 @@ const DataGrid = forwardRef(
|
|
|
3097
3395
|
data-tooltip-id="system-tooltip"
|
|
3098
3396
|
data-tooltip-content={`${column.label} Timer`}
|
|
3099
3397
|
strokeWidth={2}
|
|
3100
|
-
size={
|
|
3398
|
+
size={14}
|
|
3101
3399
|
style={{
|
|
3102
3400
|
color: 'white',
|
|
3103
3401
|
}}
|
|
@@ -3398,14 +3696,21 @@ const DataGrid = forwardRef(
|
|
|
3398
3696
|
render: ({ data }) => {
|
|
3399
3697
|
if (data && data[column.id]) {
|
|
3400
3698
|
return (
|
|
3401
|
-
<
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
>
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3699
|
+
<CellWithTooltip
|
|
3700
|
+
value={data[column.id]}
|
|
3701
|
+
columnType="url"
|
|
3702
|
+
>
|
|
3703
|
+
<span>
|
|
3704
|
+
<a
|
|
3705
|
+
href={
|
|
3706
|
+
data[column.id]
|
|
3707
|
+
}
|
|
3708
|
+
target="_blank"
|
|
3709
|
+
>
|
|
3710
|
+
Link
|
|
3711
|
+
</a>
|
|
3712
|
+
</span>
|
|
3713
|
+
</CellWithTooltip>
|
|
3409
3714
|
);
|
|
3410
3715
|
} else {
|
|
3411
3716
|
return null;
|
|
@@ -3537,7 +3842,14 @@ const DataGrid = forwardRef(
|
|
|
3537
3842
|
}
|
|
3538
3843
|
|
|
3539
3844
|
return (
|
|
3540
|
-
<
|
|
3845
|
+
<CellWithTooltip
|
|
3846
|
+
value={data[column.id]}
|
|
3847
|
+
columnType="text"
|
|
3848
|
+
>
|
|
3849
|
+
<span>
|
|
3850
|
+
{parse(content)}
|
|
3851
|
+
</span>
|
|
3852
|
+
</CellWithTooltip>
|
|
3541
3853
|
);
|
|
3542
3854
|
} else {
|
|
3543
3855
|
return null;
|
|
@@ -3771,7 +4083,7 @@ const DataGrid = forwardRef(
|
|
|
3771
4083
|
setLimit(ajaxSetting.take);
|
|
3772
4084
|
} else {
|
|
3773
4085
|
const calculateRows = (height) =>
|
|
3774
|
-
Math.floor((height - 100) /
|
|
4086
|
+
Math.floor((height - 100) / 32);
|
|
3775
4087
|
|
|
3776
4088
|
const rowCount = calculateRows(minHeight);
|
|
3777
4089
|
setLimit(rowCount);
|
|
@@ -3846,14 +4158,20 @@ const DataGrid = forwardRef(
|
|
|
3846
4158
|
}}
|
|
3847
4159
|
>
|
|
3848
4160
|
{/* Top container with search, action buttons, and auto-refresh */}
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
<div className={styles.
|
|
3854
|
-
{
|
|
4161
|
+
{/* Only show top container if there are controls to display */}
|
|
4162
|
+
{(renderSearch() ||
|
|
4163
|
+
(!shouldRelocateAutoRefresh() &&
|
|
4164
|
+
renderAutoRefreshControls())) && (
|
|
4165
|
+
<div className={styles.dataGridTopContainer}>
|
|
4166
|
+
<div className={styles.dataGridTopLeftContainer}>
|
|
4167
|
+
{renderSearch()}
|
|
4168
|
+
</div>
|
|
4169
|
+
<div className={styles.dataGridTopRightContainer}>
|
|
4170
|
+
{!shouldRelocateAutoRefresh() &&
|
|
4171
|
+
renderAutoRefreshControls()}
|
|
4172
|
+
</div>
|
|
3855
4173
|
</div>
|
|
3856
|
-
|
|
4174
|
+
)}
|
|
3857
4175
|
|
|
3858
4176
|
{/* DataGrid container with its own border */}
|
|
3859
4177
|
<div className={styles.dataGridContainer}>
|
|
@@ -3877,7 +4195,7 @@ const DataGrid = forwardRef(
|
|
|
3877
4195
|
}
|
|
3878
4196
|
headerProps={headerProps}
|
|
3879
4197
|
idProperty="id"
|
|
3880
|
-
minRowHeight={
|
|
4198
|
+
minRowHeight={32}
|
|
3881
4199
|
onFilterValueChange={(fv) => {
|
|
3882
4200
|
handleFilterChange(fv, filterValue);
|
|
3883
4201
|
}}
|
|
@@ -3911,9 +4229,26 @@ const DataGrid = forwardRef(
|
|
|
3911
4229
|
borderRadius: 'var(--br, 4px)',
|
|
3912
4230
|
overflow: 'hidden',
|
|
3913
4231
|
}}
|
|
4232
|
+
checkboxColumnProps={{
|
|
4233
|
+
width: 60,
|
|
4234
|
+
minWidth: 60,
|
|
4235
|
+
maxWidth: 60,
|
|
4236
|
+
resizable: false,
|
|
4237
|
+
sortable: false,
|
|
4238
|
+
headerAlign: 'center',
|
|
4239
|
+
textAlign: 'center',
|
|
4240
|
+
}}
|
|
3914
4241
|
/>
|
|
3915
4242
|
) : null}
|
|
3916
4243
|
</div>
|
|
4244
|
+
|
|
4245
|
+
{/* Relocated auto refresh control when it's the only control */}
|
|
4246
|
+
{shouldRelocateAutoRefresh() && (
|
|
4247
|
+
<div className={styles.dataGridBottomContainer}>
|
|
4248
|
+
{renderAutoRefreshControls(true)}
|
|
4249
|
+
</div>
|
|
4250
|
+
)}
|
|
4251
|
+
|
|
3917
4252
|
{audioSource && <audio src={audioSource} ref={audioRef} />}
|
|
3918
4253
|
<Popup
|
|
3919
4254
|
open={modalShow}
|
|
@@ -3923,25 +4258,44 @@ const DataGrid = forwardRef(
|
|
|
3923
4258
|
width: windowWidth < 768 ? '95vw' : '80vw',
|
|
3924
4259
|
minWidth: windowWidth < 768 ? '95vw' : '600px',
|
|
3925
4260
|
maxWidth: '1200px',
|
|
4261
|
+
...(formData.verticalAlign === 'top' && {
|
|
4262
|
+
position: 'fixed',
|
|
4263
|
+
top: '5vh',
|
|
4264
|
+
left: '50%',
|
|
4265
|
+
transform: 'translateX(-50%)',
|
|
4266
|
+
margin: '0',
|
|
4267
|
+
}),
|
|
3926
4268
|
}}
|
|
3927
4269
|
nested
|
|
3928
4270
|
>
|
|
3929
|
-
<
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
4271
|
+
<div
|
|
4272
|
+
className={`${styles.modalwrap} ${
|
|
4273
|
+
styles['top--modal']
|
|
4274
|
+
} ${styles.modalWide} ${
|
|
4275
|
+
formData.verticalAlign === 'top'
|
|
4276
|
+
? 'modal-top-aligned'
|
|
4277
|
+
: ''
|
|
4278
|
+
}`}
|
|
4279
|
+
>
|
|
4280
|
+
<div className={styles.modal}>
|
|
4281
|
+
<Form
|
|
4282
|
+
ajaxSetting={ajaxSetting}
|
|
4283
|
+
api={api}
|
|
4284
|
+
closeModal={modalClose}
|
|
4285
|
+
columnId={formId}
|
|
4286
|
+
fetchTable={handleReload}
|
|
4287
|
+
formSettings={formData}
|
|
4288
|
+
formType={formType}
|
|
4289
|
+
gridRef={gridRef}
|
|
4290
|
+
mapbox={mapbox}
|
|
4291
|
+
modalOpen={modalOpen}
|
|
4292
|
+
paramValue={paramValue}
|
|
4293
|
+
style={style}
|
|
4294
|
+
updateForm={setFormData}
|
|
4295
|
+
userProfile={userProfile}
|
|
4296
|
+
/>
|
|
4297
|
+
</div>
|
|
4298
|
+
</div>
|
|
3945
4299
|
</Popup>
|
|
3946
4300
|
<Popup
|
|
3947
4301
|
open={modalGalleryShow}
|