You've already forked focalboard
mirror of
https://github.com/mattermost/focalboard.git
synced 2025-07-15 23:54:29 +02:00
making the table a virtual list to improve performance
This commit is contained in:
83
webapp/package-lock.json
generated
83
webapp/package-lock.json
generated
@ -48,6 +48,8 @@
|
|||||||
"react-redux": "^7.2.0",
|
"react-redux": "^7.2.0",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-select": "^5.2.2",
|
"react-select": "^5.2.2",
|
||||||
|
"react-virtualized-auto-sizer": "^1.0.7",
|
||||||
|
"react-window": "^1.8.8",
|
||||||
"trim-newlines": "^4.0.2"
|
"trim-newlines": "^4.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -72,6 +74,8 @@
|
|||||||
"@types/react-redux": "^7.1.23",
|
"@types/react-redux": "^7.1.23",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"@types/react-select": "^5.0.0",
|
"@types/react-select": "^5.0.0",
|
||||||
|
"@types/react-virtualized-auto-sizer": "^1.0.1",
|
||||||
|
"@types/react-window": "^1.8.5",
|
||||||
"@types/redux-mock-store": "^1.0.3",
|
"@types/redux-mock-store": "^1.0.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.16.0",
|
"@typescript-eslint/eslint-plugin": "^5.16.0",
|
||||||
"@typescript-eslint/parser": "^5.16.0",
|
"@typescript-eslint/parser": "^5.16.0",
|
||||||
@ -2795,6 +2799,24 @@
|
|||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-virtualized-auto-sizer": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-GH8sAnBEM5GV9LTeiz56r4ZhMOUSrP43tAQNSRVxNexDjcNKLCEtnxusAItg1owFUFE6k0NslV26gqVClVvong==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/react-window": {
|
||||||
|
"version": "1.8.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.5.tgz",
|
||||||
|
"integrity": "sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/redux-mock-store": {
|
"node_modules/@types/redux-mock-store": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/redux-mock-store/-/redux-mock-store-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/redux-mock-store/-/redux-mock-store-1.0.3.tgz",
|
||||||
@ -14075,6 +14097,34 @@
|
|||||||
"react-dom": ">=16.6.0"
|
"react-dom": ">=16.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-virtualized-auto-sizer": {
|
||||||
|
"version": "1.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.7.tgz",
|
||||||
|
"integrity": "sha512-Mxi6lwOmjwIjC1X4gABXMJcKHsOo0xWl3E3ugOgufB8GJU+MqrtY35aBuvCYv/razQ1Vbp7h1gWJjGjoNN5pmA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc",
|
||||||
|
"react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-window": {
|
||||||
|
"version": "1.8.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.8.tgz",
|
||||||
|
"integrity": "sha512-D4IiBeRtGXziZ1n0XklnFGu7h9gU684zepqyKzgPNzrsrk7xOCxni+TCckjg2Nr/DiaEEGVVmnhYSlT2rB47dQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"memoize-one": ">=3.1.1 <6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/read-pkg": {
|
"node_modules/read-pkg": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
|
||||||
@ -19590,6 +19640,24 @@
|
|||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/react-virtualized-auto-sizer": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-GH8sAnBEM5GV9LTeiz56r4ZhMOUSrP43tAQNSRVxNexDjcNKLCEtnxusAItg1owFUFE6k0NslV26gqVClVvong==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/react-window": {
|
||||||
|
"version": "1.8.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.5.tgz",
|
||||||
|
"integrity": "sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/redux-mock-store": {
|
"@types/redux-mock-store": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/redux-mock-store/-/redux-mock-store-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/redux-mock-store/-/redux-mock-store-1.0.3.tgz",
|
||||||
@ -28118,6 +28186,21 @@
|
|||||||
"prop-types": "^15.6.2"
|
"prop-types": "^15.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-virtualized-auto-sizer": {
|
||||||
|
"version": "1.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.7.tgz",
|
||||||
|
"integrity": "sha512-Mxi6lwOmjwIjC1X4gABXMJcKHsOo0xWl3E3ugOgufB8GJU+MqrtY35aBuvCYv/razQ1Vbp7h1gWJjGjoNN5pmA==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
|
"react-window": {
|
||||||
|
"version": "1.8.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.8.tgz",
|
||||||
|
"integrity": "sha512-D4IiBeRtGXziZ1n0XklnFGu7h9gU684zepqyKzgPNzrsrk7xOCxni+TCckjg2Nr/DiaEEGVVmnhYSlT2rB47dQ==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"memoize-one": ">=3.1.1 <6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"read-pkg": {
|
"read-pkg": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
|
||||||
|
@ -65,6 +65,8 @@
|
|||||||
"react-redux": "^7.2.0",
|
"react-redux": "^7.2.0",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-select": "^5.2.2",
|
"react-select": "^5.2.2",
|
||||||
|
"react-virtualized-auto-sizer": "^1.0.7",
|
||||||
|
"react-window": "^1.8.8",
|
||||||
"trim-newlines": "^4.0.2"
|
"trim-newlines": "^4.0.2"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
@ -113,6 +115,8 @@
|
|||||||
"@types/react-redux": "^7.1.23",
|
"@types/react-redux": "^7.1.23",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"@types/react-select": "^5.0.0",
|
"@types/react-select": "^5.0.0",
|
||||||
|
"@types/react-virtualized-auto-sizer": "^1.0.1",
|
||||||
|
"@types/react-window": "^1.8.5",
|
||||||
"@types/redux-mock-store": "^1.0.3",
|
"@types/redux-mock-store": "^1.0.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.16.0",
|
"@typescript-eslint/eslint-plugin": "^5.16.0",
|
||||||
"@typescript-eslint/parser": "^5.16.0",
|
"@typescript-eslint/parser": "^5.16.0",
|
||||||
|
@ -212,7 +212,8 @@
|
|||||||
.octo-table-body {
|
.octo-table-body {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: fit-content;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.octo-table-header,
|
.octo-table-header,
|
||||||
@ -250,7 +251,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.table-row-container {
|
.table-row-container {
|
||||||
width: fit-content;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
.octo-table-cell {
|
.octo-table-cell {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
import React, {useCallback} from 'react'
|
import React, {useCallback} from 'react'
|
||||||
|
import {FixedSizeList, ListChildComponentProps} from 'react-window';
|
||||||
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||||
|
|
||||||
import {Card} from '../../blocks/card'
|
import {Card} from '../../blocks/card'
|
||||||
import {Board} from '../../blocks/board'
|
import {Board} from '../../blocks/board'
|
||||||
@ -26,14 +28,26 @@ type Props = {
|
|||||||
const TableRows = (props: Props): JSX.Element => {
|
const TableRows = (props: Props): JSX.Element => {
|
||||||
const {board, cards, activeView} = props
|
const {board, cards, activeView} = props
|
||||||
|
|
||||||
|
console.log(cards);
|
||||||
|
|
||||||
const onClickRow = useCallback((e: React.MouseEvent<HTMLDivElement>, card: Card) => {
|
const onClickRow = useCallback((e: React.MouseEvent<HTMLDivElement>, card: Card) => {
|
||||||
props.onCardClicked(e, card)
|
props.onCardClicked(e, card)
|
||||||
}, [props.onCardClicked])
|
}, [props.onCardClicked])
|
||||||
|
|
||||||
return (
|
const isItemLoaded = (index: number) => {
|
||||||
<>
|
return index < cards.length;
|
||||||
{cards.map((card, idx) => {
|
};
|
||||||
return (
|
|
||||||
|
const Item = ({index, style}: ListChildComponentProps) => {
|
||||||
|
|
||||||
|
const card = cards[index]
|
||||||
|
console.log(card)
|
||||||
|
if (isItemLoaded(index)) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={style}
|
||||||
|
key={card.id + card.updateAt}
|
||||||
|
>
|
||||||
<TableRow
|
<TableRow
|
||||||
key={card.id + card.updateAt}
|
key={card.id + card.updateAt}
|
||||||
board={board}
|
board={board}
|
||||||
@ -46,14 +60,34 @@ const TableRows = (props: Props): JSX.Element => {
|
|||||||
addCard={props.addCard}
|
addCard={props.addCard}
|
||||||
isSelected={props.selectedCardIds.includes(card.id)}
|
isSelected={props.selectedCardIds.includes(card.id)}
|
||||||
focusOnMount={props.cardIdToFocusOnRender === card.id}
|
focusOnMount={props.cardIdToFocusOnRender === card.id}
|
||||||
isLastCard={idx === (cards.length - 1)}
|
isLastCard={index === (cards.length - 1)}
|
||||||
onClick={onClickRow}
|
onClick={onClickRow}
|
||||||
showCard={props.showCard}
|
showCard={props.showCard}
|
||||||
readonly={props.readonly}
|
readonly={props.readonly}
|
||||||
onDrop={props.onDrop}
|
onDrop={props.onDrop}
|
||||||
/>)
|
/>
|
||||||
})}
|
</div>
|
||||||
</>
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AutoSizer>
|
||||||
|
{({height, width}) => (
|
||||||
|
<FixedSizeList
|
||||||
|
height={height}
|
||||||
|
itemCount={1828}
|
||||||
|
itemSize={44}
|
||||||
|
width={width}
|
||||||
|
>
|
||||||
|
{Item}
|
||||||
|
</FixedSizeList>
|
||||||
|
)}
|
||||||
|
</AutoSizer>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user