datool 0.0.4 → 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 +115 -4
- package/src/client/components/data-table-cell.tsx +19 -6
- package/src/client/components/data-table.tsx +492 -84
- package/src/client/components/viewer-settings.tsx +67 -0
- package/src/client/index.css +3 -0
- package/src/client/lib/datool-url-state.ts +29 -2
- package/src/node/config.ts +22 -0
- package/src/shared/types.ts +4 -0
- package/client-dist/assets/index-B5MN-j1l.js +0 -164
- package/client-dist/assets/index-BkIiz0aS.css +0 -1
|
@@ -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,9 +198,11 @@ 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
|
|
205
|
+
rowStyle?: (row: TData) => React.CSSProperties | undefined
|
|
187
206
|
rowHeight?: number
|
|
188
207
|
statePersistence?: "localStorage" | "none" | "url"
|
|
189
208
|
}
|
|
@@ -226,6 +245,7 @@ type PersistedTableState = {
|
|
|
226
245
|
highlightedColumns?: Record<string, boolean>
|
|
227
246
|
columnVisibility?: VisibilityState
|
|
228
247
|
globalFilter?: string
|
|
248
|
+
grouping?: GroupingState
|
|
229
249
|
sorting?: SortingState
|
|
230
250
|
}
|
|
231
251
|
|
|
@@ -401,6 +421,7 @@ function getPersistedUrlParam(id: string) {
|
|
|
401
421
|
function isPersistedStateEmpty(state: PersistedTableState) {
|
|
402
422
|
return (
|
|
403
423
|
(state.sorting?.length ?? 0) === 0 &&
|
|
424
|
+
(state.grouping?.length ?? 0) === 0 &&
|
|
404
425
|
(state.columnFilters?.length ?? 0) === 0 &&
|
|
405
426
|
Object.keys(state.highlightedColumns ?? {}).length === 0 &&
|
|
406
427
|
Object.keys(state.columnVisibility ?? {}).length === 0 &&
|
|
@@ -495,6 +516,119 @@ function inferWidth(kind: DataTableColumnKind) {
|
|
|
495
516
|
}
|
|
496
517
|
}
|
|
497
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
|
+
|
|
498
632
|
function resolveColumnId<TData extends DataTableRow>(
|
|
499
633
|
column: DataTableColumnConfig<TData>,
|
|
500
634
|
index: number
|
|
@@ -511,6 +645,7 @@ function resolveColumnId<TData extends DataTableRow>(
|
|
|
511
645
|
function buildColumns<TData extends DataTableRow>(
|
|
512
646
|
data: TData[],
|
|
513
647
|
columns?: DataTableColumnConfig<TData>[],
|
|
648
|
+
dateFormat?: DatoolDateFormat,
|
|
514
649
|
showRowSelectionColumn?: boolean,
|
|
515
650
|
showRowActionButtonsColumn?: boolean,
|
|
516
651
|
rowActionsColumnSize?: number
|
|
@@ -552,18 +687,29 @@ function buildColumns<TData extends DataTableRow>(
|
|
|
552
687
|
return {
|
|
553
688
|
accessorFn: column.accessorFn,
|
|
554
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),
|
|
555
698
|
cell: ({ getValue, row }) =>
|
|
556
699
|
column.cell
|
|
557
700
|
? column.cell({ row: row.original, value: getValue() })
|
|
558
701
|
: fallbackCellValue(getValue(), kind, {
|
|
702
|
+
dateFormat,
|
|
559
703
|
enumColors: kind === "enum" ? column.enumColors : undefined,
|
|
560
704
|
enumOptions: kind === "enum" ? column.enumOptions : undefined,
|
|
561
705
|
}),
|
|
562
706
|
enableGlobalFilter: column.enableFiltering ?? true,
|
|
707
|
+
enableGrouping: column.enableGrouping ?? true,
|
|
563
708
|
filterFn: column.filterFn,
|
|
564
709
|
enableHiding: column.enableHiding ?? true,
|
|
565
710
|
enableResizing: column.enableResizing ?? true,
|
|
566
711
|
enableSorting: column.enableSorting ?? true,
|
|
712
|
+
getGroupingValue: column.getGroupingValue,
|
|
567
713
|
header: column.header ?? formatHeaderLabel(id),
|
|
568
714
|
id,
|
|
569
715
|
maxSize: column.maxWidth ?? 420,
|
|
@@ -582,6 +728,7 @@ function buildColumns<TData extends DataTableRow>(
|
|
|
582
728
|
...builtColumns,
|
|
583
729
|
{
|
|
584
730
|
cell: () => null,
|
|
731
|
+
enableGrouping: false,
|
|
585
732
|
enableGlobalFilter: false,
|
|
586
733
|
enableHiding: false,
|
|
587
734
|
enableResizing: false,
|
|
@@ -603,13 +750,16 @@ function buildColumns<TData extends DataTableRow>(
|
|
|
603
750
|
{
|
|
604
751
|
cell: ({ row }) => (
|
|
605
752
|
<div className="flex items-center justify-center">
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
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}
|
|
611
760
|
</div>
|
|
612
761
|
),
|
|
762
|
+
enableGrouping: false,
|
|
613
763
|
enableGlobalFilter: false,
|
|
614
764
|
enableHiding: false,
|
|
615
765
|
enableResizing: false,
|
|
@@ -648,6 +798,7 @@ function buildColumns<TData extends DataTableRow>(
|
|
|
648
798
|
...withSelectionColumn,
|
|
649
799
|
{
|
|
650
800
|
cell: () => null,
|
|
801
|
+
enableGrouping: false,
|
|
651
802
|
enableGlobalFilter: false,
|
|
652
803
|
enableHiding: false,
|
|
653
804
|
enableResizing: false,
|
|
@@ -703,6 +854,31 @@ function shouldIgnoreRowSelectionTarget(target: EventTarget | null) {
|
|
|
703
854
|
)
|
|
704
855
|
}
|
|
705
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
|
+
|
|
706
882
|
function resolveRowActionRows<TData extends DataTableRow>(
|
|
707
883
|
action: DataTableRowAction<TData>,
|
|
708
884
|
row: Row<TData>,
|
|
@@ -1118,6 +1294,21 @@ function RowActionButtonGroup<TData extends DataTableRow>({
|
|
|
1118
1294
|
)
|
|
1119
1295
|
}
|
|
1120
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
|
+
|
|
1121
1312
|
function DataTableView<TData extends DataTableRow>({
|
|
1122
1313
|
autoScrollToBottom = false,
|
|
1123
1314
|
autoScrollToBottomThreshold = 96,
|
|
@@ -1125,10 +1316,12 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1125
1316
|
columnVisibility: controlledColumnVisibility,
|
|
1126
1317
|
columns,
|
|
1127
1318
|
data,
|
|
1319
|
+
dateFormat,
|
|
1128
1320
|
edgeHorizontalPadding = "16px",
|
|
1129
1321
|
enableRowSelection = false,
|
|
1130
1322
|
filterPlaceholder = "Search across visible columns",
|
|
1131
1323
|
globalFilter,
|
|
1324
|
+
grouping: controlledGrouping,
|
|
1132
1325
|
getRowId,
|
|
1133
1326
|
height = 620,
|
|
1134
1327
|
highlightQuery = "",
|
|
@@ -1136,9 +1329,11 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1136
1329
|
onColumnFiltersChange,
|
|
1137
1330
|
onColumnVisibilityChange,
|
|
1138
1331
|
onGlobalFilterChange,
|
|
1332
|
+
onGroupingChange,
|
|
1139
1333
|
resolveColumnHighlightTerms,
|
|
1140
1334
|
rowActions,
|
|
1141
1335
|
rowClassName,
|
|
1336
|
+
rowStyle,
|
|
1142
1337
|
rowHeight = 48,
|
|
1143
1338
|
statePersistence = "localStorage",
|
|
1144
1339
|
}: DataTableProps<TData>) {
|
|
@@ -1161,6 +1356,9 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1161
1356
|
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
|
1162
1357
|
() => persistedState.columnFilters ?? []
|
|
1163
1358
|
)
|
|
1359
|
+
const [grouping, setGrouping] = React.useState<GroupingState>(
|
|
1360
|
+
() => persistedState.grouping ?? []
|
|
1361
|
+
)
|
|
1164
1362
|
const [rowSelection, setRowSelection] = React.useState<RowSelectionState>({})
|
|
1165
1363
|
const [rowActionStatuses, setRowActionStatuses] = React.useState<
|
|
1166
1364
|
Record<string, RowActionStatus>
|
|
@@ -1183,9 +1381,11 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1183
1381
|
const isColumnFiltersControlled = controlledColumnFilters !== undefined
|
|
1184
1382
|
const isColumnVisibilityControlled = controlledColumnVisibility !== undefined
|
|
1185
1383
|
const isGlobalFilterControlled = globalFilter !== undefined
|
|
1384
|
+
const isGroupingControlled = controlledGrouping !== undefined
|
|
1186
1385
|
const resolvedColumnFilters = controlledColumnFilters ?? columnFilters
|
|
1187
1386
|
const resolvedColumnVisibility =
|
|
1188
1387
|
controlledColumnVisibility ?? columnVisibility
|
|
1388
|
+
const resolvedGrouping = controlledGrouping ?? grouping
|
|
1189
1389
|
const hasSelectionActions = rowActions
|
|
1190
1390
|
? hasSelectionScopedAction(rowActions)
|
|
1191
1391
|
: false
|
|
@@ -1232,6 +1432,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1232
1432
|
buildColumns(
|
|
1233
1433
|
data,
|
|
1234
1434
|
columnsWithEnumOptions,
|
|
1435
|
+
dateFormat,
|
|
1235
1436
|
showRowSelectionColumn,
|
|
1236
1437
|
showRowActionButtonsColumn,
|
|
1237
1438
|
rowActionsColumnSize
|
|
@@ -1239,6 +1440,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1239
1440
|
[
|
|
1240
1441
|
columnsWithEnumOptions,
|
|
1241
1442
|
data,
|
|
1443
|
+
dateFormat,
|
|
1242
1444
|
rowActionsColumnSize,
|
|
1243
1445
|
showRowActionButtonsColumn,
|
|
1244
1446
|
showRowSelectionColumn,
|
|
@@ -1312,28 +1514,52 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1312
1514
|
resolvedColumnVisibility,
|
|
1313
1515
|
]
|
|
1314
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
|
+
)
|
|
1315
1533
|
|
|
1316
1534
|
const table = useReactTable({
|
|
1317
1535
|
columnResizeMode: "onChange",
|
|
1318
1536
|
columns: tableColumns,
|
|
1319
1537
|
data,
|
|
1320
1538
|
enableColumnResizing: true,
|
|
1321
|
-
|
|
1539
|
+
enableGrouping: true,
|
|
1540
|
+
enableRowSelection: canSelectRows ? (row) => !row.getIsGrouped() : false,
|
|
1541
|
+
enableSubRowSelection: false,
|
|
1322
1542
|
getCoreRowModel: getCoreRowModel(),
|
|
1543
|
+
getExpandedRowModel: getExpandedRowModel(),
|
|
1323
1544
|
getFilteredRowModel: getFilteredRowModel(),
|
|
1545
|
+
getGroupedRowModel: getGroupedRowModel(),
|
|
1324
1546
|
getRowId,
|
|
1325
1547
|
getSortedRowModel: getSortedRowModel(),
|
|
1548
|
+
groupedColumnMode: false,
|
|
1326
1549
|
globalFilterFn: globalFilterFn as FilterFn<TData>,
|
|
1327
1550
|
onColumnFiltersChange: handleColumnFiltersChange,
|
|
1328
1551
|
onColumnSizingChange: handleColumnSizingChange,
|
|
1329
1552
|
onColumnVisibilityChange: handleColumnVisibilityChange,
|
|
1553
|
+
onGroupingChange: handleGroupingChange,
|
|
1330
1554
|
onRowSelectionChange: setRowSelection,
|
|
1331
1555
|
onSortingChange: setSorting,
|
|
1332
1556
|
state: {
|
|
1333
1557
|
columnFilters: resolvedColumnFilters,
|
|
1334
1558
|
columnSizing,
|
|
1335
1559
|
columnVisibility: resolvedColumnVisibility,
|
|
1560
|
+
expanded: expandedState,
|
|
1336
1561
|
globalFilter: deferredSearch.trim(),
|
|
1562
|
+
grouping: resolvedGrouping,
|
|
1337
1563
|
rowSelection,
|
|
1338
1564
|
sorting,
|
|
1339
1565
|
},
|
|
@@ -1344,6 +1570,10 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1344
1570
|
const hasAutoScrolledOnMountRef = React.useRef(false)
|
|
1345
1571
|
const previousDataLengthRef = React.useRef(0)
|
|
1346
1572
|
const rows = table.getRowModel().rows
|
|
1573
|
+
const selectableRows = React.useMemo(
|
|
1574
|
+
() => rows.filter((row) => row.getCanSelect()),
|
|
1575
|
+
[rows]
|
|
1576
|
+
)
|
|
1347
1577
|
const selectedTableRows = table.getSelectedRowModel().rows
|
|
1348
1578
|
const resolvedHeight = typeof height === "number" ? height : 0
|
|
1349
1579
|
const initialOffsetRef = React.useRef(
|
|
@@ -1385,6 +1615,9 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1385
1615
|
}
|
|
1386
1616
|
setHighlightedColumns(nextState.highlightedColumns ?? {})
|
|
1387
1617
|
setColumnFilters(nextState.columnFilters ?? [])
|
|
1618
|
+
if (!isGroupingControlled) {
|
|
1619
|
+
setGrouping(nextState.grouping ?? [])
|
|
1620
|
+
}
|
|
1388
1621
|
setSearchDraft(nextState.globalFilter ?? "")
|
|
1389
1622
|
setRowSelection({})
|
|
1390
1623
|
dragSelectionRef.current = null
|
|
@@ -1396,7 +1629,13 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1396
1629
|
}
|
|
1397
1630
|
rowActionStatusTimersRef.current = {}
|
|
1398
1631
|
setRowActionStatuses({})
|
|
1399
|
-
}, [
|
|
1632
|
+
}, [
|
|
1633
|
+
id,
|
|
1634
|
+
isColumnFiltersControlled,
|
|
1635
|
+
isColumnVisibilityControlled,
|
|
1636
|
+
isGroupingControlled,
|
|
1637
|
+
statePersistence,
|
|
1638
|
+
])
|
|
1400
1639
|
|
|
1401
1640
|
React.useEffect(() => {
|
|
1402
1641
|
if (!isColumnFiltersControlled) {
|
|
@@ -1414,6 +1653,14 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1414
1653
|
setColumnVisibility(controlledColumnVisibility)
|
|
1415
1654
|
}, [controlledColumnVisibility, isColumnVisibilityControlled])
|
|
1416
1655
|
|
|
1656
|
+
React.useEffect(() => {
|
|
1657
|
+
if (!isGroupingControlled) {
|
|
1658
|
+
return
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
setGrouping(controlledGrouping)
|
|
1662
|
+
}, [controlledGrouping, isGroupingControlled])
|
|
1663
|
+
|
|
1417
1664
|
React.useEffect(() => {
|
|
1418
1665
|
if (!isGlobalFilterControlled) {
|
|
1419
1666
|
return
|
|
@@ -1437,6 +1684,9 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1437
1684
|
}
|
|
1438
1685
|
setHighlightedColumns(nextState.highlightedColumns ?? {})
|
|
1439
1686
|
setColumnFilters(nextState.columnFilters ?? [])
|
|
1687
|
+
if (!isGroupingControlled) {
|
|
1688
|
+
setGrouping(nextState.grouping ?? [])
|
|
1689
|
+
}
|
|
1440
1690
|
setSearchDraft(nextState.globalFilter ?? "")
|
|
1441
1691
|
setRowSelection({})
|
|
1442
1692
|
dragSelectionRef.current = null
|
|
@@ -1448,7 +1698,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1448
1698
|
window.addEventListener("popstate", syncFromUrl)
|
|
1449
1699
|
|
|
1450
1700
|
return () => window.removeEventListener("popstate", syncFromUrl)
|
|
1451
|
-
}, [id, isColumnVisibilityControlled, statePersistence])
|
|
1701
|
+
}, [id, isColumnVisibilityControlled, isGroupingControlled, statePersistence])
|
|
1452
1702
|
|
|
1453
1703
|
React.useEffect(() => {
|
|
1454
1704
|
if (isGlobalFilterControlled || isColumnFiltersControlled) {
|
|
@@ -1461,6 +1711,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1461
1711
|
highlightedColumns,
|
|
1462
1712
|
columnVisibility: resolvedColumnVisibility,
|
|
1463
1713
|
globalFilter: deferredSearch.trim(),
|
|
1714
|
+
grouping: resolvedGrouping,
|
|
1464
1715
|
sorting,
|
|
1465
1716
|
})
|
|
1466
1717
|
}, [
|
|
@@ -1471,7 +1722,9 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1471
1722
|
id,
|
|
1472
1723
|
isColumnFiltersControlled,
|
|
1473
1724
|
isGlobalFilterControlled,
|
|
1725
|
+
isGroupingControlled,
|
|
1474
1726
|
resolvedColumnVisibility,
|
|
1727
|
+
resolvedGrouping,
|
|
1475
1728
|
sorting,
|
|
1476
1729
|
statePersistence,
|
|
1477
1730
|
])
|
|
@@ -1577,6 +1830,13 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1577
1830
|
|
|
1578
1831
|
onGlobalFilterChange?.(value)
|
|
1579
1832
|
}
|
|
1833
|
+
const clearRowSelection = React.useCallback(() => {
|
|
1834
|
+
setRowSelection({})
|
|
1835
|
+
dragSelectionRef.current = null
|
|
1836
|
+
dragPointerRef.current = null
|
|
1837
|
+
setIsDragSelecting(false)
|
|
1838
|
+
selectionAnchorIdRef.current = null
|
|
1839
|
+
}, [])
|
|
1580
1840
|
|
|
1581
1841
|
const isColumnHighlightEnabled = React.useCallback(
|
|
1582
1842
|
(columnId: string, meta: DataTableColumnMeta) =>
|
|
@@ -1589,10 +1849,10 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1589
1849
|
rowId: string,
|
|
1590
1850
|
baseSelection: RowSelectionState = {}
|
|
1591
1851
|
) => {
|
|
1592
|
-
const anchorIndex =
|
|
1852
|
+
const anchorIndex = selectableRows.findIndex(
|
|
1593
1853
|
(candidateRow) => candidateRow.id === anchorId
|
|
1594
1854
|
)
|
|
1595
|
-
const rowIndex =
|
|
1855
|
+
const rowIndex = selectableRows.findIndex(
|
|
1596
1856
|
(candidateRow) => candidateRow.id === rowId
|
|
1597
1857
|
)
|
|
1598
1858
|
|
|
@@ -1608,13 +1868,13 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1608
1868
|
setRowSelection({
|
|
1609
1869
|
...baseSelection,
|
|
1610
1870
|
...Object.fromEntries(
|
|
1611
|
-
|
|
1871
|
+
selectableRows
|
|
1612
1872
|
.slice(start, end + 1)
|
|
1613
1873
|
.map((candidateRow) => [candidateRow.id, true])
|
|
1614
1874
|
),
|
|
1615
1875
|
})
|
|
1616
1876
|
},
|
|
1617
|
-
[
|
|
1877
|
+
[selectableRows]
|
|
1618
1878
|
)
|
|
1619
1879
|
const selectSingleRow = React.useCallback((rowId: string) => {
|
|
1620
1880
|
selectionAnchorIdRef.current = rowId
|
|
@@ -1661,6 +1921,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1661
1921
|
if (
|
|
1662
1922
|
event.button !== 0 ||
|
|
1663
1923
|
!canSelectRows ||
|
|
1924
|
+
!row.getCanSelect() ||
|
|
1664
1925
|
shouldIgnoreRowSelectionTarget(event.target)
|
|
1665
1926
|
) {
|
|
1666
1927
|
return
|
|
@@ -1722,6 +1983,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1722
1983
|
(event: React.MouseEvent<HTMLTableRowElement>, row: Row<TData>) => {
|
|
1723
1984
|
if (
|
|
1724
1985
|
!canSelectRows ||
|
|
1986
|
+
!row.getCanSelect() ||
|
|
1725
1987
|
event.buttons !== 1 ||
|
|
1726
1988
|
shouldIgnoreRowSelectionTarget(event.target) ||
|
|
1727
1989
|
!dragSelectionRef.current
|
|
@@ -1737,7 +1999,7 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1737
1999
|
)
|
|
1738
2000
|
const handleRowContextMenu = React.useCallback(
|
|
1739
2001
|
(row: Row<TData>) => {
|
|
1740
|
-
if (!canSelectRows) {
|
|
2002
|
+
if (!canSelectRows || !row.getCanSelect()) {
|
|
1741
2003
|
return
|
|
1742
2004
|
}
|
|
1743
2005
|
|
|
@@ -1817,6 +2079,27 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1817
2079
|
window.cancelAnimationFrame(frameId)
|
|
1818
2080
|
}
|
|
1819
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])
|
|
1820
2103
|
|
|
1821
2104
|
return (
|
|
1822
2105
|
<section
|
|
@@ -1894,99 +2177,224 @@ function DataTableView<TData extends DataTableRow>({
|
|
|
1894
2177
|
) : (
|
|
1895
2178
|
virtualRows.map((virtualRow) => {
|
|
1896
2179
|
const row = rows[virtualRow.index]
|
|
1897
|
-
const
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
2180
|
+
const isGroupRow = row.getIsGrouped()
|
|
2181
|
+
const visibleRowActions = isGroupRow
|
|
2182
|
+
? []
|
|
2183
|
+
: resolveVisibleRowActions(
|
|
2184
|
+
rowActions ?? [],
|
|
2185
|
+
row,
|
|
2186
|
+
selectedTableRows
|
|
2187
|
+
)
|
|
1902
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
|
+
: []
|
|
1903
2231
|
const rowContent = (
|
|
1904
2232
|
<tr
|
|
1905
2233
|
aria-selected={isSelected}
|
|
1906
2234
|
className={cn(
|
|
1907
|
-
"absolute left-0 flex w-full
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
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 &&
|
|
1911
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-['']"
|
|
1912
2246
|
)}
|
|
1913
2247
|
data-index={virtualRow.index}
|
|
1914
2248
|
data-row-id={row.id}
|
|
1915
|
-
data-state={isSelected ? "selected" : undefined}
|
|
2249
|
+
data-state={!isGroupRow && isSelected ? "selected" : undefined}
|
|
1916
2250
|
key={row.id}
|
|
1917
|
-
onContextMenu={
|
|
1918
|
-
|
|
1919
|
-
|
|
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
|
+
}
|
|
1920
2264
|
ref={(node) => {
|
|
1921
2265
|
if (node) {
|
|
1922
2266
|
rowVirtualizer.measureElement(node)
|
|
1923
2267
|
}
|
|
1924
2268
|
}}
|
|
1925
2269
|
style={{
|
|
1926
|
-
|
|
2270
|
+
...(!isGroupRow ? rowStyle?.(row.original) : undefined),
|
|
2271
|
+
minHeight: isGroupRow ? Math.max(rowHeight, 44) : rowHeight,
|
|
1927
2272
|
transform: `translateY(${virtualRow.start}px)`,
|
|
1928
2273
|
width: table.getTotalSize(),
|
|
1929
2274
|
}}
|
|
1930
2275
|
>
|
|
1931
|
-
{
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
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
|
+
|
|
1946
2380
|
return (
|
|
1947
|
-
<
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
)}
|
|
2381
|
+
<DataTableBodyCell
|
|
2382
|
+
cell={cell}
|
|
2383
|
+
dateFormat={dateFormat}
|
|
2384
|
+
highlightTerms={highlightTerms}
|
|
1952
2385
|
key={cell.id}
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
>
|
|
1963
|
-
<div className="w-full min-w-0">
|
|
1964
|
-
<RowActionButtonGroup
|
|
1965
|
-
resolvedActions={visibleRowActions}
|
|
1966
|
-
setStatus={setRowActionStatus}
|
|
1967
|
-
statuses={rowActionStatuses}
|
|
1968
|
-
/>
|
|
1969
|
-
</div>
|
|
1970
|
-
</td>
|
|
2386
|
+
paddingLeft={
|
|
2387
|
+
index === 0 ? edgeHorizontalPadding : undefined
|
|
2388
|
+
}
|
|
2389
|
+
paddingRight={
|
|
2390
|
+
index === visibleCells.length - 1
|
|
2391
|
+
? edgeHorizontalPadding
|
|
2392
|
+
: undefined
|
|
2393
|
+
}
|
|
2394
|
+
/>
|
|
1971
2395
|
)
|
|
1972
|
-
}
|
|
1973
|
-
|
|
1974
|
-
return (
|
|
1975
|
-
<DataTableBodyCell
|
|
1976
|
-
cell={cell}
|
|
1977
|
-
highlightTerms={highlightTerms}
|
|
1978
|
-
key={cell.id}
|
|
1979
|
-
paddingLeft={
|
|
1980
|
-
index === 0 ? edgeHorizontalPadding : undefined
|
|
1981
|
-
}
|
|
1982
|
-
paddingRight={
|
|
1983
|
-
index === visibleCells.length - 1
|
|
1984
|
-
? edgeHorizontalPadding
|
|
1985
|
-
: undefined
|
|
1986
|
-
}
|
|
1987
|
-
/>
|
|
1988
|
-
)
|
|
1989
|
-
})}
|
|
2396
|
+
})
|
|
2397
|
+
)}
|
|
1990
2398
|
</tr>
|
|
1991
2399
|
)
|
|
1992
2400
|
|