datool 0.0.5 → 0.0.6
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 +14 -0
- package/client-dist/assets/index-CU3ksvkv.js +164 -0
- package/client-dist/assets/index-Rn9jSaAz.css +1 -0
- package/client-dist/index.html +2 -2
- package/package.json +1 -1
- package/src/client/App.tsx +11 -40
- package/src/client/components/data-table-cell.tsx +19 -6
- package/src/client/components/data-table.tsx +490 -85
- package/src/node/config.ts +22 -0
- package/src/shared/types.ts +4 -0
- package/client-dist/assets/index-DUkIilaZ.css +0 -1
- package/client-dist/assets/index-OdNyDkx7.js +0 -164
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/incompatible-library, react-refresh/only-export-components */
|
|
2
2
|
import {
|
|
3
|
+
getExpandedRowModel,
|
|
4
|
+
getGroupedRowModel,
|
|
3
5
|
functionalUpdate,
|
|
4
6
|
getCoreRowModel,
|
|
5
7
|
getFilteredRowModel,
|
|
6
8
|
getSortedRowModel,
|
|
7
9
|
useReactTable,
|
|
10
|
+
type AggregationFnOption,
|
|
11
|
+
type Column,
|
|
8
12
|
type ColumnDef,
|
|
9
13
|
type ColumnFiltersState,
|
|
14
|
+
type ExpandedState,
|
|
10
15
|
type FilterFn,
|
|
16
|
+
type GroupingState,
|
|
11
17
|
type OnChangeFn,
|
|
12
18
|
type Row,
|
|
13
19
|
type RowData,
|
|
@@ -19,6 +25,8 @@ import {
|
|
|
19
25
|
import { useVirtualizer } from "@tanstack/react-virtual"
|
|
20
26
|
import {
|
|
21
27
|
Check,
|
|
28
|
+
ChevronDown,
|
|
29
|
+
ChevronRight,
|
|
22
30
|
CircleAlert,
|
|
23
31
|
EyeOff,
|
|
24
32
|
LayoutGrid,
|
|
@@ -46,7 +54,10 @@ import {
|
|
|
46
54
|
inferDataTableColumnKind,
|
|
47
55
|
type DataTableColumnKind,
|
|
48
56
|
} from "./data-table-col-icon"
|
|
49
|
-
import type {
|
|
57
|
+
import type {
|
|
58
|
+
DatoolDateFormat,
|
|
59
|
+
DatoolEnumColorMap,
|
|
60
|
+
} from "../../shared/types"
|
|
50
61
|
import { Button } from "@/components/ui/button"
|
|
51
62
|
import {
|
|
52
63
|
ContextMenu,
|
|
@@ -142,10 +153,13 @@ export type DataTableRowAction<TData extends DataTableRow> = {
|
|
|
142
153
|
export type DataTableColumnConfig<TData extends DataTableRow> = {
|
|
143
154
|
accessorFn?: (row: TData) => unknown
|
|
144
155
|
accessorKey?: Extract<keyof TData, string>
|
|
156
|
+
aggregatedCell?: ColumnDef<TData>["aggregatedCell"]
|
|
157
|
+
aggregationFn?: AggregationFnOption<TData>
|
|
145
158
|
align?: DataTableAlign
|
|
146
159
|
cell?: (args: { row: TData; value: unknown }) => React.ReactNode
|
|
147
160
|
cellClassName?: string
|
|
148
161
|
enableFiltering?: boolean
|
|
162
|
+
enableGrouping?: boolean
|
|
149
163
|
enableHiding?: boolean
|
|
150
164
|
enableResizing?: boolean
|
|
151
165
|
enableSorting?: boolean
|
|
@@ -161,6 +175,7 @@ export type DataTableColumnConfig<TData extends DataTableRow> = {
|
|
|
161
175
|
minWidth?: number
|
|
162
176
|
truncate?: boolean
|
|
163
177
|
width?: number
|
|
178
|
+
getGroupingValue?: (row: TData) => unknown
|
|
164
179
|
}
|
|
165
180
|
|
|
166
181
|
export type DataTableProps<TData extends DataTableRow> = {
|
|
@@ -170,10 +185,12 @@ export type DataTableProps<TData extends DataTableRow> = {
|
|
|
170
185
|
columnVisibility?: VisibilityState
|
|
171
186
|
columns?: DataTableColumnConfig<TData>[]
|
|
172
187
|
data: TData[]
|
|
188
|
+
dateFormat?: DatoolDateFormat
|
|
173
189
|
edgeHorizontalPadding?: React.CSSProperties["paddingLeft"]
|
|
174
190
|
enableRowSelection?: boolean
|
|
175
191
|
filterPlaceholder?: string
|
|
176
192
|
globalFilter?: string
|
|
193
|
+
grouping?: GroupingState
|
|
177
194
|
getRowId?: (row: TData, index: number) => string
|
|
178
195
|
height?: React.CSSProperties["height"]
|
|
179
196
|
highlightQuery?: string
|
|
@@ -181,6 +198,7 @@ export type DataTableProps<TData extends DataTableRow> = {
|
|
|
181
198
|
onColumnFiltersChange?: (value: ColumnFiltersState) => void
|
|
182
199
|
onColumnVisibilityChange?: (value: VisibilityState) => void
|
|
183
200
|
onGlobalFilterChange?: (value: string) => void
|
|
201
|
+
onGroupingChange?: (value: GroupingState) => void
|
|
184
202
|
resolveColumnHighlightTerms?: (columnId: string, query: string) => string[]
|
|
185
203
|
rowActions?: DataTableRowAction<TData>[]
|
|
186
204
|
rowClassName?: (row: TData) => string | undefined
|
|
@@ -227,6 +245,7 @@ type PersistedTableState = {
|
|
|
227
245
|
highlightedColumns?: Record<string, boolean>
|
|
228
246
|
columnVisibility?: VisibilityState
|
|
229
247
|
globalFilter?: string
|
|
248
|
+
grouping?: GroupingState
|
|
230
249
|
sorting?: SortingState
|
|
231
250
|
}
|
|
232
251
|
|
|
@@ -402,6 +421,7 @@ function getPersistedUrlParam(id: string) {
|
|
|
402
421
|
function isPersistedStateEmpty(state: PersistedTableState) {
|
|
403
422
|
return (
|
|
404
423
|
(state.sorting?.length ?? 0) === 0 &&
|
|
424
|
+
(state.grouping?.length ?? 0) === 0 &&
|
|
405
425
|
(state.columnFilters?.length ?? 0) === 0 &&
|
|
406
426
|
Object.keys(state.highlightedColumns ?? {}).length === 0 &&
|
|
407
427
|
Object.keys(state.columnVisibility ?? {}).length === 0 &&
|
|
@@ -496,6 +516,119 @@ function inferWidth(kind: DataTableColumnKind) {
|
|
|
496
516
|
}
|
|
497
517
|
}
|
|
498
518
|
|
|
519
|
+
type DateRangeAggregate = {
|
|
520
|
+
durationMs: number
|
|
521
|
+
endMs: number
|
|
522
|
+
startMs: number
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function toTimestamp(value: unknown) {
|
|
526
|
+
if (value instanceof Date) {
|
|
527
|
+
return Number.isNaN(value.getTime()) ? null : value.getTime()
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
if (typeof value === "number") {
|
|
531
|
+
return Number.isFinite(value) ? value : null
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (typeof value === "string") {
|
|
535
|
+
const timestamp = Date.parse(value)
|
|
536
|
+
|
|
537
|
+
return Number.isNaN(timestamp) ? null : timestamp
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return null
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function buildDateRangeAggregate<TData extends DataTableRow>(
|
|
544
|
+
columnId: string,
|
|
545
|
+
leafRows: Row<TData>[]
|
|
546
|
+
) {
|
|
547
|
+
let startMs = Number.POSITIVE_INFINITY
|
|
548
|
+
let endMs = Number.NEGATIVE_INFINITY
|
|
549
|
+
|
|
550
|
+
for (const row of leafRows) {
|
|
551
|
+
const timestamp = toTimestamp(row.getValue(columnId))
|
|
552
|
+
|
|
553
|
+
if (timestamp === null) {
|
|
554
|
+
continue
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
startMs = Math.min(startMs, timestamp)
|
|
558
|
+
endMs = Math.max(endMs, timestamp)
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
if (
|
|
562
|
+
startMs === Number.POSITIVE_INFINITY ||
|
|
563
|
+
endMs === Number.NEGATIVE_INFINITY
|
|
564
|
+
) {
|
|
565
|
+
return null
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
return {
|
|
569
|
+
durationMs: Math.max(0, endMs - startMs),
|
|
570
|
+
endMs,
|
|
571
|
+
startMs,
|
|
572
|
+
} satisfies DateRangeAggregate
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function isDateRangeAggregate(value: unknown): value is DateRangeAggregate {
|
|
576
|
+
return (
|
|
577
|
+
value !== null &&
|
|
578
|
+
typeof value === "object" &&
|
|
579
|
+
"durationMs" in value &&
|
|
580
|
+
"endMs" in value &&
|
|
581
|
+
"startMs" in value
|
|
582
|
+
)
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function formatSummaryNumber(value: number) {
|
|
586
|
+
return new Intl.NumberFormat(undefined, {
|
|
587
|
+
maximumFractionDigits: Number.isInteger(value) ? 0 : 2,
|
|
588
|
+
}).format(value)
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
function formatDuration(durationMs: number) {
|
|
592
|
+
const totalSeconds = Math.max(0, Math.floor(durationMs / 1000))
|
|
593
|
+
const days = Math.floor(totalSeconds / 86_400)
|
|
594
|
+
const hours = Math.floor((totalSeconds % 86_400) / 3_600)
|
|
595
|
+
const minutes = Math.floor((totalSeconds % 3_600) / 60)
|
|
596
|
+
const seconds = totalSeconds % 60
|
|
597
|
+
const parts = [
|
|
598
|
+
days > 0 ? `${days}d` : null,
|
|
599
|
+
hours > 0 ? `${hours}h` : null,
|
|
600
|
+
minutes > 0 ? `${minutes}m` : null,
|
|
601
|
+
seconds > 0 || totalSeconds === 0 ? `${seconds}s` : null,
|
|
602
|
+
].filter(Boolean)
|
|
603
|
+
|
|
604
|
+
return parts.join(" ")
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function getColumnHeaderLabel<TData extends DataTableRow>(
|
|
608
|
+
column: Column<TData, unknown>
|
|
609
|
+
) {
|
|
610
|
+
return typeof column.columnDef.header === "string"
|
|
611
|
+
? column.columnDef.header
|
|
612
|
+
: formatHeaderLabel(column.id)
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function resolveGroupedPadding(
|
|
616
|
+
padding: React.CSSProperties["paddingLeft"],
|
|
617
|
+
depth: number
|
|
618
|
+
) {
|
|
619
|
+
const indent = depth * 16
|
|
620
|
+
|
|
621
|
+
if (typeof padding === "number") {
|
|
622
|
+
return padding + indent
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
if (typeof padding === "string") {
|
|
626
|
+
return `calc(${padding} + ${indent}px)`
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
return indent
|
|
630
|
+
}
|
|
631
|
+
|
|
499
632
|
function resolveColumnId<TData extends DataTableRow>(
|
|
500
633
|
column: DataTableColumnConfig<TData>,
|
|
501
634
|
index: number
|
|
@@ -512,6 +645,7 @@ function resolveColumnId<TData extends DataTableRow>(
|
|
|
512
645
|
function buildColumns<TData extends DataTableRow>(
|
|
513
646
|
data: TData[],
|
|
514
647
|
columns?: DataTableColumnConfig<TData>[],
|
|
648
|
+
dateFormat?: DatoolDateFormat,
|
|
515
649
|
showRowSelectionColumn?: boolean,
|
|
516
650
|
showRowActionButtonsColumn?: boolean,
|
|
517
651
|
rowActionsColumnSize?: number
|
|
@@ -553,18 +687,29 @@ function buildColumns<TData extends DataTableRow>(
|
|
|
553
687
|
return {
|
|
554
688
|
accessorFn: column.accessorFn,
|
|
555
689
|
accessorKey: column.accessorKey,
|
|
690
|
+
aggregatedCell: column.aggregatedCell,
|
|
691
|
+
aggregationFn:
|
|
692
|
+
column.aggregationFn ??
|
|
693
|
+
(kind === "date"
|
|
694
|
+
? buildDateRangeAggregate
|
|
695
|
+
: kind === "number"
|
|
696
|
+
? "sum"
|
|
697
|
+
: undefined),
|
|
556
698
|
cell: ({ getValue, row }) =>
|
|
557
699
|
column.cell
|
|
558
700
|
? column.cell({ row: row.original, value: getValue() })
|
|
559
701
|
: fallbackCellValue(getValue(), kind, {
|
|
702
|
+
dateFormat,
|
|
560
703
|
enumColors: kind === "enum" ? column.enumColors : undefined,
|
|
561
704
|
enumOptions: kind === "enum" ? column.enumOptions : undefined,
|
|
562
705
|
}),
|
|
563
706
|
enableGlobalFilter: column.enableFiltering ?? true,
|
|
707
|
+
enableGrouping: column.enableGrouping ?? true,
|
|
564
708
|
filterFn: column.filterFn,
|
|
565
709
|
enableHiding: column.enableHiding ?? true,
|
|
566
710
|
enableResizing: column.enableResizing ?? true,
|
|
567
711
|
enableSorting: column.enableSorting ?? true,
|
|
712
|
+
getGroupingValue: column.getGroupingValue,
|
|
568
713
|
header: column.header ?? formatHeaderLabel(id),
|
|
569
714
|
id,
|
|
570
715
|
maxSize: column.maxWidth ?? 420,
|
|
@@ -583,6 +728,7 @@ function buildColumns<TData extends DataTableRow>(
|
|
|
583
728
|
...builtColumns,
|
|
584
729
|
{
|
|
585
730
|
cell: () => null,
|
|
731
|
+
enableGrouping: false,
|
|
586
732
|
enableGlobalFilter: false,
|
|
587
733
|
enableHiding: false,
|
|
588
734
|
enableResizing: false,
|
|
@@ -604,13 +750,16 @@ function buildColumns<TData extends DataTableRow>(
|
|
|
604
750
|
{
|
|
605
751
|
cell: ({ row }) => (
|
|
606
752
|
<div className="flex items-center justify-center">
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
753
|
+
{row.getCanSelect() ? (
|
|
754
|
+
<DataTableCheckbox
|
|
755
|
+
ariaLabel={`Select row ${row.index + 1}`}
|
|
756
|
+
checked={row.getIsSelected()}
|
|
757
|
+
onCheckedChange={(checked) => row.toggleSelected(checked)}
|
|
758
|
+
/>
|
|
759
|
+
) : null}
|
|
612
760
|
</div>
|
|
613
761
|
),
|
|
762
|
+
enableGrouping: false,
|
|
614
763
|
enableGlobalFilter: false,
|
|
615
764
|
enableHiding: false,
|
|
616
765
|
enableResizing: false,
|
|
@@ -649,6 +798,7 @@ function buildColumns<TData extends DataTableRow>(
|
|
|
649
798
|
...withSelectionColumn,
|
|
650
799
|
{
|
|
651
800
|
cell: () => null,
|
|
801
|
+
enableGrouping: false,
|
|
652
802
|
enableGlobalFilter: false,
|
|
653
803
|
enableHiding: false,
|
|
654
804
|
enableResizing: false,
|
|
@@ -704,6 +854,31 @@ function shouldIgnoreRowSelectionTarget(target: EventTarget | null) {
|
|
|
704
854
|
)
|
|
705
855
|
}
|
|
706
856
|
|
|
857
|
+
function shouldIgnoreSelectionShortcutTarget(target: EventTarget | null) {
|
|
858
|
+
return (
|
|
859
|
+
target instanceof Element &&
|
|
860
|
+
Boolean(
|
|
861
|
+
target.closest(
|
|
862
|
+
[
|
|
863
|
+
"a",
|
|
864
|
+
"button",
|
|
865
|
+
"input",
|
|
866
|
+
"select",
|
|
867
|
+
"textarea",
|
|
868
|
+
"[contenteditable=true]",
|
|
869
|
+
'[role="button"]',
|
|
870
|
+
'[role="combobox"]',
|
|
871
|
+
'[role="dialog"]',
|
|
872
|
+
'[role="menu"]',
|
|
873
|
+
'[role="menuitem"]',
|
|
874
|
+
'[role="searchbox"]',
|
|
875
|
+
'[role="textbox"]',
|
|
876
|
+
].join(",")
|
|
877
|
+
)
|
|
878
|
+
)
|
|
879
|
+
)
|
|
880
|
+
}
|
|
881
|
+
|
|
707
882
|
function resolveRowActionRows<TData extends DataTableRow>(
|
|
708
883
|
action: DataTableRowAction<TData>,
|
|
709
884
|
row: Row<TData>,
|
|
@@ -1119,6 +1294,21 @@ function RowActionButtonGroup<TData extends DataTableRow>({
|
|
|
1119
1294
|
)
|
|
1120
1295
|
}
|
|
1121
1296
|
|
|
1297
|
+
function GroupSummaryBadge({
|
|
1298
|
+
label,
|
|
1299
|
+
value,
|
|
1300
|
+
}: {
|
|
1301
|
+
label: string
|
|
1302
|
+
value: string
|
|
1303
|
+
}) {
|
|
1304
|
+
return (
|
|
1305
|
+
<span className="inline-flex items-center gap-1 rounded-full border border-border/70 bg-background/80 px-2 py-0.5 text-[11px] font-medium text-muted-foreground">
|
|
1306
|
+
<span className="text-foreground">{value}</span>
|
|
1307
|
+
<span>{label}</span>
|
|
1308
|
+
</span>
|
|
1309
|
+
)
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1122
1312
|
function DataTableView<TData extends DataTableRow>({
|
|
1123
1313
|
autoScrollToBottom = false,
|
|
1124
1314
|
autoScrollToBottomThreshold = 96,
|
|
@@ -1126,10 +1316,12 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1126
1316
|
columnVisibility: controlledColumnVisibility,
|
|
1127
1317
|
columns,
|
|
1128
1318
|
data,
|
|
1319
|
+
dateFormat,
|
|
1129
1320
|
edgeHorizontalPadding = "16px",
|
|
1130
1321
|
enableRowSelection = false,
|
|
1131
1322
|
filterPlaceholder = "Search across visible columns",
|
|
1132
1323
|
globalFilter,
|
|
1324
|
+
grouping: controlledGrouping,
|
|
1133
1325
|
getRowId,
|
|
1134
1326
|
height = 620,
|
|
1135
1327
|
highlightQuery = "",
|
|
@@ -1137,6 +1329,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1137
1329
|
onColumnFiltersChange,
|
|
1138
1330
|
onColumnVisibilityChange,
|
|
1139
1331
|
onGlobalFilterChange,
|
|
1332
|
+
onGroupingChange,
|
|
1140
1333
|
resolveColumnHighlightTerms,
|
|
1141
1334
|
rowActions,
|
|
1142
1335
|
rowClassName,
|
|
@@ -1163,6 +1356,9 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1163
1356
|
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
|
1164
1357
|
() => persistedState.columnFilters ?? []
|
|
1165
1358
|
)
|
|
1359
|
+
const [grouping, setGrouping] = React.useState<GroupingState>(
|
|
1360
|
+
() => persistedState.grouping ?? []
|
|
1361
|
+
)
|
|
1166
1362
|
const [rowSelection, setRowSelection] = React.useState<RowSelectionState>({})
|
|
1167
1363
|
const [rowActionStatuses, setRowActionStatuses] = React.useState<
|
|
1168
1364
|
Record<string, RowActionStatus>
|
|
@@ -1185,9 +1381,11 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1185
1381
|
const isColumnFiltersControlled = controlledColumnFilters !== undefined
|
|
1186
1382
|
const isColumnVisibilityControlled = controlledColumnVisibility !== undefined
|
|
1187
1383
|
const isGlobalFilterControlled = globalFilter !== undefined
|
|
1384
|
+
const isGroupingControlled = controlledGrouping !== undefined
|
|
1188
1385
|
const resolvedColumnFilters = controlledColumnFilters ?? columnFilters
|
|
1189
1386
|
const resolvedColumnVisibility =
|
|
1190
1387
|
controlledColumnVisibility ?? columnVisibility
|
|
1388
|
+
const resolvedGrouping = controlledGrouping ?? grouping
|
|
1191
1389
|
const hasSelectionActions = rowActions
|
|
1192
1390
|
? hasSelectionScopedAction(rowActions)
|
|
1193
1391
|
: false
|
|
@@ -1234,6 +1432,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1234
1432
|
buildColumns(
|
|
1235
1433
|
data,
|
|
1236
1434
|
columnsWithEnumOptions,
|
|
1435
|
+
dateFormat,
|
|
1237
1436
|
showRowSelectionColumn,
|
|
1238
1437
|
showRowActionButtonsColumn,
|
|
1239
1438
|
rowActionsColumnSize
|
|
@@ -1241,6 +1440,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1241
1440
|
[
|
|
1242
1441
|
columnsWithEnumOptions,
|
|
1243
1442
|
data,
|
|
1443
|
+
dateFormat,
|
|
1244
1444
|
rowActionsColumnSize,
|
|
1245
1445
|
showRowActionButtonsColumn,
|
|
1246
1446
|
showRowSelectionColumn,
|
|
@@ -1314,28 +1514,52 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1314
1514
|
resolvedColumnVisibility,
|
|
1315
1515
|
]
|
|
1316
1516
|
)
|
|
1517
|
+
const handleGroupingChange = React.useCallback<OnChangeFn<GroupingState>>(
|
|
1518
|
+
(updater) => {
|
|
1519
|
+
const nextValue = functionalUpdate(updater, resolvedGrouping)
|
|
1520
|
+
|
|
1521
|
+
if (!isGroupingControlled) {
|
|
1522
|
+
setGrouping(nextValue)
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
onGroupingChange?.(nextValue)
|
|
1526
|
+
},
|
|
1527
|
+
[isGroupingControlled, onGroupingChange, resolvedGrouping]
|
|
1528
|
+
)
|
|
1529
|
+
const expandedState = React.useMemo<ExpandedState>(
|
|
1530
|
+
() => (resolvedGrouping.length > 0 ? true : {}),
|
|
1531
|
+
[resolvedGrouping.length]
|
|
1532
|
+
)
|
|
1317
1533
|
|
|
1318
1534
|
const table = useReactTable({
|
|
1319
1535
|
columnResizeMode: "onChange",
|
|
1320
1536
|
columns: tableColumns,
|
|
1321
1537
|
data,
|
|
1322
1538
|
enableColumnResizing: true,
|
|
1323
|
-
|
|
1539
|
+
enableGrouping: true,
|
|
1540
|
+
enableRowSelection: canSelectRows ? (row) => !row.getIsGrouped() : false,
|
|
1541
|
+
enableSubRowSelection: false,
|
|
1324
1542
|
getCoreRowModel: getCoreRowModel(),
|
|
1543
|
+
getExpandedRowModel: getExpandedRowModel(),
|
|
1325
1544
|
getFilteredRowModel: getFilteredRowModel(),
|
|
1545
|
+
getGroupedRowModel: getGroupedRowModel(),
|
|
1326
1546
|
getRowId,
|
|
1327
1547
|
getSortedRowModel: getSortedRowModel(),
|
|
1548
|
+
groupedColumnMode: false,
|
|
1328
1549
|
globalFilterFn: globalFilterFn as FilterFn<TData>,
|
|
1329
1550
|
onColumnFiltersChange: handleColumnFiltersChange,
|
|
1330
1551
|
onColumnSizingChange: handleColumnSizingChange,
|
|
1331
1552
|
onColumnVisibilityChange: handleColumnVisibilityChange,
|
|
1553
|
+
onGroupingChange: handleGroupingChange,
|
|
1332
1554
|
onRowSelectionChange: setRowSelection,
|
|
1333
1555
|
onSortingChange: setSorting,
|
|
1334
1556
|
state: {
|
|
1335
1557
|
columnFilters: resolvedColumnFilters,
|
|
1336
1558
|
columnSizing,
|
|
1337
1559
|
columnVisibility: resolvedColumnVisibility,
|
|
1560
|
+
expanded: expandedState,
|
|
1338
1561
|
globalFilter: deferredSearch.trim(),
|
|
1562
|
+
grouping: resolvedGrouping,
|
|
1339
1563
|
rowSelection,
|
|
1340
1564
|
sorting,
|
|
1341
1565
|
},
|
|
@@ -1346,6 +1570,10 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1346
1570
|
const hasAutoScrolledOnMountRef = React.useRef(false)
|
|
1347
1571
|
const previousDataLengthRef = React.useRef(0)
|
|
1348
1572
|
const rows = table.getRowModel().rows
|
|
1573
|
+
const selectableRows = React.useMemo(
|
|
1574
|
+
() => rows.filter((row) => row.getCanSelect()),
|
|
1575
|
+
[rows]
|
|
1576
|
+
)
|
|
1349
1577
|
const selectedTableRows = table.getSelectedRowModel().rows
|
|
1350
1578
|
const resolvedHeight = typeof height === "number" ? height : 0
|
|
1351
1579
|
const initialOffsetRef = React.useRef(
|
|
@@ -1387,6 +1615,9 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1387
1615
|
}
|
|
1388
1616
|
setHighlightedColumns(nextState.highlightedColumns ?? {})
|
|
1389
1617
|
setColumnFilters(nextState.columnFilters ?? [])
|
|
1618
|
+
if (!isGroupingControlled) {
|
|
1619
|
+
setGrouping(nextState.grouping ?? [])
|
|
1620
|
+
}
|
|
1390
1621
|
setSearchDraft(nextState.globalFilter ?? "")
|
|
1391
1622
|
setRowSelection({})
|
|
1392
1623
|
dragSelectionRef.current = null
|
|
@@ -1398,7 +1629,13 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1398
1629
|
}
|
|
1399
1630
|
rowActionStatusTimersRef.current = {}
|
|
1400
1631
|
setRowActionStatuses({})
|
|
1401
|
-
}, [
|
|
1632
|
+
}, [
|
|
1633
|
+
id,
|
|
1634
|
+
isColumnFiltersControlled,
|
|
1635
|
+
isColumnVisibilityControlled,
|
|
1636
|
+
isGroupingControlled,
|
|
1637
|
+
statePersistence,
|
|
1638
|
+
])
|
|
1402
1639
|
|
|
1403
1640
|
React.useEffect(() => {
|
|
1404
1641
|
if (!isColumnFiltersControlled) {
|
|
@@ -1416,6 +1653,14 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1416
1653
|
setColumnVisibility(controlledColumnVisibility)
|
|
1417
1654
|
}, [controlledColumnVisibility, isColumnVisibilityControlled])
|
|
1418
1655
|
|
|
1656
|
+
React.useEffect(() => {
|
|
1657
|
+
if (!isGroupingControlled) {
|
|
1658
|
+
return
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
setGrouping(controlledGrouping)
|
|
1662
|
+
}, [controlledGrouping, isGroupingControlled])
|
|
1663
|
+
|
|
1419
1664
|
React.useEffect(() => {
|
|
1420
1665
|
if (!isGlobalFilterControlled) {
|
|
1421
1666
|
return
|
|
@@ -1439,6 +1684,9 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1439
1684
|
}
|
|
1440
1685
|
setHighlightedColumns(nextState.highlightedColumns ?? {})
|
|
1441
1686
|
setColumnFilters(nextState.columnFilters ?? [])
|
|
1687
|
+
if (!isGroupingControlled) {
|
|
1688
|
+
setGrouping(nextState.grouping ?? [])
|
|
1689
|
+
}
|
|
1442
1690
|
setSearchDraft(nextState.globalFilter ?? "")
|
|
1443
1691
|
setRowSelection({})
|
|
1444
1692
|
dragSelectionRef.current = null
|
|
@@ -1450,7 +1698,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1450
1698
|
window.addEventListener("popstate", syncFromUrl)
|
|
1451
1699
|
|
|
1452
1700
|
return () => window.removeEventListener("popstate", syncFromUrl)
|
|
1453
|
-
}, [id, isColumnVisibilityControlled, statePersistence])
|
|
1701
|
+
}, [id, isColumnVisibilityControlled, isGroupingControlled, statePersistence])
|
|
1454
1702
|
|
|
1455
1703
|
React.useEffect(() => {
|
|
1456
1704
|
if (isGlobalFilterControlled || isColumnFiltersControlled) {
|
|
@@ -1463,6 +1711,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1463
1711
|
highlightedColumns,
|
|
1464
1712
|
columnVisibility: resolvedColumnVisibility,
|
|
1465
1713
|
globalFilter: deferredSearch.trim(),
|
|
1714
|
+
grouping: resolvedGrouping,
|
|
1466
1715
|
sorting,
|
|
1467
1716
|
})
|
|
1468
1717
|
}, [
|
|
@@ -1473,7 +1722,9 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1473
1722
|
id,
|
|
1474
1723
|
isColumnFiltersControlled,
|
|
1475
1724
|
isGlobalFilterControlled,
|
|
1725
|
+
isGroupingControlled,
|
|
1476
1726
|
resolvedColumnVisibility,
|
|
1727
|
+
resolvedGrouping,
|
|
1477
1728
|
sorting,
|
|
1478
1729
|
statePersistence,
|
|
1479
1730
|
])
|
|
@@ -1579,6 +1830,13 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1579
1830
|
|
|
1580
1831
|
onGlobalFilterChange?.(value)
|
|
1581
1832
|
}
|
|
1833
|
+
const clearRowSelection = React.useCallback(() => {
|
|
1834
|
+
setRowSelection({})
|
|
1835
|
+
dragSelectionRef.current = null
|
|
1836
|
+
dragPointerRef.current = null
|
|
1837
|
+
setIsDragSelecting(false)
|
|
1838
|
+
selectionAnchorIdRef.current = null
|
|
1839
|
+
}, [])
|
|
1582
1840
|
|
|
1583
1841
|
const isColumnHighlightEnabled = React.useCallback(
|
|
1584
1842
|
(columnId: string, meta: DataTableColumnMeta) =>
|
|
@@ -1591,10 +1849,10 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1591
1849
|
rowId: string,
|
|
1592
1850
|
baseSelection: RowSelectionState = {}
|
|
1593
1851
|
) => {
|
|
1594
|
-
const anchorIndex =
|
|
1852
|
+
const anchorIndex = selectableRows.findIndex(
|
|
1595
1853
|
(candidateRow) => candidateRow.id === anchorId
|
|
1596
1854
|
)
|
|
1597
|
-
const rowIndex =
|
|
1855
|
+
const rowIndex = selectableRows.findIndex(
|
|
1598
1856
|
(candidateRow) => candidateRow.id === rowId
|
|
1599
1857
|
)
|
|
1600
1858
|
|
|
@@ -1610,13 +1868,13 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1610
1868
|
setRowSelection({
|
|
1611
1869
|
...baseSelection,
|
|
1612
1870
|
...Object.fromEntries(
|
|
1613
|
-
|
|
1871
|
+
selectableRows
|
|
1614
1872
|
.slice(start, end + 1)
|
|
1615
1873
|
.map((candidateRow) => [candidateRow.id, true])
|
|
1616
1874
|
),
|
|
1617
1875
|
})
|
|
1618
1876
|
},
|
|
1619
|
-
[
|
|
1877
|
+
[selectableRows]
|
|
1620
1878
|
)
|
|
1621
1879
|
const selectSingleRow = React.useCallback((rowId: string) => {
|
|
1622
1880
|
selectionAnchorIdRef.current = rowId
|
|
@@ -1663,6 +1921,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1663
1921
|
if (
|
|
1664
1922
|
event.button !== 0 ||
|
|
1665
1923
|
!canSelectRows ||
|
|
1924
|
+
!row.getCanSelect() ||
|
|
1666
1925
|
shouldIgnoreRowSelectionTarget(event.target)
|
|
1667
1926
|
) {
|
|
1668
1927
|
return
|
|
@@ -1724,6 +1983,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1724
1983
|
(event: React.MouseEvent<HTMLTableRowElement>, row: Row<TData>) => {
|
|
1725
1984
|
if (
|
|
1726
1985
|
!canSelectRows ||
|
|
1986
|
+
!row.getCanSelect() ||
|
|
1727
1987
|
event.buttons !== 1 ||
|
|
1728
1988
|
shouldIgnoreRowSelectionTarget(event.target) ||
|
|
1729
1989
|
!dragSelectionRef.current
|
|
@@ -1739,7 +1999,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1739
1999
|
)
|
|
1740
2000
|
const handleRowContextMenu = React.useCallback(
|
|
1741
2001
|
(row: Row<TData>) => {
|
|
1742
|
-
if (!canSelectRows) {
|
|
2002
|
+
if (!canSelectRows || !row.getCanSelect()) {
|
|
1743
2003
|
return
|
|
1744
2004
|
}
|
|
1745
2005
|
|
|
@@ -1819,6 +2079,27 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1819
2079
|
window.cancelAnimationFrame(frameId)
|
|
1820
2080
|
}
|
|
1821
2081
|
}, [isDragSelecting, updateDragSelectionFromPointer])
|
|
2082
|
+
React.useEffect(() => {
|
|
2083
|
+
if (!canSelectRows) {
|
|
2084
|
+
return
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
const handleWindowKeyDown = (event: KeyboardEvent) => {
|
|
2088
|
+
if (
|
|
2089
|
+
event.key !== "Escape" ||
|
|
2090
|
+
Object.keys(rowSelection).length === 0 ||
|
|
2091
|
+
shouldIgnoreSelectionShortcutTarget(event.target)
|
|
2092
|
+
) {
|
|
2093
|
+
return
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
clearRowSelection()
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
window.addEventListener("keydown", handleWindowKeyDown)
|
|
2100
|
+
|
|
2101
|
+
return () => window.removeEventListener("keydown", handleWindowKeyDown)
|
|
2102
|
+
}, [canSelectRows, clearRowSelection, rowSelection])
|
|
1822
2103
|
|
|
1823
2104
|
return (
|
|
1824
2105
|
<section
|
|
@@ -1896,100 +2177,224 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1896
2177
|
) : (
|
|
1897
2178
|
virtualRows.map((virtualRow) => {
|
|
1898
2179
|
const row = rows[virtualRow.index]
|
|
1899
|
-
const
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
2180
|
+
const isGroupRow = row.getIsGrouped()
|
|
2181
|
+
const visibleRowActions = isGroupRow
|
|
2182
|
+
? []
|
|
2183
|
+
: resolveVisibleRowActions(
|
|
2184
|
+
rowActions ?? [],
|
|
2185
|
+
row,
|
|
2186
|
+
selectedTableRows
|
|
2187
|
+
)
|
|
1904
2188
|
const isSelected = row.getIsSelected()
|
|
2189
|
+
const groupVisibleCells = row.getVisibleCells()
|
|
2190
|
+
const groupingColumn = row.groupingColumnId
|
|
2191
|
+
? table.getColumn(row.groupingColumnId)
|
|
2192
|
+
: undefined
|
|
2193
|
+
const groupingMeta = groupingColumn?.columnDef.meta as
|
|
2194
|
+
| DataTableColumnMeta
|
|
2195
|
+
| undefined
|
|
2196
|
+
const groupingValue = groupingColumn
|
|
2197
|
+
? fallbackCellValue(row.groupingValue, groupingMeta?.kind, {
|
|
2198
|
+
dateFormat,
|
|
2199
|
+
enumColors: groupingMeta?.enumColors,
|
|
2200
|
+
enumOptions: groupingMeta?.enumOptions,
|
|
2201
|
+
})
|
|
2202
|
+
: null
|
|
2203
|
+
const groupSummaries = isGroupRow
|
|
2204
|
+
? groupVisibleCells.flatMap((cell) => {
|
|
2205
|
+
const meta = (cell.column.columnDef.meta ??
|
|
2206
|
+
{}) as DataTableColumnMeta
|
|
2207
|
+
const value = cell.getValue()
|
|
2208
|
+
const label = getColumnHeaderLabel(cell.column)
|
|
2209
|
+
|
|
2210
|
+
if (meta.kind === "date" && isDateRangeAggregate(value)) {
|
|
2211
|
+
return [
|
|
2212
|
+
{
|
|
2213
|
+
label: `${label} span`,
|
|
2214
|
+
value: formatDuration(value.durationMs),
|
|
2215
|
+
},
|
|
2216
|
+
]
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
if (meta.kind === "number" && typeof value === "number") {
|
|
2220
|
+
return [
|
|
2221
|
+
{
|
|
2222
|
+
label: `${label} sum`,
|
|
2223
|
+
value: formatSummaryNumber(value),
|
|
2224
|
+
},
|
|
2225
|
+
]
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
return []
|
|
2229
|
+
})
|
|
2230
|
+
: []
|
|
1905
2231
|
const rowContent = (
|
|
1906
2232
|
<tr
|
|
1907
2233
|
aria-selected={isSelected}
|
|
1908
2234
|
className={cn(
|
|
1909
|
-
"absolute left-0 flex w-full
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
2235
|
+
"absolute left-0 flex w-full transition-colors",
|
|
2236
|
+
isGroupRow
|
|
2237
|
+
? "bg-transparent"
|
|
2238
|
+
: "bg-card",
|
|
2239
|
+
canSelectRows &&
|
|
2240
|
+
row.getCanSelect() &&
|
|
2241
|
+
"cursor-pointer",
|
|
2242
|
+
!isGroupRow && rowClassName?.(row.original),
|
|
2243
|
+
!isGroupRow &&
|
|
2244
|
+
isSelected &&
|
|
1913
2245
|
"bg-primary/10 before:absolute before:-top-px before:left-0 before:h-px before:w-full before:bg-primary before:content-[''] after:absolute after:bottom-0 after:left-0 after:h-px after:w-full after:bg-primary after:content-['']"
|
|
1914
2246
|
)}
|
|
1915
2247
|
data-index={virtualRow.index}
|
|
1916
2248
|
data-row-id={row.id}
|
|
1917
|
-
data-state={isSelected ? "selected" : undefined}
|
|
2249
|
+
data-state={!isGroupRow && isSelected ? "selected" : undefined}
|
|
1918
2250
|
key={row.id}
|
|
1919
|
-
onContextMenu={
|
|
1920
|
-
|
|
1921
|
-
|
|
2251
|
+
onContextMenu={
|
|
2252
|
+
isGroupRow ? undefined : () => handleRowContextMenu(row)
|
|
2253
|
+
}
|
|
2254
|
+
onMouseDown={
|
|
2255
|
+
isGroupRow
|
|
2256
|
+
? undefined
|
|
2257
|
+
: (event) => handleRowMouseDown(event, row)
|
|
2258
|
+
}
|
|
2259
|
+
onMouseEnter={
|
|
2260
|
+
isGroupRow
|
|
2261
|
+
? undefined
|
|
2262
|
+
: (event) => handleRowMouseEnter(event, row)
|
|
2263
|
+
}
|
|
1922
2264
|
ref={(node) => {
|
|
1923
2265
|
if (node) {
|
|
1924
2266
|
rowVirtualizer.measureElement(node)
|
|
1925
2267
|
}
|
|
1926
2268
|
}}
|
|
1927
2269
|
style={{
|
|
1928
|
-
...rowStyle?.(row.original),
|
|
1929
|
-
minHeight: rowHeight,
|
|
2270
|
+
...(!isGroupRow ? rowStyle?.(row.original) : undefined),
|
|
2271
|
+
minHeight: isGroupRow ? Math.max(rowHeight, 44) : rowHeight,
|
|
1930
2272
|
transform: `translateY(${virtualRow.start}px)`,
|
|
1931
2273
|
width: table.getTotalSize(),
|
|
1932
2274
|
}}
|
|
1933
2275
|
>
|
|
1934
|
-
{
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
2276
|
+
{isGroupRow ? (
|
|
2277
|
+
<td
|
|
2278
|
+
className="flex shrink-0 items-center border-y border-border/70 px-2 py-2 align-middle text-xs text-muted-foreground"
|
|
2279
|
+
style={{
|
|
2280
|
+
background:
|
|
2281
|
+
"var(--color-table-gap, color-mix(in oklab, var(--color-muted) 84%, transparent))",
|
|
2282
|
+
paddingLeft: resolveGroupedPadding(
|
|
2283
|
+
edgeHorizontalPadding,
|
|
2284
|
+
row.depth
|
|
2285
|
+
),
|
|
2286
|
+
paddingRight: edgeHorizontalPadding,
|
|
2287
|
+
width: table.getTotalSize(),
|
|
2288
|
+
}}
|
|
2289
|
+
>
|
|
2290
|
+
<div className="flex w-full min-w-0 flex-wrap items-center gap-2">
|
|
2291
|
+
{row.getCanExpand() ? (
|
|
2292
|
+
<button
|
|
2293
|
+
aria-label={
|
|
2294
|
+
row.getIsExpanded()
|
|
2295
|
+
? "Collapse group"
|
|
2296
|
+
: "Expand group"
|
|
2297
|
+
}
|
|
2298
|
+
className="inline-flex size-6 items-center justify-center rounded-md border border-border/70 bg-background/80 text-foreground transition-colors hover:bg-background"
|
|
2299
|
+
onClick={() => row.toggleExpanded()}
|
|
2300
|
+
type="button"
|
|
2301
|
+
>
|
|
2302
|
+
{row.getIsExpanded() ? (
|
|
2303
|
+
<ChevronDown className="size-3.5" />
|
|
2304
|
+
) : (
|
|
2305
|
+
<ChevronRight className="size-3.5" />
|
|
2306
|
+
)}
|
|
2307
|
+
</button>
|
|
2308
|
+
) : null}
|
|
2309
|
+
{groupingColumn ? (
|
|
2310
|
+
<span className="inline-flex items-center gap-2 text-xs">
|
|
2311
|
+
<span className="font-medium text-foreground">
|
|
2312
|
+
{getColumnHeaderLabel(groupingColumn)}
|
|
2313
|
+
</span>
|
|
2314
|
+
<span className="min-w-0 truncate text-foreground">
|
|
2315
|
+
{groupingValue}
|
|
2316
|
+
</span>
|
|
2317
|
+
</span>
|
|
2318
|
+
) : (
|
|
2319
|
+
<span className="font-medium text-foreground">
|
|
2320
|
+
Group
|
|
2321
|
+
</span>
|
|
2322
|
+
)}
|
|
2323
|
+
<GroupSummaryBadge
|
|
2324
|
+
label="rows"
|
|
2325
|
+
value={formatSummaryNumber(row.getLeafRows().length)}
|
|
2326
|
+
/>
|
|
2327
|
+
{groupSummaries.map((summary) => (
|
|
2328
|
+
<GroupSummaryBadge
|
|
2329
|
+
key={`${row.id}-${summary.label}`}
|
|
2330
|
+
label={summary.label}
|
|
2331
|
+
value={summary.value}
|
|
2332
|
+
/>
|
|
2333
|
+
))}
|
|
2334
|
+
</div>
|
|
2335
|
+
</td>
|
|
2336
|
+
) : (
|
|
2337
|
+
row.getVisibleCells().map((cell, index, visibleCells) => {
|
|
2338
|
+
const meta = (cell.column.columnDef.meta ??
|
|
2339
|
+
{}) as DataTableColumnMeta
|
|
2340
|
+
const isActionsCell = cell.column.id === "__actions"
|
|
2341
|
+
const highlightTerms =
|
|
2342
|
+
meta.kind === "text" &&
|
|
2343
|
+
resolveColumnHighlightTerms &&
|
|
2344
|
+
isColumnHighlightEnabled(cell.column.id, meta)
|
|
2345
|
+
? resolveColumnHighlightTerms(
|
|
2346
|
+
cell.column.id,
|
|
2347
|
+
highlightQuery
|
|
2348
|
+
)
|
|
2349
|
+
: []
|
|
2350
|
+
|
|
2351
|
+
if (isActionsCell) {
|
|
2352
|
+
return (
|
|
2353
|
+
<td
|
|
2354
|
+
className={cn(
|
|
2355
|
+
"flex shrink-0 border-b border-border px-2 py-1.5 align-middle text-sm text-foreground justify-end text-right",
|
|
2356
|
+
meta.cellClassName
|
|
2357
|
+
)}
|
|
2358
|
+
key={cell.id}
|
|
2359
|
+
style={{
|
|
2360
|
+
paddingLeft:
|
|
2361
|
+
index === 0 ? edgeHorizontalPadding : undefined,
|
|
2362
|
+
paddingRight:
|
|
2363
|
+
index === visibleCells.length - 1
|
|
2364
|
+
? edgeHorizontalPadding
|
|
2365
|
+
: undefined,
|
|
2366
|
+
width: cell.column.getSize(),
|
|
2367
|
+
}}
|
|
2368
|
+
>
|
|
2369
|
+
<div className="w-full min-w-0">
|
|
2370
|
+
<RowActionButtonGroup
|
|
2371
|
+
resolvedActions={visibleRowActions}
|
|
2372
|
+
setStatus={setRowActionStatus}
|
|
2373
|
+
statuses={rowActionStatuses}
|
|
2374
|
+
/>
|
|
2375
|
+
</div>
|
|
2376
|
+
</td>
|
|
2377
|
+
)
|
|
2378
|
+
}
|
|
2379
|
+
|
|
1949
2380
|
return (
|
|
1950
|
-
<
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
)}
|
|
2381
|
+
<DataTableBodyCell
|
|
2382
|
+
cell={cell}
|
|
2383
|
+
dateFormat={dateFormat}
|
|
2384
|
+
highlightTerms={highlightTerms}
|
|
1955
2385
|
key={cell.id}
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
>
|
|
1966
|
-
<div className="w-full min-w-0">
|
|
1967
|
-
<RowActionButtonGroup
|
|
1968
|
-
resolvedActions={visibleRowActions}
|
|
1969
|
-
setStatus={setRowActionStatus}
|
|
1970
|
-
statuses={rowActionStatuses}
|
|
1971
|
-
/>
|
|
1972
|
-
</div>
|
|
1973
|
-
</td>
|
|
2386
|
+
paddingLeft={
|
|
2387
|
+
index === 0 ? edgeHorizontalPadding : undefined
|
|
2388
|
+
}
|
|
2389
|
+
paddingRight={
|
|
2390
|
+
index === visibleCells.length - 1
|
|
2391
|
+
? edgeHorizontalPadding
|
|
2392
|
+
: undefined
|
|
2393
|
+
}
|
|
2394
|
+
/>
|
|
1974
2395
|
)
|
|
1975
|
-
}
|
|
1976
|
-
|
|
1977
|
-
return (
|
|
1978
|
-
<DataTableBodyCell
|
|
1979
|
-
cell={cell}
|
|
1980
|
-
highlightTerms={highlightTerms}
|
|
1981
|
-
key={cell.id}
|
|
1982
|
-
paddingLeft={
|
|
1983
|
-
index === 0 ? edgeHorizontalPadding : undefined
|
|
1984
|
-
}
|
|
1985
|
-
paddingRight={
|
|
1986
|
-
index === visibleCells.length - 1
|
|
1987
|
-
? edgeHorizontalPadding
|
|
1988
|
-
: undefined
|
|
1989
|
-
}
|
|
1990
|
-
/>
|
|
1991
|
-
)
|
|
1992
|
-
})}
|
|
2396
|
+
})
|
|
2397
|
+
)}
|
|
1993
2398
|
</tr>
|
|
1994
2399
|
)
|
|
1995
2400
|
|