Skip to content

Commit af5a5ac

Browse files
authored
Feat/virtualize netdata table (#411)
* remove container from Table at base table * add virtualize to netdata table * add constants file for netdata table * enable virtualization * add correct colour of stripes at table * enbable colum pinning at netdata table stories * if pagiantion is not enabled swap to manual pagination * minor fixes at table styling * add cell height in constants
1 parent 7e2290e commit af5a5ac

File tree

11 files changed

+140
-71
lines changed

11 files changed

+140
-71
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"@prismicio/client": "5.1.1",
3838
"@styled-system/css": "^5.1.5",
3939
"@tanstack/react-table": "^8.5.11",
40+
"@tanstack/react-virtual": "^3.0.0-beta.23",
4041
"axios": "^0.27.2",
4142
"polished": "^4.2.2",
4243
"ramda": "^0.28.0",

src/components/tableV2/constants.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const TABLE_HEAD_HEIGHT = 91
2+
export const CELL_HEIGHT = 65

src/components/tableV2/core/base-table.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ import useToggle from "src/hooks/use-toggle"
1717
const StyledRow = styled.tr`
1818
font-size: 14px;
1919
color: ${getColor("text")};
20-
background: ${getColor("mainBackground")};
21-
&:nth-child(2n) {
22-
background: ${getColor("tableRowBg")};
23-
}
2420
width: fit-content;
2521
`
2622
const StyledHeaderRow = styled.tr`

src/components/tableV2/core/fullTable.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const FullTable = ({
2020
testPrefix,
2121
testPrefixCallback,
2222
width,
23+
scrollParentRef,
2324
}) => {
2425
return (
2526
<Table
@@ -31,11 +32,19 @@ const FullTable = ({
3132
>
3233
<Table.Head data-testid={`netdata-table-head${testPrefix}`}>
3334
<Table.HeadRow data-testid={`netdata-table-headRow${testPrefix}`}>
34-
{makeHeadCell({ enableResize, enableSorting, headers, pinnedStyles, table, testPrefix })}
35+
{makeHeadCell({
36+
enableResize,
37+
enableSorting,
38+
headers,
39+
pinnedStyles,
40+
table,
41+
testPrefix,
42+
})}
3543
</Table.HeadRow>
3644
</Table.Head>
3745
<Table.Body data-testid={`netdata-table-body${testPrefix}`}>
3846
<Rows
47+
scrollParentRef={scrollParentRef}
3948
disableClickRow={disableClickRow}
4049
flexRender={flexRender}
4150
getRowHandler={getRowHandler}

src/components/tableV2/core/row.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const Row = ({
1313
onMouseEnter,
1414
onMouseLeave,
1515
isHovering,
16+
background,
1617
}) => {
1718
return (
1819
<Table.Row
@@ -26,6 +27,7 @@ const Row = ({
2627
onMouseEnter={onMouseEnter}
2728
onMouseLeave={onMouseLeave}
2829
isHovering={isHovering}
30+
background={background}
2931
>
3032
{children}
3133
</Table.Row>

src/components/tableV2/core/rows.js

Lines changed: 66 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import Row from "./row"
44
import DataCell from "./dataCell"
55

66
import useSharedTable from "../hooks/useSharedTable"
7+
import { useVirtualizer } from "@tanstack/react-virtual"
8+
9+
import { CELL_HEIGHT } from "../constants"
710

811
const Rows = ({
912
disableClickRow,
@@ -15,8 +18,24 @@ const Rows = ({
1518
table,
1619
testPrefix,
1720
testPrefixCallback,
21+
scrollParentRef,
1822
}) => {
1923
const { state, updateState } = useSharedTable({})
24+
const { rows } = table.getRowModel()
25+
26+
const virtualizer = useVirtualizer({
27+
count: rows.length,
28+
getScrollElement: () => scrollParentRef.current,
29+
estimateSize: () => CELL_HEIGHT,
30+
overscan: 20,
31+
})
32+
33+
const virtualRows = virtualizer.getVirtualItems()
34+
const totalSize = virtualizer.getTotalSize()
35+
36+
const paddingTop = virtualRows.length > 0 ? virtualRows?.[0]?.start || 0 : 0
37+
const paddingBottom =
38+
virtualRows.length > 0 ? totalSize - (virtualRows?.[virtualRows.length - 1]?.end || 0) : 0
2039

2140
const handleOnMouseEnter = useCallback(
2241
id => {
@@ -29,40 +48,56 @@ const Rows = ({
2948
const handleOnMouseLeave = useCallback(() => {
3049
updateState({ currentHoveredRow: null })
3150
}, [onHoverRow, updateState])
51+
return (
52+
<>
53+
{paddingTop > 0 && (
54+
<tr>
55+
<td style={{ height: `${paddingTop}px` }} />
56+
</tr>
57+
)}
58+
{virtualizer.getVirtualItems().map(({ index }) => {
59+
const row = rows[index]
60+
const cells = row[getRowHandler]()
3261

33-
return table.getRowModel().rows.map(row => {
34-
const cells = row[getRowHandler]()
62+
return (
63+
<Row
64+
id={row.id}
65+
key={row.id}
66+
testPrefix={testPrefix}
67+
testPrefixCallback={testPrefixCallback}
68+
row={row}
69+
table={table}
70+
onClickRow={onClickRow}
71+
disableClickRow={disableClickRow}
72+
onMouseEnter={() => handleOnMouseEnter(row.id)}
73+
onMouseLeave={handleOnMouseLeave}
74+
isHovering={row.id === state?.currentHoveredRow}
75+
background={index % 2 == 0 ? "mainBackground" : "tableRowBg"}
76+
>
77+
{cells.map((cell, index) => {
78+
const isLast = cells.length === index + 1
3579

36-
return (
37-
<Row
38-
id={row.id}
39-
key={row.id}
40-
testPrefix={testPrefix}
41-
testPrefixCallback={testPrefixCallback}
42-
row={row}
43-
table={table}
44-
onClickRow={onClickRow}
45-
disableClickRow={disableClickRow}
46-
onMouseEnter={() => handleOnMouseEnter(row.id)}
47-
onMouseLeave={handleOnMouseLeave}
48-
isHovering={row.id === state?.currentHoveredRow}
49-
>
50-
{cells.map((cell, index) => {
51-
const isLast = cells.length === index + 1
80+
return (
81+
<DataCell
82+
cell={cell}
83+
flexRender={flexRender}
84+
key={cell.column.columnDef.id}
85+
pinnedStyles={isLast ? pinnedStyles : {}}
86+
testPrefix={testPrefix}
87+
/>
88+
)
89+
})}
90+
</Row>
91+
)
92+
})}
5293

53-
return (
54-
<DataCell
55-
cell={cell}
56-
flexRender={flexRender}
57-
key={cell.column.columnDef.id}
58-
pinnedStyles={isLast ? pinnedStyles : {}}
59-
testPrefix={testPrefix}
60-
/>
61-
)
62-
})}
63-
</Row>
64-
)
65-
})
94+
{paddingBottom > 0 && (
95+
<tr>
96+
<td style={{ height: `${paddingBottom}px` }} />
97+
</tr>
98+
)}
99+
</>
100+
)
66101
}
67102

68103
export default Rows

src/components/tableV2/features/columnPinning.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const ColumnPinning = ({
1414
table,
1515
testPrefix,
1616
testPrefixCallback,
17+
scrollParentRef,
1718
}) => {
1819
const getThemeColor = useColor()
1920
const headers = table.getLeftFlatHeaders()
@@ -28,6 +29,7 @@ const ColumnPinning = ({
2829
}}
2930
>
3031
<FullTable
32+
scrollParentRef={scrollParentRef}
3133
dataGa={`pin-${dataGa}`}
3234
disableClickRow={disableClickRow}
3335
enableResize={enableResize}

src/components/tableV2/features/mainTable.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ const MainTable = ({
1515
flexRender,
1616
onHoverRow,
1717
enableResize,
18+
scrollParentRef,
1819
}) => {
1920
const headers = enableColumnPinning ? table.getCenterFlatHeaders() : table.getFlatHeaders()
2021

2122
return (
2223
<FullTable
24+
scrollParentRef={scrollParentRef}
2325
width={enableResize ? `${table.getTotalSize()}px` : "100%"}
2426
enableResize={enableResize}
2527
onHoverRow={onHoverRow}

src/components/tableV2/netdataTable.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//TODO refactor bulk action and row action to single funtion to decrease repeatabillity
2-
import React, { useEffect, useMemo, useState, useCallback } from "react"
2+
import React, { useEffect, useMemo, useState, useCallback, useRef } from "react"
33

44
import {
55
flexRender,
@@ -70,6 +70,8 @@ const NetdataTable = ({
7070
pageSize: paginationOptions.pageSize,
7171
})
7272

73+
const scrollParentRef = useRef()
74+
7375
const handleGlobalSearch = useCallback(value => {
7476
onGlobalSearchChange?.(value)
7577
setGlobalFilter(String(value))
@@ -150,6 +152,7 @@ const NetdataTable = ({
150152
const table = useReactTable({
151153
columns: [...makeSelectionColumn, ...makeDataColumns, ...makeActionsColumn],
152154
data: data,
155+
manualPagination: !enablePagination,
153156
columnResizeMode: enableResize ? "onEnd" : "",
154157
filterFns: {
155158
comparison,
@@ -200,7 +203,12 @@ const NetdataTable = ({
200203
dataGa={dataGa}
201204
bulkActions={renderBulkActions}
202205
/>
203-
<Flex overflow={{ vertical: "auto", horizontal: "auto" }} width="100%" height="100%">
206+
<Flex
207+
ref={scrollParentRef}
208+
overflow={{ vertical: "auto", horizontal: "auto" }}
209+
width="100%"
210+
height="100%"
211+
>
204212
{enableColumnPinning && (
205213
<ColumnPinning
206214
enableResize={enableResize}
@@ -214,9 +222,11 @@ const NetdataTable = ({
214222
dataGa={dataGa}
215223
flexRender={flexRender}
216224
onHoverRow={onHoverRow}
225+
scrollParentRef={scrollParentRef}
217226
/>
218227
)}
219228
<MainTable
229+
scrollParentRef={scrollParentRef}
220230
enableResize={enableResize}
221231
disableClickRow={disableClickRow}
222232
onClickRow={onClickRow}

src/components/tableV2/netdataTable.stories.js

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -417,45 +417,45 @@ StoryTable.add("Full Table functionallity", () => {
417417

418418
const mockData = () => [
419419
{
420-
nodes: "node8",
420+
nodes: "node31",
421421
alerts: 15,
422422
user: "mitsos",
423423
disabled: true,
424424
status: "stale",
425425
untouchable: "true",
426426
},
427-
{ nodes: "node9", alerts: 11, user: "koukouroukou", status: "offline", untouchable: "true" },
428-
{ nodes: "node10", alerts: 22, user: "reena", status: "online", untouchable: "true" },
427+
{ nodes: "node0", alerts: 11, user: "koukouroukou", status: "offline", untouchable: "true" },
428+
{ nodes: "node1", alerts: 22, user: "reena", status: "online", untouchable: "true" },
429429
{ nodes: "node1", alerts: 15, user: "nic", status: "online", untouchable: "true" },
430430
{ nodes: "node2", alerts: 11, user: "alex", status: "offline", untouchable: "true" },
431-
{ nodes: "node34", alerts: 22, user: "manolis", status: "offline", untouchable: "true" },
432-
{ nodes: "node5", alerts: 15, user: "achile", status: "stale", untouchable: "true" },
433-
{ nodes: "node6", alerts: 11, user: "barba", status: "stale", untouchable: "false" },
434-
{ nodes: "node7", alerts: 22, user: "decker", status: "online", untouchable: "false" },
435-
{ nodes: "node9", alerts: 11, user: "koukouroukou", status: "offline", untouchable: "true" },
436-
{ nodes: "node10", alerts: 22, user: "reena", status: "online", untouchable: "true" },
437-
{ nodes: "node1", alerts: 15, user: "nic", status: "online", untouchable: "true" },
438-
{ nodes: "node2", alerts: 11, user: "alex", status: "offline", untouchable: "true" },
439-
{ nodes: "node34", alerts: 22, user: "manolis", status: "offline", untouchable: "true" },
440-
{ nodes: "node5", alerts: 15, user: "achile", status: "stale", untouchable: "true" },
441-
{ nodes: "node6", alerts: 11, user: "barba", status: "stale", untouchable: "false" },
442-
{ nodes: "node7", alerts: 22, user: "decker", status: "online", untouchable: "false" },
443-
{ nodes: "node9", alerts: 11, user: "koukouroukou", status: "offline", untouchable: "true" },
444-
{ nodes: "node10", alerts: 22, user: "reena", status: "online", untouchable: "true" },
445-
{ nodes: "node1", alerts: 15, user: "nic", status: "online", untouchable: "true" },
446-
{ nodes: "node2", alerts: 11, user: "alex", status: "offline", untouchable: "true" },
447-
{ nodes: "node34", alerts: 22, user: "manolis", status: "offline", untouchable: "true" },
448-
{ nodes: "node5", alerts: 15, user: "achile", status: "stale", untouchable: "true" },
449-
{ nodes: "node6", alerts: 11, user: "barba", status: "stale", untouchable: "false" },
450-
{ nodes: "node7", alerts: 22, user: "decker", status: "online", untouchable: "false" },
451-
{ nodes: "node9", alerts: 11, user: "koukouroukou", status: "offline", untouchable: "true" },
452-
{ nodes: "node10", alerts: 22, user: "reena", status: "online", untouchable: "true" },
453-
{ nodes: "node1", alerts: 15, user: "nic", status: "online", untouchable: "true" },
454-
{ nodes: "node2", alerts: 11, user: "alex", status: "offline", untouchable: "true" },
455-
{ nodes: "node34", alerts: 22, user: "manolis", status: "offline", untouchable: "true" },
456-
{ nodes: "node5", alerts: 15, user: "achile", status: "stale", untouchable: "true" },
457-
{ nodes: "node6", alerts: 11, user: "barba", status: "stale", untouchable: "false" },
458-
{ nodes: "node7", alerts: 22, user: "decker", status: "online", untouchable: "false" },
431+
{ nodes: "node3", alerts: 22, user: "manolis", status: "offline", untouchable: "true" },
432+
{ nodes: "node4", alerts: 15, user: "achile", status: "stale", untouchable: "true" },
433+
{ nodes: "node5", alerts: 11, user: "barba", status: "stale", untouchable: "false" },
434+
{ nodes: "node6", alerts: 22, user: "decker", status: "online", untouchable: "false" },
435+
{ nodes: "node7", alerts: 11, user: "koukouroukou", status: "offline", untouchable: "true" },
436+
{ nodes: "node8", alerts: 22, user: "reena", status: "online", untouchable: "true" },
437+
{ nodes: "node9", alerts: 15, user: "nic", status: "online", untouchable: "true" },
438+
{ nodes: "node10", alerts: 11, user: "alex", status: "offline", untouchable: "true" },
439+
{ nodes: "node11", alerts: 22, user: "manolis", status: "offline", untouchable: "true" },
440+
{ nodes: "node12", alerts: 15, user: "achile", status: "stale", untouchable: "true" },
441+
{ nodes: "node13", alerts: 11, user: "barba", status: "stale", untouchable: "false" },
442+
{ nodes: "node14", alerts: 22, user: "decker", status: "online", untouchable: "false" },
443+
{ nodes: "node15", alerts: 11, user: "koukouroukou", status: "offline", untouchable: "true" },
444+
{ nodes: "node16", alerts: 22, user: "reena", status: "online", untouchable: "true" },
445+
{ nodes: "node17", alerts: 15, user: "nic", status: "online", untouchable: "true" },
446+
{ nodes: "node18", alerts: 11, user: "alex", status: "offline", untouchable: "true" },
447+
{ nodes: "node19", alerts: 22, user: "manolis", status: "offline", untouchable: "true" },
448+
{ nodes: "node20", alerts: 15, user: "achile", status: "stale", untouchable: "true" },
449+
{ nodes: "node21", alerts: 11, user: "barba", status: "stale", untouchable: "false" },
450+
{ nodes: "node22", alerts: 22, user: "decker", status: "online", untouchable: "false" },
451+
{ nodes: "node23", alerts: 11, user: "koukouroukou", status: "offline", untouchable: "true" },
452+
{ nodes: "node24", alerts: 22, user: "reena", status: "online", untouchable: "true" },
453+
{ nodes: "node25", alerts: 15, user: "nic", status: "online", untouchable: "true" },
454+
{ nodes: "node26", alerts: 11, user: "alex", status: "offline", untouchable: "true" },
455+
{ nodes: "node27", alerts: 22, user: "manolis", status: "offline", untouchable: "true" },
456+
{ nodes: "node28", alerts: 15, user: "achile", status: "stale", untouchable: "true" },
457+
{ nodes: "node29", alerts: 11, user: "barba", status: "stale", untouchable: "false" },
458+
{ nodes: "node30", alerts: 22, user: "decker", status: "online", untouchable: "false" },
459459
]
460460

461461
return (
@@ -469,8 +469,6 @@ StoryTable.add("Full Table functionallity", () => {
469469
sortBy={[{ id: "nodes", desc: false }]}
470470
onGlobalSearchChange={onGlobalSearchChange}
471471
enableSorting
472-
paginationOptions={paginationOptions}
473-
enablePagination
474472
rowActions={rowActions}
475473
bulkActions={bulkActions}
476474
enableSelection

yarn.lock

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3203,11 +3203,23 @@
32033203
dependencies:
32043204
"@tanstack/table-core" "8.5.11"
32053205

3206+
"@tanstack/react-virtual@^3.0.0-beta.23":
3207+
version "3.0.0-beta.23"
3208+
resolved "https://registry.yarnpkg.com/@tanstack/react-virtual/-/react-virtual-3.0.0-beta.23.tgz#f3d3e049d6b49e2b91c46ec3d35f48d9fdf7426a"
3209+
integrity sha512-FurqZJD7oSXLtL5NP0YQKXNEY+2qczXjzxmxkD51ZO8ykyr2z62IRNfvpOyly2CPLg+M346mA/Ul2hlx4R3KPw==
3210+
dependencies:
3211+
"@tanstack/virtual-core" "3.0.0-beta.23"
3212+
32063213
"@tanstack/[email protected]":
32073214
version "8.5.11"
32083215
resolved "https://registry.yarnpkg.com/@tanstack/table-core/-/table-core-8.5.11.tgz#a23178a097df4b0b64bdfa6f79e6d8933e97c7f7"
32093216
integrity sha512-ZN61ockLaIAiiPbZfMKT2S03nbWx28OHg/nAiDnNfmN4QmAMcdwVajPn2QQwnNVGAr4jS4nbhbYzCcjq8livXQ==
32103217

3218+
"@tanstack/[email protected]":
3219+
version "3.0.0-beta.23"
3220+
resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.0.0-beta.23.tgz#2e586256bdb239e35c8d1ca4e8d66c1c55151419"
3221+
integrity sha512-xQfJgz4mdaxifPjOqUBYAar60UAQTrED2SpS0VI5AZvxYI4NDTxx5cFrjaP4baKY3UnVc8IsGFbqr8Q/LZNMag==
3222+
32113223
"@testing-library/dom@^8.3.0", "@testing-library/dom@^8.5.0":
32123224
version "8.16.0"
32133225
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.16.0.tgz#d6fc50250aed17b1035ca1bd64655e342db3936a"

0 commit comments

Comments
 (0)