X-Git-Url: https://git.arvados.org/arvados-workbench2.git/blobdiff_plain/b57a24f2a59938be52c78d453dea00d5cd54720d..b62944772ff96019c1e497426784690978bb9c96:/src/components/tree/tree.tsx diff --git a/src/components/tree/tree.tsx b/src/components/tree/tree.tsx index 3a644734..20526005 100644 --- a/src/components/tree/tree.tsx +++ b/src/components/tree/tree.tsx @@ -3,73 +3,117 @@ // SPDX-License-Identifier: AGPL-3.0 import * as React from 'react'; -import List from "@material-ui/core/List/List"; -import ListItem from "@material-ui/core/ListItem/ListItem"; -import { StyleRulesCallback, Theme, withStyles, WithStyles } from '@material-ui/core/styles'; +import { List, ListItem, ListItemIcon, Collapse } from "@material-ui/core"; +import { StyleRulesCallback, withStyles, WithStyles } from '@material-ui/core/styles'; import { ReactElement } from "react"; -import Collapse from "@material-ui/core/Collapse/Collapse"; +import CircularProgress from '@material-ui/core/CircularProgress'; +import * as classnames from "classnames"; -type CssRules = 'list' | 'activeArrow' | 'arrow' | 'arrowRotate'; +import { ArvadosTheme } from '../../common/custom-theme'; +import { SidePanelRightArrowIcon } from '../icon/icon'; -const styles: StyleRulesCallback = (theme: Theme) => ({ +type CssRules = 'list' | 'active' | 'loader' | 'toggableIconContainer' | 'iconClose' | 'iconOpen' | 'toggableIcon'; + +const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ list: { - paddingBottom: '3px', - paddingTop: '3px', + padding: '3px 0px' }, - activeArrow: { - color: '#4285F6', + loader: { position: 'absolute', + transform: 'translate(0px)', + top: '3px' }, - arrow: { - position: 'absolute', + toggableIconContainer: { + color: theme.palette.grey["700"], + height: '14px', + position: 'absolute' + }, + toggableIcon: { + fontSize: '14px' }, - arrowRotate: { - transform: 'rotate(-90deg)', + active: { + color: theme.palette.primary.main, + }, + iconClose: { + transition: 'all 0.1s ease', + }, + iconOpen: { + transition: 'all 0.1s ease', + transform: 'rotate(90deg)', } }); +export enum TreeItemStatus { + INITIAL, + PENDING, + LOADED +} + export interface TreeItem { data: T; id: string; open: boolean; active: boolean; + status: TreeItemStatus; items?: Array>; } interface TreeProps { items?: Array>; render: (item: TreeItem, level?: number) => ReactElement<{}>; - toggleItem: (id: string) => any; + toggleItemOpen: (id: string, status: TreeItemStatus) => void; + toggleItemActive: (id: string, status: TreeItemStatus) => void; level?: number; + onContextMenu: (event: React.MouseEvent, item: TreeItem) => void; } -class Tree extends React.Component & WithStyles, {}> { - renderArrow (items: Array> | undefined, arrowClass: string, isOpen: boolean){ - return items && items.length > 0 ? : '' - } - render(): ReactElement { - const level = this.props.level ? this.props.level : 0; - const {classes, render, toggleItem, items} = this.props; - const {list, arrow, activeArrow} = classes; - return - {items && items.map((it: TreeItem, idx: number) => -
- toggleItem(it.id)} className={list} style={{paddingLeft: (level + 1) * 20}}> - {this.renderArrow(it.items, it.active ? activeArrow : arrow, it.open)} - {render(it, level)} - - {it.items && it.items.length > 0 && - - - } -
)} -
- } -} +export const Tree = withStyles(styles)( + class Component extends React.Component & WithStyles, {}> { + render(): ReactElement { + const level = this.props.level ? this.props.level : 0; + const { classes, render, toggleItemOpen, items, toggleItemActive, onContextMenu } = this.props; + const { list, loader, toggableIconContainer } = classes; + return + {items && items.map((it: TreeItem, idx: number) => +
+ toggleItemActive(it.id, it.status)} + onContextMenu={this.handleRowContextMenu(it)}> + {it.status === TreeItemStatus.PENDING ? + : null} + this.props.toggleItemOpen(it.id, it.status)} + className={toggableIconContainer}> + + {it.status !== TreeItemStatus.INITIAL && it.items && it.items.length === 0 ? : } + + + {render(it, level)} + + {it.items && it.items.length > 0 && + + + } +
)} +
; + } + + getToggableIconClassNames = (isOpen?: boolean, isActive?: boolean) => { + const { iconOpen, iconClose, active, toggableIcon } = this.props.classes; + return classnames(toggableIcon, { + [iconOpen]: isOpen, + [iconClose]: !isOpen, + [active]: isActive + }); + } -const StyledTree = withStyles(styles)(Tree); -export default StyledTree + handleRowContextMenu = (item: TreeItem) => + (event: React.MouseEvent) => + this.props.onContextMenu(event, item) + } +);