@visns-studio/visns-components 5.12.12 → 5.12.14
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/package.json
CHANGED
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
88
88
|
},
|
|
89
89
|
"name": "@visns-studio/visns-components",
|
|
90
|
-
"version": "5.12.
|
|
90
|
+
"version": "5.12.14",
|
|
91
91
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
92
92
|
"main": "src/index.js",
|
|
93
93
|
"files": [
|
|
@@ -10,6 +10,64 @@ import CustomFetch from '../Fetch';
|
|
|
10
10
|
import MultiSelect from '../MultiSelect';
|
|
11
11
|
import styles from '../styles/GenericEditableTable.module.scss';
|
|
12
12
|
|
|
13
|
+
// Simple Tooltip Component
|
|
14
|
+
const Tooltip = ({ children, text, position = 'top' }) => {
|
|
15
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
16
|
+
const [coords, setCoords] = useState({ x: 0, y: 0 });
|
|
17
|
+
const elementRef = useRef(null);
|
|
18
|
+
|
|
19
|
+
const handleMouseEnter = () => {
|
|
20
|
+
if (!elementRef.current) return;
|
|
21
|
+
const rect = elementRef.current.getBoundingClientRect();
|
|
22
|
+
const scrollLeft =
|
|
23
|
+
window.pageXOffset || document.documentElement.scrollLeft;
|
|
24
|
+
const scrollTop =
|
|
25
|
+
window.pageYOffset || document.documentElement.scrollTop;
|
|
26
|
+
|
|
27
|
+
let x = rect.left + scrollLeft + rect.width / 2;
|
|
28
|
+
let y = rect.top + scrollTop;
|
|
29
|
+
|
|
30
|
+
if (position === 'bottom') {
|
|
31
|
+
y = rect.bottom + scrollTop + 5;
|
|
32
|
+
} else if (position === 'top') {
|
|
33
|
+
y = y - 5;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
setCoords({ x, y });
|
|
37
|
+
setIsVisible(true);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const handleMouseLeave = () => {
|
|
41
|
+
setIsVisible(false);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<span
|
|
46
|
+
ref={elementRef}
|
|
47
|
+
onMouseEnter={handleMouseEnter}
|
|
48
|
+
onMouseLeave={handleMouseLeave}
|
|
49
|
+
className={styles.tooltipContainer}
|
|
50
|
+
>
|
|
51
|
+
{children}
|
|
52
|
+
{isVisible &&
|
|
53
|
+
ReactDOM.createPortal(
|
|
54
|
+
<div
|
|
55
|
+
className={`${styles.tooltip} ${
|
|
56
|
+
styles[`tooltip-${position}`]
|
|
57
|
+
}`}
|
|
58
|
+
style={{
|
|
59
|
+
left: coords.x,
|
|
60
|
+
top: coords.y,
|
|
61
|
+
}}
|
|
62
|
+
>
|
|
63
|
+
{text}
|
|
64
|
+
</div>,
|
|
65
|
+
document.body
|
|
66
|
+
)}
|
|
67
|
+
</span>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
13
71
|
// Updated ColourPicker with an expanded pastel palette
|
|
14
72
|
const ColourPicker = ({ value, columnId, keyCounter, onChange }) => {
|
|
15
73
|
const [colorPickerShow, setColorPickerShow] = useState(false);
|
|
@@ -57,38 +115,47 @@ const ColourPicker = ({ value, columnId, keyCounter, onChange }) => {
|
|
|
57
115
|
return (
|
|
58
116
|
<div className={styles.cpicker}>
|
|
59
117
|
<div className={styles.cpicker__btn}>
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
118
|
+
<Tooltip text="Select color">
|
|
119
|
+
<button
|
|
120
|
+
ref={buttonRef}
|
|
121
|
+
style={
|
|
122
|
+
value
|
|
123
|
+
? {
|
|
124
|
+
background: value,
|
|
125
|
+
border: '1px solid rgba(0,0,0,0.2)',
|
|
126
|
+
borderRadius: '3px',
|
|
127
|
+
width: '20px',
|
|
128
|
+
height: '20px',
|
|
129
|
+
padding: '0',
|
|
130
|
+
cursor: 'pointer',
|
|
131
|
+
display: 'flex',
|
|
132
|
+
alignItems: 'center',
|
|
133
|
+
justifyContent: 'center',
|
|
134
|
+
}
|
|
135
|
+
: {
|
|
136
|
+
background: 'transparent',
|
|
137
|
+
border: '1px solid rgba(0,0,0,0.2)',
|
|
138
|
+
borderRadius: '3px',
|
|
139
|
+
width: '20px',
|
|
140
|
+
height: '20px',
|
|
141
|
+
padding: '0',
|
|
142
|
+
cursor: 'pointer',
|
|
143
|
+
display: 'flex',
|
|
144
|
+
alignItems: 'center',
|
|
145
|
+
justifyContent: 'center',
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
onClick={(e) => {
|
|
149
|
+
e.preventDefault();
|
|
150
|
+
setColorPickerShow(!colorPickerShow);
|
|
151
|
+
}}
|
|
152
|
+
>
|
|
153
|
+
<Droplets
|
|
154
|
+
size={18}
|
|
155
|
+
style={{ color: value ? 'white' : 'black' }}
|
|
156
|
+
/>
|
|
157
|
+
</button>
|
|
158
|
+
</Tooltip>
|
|
92
159
|
|
|
93
160
|
{colorPickerShow &&
|
|
94
161
|
ReactDOM.createPortal(
|
|
@@ -146,7 +213,7 @@ const GenericEditableTable = ({
|
|
|
146
213
|
const isInitialLoad = useRef(true);
|
|
147
214
|
const { columns, rows, form, title } = schedulingConfig;
|
|
148
215
|
const hasCategory = rows && rows.categoryKey; // Only group if defined
|
|
149
|
-
const hasColourColumn = columns.some(col => col.id === 'colours');
|
|
216
|
+
const hasColourColumn = columns.some((col) => col.id === 'colours');
|
|
150
217
|
|
|
151
218
|
// dataSets: each item => { created_at: string, data: array of rows }
|
|
152
219
|
const [dataSets, setDataSets] = useState([]);
|
|
@@ -158,6 +225,9 @@ const GenericEditableTable = ({
|
|
|
158
225
|
const [newEntries, setNewEntries] = useState({});
|
|
159
226
|
const [newEntry, setNewEntry] = useState({});
|
|
160
227
|
|
|
228
|
+
// Row selection state for copy functionality
|
|
229
|
+
const [selectedRows, setSelectedRows] = useState(new Set());
|
|
230
|
+
|
|
161
231
|
// On mount or when 'data' changes, read from data[schedulingConfig.rows.key] and handle both new & old formats
|
|
162
232
|
useEffect(() => {
|
|
163
233
|
const raw = data && data[schedulingConfig.rows.key];
|
|
@@ -220,6 +290,8 @@ const GenericEditableTable = ({
|
|
|
220
290
|
} else {
|
|
221
291
|
setLocalData([]);
|
|
222
292
|
}
|
|
293
|
+
// Clear selected rows when dataset changes
|
|
294
|
+
setSelectedRows(new Set());
|
|
223
295
|
}, [dataSets, activeDatasetIndex]);
|
|
224
296
|
|
|
225
297
|
// Helper to sort by sort_order
|
|
@@ -504,11 +576,50 @@ const GenericEditableTable = ({
|
|
|
504
576
|
return hasCategory ? groupCategoriesByType(localData) : [];
|
|
505
577
|
}, [localData, hasCategory]);
|
|
506
578
|
|
|
507
|
-
// 5)
|
|
579
|
+
// 5) Row selection handlers
|
|
580
|
+
const handleRowSelection = (rowId, isChecked) => {
|
|
581
|
+
setSelectedRows((prev) => {
|
|
582
|
+
const newSelected = new Set(prev);
|
|
583
|
+
if (isChecked) {
|
|
584
|
+
newSelected.add(rowId);
|
|
585
|
+
} else {
|
|
586
|
+
newSelected.delete(rowId);
|
|
587
|
+
}
|
|
588
|
+
return newSelected;
|
|
589
|
+
});
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
const handleSelectAll = (isChecked, dataToSelect = null) => {
|
|
593
|
+
if (isChecked) {
|
|
594
|
+
const rowIds = dataToSelect
|
|
595
|
+
? dataToSelect.map((entry) => entry.id)
|
|
596
|
+
: localData.map((entry) => entry.id);
|
|
597
|
+
setSelectedRows(new Set(rowIds));
|
|
598
|
+
} else {
|
|
599
|
+
setSelectedRows(new Set());
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
const isAllSelected = (dataToCheck = null) => {
|
|
604
|
+
const dataSet = dataToCheck || localData;
|
|
605
|
+
return (
|
|
606
|
+
dataSet.length > 0 &&
|
|
607
|
+
dataSet.every((entry) => selectedRows.has(entry.id))
|
|
608
|
+
);
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
// 6) Enhanced column copy with row selection
|
|
508
612
|
const handleColumnCopy = (column, group = null) => {
|
|
509
|
-
let
|
|
510
|
-
|
|
511
|
-
|
|
613
|
+
let dataToProcess = group ? group.entries : localData;
|
|
614
|
+
|
|
615
|
+
// Filter by selected rows if any are selected
|
|
616
|
+
if (selectedRows.size > 0) {
|
|
617
|
+
dataToProcess = dataToProcess.filter((entry) =>
|
|
618
|
+
selectedRows.has(entry.id)
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
let values = dataToProcess.map((entry) => entry[column.id]);
|
|
512
623
|
|
|
513
624
|
const textToCopy = values
|
|
514
625
|
.filter((val) => val !== undefined && val !== null)
|
|
@@ -516,19 +627,23 @@ const GenericEditableTable = ({
|
|
|
516
627
|
|
|
517
628
|
navigator.clipboard
|
|
518
629
|
.writeText(textToCopy)
|
|
519
|
-
.then(() =>
|
|
630
|
+
.then(() => {
|
|
631
|
+
const selectionInfo =
|
|
632
|
+
selectedRows.size > 0
|
|
633
|
+
? ` (${selectedRows.size} selected rows)`
|
|
634
|
+
: ' (all rows)';
|
|
520
635
|
toast.success(
|
|
521
636
|
`Copied ${values.length} value${
|
|
522
637
|
values.length !== 1 ? 's' : ''
|
|
523
638
|
} from "${column.label}"${
|
|
524
639
|
group ? ` (Group: ${group.category})` : ''
|
|
525
|
-
}`
|
|
526
|
-
)
|
|
527
|
-
)
|
|
640
|
+
}${selectionInfo}`
|
|
641
|
+
);
|
|
642
|
+
})
|
|
528
643
|
.catch(() => toast.error('Failed to copy to clipboard'));
|
|
529
644
|
};
|
|
530
645
|
|
|
531
|
-
//
|
|
646
|
+
// 7) Sorting: grouped
|
|
532
647
|
const handleSortChangeGrouped = (groupId, entryId, direction) => {
|
|
533
648
|
if (!hasCategory) return;
|
|
534
649
|
setLocalData((prev) => {
|
|
@@ -580,7 +695,7 @@ const GenericEditableTable = ({
|
|
|
580
695
|
});
|
|
581
696
|
};
|
|
582
697
|
|
|
583
|
-
//
|
|
698
|
+
// 8) Sorting: ungrouped
|
|
584
699
|
const handleSortChangeUngrouped = (entryId, direction) => {
|
|
585
700
|
setLocalData((prev) => {
|
|
586
701
|
const sortedData = sortBySortOrder(prev);
|
|
@@ -611,7 +726,7 @@ const GenericEditableTable = ({
|
|
|
611
726
|
});
|
|
612
727
|
};
|
|
613
728
|
|
|
614
|
-
//
|
|
729
|
+
// 9) Deletion
|
|
615
730
|
const handleDeleteRow = (entry) => {
|
|
616
731
|
confirmDialog({
|
|
617
732
|
title: 'Confirm to Delete',
|
|
@@ -784,7 +899,7 @@ const GenericEditableTable = ({
|
|
|
784
899
|
// Render new row field
|
|
785
900
|
const renderNewRowField = (newRowData, column, groupId = null) => {
|
|
786
901
|
const value = newRowData ? newRowData[column.id] : '';
|
|
787
|
-
|
|
902
|
+
|
|
788
903
|
// Special handling for colours column regardless of type
|
|
789
904
|
if (column.id === 'colours') {
|
|
790
905
|
return (
|
|
@@ -800,7 +915,7 @@ const GenericEditableTable = ({
|
|
|
800
915
|
/>
|
|
801
916
|
);
|
|
802
917
|
}
|
|
803
|
-
|
|
918
|
+
|
|
804
919
|
switch (column.type) {
|
|
805
920
|
case 'colour':
|
|
806
921
|
// For other colour columns, picker is rendered in the action column
|
|
@@ -921,6 +1036,7 @@ const GenericEditableTable = ({
|
|
|
921
1036
|
const newRowData = hasCategory ? newEntries[groupId] || {} : newEntry;
|
|
922
1037
|
return (
|
|
923
1038
|
<tr className={styles.newRow}>
|
|
1039
|
+
<td className={styles.checkboxColumn}></td>
|
|
924
1040
|
{columns.map((column) => (
|
|
925
1041
|
<td
|
|
926
1042
|
key={column.id}
|
|
@@ -946,6 +1062,51 @@ const GenericEditableTable = ({
|
|
|
946
1062
|
);
|
|
947
1063
|
};
|
|
948
1064
|
|
|
1065
|
+
// Checkbox column header
|
|
1066
|
+
const renderSelectAllCheckbox = (group = null) => (
|
|
1067
|
+
<th
|
|
1068
|
+
key="select-all"
|
|
1069
|
+
className={styles.checkboxColumn}
|
|
1070
|
+
onClick={() => {
|
|
1071
|
+
const currentlyAllSelected = isAllSelected(group?.entries);
|
|
1072
|
+
handleSelectAll(!currentlyAllSelected, group?.entries);
|
|
1073
|
+
}}
|
|
1074
|
+
style={{ cursor: 'pointer' }}
|
|
1075
|
+
title={
|
|
1076
|
+
group ? `Select all in ${group.category}` : 'Select all rows'
|
|
1077
|
+
}
|
|
1078
|
+
>
|
|
1079
|
+
<input
|
|
1080
|
+
type="checkbox"
|
|
1081
|
+
checked={isAllSelected(group?.entries)}
|
|
1082
|
+
onChange={() => {}} // Empty handler since we handle click on the cell
|
|
1083
|
+
style={{ cursor: 'pointer', pointerEvents: 'none' }}
|
|
1084
|
+
tabIndex={-1}
|
|
1085
|
+
/>
|
|
1086
|
+
</th>
|
|
1087
|
+
);
|
|
1088
|
+
|
|
1089
|
+
// Row checkbox cell
|
|
1090
|
+
const renderRowCheckbox = (entry) => (
|
|
1091
|
+
<td
|
|
1092
|
+
key={`checkbox-${entry.id}`}
|
|
1093
|
+
className={styles.checkboxColumn}
|
|
1094
|
+
onClick={() => {
|
|
1095
|
+
const isCurrentlySelected = selectedRows.has(entry.id);
|
|
1096
|
+
handleRowSelection(entry.id, !isCurrentlySelected);
|
|
1097
|
+
}}
|
|
1098
|
+
style={{ cursor: 'pointer' }}
|
|
1099
|
+
>
|
|
1100
|
+
<input
|
|
1101
|
+
type="checkbox"
|
|
1102
|
+
checked={selectedRows.has(entry.id)}
|
|
1103
|
+
onChange={() => {}} // Empty handler since we handle click on the cell
|
|
1104
|
+
style={{ cursor: 'pointer', pointerEvents: 'none' }}
|
|
1105
|
+
tabIndex={-1}
|
|
1106
|
+
/>
|
|
1107
|
+
</td>
|
|
1108
|
+
);
|
|
1109
|
+
|
|
949
1110
|
// Header cell with optional copy icon
|
|
950
1111
|
const renderHeaderCell = (column, group = null) => (
|
|
951
1112
|
<th
|
|
@@ -961,15 +1122,17 @@ const GenericEditableTable = ({
|
|
|
961
1122
|
>
|
|
962
1123
|
<span>{column.label}</span>
|
|
963
1124
|
{column.copy && (
|
|
964
|
-
<
|
|
965
|
-
|
|
966
|
-
e
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1125
|
+
<Tooltip text="Copy column data to clipboard">
|
|
1126
|
+
<span
|
|
1127
|
+
onClick={(e) => {
|
|
1128
|
+
e.stopPropagation();
|
|
1129
|
+
handleColumnCopy(column, group);
|
|
1130
|
+
}}
|
|
1131
|
+
style={{ cursor: 'pointer' }}
|
|
1132
|
+
>
|
|
1133
|
+
<Copy size={20} />
|
|
1134
|
+
</span>
|
|
1135
|
+
</Tooltip>
|
|
973
1136
|
)}
|
|
974
1137
|
</div>
|
|
975
1138
|
</th>
|
|
@@ -1027,11 +1190,12 @@ const GenericEditableTable = ({
|
|
|
1027
1190
|
{groupedCategories.map((group) => (
|
|
1028
1191
|
<React.Fragment key={group.id}>
|
|
1029
1192
|
<tr className={styles.categoryRow}>
|
|
1030
|
-
<td colSpan={columns.length +
|
|
1193
|
+
<td colSpan={columns.length + 2}>
|
|
1031
1194
|
{group.category}
|
|
1032
1195
|
</td>
|
|
1033
1196
|
</tr>
|
|
1034
1197
|
<tr>
|
|
1198
|
+
{renderSelectAllCheckbox(group)}
|
|
1035
1199
|
{columns.map((column) =>
|
|
1036
1200
|
renderHeaderCell(column, group)
|
|
1037
1201
|
)}
|
|
@@ -1046,6 +1210,7 @@ const GenericEditableTable = ({
|
|
|
1046
1210
|
getRowBackground(entry),
|
|
1047
1211
|
}}
|
|
1048
1212
|
>
|
|
1213
|
+
{renderRowCheckbox(entry)}
|
|
1049
1214
|
{columns.map((column) => (
|
|
1050
1215
|
<td
|
|
1051
1216
|
key={column.id}
|
|
@@ -1070,55 +1235,70 @@ const GenericEditableTable = ({
|
|
|
1070
1235
|
>
|
|
1071
1236
|
{!hasColourColumn && (
|
|
1072
1237
|
<ColourPicker
|
|
1073
|
-
value={
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1238
|
+
value={
|
|
1239
|
+
entry.row_colour ||
|
|
1240
|
+
''
|
|
1241
|
+
}
|
|
1242
|
+
columnId={
|
|
1243
|
+
'row_colour'
|
|
1244
|
+
}
|
|
1245
|
+
keyCounter={
|
|
1246
|
+
entry.keyCounter
|
|
1247
|
+
}
|
|
1248
|
+
onChange={
|
|
1249
|
+
handleFieldChange
|
|
1250
|
+
}
|
|
1077
1251
|
/>
|
|
1078
1252
|
)}
|
|
1079
1253
|
{idx > 0 && (
|
|
1080
|
-
<
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1254
|
+
<Tooltip text="Move up">
|
|
1255
|
+
<ArrowUp
|
|
1256
|
+
size={16}
|
|
1257
|
+
onClick={() =>
|
|
1258
|
+
handleSortChangeGrouped(
|
|
1259
|
+
group.id,
|
|
1260
|
+
entry.id,
|
|
1261
|
+
'up'
|
|
1262
|
+
)
|
|
1263
|
+
}
|
|
1264
|
+
style={{
|
|
1265
|
+
cursor: 'pointer',
|
|
1266
|
+
}}
|
|
1267
|
+
/>
|
|
1268
|
+
</Tooltip>
|
|
1093
1269
|
)}
|
|
1094
1270
|
{idx <
|
|
1095
1271
|
group.entries.length -
|
|
1096
1272
|
1 && (
|
|
1097
|
-
<
|
|
1273
|
+
<Tooltip text="Move down">
|
|
1274
|
+
<ArrowDown
|
|
1275
|
+
size={16}
|
|
1276
|
+
onClick={() =>
|
|
1277
|
+
handleSortChangeGrouped(
|
|
1278
|
+
group.id,
|
|
1279
|
+
entry.id,
|
|
1280
|
+
'down'
|
|
1281
|
+
)
|
|
1282
|
+
}
|
|
1283
|
+
style={{
|
|
1284
|
+
cursor: 'pointer',
|
|
1285
|
+
}}
|
|
1286
|
+
/>
|
|
1287
|
+
</Tooltip>
|
|
1288
|
+
)}
|
|
1289
|
+
<Tooltip text="Delete row">
|
|
1290
|
+
<Trash2
|
|
1098
1291
|
size={16}
|
|
1099
1292
|
onClick={() =>
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
entry.id,
|
|
1103
|
-
'down'
|
|
1293
|
+
handleDeleteRow(
|
|
1294
|
+
entry
|
|
1104
1295
|
)
|
|
1105
1296
|
}
|
|
1106
1297
|
style={{
|
|
1107
1298
|
cursor: 'pointer',
|
|
1108
1299
|
}}
|
|
1109
1300
|
/>
|
|
1110
|
-
|
|
1111
|
-
<Trash2
|
|
1112
|
-
size={16}
|
|
1113
|
-
onClick={() =>
|
|
1114
|
-
handleDeleteRow(
|
|
1115
|
-
entry
|
|
1116
|
-
)
|
|
1117
|
-
}
|
|
1118
|
-
style={{
|
|
1119
|
-
cursor: 'pointer',
|
|
1120
|
-
}}
|
|
1121
|
-
/>
|
|
1301
|
+
</Tooltip>
|
|
1122
1302
|
</div>
|
|
1123
1303
|
</td>
|
|
1124
1304
|
</tr>
|
|
@@ -1130,6 +1310,7 @@ const GenericEditableTable = ({
|
|
|
1130
1310
|
(col) => col.type === 'total'
|
|
1131
1311
|
) !== -1 && (
|
|
1132
1312
|
<tr className={styles.subtotalRow}>
|
|
1313
|
+
<td></td>
|
|
1133
1314
|
{columns.map((col, index) => {
|
|
1134
1315
|
const totalColIndex =
|
|
1135
1316
|
columns.findIndex(
|
|
@@ -1192,126 +1373,153 @@ const GenericEditableTable = ({
|
|
|
1192
1373
|
<table className={styles.schedulingTable}>
|
|
1193
1374
|
<thead>
|
|
1194
1375
|
<tr>
|
|
1376
|
+
{renderSelectAllCheckbox()}
|
|
1195
1377
|
{columns.map((column) => renderHeaderCell(column))}
|
|
1196
1378
|
<th style={{ width: '5%' }}></th>
|
|
1197
1379
|
</tr>
|
|
1198
1380
|
</thead>
|
|
1199
1381
|
<tbody>
|
|
1200
|
-
{localData.length > 0 &&
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1382
|
+
{localData.length > 0 &&
|
|
1383
|
+
sortBySortOrder(localData).map((entry, idx) => (
|
|
1384
|
+
<tr
|
|
1385
|
+
key={entry.id}
|
|
1386
|
+
style={{
|
|
1387
|
+
background: getRowBackground(entry),
|
|
1388
|
+
}}
|
|
1389
|
+
>
|
|
1390
|
+
{renderRowCheckbox(entry)}
|
|
1391
|
+
{columns.map((column) => (
|
|
1392
|
+
<td
|
|
1393
|
+
key={column.id}
|
|
1394
|
+
style={{
|
|
1395
|
+
width: column.width || 'auto',
|
|
1396
|
+
textAlign:
|
|
1397
|
+
column.type === 'currency'
|
|
1398
|
+
? 'right'
|
|
1399
|
+
: 'left',
|
|
1400
|
+
}}
|
|
1401
|
+
>
|
|
1402
|
+
{renderScheduledTableField(
|
|
1403
|
+
entry,
|
|
1404
|
+
column,
|
|
1405
|
+
idx
|
|
1406
|
+
)}
|
|
1407
|
+
</td>
|
|
1408
|
+
))}
|
|
1409
|
+
<td>
|
|
1410
|
+
<div className={styles.tdactions}>
|
|
1411
|
+
{!hasColourColumn && (
|
|
1412
|
+
<ColourPicker
|
|
1413
|
+
value={
|
|
1414
|
+
entry.row_colour || ''
|
|
1415
|
+
}
|
|
1416
|
+
columnId={'row_colour'}
|
|
1417
|
+
keyCounter={idx}
|
|
1418
|
+
onChange={handleFieldChange}
|
|
1419
|
+
/>
|
|
1420
|
+
)}
|
|
1421
|
+
{idx > 0 && (
|
|
1422
|
+
<Tooltip text="Move up">
|
|
1423
|
+
<ArrowUp
|
|
1424
|
+
size={16}
|
|
1425
|
+
onClick={() =>
|
|
1426
|
+
handleSortChangeUngrouped(
|
|
1427
|
+
entry.id,
|
|
1428
|
+
'up'
|
|
1429
|
+
)
|
|
1430
|
+
}
|
|
1431
|
+
style={{
|
|
1432
|
+
cursor: 'pointer',
|
|
1433
|
+
}}
|
|
1434
|
+
/>
|
|
1435
|
+
</Tooltip>
|
|
1436
|
+
)}
|
|
1437
|
+
{idx <
|
|
1438
|
+
sortBySortOrder(localData)
|
|
1439
|
+
.length -
|
|
1440
|
+
1 && (
|
|
1441
|
+
<Tooltip text="Move down">
|
|
1442
|
+
<ArrowDown
|
|
1443
|
+
size={16}
|
|
1444
|
+
onClick={() =>
|
|
1445
|
+
handleSortChangeUngrouped(
|
|
1446
|
+
entry.id,
|
|
1447
|
+
'down'
|
|
1448
|
+
)
|
|
1449
|
+
}
|
|
1450
|
+
style={{
|
|
1451
|
+
cursor: 'pointer',
|
|
1452
|
+
}}
|
|
1453
|
+
/>
|
|
1454
|
+
</Tooltip>
|
|
1455
|
+
)}
|
|
1456
|
+
<Tooltip text="Delete row">
|
|
1457
|
+
<Trash2
|
|
1458
|
+
size={16}
|
|
1459
|
+
onClick={() =>
|
|
1460
|
+
handleDeleteRow(entry)
|
|
1461
|
+
}
|
|
1462
|
+
style={{
|
|
1463
|
+
cursor: 'pointer',
|
|
1464
|
+
}}
|
|
1465
|
+
/>
|
|
1466
|
+
</Tooltip>
|
|
1467
|
+
</div>
|
|
1221
1468
|
</td>
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
<div className={styles.tdactions}>
|
|
1225
|
-
{!hasColourColumn && (
|
|
1226
|
-
<ColourPicker
|
|
1227
|
-
value={entry.row_colour || ''}
|
|
1228
|
-
columnId={'row_colour'}
|
|
1229
|
-
keyCounter={idx}
|
|
1230
|
-
onChange={handleFieldChange}
|
|
1231
|
-
/>
|
|
1232
|
-
)}
|
|
1233
|
-
{idx > 0 && (
|
|
1234
|
-
<ArrowUp
|
|
1235
|
-
size={16}
|
|
1236
|
-
onClick={() =>
|
|
1237
|
-
handleSortChangeUngrouped(
|
|
1238
|
-
entry.id,
|
|
1239
|
-
'up'
|
|
1240
|
-
)
|
|
1241
|
-
}
|
|
1242
|
-
style={{ cursor: 'pointer' }}
|
|
1243
|
-
/>
|
|
1244
|
-
)}
|
|
1245
|
-
{idx <
|
|
1246
|
-
sortBySortOrder(localData).length -
|
|
1247
|
-
1 && (
|
|
1248
|
-
<ArrowDown
|
|
1249
|
-
size={16}
|
|
1250
|
-
onClick={() =>
|
|
1251
|
-
handleSortChangeUngrouped(
|
|
1252
|
-
entry.id,
|
|
1253
|
-
'down'
|
|
1254
|
-
)
|
|
1255
|
-
}
|
|
1256
|
-
style={{ cursor: 'pointer' }}
|
|
1257
|
-
/>
|
|
1258
|
-
)}
|
|
1259
|
-
<Trash2
|
|
1260
|
-
size={16}
|
|
1261
|
-
onClick={() =>
|
|
1262
|
-
handleDeleteRow(entry)
|
|
1263
|
-
}
|
|
1264
|
-
style={{ cursor: 'pointer' }}
|
|
1265
|
-
/>
|
|
1266
|
-
</div>
|
|
1267
|
-
</td>
|
|
1268
|
-
</tr>
|
|
1269
|
-
))}
|
|
1469
|
+
</tr>
|
|
1470
|
+
))}
|
|
1270
1471
|
|
|
1271
1472
|
{renderNewRowForm()}
|
|
1272
1473
|
|
|
1273
|
-
{localData.length > 0 &&
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
{
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
index === totalColIndex - 1 &&
|
|
1282
|
-
index > 0
|
|
1283
|
-
) {
|
|
1284
|
-
return <td key={col.id}>Subtotal</td>;
|
|
1285
|
-
}
|
|
1286
|
-
if (index === totalColIndex) {
|
|
1287
|
-
const overallTotal = sortBySortOrder(
|
|
1288
|
-
localData
|
|
1289
|
-
).reduce(
|
|
1290
|
-
(sum, entry) =>
|
|
1291
|
-
sum +
|
|
1292
|
-
calculateTotal(
|
|
1293
|
-
entry,
|
|
1294
|
-
columns[totalColIndex].keys
|
|
1295
|
-
),
|
|
1296
|
-
0
|
|
1297
|
-
);
|
|
1298
|
-
return (
|
|
1299
|
-
<td key={col.id}>
|
|
1300
|
-
{overallTotal.toLocaleString(
|
|
1301
|
-
'en-AU',
|
|
1302
|
-
{
|
|
1303
|
-
style: 'currency',
|
|
1304
|
-
currency: 'AUD',
|
|
1305
|
-
}
|
|
1306
|
-
)}
|
|
1307
|
-
</td>
|
|
1474
|
+
{localData.length > 0 &&
|
|
1475
|
+
columns.findIndex((col) => col.type === 'total') !==
|
|
1476
|
+
-1 && (
|
|
1477
|
+
<tr className={styles.subtotalRow}>
|
|
1478
|
+
<td></td>
|
|
1479
|
+
{columns.map((col, index) => {
|
|
1480
|
+
const totalColIndex = columns.findIndex(
|
|
1481
|
+
(c) => c.type === 'total'
|
|
1308
1482
|
);
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1483
|
+
if (
|
|
1484
|
+
index === totalColIndex - 1 &&
|
|
1485
|
+
index > 0
|
|
1486
|
+
) {
|
|
1487
|
+
return (
|
|
1488
|
+
<td key={col.id}>Subtotal</td>
|
|
1489
|
+
);
|
|
1490
|
+
}
|
|
1491
|
+
if (index === totalColIndex) {
|
|
1492
|
+
const overallTotal =
|
|
1493
|
+
sortBySortOrder(
|
|
1494
|
+
localData
|
|
1495
|
+
).reduce(
|
|
1496
|
+
(sum, entry) =>
|
|
1497
|
+
sum +
|
|
1498
|
+
calculateTotal(
|
|
1499
|
+
entry,
|
|
1500
|
+
columns[
|
|
1501
|
+
totalColIndex
|
|
1502
|
+
].keys
|
|
1503
|
+
),
|
|
1504
|
+
0
|
|
1505
|
+
);
|
|
1506
|
+
return (
|
|
1507
|
+
<td key={col.id}>
|
|
1508
|
+
{overallTotal.toLocaleString(
|
|
1509
|
+
'en-AU',
|
|
1510
|
+
{
|
|
1511
|
+
style: 'currency',
|
|
1512
|
+
currency: 'AUD',
|
|
1513
|
+
}
|
|
1514
|
+
)}
|
|
1515
|
+
</td>
|
|
1516
|
+
);
|
|
1517
|
+
}
|
|
1518
|
+
return <td key={col.id} />;
|
|
1519
|
+
})}
|
|
1520
|
+
<td></td>
|
|
1521
|
+
</tr>
|
|
1522
|
+
)}
|
|
1315
1523
|
</tbody>
|
|
1316
1524
|
</table>
|
|
1317
1525
|
)}
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
|
|
6
6
|
th,
|
|
7
7
|
td {
|
|
8
|
-
padding: 0.
|
|
8
|
+
padding: 0.4rem 0.5rem; // Increased padding for better readability
|
|
9
9
|
text-align: left;
|
|
10
10
|
border: 1px solid rgba(var(--primary-rgb), 0.1);
|
|
11
|
-
line-height: 1; //
|
|
11
|
+
line-height: 1.3; // Increased line height for better readability
|
|
12
12
|
vertical-align: middle; // Ensure vertical alignment
|
|
13
|
-
height:
|
|
13
|
+
height: 40px; // Increased row height
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// Additional high-specificity selectors to override any global styles
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
td select,
|
|
19
19
|
th input,
|
|
20
20
|
th select {
|
|
21
|
-
padding: 0.
|
|
21
|
+
padding: 0.3rem 0.5rem !important;
|
|
22
22
|
margin: 0 !important;
|
|
23
|
-
font-size: 0.
|
|
24
|
-
height:
|
|
25
|
-
line-height: 1 !important;
|
|
23
|
+
font-size: 0.9rem !important;
|
|
24
|
+
height: 32px !important;
|
|
25
|
+
line-height: 1.2 !important;
|
|
26
26
|
border: 1px solid rgba(var(--primary-rgb), 0.1) !important;
|
|
27
27
|
box-sizing: border-box !important;
|
|
28
|
-
border-radius:
|
|
28
|
+
border-radius: 4px !important;
|
|
29
29
|
width: 100% !important;
|
|
30
30
|
appearance: none !important;
|
|
31
31
|
background: white !important;
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
th select {
|
|
36
36
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><path d="M6 9L1 4h10z" fill="%23666"/></svg>') !important;
|
|
37
37
|
background-repeat: no-repeat !important;
|
|
38
|
-
background-position: right 0.
|
|
39
|
-
background-size:
|
|
40
|
-
padding: 0.
|
|
38
|
+
background-position: right 0.5rem center !important;
|
|
39
|
+
background-size: 10px !important;
|
|
40
|
+
padding: 0.3rem 1.5rem 0.3rem 0.5rem !important;
|
|
41
41
|
cursor: pointer !important;
|
|
42
42
|
|
|
43
43
|
&::-ms-expand {
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
th {
|
|
49
|
-
padding: 0.
|
|
50
|
-
font-size:
|
|
49
|
+
padding: 0.5rem 0.5rem; // Increased header padding
|
|
50
|
+
font-size: 1rem; // Larger font size for headers
|
|
51
51
|
font-weight: bold;
|
|
52
52
|
background-color: var(--primary-color);
|
|
53
53
|
color: white;
|
|
54
54
|
text-align: center;
|
|
55
|
-
height:
|
|
55
|
+
height: 45px; // Increased header height
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
td {
|
|
@@ -64,17 +64,17 @@
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
/*
|
|
67
|
+
/* Updated styling for native input and select elements */
|
|
68
68
|
input,
|
|
69
69
|
select {
|
|
70
|
-
padding: 0.
|
|
70
|
+
padding: 0.3rem 0.5rem !important; // Increased padding for better usability
|
|
71
71
|
margin: 0 !important;
|
|
72
|
-
font-size: 0.
|
|
73
|
-
height:
|
|
74
|
-
line-height: 1 !important;
|
|
72
|
+
font-size: 0.9rem !important; // Larger font size for readability
|
|
73
|
+
height: 32px !important; // Increased height
|
|
74
|
+
line-height: 1.2 !important;
|
|
75
75
|
border: 1px solid rgba(var(--primary-rgb), 0.1) !important;
|
|
76
76
|
box-sizing: border-box !important;
|
|
77
|
-
border-radius:
|
|
77
|
+
border-radius: 4px !important; // Larger border radius
|
|
78
78
|
width: 100% !important;
|
|
79
79
|
appearance: none !important; // Remove default dropdown arrow for consistency
|
|
80
80
|
background: white !important;
|
|
@@ -84,9 +84,9 @@
|
|
|
84
84
|
&:not([type]) {
|
|
85
85
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><path d="M6 9L1 4h10z" fill="%23666"/></svg>') !important;
|
|
86
86
|
background-repeat: no-repeat !important;
|
|
87
|
-
background-position: right 0.
|
|
88
|
-
background-size:
|
|
89
|
-
padding-right:
|
|
87
|
+
background-position: right 0.5rem center !important;
|
|
88
|
+
background-size: 10px !important;
|
|
89
|
+
padding-right: 1.5rem !important;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -96,9 +96,9 @@
|
|
|
96
96
|
background: white !important;
|
|
97
97
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><path d="M6 9L1 4h10z" fill="%23666"/></svg>') !important;
|
|
98
98
|
background-repeat: no-repeat !important;
|
|
99
|
-
background-position: right 0.
|
|
100
|
-
background-size:
|
|
101
|
-
padding: 0.
|
|
99
|
+
background-position: right 0.5rem center !important;
|
|
100
|
+
background-size: 10px !important;
|
|
101
|
+
padding: 0.3rem 1.5rem 0.3rem 0.5rem !important; // Increased padding values
|
|
102
102
|
cursor: pointer !important;
|
|
103
103
|
|
|
104
104
|
// Remove default arrow on different browsers
|
|
@@ -233,19 +233,19 @@
|
|
|
233
233
|
width: max-content;
|
|
234
234
|
display: inline-block;
|
|
235
235
|
position: relative;
|
|
236
|
-
padding: 0.
|
|
236
|
+
padding: 0.4rem 0.8rem; /* Increased padding */
|
|
237
237
|
cursor: pointer;
|
|
238
|
-
font-size: 0.
|
|
238
|
+
font-size: 0.9rem; /* Larger font size */
|
|
239
239
|
color: var(--tertiary-color);
|
|
240
240
|
text-decoration: none;
|
|
241
241
|
overflow: hidden;
|
|
242
242
|
background: var(--primary-color);
|
|
243
243
|
border: 1px solid rgba(var(--primary-color--rgb), 1.1);
|
|
244
|
-
border-radius:
|
|
244
|
+
border-radius: 4px; /* Larger border radius */
|
|
245
245
|
outline: none;
|
|
246
246
|
transition: all 0.2s cubic-bezier(0.85, 0, 0.15, 1) 0s;
|
|
247
|
-
height:
|
|
248
|
-
line-height: 1;
|
|
247
|
+
height: 34px; /* Match input height */
|
|
248
|
+
line-height: 1.2;
|
|
249
249
|
display: flex;
|
|
250
250
|
align-items: center;
|
|
251
251
|
justify-content: center;
|
|
@@ -263,19 +263,19 @@
|
|
|
263
263
|
flex-wrap: nowrap;
|
|
264
264
|
justify-content: flex-start;
|
|
265
265
|
align-items: center;
|
|
266
|
-
gap: 0.
|
|
266
|
+
gap: 0.3rem; // Increased gap
|
|
267
267
|
background: transparent !important; /* Ensure no background color interference */
|
|
268
268
|
|
|
269
269
|
span {
|
|
270
270
|
display: flex;
|
|
271
271
|
align-items: center;
|
|
272
272
|
position: relative;
|
|
273
|
-
width:
|
|
274
|
-
height:
|
|
273
|
+
width: 16px; // Smaller icons for sort and trash
|
|
274
|
+
height: 16px;
|
|
275
275
|
|
|
276
276
|
svg {
|
|
277
|
-
width:
|
|
278
|
-
height:
|
|
277
|
+
width: 16px;
|
|
278
|
+
height: 16px;
|
|
279
279
|
}
|
|
280
280
|
}
|
|
281
281
|
}
|
|
@@ -293,8 +293,8 @@
|
|
|
293
293
|
margin: 0;
|
|
294
294
|
outline: none;
|
|
295
295
|
transition: all 0.2s ease;
|
|
296
|
-
width:
|
|
297
|
-
height:
|
|
296
|
+
width: 24px; // Larger color picker button
|
|
297
|
+
height: 24px;
|
|
298
298
|
|
|
299
299
|
&:hover {
|
|
300
300
|
opacity: 0.8;
|
|
@@ -302,8 +302,8 @@
|
|
|
302
302
|
}
|
|
303
303
|
|
|
304
304
|
svg {
|
|
305
|
-
width:
|
|
306
|
-
height:
|
|
305
|
+
width: 18px; // Larger icon
|
|
306
|
+
height: 18px;
|
|
307
307
|
}
|
|
308
308
|
}
|
|
309
309
|
}
|
|
@@ -665,19 +665,19 @@
|
|
|
665
665
|
border-top: 1px dashed rgba(var(--primary-rgb), 0.3);
|
|
666
666
|
border-bottom: 1px dashed rgba(var(--primary-rgb), 0.3);
|
|
667
667
|
|
|
668
|
-
/*
|
|
668
|
+
/* Updated styling for new row inputs and selects */
|
|
669
669
|
input,
|
|
670
670
|
select {
|
|
671
|
-
height:
|
|
672
|
-
padding: 0.
|
|
673
|
-
font-size: 0.
|
|
671
|
+
height: 32px !important; // Increased height
|
|
672
|
+
padding: 0.3rem 0.5rem !important; // Increased padding
|
|
673
|
+
font-size: 0.9rem !important;
|
|
674
674
|
appearance: none !important;
|
|
675
675
|
background: white !important;
|
|
676
676
|
margin: 0 !important;
|
|
677
|
-
line-height: 1 !important;
|
|
677
|
+
line-height: 1.2 !important;
|
|
678
678
|
border: 1px solid rgba(var(--primary-rgb), 0.1) !important;
|
|
679
679
|
box-sizing: border-box !important;
|
|
680
|
-
border-radius:
|
|
680
|
+
border-radius: 4px !important;
|
|
681
681
|
width: 100% !important;
|
|
682
682
|
|
|
683
683
|
// Ensure selects have dropdown arrow
|
|
@@ -685,9 +685,9 @@
|
|
|
685
685
|
&:not([type]) {
|
|
686
686
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><path d="M6 9L1 4h10z" fill="%23666"/></svg>') !important;
|
|
687
687
|
background-repeat: no-repeat !important;
|
|
688
|
-
background-position: right 0.
|
|
689
|
-
background-size:
|
|
690
|
-
padding-right:
|
|
688
|
+
background-position: right 0.5rem center !important;
|
|
689
|
+
background-size: 10px !important;
|
|
690
|
+
padding-right: 1.5rem !important;
|
|
691
691
|
}
|
|
692
692
|
}
|
|
693
693
|
|
|
@@ -696,9 +696,9 @@
|
|
|
696
696
|
background: white !important;
|
|
697
697
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><path d="M6 9L1 4h10z" fill="%23666"/></svg>') !important;
|
|
698
698
|
background-repeat: no-repeat !important;
|
|
699
|
-
background-position: right 0.
|
|
700
|
-
background-size:
|
|
701
|
-
padding: 0.
|
|
699
|
+
background-position: right 0.5rem center !important;
|
|
700
|
+
background-size: 10px !important;
|
|
701
|
+
padding: 0.3rem 1.5rem 0.3rem 0.5rem !important; // Updated padding
|
|
702
702
|
cursor: pointer !important;
|
|
703
703
|
|
|
704
704
|
&::-ms-expand {
|
|
@@ -707,6 +707,122 @@
|
|
|
707
707
|
}
|
|
708
708
|
}
|
|
709
709
|
|
|
710
|
+
/* Tooltip styles */
|
|
711
|
+
.tooltipContainer {
|
|
712
|
+
position: relative;
|
|
713
|
+
display: inline-flex;
|
|
714
|
+
align-items: center;
|
|
715
|
+
justify-content: center;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
.tooltip {
|
|
719
|
+
position: absolute;
|
|
720
|
+
background: rgba(0, 0, 0, 0.9);
|
|
721
|
+
color: white;
|
|
722
|
+
padding: 6px 10px;
|
|
723
|
+
border-radius: 4px;
|
|
724
|
+
font-size: 0.75rem;
|
|
725
|
+
font-weight: 500;
|
|
726
|
+
white-space: nowrap;
|
|
727
|
+
z-index: 10000;
|
|
728
|
+
pointer-events: none;
|
|
729
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
|
730
|
+
transform: translateX(-50%);
|
|
731
|
+
|
|
732
|
+
&::before {
|
|
733
|
+
content: '';
|
|
734
|
+
position: absolute;
|
|
735
|
+
left: 50%;
|
|
736
|
+
border: 5px solid transparent;
|
|
737
|
+
transform: translateX(-50%);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
&.tooltip-top {
|
|
741
|
+
transform: translateX(-50%) translateY(-100%);
|
|
742
|
+
margin-top: -5px;
|
|
743
|
+
|
|
744
|
+
&::before {
|
|
745
|
+
top: 100%;
|
|
746
|
+
border-top-color: rgba(0, 0, 0, 0.9);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
&.tooltip-bottom {
|
|
751
|
+
transform: translateX(-50%) translateY(0%);
|
|
752
|
+
margin-top: 5px;
|
|
753
|
+
|
|
754
|
+
&::before {
|
|
755
|
+
bottom: 100%;
|
|
756
|
+
border-bottom-color: rgba(0, 0, 0, 0.9);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/* Checkbox styling */
|
|
762
|
+
.schedulingTable input[type="checkbox"] {
|
|
763
|
+
cursor: pointer;
|
|
764
|
+
width: 14px !important;
|
|
765
|
+
height: 14px !important;
|
|
766
|
+
min-width: 14px !important;
|
|
767
|
+
min-height: 14px !important;
|
|
768
|
+
max-width: 14px !important;
|
|
769
|
+
max-height: 14px !important;
|
|
770
|
+
margin: 0 !important;
|
|
771
|
+
padding: 0 !important;
|
|
772
|
+
accent-color: var(--primary-color);
|
|
773
|
+
vertical-align: middle;
|
|
774
|
+
flex-shrink: 0;
|
|
775
|
+
display: inline-block;
|
|
776
|
+
|
|
777
|
+
&:hover {
|
|
778
|
+
transform: scale(1.05);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/* Checkbox column specific styling */
|
|
783
|
+
.checkboxColumn {
|
|
784
|
+
width: 30px !important;
|
|
785
|
+
max-width: 30px !important;
|
|
786
|
+
min-width: 30px !important;
|
|
787
|
+
padding: 0.2rem !important;
|
|
788
|
+
text-align: center !important;
|
|
789
|
+
vertical-align: middle !important;
|
|
790
|
+
cursor: pointer !important;
|
|
791
|
+
user-select: none !important;
|
|
792
|
+
|
|
793
|
+
/* Ensure checkbox container doesn't stretch */
|
|
794
|
+
display: table-cell !important;
|
|
795
|
+
|
|
796
|
+
input[type="checkbox"] {
|
|
797
|
+
display: inline-block !important;
|
|
798
|
+
vertical-align: middle !important;
|
|
799
|
+
pointer-events: none !important; /* Prevent direct checkbox interaction */
|
|
800
|
+
position: relative !important;
|
|
801
|
+
top: 0 !important;
|
|
802
|
+
left: 0 !important;
|
|
803
|
+
transform: none !important;
|
|
804
|
+
margin: 0 auto !important;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/* Specific styling for header checkbox to ensure proper alignment */
|
|
809
|
+
.schedulingTable th.checkboxColumn {
|
|
810
|
+
position: relative !important;
|
|
811
|
+
|
|
812
|
+
input[type="checkbox"] {
|
|
813
|
+
position: absolute !important;
|
|
814
|
+
top: 50% !important;
|
|
815
|
+
left: 50% !important;
|
|
816
|
+
transform: translate(-50%, -50%) !important;
|
|
817
|
+
margin: 0 !important;
|
|
818
|
+
display: block !important;
|
|
819
|
+
|
|
820
|
+
&:hover {
|
|
821
|
+
transform: translate(-50%, -50%) scale(1.05) !important;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
710
826
|
.datasetSelector {
|
|
711
827
|
display: flex;
|
|
712
828
|
align-items: center;
|