From: Lucas Di Pentima Date: Fri, 26 Jun 2020 20:25:10 +0000 (-0300) Subject: 15610: Adds behaviors like the original Tree, and max height on VirtualTree. X-Git-Tag: 2.1.0~22^2~7 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/159c84a15b7739c02dc4bc0d9626b515e8426b92 15610: Adds behaviors like the original Tree, and max height on VirtualTree. Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima --- diff --git a/src/components/file-tree/file-tree.tsx b/src/components/file-tree/file-tree.tsx index b5d98c08..d4b47be9 100644 --- a/src/components/file-tree/file-tree.tsx +++ b/src/components/file-tree/file-tree.tsx @@ -4,7 +4,7 @@ import * as React from "react"; import { TreeItem, TreeItemStatus } from "../tree/tree"; -import { VirtualTree as Tree } from "../tree/virtual-tree"; +import { VirtualTree } from "../tree/virtual-tree"; import { FileTreeData } from "./file-tree-data"; import { FileTreeItem } from "./file-tree-item"; @@ -17,6 +17,7 @@ export interface FileTreeProps { currentItemUuid?: string; } +const Tree = VirtualTree(20); export class FileTree extends React.Component { render() { return { selected?: boolean; status: TreeItemStatus; items?: Array>; - itemCount?: number; - level?: number; } export interface TreeProps { diff --git a/src/components/tree/virtual-tree.tsx b/src/components/tree/virtual-tree.tsx index 467969fa..9330fbe5 100644 --- a/src/components/tree/virtual-tree.tsx +++ b/src/components/tree/virtual-tree.tsx @@ -13,6 +13,7 @@ import { ArvadosTheme } from '~/common/custom-theme'; import { TreeItem, TreeProps, TreeItemStatus } from './tree'; import { ListItem, Radio, Checkbox, CircularProgress, ListItemIcon } from '@material-ui/core'; import { SidePanelRightArrowIcon } from '../icon/icon'; +import { min } from 'lodash'; type CssRules = 'list' | 'listItem' @@ -71,35 +72,35 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ } }); -// export const RowA = (items: TreeItem[], render:any) => (index: number) => { -// return
-// {render(items[index])} -//
; -// }; +export interface VirtualTreeItem extends TreeItem { + itemCount?: number; + level?: number; +} // For some reason, on TSX files it isn't accepted just one generic param, so // I'm using as a workaround. -export const Row = (itemList: TreeItem[], render: any) => withStyles(styles)( - (props: React.PropsWithChildren & TreeProps & WithStyles) => { - const { index, style } = props; +export const Row = (itemList: VirtualTreeItem[], render: any, treeProps: TreeProps) => withStyles(styles)( + (props: React.PropsWithChildren & WithStyles) => { + const { index, style, classes } = props; const it = itemList[index]; const level = it.level || 0; - const { classes, toggleItemActive, disableRipple, currentItemUuid, useRadioButtons } = props; + const { toggleItemActive, disableRipple, currentItemUuid, useRadioButtons } = treeProps; const { listItem, loader, toggableIconContainer, renderContainer } = classes; - const { levelIndentation = 20, itemRightPadding = 20 } = props; + const { levelIndentation = 20, itemRightPadding = 20 } = treeProps; - const showSelection = typeof props.showSelection === 'function' - ? props.showSelection - : () => props.showSelection ? true : false; + const showSelection = typeof treeProps.showSelection === 'function' + ? treeProps.showSelection + : () => treeProps.showSelection ? true : false; - const handleRowContextMenu = (item: TreeItem) => - (event: React.MouseEvent) => - props.onContextMenu(event, item); + const handleRowContextMenu = (item: VirtualTreeItem) => + (event: React.MouseEvent) => { + treeProps.onContextMenu(event, item); + }; - const handleToggleItemOpen = (item: TreeItem) => + const handleToggleItemOpen = (item: VirtualTreeItem) => (event: React.MouseEvent) => { event.stopPropagation(); - props.toggleItemOpen(event, item); + treeProps.toggleItemOpen(event, item); }; const getToggableIconClassNames = (isOpen?: boolean, isActive?: boolean) => { @@ -120,8 +121,8 @@ export const Row = (itemList: TreeItem[], render: any) => withStyles(s return isSidePanelIconNotNeeded(status, itemCount) ? : ; }; - const handleCheckboxChange = (item: TreeItem) => { - const { toggleItemSelection } = props; + const handleCheckboxChange = (item: VirtualTreeItem) => { + const { toggleItemSelection } = treeProps; return toggleItemSelection ? (event: React.MouseEvent) => { event.stopPropagation(); @@ -166,24 +167,30 @@ export const Row = (itemList: TreeItem[], render: any) => withStyles(s ; }); -export const VirtualList = (height: number, width: number, items: TreeItem[], render: any) => +const itemSize = 30; + +export const VirtualList = (height: number, width: number, items: VirtualTreeItem[], render: any, treeProps: TreeProps) => - {Row(items, render)} + {Row(items, render, treeProps)} ; -export const VirtualTree = withStyles(styles)( +export const VirtualTree = (maxElements: number) => withStyles(styles)( class Component extends React.Component & WithStyles, {}> { render(): ReactElement { const { items, render } = this.props; - return
+ // Virtual list viewport's maximum height + const itemsQty = items && items.length || 0; + const viewportHeight = min([itemsQty, maxElements])! * itemSize; + + return
{({ height, width }) => { - return VirtualList(height, width, items || [], render); + return VirtualList(height, width, items || [], render, this.props); }}
; } diff --git a/src/models/tree.ts b/src/models/tree.ts index 69224059..c7713cbc 100644 --- a/src/models/tree.ts +++ b/src/models/tree.ts @@ -16,7 +16,6 @@ export interface TreeNode { selected: boolean; expanded: boolean; status: TreeNodeStatus; - level?: number; } export enum TreeNodeStatus { @@ -194,7 +193,6 @@ export const initTreeNode = (data: Pick, 'id' | 'value'> & { pare expanded: false, status: TreeNodeStatus.INITIAL, parent: '', - level: 0, ...data, }); diff --git a/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts b/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts index 175a8cef..204d4c0e 100644 --- a/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts +++ b/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts @@ -31,25 +31,15 @@ export const COLLECTION_PANEL_LOAD_FILES_THRESHOLD = 40000; export const loadCollectionFiles = (uuid: string) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { - let step = Date.now(); dispatch(progressIndicatorActions.START_WORKING(COLLECTION_PANEL_LOAD_FILES)); const files = await services.collectionService.files(uuid); - console.log('Get files: ', (Date.now()-step)/1000); // Given the array of directories and files, create the appropriate tree nodes, // sort them, and add the complete url to each. - step = Date.now(); const tree = createCollectionFilesTree(files); - console.log('Create tree: ', (Date.now()-step)/1000); - step = Date.now(); const sorted = sortFilesTree(tree); - console.log('Sort tree: ', (Date.now()-step)/1000); - step = Date.now(); const mapped = mapTreeValues(services.collectionService.extendFileURL)(sorted); - console.log('Add URL: ', (Date.now()-step)/1000); - step = Date.now(); dispatch(collectionPanelFilesAction.SET_COLLECTION_FILES(mapped)); - console.log('Dispatch: ', (Date.now()-step)/1000); dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PANEL_LOAD_FILES)); }; diff --git a/src/views-components/collection-panel-files/collection-panel-files.ts b/src/views-components/collection-panel-files/collection-panel-files.ts index 3cc3569d..79970003 100644 --- a/src/views-components/collection-panel-files/collection-panel-files.ts +++ b/src/views-components/collection-panel-files/collection-panel-files.ts @@ -8,7 +8,8 @@ import { CollectionPanelFilesProps } from "~/components/collection-panel-files/collection-panel-files"; import { RootState } from "~/store/store"; -import { TreeItem, TreeItemStatus } from "~/components/tree/tree"; +import { TreeItemStatus } from "~/components/tree/tree"; +import { VirtualTreeItem as TreeItem } from "~/components/tree/virtual-tree"; import { CollectionPanelDirectory, CollectionPanelFile, @@ -75,10 +76,9 @@ const mapDispatchToProps = (dispatch: Dispatch): Pick (tree: Tree) => +const collectionItemToList = (level: number) => (tree: Tree) => (id: string): TreeItem[] => { const node: TreeNode = getNode(id)(tree) || initTreeNode({ id: '', @@ -107,38 +107,12 @@ export const collectionItemToList = (level: number) => (tree: Tree) => - (id: string): TreeItem => { - const node: TreeNode = getNode(id)(tree) || initTreeNode({ - id: '', - parent: '', - value: { - ...createCollectionDirectory({ name: 'Invalid file' }), - selected: false, - collapsed: true - } - }); - return { - active: false, - data: { - name: node.value.name, - size: node.value.type === CollectionFileType.FILE ? node.value.size : undefined, - type: node.value.type, - url: node.value.url, - }, - id: node.id, - items: getNodeChildrenIds(node.id)(tree) - .map(collectionItemToTreeItem(tree)), - open: node.value.type === CollectionFileType.DIRECTORY ? !node.value.collapsed : false, - selected: node.value.selected, - status: TreeItemStatus.LOADED - }; - };