Merge pull request #12999 from overleaf/ii-history-react-file-tree-optimisation

[web] History file tree list items optimisation

GitOrigin-RevId: b5e9b72b7df857479db3b2a276e6c064d8f9427a
This commit is contained in:
ilkin-overleaf
2023-05-09 11:56:26 +03:00
committed by Copybot
parent cf05b4a3d1
commit aea43cee29
5 changed files with 84 additions and 51 deletions

View File

@@ -1,29 +1,32 @@
import { memo } from 'react'
import classNames from 'classnames'
import HistoryFileTreeItem from './history-file-tree-item'
import iconTypeFromName from '../../../file-tree/util/icon-type-from-name'
import Icon from '../../../../shared/components/icon'
import { useFileTreeItemSelection } from '../../context/hooks/use-file-tree-item-selection'
import type { FileDiff } from '../../services/types/file'
type HistoryFileTreeDocProps = {
file: FileDiff
name: string
selected: boolean
onClick: (file: FileDiff) => void
onKeyDown: (file: FileDiff, event: React.KeyboardEvent<HTMLLIElement>) => void
}
export default function HistoryFileTreeDoc({
function HistoryFileTreeDoc({
file,
name,
selected,
onClick,
onKeyDown,
}: HistoryFileTreeDocProps) {
const { isSelected, handleClick, handleKeyDown } =
useFileTreeItemSelection(file)
return (
<li
role="treeitem"
className={classNames({ selected: isSelected })}
onClick={handleClick}
onKeyDown={handleKeyDown}
aria-selected={isSelected}
className={classNames({ selected })}
onClick={() => onClick(file)}
onKeyDown={e => onKeyDown(file, e)}
aria-selected={selected}
aria-label={name}
tabIndex={0}
>
@@ -41,3 +44,5 @@ export default function HistoryFileTreeDoc({
</li>
)
}
export default memo(HistoryFileTreeDoc)

View File

@@ -2,8 +2,10 @@ import classNames from 'classnames'
import HistoryFileTreeDoc from './history-file-tree-doc'
import HistoryFileTreeFolder from './history-file-tree-folder'
import type { ReactNode } from 'react'
import { ReactNode, useCallback } from 'react'
import type { HistoryFileTree, HistoryDoc } from '../../utils/file-tree'
import { useHistoryContext } from '../../context/history-context'
import { FileDiff } from '../../services/types/file'
type HistoryFileTreeFolderListProps = {
folders: HistoryFileTree[]
@@ -12,12 +14,46 @@ type HistoryFileTreeFolderListProps = {
children?: ReactNode
}
export default function HistoryFileTreeFolderList({
function HistoryFileTreeFolderList({
folders,
docs,
rootClassName,
children,
}: HistoryFileTreeFolderListProps) {
const { selection, setSelection } = useHistoryContext()
const handleEvent = useCallback(
(file: FileDiff) => {
setSelection(prevSelection => {
if (file.pathname !== prevSelection.selectedFile?.pathname) {
return {
...prevSelection,
selectedFile: file,
}
}
return prevSelection
})
},
[setSelection]
)
const handleClick = useCallback(
(file: FileDiff) => {
handleEvent(file)
},
[handleEvent]
)
const handleKeyDown = useCallback(
(file: FileDiff, event: React.KeyboardEvent<HTMLLIElement>) => {
if (event.key === 'Enter' || event.key === ' ') {
handleEvent(file)
}
},
[handleEvent]
)
return (
<ul className={classNames('list-unstyled', rootClassName)} role="tree">
{folders.map(folder => (
@@ -29,9 +65,18 @@ export default function HistoryFileTreeFolderList({
/>
))}
{docs.map(doc => (
<HistoryFileTreeDoc key={doc.pathname} name={doc.name} file={doc} />
<HistoryFileTreeDoc
key={doc.pathname}
name={doc.name}
file={doc}
selected={selection.selectedFile?.pathname === doc.pathname}
onClick={handleClick}
onKeyDown={handleKeyDown}
/>
))}
{children}
</ul>
)
}
export default HistoryFileTreeFolderList

View File

@@ -1,4 +1,4 @@
import { useState } from 'react'
import { useState, memo } from 'react'
import { useTranslation } from 'react-i18next'
import HistoryFileTreeItem from './history-file-tree-item'
@@ -13,7 +13,7 @@ type HistoryFileTreeFolderProps = {
docs: HistoryDoc[]
}
export default function HistoryFileTreeFolder({
function HistoryFileTreeFolder({
name,
folders,
docs,
@@ -61,3 +61,5 @@ export default function HistoryFileTreeFolder({
</>
)
}
export default memo(HistoryFileTreeFolder)

View File

@@ -1,3 +1,4 @@
import { useMemo } from 'react'
import { orderBy, reduce } from 'lodash'
import { useHistoryContext } from '../context/history-context'
import {
@@ -9,13 +10,26 @@ import HistoryFileTreeFolderList from './file-tree/history-file-tree-folder-list
export default function HistoryFileTree() {
const { selection, error } = useHistoryContext()
const fileTree = reduce(selection.files, reducePathsToTree, [])
const fileTree = useMemo(
() => reduce(selection.files, reducePathsToTree, []),
[selection.files]
)
const sortedFileTree = orderBy(fileTree, ['-type', 'operation', 'name'])
const sortedFileTree = useMemo(
() => orderBy(fileTree, ['-type', 'operation', 'name']),
[fileTree]
)
const mappedFileTree = fileTreeDiffToFileTreeData(sortedFileTree)
const mappedFileTree = useMemo(
() => fileTreeDiffToFileTreeData(sortedFileTree),
[sortedFileTree]
)
return error ? null : (
if (error) {
return null
}
return (
<HistoryFileTreeFolderList
folders={mappedFileTree.folders}
docs={mappedFileTree.docs ?? []}

View File

@@ -1,33 +0,0 @@
import { useCallback } from 'react'
import { useHistoryContext } from '../history-context'
import type { FileDiff } from '../../services/types/file'
export function useFileTreeItemSelection(file: FileDiff) {
const { selection, setSelection } = useHistoryContext()
const handleEvent = useCallback(() => {
if (file.pathname !== selection.selectedFile?.pathname) {
setSelection({
...selection,
selectedFile: file,
})
}
}, [file, selection, setSelection])
const handleClick = useCallback(() => {
handleEvent()
}, [handleEvent])
const handleKeyDown = useCallback(
event => {
if (event.key === 'Enter' || event.key === ' ') {
handleEvent()
}
},
[handleEvent]
)
const isSelected = selection.selectedFile?.pathname === file.pathname
return { isSelected, handleClick, handleKeyDown }
}