1
0
mirror of https://github.com/mattermost/focalboard.git synced 2024-12-21 13:38:56 +02:00

making the grouped table list flat to prepare for virtualization

This commit is contained in:
Benjamin Cooke 2023-03-09 11:28:21 -05:00
parent 31b7734f85
commit 19007c486a
6 changed files with 106 additions and 57 deletions

View File

@ -188,27 +188,27 @@ const Table = (props: Props): JSX.Element => {
{/* Table rows */}
<div className='table-row-container'>
{activeView.fields.groupById &&
visibleGroups.map((group) => {
return (
<TableGroup
key={group.option.id}
board={board}
activeView={activeView}
groupByProperty={groupByProperty}
group={group}
readonly={props.readonly || !canEditCards}
selectedCardIds={props.selectedCardIds}
cardIdToFocusOnRender={props.cardIdToFocusOnRender}
hideGroup={hideGroup}
addCard={props.addCard}
showCard={props.showCard}
propertyNameChanged={propertyNameChanged}
onCardClicked={props.onCardClicked}
onDropToGroupHeader={onDropToGroupHeader}
onDropToCard={onDropToCard}
onDropToGroup={onDropToGroup}
/>)
})
visibleGroups.map((group) => {
return (
<TableGroup
key={group.option.id}
board={board}
activeView={activeView}
groupByProperty={groupByProperty}
group={group}
readonly={props.readonly || !canEditCards}
selectedCardIds={props.selectedCardIds}
cardIdToFocusOnRender={props.cardIdToFocusOnRender}
hideGroup={hideGroup}
addCard={props.addCard}
showCard={props.showCard}
propertyNameChanged={propertyNameChanged}
onCardClicked={props.onCardClicked}
onDropToGroupHeader={onDropToGroupHeader}
onDropToCard={onDropToCard}
onDropToGroup={onDropToGroup}
/>)
})
}
{/* No Grouping, Rows, one per card */}
@ -224,6 +224,7 @@ const Table = (props: Props): JSX.Element => {
addCard={props.addCard}
onCardClicked={props.onCardClicked}
onDrop={onDropToCard}
useVirtualizedList={true}
/>
}
</div>

View File

@ -32,31 +32,9 @@ type Props = {
const TableGroup = (props: Props): JSX.Element => {
const {board, activeView, group, onDropToGroup, groupByProperty} = props
const groupId = group.option.id
const [{isOver}, drop] = useDrop(() => ({
accept: 'card',
collect: (monitor) => ({
isOver: monitor.isOver(),
}),
drop: (item: Card, monitor) => {
if (monitor.isOver({shallow: true})) {
onDropToGroup(item, groupId, '')
}
},
}), [onDropToGroup, groupId])
let className = 'octo-table-group'
if (isOver) {
className += ' dragover'
}
return (
<div
ref={drop}
className={className}
key={group.option.id}
>
<>
<TableGroupHeaderRow
group={group}
board={board}
@ -67,6 +45,8 @@ const TableGroup = (props: Props): JSX.Element => {
readonly={props.readonly}
propertyNameChanged={props.propertyNameChanged}
onDrop={props.onDropToGroupHeader}
key={group.option.id}
onDropToGroup={onDropToGroup}
/>
{(group.cards.length > 0) &&
@ -81,8 +61,10 @@ const TableGroup = (props: Props): JSX.Element => {
addCard={props.addCard}
onCardClicked={props.onCardClicked}
onDrop={props.onDropToCard}
useVirtualizedList={false}
/>}
</div>
</>
)
}

View File

@ -71,6 +71,7 @@ test('should match snapshot, no groups', async () => {
type: 'text',
options: [{id: 'property1', value: 'Property 1', color: ''}],
}}
onDropToGroup={jest.fn()}
/>
</Wrapper>,
)
@ -89,6 +90,7 @@ test('should match snapshot with Group', async () => {
addCard={jest.fn()}
propertyNameChanged={jest.fn()}
onDrop={jest.fn()}
onDropToGroup={jest.fn()}
/>
</Wrapper>,
)
@ -107,6 +109,7 @@ test('should match snapshot on read only', async () => {
addCard={jest.fn()}
propertyNameChanged={jest.fn()}
onDrop={jest.fn()}
onDropToGroup={jest.fn()}
/>
</Wrapper>,
)
@ -130,6 +133,7 @@ test('should match snapshot, hide group', async () => {
addCard={jest.fn()}
propertyNameChanged={jest.fn()}
onDrop={jest.fn()}
onDropToGroup={jest.fn()}
/>
</Wrapper>,
)
@ -158,6 +162,7 @@ test('should match snapshot, add new', async () => {
addCard={addNew}
propertyNameChanged={jest.fn()}
onDrop={jest.fn()}
onDropToGroup={jest.fn()}
/>
</Wrapper>,
)
@ -184,6 +189,7 @@ test('should match snapshot, edit title', async () => {
addCard={jest.fn()}
propertyNameChanged={jest.fn()}
onDrop={jest.fn()}
onDropToGroup={jest.fn()}
/>
</Wrapper>,
)

View File

@ -1,13 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/* eslint-disable max-lines */
import React, {useState, useEffect} from 'react'
import React, {useState, useEffect, useRef} from 'react'
import {FormattedMessage, useIntl} from 'react-intl'
import {useDrag, useDrop} from 'react-dnd'
import {Constants} from '../../constants'
import {IPropertyOption, Board, IPropertyTemplate, BoardGroup} from '../../blocks/board'
import {BoardView} from '../../blocks/boardView'
import {useSortable} from '../../hooks/sortable'
import {Card} from '../../blocks/card'
import mutator from '../../mutator'
import Button from '../../widgets/buttons/button'
import IconButton from '../../widgets/buttons/iconButton'
@ -33,13 +34,42 @@ type Props = {
addCard: (groupByOptionId?: string) => Promise<void>
propertyNameChanged: (option: IPropertyOption, text: string) => Promise<void>
onDrop: (srcOption: IPropertyOption, dstOption?: IPropertyOption) => void
onDropToGroup: (srcCard: Card, groupID: string, dstCardID: string) => void
}
const TableGroupHeaderRow = (props: Props): JSX.Element => {
const {board, activeView, group, groupByProperty} = props
const [groupTitle, setGroupTitle] = useState(group.option.value)
const [isDragging, isOver, groupHeaderRef] = useSortable('groupHeader', group.option, !props.readonly, props.onDrop)
const ref = useRef<HTMLDivElement>(null)
const [{isDragging}, drag] = useDrag(() => ({
type: 'groupHeader',
item: group.option,
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
canDrag: () => !props.readonly,
}), ['groupHeader', group.option, props.readonly])
const [{isOver}, drop] = useDrop(() => ({
accept: ['groupHeader', 'card'],
collect: (monitor) => ({
isOver: monitor.isOver(),
}),
drop: (dragItem: IPropertyOption | Card, monitor) => {
// @ts-ignore
if (dragItem?.type === 'card' && monitor.isOver({shallow: true})) {
// @ts-ignore
props.onDropToGroup(dragItem, group.option.id, '')
return;
}
// @ts-ignore
props.onDrop(dragItem, group.option)
},
canDrop: () => !props.readonly,
}), [group.option, props.onDrop, props.readonly])
drop(drag(ref))
const intl = useIntl()
const columnResize = useColumnResize()
@ -59,7 +89,7 @@ const TableGroupHeaderRow = (props: Props): JSX.Element => {
return (
<div
key={group.option.id + 'header'}
ref={groupHeaderRef}
ref={ref}
style={{opacity: isDragging ? 0.5 : 1}}
className={className}
>

View File

@ -74,6 +74,7 @@ describe('components/table/TableRows', () => {
addCard={addCard}
onCardClicked={jest.fn()}
onDrop={jest.fn()}
useVirtualizedList={false}
/>
</ColumnResizeProvider>
</ReduxProvider>,

View File

@ -1,8 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback} from 'react'
import {FixedSizeList, ListChildComponentProps} from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';
import {FixedSizeList, ListChildComponentProps} from 'react-window'
import AutoSizer from 'react-virtualized-auto-sizer'
import {Card} from '../../blocks/card'
import {Board} from '../../blocks/board'
@ -23,21 +23,50 @@ type Props = {
addCard: (groupByOptionId?: string) => Promise<void>
onCardClicked: (e: React.MouseEvent, card: Card) => void
onDrop: (srcCard: Card, dstCard: Card) => void
useVirtualizedList: boolean
}
const TableRows = (props: Props): JSX.Element => {
const {board, cards, activeView} = props
const {board, cards, activeView, useVirtualizedList} = props
const onClickRow = useCallback((e: React.MouseEvent<HTMLDivElement>, card: Card) => {
props.onCardClicked(e, card)
}, [props.onCardClicked])
if (!useVirtualizedList) {
return (
<>
{cards.map((card, idx) => {
return (
<TableRow
key={card.id + card.updateAt}
board={board}
columnWidths={activeView.fields.columnWidths}
isManualSort={activeView.fields.sortOptions.length === 0}
groupById={activeView.fields.groupById}
visiblePropertyIds={activeView.fields.visiblePropertyIds}
collapsedOptionIds={activeView.fields.collapsedOptionIds}
card={card}
addCard={props.addCard}
isSelected={props.selectedCardIds.includes(card.id)}
focusOnMount={props.cardIdToFocusOnRender === card.id}
isLastCard={idx === (cards.length - 1)}
onClick={onClickRow}
showCard={props.showCard}
readonly={props.readonly}
onDrop={props.onDrop}
/>
)
})}
</>
)
}
const isItemLoaded = (index: number) => {
return index < cards.length;
};
}
const Item = ({index, style}: ListChildComponentProps) => {
const card = cards[index]
if (isItemLoaded(index)) {
return (
@ -72,13 +101,13 @@ const TableRows = (props: Props): JSX.Element => {
}
return (
<AutoSizer>
{({height, width}) => (
<AutoSizer disableWidth>
{({height}) => (
<FixedSizeList
height={height}
itemCount={1828}
itemSize={44}
width={width}
width={'100%'}
>
{Item}
</FixedSizeList>